diff --git a/src/network/PacketType.java b/src/network/PacketType.java index 324617278..2b45fd1c2 100644 --- a/src/network/PacketType.java +++ b/src/network/PacketType.java @@ -162,6 +162,18 @@ import network.packets.swg.zone.spatial.AttributeListMessage; import network.packets.swg.zone.spatial.GetMapLocationsMessage; import network.packets.swg.zone.spatial.GetMapLocationsResponseMessage; import network.packets.swg.zone.spatial.NewTicketActivityResponseMessage; +import network.packets.swg.zone.trade.AbortTradeMessage; +import network.packets.swg.zone.trade.AcceptTransactionMessage; +import network.packets.swg.zone.trade.AddItemFailedMessage; +import network.packets.swg.zone.trade.AddItemMessage; +import network.packets.swg.zone.trade.BeginTradeMessage; +import network.packets.swg.zone.trade.BeginVerificationMessage; +import network.packets.swg.zone.trade.DenyTradeMessage; +import network.packets.swg.zone.trade.GiveMoneyMessage; +import network.packets.swg.zone.trade.RemoveItemMessage; +import network.packets.swg.zone.trade.TradeCompleteMessage; +import network.packets.swg.zone.trade.UnAcceptTransactionMessage; +import network.packets.swg.zone.trade.VerifyTradeMessage; public enum PacketType { @@ -326,6 +338,19 @@ public enum PacketType { PLANET_TRAVEL_POINT_LIST_REQUEST (PlanetTravelPointListRequest.CRC, PlanetTravelPointListRequest.class), PLANET_TRAVEL_POINT_LIST_RESPONSE (PlanetTravelPointListResponse.CRC, PlanetTravelPointListResponse.class), + //Trade + ABORT_TRADE_MESSAGE (AbortTradeMessage.CRC, AbortTradeMessage.class), + ACCEPT_TRANSACTION_MESSAGE (AcceptTransactionMessage.CRC, AcceptTransactionMessage.class), + ADD_ITEM_FAILED_MESSAGE (AddItemFailedMessage.CRC, AddItemFailedMessage.class), + ADD_ITEM_MESSAGE (AddItemMessage.CRC, AddItemMessage.class), + BEGIN_TRADE_MESSAGE (BeginTradeMessage.CRC, BeginTradeMessage.class), + BEGIN_VERIFICATION_MESSAGE (BeginVerificationMessage.CRC, BeginVerificationMessage.class), + DENY_TRADE_MESSAGE (DenyTradeMessage.CRC, DenyTradeMessage.class), + GIVE_MONEY_MESSAGE (GiveMoneyMessage.CRC, GiveMoneyMessage.class), + REMOVE_ITEM_MESSAGE (RemoveItemMessage.CRC, RemoveItemMessage.class), + TRADE_COMPLETE_MESSAGE (TradeCompleteMessage.CRC, TradeCompleteMessage.class), + UNACCEPT_TRANSACTION_MESSAGE (UnAcceptTransactionMessage.CRC, UnAcceptTransactionMessage.class), + VERIFY_TRADE_MESSAGE (VerifyTradeMessage.CRC, VerifyTradeMessage.class), UNKNOWN (0xFFFFFFFF, SWGPacket.class); diff --git a/src/network/packets/swg/zone/object_controller/MessageQueueSecureTrade.java b/src/network/packets/swg/zone/object_controller/MessageQueueSecureTrade.java deleted file mode 100644 index 393bedac4..000000000 --- a/src/network/packets/swg/zone/object_controller/MessageQueueSecureTrade.java +++ /dev/null @@ -1,42 +0,0 @@ -package network.packets.swg.zone.object_controller; - -import com.projectswg.common.network.NetBuffer; - -public class MessageQueueSecureTrade extends ObjectController { - - public static final int CRC = 0x0115; - - private int tradeId; - private long trader; - private long reciever; - - public MessageQueueSecureTrade(int tradeId, long trader, long reciever) { - super(CRC); - this.tradeId = tradeId; - this.trader = trader; - this.reciever = reciever; - } - - public MessageQueueSecureTrade(NetBuffer data) { - super(CRC); - decode(data); - } - - @Override - public void decode(NetBuffer data) { - decodeHeader(data); - tradeId = data.getInt(); - trader = data.getLong(); - reciever = data.getLong(); - } - - @Override - public NetBuffer encode() { - NetBuffer data = NetBuffer.allocate(HEADER_LENGTH + 20); - encodeHeader(data); - data.addInt(tradeId); - data.addLong(trader); - data.addLong(reciever); - return data; - } -} \ No newline at end of file diff --git a/src/network/packets/swg/zone/object_controller/ObjectController.java b/src/network/packets/swg/zone/object_controller/ObjectController.java index 7dcd17181..ff07527ba 100644 --- a/src/network/packets/swg/zone/object_controller/ObjectController.java +++ b/src/network/packets/swg/zone/object_controller/ObjectController.java @@ -114,7 +114,7 @@ public abstract class ObjectController extends SWGPacket { case 0x04C5: return new IntendedTarget(data); case 0x00F5: return new MissionListRequest(data); case 0x041C: return new JTLTerminalSharedMessage(data); - case 0x0115: return new MessageQueueSecureTrade(data); + case 0x0115: return new SecureTrade(data); } Log.w("Unknown object controller: %08X", crc); return new GenericObjectController(crc, data); diff --git a/src/network/packets/swg/zone/object_controller/SecureTrade.java b/src/network/packets/swg/zone/object_controller/SecureTrade.java new file mode 100644 index 000000000..03e2ea267 --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/SecureTrade.java @@ -0,0 +1,89 @@ +package network.packets.swg.zone.object_controller; + +import com.projectswg.common.data.EnumLookup; +import com.projectswg.common.network.NetBuffer; + +public class SecureTrade extends ObjectController { + + public static final int CRC = 0x0115; + + private TradeMessageType type; + private long starterId; + private long accepterId; + + public SecureTrade(TradeMessageType type, long starterId, long accepterId) { + super(CRC); + this.type = type; + this.starterId = starterId; + this.accepterId = accepterId; + } + + public SecureTrade(NetBuffer data) { + super(CRC); + decode(data); + } + + @Override + public void decode(NetBuffer data) { + decodeHeader(data); + type = TradeMessageType.getTypeForInt(data.getInt()); + starterId = data.getLong(); + accepterId = data.getLong(); + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(HEADER_LENGTH + 20); + encodeHeader(data); + data.addInt(type.getId()); + data.addLong(starterId); + data.addLong(accepterId); + return data; + } + + public TradeMessageType getType() { + return type; + } + + public void setType(TradeMessageType type) { + this.type = type; + } + + public long getStarterId() { + return starterId; + } + + public long getAccepterId() { + return accepterId; + } + + public static enum TradeMessageType { + UNDEFINED (Integer.MIN_VALUE), + REQUEST_TRADE (0), + TRADE_REQUESTED (1), + ACCEPT_TRADE (2), + DENIED_TRADE (3), + DENIED_PLAYER_BUSY (4), + DENIED_PLAYER_UNREACHABLE (5), + REQUEST_TRADE_REVERSED (6), + LAST_TRADE_MESSAGE (7); + + private static final EnumLookup LOOKUP = new EnumLookup<>(TradeMessageType.class, t -> t.getId()); + + private int id; + + TradeMessageType(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public static TradeMessageType getTypeForInt(int id) { + return LOOKUP.getEnum(id, UNDEFINED); + } + } + + +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/AbortTradeMessage.java b/src/network/packets/swg/zone/trade/AbortTradeMessage.java new file mode 100644 index 000000000..419cae09b --- /dev/null +++ b/src/network/packets/swg/zone/trade/AbortTradeMessage.java @@ -0,0 +1,51 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class AbortTradeMessage extends SWGPacket { + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("AbortTradeMessage"); + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(6); + data.addShort(1); + data.addInt(CRC); + return data; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/AcceptTransactionMessage.java b/src/network/packets/swg/zone/trade/AcceptTransactionMessage.java new file mode 100644 index 000000000..b137c9d15 --- /dev/null +++ b/src/network/packets/swg/zone/trade/AcceptTransactionMessage.java @@ -0,0 +1,51 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class AcceptTransactionMessage extends SWGPacket { + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("AcceptTransactionMessage"); + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(6); + data.addShort(1); + data.addInt(CRC); + return data; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/AddItemFailedMessage.java b/src/network/packets/swg/zone/trade/AddItemFailedMessage.java new file mode 100644 index 000000000..971157192 --- /dev/null +++ b/src/network/packets/swg/zone/trade/AddItemFailedMessage.java @@ -0,0 +1,63 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class AddItemFailedMessage extends SWGPacket{ + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("AddItemFailedMessage"); + + private long objectId; + + public AddItemFailedMessage(long objectId) { + this.objectId = objectId; + } + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + objectId = data.getLong(); + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(14); + data.addShort(2); + data.addInt(CRC); + data.addLong(objectId); + return data; + } + + public long getObjectId() { + return objectId; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/AddItemMessage.java b/src/network/packets/swg/zone/trade/AddItemMessage.java new file mode 100644 index 000000000..7a1885692 --- /dev/null +++ b/src/network/packets/swg/zone/trade/AddItemMessage.java @@ -0,0 +1,66 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class AddItemMessage extends SWGPacket{ + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("AddItemMessage"); + + private long objectId; + + public AddItemMessage(long objectId) { + this.objectId = objectId; + } + + public AddItemMessage() { + } + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + objectId = data.getLong(); + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(14); + data.addShort(2); + data.addInt(CRC); + data.addLong(objectId); + return data; + } + + public long getObjectId() { + return objectId; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/BeginTradeMessage.java b/src/network/packets/swg/zone/trade/BeginTradeMessage.java new file mode 100644 index 000000000..59342c4f6 --- /dev/null +++ b/src/network/packets/swg/zone/trade/BeginTradeMessage.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class BeginTradeMessage extends SWGPacket { + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("BeginTradeMessage"); + + private long playerId; + + public BeginTradeMessage(long playerId) { + super(); + this.playerId = playerId; + } + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + playerId = data.getLong(); + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(14); + data.addShort(2); + data.addInt(CRC); + data.addLong(playerId); + return data; + } + + public long getPlayerId() { + return playerId; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/BeginVerificationMessage.java b/src/network/packets/swg/zone/trade/BeginVerificationMessage.java new file mode 100644 index 000000000..5ee9cf849 --- /dev/null +++ b/src/network/packets/swg/zone/trade/BeginVerificationMessage.java @@ -0,0 +1,51 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class BeginVerificationMessage extends SWGPacket { + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("BeginVerificationMessage"); + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(6); + data.addShort(1); + data.addInt(CRC); + return data; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/DenyTradeMessage.java b/src/network/packets/swg/zone/trade/DenyTradeMessage.java new file mode 100644 index 000000000..3ab8d321c --- /dev/null +++ b/src/network/packets/swg/zone/trade/DenyTradeMessage.java @@ -0,0 +1,51 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class DenyTradeMessage extends SWGPacket { + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("DenyTradeMessage"); + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(6); + data.addShort(1); + data.addInt(CRC); + return data; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/GiveMoneyMessage.java b/src/network/packets/swg/zone/trade/GiveMoneyMessage.java new file mode 100644 index 000000000..feddf2a53 --- /dev/null +++ b/src/network/packets/swg/zone/trade/GiveMoneyMessage.java @@ -0,0 +1,68 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class GiveMoneyMessage extends SWGPacket{ + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("GiveMoneyMessage"); + + private int moneyAmount; + + public GiveMoneyMessage(int moneyAmount) { + super(); + this.moneyAmount = moneyAmount; + } + + public GiveMoneyMessage() { + super(); + } + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + moneyAmount = data.getInt(); + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(10); + data.addShort(2); + data.addInt(CRC); + data.addInt(moneyAmount); + return data; + } + + public int getMoneyAmount() { + return moneyAmount; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/RemoveItemMessage.java b/src/network/packets/swg/zone/trade/RemoveItemMessage.java new file mode 100644 index 000000000..274070cc0 --- /dev/null +++ b/src/network/packets/swg/zone/trade/RemoveItemMessage.java @@ -0,0 +1,64 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class RemoveItemMessage extends SWGPacket{ + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("RemoveItemMessage"); + + private long objectId; + + public RemoveItemMessage(long objectId) { + super(); + this.objectId = objectId; + } + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + objectId = data.getLong(); + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(14); + data.addShort(2); + data.addInt(CRC); + data.addLong(objectId); + return data; + } + + public long getObjectId() { + return objectId; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/TradeCompleteMessage.java b/src/network/packets/swg/zone/trade/TradeCompleteMessage.java new file mode 100644 index 000000000..c21d69a7e --- /dev/null +++ b/src/network/packets/swg/zone/trade/TradeCompleteMessage.java @@ -0,0 +1,51 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class TradeCompleteMessage extends SWGPacket{ + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("TradeCompleteMessage"); + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(6); + data.addShort(1); + data.addInt(CRC); + return data; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/UnAcceptTransactionMessage.java b/src/network/packets/swg/zone/trade/UnAcceptTransactionMessage.java new file mode 100644 index 000000000..c61f6cd66 --- /dev/null +++ b/src/network/packets/swg/zone/trade/UnAcceptTransactionMessage.java @@ -0,0 +1,51 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class UnAcceptTransactionMessage extends SWGPacket { + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("UnAcceptTransactionMessage"); + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(6); + data.addShort(1); + data.addInt(CRC); + return data; + } +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/trade/VerifyTradeMessage.java b/src/network/packets/swg/zone/trade/VerifyTradeMessage.java new file mode 100644 index 000000000..4f82a5319 --- /dev/null +++ b/src/network/packets/swg/zone/trade/VerifyTradeMessage.java @@ -0,0 +1,51 @@ +/************************************************************************************ + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com * + * * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on * + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. * + * Our goal is to create an emulator which will provide a server for players to * + * continue playing a game similar to the one they used to play. We are basing * + * it on the final publish of the game prior to end-game events. * + * * + * This file is part of Holocore. * + * * + * -------------------------------------------------------------------------------- * + * * + * Holocore is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * Holocore is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with Holocore. If not, see . * + * * + ***********************************************************************************/ +package network.packets.swg.zone.trade; + +import com.projectswg.common.network.NetBuffer; + +import network.packets.swg.SWGPacket; + +public class VerifyTradeMessage extends SWGPacket { + + public static final int CRC = com.projectswg.common.data.CRC.getCrc("VerifyTradeMessage"); + + @Override + public void decode(NetBuffer data) { + if (!super.checkDecode(data, CRC)) + return; + } + + @Override + public NetBuffer encode() { + NetBuffer data = NetBuffer.allocate(6); + data.addShort(1); + data.addInt(CRC); + return data; + } +} \ No newline at end of file diff --git a/src/resources/commands/callbacks/QaToolCmdCallback.java b/src/resources/commands/callbacks/QaToolCmdCallback.java index d3ce2defb..d977e5d95 100644 --- a/src/resources/commands/callbacks/QaToolCmdCallback.java +++ b/src/resources/commands/callbacks/QaToolCmdCallback.java @@ -27,9 +27,12 @@ package resources.commands.callbacks; +import java.util.Map; + import com.projectswg.common.data.location.Location; import com.projectswg.common.data.location.Terrain; import com.projectswg.common.debug.Log; + import groovy.util.ResourceException; import groovy.util.ScriptException; import intents.chat.ChatBroadcastIntent; @@ -59,8 +62,6 @@ import services.objects.StaticItemService.ObjectCreationHandler; import services.player.PlayerManager; import utilities.Scripts; -import java.util.Map; - /** * Created by Waverunner on 8/19/2015 */ @@ -186,15 +187,19 @@ public class QaToolCmdCallback implements ICmdCallback { inputBox.display(player); } - private void recoverPlayer(ObjectManager objManager, PlayerManager playerManager, Player player, String args) { + private void recoverPlayer(ObjectManager objectManager, PlayerManager playerManager, Player player, String args) { args = args.trim(); - Player recoveree = playerManager.getPlayerByCreatureFirstName(args); - if (recoveree == null) { + long recoveree = playerManager.getCharacterIdByFirstName(args); + if (recoveree == 0) { sendSystemMessage(player, "Could not find player by first name: '" + args + "'"); return; } - CreatureObject obj = recoveree.getCreatureObject(); + SWGObject obj = objectManager.getObjectById(recoveree); + if (!(obj instanceof CreatureObject)) { + sendSystemMessage(player, "Object is not a creature: '" + args + "'"); + return; + } Location loc = new Location(3525, 4, -4807, Terrain.TATOOINE); new ObjectTeleportIntent(obj, loc).broadcast(); sendSystemMessage(player, "Sucessfully teleported " + obj.getObjectName() + " to " + loc.getPosition()); diff --git a/src/resources/containers/InventoryPermissions.java b/src/resources/containers/InventoryPermissions.java index 743a6cf13..4055ffeb6 100644 --- a/src/resources/containers/InventoryPermissions.java +++ b/src/resources/containers/InventoryPermissions.java @@ -28,6 +28,8 @@ package resources.containers; import resources.objects.SWGObject; +import resources.objects.creature.CreatureObject; +import services.trade.TradeSession; class InventoryPermissions extends DefaultPermissions { @@ -37,7 +39,9 @@ class InventoryPermissions extends DefaultPermissions { return true; if (container.getOwner() == null) return false; - return requester.getOwner().equals(container.getOwner()); + if (requester.getOwner().equals(container.getOwner())) + return true; + return canTradePartnerView(requester, container); } @Override @@ -48,4 +52,18 @@ class InventoryPermissions extends DefaultPermissions { return false; return requester.getOwner().equals(container.getOwner()); } -} + + private boolean canTradePartnerView(SWGObject requester, SWGObject container) { + CreatureObject creature = container.getOwner().getCreatureObject(); + if (creature == null) + return false; + if(container.getOwner() == null) + return false; + TradeSession session = creature.getTradeSession(); + if (session == null || !session.getFromItemList(creature).contains(container.getObjectId())) + return false; + CreatureObject partner = session.getTradePartner(creature); + return partner != null && partner.equals(requester); + } + +} \ No newline at end of file diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 8bb33d16d..4a698d3dd 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -295,6 +295,10 @@ public abstract class SWGObject extends BaselineObject implements Comparable getSlots() { return new HashMap<>(slots); } diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index f0ce20945..065c4719d 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -63,6 +63,7 @@ import resources.objects.weapon.WeaponObject; import resources.persistable.SWGObjectFactory; import resources.player.Player; import services.group.GroupInviterData; +import services.trade.TradeSession; public class CreatureObject extends TangibleObject { @@ -83,6 +84,7 @@ public class CreatureObject extends TangibleObject { private int battleFatigue = 0; private long statesBitmask = 0; private long lastTransform = 0; + private TradeSession tradeSession = null; private SWGSet skills = new SWGSet(1, 3, StringType.ASCII); @@ -265,8 +267,16 @@ public class CreatureObject extends TangibleObject { public boolean isLoggedOutPlayer() { return getOwner() == null && isPlayer(); - } + } + public TradeSession getTradeSession() { + return tradeSession; + } + + public void setTradeSession(TradeSession tradeSession) { + this.tradeSession = tradeSession; + } + public void setPosture(Posture posture) { this.posture = posture; sendDelta(3, 13, posture.getId()); diff --git a/src/services/commands/EntertainmentService.java b/src/services/commands/EntertainmentService.java index 12fc47830..8f9137144 100644 --- a/src/services/commands/EntertainmentService.java +++ b/src/services/commands/EntertainmentService.java @@ -454,7 +454,7 @@ public class EntertainmentService extends Service { PerformanceData performanceData = performanceMap.get(performanceName); int flourishXpMod = performanceData.getFlourishXpMod(); int performanceCounter = performer.getPerformanceCounter(); - int xpGained = (int) (performanceCounter * (flourishXpMod * 3.8)); + int xpGained = (int) (performanceCounter * flourishXpMod); if(xpGained > 0) { new ExperienceIntent(performer, "entertainer", xpGained).broadcast(); diff --git a/src/services/galaxy/GalacticManager.java b/src/services/galaxy/GalacticManager.java index 0110f1313..3de254f75 100644 --- a/src/services/galaxy/GalacticManager.java +++ b/src/services/galaxy/GalacticManager.java @@ -46,6 +46,7 @@ import services.galaxy.travel.TravelService; import services.objects.ObjectManager; import services.objects.UniformBoxService; import services.player.PlayerManager; +import services.trade.TradeService; public class GalacticManager extends Manager { @@ -56,6 +57,7 @@ public class GalacticManager extends Manager { private final TravelService travelService; private final DeveloperService developerService; private final UniformBoxService uniformBox; + private final TradeService tradeService; private final Map prevIntentMap; public GalacticManager() { @@ -66,8 +68,9 @@ public class GalacticManager extends Manager { travelService = new TravelService(); developerService = new DeveloperService(); uniformBox = new UniformBoxService(); + tradeService = new TradeService(); prevIntentMap = new SynchronizedMap<>(); - + addChildService(objectManager); addChildService(playerManager); addChildService(gameManager); @@ -75,6 +78,7 @@ public class GalacticManager extends Manager { addChildService(travelService); addChildService(developerService); addChildService(uniformBox); + addChildService(tradeService); registerForIntent(InboundPacketIntent.class, ipi -> handleInboundPacketIntent(ipi)); registerForIntent(ConnectionOpenedIntent.class, coi -> handleConnectionOpenedIntent(coi)); diff --git a/src/services/objects/ObjectAwareness.java b/src/services/objects/ObjectAwareness.java index 73889f9d1..4753664fa 100644 --- a/src/services/objects/ObjectAwareness.java +++ b/src/services/objects/ObjectAwareness.java @@ -170,26 +170,26 @@ public class ObjectAwareness extends Service implements TerrainMapCallback { } } - private void processGalacticPacketIntent(GalacticPacketIntent i) { - Packet packet = i.getPacket(); + private void processGalacticPacketIntent(GalacticPacketIntent gpi) { + Packet packet = gpi.getPacket(); if (packet instanceof DataTransform) { - handleDataTransform((DataTransform) packet, i.getObjectManager()); + handleDataTransform((DataTransform) packet, gpi.getObjectManager()); } else if (packet instanceof DataTransformWithParent) { - handleDataTransformWithParent((DataTransformWithParent) packet, i.getObjectManager()); + handleDataTransformWithParent((DataTransformWithParent) packet, gpi.getObjectManager()); } else if (packet instanceof CmdSceneReady) { - handleCmdSceneReady(i.getPlayer(), (CmdSceneReady) packet); + handleCmdSceneReady(gpi.getPlayer(), (CmdSceneReady) packet); } } - private void processMoveObjectIntent(MoveObjectIntent i) { - moveObjectWithTransform(i.getObject(), i.getParent(), i.getNewLocation(), i.getSpeed(), i.getUpdateCounter()); + private void processMoveObjectIntent(MoveObjectIntent moi) { + moveObjectWithTransform(moi.getObject(), moi.getParent(), moi.getNewLocation(), moi.getSpeed(), moi.getUpdateCounter()); } - private void processContainerTransferIntent(ContainerTransferIntent i) { - SWGObject obj = i.getObject(); + private void processContainerTransferIntent(ContainerTransferIntent cti) { + SWGObject obj = cti.getObject(); Assert.notNull(obj); Assert.notNull(obj.getTerrain()); - moveObject(obj, i.getContainer(), obj.getLocation()); + moveObject(obj, cti.getContainer(), obj.getLocation()); } private void handleZoneIn(CreatureObject creature, Player player, Location loc, SWGObject parent) { diff --git a/src/services/player/LoginService.java b/src/services/player/LoginService.java index dccdf42ba..a8722a452 100644 --- a/src/services/player/LoginService.java +++ b/src/services/player/LoginService.java @@ -83,6 +83,7 @@ public class LoginService extends Service { private RelationalDatabase database; private PreparedStatement getUser; private PreparedStatement getCharacter; + private PreparedStatement getCharacterFirstName; private PreparedStatement getCharacters; private PreparedStatement deleteCharacter; @@ -96,6 +97,7 @@ public class LoginService extends Service { database = RelationalServerFactory.getServerDatabase("login/login.db"); getUser = database.prepareStatement("SELECT * FROM users WHERE LOWER(username) = LOWER(?)"); getCharacter = database.prepareStatement("SELECT id FROM players WHERE LOWER(name) = ?"); + getCharacterFirstName = database.prepareStatement("SELECT id FROM players WHERE LOWER(name) = ? OR LOWER(name) LIKE ?"); getCharacters = database.prepareStatement("SELECT * FROM players WHERE userid = ?"); deleteCharacter = database.prepareStatement("DELETE FROM players WHERE id = ?"); return super.initialize(); @@ -107,6 +109,24 @@ public class LoginService extends Service { return super.terminate(); } + public long getCharacterIdByFirstName(String name) { + Assert.notNull(name); + name = name.trim().toLowerCase(Locale.US); + Assert.test(!name.isEmpty()); + synchronized (getCharacterFirstName) { + try { + getCharacterFirstName.setString(1, name + "%"); + try (ResultSet set = getCharacterFirstName.executeQuery()) { + if (set.next()) + return set.getLong("id"); + } + } catch (SQLException e) { + Log.e(e); + } + } + return 0; + } + public long getCharacterId(String name) { Assert.notNull(name); name = name.trim().toLowerCase(Locale.US); diff --git a/src/services/player/PlayerManager.java b/src/services/player/PlayerManager.java index 9f8790388..9d96774ee 100644 --- a/src/services/player/PlayerManager.java +++ b/src/services/player/PlayerManager.java @@ -102,6 +102,12 @@ public class PlayerManager extends Manager { return null; } + public long getCharacterIdByFirstName(String name) { + Assert.notNull(name); + Assert.test(!name.trim().isEmpty()); + return loginService.getCharacterIdByFirstName(name); + } + public long getCharacterIdByName(String name) { Assert.notNull(name); Assert.test(!name.trim().isEmpty()); diff --git a/src/services/player/creation/CharacterCreation.java b/src/services/player/creation/CharacterCreation.java index ee24d0524..10a3a7807 100644 --- a/src/services/player/creation/CharacterCreation.java +++ b/src/services/player/creation/CharacterCreation.java @@ -77,7 +77,6 @@ public class CharacterCreation { setPlayerObjectValues(playerObj); createHair(creatureObj, create.getHair(), create.getHairCustomization()); createStarterClothing(creatureObj, create.getRace()); - playerObj.setAdminTag(accessLevel); new ObjectCreatedIntent(creatureObj).broadcast(); return creatureObj; @@ -151,6 +150,8 @@ public class CharacterCreation { creatureObj.setObjectName(create.getName()); creatureObj.setPvpFlags(PvpFlag.PLAYER); creatureObj.setVolume(0x000F4240); + creatureObj.setBankBalance(1000); + creatureObj.setCashBalance(100); new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, create.getStartingPhase(), creatureObj, true).broadcast(); new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, "species_" + creatureObj.getRace().getSpecies(), creatureObj, true).broadcast(); @@ -161,7 +162,7 @@ public class CharacterCreation { defWeapon.setMinDamage(50); defWeapon.setMaxDamage(100); creatureObj.setEquippedWeapon(defWeapon); - createInventoryObject(creatureObj, "object/tangible/inventory/shared_character_inventory.iff"); + createDefaultObject(creatureObj, "object/tangible/inventory/shared_character_inventory.iff"); createInventoryObject(creatureObj, "object/tangible/datapad/shared_character_datapad.iff"); createInventoryObject(creatureObj, "object/tangible/inventory/shared_appearance_inventory.iff"); createInventoryObject(creatureObj, "object/tangible/bank/shared_character_bank.iff"); diff --git a/src/services/trade/TradeService.java b/src/services/trade/TradeService.java new file mode 100644 index 000000000..27428b6a8 --- /dev/null +++ b/src/services/trade/TradeService.java @@ -0,0 +1,269 @@ +package services.trade; + +import java.util.ArrayList; +import java.util.List; + +import com.projectswg.common.control.Service; +import com.projectswg.common.debug.Log; + +import intents.PlayerEventIntent; +import intents.chat.ChatBroadcastIntent; +import intents.network.GalacticPacketIntent; +import network.packets.Packet; +import network.packets.swg.zone.object_controller.SecureTrade; +import network.packets.swg.zone.object_controller.SecureTrade.TradeMessageType; +import network.packets.swg.zone.trade.AbortTradeMessage; +import network.packets.swg.zone.trade.AcceptTransactionMessage; +import network.packets.swg.zone.trade.AddItemMessage; +import network.packets.swg.zone.trade.BeginTradeMessage; +import network.packets.swg.zone.trade.BeginVerificationMessage; +import network.packets.swg.zone.trade.DenyTradeMessage; +import network.packets.swg.zone.trade.GiveMoneyMessage; +import network.packets.swg.zone.trade.RemoveItemMessage; +import network.packets.swg.zone.trade.TradeCompleteMessage; +import network.packets.swg.zone.trade.UnAcceptTransactionMessage; +import network.packets.swg.zone.trade.VerifyTradeMessage; +import resources.Posture; +import resources.containers.ContainerPermissionsType; +import resources.objects.SWGObject; +import resources.objects.creature.CreatureObject; +import resources.player.Player; +import resources.sui.SuiButtons; +import resources.sui.SuiMessageBox; +import services.objects.ObjectManager; + +public class TradeService extends Service { + + private final List tradeSessions; + + public TradeService() { + tradeSessions = new ArrayList(); + + registerForIntent(GalacticPacketIntent.class, this::handleGalacticPacketIntent); + registerForIntent(PlayerEventIntent.class, this::handlePlayerEventIntent); + } + + @Override + public boolean stop() { + for (TradeSession tradeSession : tradeSessions) { + tradeSession.sendAbortTrade(); + } + return super.stop(); + } + + private void handlePlayerEventIntent(PlayerEventIntent pei) { + if (pei.getPlayer().getCreatureObject() == null) + return; + TradeSession session = pei.getPlayer().getCreatureObject().getTradeSession(); + if (session == null) + return; + + switch (pei.getEvent()) { + case PE_FIRST_ZONE: + case PE_LOGGED_OUT: + session.sendAbortTrade(); + break; + default: + break; + } + } + + private void handleGalacticPacketIntent(GalacticPacketIntent gpi) { + Packet packet = gpi.getPacket(); + + if (packet instanceof SecureTrade) { + handleSecureTrade((SecureTrade) packet,gpi.getPlayer(), gpi.getObjectManager()); + } else if (packet instanceof AbortTradeMessage){ + handleAbortTradeMessage(gpi.getPlayer()); + } else if (packet instanceof DenyTradeMessage){ + handleDenyTradeMessage(gpi.getPlayer()); + } else if (packet instanceof AcceptTransactionMessage){ + handleAcceptTransactionMessage(gpi.getPlayer()); + } else if (packet instanceof UnAcceptTransactionMessage){ + handleUnAcceptTransactionMessage(gpi.getPlayer()); + } else if (packet instanceof AddItemMessage){ + handleAddItemMessage((AddItemMessage) packet, gpi.getPlayer(), gpi.getObjectManager()); + } else if (packet instanceof GiveMoneyMessage){ + handleGiveMoneyMessage((GiveMoneyMessage) packet, gpi.getPlayer()); + } else if (packet instanceof BeginVerificationMessage){ + handleBeginVerificationMessage(gpi.getPlayer()); + } else if (packet instanceof VerifyTradeMessage){ + handleVerifyTradeMessage(gpi.getPlayer(), gpi.getObjectManager()); + } else if (packet instanceof TradeCompleteMessage){ + handleTradeCompleteMessage(gpi.getPlayer()); + } + } + + private void handleSecureTrade(SecureTrade packet, Player player, ObjectManager objectManager) { + CreatureObject initiator = player.getCreatureObject(); + SWGObject accepterObject = objectManager.getObjectById(packet.getAccepterId()); + CreatureObject accepter; + if (!(accepterObject instanceof CreatureObject) || !((CreatureObject) accepterObject).isPlayer()) { + sendSystemMessage(initiator.getOwner(), "start_fail_target_not_player"); + return; + } + accepter = (CreatureObject) accepterObject; + + if(initiator.isInCombat() || accepter.isInCombat()){ + return; + } + + if(initiator.getPosture() == Posture.INCAPACITATED || accepter.getPosture() == Posture.INCAPACITATED){ + sendSystemMessage(initiator.getOwner(), "player_incapacitated"); + return; + } + + if(initiator.getPosture() == Posture.DEAD || accepter.getPosture() == Posture.DEAD){ + sendSystemMessage(initiator.getOwner(), "player_dead"); + return; + } + + TradeSession tradeSession = new TradeSession(initiator, accepter); + tradeSessions.add(tradeSession); + initiator.setTradeSession(tradeSession); + handleTradeSessionRequest(packet, player, initiator, accepter); + Log.d("Trade Session Request. Type=%s Initiator=%s Receipient=%s PacketSenderID: %d", packet.getType(), initiator, accepter, player.getCreatureObject().getObjectId()); + } + + private void handleAbortTradeMessage(Player player) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + + if(tradeSession == null) + return; + + tradeSession.sendAbortTrade(); + } + + private void handleDenyTradeMessage(Player player) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + + if(tradeSession == null) + return; + + tradeSession.sendToPartner(player.getCreatureObject(), new DenyTradeMessage()); + } + + private void handleAcceptTransactionMessage(Player player) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + + if(tradeSession == null) + return; + + tradeSession.sendToPartner(player.getCreatureObject(), new AcceptTransactionMessage()); + } + + private void handleUnAcceptTransactionMessage(Player player) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + + if(tradeSession == null) + return; + + tradeSession.sendToPartner(player.getCreatureObject(), new UnAcceptTransactionMessage()); + } + + private void handleAddItemMessage(AddItemMessage packet, Player player, ObjectManager objectManager) { + CreatureObject creature = player.getCreatureObject(); + TradeSession tradeSession = creature.getTradeSession(); + if (tradeSession == null) { + Log.w("Invalid TradeSession for handleAddItemMessage. Creature %s: ", creature); + return; + } + + SWGObject tradeObject = objectManager.getObjectById(packet.getObjectId()); + if(creature.hasSlottedObject(tradeObject)){ + tradeSession.sendAbortTrade(); + return; + } + + if(tradeObject.hasAttribute("no_trade")){ + sendSystemMessage(player, "add_item_failed_prose"); + tradeSession.sendAbortTrade(); + } + + tradeObject.setContainerPermissions(ContainerPermissionsType.INVENTORY); + tradeSession.addItem(creature, tradeObject); + tradeSession.sendToPartner(creature, new AddItemMessage(packet.getObjectId())); + tradeSession.getTradePartner(creature).addCustomAware(tradeObject); + } + + private void handleGiveMoneyMessage(GiveMoneyMessage packet, Player player) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + tradeSession.setMoneyAmount(player.getCreatureObject(), packet.getMoneyAmount()); + tradeSession.sendToPartner(player.getCreatureObject(), new GiveMoneyMessage(packet.getMoneyAmount())); + } + + private void handleVerifyTradeMessage(Player player, ObjectManager objectManager) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + CreatureObject creature = player.getCreatureObject(); + CreatureObject initiator = tradeSession.getInitiator(); + CreatureObject accepter = tradeSession.getAccepter(); + + if(creature.equals(accepter) && !tradeSession.isAccepterVerified()){ + accepter.sendSelf(new VerifyTradeMessage()); + tradeSession.setAccepterVerified(true); + } + + if(creature.equals(initiator) && !tradeSession.isInitiatorVerified()){ + initiator.sendSelf(new VerifyTradeMessage()); + tradeSession.setInititatorVerified(true); + } + + if (!tradeSession.isInitiatorVerified() || !tradeSession.isAccepterVerified()) + return; + + tradeSession.moveToPartnerInventory(accepter, tradeSession.getFromItemList(accepter)); + tradeSession.moveToPartnerInventory(initiator, tradeSession.getFromItemList(initiator)); + + long initiatorTransfer = tradeSession.getMoneyAmount(initiator); + long accepterTransfer = tradeSession.getMoneyAmount(accepter); + + initiator.setCashBalance(initiator.getCashBalance() + accepterTransfer - initiatorTransfer); + accepter.setCashBalance(accepter.getCashBalance() + initiatorTransfer - accepterTransfer); + + accepter.sendSelf(new TradeCompleteMessage()); + initiator.sendSelf(new TradeCompleteMessage()); + } + + private void handleTradeCompleteMessage(Player player) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + tradeSession.sendToPartner(player.getCreatureObject(), new TradeCompleteMessage()); + tradeSession.getAccepter().setTradeSession(null); + tradeSession.getInitiator().setTradeSession(null); + } + + private void handleBeginVerificationMessage(Player player) { + TradeSession tradeSession = player.getCreatureObject().getTradeSession(); + tradeSession.getAccepter().sendSelf(new VerifyTradeMessage()); + tradeSession.getInitiator().sendSelf(new VerifyTradeMessage()); + } + + private void handleTradeSessionRequest(SecureTrade packet, Player packetSender , CreatureObject initiator, CreatureObject accepter) { + SuiMessageBox requestBox = new SuiMessageBox(SuiButtons.OK_CANCEL, "Trade Request", accepter.getOwner().getCharacterName() + " wants to trade with you.\nDo you want to accept the request?"); + requestBox.display(accepter.getOwner()); + requestBox.addOkButtonCallback("handleTradeRequest", (player, actor, event, paramenters)-> { + if(initiator.getTradeSession() == null) + return; + + accepter.setTradeSession(initiator.getTradeSession()); + accepter.sendSelf(new SecureTrade(TradeMessageType.REQUEST_TRADE, initiator.getObjectId(), accepter.getObjectId())); + initiator.sendSelf(new SecureTrade(TradeMessageType.REQUEST_TRADE, initiator.getObjectId(), accepter.getObjectId())); + initiator.sendSelf(new BeginTradeMessage(accepter.getObjectId())); + accepter.sendSelf(new BeginTradeMessage(initiator.getObjectId())); + Log.d("Trade Session Request. Type=%s Initiator=%d Receipient=%d PacketSenderID: %d", packet.getType(), packet.getStarterId(), packet.getAccepterId(), player.getCreatureObject().getObjectId()); + }); + requestBox.addCancelButtonCallback("handleTradeRequestDeny", (player, actor, event, paramenters)-> { + if(packetSender.getCreatureObject().equals(initiator)){ + initiator.sendSelf(new DenyTradeMessage()); + initiator.sendSelf(new AbortTradeMessage()); + } else { + accepter.sendSelf(new DenyTradeMessage()); + accepter.sendSelf(new AbortTradeMessage()); + } + }); + Log.i("Player: %s sent TradeRequest to Player %s", initiator.getOwner().getCharacterName(), accepter.getOwner().getCharacterName()); + } + + private void sendSystemMessage(Player player, String str) { + new ChatBroadcastIntent(player, "@ui_trade:" + str).broadcast(); + } +} \ No newline at end of file diff --git a/src/services/trade/TradeSession.java b/src/services/trade/TradeSession.java new file mode 100644 index 000000000..e0cdf5108 --- /dev/null +++ b/src/services/trade/TradeSession.java @@ -0,0 +1,164 @@ +package services.trade; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import com.projectswg.common.debug.Assert; + +import network.packets.swg.SWGPacket; +import network.packets.swg.zone.trade.AbortTradeMessage; +import network.packets.swg.zone.trade.TradeCompleteMessage; +import resources.objects.SWGObject; +import resources.objects.creature.CreatureObject; +import resources.player.Player; + +public class TradeSession { + + private final List initiatorTradeItems; + private final List accepterTradeItems; + private final CreatureObject initiator; + private final CreatureObject accepter; + private final AtomicInteger initiatorMoneyAmount; + private final AtomicInteger accepterMoneyAmount; + private final AtomicBoolean initiatorVerified; + private final AtomicBoolean accepterVerified; + + public TradeSession(CreatureObject initiator, CreatureObject accepter) { + this.initiatorTradeItems = new ArrayList<>(); + this.accepterTradeItems = new ArrayList<>(); + this.initiator = Objects.requireNonNull(initiator, "Initiator cannot be null!"); + this.accepter = Objects.requireNonNull(accepter, "Accepter cannot be null!"); + this.initiatorMoneyAmount = new AtomicInteger(); + this.accepterMoneyAmount = new AtomicInteger(); + this.initiatorVerified = new AtomicBoolean(); + this.accepterVerified = new AtomicBoolean(); + } + + public void removeFromItemList(CreatureObject requester, long objectId) { + Assert.test(isInTradeSession(requester), "Creature is not a part of this trade session!"); + if(isInitiator(requester)){ + synchronized (initiatorTradeItems) { + initiatorTradeItems.remove(objectId); + } + + } else { + synchronized (accepterTradeItems) { + accepterTradeItems.remove(objectId); + } + } + } + + public CreatureObject getTradePartner(CreatureObject creature) { + Assert.test(isInTradeSession(creature), "Creature is not a part of this trade session!"); + if(isInitiator(creature)){ + return accepter; + } else { + return initiator; + } + } + + public List getFromItemList(CreatureObject creature) { + Assert.test(isInTradeSession(creature), "Creature is not a part of this trade session!"); + if(isInitiator(creature)){ + return Collections.unmodifiableList(initiatorTradeItems); + } else { + return Collections.unmodifiableList(accepterTradeItems); + } + } + + public CreatureObject getInitiator() { + return initiator; + } + + public CreatureObject getAccepter() { + return accepter; + } + + public void addItem(CreatureObject creature, SWGObject tradeObject) { + Assert.test(isInTradeSession(creature), "Creature is not a part of this trade session!"); + if(isInitiator(creature)){ + synchronized (initiatorTradeItems) { + initiatorTradeItems.add(tradeObject); + } + } else { + synchronized (accepterTradeItems) { + accepterTradeItems.add(tradeObject); + } + } + } + + public void sendToPartner(CreatureObject creature, SWGPacket packet) { + Assert.test(isInTradeSession(creature), "Creature is not a part of this trade session!"); + if(isInitiator(creature)){ + getAccepter().getOwner().sendPacket(packet); + } else { + getInitiator().getOwner().sendPacket(packet); + } + } + + public void setMoneyAmount(CreatureObject creature, int amount){ + Assert.test(isInTradeSession(creature), "Creature is not a part of this trade session!"); + if(isInitiator(creature)){ + initiatorMoneyAmount.set(amount); + } else { + accepterMoneyAmount.set(amount); + } + } + + public int getMoneyAmount(CreatureObject creature) { + Assert.test(isInTradeSession(creature), "Creature is not a part of this trade session!"); + if(isInitiator(creature)){ + return initiatorMoneyAmount.get(); + } else { + return accepterMoneyAmount.get(); + } + } + + public void moveToPartnerInventory(CreatureObject partner, List fromItemList) { + for (SWGObject tradeObject : fromItemList) { + tradeObject.moveToContainer(getTradePartner(partner).getSlottedObject("inventory")); + } + } + + public boolean isInitiatorVerified() { + return initiatorVerified.get(); + } + + public boolean isAccepterVerified() { + return accepterVerified.get(); + } + + public void setInititatorVerified(boolean initiatorVerfified){ + this.initiatorVerified.set(initiatorVerfified); + } + + public void setAccepterVerified(boolean accepterVerified){ + this.accepterVerified.set(accepterVerified); + } + + public void sendAbortTrade() { + Player accepter = this.accepter.getOwner(); + Player initiator = this.initiator.getOwner(); + if (accepter != null) + accepter.sendPacket(new AbortTradeMessage(), new TradeCompleteMessage()); + if (initiator != null) + initiator.sendPacket(new AbortTradeMessage(), new TradeCompleteMessage()); + + if (initiator.getCreatureObject() != null) + initiator.getCreatureObject().setTradeSession(null); + if (accepter.getCreatureObject() != null) + accepter.getCreatureObject().setTradeSession(null); + } + + private boolean isInitiator(CreatureObject creature) { + return creature.equals(initiator); + } + + private boolean isInTradeSession(CreatureObject creature) { + return isInitiator(creature) || (accepter != null && creature.equals(accepter)); + } +} \ No newline at end of file