From 47231d7f4d10b1c0cecb3020d3d7ca6aa0f8143d Mon Sep 17 00:00:00 2001 From: Obique Date: Sat, 2 May 2015 11:56:03 -0500 Subject: [PATCH] Merged Engine into the Core! Woooo open source --- .classpath | 3 +- src/intents/CloseConnectionIntent.java | 46 ++ src/intents/InboundPacketIntent.java | 46 ++ src/intents/InboundUdpPacketIntent.java | 36 + src/intents/LoginEventIntent.java | 42 ++ src/intents/OutboundPacketIntent.java | 35 + src/intents/OutboundUdpPacketIntent.java | 36 + src/intents/PingIntent.java | 13 + src/intents/ServerStatusIntent.java | 44 ++ .../SWGObjectEventIntent.java | 39 + .../SWGObjectMovedIntent.java | 23 + src/main/ProjectSWG.java | 2 +- src/network/FragmentedHandler.java | 83 +++ src/network/InboundNetworkHandler.java | 166 +++++ src/network/NetworkClient.java | 100 +++ src/network/NetworkProtocol.java | 128 ++++ src/network/OutboundNetworkHandler.java | 232 ++++++ src/network/OutboundPacketService.java | 163 ++++ src/network/PacketType.java | 182 +++++ src/network/encryption/Encryption.java | 116 +++ src/network/encryption/EncryptionCRC.java | 76 ++ src/network/encryption/MD5.java | 30 + src/network/packets/Packet.java | 185 +++++ src/network/packets/soe/Acknowledge.java | 41 + .../soe/ClientNetworkStatusUpdate.java | 80 ++ src/network/packets/soe/DataChannelA.java | 141 ++++ src/network/packets/soe/Disconnect.java | 78 ++ src/network/packets/soe/Fragmented.java | 114 +++ src/network/packets/soe/MultiPacket.java | 113 +++ src/network/packets/soe/OutOfOrder.java | 37 + .../soe/ServerNetworkStatusUpdate.java | 69 ++ src/network/packets/soe/SessionRequest.java | 49 ++ src/network/packets/soe/SessionResponse.java | 76 ++ src/network/packets/swg/ErrorMessage.java | 40 + src/network/packets/swg/SWGPacket.java | 77 ++ .../packets/swg/ServerUnixEpochTime.java | 36 + .../packets/swg/login/AccountFeatureBits.java | 33 + .../swg/login/CharacterCreationDisabled.java | 50 ++ .../packets/swg/login/ClientIdMsg.java | 53 ++ .../swg/login/ClientPermissionsMessage.java | 53 ++ .../swg/login/EnumerateCharacterId.java | 109 +++ .../packets/swg/login/LoginClientId.java | 54 ++ .../packets/swg/login/LoginClientToken.java | 65 ++ .../packets/swg/login/LoginClusterStatus.java | 92 +++ .../packets/swg/login/LoginEnumCluster.java | 73 ++ .../swg/login/LoginIncorrectClientId.java | 43 ++ .../swg/login/OfflineServersMessage.java | 60 ++ .../swg/login/RequestExtendedClusters.java | 28 + src/network/packets/swg/login/ServerId.java | 39 + .../packets/swg/login/ServerString.java | 39 + .../swg/login/StationIdHasJediSlot.java | 40 + .../login/creation/ClientCreateCharacter.java | 98 +++ .../ClientVerifyAndLockNameRequest.java | 41 + .../ClientVerifyAndLockNameResponse.java | 62 ++ .../creation/CreateCharacterFailure.java | 60 ++ .../creation/CreateCharacterSuccess.java | 37 + .../creation/DeleteCharacterRequest.java | 41 + .../creation/DeleteCharacterResponse.java | 34 + .../swg/login/creation/RandomNameRequest.java | 32 + .../login/creation/RandomNameResponse.java | 53 ++ .../packets/swg/zone/ChatRequestRoomList.java | 27 + .../packets/swg/zone/CmdSceneReady.java | 27 + .../zone/ConnectPlayerResponseMessage.java | 33 + .../swg/zone/GalaxyLoopTimesRequest.java | 27 + .../swg/zone/GalaxyLoopTimesResponse.java | 34 + .../packets/swg/zone/HeartBeatMessage.java | 28 + .../swg/zone/OpenedContainerMessage.java | 43 ++ .../packets/swg/zone/ParametersMessage.java | 29 + .../swg/zone/SceneCreateObjectByCrc.java | 53 ++ .../packets/swg/zone/SceneDestroyObject.java | 44 ++ .../packets/swg/zone/SceneEndBaselines.java | 37 + .../packets/swg/zone/ServerTimeMessage.java | 38 + .../packets/swg/zone/SetWaypointColor.java | 31 + .../swg/zone/UpdateContainmentMessage.java | 47 ++ .../swg/zone/UpdatePostureMessage.java | 44 ++ .../swg/zone/UpdatePvpStatusMessage.java | 58 ++ .../swg/zone/UpdateTransformsMessage.java | 78 ++ .../auction/AuctionQueryHeadersMessage.java | 35 + .../AuctionQueryHeadersResponseMessage.java | 222 ++++++ .../auction/CancelLiveAuctionMessage.java | 35 + .../CancelLiveAuctionResponseMessage.java | 35 + .../swg/zone/auction/GetAuctionDetails.java | 39 + .../auction/GetAuctionDetailsResponse.java | 65 ++ .../auction/IsVendorOwnerResponseMessage.java | 35 + .../auction/RetrieveAuctionItemMessage.java | 35 + .../RetrieveAuctionItemResponseMessage.java | 35 + .../packets/swg/zone/baselines/Baseline.java | 77 ++ .../packets/swg/zone/baselines/CREO3.java | 81 ++ .../packets/swg/zone/baselines/CREO6.java | 106 +++ .../packets/swg/zone/baselines/CREO8.java | 22 + .../packets/swg/zone/baselines/CREO9.java | 22 + .../packets/swg/zone/baselines/PLAY6.java | 28 + .../packets/swg/zone/baselines/PLAY9.java | 86 +++ .../building/UpdateCellPermissionMessage.java | 47 ++ .../chat/ChatDeletePersistentMessage.java | 21 + .../swg/zone/chat/ChatFriendsListUpdate.java | 47 ++ .../packets/swg/zone/chat/ChatIgnoreList.java | 86 +++ .../chat/ChatInstantMessageToCharacter.java | 73 ++ .../zone/chat/ChatInstantMessageToClient.java | 67 ++ .../swg/zone/chat/ChatOnConnectAvatar.java | 35 + .../swg/zone/chat/ChatOnDestroyRoom.java | 58 ++ .../swg/zone/chat/ChatOnEnteredRoom.java | 78 ++ .../swg/zone/chat/ChatOnLeaveRoom.java | 57 ++ .../chat/ChatOnReceiveRoomInvitation.java | 35 + .../zone/chat/ChatOnSendInstantMessage.java | 59 ++ .../chat/ChatOnSendPersistentMessage.java | 27 + .../swg/zone/chat/ChatOnSendRoomMessage.java | 38 + .../chat/ChatPersistentMessageToClient.java | 334 +++++++++ .../chat/ChatPersistentMessageToServer.java | 102 +++ .../chat/ChatRequestPersistentMessage.java | 21 + .../swg/zone/chat/ChatRoomMessage.java | 51 ++ .../swg/zone/chat/ChatSystemMessage.java | 80 ++ .../swg/zone/chat/ConGenericMessage.java | 41 + .../swg/zone/chat/VoiceChatStatus.java | 33 + .../swg/zone/combat/GrantCommandMessage.java | 47 ++ .../swg/zone/deltas/DeltasMessage.java | 69 ++ .../swg/zone/insertion/ChatRoomList.java | 209 ++++++ .../swg/zone/insertion/ChatServerStatus.java | 34 + .../swg/zone/insertion/CmdStartScene.java | 73 ++ .../zone/insertion/ConnectPlayerMessage.java | 28 + .../swg/zone/insertion/SelectCharacter.java | 36 + .../CommandQueueDequeue.java | 52 ++ .../CommandQueueEnqueue.java | 50 ++ .../zone/object_controller/DataTransform.java | 77 ++ .../object_controller/ObjectController.java | 70 ++ .../object_controller/ObjectMenuRequest.java | 79 ++ .../object_controller/ObjectMenuResponse.java | 79 ++ .../zone/object_controller/PlayerEmote.java | 56 ++ .../zone/object_controller/PostureUpdate.java | 41 + .../zone/object_controller/SitOnObject.java | 61 ++ .../zone/object_controller/SpatialChat.java | 102 +++ .../zone/server_ui/SuiCreatePageMessage.java | 123 +++ .../zone/server_ui/SuiEventNotification.java | 47 ++ .../zone/spatial/AttributeListMessage.java | 64 ++ .../zone/spatial/GetMapLocationsMessage.java | 60 ++ .../GetMapLocationsResponseMessage.java | 32 + .../NewTicketActivityResponseMessage.java | 35 + .../StopClientEffectObjectByLabelMessage.java | 45 ++ src/resources/Attributes.java | 26 + src/resources/Galaxy.java | 80 ++ src/resources/Location.java | 202 +++++ src/resources/Posture.java | 45 ++ src/resources/Race.java | 121 +++ src/resources/RadialOption.java | 29 + src/resources/SortedLinkedList.java | 54 ++ src/resources/Terrain.java | 155 ++++ src/resources/client_info/ClientFactory.java | 252 +++++++ .../client_info/visitors/ClientData.java | 8 + .../visitors/CrcStringTableData.java | 69 ++ .../client_info/visitors/DatatableData.java | 171 +++++ .../client_info/visitors/ObjectData.java | 133 ++++ .../visitors/ProfTemplateData.java | 61 ++ .../visitors/SlotArrangementData.java | 29 + .../visitors/SlotDefinitionData.java | 55 ++ .../visitors/SlotDescriptorData.java | 28 + src/resources/collections/SWGList.java | 229 ++++++ src/resources/collections/SWGMap.java | 224 ++++++ .../callbacks/SitOnObjectCmdCallback.java | 2 - src/resources/common/CRC.java | 152 ++++ src/resources/config/ConfigFile.java | 15 + src/resources/control/Intent.java | 120 +++ src/resources/control/IntentManager.java | 130 ++++ src/resources/control/IntentReceiver.java | 14 + src/resources/control/Manager.java | 155 ++++ src/resources/control/ServerManager.java | 195 +++++ .../control/ServerPublicInterface.java | 164 ++++ src/resources/control/ServerStatus.java | 10 + src/resources/control/Service.java | 130 ++++ src/resources/encodables/OutOfBand.java | 38 + src/resources/encodables/ProsePackage.java | 195 +++++ src/resources/encodables/Stf.java | 58 ++ .../encodables/player/Equipment.java | 71 ++ src/resources/encodables/player/Mail.java | 74 ++ src/resources/network/BaselineBuilder.java | 142 ++++ src/resources/network/DeltaBuilder.java | 55 ++ src/resources/network/ServerType.java | 8 + src/resources/network/UDPServer.java | 225 ++++++ src/resources/objects/SWGObject.java | 528 +++++++++++++ .../objects/building/BuildingObject.java | 13 + src/resources/objects/cell/CellObject.java | 41 + .../objects/creature/CreatureDifficulty.java | 24 + .../objects/creature/CreatureObject.java | 701 ++++++++++++++++++ .../installation/InstallationObject.java | 41 + .../objects/intangible/IntangibleObject.java | 64 ++ .../objects/mobile/MobileObject.java | 13 + .../objects/player/PlayerObject.java | 515 +++++++++++++ src/resources/objects/quadtree/QuadTree.java | 311 ++++++++ .../resource/ResourceContainerObject.java | 68 ++ src/resources/objects/ship/ShipObject.java | 13 + src/resources/objects/sound/SoundObject.java | 13 + .../objects/staticobject/StaticObject.java | 13 + .../objects/tangible/TangibleObject.java | 204 +++++ .../objects/waypoint/WaypointObject.java | 110 +++ .../objects/weapon/WeaponObject.java | 121 +++ src/resources/objects/weapon/WeaponType.java | 19 + src/resources/player/AccessLevel.java | 8 + src/resources/player/Player.java | 171 +++++ src/resources/player/PlayerFlags.java | 10 + src/resources/player/PlayerState.java | 12 + .../server_info/CachedObjectDatabase.java | 152 ++++ src/resources/server_info/DataManager.java | 94 +++ src/resources/server_info/ObjectDatabase.java | 128 ++++ .../server_info/PostgresqlDatabase.java | 9 + .../server_info/RelationalDatabase.java | 97 +++ .../server_info/UncachedObjectDatabase.java | 353 +++++++++ src/resources/services/Config.java | 184 +++++ src/resources/services/ProblemSeverity.java | 9 + src/resources/services/ServiceProblem.java | 21 + src/resources/zone/NameFilter.java | 153 ++++ src/services/CoreManager.java | 2 +- src/services/EngineManager.java | 49 ++ src/services/chat/ChatService.java | 2 +- .../network/NetworkClientManager.java | 247 ++++++ .../network/NetworkListenerService.java | 161 ++++ src/services/network/NetworkManager.java | 38 + src/utilities/ByteUtilities.java | 65 ++ src/utilities/Encoder.java | 93 +++ src/utilities/MathUtils.java | 64 ++ src/utilities/namegen/RaceNameRule.java | 55 ++ src/utilities/namegen/SWGNameGenerator.java | 296 ++++++++ .../encryption/FragmentedChannelA.java | 65 ++ test/network/encryption/TestEncryption.java | 87 +++ test/network/encryption/TestFragmented.java | 64 ++ .../objects/quadtree/TestQuadTree.java | 214 ++++++ .../server_info/TestObjectDatabase.java | 95 +++ 225 files changed, 18389 insertions(+), 6 deletions(-) create mode 100644 src/intents/CloseConnectionIntent.java create mode 100644 src/intents/InboundPacketIntent.java create mode 100644 src/intents/InboundUdpPacketIntent.java create mode 100644 src/intents/LoginEventIntent.java create mode 100644 src/intents/OutboundPacketIntent.java create mode 100644 src/intents/OutboundUdpPacketIntent.java create mode 100644 src/intents/PingIntent.java create mode 100644 src/intents/ServerStatusIntent.java create mode 100644 src/intents/swgobject_events/SWGObjectEventIntent.java create mode 100644 src/intents/swgobject_events/SWGObjectMovedIntent.java create mode 100644 src/network/FragmentedHandler.java create mode 100644 src/network/InboundNetworkHandler.java create mode 100644 src/network/NetworkClient.java create mode 100644 src/network/NetworkProtocol.java create mode 100644 src/network/OutboundNetworkHandler.java create mode 100644 src/network/OutboundPacketService.java create mode 100644 src/network/PacketType.java create mode 100644 src/network/encryption/Encryption.java create mode 100644 src/network/encryption/EncryptionCRC.java create mode 100644 src/network/encryption/MD5.java create mode 100644 src/network/packets/Packet.java create mode 100644 src/network/packets/soe/Acknowledge.java create mode 100644 src/network/packets/soe/ClientNetworkStatusUpdate.java create mode 100644 src/network/packets/soe/DataChannelA.java create mode 100644 src/network/packets/soe/Disconnect.java create mode 100644 src/network/packets/soe/Fragmented.java create mode 100644 src/network/packets/soe/MultiPacket.java create mode 100644 src/network/packets/soe/OutOfOrder.java create mode 100644 src/network/packets/soe/ServerNetworkStatusUpdate.java create mode 100644 src/network/packets/soe/SessionRequest.java create mode 100644 src/network/packets/soe/SessionResponse.java create mode 100644 src/network/packets/swg/ErrorMessage.java create mode 100644 src/network/packets/swg/SWGPacket.java create mode 100644 src/network/packets/swg/ServerUnixEpochTime.java create mode 100644 src/network/packets/swg/login/AccountFeatureBits.java create mode 100644 src/network/packets/swg/login/CharacterCreationDisabled.java create mode 100644 src/network/packets/swg/login/ClientIdMsg.java create mode 100644 src/network/packets/swg/login/ClientPermissionsMessage.java create mode 100644 src/network/packets/swg/login/EnumerateCharacterId.java create mode 100644 src/network/packets/swg/login/LoginClientId.java create mode 100644 src/network/packets/swg/login/LoginClientToken.java create mode 100644 src/network/packets/swg/login/LoginClusterStatus.java create mode 100644 src/network/packets/swg/login/LoginEnumCluster.java create mode 100644 src/network/packets/swg/login/LoginIncorrectClientId.java create mode 100644 src/network/packets/swg/login/OfflineServersMessage.java create mode 100644 src/network/packets/swg/login/RequestExtendedClusters.java create mode 100644 src/network/packets/swg/login/ServerId.java create mode 100644 src/network/packets/swg/login/ServerString.java create mode 100644 src/network/packets/swg/login/StationIdHasJediSlot.java create mode 100644 src/network/packets/swg/login/creation/ClientCreateCharacter.java create mode 100644 src/network/packets/swg/login/creation/ClientVerifyAndLockNameRequest.java create mode 100644 src/network/packets/swg/login/creation/ClientVerifyAndLockNameResponse.java create mode 100644 src/network/packets/swg/login/creation/CreateCharacterFailure.java create mode 100644 src/network/packets/swg/login/creation/CreateCharacterSuccess.java create mode 100644 src/network/packets/swg/login/creation/DeleteCharacterRequest.java create mode 100644 src/network/packets/swg/login/creation/DeleteCharacterResponse.java create mode 100644 src/network/packets/swg/login/creation/RandomNameRequest.java create mode 100644 src/network/packets/swg/login/creation/RandomNameResponse.java create mode 100644 src/network/packets/swg/zone/ChatRequestRoomList.java create mode 100644 src/network/packets/swg/zone/CmdSceneReady.java create mode 100644 src/network/packets/swg/zone/ConnectPlayerResponseMessage.java create mode 100644 src/network/packets/swg/zone/GalaxyLoopTimesRequest.java create mode 100644 src/network/packets/swg/zone/GalaxyLoopTimesResponse.java create mode 100644 src/network/packets/swg/zone/HeartBeatMessage.java create mode 100644 src/network/packets/swg/zone/OpenedContainerMessage.java create mode 100644 src/network/packets/swg/zone/ParametersMessage.java create mode 100644 src/network/packets/swg/zone/SceneCreateObjectByCrc.java create mode 100644 src/network/packets/swg/zone/SceneDestroyObject.java create mode 100644 src/network/packets/swg/zone/SceneEndBaselines.java create mode 100644 src/network/packets/swg/zone/ServerTimeMessage.java create mode 100644 src/network/packets/swg/zone/SetWaypointColor.java create mode 100644 src/network/packets/swg/zone/UpdateContainmentMessage.java create mode 100644 src/network/packets/swg/zone/UpdatePostureMessage.java create mode 100644 src/network/packets/swg/zone/UpdatePvpStatusMessage.java create mode 100644 src/network/packets/swg/zone/UpdateTransformsMessage.java create mode 100644 src/network/packets/swg/zone/auction/AuctionQueryHeadersMessage.java create mode 100644 src/network/packets/swg/zone/auction/AuctionQueryHeadersResponseMessage.java create mode 100644 src/network/packets/swg/zone/auction/CancelLiveAuctionMessage.java create mode 100644 src/network/packets/swg/zone/auction/CancelLiveAuctionResponseMessage.java create mode 100644 src/network/packets/swg/zone/auction/GetAuctionDetails.java create mode 100644 src/network/packets/swg/zone/auction/GetAuctionDetailsResponse.java create mode 100644 src/network/packets/swg/zone/auction/IsVendorOwnerResponseMessage.java create mode 100644 src/network/packets/swg/zone/auction/RetrieveAuctionItemMessage.java create mode 100644 src/network/packets/swg/zone/auction/RetrieveAuctionItemResponseMessage.java create mode 100644 src/network/packets/swg/zone/baselines/Baseline.java create mode 100644 src/network/packets/swg/zone/baselines/CREO3.java create mode 100644 src/network/packets/swg/zone/baselines/CREO6.java create mode 100644 src/network/packets/swg/zone/baselines/CREO8.java create mode 100644 src/network/packets/swg/zone/baselines/CREO9.java create mode 100644 src/network/packets/swg/zone/baselines/PLAY6.java create mode 100644 src/network/packets/swg/zone/baselines/PLAY9.java create mode 100644 src/network/packets/swg/zone/building/UpdateCellPermissionMessage.java create mode 100644 src/network/packets/swg/zone/chat/ChatDeletePersistentMessage.java create mode 100644 src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java create mode 100644 src/network/packets/swg/zone/chat/ChatIgnoreList.java create mode 100644 src/network/packets/swg/zone/chat/ChatInstantMessageToCharacter.java create mode 100644 src/network/packets/swg/zone/chat/ChatInstantMessageToClient.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnSendInstantMessage.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java create mode 100644 src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java create mode 100644 src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java create mode 100644 src/network/packets/swg/zone/chat/ChatRequestPersistentMessage.java create mode 100644 src/network/packets/swg/zone/chat/ChatRoomMessage.java create mode 100644 src/network/packets/swg/zone/chat/ChatSystemMessage.java create mode 100644 src/network/packets/swg/zone/chat/ConGenericMessage.java create mode 100644 src/network/packets/swg/zone/chat/VoiceChatStatus.java create mode 100644 src/network/packets/swg/zone/combat/GrantCommandMessage.java create mode 100644 src/network/packets/swg/zone/deltas/DeltasMessage.java create mode 100644 src/network/packets/swg/zone/insertion/ChatRoomList.java create mode 100644 src/network/packets/swg/zone/insertion/ChatServerStatus.java create mode 100644 src/network/packets/swg/zone/insertion/CmdStartScene.java create mode 100644 src/network/packets/swg/zone/insertion/ConnectPlayerMessage.java create mode 100644 src/network/packets/swg/zone/insertion/SelectCharacter.java create mode 100644 src/network/packets/swg/zone/object_controller/CommandQueueDequeue.java create mode 100644 src/network/packets/swg/zone/object_controller/CommandQueueEnqueue.java create mode 100644 src/network/packets/swg/zone/object_controller/DataTransform.java create mode 100644 src/network/packets/swg/zone/object_controller/ObjectController.java create mode 100644 src/network/packets/swg/zone/object_controller/ObjectMenuRequest.java create mode 100644 src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java create mode 100644 src/network/packets/swg/zone/object_controller/PlayerEmote.java create mode 100644 src/network/packets/swg/zone/object_controller/PostureUpdate.java create mode 100644 src/network/packets/swg/zone/object_controller/SitOnObject.java create mode 100644 src/network/packets/swg/zone/object_controller/SpatialChat.java create mode 100644 src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java create mode 100644 src/network/packets/swg/zone/server_ui/SuiEventNotification.java create mode 100644 src/network/packets/swg/zone/spatial/AttributeListMessage.java create mode 100644 src/network/packets/swg/zone/spatial/GetMapLocationsMessage.java create mode 100644 src/network/packets/swg/zone/spatial/GetMapLocationsResponseMessage.java create mode 100644 src/network/packets/swg/zone/spatial/NewTicketActivityResponseMessage.java create mode 100644 src/network/packets/swg/zone/spatial/StopClientEffectObjectByLabelMessage.java create mode 100644 src/resources/Attributes.java create mode 100644 src/resources/Galaxy.java create mode 100644 src/resources/Location.java create mode 100644 src/resources/Posture.java create mode 100644 src/resources/Race.java create mode 100644 src/resources/RadialOption.java create mode 100644 src/resources/SortedLinkedList.java create mode 100644 src/resources/Terrain.java create mode 100644 src/resources/client_info/ClientFactory.java create mode 100644 src/resources/client_info/visitors/ClientData.java create mode 100644 src/resources/client_info/visitors/CrcStringTableData.java create mode 100644 src/resources/client_info/visitors/DatatableData.java create mode 100644 src/resources/client_info/visitors/ObjectData.java create mode 100644 src/resources/client_info/visitors/ProfTemplateData.java create mode 100644 src/resources/client_info/visitors/SlotArrangementData.java create mode 100644 src/resources/client_info/visitors/SlotDefinitionData.java create mode 100644 src/resources/client_info/visitors/SlotDescriptorData.java create mode 100644 src/resources/collections/SWGList.java create mode 100644 src/resources/collections/SWGMap.java create mode 100644 src/resources/common/CRC.java create mode 100644 src/resources/config/ConfigFile.java create mode 100644 src/resources/control/Intent.java create mode 100644 src/resources/control/IntentManager.java create mode 100644 src/resources/control/IntentReceiver.java create mode 100644 src/resources/control/Manager.java create mode 100644 src/resources/control/ServerManager.java create mode 100644 src/resources/control/ServerPublicInterface.java create mode 100644 src/resources/control/ServerStatus.java create mode 100644 src/resources/control/Service.java create mode 100644 src/resources/encodables/OutOfBand.java create mode 100644 src/resources/encodables/ProsePackage.java create mode 100644 src/resources/encodables/Stf.java create mode 100644 src/resources/encodables/player/Equipment.java create mode 100644 src/resources/encodables/player/Mail.java create mode 100644 src/resources/network/BaselineBuilder.java create mode 100644 src/resources/network/DeltaBuilder.java create mode 100644 src/resources/network/ServerType.java create mode 100644 src/resources/network/UDPServer.java create mode 100644 src/resources/objects/SWGObject.java create mode 100644 src/resources/objects/building/BuildingObject.java create mode 100644 src/resources/objects/cell/CellObject.java create mode 100644 src/resources/objects/creature/CreatureDifficulty.java create mode 100644 src/resources/objects/creature/CreatureObject.java create mode 100644 src/resources/objects/installation/InstallationObject.java create mode 100644 src/resources/objects/intangible/IntangibleObject.java create mode 100644 src/resources/objects/mobile/MobileObject.java create mode 100644 src/resources/objects/player/PlayerObject.java create mode 100644 src/resources/objects/quadtree/QuadTree.java create mode 100644 src/resources/objects/resource/ResourceContainerObject.java create mode 100644 src/resources/objects/ship/ShipObject.java create mode 100644 src/resources/objects/sound/SoundObject.java create mode 100644 src/resources/objects/staticobject/StaticObject.java create mode 100644 src/resources/objects/tangible/TangibleObject.java create mode 100644 src/resources/objects/waypoint/WaypointObject.java create mode 100644 src/resources/objects/weapon/WeaponObject.java create mode 100644 src/resources/objects/weapon/WeaponType.java create mode 100644 src/resources/player/AccessLevel.java create mode 100644 src/resources/player/Player.java create mode 100644 src/resources/player/PlayerFlags.java create mode 100644 src/resources/player/PlayerState.java create mode 100644 src/resources/server_info/CachedObjectDatabase.java create mode 100644 src/resources/server_info/DataManager.java create mode 100644 src/resources/server_info/ObjectDatabase.java create mode 100644 src/resources/server_info/PostgresqlDatabase.java create mode 100644 src/resources/server_info/RelationalDatabase.java create mode 100644 src/resources/server_info/UncachedObjectDatabase.java create mode 100644 src/resources/services/Config.java create mode 100644 src/resources/services/ProblemSeverity.java create mode 100644 src/resources/services/ServiceProblem.java create mode 100644 src/resources/zone/NameFilter.java create mode 100644 src/services/EngineManager.java create mode 100644 src/services/network/NetworkClientManager.java create mode 100644 src/services/network/NetworkListenerService.java create mode 100644 src/services/network/NetworkManager.java create mode 100644 src/utilities/ByteUtilities.java create mode 100644 src/utilities/Encoder.java create mode 100644 src/utilities/MathUtils.java create mode 100644 src/utilities/namegen/RaceNameRule.java create mode 100644 src/utilities/namegen/SWGNameGenerator.java create mode 100644 test/network/encryption/FragmentedChannelA.java create mode 100644 test/network/encryption/TestEncryption.java create mode 100644 test/network/encryption/TestFragmented.java create mode 100644 test/resources/objects/quadtree/TestQuadTree.java create mode 100644 test/resources/server_info/TestObjectDatabase.java diff --git a/.classpath b/.classpath index 953b5759..e4494fb5 100644 --- a/.classpath +++ b/.classpath @@ -1,9 +1,10 @@ + - + diff --git a/src/intents/CloseConnectionIntent.java b/src/intents/CloseConnectionIntent.java new file mode 100644 index 00000000..2b623321 --- /dev/null +++ b/src/intents/CloseConnectionIntent.java @@ -0,0 +1,46 @@ +package intents; + +import network.packets.soe.Disconnect.DisconnectReason; +import resources.control.Intent; + + +public class CloseConnectionIntent extends Intent { + + public static final String TYPE = "CloseConnectionIntent"; + + private int connId; + private long networkId; + private DisconnectReason reason; + + public CloseConnectionIntent(int connId, long networkId, DisconnectReason reason) { + super(TYPE); + setConnectionId(connId); + setNetworkId(networkId); + setReason(reason); + } + + public void setConnectionId(int connId) { + this.connId = connId; + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } + + public void setReason(DisconnectReason reason) { + this.reason = reason; + } + + public int getConnectionId() { + return connId; + } + + public long getNetworkId() { + return networkId; + } + + public DisconnectReason getReason() { + return reason; + } + +} diff --git a/src/intents/InboundPacketIntent.java b/src/intents/InboundPacketIntent.java new file mode 100644 index 00000000..d1ad3ead --- /dev/null +++ b/src/intents/InboundPacketIntent.java @@ -0,0 +1,46 @@ +package intents; + +import network.packets.Packet; +import resources.control.Intent; +import resources.network.ServerType; + +public class InboundPacketIntent extends Intent { + + public static final String TYPE = "InboundPacketIntent"; + + private Packet packet; + private ServerType type; + private long networkId; + + public InboundPacketIntent(ServerType type, Packet p, long networkId) { + super(TYPE); + setPacket(p); + setServerType(type); + setNetworkId(networkId); + } + + public void setPacket(Packet p) { + this.packet = p; + } + + public void setServerType(ServerType type) { + this.type = type; + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } + + public Packet getPacket() { + return packet; + } + + public ServerType getServerType() { + return type; + } + + public long getNetworkId() { + return networkId; + } + +} diff --git a/src/intents/InboundUdpPacketIntent.java b/src/intents/InboundUdpPacketIntent.java new file mode 100644 index 00000000..b0db55e8 --- /dev/null +++ b/src/intents/InboundUdpPacketIntent.java @@ -0,0 +1,36 @@ +package intents; + +import resources.control.Intent; +import resources.network.ServerType; +import resources.network.UDPServer.UDPPacket; + +public class InboundUdpPacketIntent extends Intent { + + public static final String TYPE = "InboundUdpPacketIntent"; + + private UDPPacket packet; + private ServerType type; + + public InboundUdpPacketIntent(ServerType type, UDPPacket p) { + super(TYPE); + setPacket(p); + setServerType(type); + } + + public void setPacket(UDPPacket p) { + this.packet = p; + } + + public void setServerType(ServerType type) { + this.type = type; + } + + public UDPPacket getPacket() { + return packet; + } + + public ServerType getServerType() { + return type; + } + +} diff --git a/src/intents/LoginEventIntent.java b/src/intents/LoginEventIntent.java new file mode 100644 index 00000000..db82c339 --- /dev/null +++ b/src/intents/LoginEventIntent.java @@ -0,0 +1,42 @@ +package intents; + +import resources.control.Intent; + +public class LoginEventIntent extends Intent { + + public static final String TYPE = "LoginEventIntent"; + + private LoginEvent event; + private long networkId; + + public LoginEventIntent(long networkId, LoginEvent event) { + super(TYPE); + setNetworkId(networkId); + setEvent(event); + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } + + public void setEvent(LoginEvent event) { + this.event = event; + } + + public long getNetworkId() { + return networkId; + } + + public LoginEvent getEvent() { + return event; + } + + public enum LoginEvent { + LOGIN_FAIL_INVALID_VERSION_CODE, + LOGIN_FAIL_INVALID_USER_PASS, + LOGIN_FAIL_SERVER_ERROR, + LOGIN_FAIL_BANNED, + LOGIN_SUCCESS + } + +} diff --git a/src/intents/OutboundPacketIntent.java b/src/intents/OutboundPacketIntent.java new file mode 100644 index 00000000..8bbb23f0 --- /dev/null +++ b/src/intents/OutboundPacketIntent.java @@ -0,0 +1,35 @@ +package intents; + +import network.packets.Packet; +import resources.control.Intent; + +public class OutboundPacketIntent extends Intent { + + public static final String TYPE = "OutboundPacketIntent"; + + private Packet packet; + private long networkId; + + public OutboundPacketIntent(Packet p, long networkId) { + super(TYPE); + setPacket(p); + setNetworkId(networkId); + } + + public void setPacket(Packet p) { + this.packet = p; + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } + + public Packet getPacket() { + return packet; + } + + public long getNetworkId() { + return networkId; + } + +} diff --git a/src/intents/OutboundUdpPacketIntent.java b/src/intents/OutboundUdpPacketIntent.java new file mode 100644 index 00000000..8102fc7f --- /dev/null +++ b/src/intents/OutboundUdpPacketIntent.java @@ -0,0 +1,36 @@ +package intents; + +import resources.control.Intent; +import resources.network.ServerType; +import resources.network.UDPServer.UDPPacket; + +public class OutboundUdpPacketIntent extends Intent { + + public static final String TYPE = "OutboundUdpPacketIntent"; + + private UDPPacket packet; + private ServerType type; + + public OutboundUdpPacketIntent(ServerType type, UDPPacket p) { + super(TYPE); + setPacket(p); + setServerType(type); + } + + public void setPacket(UDPPacket p) { + this.packet = p; + } + + public void setServerType(ServerType type) { + this.type = type; + } + + public UDPPacket getPacket() { + return packet; + } + + public ServerType getServerType() { + return type; + } + +} diff --git a/src/intents/PingIntent.java b/src/intents/PingIntent.java new file mode 100644 index 00000000..cac16f4c --- /dev/null +++ b/src/intents/PingIntent.java @@ -0,0 +1,13 @@ +package intents; + +import resources.control.Intent; + +public class PingIntent extends Intent { + + public static final String TYPE = "PingIntent"; + + public PingIntent() { + super(TYPE); + } + +} diff --git a/src/intents/ServerStatusIntent.java b/src/intents/ServerStatusIntent.java new file mode 100644 index 00000000..0a0ab9c4 --- /dev/null +++ b/src/intents/ServerStatusIntent.java @@ -0,0 +1,44 @@ +package intents; + +import resources.control.Intent; +import resources.control.ServerStatus; + +public class ServerStatusIntent extends Intent { + + public static final String TYPE = "ServerStatusIntent"; + + private ServerStatus status; + private long time; + + public ServerStatusIntent() { + super(TYPE); + setStatus(null); + } + + public ServerStatusIntent(ServerStatus status) { + super(TYPE); + setStatus(status); + } + + public ServerStatusIntent(ServerStatus status, long time) { + this(status); + setTime(time); + } + + public void setTime(long time) { + this.time = time; + } + + public long getTime() { + return time; + } + + public void setStatus(ServerStatus status) { + this.status = status; + } + + public ServerStatus getStatus() { + return status; + } + +} diff --git a/src/intents/swgobject_events/SWGObjectEventIntent.java b/src/intents/swgobject_events/SWGObjectEventIntent.java new file mode 100644 index 00000000..eb78e78f --- /dev/null +++ b/src/intents/swgobject_events/SWGObjectEventIntent.java @@ -0,0 +1,39 @@ +package intents.swgobject_events; + +import resources.control.Intent; +import resources.objects.SWGObject; + +public class SWGObjectEventIntent extends Intent { + + public static final String TYPE = "SWGObjectEventType"; + + private SWGObject obj; + private Event event; + + public SWGObjectEventIntent(SWGObject obj, Event e) { + super(TYPE); + setObject(obj); + setEvent(e); + } + + public void setObject(SWGObject obj) { + this.obj = obj; + } + + public void setEvent(Event e) { + this.event = e; + } + + public SWGObject getObject() { + return obj; + } + + public Event getEvent() { + return event; + } + + public enum Event { + SOE_UPDATE_LOCATION + } + +} diff --git a/src/intents/swgobject_events/SWGObjectMovedIntent.java b/src/intents/swgobject_events/SWGObjectMovedIntent.java new file mode 100644 index 00000000..c6c4fa66 --- /dev/null +++ b/src/intents/swgobject_events/SWGObjectMovedIntent.java @@ -0,0 +1,23 @@ +package intents.swgobject_events; + +import resources.Location; +import resources.objects.SWGObject; + +public class SWGObjectMovedIntent extends SWGObjectEventIntent { + + private Location oldLocation; + + public SWGObjectMovedIntent(SWGObject object, Location oldLocation) { + super(object, SWGObjectEventIntent.Event.SOE_UPDATE_LOCATION); + this.oldLocation = oldLocation; + } + + public Location getOldLocation() { + return oldLocation; + } + + public Location getNewLocation() { + return getObject().getLocation(); + } + +} diff --git a/src/main/ProjectSWG.java b/src/main/ProjectSWG.java index fe693d41..a9840912 100644 --- a/src/main/ProjectSWG.java +++ b/src/main/ProjectSWG.java @@ -1,8 +1,8 @@ package main; import intents.ServerStatusIntent; -import intents.ServerStatusIntent.ServerStatus; import resources.Galaxy.GalaxyStatus; +import resources.control.ServerStatus; import services.CoreManager; public class ProjectSWG { diff --git a/src/network/FragmentedHandler.java b/src/network/FragmentedHandler.java new file mode 100644 index 00000000..9bff7585 --- /dev/null +++ b/src/network/FragmentedHandler.java @@ -0,0 +1,83 @@ +package network; + +import java.nio.ByteOrder; + +import network.packets.soe.Fragmented; +import resources.SortedLinkedList; + +public class FragmentedHandler { + + private SortedLinkedList fragPackets; + private int fragSize; + + public FragmentedHandler() { + fragPackets = new SortedLinkedList(); + fragSize = 0; + } + + public void reset() { + fragPackets.clear(); + fragSize = 0; + } + + public byte [] onReceived(Fragmented f) { + synchronized (fragPackets) { + if (insertIfNew(f) && getBufferedSize() == fragSize) { + byte [] data = new byte[fragSize]; + int offset = 0; + while (fragPackets.size() > 0 && offset < fragSize) { + offset = spliceFragmentedIntoBuffer(fragPackets.removeFirst(), data, offset); + } + updateMetadata(); + return data; + } + return new byte[0]; + } + } + + private boolean insertIfNew(Fragmented f) { + synchronized (fragPackets) { + if (!fragPackets.contains(f)) { + fragPackets.add(f); + updateMetadata(); + return true; + } + } + return false; + } + + private int spliceFragmentedIntoBuffer(Fragmented f, byte [] data, int offset) { + byte [] fData = f.encode().array(); + int header = offset==0?8:4; + System.arraycopy(fData, header, data, offset, fData.length-header); + return offset + fData.length-header; + } + + private void updateMetadata() { + synchronized (fragPackets) { + if (fragPackets.isEmpty()) + fragSize = 0; + else + fragSize = fragPackets.getFirst().encode().order(ByteOrder.BIG_ENDIAN).getInt(4); + } + } + + private int getBufferedSize() { + int curSize = 0; + int i = 0; + short prevSeq = (short) (fragPackets.getFirst().getSequence()-1); + for (Fragmented frag : fragPackets) { + // Update previous sequence and verify all in-order + if (prevSeq+1 != frag.getSequence()) + break; + prevSeq = frag.getSequence(); + // Update current size + curSize += (i == 0) ? frag.encode().array().length-8 : frag.encode().array().length-4; + i++; + if (curSize >= fragSize) + break; + } + return curSize; + } + +} diff --git a/src/network/InboundNetworkHandler.java b/src/network/InboundNetworkHandler.java new file mode 100644 index 00000000..c77a08fc --- /dev/null +++ b/src/network/InboundNetworkHandler.java @@ -0,0 +1,166 @@ +package network; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.LinkedList; +import java.util.Queue; + +import network.encryption.Encryption; +import network.packets.Packet; +import network.packets.soe.Acknowledge; +import network.packets.soe.ClientNetworkStatusUpdate; +import network.packets.soe.DataChannelA; +import network.packets.soe.Disconnect; +import network.packets.soe.Fragmented; +import network.packets.soe.MultiPacket; +import network.packets.soe.OutOfOrder; +import network.packets.soe.SessionRequest; +import network.packets.soe.SessionResponse; +import network.packets.swg.SWGPacket; +import network.packets.swg.zone.object_controller.ObjectController; + +public class InboundNetworkHandler { + + private final Queue inboundQueue; + private final FragmentedHandler fragStream; + private final InboundEventCallback eventCallback; + private short recvSequence; + private int crc; + + public InboundNetworkHandler(InboundEventCallback eventCallback) { + this.inboundQueue = new LinkedList(); + this.fragStream = new FragmentedHandler(); + this.eventCallback = eventCallback; + recvSequence = -1; + crc = 0; + } + + public synchronized void reset() { + fragStream.reset(); + recvSequence = -1; + crc = 0; + } + + public synchronized void setCrc(int crc) { + this.crc = crc; + } + + public synchronized int getCrc() { + return crc; + } + + public synchronized short getReceivedSequence() { + return recvSequence; + } + + public synchronized boolean hasInbound() { + synchronized (inboundQueue) { + return !inboundQueue.isEmpty(); + } + } + + public synchronized Packet pollInbound() { + synchronized (inboundQueue) { + return inboundQueue.poll(); + } + } + + private void pushPacket(Packet packet) { + synchronized (inboundQueue) { + inboundQueue.add(packet); + } + } + + public synchronized int onReceive(byte [] data) { + if (data.length < 2) + return 0; + if (data[1] == 1 || data[1] == 2) + return processPacket(data); + else + return processPacket(Encryption.decode(data, crc)); + } + + private int processPacket(byte [] data) { + if (data.length < 2) + return 0; + ByteBuffer bb = ByteBuffer.wrap(data); + int packets = 0; + switch (data[1]) { + case 0x00: + if (data[0] > 0) + packets += processSwgPacket(data); + break; + case 0x01: ++packets; pushPacket(new SessionRequest(bb)); break; + case 0x02: ++packets; pushPacket(new SessionResponse(bb)); break; + case 0x03: packets += processMulti(new MultiPacket(bb)); break; + case 0x05: ++packets; pushPacket(new Disconnect(bb)); break; + case 0x07: ++packets; pushPacket(new ClientNetworkStatusUpdate(bb)); break; + case 0x09: packets += processData(new DataChannelA(bb)); break; + case 0x0D: packets += processFrag(new Fragmented(bb)); break; + case 0x11: ++packets; pushPacket(new OutOfOrder(bb)); break; + case 0x15: ++packets; pushPacket(new Acknowledge(bb)); break; + default: + break; + } + return packets; + } + + private int processMulti(MultiPacket packet) { + int packets = 0; + for (Packet p : packet.getPackets()) + packets += processPacket(p.getData().array()); + return packets; + } + + private int processData(DataChannelA packet) { + if (packet.getSequence() != (short) (recvSequence+1)) { + if (packet.getSequence() > recvSequence) + eventCallback.sendOutOfOrder(packet.getSequence()); + return 0; + } + recvSequence = packet.getSequence(); + eventCallback.sendAcknowledge(recvSequence); + int packets = 0; + for (SWGPacket p : packet.getPackets()) { + processSwgPacket(p.getData().array()); + ++packets; + } + return packets; + } + + private int processFrag(Fragmented packet) { + if (packet.getSequence() != (short) (recvSequence+1)) { + if (packet.getSequence() > recvSequence) + eventCallback.sendOutOfOrder(packet.getSequence()); + return 0; + } + recvSequence = packet.getSequence(); + eventCallback.sendAcknowledge(recvSequence); + return processPacket(fragStream.onReceived(packet)); + } + + private int processSwgPacket(byte [] data) { + if (data.length < 6) + return 0; + ByteBuffer bb = ByteBuffer.wrap(data); + int crc = bb.order(ByteOrder.LITTLE_ENDIAN).getInt(2); + SWGPacket packet; + if (crc == ObjectController.CRC) + packet = ObjectController.decodeController(bb); + else { + packet = PacketType.getForCrc(crc); + if (packet != null) + packet.decode(bb); + } + if (packet == null) + return 0; + pushPacket(packet); + return 1; + } + + public interface InboundEventCallback { + public void sendAcknowledge(short sequence); + public void sendOutOfOrder(short sequence); + } + +} diff --git a/src/network/NetworkClient.java b/src/network/NetworkClient.java new file mode 100644 index 00000000..91d35002 --- /dev/null +++ b/src/network/NetworkClient.java @@ -0,0 +1,100 @@ +package network; + +import intents.InboundPacketIntent; + +import java.net.InetAddress; +import java.util.List; + +import resources.control.Intent; +import resources.network.ServerType; +import network.packets.Packet; + +public class NetworkClient { + + private final Object prevPacketIntentMutex = new Object(); + private final long networkId; + private final ServerType serverType; + private final NetworkProtocol protocol; + private InetAddress address; + private Intent prevPacketIntent; + private int port; + private int connId; + + public NetworkClient(ServerType type, InetAddress addr, int port, long networkId) { + this.serverType = type; + this.networkId = networkId; + protocol = new NetworkProtocol(type, addr, port); + prevPacketIntent = null; + connId = 0; + updateNetworkInfo(addr, port); + } + + public void updateNetworkInfo(InetAddress addr, int port) { + protocol.updateNetworkInfo(addr, port); + this.address = addr; + this.port = port; + } + + public void resetNetwork() { + protocol.resetNetwork(); + connId = 0; + } + + public void setCrc(int crc) { + protocol.setCrc(crc); + } + + public void setConnectionId(int id) { + connId = id; + } + + public InetAddress getAddress() { + return address; + } + + public int getPort() { + return port; + } + + public int getCrc() { + return protocol.getCrc(); + } + + public int getConnectionId() { + return connId; + } + + public long getNetworkId() { + return networkId; + } + + public void sendPacket(Packet p) { + protocol.sendPacket(p); + } + + public boolean processPacket(ServerType type, byte [] data) { + if (type != serverType || type == ServerType.UNKNOWN) + return false; + if (type == ServerType.PING) + return true; + List packets = protocol.process(data); + for (Packet p : packets) { + p.setAddress(address); + p.setPort(port); + synchronized (prevPacketIntentMutex) { + InboundPacketIntent i = new InboundPacketIntent(type, p, networkId); + if (prevPacketIntent == null) + i.broadcast(); + else + i.broadcastAfterIntent(prevPacketIntent); + prevPacketIntent = i; + } + } + return packets.size() > 0; + } + + public String toString() { + return "NetworkClient[ConnId=" + connId + " " + address + ":" + port + "]"; + } + +} diff --git a/src/network/NetworkProtocol.java b/src/network/NetworkProtocol.java new file mode 100644 index 00000000..a5123443 --- /dev/null +++ b/src/network/NetworkProtocol.java @@ -0,0 +1,128 @@ +package network; + +import intents.OutboundUdpPacketIntent; + +import java.net.InetAddress; +import java.util.LinkedList; +import java.util.List; + +import resources.control.Intent; +import resources.network.ServerType; +import resources.network.UDPServer.UDPPacket; +import network.InboundNetworkHandler.InboundEventCallback; +import network.packets.Packet; +import network.packets.soe.Acknowledge; +import network.packets.soe.ClientNetworkStatusUpdate; +import network.packets.soe.OutOfOrder; +import network.packets.soe.ServerNetworkStatusUpdate; + +public class NetworkProtocol implements InboundEventCallback { + + private final Object prevOutboundIntentMutex = new Object(); + private final InboundNetworkHandler inbound; + private final OutboundNetworkHandler outbound; + private final ServerType serverType; + + private Intent prevOutboundIntent; + private InetAddress address; + private int port; + private int crc; + + public NetworkProtocol(ServerType type, InetAddress address, int port) { + this.inbound = new InboundNetworkHandler(this); + this.outbound = new OutboundNetworkHandler(); + this.serverType = type; + prevOutboundIntent = null; + crc = 0; + updateNetworkInfo(address, port); + } + + public void setCrc(int crc) { + this.crc = crc; + inbound.setCrc(crc); + outbound.setCrc(crc); + } + + public int getCrc() { + return crc; + } + + @Override + public void sendAcknowledge(short sequence) { + sendPacket(new Acknowledge(sequence)); + } + + @Override + public void sendOutOfOrder(short sequence) { + sendPacket(new OutOfOrder(sequence)); + } + + public void updateNetworkInfo(InetAddress addr, int port) { + this.address = addr; + this.port = port; + } + + public void resetNetwork() { + inbound.reset(); + outbound.reset(); + prevOutboundIntent = null; + } + + public List process(byte [] data) { + inbound.onReceive(data); + List packets = new LinkedList(); + while (inbound.hasInbound()) + process(packets, inbound.pollInbound()); + return packets; + } + + private void process(List packets, Packet packet) { + if (packet == null) + return; + packets.add(packet); + if (packet instanceof Acknowledge) + outbound.onAcknowledge(((Acknowledge) packet).getSequence()); + else if (packet instanceof OutOfOrder) + outbound.onOutOfOrder(((OutOfOrder) packet).getSequence()); + else if (packet instanceof ClientNetworkStatusUpdate) + processClientNetworkUpdate((ClientNetworkStatusUpdate) packet); + flushAssembled(); + } + + public void sendPacket(Packet packet) { + if (address == null) + return; + outbound.assemble(packet); + flushAssembled(); + } + + private void send(byte [] data) { + if (data == null) + return; + UDPPacket packet = new UDPPacket(address, port, data); + OutboundUdpPacketIntent intent = new OutboundUdpPacketIntent(serverType, packet); + synchronized (prevOutboundIntentMutex) { + intent.broadcastAfterIntent(prevOutboundIntent); + prevOutboundIntent = intent; + } + } + + private void processClientNetworkUpdate(ClientNetworkStatusUpdate update) { + ServerNetworkStatusUpdate serverNet = new ServerNetworkStatusUpdate(); + serverNet.setClientTickCount((short) update.getTick()); + serverNet.setServerSyncStampLong(0); + int recv = inbound.getReceivedSequence() < 0 ? 0 : inbound.getReceivedSequence(); + int send = outbound.getSentSequence(); + serverNet.setClientPacketsSent(recv); + serverNet.setClientPacketsRecv(send); + serverNet.setServerPacketsSent(send); + serverNet.setServerPacketsRecv(recv); + sendPacket(serverNet); + } + + private void flushAssembled() { + while (outbound.hasAssembled()) + send(outbound.pollAssembled()); + } + +} diff --git a/src/network/OutboundNetworkHandler.java b/src/network/OutboundNetworkHandler.java new file mode 100644 index 00000000..e09700bd --- /dev/null +++ b/src/network/OutboundNetworkHandler.java @@ -0,0 +1,232 @@ +package network; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Queue; + +import resources.SortedLinkedList; +import network.encryption.Encryption; +import network.packets.Packet; +import network.packets.soe.DataChannelA; +import network.packets.soe.Fragmented; +import network.packets.soe.MultiPacket; +import network.packets.soe.SessionRequest; +import network.packets.soe.SessionResponse; +import network.packets.swg.SWGPacket; + +public class OutboundNetworkHandler { + + private final Queue assembleQueue; + private final SortedLinkedList sequenced; + private short sendSequence; + private int crc; + + public OutboundNetworkHandler() { + assembleQueue = new LinkedList(); + sequenced = new SortedLinkedList(); + sendSequence = 0; + crc = 0; + } + + public synchronized void reset() { + sendSequence = 0; + crc = 0; + } + + public synchronized void setCrc(int crc) { + this.crc = crc; + } + + public synchronized int getCrc() { + return crc; + } + + public synchronized short getSentSequence() { + return sendSequence; + } + + public synchronized void onAcknowledge(short sequence) { + synchronized (sequenced) { + Iterator it = sequenced.iterator(); + while (it.hasNext()) { + SequencedPacket sp = it.next(); + if (sp.getSequence() <= sequence) + it.remove(); + else + break; + } + } + } + + public synchronized void onOutOfOrder(short sequence) { + synchronized (sequenced) { + Iterator it = sequenced.iterator(); + while (it.hasNext()) { + SequencedPacket sp = it.next(); + if (sp.getSequence() <= sequence) + pushAssembledEncrypted(sp.getPacket()); + else + break; + } + } + } + + public synchronized boolean hasAssembled() { + synchronized (assembleQueue) { + return !assembleQueue.isEmpty(); + } + } + + public synchronized byte [] pollAssembled() { + synchronized (assembleQueue) { + return assembleQueue.poll(); + } + } + + private void pushAssembledEncrypted(byte [] data) { + data = Encryption.encode(data, crc); + synchronized (assembleQueue) { + assembleQueue.add(data); + } + } + + private void pushAssembledUnencrypted(byte [] data) { + synchronized (assembleQueue) { + assembleQueue.add(data); + } + } + + private void pushSequencedPacket(short sequence, byte [] packet) { + synchronized (sequenced) { + sequenced.add(new SequencedPacket(sequence, packet)); + } + } + + public synchronized int assemble(Packet packet) { + if (packet instanceof SessionRequest || packet instanceof SessionResponse) { + pushAssembledUnencrypted(packet.encode().array()); + return 1; + } else + return assembleUnencrypted(packet); + } + + private int assembleUnencrypted(Packet packet) { + if (packet instanceof SWGPacket) + return assembleSwg((SWGPacket) packet); + else + return assembleSoe(packet); + } + + private int assembleSoe(Packet packet) { + if (packet instanceof DataChannelA) + return assembleDataChannelA((DataChannelA) packet); + if (packet instanceof MultiPacket) + return assembleMultiPacket((MultiPacket) packet); + pushAssembledEncrypted(packet.encode().array()); + return 1; + } + + private int assembleSwg(SWGPacket packet) { + return assembleDataChannelA(new DataChannelA(packet)); + } + + private int assembleMultiPacket(MultiPacket m) { + int len = m.getLength(); + if (len >= 493) { + int count = getFragmentedPacketCount(len); + int lastSeq = updateSequencesMulti((short)(sendSequence+count), m); + for (Fragmented f : Fragmented.encode(m.encode(), sendSequence)) { + byte [] encoded = f.encode().array(); + pushSequencedPacket(f.getSequence(), encoded); + pushAssembledEncrypted(encoded); + } + sendSequence = (short) (lastSeq + 1); + return count; + } else { + sendSequence = updateSequencesMulti(sendSequence, m); + pushAssembledEncrypted(m.encode().array()); + return 1; + } + } + + private int assembleDataChannelA(DataChannelA d) { + int len = d.getLength(); + if (len >= 493) { + int count = getFragmentedPacketCount(len); + int lastSeq = updateSequenceData((short)(sendSequence+count), d); + for (Fragmented f : Fragmented.encode(d.encode(), sendSequence)) { + byte [] encoded = f.encode().array(); + pushSequencedPacket(f.getSequence(), encoded); + pushAssembledEncrypted(encoded); + } + sendSequence = (short) lastSeq; + return count; + } else { + d.setSequence(sendSequence++); + byte [] encoded = d.encode().array(); + pushSequencedPacket(d.getSequence(), encoded); + pushAssembledEncrypted(encoded); + return 1; + } + } + + private short updateSequencesMulti(short seq, MultiPacket m) { + for (Packet p : m.getPackets()) { + if (p instanceof DataChannelA) + seq = updateSequenceData(seq, (DataChannelA) p); + } + return seq; + } + + private short updateSequenceData(short seq, DataChannelA d) { + d.setSequence(seq++); + return seq; + } + + private int getFragmentedPacketCount(int length) { + return (int) Math.ceil((length+4)/489.0); + } + + private static class SequencedPacket implements Comparable { + private final short sequence; + private final byte [] packet; + + public SequencedPacket(short sequence, byte [] packet) { + this.sequence = sequence; + this.packet = packet; + } + + public short getSequence() { + return sequence; + } + + public byte [] getPacket() { + return packet; + } + + @Override + public int compareTo(SequencedPacket sp) { + if (sequence < sp.getSequence()) + return -1; + if (sequence == sp.getSequence()) + return 0; + return 1; + } + + @Override + public boolean equals(Object o) { + if (o == null) + return false; + if (o instanceof SequencedPacket) + return ((SequencedPacket) o).getSequence() == sequence; + return false; + } + + @Override + public int hashCode() { + return sequence; + } + + } + +} diff --git a/src/network/OutboundPacketService.java b/src/network/OutboundPacketService.java new file mode 100644 index 00000000..0ed004f9 --- /dev/null +++ b/src/network/OutboundPacketService.java @@ -0,0 +1,163 @@ +package network; + +import intents.CloseConnectionIntent; +import intents.OutboundPacketIntent; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import resources.control.Intent; +import resources.control.Service; +import network.packets.Packet; +import network.packets.soe.DataChannelA; +import network.packets.soe.MultiPacket; +import network.packets.soe.SessionResponse; +import network.packets.swg.SWGPacket; + +public class OutboundPacketService { + + private final Map outboundPackets = new HashMap(); + + public OutboundPacketService() { + new Service() { + public void onIntentReceived(Intent i) { + if (i instanceof CloseConnectionIntent) + closeConnection(((CloseConnectionIntent)i).getNetworkId()); + } + }.registerForIntent(CloseConnectionIntent.TYPE); + } + + public void sendPacket(long networkId, Packet ... packets) { + getSender(networkId).add(packets); + } + + public void sendPacket(long networkId, Packet packet) { + getSender(networkId).add(packet); + } + + public int flushPackets() { + int count = 0; + synchronized (outboundPackets) { + for (OutboundPacketSender sender : outboundPackets.values()) + count += sender.sendPackets(); + } + return count; + } + + private void closeConnection(long networkId) { + synchronized (outboundPackets) { + outboundPackets.remove(networkId); + } + } + + private OutboundPacketSender getSender(long networkId) { + synchronized (outboundPackets) { + OutboundPacketSender outbound = outboundPackets.get(networkId); + if (outbound == null) { + outbound = new OutboundPacketSender(networkId); + outboundPackets.put(networkId, outbound); + } + return outbound; + } + } + + private static class OutboundPacketSender { + + private final List outbound; + private final long networkId; + private Intent prevOutbound; + private boolean hasSoe; + private boolean hasSwg; + + public OutboundPacketSender(long networkId) { + outbound = new LinkedList(); + this.networkId = networkId; + prevOutbound = null; + hasSoe = false; + hasSwg = false; + } + + public synchronized void add(Packet ... packets) { + for (Packet p : packets) + add(p); + } + + public synchronized void add(Packet p) { + if (p instanceof SessionResponse) { + send(p); + } else { + if (p instanceof SWGPacket) + hasSwg = true; + else + hasSoe = true; + outbound.add(p); + } + } + + public synchronized int sendPackets() { + if (outbound.isEmpty()) + return 0; + int size = outbound.size(); + packageAndSendPackets(); + return size; + } + + private synchronized void send(Packet p) { + Intent out = new OutboundPacketIntent(p, networkId); + out.broadcastAfterIntent(prevOutbound); + prevOutbound = out; + } + + private synchronized void clear() { + hasSoe = false; + hasSwg = false; + outbound.clear(); + } + + private synchronized void packageAndSendPackets() { + if (hasSwg) { + if (hasSoe) + packageMix(); + else + packageSwg(); + } else { + if (hasSoe) + packageSoe(); + } + clear(); + } + + private synchronized void packageSoe() { + send(new MultiPacket(new LinkedList(outbound))); + } + + private synchronized void packageSwg() { + send(new DataChannelA(outbound.toArray(new SWGPacket[outbound.size()]))); + } + + private synchronized void packageMix() { + MultiPacket multi = new MultiPacket(); + DataChannelA data = null; + for (Packet p : outbound) { + if (p instanceof SWGPacket) { + if (data == null) + data = new DataChannelA(); + data.addPacket((SWGPacket) p); + } else { + if (data != null) { + multi.addPacket(data); + data = null; + } + multi.addPacket(p); + } + } + if (data != null) + multi.addPacket(data); + send(multi); + } + + } + +} diff --git a/src/network/PacketType.java b/src/network/PacketType.java new file mode 100644 index 00000000..7685bb72 --- /dev/null +++ b/src/network/PacketType.java @@ -0,0 +1,182 @@ +package network; + +import java.util.HashMap; +import java.util.Map; + +import network.packets.swg.*; +import network.packets.swg.login.*; +import network.packets.swg.login.creation.*; +import network.packets.swg.zone.*; +import network.packets.swg.zone.auction.*; +import network.packets.swg.zone.baselines.*; +import network.packets.swg.zone.building.*; +import network.packets.swg.zone.chat.*; +import network.packets.swg.zone.combat.*; +import network.packets.swg.zone.deltas.*; +import network.packets.swg.zone.insertion.*; +import network.packets.swg.zone.object_controller.*; +import network.packets.swg.zone.server_ui.*; +import network.packets.swg.zone.spatial.*; + +public enum PacketType { + + // Both + SERVER_UNIX_EPOCH_TIME (0x24b73893, ServerUnixEpochTime.class), + SERVER_ID (0x58c07f21, ServerId.class), + SERVER_STRING (0x0e20d7e9, ServerString.class), + + // Login + CLIENT_ID_MSG (0xd5899226, ClientIdMsg.class), + ERROR_MESSAGE (0xb5abf91a, ErrorMessage.class), + ACCOUNT_FEATURE_BITS (0x979f0279, AccountFeatureBits.class), + CLIENT_PERMISSIONS_MESSAGE (0xe00730e5, ClientPermissionsMessage.class), + REQUEST_EXTENDED_CLUSTERS (0x8e33ed05, RequestExtendedClusters.class), + OFFLINE_SERVERS_MESSAGE (0xF41A5265, OfflineServersMessage.class), + + // Post-Login + LOGIN_CLIENT_ID (0x41131F96, LoginClientId.class), + LOGIN_INCORRECT_CLIENT_ID (0x20E7E510, LoginIncorrectClientId.class), + LOGIN_CLIENT_TOKEN (0xaab296c6, LoginClientToken.class), + LOGIN_ENUM_CLUSTER (0xc11c63b9, LoginEnumCluster.class), + LOGIN_CLUSTER_STATUS (0x3436aeb6, LoginClusterStatus.class), + ENUMERATE_CHARACTER_ID (0x65ea4574, EnumerateCharacterId.class), + STATION_ID_HAS_JEDI_SLOT (0xcc9fccf8, StationIdHasJediSlot.class), + CHARACTER_CREATION_DISABLED (0xf4a15265, CharacterCreationDisabled.class), + + // Character Creation + CLIENT_CREATE_CHARACTER (0xb97f3074, ClientCreateCharacter.class), + CREATE_CHARACTER_SUCCESS (0x1db575cc, CreateCharacterSuccess.class), + CREATE_CHARACTER_FAILURE (0xdf333c6e, CreateCharacterFailure.class), + APPROVE_NAME_REQUEST (0x9eb04b9f, ClientVerifyAndLockNameRequest.class), + APPROVE_NAME_RESPONSE (0x9b2c6ba7, ClientVerifyAndLockNameResponse.class), + RANDOM_NAME_REQUEST (0xd6d1b6d1, RandomNameRequest.class), + RANDOM_NAME_RESPONSE (0xe85fb868, RandomNameResponse.class), + + // Character Deletion + DELETE_CHARACTER_RESPONSE (0x8268989b, DeleteCharacterResponse.class), + DELETE_CHARACTER_REQUEST (0xe87ad031, DeleteCharacterRequest.class), + + // Zone + COMMAND_QUEUE_ENQUEUE (0x00000116, CommandQueueEnqueue.class), + SELECT_CHARACTER (0xb5098d76, SelectCharacter.class), + CMD_SCENE_READY (0x43fd1c22, CmdSceneReady.class), + CMD_START_SCENE (0x3ae6dfae, CmdStartScene.class), + HEART_BEAT_MESSAGE (0xa16cf9af, HeartBeatMessage.class), + OBJECT_CONTROLLER (0x80ce5e46, ObjectController.class), + BASELINE (0x68a75f0c, Baseline.class), + DATA_TRANSFORM (0x00000071, DataTransform.class), + CONNECT_PLAYER_MESSAGE (0x2e365218, ConnectPlayerMessage.class), + CONNECT_PLAYER_RESPONSE_MESSAGE (0x6137556F, ConnectPlayerResponseMessage.class), + GALAXY_LOOP_TIMES_REQUEST (0x7d842d68, GalaxyLoopTimesRequest.class), + GALAXY_LOOP_TIMES_RESPONSE (0x4e428088, GalaxyLoopTimesResponse.class), + PARAMETERS_MESSAGE (0x487652DA, ParametersMessage.class), + DELTA (0x12862153, DeltasMessage.class), + SERVER_TIME_MESSAGE (0x2EBC3BD9, ServerTimeMessage.class), + SET_WAYPOINT_COLOR (0x90C59FDE, SetWaypointColor.class), + + // Chat + CHAT_FRIENDS_LIST_UPDATE (0x6CD2FCD8, ChatFriendsListUpdate.class), + CHAT_IGNORE_LIST (0xF8C275B0, ChatIgnoreList.class), + CHAT_INSTANT_MESSAGE_TO_CLIENT (0x3C565CED, ChatInstantMessageToClient.class), + CHAT_INSTANT_MESSAGE_TO_CHARACTER (0x84BB21F7, ChatInstantMessageToCharacter.class), + CHAT_ON_CONNECT_AVATAR (0xD72FE9BE, ChatOnConnectAvatar.class), + CHAT_ON_DESTROY_ROOM (0xE8EC5877, ChatOnDestroyRoom.class), + CHAT_ON_ENTERED_ROOM (0xE69BDC0A, ChatOnEnteredRoom.class), + CHAT_ON_LEAVE_ROOM (0x60B5098B, ChatOnLeaveRoom.class), + CHAT_ON_RECEIVE_ROOM_INVITATION (0xC17EB06D, ChatOnReceiveRoomInvitation.class), + CHAT_ON_SEND_INSTANT_MESSAGE (0x88DBB381, ChatOnSendInstantMessage.class), + CHAT_ON_SEND_ROOM_MESSAGE (0xE7B61633, ChatOnSendRoomMessage.class), + CHAT_PERSISTENT_MESSAGE_TO_CLIENT (0x08485E17, ChatPersistentMessageToClient.class), + CHAT_PERSISTENT_MESSAGE_TO_SERVER (0x25A29FA6, ChatPersistentMessageToServer.class), + CHAT_DELETE_PERSISTENT_MESSAGE (0x8F251641, ChatDeletePersistentMessage.class), + CHAT_REQUEST_PERSISTENT_MESSAGE (0x07E3559F, ChatRequestPersistentMessage.class), + CHAT_REQUEST_ROOM_LIST (0x4C3d2CfA, ChatRequestRoomList.class), + CHAT_ROOM_LIST (0x70DEB197, ChatRoomList.class), + CHAT_ROOM_MESSAGE (0xCD4CE444, ChatRoomMessage.class), + CHAT_SERVER_STATUS (0x7102B15F, ChatServerStatus.class), + CHAT_SYSTEM_MESSAGE (0x6D2A6413, ChatSystemMessage.class), + CON_GENERIC_MESSAGE (0x08C5FC76, ConGenericMessage.class), + VOICE_CHAT_STATUS (0x9E601905, VoiceChatStatus.class), + + // Scene + SCENE_END_BASELINES (0x2C436037, SceneEndBaselines.class), + SCENE_CREATE_OBJECT_BY_CRC (0xFE89DDEA, SceneCreateObjectByCrc.class), + SCENE_DESTROY_OBJECT (0x4D45D504, SceneDestroyObject.class), + UPDATE_CONTAINMENT_MESSAGE (0x56CBDE9E, UpdateContainmentMessage.class), + UPDATE_CELL_PERMISSIONS_MESSAGE (0xF612499C, UpdateCellPermissionMessage.class), + GET_MAP_LOCATIONS_MESSAGE (0x1A7AB839, GetMapLocationsMessage.class), + GET_MAP_LOCATIONS_RESPONSE_MESSAGE (0x9F80464C, GetMapLocationsResponseMessage.class), + + // Spatial + UPDATE_POSTURE_MESSAGE (0x0bde6b41, UpdatePostureMessage.class), + UPDATE_TRANSFORMS_MESSAGE (0x1B24F808, UpdateTransformsMessage.class), + SPATIAL_CHAT (0x000000f4, SpatialChat.class), + NEW_TICKET_ACTIVITY_RESPONSE_MESSAGE (0x6EA42D80, NewTicketActivityResponseMessage.class), + ATTRIBUTE_LIST_MESSAGE (0xF3F12F2A, AttributeListMessage.class), + STOP_CLIENT_EFFECT_OBJECT_BY_LABEL (0xAD6F6B26, StopClientEffectObjectByLabelMessage.class), + OPENED_CONTAINER_MESSAGE (0x2E11E4AB, OpenedContainerMessage.class), + + // Combat + UPDATE_PVP_STATUS_MESSAGE (0x08a1c126, UpdatePvpStatusMessage.class), + GRANT_COMMAND_MESSAGE (0xE67E3875, GrantCommandMessage.class), + + // Server UI + OBJECT_MENU_REQUEST (0x00000146, ObjectMenuRequest.class), + OBJECT_MENU_RESPONSE (0x00000147, ObjectMenuResponse.class), + SUI_CREATE_PAGE_MESSAGE (0xD44B7259, SuiCreatePageMessage.class), + SUI_EVENT_NOTIFICATION (0x092D3564, SuiEventNotification.class), + + // Auction + IS_VENDOR_OWNER_RESPONSE_MESSAGE (0xCE04173E, IsVendorOwnerResponseMessage.class), + AUCTION_QUERY_HEADERS_MESSAGE (0x679E0D00, AuctionQueryHeadersMessage.class), + GET_AUCTION_DETAILS (0xD36EFAE4, GetAuctionDetails.class), + GET_AUCTION_DETAILS_RESPONSE (0xFE0E644B, GetAuctionDetailsResponse.class), + CANCEL_LIVE_AUCTION_MESSAGE (0x3687A4D2, CancelLiveAuctionMessage.class), + CANCEL_LIVE_AUCTION_RESPONSE_MESSAGE (0x7DA2246C, CancelLiveAuctionResponseMessage.class), + AUCTION_QUERY_HEADERS_RESPONSE_MESSAGE (0xFA500E52, AuctionQueryHeadersResponseMessage.class), + RETRIEVE_AUCTION_ITEM_MESSAGE (0x12B0D449, RetrieveAuctionItemMessage.class), + RETRIEVE_AUCTION_ITEM_RESPONSE_MESSAGE (0x9499EF8C, RetrieveAuctionItemResponseMessage.class), + + UNKNOWN (0xFFFFFFFF, SWGPacket.class); + + private static final Map packetMap = new HashMap(); + + static { + for (PacketType type : values()) { + packetMap.put(type.crc, type); + } + } + + private int crc; + private Class c; + + PacketType(int crc, Class c) { + this.crc = crc; + this.c = c; + } + + public int getCrc() { + return crc; + } + + public static final PacketType fromCrc(int crc) { + PacketType type = packetMap.get(crc); + if (type == null) + return UNKNOWN; + return type; + } + + public static final SWGPacket getForCrc(int crc) { + PacketType type = packetMap.get(crc); + if (type == null) + return null; + Class c = type.c; + try { + return c.newInstance(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/src/network/encryption/Encryption.java b/src/network/encryption/Encryption.java new file mode 100644 index 00000000..7d28db1e --- /dev/null +++ b/src/network/encryption/Encryption.java @@ -0,0 +1,116 @@ +package network.encryption; + +import java.nio.ByteBuffer; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +public class Encryption { + + public static String md5(String plaintext) { + return MD5.digest(plaintext); + } + + public static byte [] encode(byte [] input, int crc) { + return assembleMessage(input, crc); + } + + public static byte [] decode(byte [] input, int crc) { + return disassemble(input, crc); + } + + private static byte [] disassemble(byte [] data, int crcSeed) { + return decompress(encrypt(EncryptionCRC.validate(data, crcSeed), crcSeed, false)); + } + + private static byte [] assembleMessage(byte [] data, int crc) { + if (data.length < 2) + return data; + return EncryptionCRC.append(encrypt(compress(data), crc, true), crc); + } + + public static byte [] encrypt(byte [] data, int iCrc, boolean encrypt) { + if (data.length < 2) + return data; + byte [] encrypted = new byte[data.length]; + int start = 2; + encrypted[0] = data[0]; + if (data[0] != 0) + start = 1; + else + encrypted[1] = data[1]; + if (data.length < 6) { + for (int i = start; i < data.length; i++) + encrypted[i] = (byte) (data[i] ^ iCrc); + return encrypted; + } + int lastBytes = start+(int)((data.length-start)/4)*4; + byte [] crc = new byte[] {(byte)(iCrc), (byte)(iCrc >>> 8),(byte)(iCrc >>> 16), (byte)(iCrc >>> 24)}; + for (int i = start; i < lastBytes; i++) { + encrypted[i] = (byte) (data[i] ^ crc[(i-start)%4]); + crc[(i-start)%4] = encrypt ? encrypted[i] : data[i]; + } + if (lastBytes >= 4) { // Avoids an Index Out of Bounds Exception + for (int i = lastBytes; i < data.length; i++) { // Remaining 0-3 bytes that won't fit w/ the crc + byte lastCrc = encrypt ? encrypted[lastBytes-4] : data[lastBytes-4]; + encrypted[i] = (byte) (data[i] ^ lastCrc); + } + } + return encrypted; + } + + public static byte [] compress(byte [] data) { + if (data.length >= 200) { + byte [] result = new byte[512]; + Deflater compressor = new Deflater(); + compressor.setInput(data, 2, data.length - 2); + compressor.finish(); + int length = compressor.deflate(result); + if (length < data.length) { + ByteBuffer bb = ByteBuffer.allocate(length+3); + bb.put(data[0]).put(data[1]); + bb.put(result, 0, length); + bb.put((byte) 1); + return bb.array(); + } + } + return ByteBuffer.allocate(data.length+1).put(data).put((byte) 0).array(); + } + + private static byte [] decompress(byte [] data) { + if (data.length == 0) + return data; + else if (data[data.length - 1] == 0) + return ByteBuffer.allocate(data.length - 1).put(data, 0, data.length - 1).array(); + else if (data[data.length - 1] != 1) + return new byte[0]; + + int startingIndex = data[0] > 0 ? 1 : 2; + byte [] result = new byte[512]; + int length = inflate(startingIndex, data, result); + if (length == -1) + return data; + + byte [] ret = new byte[length+startingIndex]; + ret[0] = data[0]; + if (startingIndex > 1) + System.arraycopy(data, 1, ret, 1, startingIndex-1); + System.arraycopy(result, 0, ret, startingIndex, length); + return ret; + } + + private static int inflate(int startingIndex, byte [] data, byte [] result) { + Inflater decompressor = new Inflater(); + decompressor.setInput(data, startingIndex, data.length - startingIndex); + + try { + int length = decompressor.inflate(result); + decompressor.end(); + return length; + } catch (DataFormatException e) { + System.err.println("Failed to decompress packet. "+e.getClass().getSimpleName()+" Message: " + e.getMessage()); + return -1; + } + } + +} diff --git a/src/network/encryption/EncryptionCRC.java b/src/network/encryption/EncryptionCRC.java new file mode 100644 index 00000000..996a02c3 --- /dev/null +++ b/src/network/encryption/EncryptionCRC.java @@ -0,0 +1,76 @@ +package network.encryption; + +import java.nio.ByteBuffer; + +class EncryptionCRC { + + private static int [] crcTable = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; + + public static short generate(byte [] data, int crcSeed) { + return generate(data, 0, data.length, crcSeed); + } + + public static short generate(byte [] data, int off, int len, int crcSeed) { + int crc = crcTable[(~crcSeed) & 0xFF]; + int index; + + if (data.length <= 4) return 0; + + crc ^= 0x00FFFFFF; + + for (int i = 1; i < 4; i++, crc = ((crc >> 8) & 0x00FFFFFF) ^ crcTable[index & 0xFF]) + index = (crcSeed >> (8 * i) ^ crc); + for (int i = off; i < off+len; i++, crc = ((crc >> 8) & 0x00FFFFFF) ^ crcTable[index & 0xFF]) + index = (data[i]) ^ crc; + + return (short)~crc; + } + + private static boolean isValid(byte[] data, int crcSeed) { + try { + short gen = generate(data, 0, data.length-2, crcSeed); + short crc = (short)((data[data.length-2] << 8) + (data[data.length-1] & 0xff)); + return crc == gen; + } catch (java.lang.ArrayIndexOutOfBoundsException e) { + + } + return false; + } + + public static byte[] append(byte[] data, int crcSeed) { + return ByteBuffer.allocate(data.length + 2).put(data).putShort(generate(data, crcSeed)).array(); + } + + public static byte[] validate(byte[] data, int crcSeed) { + if (isValid(data, crcSeed)) + return ByteBuffer.allocate(data.length - 2).put(data, 0, data.length-2).array(); + return new byte[] { }; + } + +} diff --git a/src/network/encryption/MD5.java b/src/network/encryption/MD5.java new file mode 100644 index 00000000..8f65e5db --- /dev/null +++ b/src/network/encryption/MD5.java @@ -0,0 +1,30 @@ +package network.encryption; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.io.UnsupportedEncodingException; + +public class MD5 { + + public static String digest(String text) { + String result = text; + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(text.getBytes("iso-8859-1"), 0, text.length()); + result = convertToHex(md.digest()); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return result; + } + + private static String convertToHex(byte[] b) { + StringBuilder result = new StringBuilder(32); + for (int i = 0; i < b.length; i++) { + result.append(Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 )); + } + return result.toString(); + } +} \ No newline at end of file diff --git a/src/network/packets/Packet.java b/src/network/packets/Packet.java new file mode 100644 index 00000000..7ddb4712 --- /dev/null +++ b/src/network/packets/Packet.java @@ -0,0 +1,185 @@ +package network.packets; + +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; + + +public class Packet { + public static Charset ascii = Charset.forName("UTF-8"); + public static Charset unicode = Charset.forName("UTF-16LE"); + private InetAddress address; + private ByteBuffer data; + private int port = 0; + private int opcode; + + public Packet() { + data = ByteBuffer.allocate(2); + } + + public Packet(ByteBuffer data) { + decode(data); + } + + public void setAddress(InetAddress address) { + this.address = address; + } + + public InetAddress getAddress() { + return address; + } + + public void setPort(int port) { + this.port = port; + } + + public int getPort() { + return port; + } + + public void setOpcode(int opcode) { + this.opcode = opcode; + } + + public int getOpcode() { + return opcode; + } + + public static void addBoolean(ByteBuffer bb, boolean b) { + bb.put(b ? (byte)1 : (byte)0); + } + + public static void addAscii(ByteBuffer bb, String s) { + bb.order(ByteOrder.LITTLE_ENDIAN); + bb.putShort((short)s.length()); + bb.put(s.getBytes(ascii)); + } + + public static void addUnicode(ByteBuffer bb, String s) { + bb.order(ByteOrder.LITTLE_ENDIAN); + bb.putInt(s.length()); + bb.put(s.getBytes(unicode)); + } + + public static void addLong(ByteBuffer bb, long l) { + bb.order(ByteOrder.LITTLE_ENDIAN).putLong(l); + } + + public static void addInt(ByteBuffer bb, int i) { + bb.order(ByteOrder.LITTLE_ENDIAN).putInt(i); + } + + public static void addFloat(ByteBuffer bb, float f) { + bb.putFloat(f); + } + + public static void addShort(ByteBuffer bb, int i) { + bb.order(ByteOrder.LITTLE_ENDIAN).putShort((short)i); + } + + public static void addNetLong(ByteBuffer bb, long l) { + bb.order(ByteOrder.BIG_ENDIAN).putLong(l); + } + + public static void addNetInt(ByteBuffer bb, int i) { + bb.order(ByteOrder.BIG_ENDIAN).putInt(i); + } + + public static void addNetShort(ByteBuffer bb, int i) { + bb.order(ByteOrder.BIG_ENDIAN).putShort((short)i); + } + + public static void addByte(ByteBuffer bb, int b) { + bb.put((byte)b); + } + + public static void addArray(ByteBuffer bb, byte [] b) { + addShort(bb, b.length); + bb.put(b); + } + + public static boolean getBoolean(ByteBuffer bb) { + return getByte(bb) == 1 ? true : false; + } + + public static String getAscii(ByteBuffer bb) { + bb.order(ByteOrder.LITTLE_ENDIAN); + short length = bb.getShort(); + if (length > bb.remaining()) + return ""; + byte [] str = new byte[length]; + bb.get(str); + return new String(str, ascii); + } + + public static String getUnicode(ByteBuffer bb) { + bb.order(ByteOrder.LITTLE_ENDIAN); + int length = bb.getInt() * 2; + if (length > bb.remaining()) + return ""; + byte [] str = new byte[length]; + bb.get(str); + return new String(str, unicode); + } + + public static byte getByte(ByteBuffer bb) { + return bb.get(); + } + + public static short getShort(ByteBuffer bb) { + return bb.order(ByteOrder.LITTLE_ENDIAN).getShort(); + } + + public static int getInt(ByteBuffer bb) { + return bb.order(ByteOrder.LITTLE_ENDIAN).getInt(); + } + + public static float getFloat(ByteBuffer bb) { + return bb.getFloat(); + } + + public static long getLong(ByteBuffer bb) { + return bb.order(ByteOrder.LITTLE_ENDIAN).getLong(); + } + + public static short getNetShort(ByteBuffer bb) { + return bb.order(ByteOrder.BIG_ENDIAN).getShort(); + } + + public static int getNetInt(ByteBuffer bb) { + return bb.order(ByteOrder.BIG_ENDIAN).getInt(); + } + + public static long getNetLong(ByteBuffer bb) { + return bb.order(ByteOrder.BIG_ENDIAN).getLong(); + } + + public static byte [] getArray(ByteBuffer bb) { + byte [] data = new byte[getShort(bb)]; + bb.get(data); + return data; + } + + public static byte [] getArray(ByteBuffer bb, int length) { + byte [] data = new byte[length]; + bb.get(data); + return data; + } + + public void decode(ByteBuffer data) { + data.position(0); + this.data = data; + opcode = getNetShort(data); + data.position(0); + } + + public ByteBuffer getData() { + return data; + } + + public ByteBuffer encode() { + return data; + } + +} diff --git a/src/network/packets/soe/Acknowledge.java b/src/network/packets/soe/Acknowledge.java new file mode 100644 index 00000000..1d16c0d8 --- /dev/null +++ b/src/network/packets/soe/Acknowledge.java @@ -0,0 +1,41 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; + +import network.packets.Packet; + +public class Acknowledge extends Packet { + + private short sequence; + + public Acknowledge() { + sequence = 0; + } + + public Acknowledge(ByteBuffer data) { + decode(data); + } + + public Acknowledge(short sequence) { + this.sequence = sequence; + } + + public void decode(ByteBuffer data) { + if (data.array().length < 4) + return; + data.position(2); + sequence = getNetShort(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(4); + addNetShort(data, 21); + addNetShort(data, sequence); + return data; + } + + public void setSequence(short sequence) { this.sequence = sequence; } + + public short getSequence() { return sequence; } + +} diff --git a/src/network/packets/soe/ClientNetworkStatusUpdate.java b/src/network/packets/soe/ClientNetworkStatusUpdate.java new file mode 100644 index 00000000..b32ab5f3 --- /dev/null +++ b/src/network/packets/soe/ClientNetworkStatusUpdate.java @@ -0,0 +1,80 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; +import network.packets.Packet; + + +public class ClientNetworkStatusUpdate extends Packet { + + private int clientTickCount; + private int lastUpdate; + private int avgUpdate; + private int shortUpdate; + private int longUpdate; + private int lastServerUpdate; + private long packetSent; + private long packetRecv; + + public ClientNetworkStatusUpdate() { + + } + + public ClientNetworkStatusUpdate(ByteBuffer data) { + decode(data); + } + + public ClientNetworkStatusUpdate(int clientTickCount, int lastUpdate, int avgUpdate, int shortUpdate, int longUpdate, int lastServerUpdate, long packetsSent, long packetsRecv) { + this.clientTickCount = clientTickCount; + this.lastUpdate = lastUpdate; + this.avgUpdate = avgUpdate; + this.shortUpdate = shortUpdate; + this.longUpdate = longUpdate; + this.lastServerUpdate = lastServerUpdate; + this.packetSent = packetsSent; + this.packetRecv = packetsRecv; + } + + public void decode(ByteBuffer data) { + data.position(2); + clientTickCount = getNetShort(data); + lastUpdate = getNetInt(data); + avgUpdate = getNetInt(data); + shortUpdate = getNetInt(data); + longUpdate = getNetInt(data); + lastServerUpdate = getNetInt(data); + packetSent = getNetLong(data); + packetRecv = getNetLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(40); + addNetShort(data, 7); + addNetShort(data, clientTickCount); + addNetInt( data, lastUpdate); + addNetInt( data, avgUpdate); + addNetInt( data, shortUpdate); + addNetInt( data, longUpdate); + addNetInt( data, lastServerUpdate); + addNetLong( data, packetSent); + addNetLong( data, packetRecv); + return data; + } + + public int getTick() { return clientTickCount; } + public int getLastUpdate() { return lastUpdate; } + public int getAverageUpdate() { return avgUpdate; } + public int getShortestUpdate() { return shortUpdate; } + public int getLongestUpdate() { return longUpdate; } + public int getLastServerUpdate() { return lastServerUpdate; } + public long getSent() { return packetSent; } + public long getRecv() { return packetRecv; } + + public void setTick(int tick) { this.clientTickCount = tick; } + public void setLastUpdate(int last) { this.lastUpdate = last; } + public void setAverageUpdate(int avg) { this.avgUpdate = avg; } + public void setShortestUpdate(int shortest) { this.shortUpdate = shortest; } + public void setLongestUpdate(int longest) { this.longUpdate = longest; } + public void setLastServerUpdate(int last) { this.lastServerUpdate = last; } + public void setPacketsSent(long sent) { this.packetSent = sent; } + public void setPacketsRecv(long recv) { this.packetRecv = recv; } +} diff --git a/src/network/packets/soe/DataChannelA.java b/src/network/packets/soe/DataChannelA.java new file mode 100644 index 00000000..fd91b2d0 --- /dev/null +++ b/src/network/packets/soe/DataChannelA.java @@ -0,0 +1,141 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import network.packets.Packet; +import network.packets.swg.SWGPacket; + + +public class DataChannelA extends Packet implements Comparable { + + private List content = new ArrayList(); + private short sequence = 0; + private short multiPacket = 0; + + public DataChannelA() { + + } + + public DataChannelA(ByteBuffer data) { + decode(data); + } + + public DataChannelA(SWGPacket packet) { + content.add(packet); + } + + public DataChannelA(List packets) { + content = packets; + } + + public DataChannelA(SWGPacket [] packets) { + for (SWGPacket p : packets) { + content.add(p); + } + } + + public void decode(ByteBuffer data) { + super.decode(data); + if (getOpcode() != 9) + return; + data.position(2); + sequence = getNetShort(data); + multiPacket = getNetShort(data); + if (multiPacket == 0x19) { + int length = 0; + while (data.remaining() > 1) { + length = getByte(data) & 0xFF; + if (length == 0xFF) + length = getNetShort(data); + if (length > data.remaining()) { + data.position(data.position()-1); + return; + } + byte [] pData = new byte[length]; + data.get(pData); + SWGPacket packet = new SWGPacket(); + packet.decode(ByteBuffer.wrap(pData)); + content.add(packet); + } + } else { + data.position(data.position()-2); + byte [] pData = new byte[data.remaining()]; + data.get(pData); + SWGPacket packet = new SWGPacket(); + packet.decode(ByteBuffer.wrap(pData)); + content.add(packet); + } + } + + public ByteBuffer encode() { + return encode(this.sequence); + } + + public ByteBuffer encode(int sequence) { + this.sequence = (short) sequence; + if (content.size() == 1) { + byte [] pData = content.get(0).encode().array(); + ByteBuffer data = ByteBuffer.allocate(4 + pData.length); + addNetShort(data, 9); + addNetShort(data, sequence); + data.put(pData); + return data; + } else if (content.size() > 1) { + int length = getLength(); + ByteBuffer data= ByteBuffer.allocate(length); + addNetShort(data, 9); + addNetShort(data, sequence); + addNetShort(data, 0x19); + for (SWGPacket packet : content) { + byte [] pData = packet.encode().array(); + if (pData.length >= 0xFF) { + addByte(data, 0xFF); + addNetShort(data, pData.length); + } else { + data.put((byte) pData.length); + } + data.put(pData); + } + return data; + } else { + return ByteBuffer.allocate(0); + } + } + + public void addPacket(SWGPacket packet) { + content.add(packet); + } + + public void clearPackets() { + content.clear(); + } + + public int getLength() { + if (content.size() == 1) { + return 4 + content.get(0).encode().array().length; + } else { + int length = 6; + for (SWGPacket packet : content) { + int addLength = packet.encode().array().length; + length += 1 + addLength + ((addLength >= 0xFF) ? 2 : 0); + } + return length; + } + } + + @Override + public int compareTo(DataChannelA d) { + if (sequence < d.sequence) + return -1; + if (sequence == d.sequence) + return 0; + return 1; + } + + public void setSequence(short sequence) { this.sequence = sequence; } + + public short getSequence() { return sequence; } + public List getPackets() { return content; } +} diff --git a/src/network/packets/soe/Disconnect.java b/src/network/packets/soe/Disconnect.java new file mode 100644 index 00000000..bda907ce --- /dev/null +++ b/src/network/packets/soe/Disconnect.java @@ -0,0 +1,78 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; + +import network.packets.Packet; + + +public class Disconnect extends Packet { + + private int connectionId; + private DisconnectReason reason; + + public Disconnect() { + connectionId = 0; + reason = DisconnectReason.NONE; + } + + public Disconnect(int connectionId, DisconnectReason reason) { + this.connectionId = connectionId; + this.reason = reason; + } + + public Disconnect(ByteBuffer data){ + this.decode(data); + } + + public void decode(ByteBuffer data) { + data.position(2); + connectionId = getNetInt(data); + reason = getReason(getNetShort(data)); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(8); + addNetShort(data, 5); + addNetInt(data, connectionId); + addNetShort(data, reason.getReason()); + return data; + } + + public int getConnectionID() { return connectionId; } + public DisconnectReason getReason() { return reason; } + + private DisconnectReason getReason(int reason) { + for (DisconnectReason dr : DisconnectReason.values()) + if (dr.getReason() == reason) + return dr; + return DisconnectReason.NONE; + } + + public enum DisconnectReason { + NONE (0x00), + ICMP_ERROR (0x01), + TIMEOUT (0x02), + OTHER_SIDE_TERMINATED (0x03), + MANAGER_DELETED (0x04), + CONNECT_FAIL (0x05), + APPLICATION (0x06), + UNREACHABLE_CONNECTION (0x07), + UNACKNOWLEDGED_TIMEOUT (0x08), + NEW_CONNECTION_ATTEMPT (0x09), + CONNECTION_REFUSED (0x0A), + MUTUAL_CONNETION_ERROR (0x0B), + CONNETING_TO_SELF (0x0C), + RELIABLE_OVERFLOW (0x0D), + COUNT (0x0E); + + private short reason; + + DisconnectReason(int reason) { + this.reason = (short) reason; + } + + public short getReason() { + return reason; + } + } +} diff --git a/src/network/packets/soe/Fragmented.java b/src/network/packets/soe/Fragmented.java new file mode 100644 index 00000000..f17f9582 --- /dev/null +++ b/src/network/packets/soe/Fragmented.java @@ -0,0 +1,114 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; + +import network.packets.Packet; + + +public class Fragmented extends Packet implements Comparable { + + private short sequence; + private int length; + private ByteBuffer packet; + private ByteBuffer data; + + public Fragmented() { + this.sequence = 0; + this.length = 0; + this.packet = null; + this.data = null; + } + + public Fragmented(ByteBuffer data) { + decode(data); + length = -1; + } + + public Fragmented(ByteBuffer data, int sequence) { + this.sequence = (short) sequence; + decode(data); + length = -1; + } + + public void setPacket(ByteBuffer packet) { + this.packet = packet; + } + + public void decode(ByteBuffer data) { + data.position(2); + sequence = getNetShort(data); + this.data = data; + } + + public ByteBuffer encode() { + return data; + } + + public Fragmented [] encode(int startSequence) { + packet.position(0); + int ord = 0; + Fragmented [] packets = new Fragmented[(int) Math.ceil((packet.remaining()+4)/489.0)]; + while (packet.remaining() > 0) { + packets[ord] = createSegment(startSequence++, ord++, packet); + } + return packets; + } + + @Override + public int compareTo(Fragmented f) { + if (sequence < f.sequence) + return -1; + if (sequence == f.sequence) + return 0; + return 1; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Fragmented) + return ((Fragmented) o).sequence == sequence; + if (o instanceof Number) + return ((Number) o).shortValue() == sequence; + return false; + } + + @Override + public int hashCode() { + return sequence; + } + + public ByteBuffer getPacketData() { return data; } + public short getSequence() { return sequence; } + public int getDatLength() { return length; } + + public static final Fragmented [] encode(ByteBuffer data, int startSequence) { + data.position(0); + int ord = 0; + Fragmented [] packets = new Fragmented[(int) Math.ceil((data.remaining()+4)/489.0)]; + while (data.remaining() > 0) { + packets[ord] = createSegment(startSequence++, ord++, data); + } + return packets; + } + + private static final Fragmented createSegment(int startSequence, int ord, ByteBuffer packet) { + int header = (ord == 0) ? 8 : 4; + ByteBuffer data = ByteBuffer.allocate(Math.min(packet.remaining()+header, 493)); + + addNetShort(data, 0x0D); + addNetShort(data, startSequence); + if (ord == 0) + addNetInt(data, packet.remaining()); + + int len = data.remaining(); + data.put(packet.array(), packet.position(), len); + packet.position(packet.position() + len); + + byte [] pData = new byte[data.array().length-header]; + System.arraycopy(data.array(), header, pData, 0, pData.length); + Fragmented f = new Fragmented(data, startSequence); + f.packet = ByteBuffer.wrap(pData); + return f; + } + +} diff --git a/src/network/packets/soe/MultiPacket.java b/src/network/packets/soe/MultiPacket.java new file mode 100644 index 00000000..f5fc5375 --- /dev/null +++ b/src/network/packets/soe/MultiPacket.java @@ -0,0 +1,113 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +import network.packets.Packet; + +public class MultiPacket extends Packet { + + private List content = new ArrayList(); + + public MultiPacket() { + this(new ArrayList()); + } + + public MultiPacket(ByteBuffer data) { + this(new ArrayList()); + decode(data); + } + + public MultiPacket(List packets) { + this.content = packets; + } + + public void decode(ByteBuffer data) { + data.position(2); + int length = data.array().length; + int pLength = 0; + for (int i = 2; i < length; i += pLength) { + if (data.remaining() < 1) + return; + pLength = getByte(data) & 0xFF; + if (pLength == 255) { + if (data.remaining() < 2) + return; + pLength = data.order(ByteOrder.LITTLE_ENDIAN).getShort(); + } + if (pLength > data.remaining()) { + data.position(data.position()-1); + return; + } + byte [] pData = new byte[pLength]; + data.get(pData); + Packet p = new Packet(); + p.decode(ByteBuffer.wrap(pData)); + content.add(p); + } + } + + public ByteBuffer encode() { + int length = 2; + for (Packet packet : content) { + int pLength = packet.encode().array().length; + if (pLength >= 255) { + length += 3; + } else { + length += 1; + } + length += pLength; + } + ByteBuffer data = ByteBuffer.allocate(length); + data.order(ByteOrder.BIG_ENDIAN).putShort((short)3); + for (Packet packet : content) { + byte [] pData = packet.encode().array(); + if (pData.length >= 255) { + data.put((byte)255); + addShort(data, (short)pData.length); + } else { + data.put((byte)pData.length); + } + data.put(pData); + } + return data; + } + + public int getLength() { + int length = 2; + for (Packet packet : content) { + int pLength = getPacketLength(packet); + if (pLength >= 255) { + length += 3; + } else { + length += 1; + } + length += pLength; + } + return length; + } + + private int getPacketLength(Packet packet) { + if (packet instanceof DataChannelA) + return ((DataChannelA) packet).getLength(); + else if (packet instanceof Acknowledge || packet instanceof OutOfOrder) + return 4; + else if (packet instanceof Disconnect) + return 8; + return packet.encode().array().length; + } + + public void addPacket(Packet packet) { + content.add(packet); + } + + public void clearPackets() { + content.clear(); + } + + public List getPackets() { + return content; + } +} diff --git a/src/network/packets/soe/OutOfOrder.java b/src/network/packets/soe/OutOfOrder.java new file mode 100644 index 00000000..2921d47d --- /dev/null +++ b/src/network/packets/soe/OutOfOrder.java @@ -0,0 +1,37 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; + +import network.packets.Packet; + + +public class OutOfOrder extends Packet { + + private short sequence; + + public OutOfOrder() { + + } + + public OutOfOrder(short sequence) { + this.sequence = sequence; + } + + public OutOfOrder(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + data.position(2); + sequence = getNetShort(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(4); + addNetShort(data, 0x11); + addNetShort(data, sequence); + return data; + } + + public short getSequence() { return sequence; } +} diff --git a/src/network/packets/soe/ServerNetworkStatusUpdate.java b/src/network/packets/soe/ServerNetworkStatusUpdate.java new file mode 100644 index 00000000..37226b78 --- /dev/null +++ b/src/network/packets/soe/ServerNetworkStatusUpdate.java @@ -0,0 +1,69 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; + +import network.packets.Packet; + + +public class ServerNetworkStatusUpdate extends Packet { + + private short clientTickCount = 0; + private int serverSyncStampLong = 0; + private long clientPacketsSent = 0; + private long clientPacketsRecv = 0; + private long serverPacketsSent = 0; + private long serverPacketsRecv = 0; + + public ServerNetworkStatusUpdate() { + + } + + public ServerNetworkStatusUpdate(ByteBuffer data) { + decode(data); + } + + public ServerNetworkStatusUpdate(int clientTickCount, long clientSent, long clientRecv, long serverSent, long serverRecv) { + this.clientTickCount = (short) clientTickCount; + this.serverSyncStampLong = 0; + this.clientPacketsSent = clientSent; + this.clientPacketsRecv = clientRecv; + this.serverPacketsSent = serverSent; + this.serverPacketsRecv = serverRecv; + } + + public void decode(ByteBuffer data) { + data.position(2); + clientTickCount = getNetShort(data); + serverSyncStampLong = getNetInt(data); + clientPacketsSent = getNetLong(data); + clientPacketsRecv = getNetLong(data); + serverPacketsSent = getNetLong(data); + serverPacketsRecv = getNetLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(40); + addNetShort(data, 8); + addNetShort(data, clientTickCount); + addNetInt( data, serverSyncStampLong); + addNetLong( data, clientPacketsSent); + addNetLong( data, clientPacketsRecv); + addNetLong( data, serverPacketsSent); + addNetLong( data, serverPacketsRecv); + return data; + } + + public short getClientTickCount() { return clientTickCount; } + public int getServerSyncStampLong() { return serverSyncStampLong; } + public long getClientPacketsSent() { return clientPacketsSent; } + public long getClientPacketsRecv() { return clientPacketsRecv; } + public long getServerPacketsSent() { return serverPacketsSent; } + public long getServerPacketsRecv() { return serverPacketsRecv; } + + public void setClientTickCount(short tick) { this.clientTickCount = tick; } + public void setServerSyncStampLong(int sync) { this.serverSyncStampLong = sync; } + public void setClientPacketsSent(int sent) { this.clientPacketsSent = sent; } + public void setClientPacketsRecv(int recv) { this.clientPacketsRecv = recv; } + public void setServerPacketsSent(int sent) { this.serverPacketsSent = sent; } + public void setServerPacketsRecv(int recv) { this.serverPacketsRecv = recv; } +} diff --git a/src/network/packets/soe/SessionRequest.java b/src/network/packets/soe/SessionRequest.java new file mode 100644 index 00000000..6d1f0122 --- /dev/null +++ b/src/network/packets/soe/SessionRequest.java @@ -0,0 +1,49 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import network.packets.Packet; + + +public class SessionRequest extends Packet { + + private int crcLength; + private int connectionID; + private int udpSize; + + public SessionRequest() { + + } + + public SessionRequest(ByteBuffer data) { + decode(data); + } + + public SessionRequest(int crcLength, int connectionID, int udpSize) { + this.crcLength = crcLength; + this.connectionID = connectionID; + this.udpSize = udpSize; + } + + public void decode(ByteBuffer packet) { + super.decode(packet); + packet.position(2); + crcLength = getNetInt(packet); + connectionID = getNetInt(packet); + udpSize = getNetInt(packet); + } + + public ByteBuffer encode() { + ByteBuffer bb = ByteBuffer.allocate(14).order(ByteOrder.BIG_ENDIAN); + addNetShort(bb, 1); + addNetInt(bb, crcLength); + addNetInt(bb, connectionID); + addNetInt(bb, udpSize); + return bb; + } + + public int getCrcLength() { return crcLength; } + public int getConnectionID() { return connectionID; } + public int getUdpSize() { return udpSize; } +} diff --git a/src/network/packets/soe/SessionResponse.java b/src/network/packets/soe/SessionResponse.java new file mode 100644 index 00000000..7b3c7a04 --- /dev/null +++ b/src/network/packets/soe/SessionResponse.java @@ -0,0 +1,76 @@ +package network.packets.soe; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import network.packets.Packet; + + +public class SessionResponse extends Packet { + + private int connectionID; + private int crcSeed; + private byte crcLength; + private byte encryptionFlag; + private byte xorLength; + private int udpSize; + + public SessionResponse() { + + } + + public SessionResponse(ByteBuffer data) { + decode(data); + } + + public SessionResponse(int connectionID, + int crcSeed, + byte crcLength, + byte encryptionFlag, + byte xorLength, + int udpSize) { + this.connectionID = connectionID; + this.crcSeed = crcSeed; + this.crcLength = crcLength; + this.encryptionFlag = encryptionFlag; + this.xorLength = xorLength; + this.udpSize = udpSize; + } + + public void decode(ByteBuffer data) { + super.decode(data); + data.position(2); + connectionID = getNetInt(data); + crcSeed = getNetInt(data); + crcLength = data.get(); + encryptionFlag = data.get(); + xorLength = data.get(); + udpSize = getNetInt(data); + } + + public ByteBuffer encode() { + ByteBuffer bb = ByteBuffer.allocate(17).order(ByteOrder.BIG_ENDIAN); + addNetShort(bb, 2); + addNetInt( bb, connectionID); + addNetInt( bb, crcSeed); + addByte( bb, crcLength); + addByte( bb, encryptionFlag); + addByte( bb, xorLength); + addNetInt( bb, udpSize); + return bb; + } + + public int getConnectionID() { return connectionID; } + public int getCrcSeed() { return crcSeed; } + public byte getCrcLength() { return crcLength; } + public short getEncryptionFlag() { return encryptionFlag; } + public byte getXorLength() { return xorLength; } + public int getUdpSize() { return udpSize; } + + public void setConnectionID(int id) { this.connectionID = id; } + public void setCrcSeed(int crc) { this.crcSeed = crc; } + public void setCrcLength(int length) { this.crcLength = (byte) length; } + public void setEncryptionFlag(short flag) { this.encryptionFlag = (byte) flag; } + public void setXorLength(byte xorLength) { this.xorLength = xorLength; } + public void setUdpSize(int size) { this.udpSize = size; } +} diff --git a/src/network/packets/swg/ErrorMessage.java b/src/network/packets/swg/ErrorMessage.java new file mode 100644 index 00000000..b3eb12a4 --- /dev/null +++ b/src/network/packets/swg/ErrorMessage.java @@ -0,0 +1,40 @@ +package network.packets.swg; + +import java.nio.ByteBuffer; + + +public class ErrorMessage extends SWGPacket { + public static final int CRC = 0xB5ABF91A; + private String type; + private String message; + private boolean fatal; + + public ErrorMessage() { + + } + + public ErrorMessage(String type, String message, boolean fatal) { + this.type = type; + this.message = message; + this.fatal = fatal; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + type = getAscii(data); + message = getAscii(data); + fatal = getBoolean(data); + } + + public ByteBuffer encode() { + int length = 11 + type.length() + message.length(); + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 3); + addInt( data, CRC); + addAscii(data, type); + addAscii(data, message); + addBoolean(data, fatal); + return data; + } +} diff --git a/src/network/packets/swg/SWGPacket.java b/src/network/packets/swg/SWGPacket.java new file mode 100644 index 00000000..b8438e96 --- /dev/null +++ b/src/network/packets/swg/SWGPacket.java @@ -0,0 +1,77 @@ +package network.packets.swg; + +import java.nio.ByteBuffer; + +import resources.Location; +import network.PacketType; +import network.packets.Packet; + + +public class SWGPacket extends Packet { + + private ByteBuffer data = null; + private int opcode = 0; + private PacketType type = PacketType.UNKNOWN; + + protected void addLocation(ByteBuffer data, Location l) { + addFloat(data, (float) (Double.isNaN(l.getOrientationX()) ? 0 : l.getOrientationX())); + addFloat(data, (float) (Double.isNaN(l.getOrientationY()) ? 0 : l.getOrientationY())); + addFloat(data, (float) (Double.isNaN(l.getOrientationZ()) ? 0 : l.getOrientationZ())); + addFloat(data, (float) (Double.isNaN(l.getOrientationW()) ? 1 : l.getOrientationW())); + addFloat(data, (float) (Double.isNaN(l.getX()) ? 0 : l.getX())); + addFloat(data, (float) (Double.isNaN(l.getY()) ? 0 : l.getY())); + addFloat(data, (float) (Double.isNaN(l.getZ()) ? 0 : l.getZ())); + } + + protected Location getLocation(ByteBuffer data) { + Location l = new Location(); + l.setOrientationX(getFloat(data)); + l.setOrientationY(getFloat(data)); + l.setOrientationZ(getFloat(data)); + l.setOrientationW(getFloat(data)); + l.setX(getFloat(data)); + l.setY(getFloat(data)); + l.setZ(getFloat(data)); + return l; + } + + public void setSWGOpcode(int opcode) { + this.opcode = opcode; + this.type = PacketType.fromCrc(opcode); + } + + public int getSWGOpcode() { + return opcode; + } + + public PacketType getPacketType() { + return type; + } + + public boolean decode(ByteBuffer data, int crc) { + this.data = data; + super.decode(data); + data.position(2); + setSWGOpcode(getInt(data)); + if (getSWGOpcode() != crc) + return false; + return true; + } + + public void decode(ByteBuffer data) { + this.data = data; + if (data.array().length < 6) + return; + data.position(2); + setSWGOpcode(getInt(data)); + data.position(0); + } + + public ByteBuffer encode() { + return data; + } + + public ByteBuffer getData() { + return data; + } +} diff --git a/src/network/packets/swg/ServerUnixEpochTime.java b/src/network/packets/swg/ServerUnixEpochTime.java new file mode 100644 index 00000000..c451f8c9 --- /dev/null +++ b/src/network/packets/swg/ServerUnixEpochTime.java @@ -0,0 +1,36 @@ +package network.packets.swg; + +import java.nio.ByteBuffer; + + +public class ServerUnixEpochTime extends SWGPacket { + + public static final int CRC = 0x24B73893; + private int time = 0; + + public ServerUnixEpochTime() { + + } + + public ServerUnixEpochTime(int time) { + this.time = time; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + time = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort(data, 2); + addInt( data, CRC); + addInt( data, time); + return data; + } + + public int getTime() { + return time; + } +} diff --git a/src/network/packets/swg/login/AccountFeatureBits.java b/src/network/packets/swg/login/AccountFeatureBits.java new file mode 100644 index 00000000..9909879a --- /dev/null +++ b/src/network/packets/swg/login/AccountFeatureBits.java @@ -0,0 +1,33 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class AccountFeatureBits extends SWGPacket { + + public static final int CRC = 0x979F0279; + + public AccountFeatureBits() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + // Not sure how to decode this.. still a mystery + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(22); + addShort(data, 2); + addInt( data, CRC); + addInt( data, 0x025C8231); + addInt( data, 1); + addInt( data, 6); + addInt( data, 0x4EEAC08A); + return data; + } + +} diff --git a/src/network/packets/swg/login/CharacterCreationDisabled.java b/src/network/packets/swg/login/CharacterCreationDisabled.java new file mode 100644 index 00000000..5f00edad --- /dev/null +++ b/src/network/packets/swg/login/CharacterCreationDisabled.java @@ -0,0 +1,50 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class CharacterCreationDisabled extends SWGPacket { + + public static final int CRC = 0xF4A15265; + + private String [] serverNames = new String[0]; + + public CharacterCreationDisabled() { + this(new String[0]); + } + + public CharacterCreationDisabled(String [] serverNames) { + this.serverNames = serverNames; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + int listSize = getInt(data); + serverNames = new String[listSize]; + for (int i = 0; i < listSize; i++) { + serverNames[i] = getAscii(data); + } + } + + public ByteBuffer encode() { + int length = 10; + for (int i = 0; i < serverNames.length; i++) + length += 2 + serverNames[i].length(); + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 2); + addInt( data, CRC); + addInt( data, serverNames.length); + for (int i = 0; i < serverNames.length; i++) { + addAscii(data, serverNames[i]); + } + return data; + } + + public String [] getServerNames() { + return serverNames; + } + +} diff --git a/src/network/packets/swg/login/ClientIdMsg.java b/src/network/packets/swg/login/ClientIdMsg.java new file mode 100644 index 00000000..59745cbd --- /dev/null +++ b/src/network/packets/swg/login/ClientIdMsg.java @@ -0,0 +1,53 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class ClientIdMsg extends SWGPacket { + + public static final int CRC = 0xD5899226; + private int gameBitsToClear; + private byte [] sessionToken; + private String version; + + public ClientIdMsg() { + this(0, new byte[0], ""); + } + + public ClientIdMsg(ByteBuffer data) { + decode(data); + } + + public ClientIdMsg(int gameBitsToClear, byte [] sessionKey, String version) { + this.gameBitsToClear = gameBitsToClear; + this.sessionToken = sessionKey; + this.version = version; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + gameBitsToClear = getInt(data); + int sessionKeyLength = getInt(data); + sessionToken = new byte[sessionKeyLength]; + data.get(sessionToken); + version = getAscii(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(16 + sessionToken.length + version.length()); + addShort(data, 4); + addInt( data, CRC); + addInt( data, gameBitsToClear); + addInt( data, sessionToken.length); + data.put(sessionToken); + addAscii(data, version); + return data; + } + + public int getGameBitsToClear() { return gameBitsToClear; } + public byte [] getSessionToken() { return sessionToken; } + public String getVersion() { return version; } +} diff --git a/src/network/packets/swg/login/ClientPermissionsMessage.java b/src/network/packets/swg/login/ClientPermissionsMessage.java new file mode 100644 index 00000000..6016104c --- /dev/null +++ b/src/network/packets/swg/login/ClientPermissionsMessage.java @@ -0,0 +1,53 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class ClientPermissionsMessage extends SWGPacket { + + public static final int CRC = 0xE00730E5; + + private boolean canLogin; + private boolean canCreateRegularCharacter; + private boolean canCreateJediCharacter; + private boolean canSkipTutorial; + + public ClientPermissionsMessage() { + canLogin = true; + canCreateRegularCharacter = true; + canCreateJediCharacter = true; + canSkipTutorial = true; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + canLogin = getBoolean(data); + canCreateRegularCharacter = getBoolean(data); + canCreateJediCharacter = getBoolean(data); + canSkipTutorial = getBoolean(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort( data, 5); + addInt( data, CRC); + addBoolean(data, canLogin); + addBoolean(data, canCreateRegularCharacter); + addBoolean(data, canCreateJediCharacter); + addBoolean(data, canSkipTutorial); + return data; + } + + public void setCanLogin(boolean can) { this.canLogin = can; } + public void setCanCreateRegularCharacter(boolean can) { this.canCreateRegularCharacter = can; } + public void setCanCreateJediCharacter(boolean can) { this.canCreateJediCharacter = can; } + public void setCanSkipTutorial(boolean can) { this.canSkipTutorial = can; } + + public boolean canLogin() { return canLogin; } + public boolean canCreateRegularCharacter() { return canCreateRegularCharacter; } + public boolean canCreateJediCharacter() { return canCreateJediCharacter; } + public boolean canSkipTutorial() { return canSkipTutorial; } +} diff --git a/src/network/packets/swg/login/EnumerateCharacterId.java b/src/network/packets/swg/login/EnumerateCharacterId.java new file mode 100644 index 00000000..5d203391 --- /dev/null +++ b/src/network/packets/swg/login/EnumerateCharacterId.java @@ -0,0 +1,109 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; +import java.util.Vector; + +import network.packets.swg.SWGPacket; + + +public class EnumerateCharacterId extends SWGPacket { + + public static final int CRC = 0x65EA4574; + + private SWGCharacter [] characters; + + public EnumerateCharacterId() { + characters = new SWGCharacter[0]; + } + + public EnumerateCharacterId(SWGCharacter [] characters) { + this.characters = characters; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + int characterLength = getInt(data); + Vector _characters = new Vector(); + for (int i = 0; i < characterLength; i++) { + SWGCharacter c = new SWGCharacter(); + c.decode(data); + _characters.add(c); + } + characters = _characters.toArray(new SWGCharacter[0]); + } + + public ByteBuffer encode() { + int length = 10; + for (int i = 0; i < characters.length; i++) { + length += characters[i].getLength(); + } + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 2); + addInt( data, CRC); + addInt( data, characters.length); + for (SWGCharacter c : characters) { + data.put(c.encode().array()); + } + return data; + } + + public SWGCharacter [] getCharacters () { + return characters; + } + + public static class SWGCharacter extends EnumerateCharacterId { + private String name; + private int raceCrc; + private long id; + private int galaxyId; + private int type; + + public SWGCharacter() { + + } + + public SWGCharacter(String name, int raceCrc, long id, int galaxyId, int status) { + this.name = name; + this.raceCrc = raceCrc; + this.id = id; + this.galaxyId = galaxyId; + this.type = status; + } + + public int getLength() { + return 24 + name.length() * 2; + } + + public void decode(ByteBuffer data) { + name = getUnicode(data); + raceCrc = getInt(data); + id = getLong(data); + galaxyId = getInt(data); + type = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(getLength()); + addUnicode(data, name); + addInt( data, raceCrc); + addLong( data, id); + addInt( data, galaxyId); + addInt( data, type); + return data; + } + + public void setId(long id) { this.id = id; } + public void setName(String name) { this.name = name; } + public void setRaceCrc(int crc) { this.raceCrc = crc; } + public void setGalaxyId(int id) { this.galaxyId = id; } + public void setType(int type) { this.type = type; } + + public long getId() { return id; } + public String getName() { return name; } + public int getRaceCrc() { return raceCrc; } + public int getGalaxyId() { return galaxyId; } + public int getType() { return type; } + + } +} diff --git a/src/network/packets/swg/login/LoginClientId.java b/src/network/packets/swg/login/LoginClientId.java new file mode 100644 index 00000000..a3c6eacd --- /dev/null +++ b/src/network/packets/swg/login/LoginClientId.java @@ -0,0 +1,54 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class LoginClientId extends SWGPacket { + + public static final int CRC = 0x41131F96; + + private String username; + private String password; + private String version; + + public LoginClientId() { + this("", "", ""); + } + + public LoginClientId(ByteBuffer data) { + decode(data); + } + + public LoginClientId(String username, String password, String version) { + this.username = username; + this.password = password; + this.version = version; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + username = getAscii(data); + password = getAscii(data); + version = getAscii(data); + } + + public ByteBuffer encode() { + int length = 6 + 6 + username.length() * 2 + password.length() * 2 + version.length() * 2; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 4); + addInt( data, CRC); + addAscii(data, username); + addAscii(data, password); + addAscii(data, version); + return data; + } + + public String getUsername() { return username; } + public void setUsername(String str) { this.username = str; } + public String getPassword() { return password; } + public void setPassword(String str) { this.password = str; } + public String getVersion() { return version; } +} diff --git a/src/network/packets/swg/login/LoginClientToken.java b/src/network/packets/swg/login/LoginClientToken.java new file mode 100644 index 00000000..3a881179 --- /dev/null +++ b/src/network/packets/swg/login/LoginClientToken.java @@ -0,0 +1,65 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class LoginClientToken extends SWGPacket { + + public static final int CRC = 0xAAB296C6; + private byte [] sessionKey; + private int userId; + private String username; + + public LoginClientToken() { + + } + + public LoginClientToken(ByteBuffer data) { + decode(data); + } + + public LoginClientToken(byte [] sessionKey, int userId, String username) { + this.sessionKey = sessionKey; + this.userId = userId; + this.username = username; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + int sessionKeyLength = getInt(data); + if (sessionKeyLength > data.remaining()) + return; + sessionKey = new byte[sessionKeyLength]; + data.get(sessionKey); + userId = getInt(data); + username = getAscii(data); + } + + public ByteBuffer encode() { + int length = 16 + sessionKey.length + username.length(); + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 4); + addInt( data, CRC); + addInt( data, sessionKey.length); + data.put(sessionKey); + addInt( data, userId); + addAscii(data, username); + return data; + } + + public byte [] getSessionKey() { + return sessionKey; + } + + public int getUserId() { + return userId; + } + + public String getUsername() { + return username; + } + +} diff --git a/src/network/packets/swg/login/LoginClusterStatus.java b/src/network/packets/swg/login/LoginClusterStatus.java new file mode 100644 index 00000000..fe384075 --- /dev/null +++ b/src/network/packets/swg/login/LoginClusterStatus.java @@ -0,0 +1,92 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Vector; + +import network.packets.swg.SWGPacket; +import resources.Galaxy; + + +public class LoginClusterStatus extends SWGPacket { + + public static final int CRC = 0x3436AEB6; + + private Vector galaxies; + + public LoginClusterStatus() { + galaxies = new Vector(); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + int serverCount = getInt(data); + for (int i = 0; i < serverCount; i++) { + Galaxy g = new Galaxy(); + g.setId(getInt(data)); + g.setAddress(getAscii(data)); + g.setZonePort(getShort(data)); + g.setPingPort(getShort(data)); + g.setPopulation(getInt(data)); + g.setPopulationStatus(getInt(data)); + g.setMaxCharacters(getInt(data)); + g.setTimeZone(getInt(data)); + g.setStatus(getInt(data)); + g.setRecommended(getBoolean(data)); + g.setOnlinePlayerLimit(getInt(data)); + g.setOnlineFreeTrialLimit(getInt(data)); + galaxies.add(g); + } + } + + public ByteBuffer encode() { + int length = 10; + for (Galaxy g : galaxies) + length += 35 + g.getAddress().length() + 8; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 2); + addInt( data, CRC); + addInt( data, galaxies.size()); + for (Galaxy g : galaxies) { + addInt( data, g.getId()); + addAscii( data, g.getAddress()); + addShort( data, g.getZonePort()); + addShort( data, g.getPingPort()); + addInt( data, g.getPopulation()); + addInt( data, getPopulationStatus(g.getPopulation())); + addInt( data, g.getMaxCharacters()); + addInt( data, g.getTimeZone()); + addInt( data, g.getStatus().getStatus()); + addBoolean(data, g.isRecommended()); + addInt( data, g.getOnlinePlayerLimit()); + addInt( data, g.getOnlineFreeTrialLimit()); + } + return data; + } + + public void addGalaxy(Galaxy g) { + galaxies.add(g); + } + + public List getGalaxies() { + return galaxies; + } + + private int getPopulationStatus(int pop) { + if (pop < 300) + return 0; // Very Light + if (pop < 600) + return 1; // Light + if (pop < 900) + return 2; // Medium + if (pop < 1200) + return 3; // Heavy + if (pop < 1500) + return 4; // Very Heavy + if (pop < 3000) + return 5; // Extremely Heavy + return 6; // Full + } + +} diff --git a/src/network/packets/swg/login/LoginEnumCluster.java b/src/network/packets/swg/login/LoginEnumCluster.java new file mode 100644 index 00000000..bf4cfd2f --- /dev/null +++ b/src/network/packets/swg/login/LoginEnumCluster.java @@ -0,0 +1,73 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Vector; + +import network.packets.swg.SWGPacket; +import resources.Galaxy; + + +public class LoginEnumCluster extends SWGPacket { + + public static final int CRC = 0xC11C63B9; + + private Vector galaxies; + private int maxCharacters; + + public LoginEnumCluster() { + galaxies = new Vector(); + } + + public LoginEnumCluster(int maxCharacters) { + galaxies = new Vector(); + this.maxCharacters = maxCharacters; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + int serverCount = getInt(data); + for (int i = 0; i < serverCount; i++) { + Galaxy g = new Galaxy(); + g.setId(getInt(data)); + g.setName(getAscii(data)); + g.setTimeZone(getInt(data)); + galaxies.add(g); + } + maxCharacters = getInt(data); + } + + public ByteBuffer encode() { + int length = 14; + for (Galaxy g : galaxies) + length += 10 + g.getName().length(); + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 3); + addInt( data, CRC); + addInt( data, galaxies.size()); + for (Galaxy g : galaxies) { + addInt( data, g.getId()); + addAscii(data, g.getName()); + addInt( data, g.getTimeZone()); + } + addInt(data, maxCharacters); + return data; + } + + public void addGalaxy(Galaxy g) { + galaxies.add(g); + } + + public void setMaxCharacters(int max) { + this.maxCharacters = max; + } + + public int getMaxCharacters() { + return maxCharacters; + } + + public List getGalaxies() { + return galaxies; + } +} diff --git a/src/network/packets/swg/login/LoginIncorrectClientId.java b/src/network/packets/swg/login/LoginIncorrectClientId.java new file mode 100644 index 00000000..7580d52c --- /dev/null +++ b/src/network/packets/swg/login/LoginIncorrectClientId.java @@ -0,0 +1,43 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class LoginIncorrectClientId extends SWGPacket { + + public static final int CRC = 0x20E7E510; + + private String serverId; + private String serverAppVersion; + + public LoginIncorrectClientId() { + this("", ""); + } + + public LoginIncorrectClientId(ByteBuffer data) { + decode(data); + } + + public LoginIncorrectClientId(String serverId, String serverAppVersion) { + this.serverId = serverId; + this.serverAppVersion = serverAppVersion; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + serverId = getAscii(data); + serverAppVersion = getAscii(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10 + serverId.length() + serverAppVersion.length()); + addShort(data, 4); + addInt(data, CRC); + addAscii(data, serverId); + addAscii(data, serverAppVersion); + return data; + } + +} diff --git a/src/network/packets/swg/login/OfflineServersMessage.java b/src/network/packets/swg/login/OfflineServersMessage.java new file mode 100644 index 00000000..25a82439 --- /dev/null +++ b/src/network/packets/swg/login/OfflineServersMessage.java @@ -0,0 +1,60 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import network.packets.swg.SWGPacket; + +public class OfflineServersMessage extends SWGPacket { + + public static final int CRC = 0xF41A5265; + + private List offlineServers; + + public OfflineServersMessage() { + offlineServers = new ArrayList(); + } + + public OfflineServersMessage(List offline) { + this.offlineServers = offline; + } + + public OfflineServersMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + int listCount = getInt(data); + offlineServers = new ArrayList(listCount); + for (int i = 0 ; i < listCount; i++) + offlineServers.add(getAscii(data)); + } + + public ByteBuffer encode() { + int strLength = 0; + for (String str : offlineServers) + strLength += 2 + str.length(); + ByteBuffer data = ByteBuffer.allocate(10 + strLength); + addShort(data, 2); + addInt( data, CRC); + for (String str : offlineServers) + addAscii(data, str); + return data; + } + + public List getOfflineServers() { + return offlineServers; + } + + public void setOfflineServers(List offline) { + offlineServers = offline; + } + + public void addOflineServer(String offline) { + offlineServers.add(offline); + } + +} diff --git a/src/network/packets/swg/login/RequestExtendedClusters.java b/src/network/packets/swg/login/RequestExtendedClusters.java new file mode 100644 index 00000000..4655c05f --- /dev/null +++ b/src/network/packets/swg/login/RequestExtendedClusters.java @@ -0,0 +1,28 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class RequestExtendedClusters extends SWGPacket { + + public static final int CRC = 0x8E33ED05; + + public RequestExtendedClusters() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort(data, 2); + addInt( data, CRC); + addInt( data, 0); + return data; + } +} diff --git a/src/network/packets/swg/login/ServerId.java b/src/network/packets/swg/login/ServerId.java new file mode 100644 index 00000000..7875cb4c --- /dev/null +++ b/src/network/packets/swg/login/ServerId.java @@ -0,0 +1,39 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class ServerId extends SWGPacket { + + public static final int CRC = 0x58C07F21; + private int serverId = 0; + + public ServerId() { + + } + + public ServerId(int id) { + this.serverId = id; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + serverId = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort(data, 2); + addInt( data, CRC); + addInt( data, serverId); + return data; + } + + public int getServerId() { + return serverId; + } + +} diff --git a/src/network/packets/swg/login/ServerString.java b/src/network/packets/swg/login/ServerString.java new file mode 100644 index 00000000..0f14cea4 --- /dev/null +++ b/src/network/packets/swg/login/ServerString.java @@ -0,0 +1,39 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class ServerString extends SWGPacket { + + public static final int CRC = 0x0E20D7E9; + private String serverName = ""; + + public ServerString() { + + } + + public ServerString(String name) { + this.serverName = name; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + serverName = getAscii(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(8 + serverName.length()); + addShort(data, 2); + addInt( data, CRC); + addAscii(data, serverName); + return data; + } + + public String getServerString() { + return serverName; + } + +} diff --git a/src/network/packets/swg/login/StationIdHasJediSlot.java b/src/network/packets/swg/login/StationIdHasJediSlot.java new file mode 100644 index 00000000..3a0d5668 --- /dev/null +++ b/src/network/packets/swg/login/StationIdHasJediSlot.java @@ -0,0 +1,40 @@ +package network.packets.swg.login; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class StationIdHasJediSlot extends SWGPacket { + + public static final int CRC = 0xCC9FCCF8; + + private int jedi; + + public StationIdHasJediSlot() { + this.jedi = 1; + } + + public StationIdHasJediSlot(int jedi) { + this.jedi = jedi; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + jedi = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort(data, 2); + addInt( data, CRC); + addInt( data, jedi); + return data; + } + + public int getJediSlot() { + return jedi; + } + +} diff --git a/src/network/packets/swg/login/creation/ClientCreateCharacter.java b/src/network/packets/swg/login/creation/ClientCreateCharacter.java new file mode 100644 index 00000000..b6f6251b --- /dev/null +++ b/src/network/packets/swg/login/creation/ClientCreateCharacter.java @@ -0,0 +1,98 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class ClientCreateCharacter extends SWGPacket { + + public static final int CRC = 0xB97F3074; + private byte [] charCustomization = new byte[0]; + private String name = ""; + private String race = ""; + private String start = ""; + private String hair = ""; + private byte [] hairCustomization = new byte[0]; + private String clothes = ""; + private boolean jedi = false; + private float height = 0; + private String biography = ""; + private boolean tutorial = false; + private String profession = ""; + private String startingPhase = ""; + + public ClientCreateCharacter() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + charCustomization = getArray(data); + name = getUnicode(data); + race = getAscii(data); + start = getAscii(data); + hair = getAscii(data); + hairCustomization = getArray(data); + clothes = getAscii(data); + jedi = getBoolean(data); + height = getFloat(data); + biography = getUnicode(data); + tutorial = getBoolean(data); + profession = getAscii(data); + startingPhase = getAscii(data); + } + + public ByteBuffer encode() { + int extraSize = charCustomization.length; + extraSize += name.length()*2; + extraSize += race.length() + start.length(); + extraSize += hair.length() + hairCustomization.length; + extraSize += clothes.length() + profession.length(); + extraSize += startingPhase.length(); + ByteBuffer data = ByteBuffer.allocate(36+extraSize); + addShort (data, 2); + addInt (data, CRC); + addArray (data, charCustomization); + addUnicode(data, name); + addAscii (data, race); + addAscii (data, start); + addAscii (data, hair); + addArray (data, hairCustomization); + addAscii (data, clothes); + addBoolean(data, jedi); + addFloat (data, height); + addUnicode(data, biography); + addBoolean(data, tutorial); + addAscii (data, profession); + addAscii (data, startingPhase); + return data; + } + + public byte [] getCharCustomization() { return charCustomization; } + public String getName() { return name; } + public String getRace() { return race; } + public String getStartLocation() { return start; } + public String getHair() { return hair; } + public byte [] getHairCustomization() { return hairCustomization; } + public String getClothes() { return clothes; } + public float getHeight() { return height; } + public boolean isTutorial() { return tutorial; } + public String getProfession() { return profession; } + public String getStartingPhase() { return startingPhase; } + + public void setCharCustomization(byte [] data) { this.charCustomization = data; } + public void setName(String name) { this.name = name; } + public String getStart() { return start; } + public void setStart(String start) { this.start = start; } + public void setRace(String race) { this.race = race; } + public void setHair(String hair) { this.hair = hair; } + public void setHairCustomization(byte [] hairCustomization) { this.hairCustomization = hairCustomization; } + public void setClothes(String clothes) { this.clothes = clothes; } + public void setHeight(float height) { this.height = height; } + public void setTutorial(boolean tutorial) { this.tutorial = tutorial; } + public void setProfession(String profession) { this.profession = profession; } + public void setStartingPhase(String startingPhase) { this.startingPhase = startingPhase; } + +} diff --git a/src/network/packets/swg/login/creation/ClientVerifyAndLockNameRequest.java b/src/network/packets/swg/login/creation/ClientVerifyAndLockNameRequest.java new file mode 100644 index 00000000..bc22e176 --- /dev/null +++ b/src/network/packets/swg/login/creation/ClientVerifyAndLockNameRequest.java @@ -0,0 +1,41 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class ClientVerifyAndLockNameRequest extends SWGPacket { + + public static final int CRC = 0x9EB04B9F; + private String race = ""; + private String name = ""; + + public ClientVerifyAndLockNameRequest() { + + } + + public ClientVerifyAndLockNameRequest(String race, String name) { + this.race = race; + this.name = name; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + race = getAscii(data); + name = getUnicode(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10 + race.length() + name.length() * 2); + addShort( data, 4); + addInt( data, CRC); + addAscii( data, race); + addUnicode(data, name); + return data; + } + + public String getRace() { return race; } + public String getName() { return name; } +} diff --git a/src/network/packets/swg/login/creation/ClientVerifyAndLockNameResponse.java b/src/network/packets/swg/login/creation/ClientVerifyAndLockNameResponse.java new file mode 100644 index 00000000..3ade13f2 --- /dev/null +++ b/src/network/packets/swg/login/creation/ClientVerifyAndLockNameResponse.java @@ -0,0 +1,62 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class ClientVerifyAndLockNameResponse extends SWGPacket { + + public static final int CRC = 0x9B2C6BA7; + + private String name = ""; + private ErrorMessage error = ErrorMessage.NAME_APPROVED; + + public ClientVerifyAndLockNameResponse() { + + } + + public ClientVerifyAndLockNameResponse(String name, ErrorMessage error) { + this.name = name; + this.error = error; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + name = getUnicode(data); + error = ErrorMessage.valueOf(getAscii(data).toUpperCase()); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(20 + error.name().length() + name.length() * 2); + addShort( data, 9); + addInt( data, CRC); + addUnicode(data, name); + addAscii( data, "ui"); + addInt( data, 0); + addAscii( data, error.name().toLowerCase()); + return data; + } + + public enum ErrorMessage { + NAME_APPROVED, + NAME_APPROVED_MODIFIED, + NAME_DECLINED_SYNTAX, + NAME_DECLINED_EMPTY, + NAME_DECLINED_RACIALLY_INAPPROPRIATE, + NAME_DECLINED_FICTIONALLY_INAPPROPRIATE, + NAME_DECLINED_PROFANE, + NAME_DECLINED_IN_USE, + NAME_DECLINED_RESERVED, + NAME_DECLINED_NO_TEMPLATE, + NAME_DECLINED_NOT_CREATURE_TEMPLATE, + NAME_DECLINED_NO_NAME_GENERATOR, + NAME_DECLINED_CANT_CREATE_AVATAR, + NAME_DECLINED_INTERNAL_ERROR, + NAME_DECLINED_RETRY, + NAME_DECLINED_TOO_FAST, + NAME_DECLINED_NOT_AUTHORIZED_FOR_SPECIES; + } + +} diff --git a/src/network/packets/swg/login/creation/CreateCharacterFailure.java b/src/network/packets/swg/login/creation/CreateCharacterFailure.java new file mode 100644 index 00000000..add4a1ad --- /dev/null +++ b/src/network/packets/swg/login/creation/CreateCharacterFailure.java @@ -0,0 +1,60 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class CreateCharacterFailure extends SWGPacket { + + public static final int CRC = 0xDF333C6E; + private NameFailureReason reason; + + public CreateCharacterFailure() { + reason = NameFailureReason.NAME_RETRY; + } + + public CreateCharacterFailure(NameFailureReason reason) { + this.reason = reason; + } + + public void decode(ByteBuffer data) { + + } + + public ByteBuffer encode() { + String errorString = nameFailureTranslation(reason); + ByteBuffer data = ByteBuffer.allocate(20 + errorString.length()); + addShort( data, 3); + addInt( data, CRC); + addUnicode(data, ""); + addAscii( data, "ui"); + addInt( data, 0); + addAscii( data, errorString); + return data; + } + + private String nameFailureTranslation(NameFailureReason reason) { + switch (reason) { + case NAME_DECLINED_EMPTY: + return "name_declined_empty"; + case NAME_IN_USE: + return "name_declined_in_use"; + case NAME_RETRY: + return "name_declined_retry"; + case NAME_SYNTAX: + return "name_declined_syntax"; + case NAME_TOO_FAST: + return "name_declined_too_fast"; + } + return "name_declined_retry"; + } + + public enum NameFailureReason { + NAME_DECLINED_EMPTY, + NAME_TOO_FAST, + NAME_RETRY, + NAME_SYNTAX, + NAME_IN_USE + } +} diff --git a/src/network/packets/swg/login/creation/CreateCharacterSuccess.java b/src/network/packets/swg/login/creation/CreateCharacterSuccess.java new file mode 100644 index 00000000..f46d878c --- /dev/null +++ b/src/network/packets/swg/login/creation/CreateCharacterSuccess.java @@ -0,0 +1,37 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class CreateCharacterSuccess extends SWGPacket { + + public static final int CRC = 0x1DB575CC; + private long id = 0; + + public CreateCharacterSuccess() { + + } + + public CreateCharacterSuccess(long charId) { + this.id = charId; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + id = getLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(14); + addShort(data, 2); + addInt( data, CRC); + addLong( data, id); + return data; + } + + public long getId() { return id; } + public void setId(long id) { this.id = id; } +} diff --git a/src/network/packets/swg/login/creation/DeleteCharacterRequest.java b/src/network/packets/swg/login/creation/DeleteCharacterRequest.java new file mode 100644 index 00000000..336548dc --- /dev/null +++ b/src/network/packets/swg/login/creation/DeleteCharacterRequest.java @@ -0,0 +1,41 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class DeleteCharacterRequest extends SWGPacket { + + public static final int CRC = 0xE87AD031; + private int serverId = 0; + private long playerId = 0; + + public DeleteCharacterRequest() { + + } + + public DeleteCharacterRequest(int serverId, long playerId) { + this.serverId = serverId; + this.playerId = playerId; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + serverId = getInt(data); + playerId = getLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(18); + addShort(data, 3); + addInt( data, CRC); + addInt( data, serverId); + addLong( data, playerId); + return data; + } + + public int getServerId() { return serverId; } + public long getPlayerId() { return playerId; } +} diff --git a/src/network/packets/swg/login/creation/DeleteCharacterResponse.java b/src/network/packets/swg/login/creation/DeleteCharacterResponse.java new file mode 100644 index 00000000..95d371ae --- /dev/null +++ b/src/network/packets/swg/login/creation/DeleteCharacterResponse.java @@ -0,0 +1,34 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class DeleteCharacterResponse extends SWGPacket { + + public static final int CRC = 0x8268989B; + private boolean deleted = true; + + public DeleteCharacterResponse() { + + } + + public DeleteCharacterResponse(boolean deleted) { + this.deleted = deleted; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + deleted = getInt(data) == 0; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort(data, 2); + addInt( data, CRC); + addInt( data, deleted ? 0 : 1); + return data; + } +} diff --git a/src/network/packets/swg/login/creation/RandomNameRequest.java b/src/network/packets/swg/login/creation/RandomNameRequest.java new file mode 100644 index 00000000..659ca5e1 --- /dev/null +++ b/src/network/packets/swg/login/creation/RandomNameRequest.java @@ -0,0 +1,32 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class RandomNameRequest extends SWGPacket { + + public static final int CRC = 0xD6D1B6D1; + private String raceCrc = "object/creature/player/human_male.iff"; + + public RandomNameRequest() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + raceCrc = getAscii(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(8 + raceCrc.length()); + addShort(data, 2); + addInt( data, CRC); + addAscii(data, raceCrc); + return data; + } + + public String getRace() { return raceCrc; } +} diff --git a/src/network/packets/swg/login/creation/RandomNameResponse.java b/src/network/packets/swg/login/creation/RandomNameResponse.java new file mode 100644 index 00000000..f63e2ce6 --- /dev/null +++ b/src/network/packets/swg/login/creation/RandomNameResponse.java @@ -0,0 +1,53 @@ +package network.packets.swg.login.creation; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + + +public class RandomNameResponse extends SWGPacket { + + public static final int CRC = 0xE85FB868; + + private String race; + private String randomName; + + public RandomNameResponse() { + this.race = "object/creature/player/human_male.iff"; + this.randomName = ""; + } + + public RandomNameResponse(String race, String randomName) { + this.race = race; + this.randomName = randomName; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + race = getAscii(data); + randomName = getUnicode(data); + getAscii(data); + getInt(data); + getAscii(data); + } + + public ByteBuffer encode() { + int length = 35 + race.length() + randomName.length() * 2; + ByteBuffer data = ByteBuffer.allocate(length); + addShort( data, 4); + addInt( data, CRC); + addAscii( data, race); + addUnicode(data, randomName); + addAscii( data, "ui"); + addInt( data, 0); + addAscii( data, "name_approved"); + return data; + } + + public void setRace(String race) { this.race = race; } + public void setRandomName(String randomName) { this.randomName = randomName; } + + public String getRace() { return race; } + public String getRandomName() { return randomName; } +} diff --git a/src/network/packets/swg/zone/ChatRequestRoomList.java b/src/network/packets/swg/zone/ChatRequestRoomList.java new file mode 100644 index 00000000..e98f164d --- /dev/null +++ b/src/network/packets/swg/zone/ChatRequestRoomList.java @@ -0,0 +1,27 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatRequestRoomList extends SWGPacket { + + public static final int CRC = 0x4C3D2CFA; + + public ChatRequestRoomList() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + int length = 6; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 1); + addInt( data, CRC); + return data; + } +} diff --git a/src/network/packets/swg/zone/CmdSceneReady.java b/src/network/packets/swg/zone/CmdSceneReady.java new file mode 100644 index 00000000..232af3ec --- /dev/null +++ b/src/network/packets/swg/zone/CmdSceneReady.java @@ -0,0 +1,27 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class CmdSceneReady extends SWGPacket { + + public static final int CRC = 0x43FD1C22; + + public CmdSceneReady() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + int length = 6; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 1); + addInt( data, CRC); + return data; + } +} diff --git a/src/network/packets/swg/zone/ConnectPlayerResponseMessage.java b/src/network/packets/swg/zone/ConnectPlayerResponseMessage.java new file mode 100644 index 00000000..9c6c61db --- /dev/null +++ b/src/network/packets/swg/zone/ConnectPlayerResponseMessage.java @@ -0,0 +1,33 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ConnectPlayerResponseMessage extends SWGPacket { + + public static final int CRC = 0x6137556F; + + public ConnectPlayerResponseMessage() { + + } + + public ConnectPlayerResponseMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort(data, 2); + addInt (data, CRC); + addInt (data, 0); + return data; + } + +} diff --git a/src/network/packets/swg/zone/GalaxyLoopTimesRequest.java b/src/network/packets/swg/zone/GalaxyLoopTimesRequest.java new file mode 100644 index 00000000..bfaa2512 --- /dev/null +++ b/src/network/packets/swg/zone/GalaxyLoopTimesRequest.java @@ -0,0 +1,27 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class GalaxyLoopTimesRequest extends SWGPacket { + + public static final int CRC = 0x7D842D68; + + public GalaxyLoopTimesRequest() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + int length = 6; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 1); + addInt( data, CRC); + return data; + } +} diff --git a/src/network/packets/swg/zone/GalaxyLoopTimesResponse.java b/src/network/packets/swg/zone/GalaxyLoopTimesResponse.java new file mode 100644 index 00000000..cd7f054c --- /dev/null +++ b/src/network/packets/swg/zone/GalaxyLoopTimesResponse.java @@ -0,0 +1,34 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class GalaxyLoopTimesResponse extends SWGPacket { + + public static final int CRC = 0x4E428088; + private long time = 0; + + public GalaxyLoopTimesResponse() { + + } + + public GalaxyLoopTimesResponse(long time) { + this.time = time; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + time = getLong(data); + } + + public ByteBuffer encode() { + int length = 14; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 3); + addInt( data, CRC); + addLong( data, time); + return data; + } +} diff --git a/src/network/packets/swg/zone/HeartBeatMessage.java b/src/network/packets/swg/zone/HeartBeatMessage.java new file mode 100644 index 00000000..c91db59c --- /dev/null +++ b/src/network/packets/swg/zone/HeartBeatMessage.java @@ -0,0 +1,28 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class HeartBeatMessage extends SWGPacket { + + public static final int CRC = 0xA16CF9AF; + + public HeartBeatMessage() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + int length = 10; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 1); + addInt( data, CRC); + addInt( data, 0); + return data; + } +} diff --git a/src/network/packets/swg/zone/OpenedContainerMessage.java b/src/network/packets/swg/zone/OpenedContainerMessage.java new file mode 100644 index 00000000..2e91fdad --- /dev/null +++ b/src/network/packets/swg/zone/OpenedContainerMessage.java @@ -0,0 +1,43 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class OpenedContainerMessage extends SWGPacket { + + public static final int CRC = 0x2E11E4AB; + + private long containerId; + + public OpenedContainerMessage() { + this(0); + } + + public OpenedContainerMessage(long containerId) { + this.containerId = 0; + } + + public OpenedContainerMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getInt(data); // 0? + containerId = getLong(data); + getShort(data); // 0? + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(20); + addShort(data, 2); + addInt (data, CRC); + addInt (data, 0); + addLong (data, containerId); + addShort(data, 0); + return data; + } + +} diff --git a/src/network/packets/swg/zone/ParametersMessage.java b/src/network/packets/swg/zone/ParametersMessage.java new file mode 100644 index 00000000..93876f6a --- /dev/null +++ b/src/network/packets/swg/zone/ParametersMessage.java @@ -0,0 +1,29 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ParametersMessage extends SWGPacket { + + public static final int CRC = 0x487652DA; + + public ParametersMessage() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getInt(data); + } + + public ByteBuffer encode() { + int length = 14; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 2); + addInt( data, CRC); + addInt( data, 900); + return data; + } +} diff --git a/src/network/packets/swg/zone/SceneCreateObjectByCrc.java b/src/network/packets/swg/zone/SceneCreateObjectByCrc.java new file mode 100644 index 00000000..ad1e3002 --- /dev/null +++ b/src/network/packets/swg/zone/SceneCreateObjectByCrc.java @@ -0,0 +1,53 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; +import resources.Location; + +public class SceneCreateObjectByCrc extends SWGPacket { + + public static final int CRC = 0xFE89DDEA; + private long objId = 0; + private Location l = new Location(); + private int objCrc = 0; + + public SceneCreateObjectByCrc() { + + } + + public SceneCreateObjectByCrc(long objId, Location l, int objCrc) { + this.objId = objId; + this.l = l; + this.objCrc = objCrc; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objId = getLong(data); + l = getLocation(); + objCrc = getInt(data); + getByte(data); // Unknown Byte + } + + public ByteBuffer encode() { + int length = 47; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 5); + addInt( data, CRC); + addLong( data, objId); + addLocation(data, l); + addInt( data, objCrc); + addByte( data, 0); // Unknown Byte + return data; + } + + public void setObjectId(long objId) { this.objId = objId; } + public void setLocation(Location l) { this.l = l; } + public void setObjectCrc(int objCrc) { this.objCrc = objCrc; } + + public long getObjectId() { return objId; } + public Location getLocation() { return l; } + public int getObjectCrc() { return objCrc; } +} diff --git a/src/network/packets/swg/zone/SceneDestroyObject.java b/src/network/packets/swg/zone/SceneDestroyObject.java new file mode 100644 index 00000000..f0c702e7 --- /dev/null +++ b/src/network/packets/swg/zone/SceneDestroyObject.java @@ -0,0 +1,44 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class SceneDestroyObject extends SWGPacket { + + public static final int CRC = 0x4D45D504; + + private long objId; + + public SceneDestroyObject() { + this(0); + } + + public SceneDestroyObject(long objId) { + + } + + public SceneDestroyObject(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objId = getLong(data); + getByte(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(15); + addShort(data, 3); + addInt (data, CRC); + addLong (data, objId); + addByte (data, 0); + return data; + } + + public long getObjectId() { return objId; } + public void setObjectId(long objId) { this.objId = objId; } + +} diff --git a/src/network/packets/swg/zone/SceneEndBaselines.java b/src/network/packets/swg/zone/SceneEndBaselines.java new file mode 100644 index 00000000..454b0376 --- /dev/null +++ b/src/network/packets/swg/zone/SceneEndBaselines.java @@ -0,0 +1,37 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class SceneEndBaselines extends SWGPacket { + + public static final int CRC = 0x2C436037; + private long objId = 0; + + public SceneEndBaselines() { + + } + + public SceneEndBaselines(long objId) { + this.objId = objId; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objId = getLong(data); + } + + public ByteBuffer encode() { + int length = 14; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 2); + addInt( data, CRC); + addLong( data, objId); + return data; + } + + public long getObjectId() { return objId; } + +} diff --git a/src/network/packets/swg/zone/ServerTimeMessage.java b/src/network/packets/swg/zone/ServerTimeMessage.java new file mode 100644 index 00000000..1b841b72 --- /dev/null +++ b/src/network/packets/swg/zone/ServerTimeMessage.java @@ -0,0 +1,38 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ServerTimeMessage extends SWGPacket { + + public static final int CRC = 0x2EBC3BD9; + + private long time = 0; + + public ServerTimeMessage() { + + } + + public ServerTimeMessage(long time) { + this.time = time; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + time = getLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(14); + addShort(data, 2); + addInt( data, CRC); + addLong( data, time); + return data; + } + + public long getTime() { + return time; + } +} diff --git a/src/network/packets/swg/zone/SetWaypointColor.java b/src/network/packets/swg/zone/SetWaypointColor.java new file mode 100644 index 00000000..05b91ba9 --- /dev/null +++ b/src/network/packets/swg/zone/SetWaypointColor.java @@ -0,0 +1,31 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class SetWaypointColor extends SWGPacket { + public static final int CRC = 0x90C59FDE; + + private long objId; + private String color; + + public SetWaypointColor() { } + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + + objId = getLong(data); + color = getAscii(data); + } + + public long getObjId() { + return objId; + } + + public String getColor() { + return color; + } +} diff --git a/src/network/packets/swg/zone/UpdateContainmentMessage.java b/src/network/packets/swg/zone/UpdateContainmentMessage.java new file mode 100644 index 00000000..0687feba --- /dev/null +++ b/src/network/packets/swg/zone/UpdateContainmentMessage.java @@ -0,0 +1,47 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class UpdateContainmentMessage extends SWGPacket { + + public static final int CRC = 0x56CBDE9E; + + private long containerId = 0; + private long objectId = 0; + private int slotIndex = 0; + + public UpdateContainmentMessage() { + + } + + public UpdateContainmentMessage(long objectId, long containerId, int slotIndex) { + this.objectId = objectId; + this.containerId = containerId; + this.slotIndex = slotIndex; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objectId = getLong(data); + containerId = getLong(data); + slotIndex = getInt(data); + } + + public ByteBuffer encode() { + int length = 26; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 4); + addInt( data, CRC); + addLong( data, objectId); + addLong( data, containerId); + addInt( data, slotIndex); + return data; + } + + public long getObjectId() { return objectId; } + public long getContainerId() { return containerId; } + public int getSlotIndex() { return slotIndex; } +} diff --git a/src/network/packets/swg/zone/UpdatePostureMessage.java b/src/network/packets/swg/zone/UpdatePostureMessage.java new file mode 100644 index 00000000..cf442b91 --- /dev/null +++ b/src/network/packets/swg/zone/UpdatePostureMessage.java @@ -0,0 +1,44 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; +import resources.Posture; + +public class UpdatePostureMessage extends SWGPacket { + + public static final int CRC = 0x00BDE6B41; + private int posture = 0; + private long objId = 0; + + public UpdatePostureMessage() { + + } + + public UpdatePostureMessage(Posture posture, long objId) { + this.posture = posture.getId(); + this.objId = objId; + } + + public UpdatePostureMessage(int posture, long objId) { + this.posture = posture; + this.objId = objId; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + posture = getByte(data); + objId = getLong(data); + } + + public ByteBuffer encode() { + int length = 16; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 3); + addInt (data, CRC); + addByte (data, posture); + addLong (data, objId); + return data; + } +} diff --git a/src/network/packets/swg/zone/UpdatePvpStatusMessage.java b/src/network/packets/swg/zone/UpdatePvpStatusMessage.java new file mode 100644 index 00000000..596edfb8 --- /dev/null +++ b/src/network/packets/swg/zone/UpdatePvpStatusMessage.java @@ -0,0 +1,58 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class UpdatePvpStatusMessage extends SWGPacket { + + public static final int CRC = 0x08A1C126; + + public static final int ATTACKABLE = 1; + public static final int AGGRESSIVE = 2; + public static final int OVERT = 4; + public static final int TEF = 8; + public static final int PLAYER = 16; + public static final int ENEMY = 32; + public static final int GOING_OVERT = 64; // purple/blue blink + public static final int GOING_COVERT = 128; // green blink + public static final int DUEL = 256; + + private int flag = 16; + private int playerFaction = 0; + private long objId = 0; + + public UpdatePvpStatusMessage() { + + } + + public UpdatePvpStatusMessage(int playerType, int flag, long objId) { + this.flag = playerType; + this.playerFaction = flag; + this.objId = objId; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + flag = getInt(data); + playerFaction = getInt(data); + objId = getLong(data); + } + + public ByteBuffer encode() { + int length = 22; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 4); + addInt( data, CRC); + addInt( data, flag); + addInt( data, playerFaction); + addLong( data, objId); + return data; + } + + public long getObjectId() { return objId; } + public int getPlayerFaction() { return playerFaction; } + public int getPlayerType() { return flag; } + +} diff --git a/src/network/packets/swg/zone/UpdateTransformsMessage.java b/src/network/packets/swg/zone/UpdateTransformsMessage.java new file mode 100644 index 00000000..ee993873 --- /dev/null +++ b/src/network/packets/swg/zone/UpdateTransformsMessage.java @@ -0,0 +1,78 @@ +package network.packets.swg.zone; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class UpdateTransformsMessage extends SWGPacket { + + public static final int CRC = 0x1B24F808; + private long objId; + private short posX; + private short posY; + private short posZ; + private int updateCounter; + private byte direction; + private float speed; + + public UpdateTransformsMessage() { + this.objId = 0; + this.posX = 0; + this.posY = 0; + this.posZ = 0; + this.updateCounter = 0; + this.direction = 0; + this.speed = 0; + } + + public UpdateTransformsMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objId = getLong(data); + posX = getShort(data); + posY = getShort(data); + posZ = getShort(data); + updateCounter = getInt(data); + speed = getByte(data); + direction = getByte(data); + getByte(data); + getByte(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(28); + addShort(data, 10); + addInt( data, CRC); + addLong( data, objId); + addShort(data, posX); + addShort(data, posY); + addShort(data, posZ); + addInt (data, updateCounter); + addByte (data, (byte) speed); + addByte (data, (byte) direction); + addByte (data, (byte) 1); // lookAtYaw + addByte (data, (byte) 0); // useLookAtYaw + return data; + } + + public void setObjectId(long objId) { this.objId = objId; } + public void setX(short x) { this.posX = x; } + public void setY(short y) { this.posY = y; } + public void setZ(short z) { this.posZ = z; } + public void setUpdateCounter(int count) { this.updateCounter = count; } + public void setDirection(byte d) { this.direction = d; } + public void setSpeed(float speed) { this.speed = speed; } + + public long getObjectId() { return objId; } + public short getX() { return posX; } + public short getY() { return posY; } + public short getZ() { return posZ; } + public int getUpdateCounter() { return updateCounter; } + public byte getDirection() { return direction; } + public float getSpeed() { return speed; } + +} diff --git a/src/network/packets/swg/zone/auction/AuctionQueryHeadersMessage.java b/src/network/packets/swg/zone/auction/AuctionQueryHeadersMessage.java new file mode 100644 index 00000000..c5a3e99b --- /dev/null +++ b/src/network/packets/swg/zone/auction/AuctionQueryHeadersMessage.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class AuctionQueryHeadersMessage extends SWGPacket { + + public static final int CRC = 0x679E0D00; + + public AuctionQueryHeadersMessage() { + + } + + public AuctionQueryHeadersMessage(String command) { + + } + + public AuctionQueryHeadersMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/auction/AuctionQueryHeadersResponseMessage.java b/src/network/packets/swg/zone/auction/AuctionQueryHeadersResponseMessage.java new file mode 100644 index 00000000..d8b3bc70 --- /dev/null +++ b/src/network/packets/swg/zone/auction/AuctionQueryHeadersResponseMessage.java @@ -0,0 +1,222 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import network.packets.swg.SWGPacket; + +public class AuctionQueryHeadersResponseMessage extends SWGPacket { + + public static final int CRC = 0xFA500E52; + + private int counter; + private int screen; + private List items; + + public AuctionQueryHeadersResponseMessage() { + items = new ArrayList(); + } + + public AuctionQueryHeadersResponseMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + counter = getInt(data); + screen = getInt(data); + String [] locations = new String[getInt(data)]; + for (int i = 0; i < locations.length; i++) + locations[i] = getAscii(data); + int itemCount = getInt(data); + AuctionItem [] items = new AuctionItem[itemCount]; + for (int itemI = 0; itemI < itemCount; itemI++) { + AuctionItem item = new AuctionItem(); + item.setItemName(getUnicode(data)); + items[itemI] = item; + } + itemCount = getInt(data); + if (itemCount != items.length) + throw new IllegalStateException("I WAS LIED TO!"); + for (int itemI = 0; itemI < itemCount; itemI++) { + AuctionItem item = items[itemI]; + item.setObjectId(getLong(data)); + getByte(data); + item.setPrice(getInt(data)); + item.setExpireTime(getInt(data)*1000+System.currentTimeMillis()); + if (getInt(data) != item.getPrice()) + throw new IllegalStateException("I WAS LIED TO AT INDEX " + itemI); + item.setVuid(locations[getShort(data)]); + item.setOwnerId(getLong(data)); + item.setOwnerName(locations[getShort(data)]); + getLong(data); + getInt(data); + getInt(data); + getShort(data); + item.setItemType(getInt(data)); + getInt(data); + item.setAuctionOptions(getInt(data)); + getInt(data); + } + getShort(data); + getByte(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 8); + addInt (data, CRC); + addInt (data, counter); + addInt (data, screen); + + Set locations = new LinkedHashSet(); + for (AuctionItem item : items) { + locations.add(item.getVuid()); + locations.add(item.getOwnerName()); + } + addInt(data, items.size()); + for (String item : locations) { + addAscii(data, item); + } + + addInt (data, items.size()); + for (AuctionItem item : items) + addUnicode(data, item.getItemName()); + + addInt (data, items.size()); + + int i = 0; + for(AuctionItem item : items) { + addLong(data, item.getObjectId()); + addByte(data, i); + addInt(data, item.getPrice()); + addInt(data, (int) ((item.getExpireTime() - System.currentTimeMillis()) / 1000)); + addInt(data, item.getPrice()); // if != price then auction instead of instant sale + //addInt(data, 0); + addShort(data, getString(locations, item.getVuid())); + addLong(data, item.getOwnerId()); + addShort(data, getString(locations, item.getOwnerName())); + addLong(data, 0); + addInt(data, 0); // unk seen as 2 mostly, doesnt seem to have any effect + addInt(data, 0); + addShort(data, (short) 0); + addInt(data, item.getItemType()); // gameObjectType/category bitmask + + addInt(data, 0); + int options = 0; + + if (item.getStatus() == AuctionState.OFFERED || item.getStatus() == AuctionState.FORSALE) + options |= 0x800; + + addInt(data, item.getAuctionOptions() | options); + addInt(data, 0); + i++; + } + + addShort(data, 0); + + addByte(data, (byte) 0); + return data; + } + + private int getString(Set strings, String str) { + int index = 0; + for (String s : strings) { + if (s.equals(str)) + return index; + index++; + } + return index; + } + + public static enum AuctionState { + PREMIUM (0x400), + WITHDRAW (0x800), + FORSALE (1), + SOLD (2), + EXPIRED (4), + OFFERED (5), + RETRIEVED (6); + + private int id; + + AuctionState(int id) { + this.id = id; + } + + public int getId() { return id; } + } + + public static class AuctionItem { + private long objectId; + private long ownerId; + private long vendorId; + private long buyerId; + private long offerToId; + private int itemType; + private int itemTypeCRC; + private String ownerName; + private String bidderName; + private String itemName; + private String itemDescription; + private String planet; + private String location; + private int price; + private int proxyBid; + private boolean auction; + private String vuid; + private boolean onBazaar = false; + private long expireTime; + private int auctionOptions; + private AuctionState state; + + public long getObjectId() { return objectId; } + public long getOwnerId() { return ownerId; } + public long getVendorId() { return vendorId; } + public long getBuyerId() { return buyerId; } + public long getOfferToId() { return offerToId; } + public int getItemType() { return itemType; } + public String getOwnerName() { return ownerName; } + public String getBidderName() { return bidderName; } + public String getItemName() { return itemName; } + public String getLocation() { return location; } + public int getPrice() { return price; } + public int getProxyBid() { return proxyBid; } + public boolean isAuction() { return auction; } + public String getVuid() { return vuid; } + public AuctionState getStatus() { return state; } + public boolean isOnBazaar() { return onBazaar; } + public int getAuctionOptions() { return auctionOptions; } + public String getPlanet() { return planet; } + public int getItemTypeCRC() { return itemTypeCRC; } + + public String getItemDescription() { return itemDescription; } + public void setObjectId(long objectId) { this.objectId = objectId; } + public void setOwnerId(long ownerId) { this.ownerId = ownerId; } + public void setVendorId(long vendorId) { this.vendorId = vendorId; } + public void setBuyerId(long buyerId) { this.buyerId = buyerId; } + public void setOfferToId(long offerToId) { this.offerToId = offerToId; } + public void setItemType(int itemType) { this.itemType = itemType; } + public void setOwnerName(String ownerName) { this.ownerName = ownerName; } + public void setBidderName(String bidderName) { this.bidderName = bidderName; } + public void setItemName(String itemName) { this.itemName = itemName; } + public void setLocation(String location) { this.location = location; } + public void setItemDescription(String itemDescription) { this.itemDescription = itemDescription; } + public void setPrice(int price) { this.price = price; } + public void setProxyBid(int proxyBid) { this.proxyBid = proxyBid; } + public void setAuction(boolean auction) { this.auction = auction; } + public void setVuid(String vuid) { this.vuid = vuid; } + public void setStatus(AuctionState state) { this.state = state; } + public void setOnBazaar(boolean onBazaar) { this.onBazaar = onBazaar; } + public long getExpireTime() { return expireTime; } + public void setExpireTime(long expireTime) { this.expireTime = expireTime; } + public void setAuctionOptions(int auctionOptions) { this.auctionOptions = auctionOptions; } + public void setPlanet(String planet) { this.planet = planet; } + public void setItemTypeCRC(int itemTypeCRC) { this.itemTypeCRC = itemTypeCRC; } + } + +} diff --git a/src/network/packets/swg/zone/auction/CancelLiveAuctionMessage.java b/src/network/packets/swg/zone/auction/CancelLiveAuctionMessage.java new file mode 100644 index 00000000..be809ee4 --- /dev/null +++ b/src/network/packets/swg/zone/auction/CancelLiveAuctionMessage.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class CancelLiveAuctionMessage extends SWGPacket { + + public static final int CRC = 0x3687A4D2; + + public CancelLiveAuctionMessage() { + + } + + public CancelLiveAuctionMessage(String command) { + + } + + public CancelLiveAuctionMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/auction/CancelLiveAuctionResponseMessage.java b/src/network/packets/swg/zone/auction/CancelLiveAuctionResponseMessage.java new file mode 100644 index 00000000..da40e114 --- /dev/null +++ b/src/network/packets/swg/zone/auction/CancelLiveAuctionResponseMessage.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class CancelLiveAuctionResponseMessage extends SWGPacket { + + public static final int CRC = 0x7DA2246C; + + public CancelLiveAuctionResponseMessage() { + + } + + public CancelLiveAuctionResponseMessage(String command) { + + } + + public CancelLiveAuctionResponseMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/auction/GetAuctionDetails.java b/src/network/packets/swg/zone/auction/GetAuctionDetails.java new file mode 100644 index 00000000..0e5ce3ad --- /dev/null +++ b/src/network/packets/swg/zone/auction/GetAuctionDetails.java @@ -0,0 +1,39 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class GetAuctionDetails extends SWGPacket { + + public static final int CRC = 0xD36EFAE4; + + private long auctionId; + + public GetAuctionDetails() { + this(0); + } + + public GetAuctionDetails(long auctionId) { + this.auctionId = auctionId; + } + + public GetAuctionDetails(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + auctionId = getLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(14); + addShort(data, 2); + addInt (data, CRC); + addLong (data, auctionId); + return data; + } + +} diff --git a/src/network/packets/swg/zone/auction/GetAuctionDetailsResponse.java b/src/network/packets/swg/zone/auction/GetAuctionDetailsResponse.java new file mode 100644 index 00000000..231bc820 --- /dev/null +++ b/src/network/packets/swg/zone/auction/GetAuctionDetailsResponse.java @@ -0,0 +1,65 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import network.packets.swg.SWGPacket; + +public class GetAuctionDetailsResponse extends SWGPacket { + + public static final int CRC = 0xFE0E644B; + + private long itemId; + private Map properties; + private String itemName; + + public GetAuctionDetailsResponse() { + this(0, new HashMap(), ""); + } + + public GetAuctionDetailsResponse(long itemId, Map properties, String itemName) { + this.itemId = itemId; + this.properties = properties; + this.itemName = itemName; + } + + public GetAuctionDetailsResponse(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + itemId = getLong(data); + getInt(data); + int count = getInt(data); + for (int i = 0; i < count; i++) { + String key = getAscii(data); + String val = getUnicode(data); + properties.put(key, val); + } + itemName = getAscii(data); + getShort(data); // 0 + } + + public ByteBuffer encode() { + int strSize = 0; + for (Entry e : properties.entrySet()) + strSize += 6 + e.getKey().length() + e.getValue().length()*2; + ByteBuffer data = ByteBuffer.allocate(18 + strSize); + addShort(data, 9); + addInt (data, CRC); + addLong (data, itemId); + addInt (data, properties.size()); + for (Entry e : properties.entrySet()) { + addAscii(data, e.getKey()); + addUnicode(data, e.getValue()); + } + addAscii(data, itemName); + addShort(data, 0); + return data; + } + +} diff --git a/src/network/packets/swg/zone/auction/IsVendorOwnerResponseMessage.java b/src/network/packets/swg/zone/auction/IsVendorOwnerResponseMessage.java new file mode 100644 index 00000000..622ff0e5 --- /dev/null +++ b/src/network/packets/swg/zone/auction/IsVendorOwnerResponseMessage.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class IsVendorOwnerResponseMessage extends SWGPacket { + + public static final int CRC = 0xCE04173E; + + public IsVendorOwnerResponseMessage() { + + } + + public IsVendorOwnerResponseMessage(String command) { + + } + + public IsVendorOwnerResponseMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/auction/RetrieveAuctionItemMessage.java b/src/network/packets/swg/zone/auction/RetrieveAuctionItemMessage.java new file mode 100644 index 00000000..8e600d36 --- /dev/null +++ b/src/network/packets/swg/zone/auction/RetrieveAuctionItemMessage.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class RetrieveAuctionItemMessage extends SWGPacket { + + public static final int CRC = 0x12B0D449; + + public RetrieveAuctionItemMessage() { + + } + + public RetrieveAuctionItemMessage(String command) { + + } + + public RetrieveAuctionItemMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/auction/RetrieveAuctionItemResponseMessage.java b/src/network/packets/swg/zone/auction/RetrieveAuctionItemResponseMessage.java new file mode 100644 index 00000000..f9e4930f --- /dev/null +++ b/src/network/packets/swg/zone/auction/RetrieveAuctionItemResponseMessage.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.auction; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class RetrieveAuctionItemResponseMessage extends SWGPacket { + + public static final int CRC = 0x9499EF8C; + + public RetrieveAuctionItemResponseMessage() { + + } + + public RetrieveAuctionItemResponseMessage(String command) { + + } + + public RetrieveAuctionItemResponseMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/baselines/Baseline.java b/src/network/packets/swg/zone/baselines/Baseline.java new file mode 100644 index 00000000..61b578d6 --- /dev/null +++ b/src/network/packets/swg/zone/baselines/Baseline.java @@ -0,0 +1,77 @@ +package network.packets.swg.zone.baselines; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class Baseline extends SWGPacket { + + public static final int CRC = 0x68A75F0C; + private BaselineType type; + private int num; + private short opCount; + private long objId; + private byte [] baseData; + + public Baseline() { + + } + + public Baseline(long objId, Baseline subData) { + this.objId = objId; + type = subData.getType(); + num = subData.getNum(); + baseData = subData.encodeBaseline().array(); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objId = getLong(data); + byte [] str = new byte[4]; data.get(str); + String strType = new StringBuffer(new String(str, ascii)).reverse().toString(); + for (BaselineType baseType : BaselineType.values()) + if (baseType.toString().equals(strType)) + type = baseType; + num = getByte(data); + baseData = new byte[getInt(data)]; + data.get(baseData); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(25 + baseData.length); + addShort(data, 5); + addInt( data, CRC); + addLong( data, objId); + data.put(new StringBuffer(type.toString()).reverse().toString().getBytes(ascii)); + addByte( data, num); + addInt( data, baseData.length + 2); + addShort( data, (opCount == 0 ? 5 : opCount)); + data.put(baseData); + // TODO: It seems that baselines are being called to encode 3 times, might be possible they're also being sent 3 times as well... + return data; + } + + public ByteBuffer encodeBaseline() { return ByteBuffer.allocate(0); } + + public long getObjectId() { return objId; } + + public void setType(BaselineType type) { this.type = type; } + public void setNum(int num) { this.num = num; } + public void setId(long id) { this.objId = id; } + public void setBaselineData(byte [] data) { this.baseData = data; } + public void setOperandCount(int count) { this.opCount = (short) count;} + + public BaselineType getType() { return type; } + public int getNum() { return num; } + public long getId() { return objId; } + public byte [] getBaselineData() { return baseData; } + + public enum BaselineType { + BMRK, BUIO, CREO, FCYT, + GILD, GRUP, HINO, INSO, + ITNO, MINO, MISO, MSCO, + PLAY, RCNO, SCLT, STAO, + SHIP, TANO, WAYP, WEAO + } +} diff --git a/src/network/packets/swg/zone/baselines/CREO3.java b/src/network/packets/swg/zone/baselines/CREO3.java new file mode 100644 index 00000000..aa098f26 --- /dev/null +++ b/src/network/packets/swg/zone/baselines/CREO3.java @@ -0,0 +1,81 @@ +package network.packets.swg.zone.baselines; + +import java.nio.ByteBuffer; + +public class CREO3 extends Baseline { + + private String dName = ""; + private String cName = ""; + private byte [] customization = new byte[0]; + private int posture = 1; + private float height = 0; + private int fatigue = 0; + + public CREO3() { + + } + + public CREO3(String dName, String cName, byte [] customization, int posture, float height, int fatigue) { + this.dName = dName; + this.cName = cName; + this.customization = customization; + this.posture = posture; + this.height = height; + this.fatigue = fatigue; + } + + public void decodeBaseline(ByteBuffer data) { + getInt(data); + getShort(data); + getAscii(data); + getInt(data); + dName = getAscii(data); + cName = getUnicode(data); + getInt(data); + getLong(data); + customization = getArray(data); + getInt(data); + getInt(data); + getInt(data); + getInt(data); + getInt(data); + getInt(data); + getInt(data); + posture = getShort(data); + getByte(data); + getLong(data); + height = getFloat(data); + fatigue = getInt(data); + } + + public ByteBuffer encodeBaseline() { + int length = 91 + "species".length() + dName.length() + cName.length() * 2 + customization.length; + ByteBuffer data = ByteBuffer.allocate(length); + addInt( data, 0x13); // Object Count? + addShort( data, 0x3F80); // Scale? + addAscii( data, "species"); // Unknown.. + addInt( data, 0); // Spacer + addAscii( data, dName); // Default Name + addUnicode(data, cName); // Custom Name + addInt( data, 0x000F4240); // Unknown + addLong( data, 0); // Unknown + addArray( data, customization); // Object Customization Data + addInt( data, 1); // Unknown + addInt( data, 0); // Unknown + addInt( data, 0); // Unknown + addInt( data, 0x80); // Unknown + addInt( data, 0); // Unknown + addInt( data, 0); // Unknown + addInt( data, 0x00003A98); // Unknown + addShort( data, posture); // Posture for Object + addByte( data, 1); // Unknown + addLong( data, 0); // Target Object Id + addFloat( data, height); // Height of Object + addInt( data, fatigue); // Battle Fatigue + addLong( data, 0); // State? + return data; + } + + public String getDefaultName() { return dName; } + public String getCustomName() { return cName; } +} diff --git a/src/network/packets/swg/zone/baselines/CREO6.java b/src/network/packets/swg/zone/baselines/CREO6.java new file mode 100644 index 00000000..509941de --- /dev/null +++ b/src/network/packets/swg/zone/baselines/CREO6.java @@ -0,0 +1,106 @@ +package network.packets.swg.zone.baselines; + +import java.nio.ByteBuffer; + + +public class CREO6 extends Baseline { + + private long objectId = 0; + + public CREO6(long objectId) { + this.objectId = objectId; + } + + public void decodeBaseline(ByteBuffer data) { + + } + + public ByteBuffer encodeBaseline() { + // ByteBuffer data = ByteBuffer.allocate(260); + // addShort(data, 0x23); + // addFloat(data, 0); + // addInt(data, 0); + // addInt(data, 0); + // + // addLong(data, 0); + // addLong(data, 0); + // addLong(data, 0); + // addLong(data, 0); + // addInt(data, 0); + // + // addByte(data, 0); + // addShort(data, 90); + // addInt(data, (byte) 0xD007); + // addShort(data, 0); + // addAscii(data, "neutral"); + // //addLong(data, objectId + 5); // WEAO ID + // addLong(data, 0); + // + // addLong(data, 0); + // addInt(data, 0); + // addLong(data, 0); + // addLong(data, 0); + // addLong(data, 0); + // addByte(data, 0); + // addInt(data, 0); + // addInt(data, 0); + // addInt(data, 0); + // addShort(data, 0); + // + // addInt(data, 6); + // addInt(data, 6); // Current Combat stats list + // + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // + // + // addInt(data, 6); + // addInt(data, 6); // Maximum Combat stats list + // + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // addInt(data, 350); + // + // + // addInt(data, 1); + // addInt(data, 1); + // + // addShort(data, 0); + // addInt(data, 4); + // addLong(data, objectId + 3); + // addInt(data, 0x73ba5001); + // addByte(data, 0); + // + // addNetInt(data, 1); + // + // addLong(data, 0); + // + // addShort(data, 0); + // + // return data; + byte [] data1 = { + (byte) 0x23, (byte) 0x00, (byte) 0x4E, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x5A, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0C, (byte) 0x00, (byte) 0x63, (byte) 0x6F, (byte) 0x6E, (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x73, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6F, (byte) 0x6E, (byte) 0x00, (byte) 0xAE, (byte) 0x5E, (byte) 0xA9, (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x3B, (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xEA, (byte) 0x0B, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x3B, (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xEA, (byte) 0x0B, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFC, (byte) 0xAD, (byte) 0x5E, (byte) 0xA9, (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1C, (byte) 0x79, (byte) 0x10, (byte) 0x21, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xAE, (byte) 0x5E, (byte) 0xA9, (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x42, (byte) 0xE7, (byte) 0xD0, (byte) 0x7D, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x0C, (byte) 0x5F, (byte) 0xA7, (byte) 0x68, (byte) 0x00, (byte) 0xAE, (byte) 0x5E, (byte) 0xA9, (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x4F, (byte) 0x41, (byte) 0x45, (byte) 0x57, (byte) 0x03, (byte) 0x6E, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0B, (byte) 0x00, (byte) 0x77, (byte) 0x65, (byte) 0x61, (byte) 0x70, (byte) 0x6F, (byte) 0x6E, (byte) 0x5F, (byte) 0x6E, (byte) 0x61, (byte) 0x6D, (byte) 0x65, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0E, (byte) 0x00, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x61, (byte) 0x75, (byte) 0x6C, (byte) 0x74, (byte) 0x5F, (byte) 0x77, (byte) 0x65, (byte) 0x61, (byte) 0x70, (byte) 0x6F, (byte) 0x6E, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3F, (byte) 0x0A, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xA0, (byte) 0x40, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x0C, (byte) 0x5F, (byte) 0xA7, (byte) 0x68, (byte) 0x00, (byte) 0xAE, (byte) 0x5E, (byte) 0xA9, (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x4F, (byte) 0x41, (byte) 0x45, (byte) 0x57, (byte) 0x06, (byte) 0x50, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x09, (byte) 0x00, (byte) 0x4E, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0B, (byte) 0x00, (byte) 0x77, (byte) 0x65, (byte) 0x61, (byte) 0x70, (byte) 0x6F, (byte) 0x6E, (byte) 0x5F, (byte) 0x6E, (byte) 0x61, (byte) 0x6D, (byte) 0x65, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0E, (byte) 0x00, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x61, (byte) 0x75, (byte) 0x6C, (byte) 0x74, (byte) 0x5F, (byte) 0x77, (byte) 0x65, (byte) 0x61, (byte) 0x70, (byte) 0x6F, (byte) 0x6E, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + + }; + byte[] data2 = new byte[] { + + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + }; + return ByteBuffer.allocate(data1.length + data2.length).put(data1).put(data2); + } + + public void setObjectId(long objectId) { + this.objectId = objectId; + } + + public long getObjectId() { + return objectId; + } +} diff --git a/src/network/packets/swg/zone/baselines/CREO8.java b/src/network/packets/swg/zone/baselines/CREO8.java new file mode 100644 index 00000000..ef1cd084 --- /dev/null +++ b/src/network/packets/swg/zone/baselines/CREO8.java @@ -0,0 +1,22 @@ +package network.packets.swg.zone.baselines; + +import java.nio.ByteBuffer; + + +public class CREO8 extends Baseline { + + public CREO8() { + + } + + public void decodeBaseline(ByteBuffer data) { + + } + + public ByteBuffer encodeBaseline() { + int length = 2; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 0); + return data; + } +} diff --git a/src/network/packets/swg/zone/baselines/CREO9.java b/src/network/packets/swg/zone/baselines/CREO9.java new file mode 100644 index 00000000..eb336a1d --- /dev/null +++ b/src/network/packets/swg/zone/baselines/CREO9.java @@ -0,0 +1,22 @@ +package network.packets.swg.zone.baselines; + +import java.nio.ByteBuffer; + + +public class CREO9 extends Baseline { + + public CREO9() { + + } + + public void decodeBaseline(ByteBuffer data) { + + } + + public ByteBuffer encodeBaseline() { + int length = 2; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 0); + return data; + } +} diff --git a/src/network/packets/swg/zone/baselines/PLAY6.java b/src/network/packets/swg/zone/baselines/PLAY6.java new file mode 100644 index 00000000..36846aed --- /dev/null +++ b/src/network/packets/swg/zone/baselines/PLAY6.java @@ -0,0 +1,28 @@ +package network.packets.swg.zone.baselines; + +import java.nio.ByteBuffer; + + +public class PLAY6 extends Baseline { + + public void decodeBaseline(ByteBuffer data) { + + } + + public ByteBuffer encodeBaseline() { + int length = 81; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 17); + addInt( data, 0x4C); + addAscii(data, "string_id_table"); + addLong( data, 0); + addLong( data, 0); + addLong( data, 0); + addLong( data, 0); + addLong( data, 0); + addLong( data, 0); + addLong( data, 0); + addShort(data, 0); + return data; + } +} diff --git a/src/network/packets/swg/zone/baselines/PLAY9.java b/src/network/packets/swg/zone/baselines/PLAY9.java new file mode 100644 index 00000000..d7abcc95 --- /dev/null +++ b/src/network/packets/swg/zone/baselines/PLAY9.java @@ -0,0 +1,86 @@ +package network.packets.swg.zone.baselines; + +import java.nio.ByteBuffer; + + +public class PLAY9 extends Baseline { + + public void decodeBaseline(ByteBuffer data) { + + } + + public ByteBuffer encodeBaseline() { + int length = 0x0143; + ByteBuffer data = ByteBuffer.allocate(length); + addInt( data, 0x1F); + addInt( data, 0); + addInt( data, 0); + addShort(data, 0); + addInt( data, 0); + addInt( data, 3); + addInt( data, 3); + addByte( data, 0); + addInt( data, 0x30254293); + addInt( data, 0xD805AB60); + addInt( data, 1); + addByte( data, 0); + addInt( data, 0x4BB23CAE); + addInt( data, 0x6C750908); + addInt( data, 1); + addByte( data, 0); + addInt( data, 0x83AADF10); + addInt( data, 0x757A3F17); + addInt( data, 1); + addByte( data, 0); + addByte( data, 0); + addShort(data, 0); + addInt( data, 0); + addInt( data, 8); + addInt( data, 0); + addInt( data, 10); + addInt( data, 0x21); + addAscii(data, "atima"); + addAscii(data, "brokovo"); + addAscii(data, "daymian"); + addAscii(data, "dow-jones"); + addAscii(data, "eclipse.pandoren"); + addAscii(data, "eclipse.rabivesk"); + addAscii(data, "kenpachie"); + addAscii(data, "melony"); + addAscii(data, "omatchi'"); + addAscii(data, "sobli"); + addInt( data, 0); + addInt( data, 3); + addInt( data, 1); + addInt( data, 0); + addInt( data, 100); + addInt( data, 0); + addInt( data, 100); + addInt( data, 0); + addInt( data, 100); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 3); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 2); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addInt( data, 0); + addShort( data, 0); + return data; + } +} diff --git a/src/network/packets/swg/zone/building/UpdateCellPermissionMessage.java b/src/network/packets/swg/zone/building/UpdateCellPermissionMessage.java new file mode 100644 index 00000000..fa1186da --- /dev/null +++ b/src/network/packets/swg/zone/building/UpdateCellPermissionMessage.java @@ -0,0 +1,47 @@ +package network.packets.swg.zone.building; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class UpdateCellPermissionMessage extends SWGPacket { + + public static final int CRC = 0xF612499C; + + private byte permissionFlag; + private long cellId; + + public UpdateCellPermissionMessage() { + permissionFlag = 0; + cellId = 0; + } + + public UpdateCellPermissionMessage(byte permissionFlag, long cellId) { + this.permissionFlag = permissionFlag; + this.cellId = cellId; + } + + public UpdateCellPermissionMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + permissionFlag = getByte(data); + cellId = getLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(15); + addShort(data, 2); + addInt( data, CRC); + addByte( data, permissionFlag); + addLong( data, cellId); + return data; + } + + public long getCellId() { return cellId; } + public byte getPermissions() { return permissionFlag; } + +} diff --git a/src/network/packets/swg/zone/chat/ChatDeletePersistentMessage.java b/src/network/packets/swg/zone/chat/ChatDeletePersistentMessage.java new file mode 100644 index 00000000..9e6511e3 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatDeletePersistentMessage.java @@ -0,0 +1,21 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatDeletePersistentMessage extends SWGPacket { + public static final int CRC = 0x8F251641; + + private int mailId; + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + + mailId = getInt(data); + } + + public int getMailId() { return mailId; } +} diff --git a/src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java b/src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java new file mode 100644 index 00000000..5bb9d386 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java @@ -0,0 +1,47 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatFriendsListUpdate extends SWGPacket { + + public static final int CRC = 0x6CD2FCD8; + + private String galaxy; + private String friendName; + private boolean online; + + public ChatFriendsListUpdate() { + + } + + public ChatFriendsListUpdate(String command) { + + } + + public ChatFriendsListUpdate(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getAscii(data); // SWG + galaxy = getAscii(data); + friendName = getAscii(data); + online = getBoolean(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort (data, 3); + addInt (data, CRC); + addAscii (data, "SWG"); + addAscii (data, galaxy); + addAscii (data, friendName); + addBoolean(data, online); + return data; + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatIgnoreList.java b/src/network/packets/swg/zone/chat/ChatIgnoreList.java new file mode 100644 index 00000000..d836123b --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatIgnoreList.java @@ -0,0 +1,86 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import network.packets.swg.SWGPacket; + +public class ChatIgnoreList extends SWGPacket { + + public static final int CRC = 0xF8C275B0; + + private long objectId; + private List ignoreList; + + public ChatIgnoreList() { + objectId = 0; + ignoreList = new ArrayList(); + } + + public ChatIgnoreList(ByteBuffer data) { + decode(data); + } + + public void addName(String game, String galaxy, String name) { + addName(new IgnoreListItem(game, galaxy, name)); + } + + public void addName(IgnoreListItem name) { + ignoreList.add(name); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objectId = getLong(data); + int listCount = getInt(data); + for (int i = 0; i < listCount; i++) { + String game = getAscii(data); + String galaxy = getAscii(data); + String name = getAscii(data); + addName(game, galaxy, name); + } + } + + public ByteBuffer encode() { + int extraSize = 0; + for (IgnoreListItem item : ignoreList) + extraSize += 6 + item.getGame().length() + item.getGalaxy().length() + item.getName().length(); + ByteBuffer data = ByteBuffer.allocate(18 + extraSize); + addShort (data, 3); + addInt (data, CRC); + addLong (data, objectId); + addInt (data, ignoreList.size()); + for (IgnoreListItem item : ignoreList) { + addAscii(data, item.getGame()); + addAscii(data, item.getGalaxy()); + addAscii(data, item.getName()); + } + return data; + } + + public static class IgnoreListItem { + private String game; + private String galaxy; + private String name; + + public IgnoreListItem() { + this("SWG", "", ""); + } + + public IgnoreListItem(String game, String galaxy, String name) { + this.game = game; + this.galaxy = galaxy; + this.name = name; + } + + public String getGame() { return game; } + public String getGalaxy() { return galaxy; } + public String getName() { return name; } + public void setGame(String game) { this.game = game; } + public void setGalaxy(String galaxy) { this.galaxy = galaxy; } + public void setName(String name) { this.name = name; } + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatInstantMessageToCharacter.java b/src/network/packets/swg/zone/chat/ChatInstantMessageToCharacter.java new file mode 100644 index 00000000..98a0c601 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatInstantMessageToCharacter.java @@ -0,0 +1,73 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatInstantMessageToCharacter extends SWGPacket { + + public static final int CRC = 0x84BB21F7; + + private String galaxy; + private String character; + private String message; + private String outOfBand; + private int sequence; + + public ChatInstantMessageToCharacter() { + this("", "", "", "", 0); + } + + public ChatInstantMessageToCharacter(String galaxy, String character, String message, int sequence) { + this(galaxy, character, message, "", sequence); + } + + public ChatInstantMessageToCharacter(String galaxy, String character, String message, String outOfBand, int sequence) { + this.galaxy = galaxy; + this.character = character; + this.message = message; + this.outOfBand = outOfBand; + this.sequence = sequence; + } + + public ChatInstantMessageToCharacter(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getAscii(data); + galaxy = getAscii(data); + character = getAscii(data); + message = getUnicode(data); + outOfBand = getUnicode(data); + sequence = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(27 + galaxy.length() + character.length() + message.length()*2); + addShort(data, 2); + addInt( data, CRC); + addAscii(data, "SWG"); + addAscii(data, galaxy); + addAscii(data, character); + addUnicode(data, message); + addUnicode(data, outOfBand); + addInt (data, sequence); + return data; + } + + public String getGalaxy() { return galaxy; } + public String getCharacter() { return character; } + public String getMessage() { return message; } + public String getOutOfBand() { return outOfBand; } + public int getSequence() { return sequence; } + + public void setGalaxy(String galaxy) { this.galaxy = galaxy; } + public void setCharacter(String character) { this.character = character; } + public void setMessage(String message) { this.message = message; } + public void setOutOfBand(String outOfBand) { this.outOfBand = outOfBand; } + public void setSequence(int sequence) { this.sequence = sequence; } + +} diff --git a/src/network/packets/swg/zone/chat/ChatInstantMessageToClient.java b/src/network/packets/swg/zone/chat/ChatInstantMessageToClient.java new file mode 100644 index 00000000..0862055b --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatInstantMessageToClient.java @@ -0,0 +1,67 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatInstantMessageToClient extends SWGPacket { + + public static final int CRC = 0x3C565CED; + + private String galaxy; + private String character; + private String message; + private String outOfBand; + + public ChatInstantMessageToClient() { + this("", "", "", ""); + } + + public ChatInstantMessageToClient(String galaxy, String character, String message) { + this(galaxy, character, message, ""); + } + + public ChatInstantMessageToClient(String galaxy, String character, String message, String outOfBand) { + this.galaxy = galaxy; + this.character = character; + this.message = message; + this.outOfBand = outOfBand; + } + + public ChatInstantMessageToClient(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getAscii(data); // "SWG" + galaxy = getAscii(data); + character = getAscii(data); + message = getUnicode(data); + outOfBand = getUnicode(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(23 + galaxy.length() + character.length() + message.length()*2 + outOfBand.length()*2); + addShort(data, 2); + addInt( data, CRC); + addAscii(data, "SWG"); + addAscii(data, galaxy); + addAscii(data, character); + addUnicode(data, message); + addUnicode(data, outOfBand); + return data; + } + + public String getGalaxy() { return galaxy; } + public String getCharacter() { return character; } + public String getMessage() { return message; } + public String getOutOfBand() { return outOfBand; } + + public void setGalaxy(String galaxy) { this.galaxy = galaxy; } + public void setCharacter(String character) { this.character = character; } + public void setMessage(String message) { this.message = message; } + public void setOutOfBand(String outOfBand) { this.outOfBand = outOfBand; } + +} diff --git a/src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java b/src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java new file mode 100644 index 00000000..c9de91d0 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnConnectAvatar extends SWGPacket { + + public static final int CRC = 0xD72FE9BE; + + public ChatOnConnectAvatar() { + + } + + public ChatOnConnectAvatar(String command) { + + } + + public ChatOnConnectAvatar(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java b/src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java new file mode 100644 index 00000000..2368746f --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java @@ -0,0 +1,58 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnDestroyRoom extends SWGPacket { + + public static final int CRC = 0xE8EC5877; + + private String galaxy; + private String owner; + private boolean success; + private int roomId; + private int requestId; + + public ChatOnDestroyRoom() { + this("", "", true, 0, 0); + } + + public ChatOnDestroyRoom(String galaxy, String owner, boolean success, int roomId, int requestId) { + this.galaxy = galaxy; + this.owner = owner; + this.success = success; + this.roomId = roomId; + this.requestId = requestId; + } + + public ChatOnDestroyRoom(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getAscii(data); // SWG + galaxy = getAscii(data); + owner = getAscii(data); + success = getInt(data) == 0; + roomId = getInt(data); + requestId = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(27 + galaxy.length() + owner.length()); + addShort(data, 5); + addInt (data, CRC); + addAscii(data, "SWG"); + addAscii(data, galaxy); + addAscii(data, owner); + addInt (data, success ? 0 : 1); + addInt (data, roomId); + addInt (data, requestId); + return data; + } + +} + diff --git a/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java b/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java new file mode 100644 index 00000000..9e4247b9 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java @@ -0,0 +1,78 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnEnteredRoom extends SWGPacket { + + public static final int CRC = 0xE69BDC0A; + + private String galaxy; + private String character; + private ChannelStatus status; + private int chatRoomId; + + public ChatOnEnteredRoom() { + this("", "", ChannelStatus.SUCCESS, 0); + } + + public ChatOnEnteredRoom(String galaxy, String character, ChannelStatus status, int chatRoomId) { + this.galaxy = galaxy; + this.character = character; + this.status = status; + this.chatRoomId = chatRoomId; + } + + public ChatOnEnteredRoom(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getAscii(data); + galaxy = getAscii(data); + character = getAscii(data); + status = ChannelStatus.fromInteger(getInt(data)); + chatRoomId = getInt(data); + getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(27 + galaxy.length() + character.length()); + addShort(data, 5); + addInt (data, CRC); + addAscii(data, "SWG"); + addAscii(data, galaxy); + addAscii(data, character); + addInt (data, status.getBitmask()); + addInt (data, chatRoomId); + addInt (data, 0); + return data; + } + + public enum ChannelStatus { + SUCCESS(0), // "You have joined the channel." + NOT_INVITED(0x10), // "You cannot join '%TU (room name)' because you are not invted to the room." + UNKNOWN(0x20); // "Chatroom '%TU (room name)' join failed for an unknown reason." + + private int bitmask; + + ChannelStatus(int bitmask) { + this.bitmask = bitmask; + } + public int getBitmask() { + return bitmask; + } + public static final ChannelStatus fromInteger(int i) { + if (i == 0) + return SUCCESS; + if (i == 0x10) + return NOT_INVITED; + return UNKNOWN; + } + }; + +} + diff --git a/src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java b/src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java new file mode 100644 index 00000000..08d9d7e7 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java @@ -0,0 +1,57 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnLeaveRoom extends SWGPacket { + + public static final int CRC = 0x60B5098B; + + private String galaxyName; + private String characterName; + private int errorCode; + private int chatRoomId; + private int requestId; + + public ChatOnLeaveRoom() { + this("", "", 0, 0, 0); + } + + public ChatOnLeaveRoom(String galaxy, String character, int errorCode, int chatRoomId, int requestId) { + this.galaxyName = galaxy; + this.characterName = character; + this.errorCode = errorCode; + this.chatRoomId = chatRoomId; + this.requestId = requestId; + } + + public ChatOnLeaveRoom(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getAscii(data); + galaxyName = getAscii(data); + characterName = getAscii(data); + errorCode = getInt(data); + chatRoomId = getInt(data); + requestId = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(27+galaxyName.length()+characterName.length()); + addShort(data, 2); + addInt( data, CRC); + addAscii(data, "SWG"); + addAscii(data, galaxyName); + addAscii(data, characterName); + addInt (data, errorCode); + addInt (data, chatRoomId); + addInt (data, requestId); + return data; + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java b/src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java new file mode 100644 index 00000000..6b9b52ff --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnReceiveRoomInvitation extends SWGPacket { + + public static final int CRC = 0xC17EB06D; + + public ChatOnReceiveRoomInvitation() { + + } + + public ChatOnReceiveRoomInvitation(String command) { + + } + + public ChatOnReceiveRoomInvitation(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 2); + addInt (data, CRC); + return data; + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatOnSendInstantMessage.java b/src/network/packets/swg/zone/chat/ChatOnSendInstantMessage.java new file mode 100644 index 00000000..e1fe75ee --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnSendInstantMessage.java @@ -0,0 +1,59 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnSendInstantMessage extends SWGPacket { + + public static final int CRC = 0x88DBB381; + + private int result; + private int sequence; + + public ChatOnSendInstantMessage() { + this(0, 0); + } + + public ChatOnSendInstantMessage(int result, int sequence) { + this.result = result; + this.sequence = sequence; + } + + public ChatOnSendInstantMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + result = getInt(data); + sequence = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(14); + addShort(data, 2); + addInt (data, CRC); + addInt (data, result); + addInt (data, sequence); + return data; + } + + public void setResult(int result) { + this.result = result; + } + + public void setSequence(int sequence) { + this.sequence = sequence; + } + + public int getResult() { + return result; + } + + public int getSequence() { + return sequence; + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java b/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java new file mode 100644 index 00000000..f0f20863 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java @@ -0,0 +1,27 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnSendPersistentMessage extends SWGPacket { + public static final int CRC = 0x94E7A7AE; + + private int errorCode; + private int count; + + public ChatOnSendPersistentMessage(int errorCode, int count) { + this.errorCode = errorCode; + this.count = count; + } + + @Override + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(20); + addShort(data, 3); + addInt(data, errorCode); + addInt(data, count); + return data; + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java b/src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java new file mode 100644 index 00000000..0a15dd1c --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java @@ -0,0 +1,38 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatOnSendRoomMessage extends SWGPacket { + + public static final int CRC = 0xE7B61633; + private int error = 0; + private int messageId = 0; + + public ChatOnSendRoomMessage() { + + } + + public ChatOnSendRoomMessage(int error, int messageId) { + this.error = error; + this.messageId = messageId; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + error = getInt(data); + messageId = getInt(data); + } + + public ByteBuffer encode() { + int length = 14; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 3); + addInt( data, CRC); + addInt( data, error); + addInt( data, messageId); + return data; + } +} diff --git a/src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java b/src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java new file mode 100644 index 00000000..68b4142d --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java @@ -0,0 +1,334 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import resources.Terrain; +import resources.network.BaselineBuilder.Encodable; +import network.packets.swg.SWGPacket; + +public class ChatPersistentMessageToClient extends SWGPacket { + + public static final int CRC = 0x08485E17; + + private String senderName; + private String galaxy; + private int mailId; + private boolean header; + private String subject; + private String message; + private List waypointAttachments; + private List proseAttachments; + private byte status; + private int timestamp; + + public ChatPersistentMessageToClient(boolean header, String sender, String galaxy, int mailId, String subject, String message, int timestamp, byte status) { + waypointAttachments = new ArrayList(); + proseAttachments = new ArrayList(); + this.senderName = sender; + this.galaxy = galaxy; + this.mailId = mailId; + this.header = header; + this.subject = subject; + this.message = message; + this.status = status; + this.timestamp = timestamp; + } + + public ChatPersistentMessageToClient(Encodable mailEncodable) { + + } + public ChatPersistentMessageToClient(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + senderName = getAscii(data); + getAscii(data); // SWG + galaxy = getAscii(data); + mailId = getInt(data); + header = getBoolean(data); + + if (header) { + getInt(data); // 0? + subject = getUnicode(data); + getInt(data); + } else { + message = getUnicode(data); + subject = getUnicode(data); + int size = getInt(data) * 2; + int start = data.position(); + do { + getShort(data); // 0? + byte type = getByte(data); + getInt(data); // Integer version of the type, it seems + if (type == 4) + waypointAttachments.add(WaypointAttachment.deserialize(data)); + else if (type == 1) + proseAttachments.add(ProseAttachment.deserialize(data)); + else { + System.err.println("Invalid type supplied in ChatPersistentMessageToClient.decode"); + break; + } + } while (data.position() - start < size); + } + status = getByte(data); + timestamp = getInt(data); + } + + public ByteBuffer encode() { + int extraSize = 0; + if (header) { + extraSize += 12 + subject.length()*2; + } else { + extraSize += 12 + message.length()*2 + subject.length()*2; + for (WaypointAttachment waypoint : waypointAttachments) + extraSize += 7 + waypoint.getSerializableSize(); + for (ProseAttachment prose : proseAttachments) + extraSize += 7 + prose.getSerializableSize(); + } + ByteBuffer data = ByteBuffer.allocate(25 + extraSize + galaxy.length() + senderName.length()); + addShort(data, 2); + addInt( data, CRC); + addAscii(data, senderName); + addAscii(data, "SWG"); + addAscii(data, galaxy); + addInt(data, mailId); + addBoolean(data, header); + + if (header) { + addInt(data, 0); // message (empty as 1 is sending only the header to the client) + addUnicode(data, subject); + addInt(data, 0); + } else { + addUnicode(data, message); + addUnicode(data, subject); + addInt(data, 0); // TODO: Mail Attachments + /*for (WaypointAttachment waypoint : waypointAttachments) { + addShort(data, 0); + addByte(data, 4); + addInt(data, 0xFFFFFFFD); + waypoint.serialize(data); + } + for (ProseAttachment prose : proseAttachments) { + addShort(data, 0); + addByte(data, 1); + addInt(data, 0xFFFFFFFF); + prose.serialize(data); + }*/ + } + addByte(data, status); + addInt(data, timestamp); + return data; + } + + public void setSenderName(String senderName) { + this.senderName = senderName; + } + + public void setGalaxy(String galaxy) { + this.galaxy = galaxy; + } + + public void setMailId(int mailId) { + this.mailId = mailId; + } + + public void setHeader(boolean header) { + this.header = header; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public void setMessage(String message) { + this.message = message; + } + + public void addWaypoint(WaypointAttachment waypoint) { + waypointAttachments.add(waypoint); + } + + public void addAllWaypoints(Collection waypoints) { + waypointAttachments.addAll(waypoints); + } + + public void addProse(ProseAttachment prose) { + proseAttachments.add(prose); + } + + public void addAllProses(Collection proses) { + proseAttachments.addAll(proses); + } + + public void setStatus(byte status) { + this.status = status; + } + + public void setTimestamp(int timestamp) { + this.timestamp = timestamp; + } + + public static class WaypointAttachment { + private float x; + private float y; + private float z; + private Terrain planet; + private String attachmentName; + private long cellId; + private byte color; + private boolean active; + + public float getX() { return x; } + public float getY() { return y; } + public float getZ() { return z; } + public Terrain getPlanet() { return planet; } + public String getAttachmentName() { return attachmentName; } + public long getCellId() { return cellId; } + public byte getColor() { return color; } + public boolean isActive() { return active; } + + public void setX(float x) { this.x = x; } + public void setY(float y) { this.y = y; } + public void setZ(float z) { this.z = z; } + public void setPlanet(Terrain p) { this.planet = p; } + public void setAttachmentName(String name) { this.attachmentName = name; } + public void setCellId(long id) { this.cellId = id; } + public void setColor(byte c) { this.color = c; } + public void setActive(boolean active) { this.active = active; } + + private final int getSerializableSize() { + return 43 + attachmentName.length()*2; + } + + private static final WaypointAttachment deserialize(ByteBuffer data) { + WaypointAttachment waypoint = new WaypointAttachment(); + getInt(data); // 0? + waypoint.setX(getFloat(data)); + waypoint.setY(getFloat(data)); + waypoint.setZ(getFloat(data)); + getLong(data); // 0? + waypoint.setPlanet(Terrain.getTerrainFromCrc(getInt(data))); + waypoint.setAttachmentName(getUnicode(data)); + waypoint.setCellId(getLong(data)); + waypoint.setColor(getByte(data)); + waypoint.setActive(getBoolean(data)); + getByte(data); // 0? + return waypoint; + } + + public final void serialize(ByteBuffer data) { + addInt (data, 0); + addFloat (data, getX()); + addFloat (data, getY()); + addFloat (data, getZ()); + addLong (data, 0); + addInt (data, planet.getCrc()); + addUnicode(data, attachmentName); + addLong (data, cellId); + addByte (data, color); + addBoolean(data, active); + addByte (data, 0); + } + } + + public static class ProseAttachment { + private String stf; + private ProseSegment tu; + private ProseSegment tt; + private ProseSegment to; + private int diInt; + private float dfFloat; + + public String getSTF() { return stf; } + public ProseSegment getTu() { return tu; } + public ProseSegment getTt() { return tt; } + public ProseSegment getTo() { return to; } + public int getDiInteger() { return diInt; } + public float getDfFloat() { return dfFloat; } + + public void setSTF(String stf) { this.stf = stf; } + public void setTu(ProseSegment tu) { this.tu = tu; } + public void setTt(ProseSegment tt) { this.tt = tt; } + public void setTo(ProseSegment to) { this.to = to; } + public void setDiInteger(int di) { this.diInt = di; } + public void setDfFloat(float df) { this.dfFloat = df; } + + private final int getSerializableSize() { + return 10 + stf.length() + tu.getSerializableSize() + tt.getSerializableSize() + to.getSerializableSize(); + } + + private static final ProseAttachment deserialize(ByteBuffer data) { + ProseAttachment prose = new ProseAttachment(); + prose.setSTF(getAscii(data)); + prose.setTu(ProseSegment.deserialize(data)); + prose.setTt(ProseSegment.deserialize(data)); + prose.setTo(ProseSegment.deserialize(data)); + prose.setDiInteger(getInt(data)); + prose.setDfFloat(getFloat(data)); + return prose; + } + + public final void serialize(ByteBuffer data) { + addAscii(data, stf); + tu.serialize(data); + tt.serialize(data); + to.serialize(data); + addInt(data, diInt); + addFloat(data, dfFloat); + } + + public static class ProseSegment { + private long objectId; + private String stf; + private String customString; + + public long getObjectId() { return objectId; } + public String getSTF() { return stf; } + public String getCustomString() { return customString; } + + public void setObjectId(long id) { this.objectId = id; } + public void setSTF(String stf) { this.stf = stf; } + public void setCustomString(String custom) { this.customString = custom; } + + private final int getSerializableSize() { + return 14 + stf.length() + customString.length()*2; + } + + private static final ProseSegment deserialize(ByteBuffer data) { + ProseSegment segment = new ProseSegment(); + segment.setObjectId(getLong(data)); + segment.setSTF(getAscii(data)); + segment.setCustomString(getUnicode(data)); + return segment; + } + + private final void serialize(ByteBuffer data) { + addLong(data, objectId); + addAscii(data, stf); + addUnicode(data, customString); + } + } + } + /* + * ASCII Stf + * LONG TuObjectId + * ASCII TuStf + * UNICODE TuCustomString + * LONG TtObjectId + * ASCII TtStf + * UNICODE TtCustomString + * LONG ToObjectId + * ASCII ToStf + * UNICODE ToCustomString + * INT DiInteger + * FLOAT DfFloat + * BYTE 0 + */ + +} diff --git a/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java new file mode 100644 index 00000000..a259cfa7 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java @@ -0,0 +1,102 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatPersistentMessageToServer extends SWGPacket { + public static final int CRC = 0x25A29FA6; + + private String message; + private String outOfBand; + private int counter; + private String subject; + private String galaxy; + private String recipient; + + public ChatPersistentMessageToServer() { + message = ""; + outOfBand = ""; + subject = ""; + + galaxy = ""; + recipient = ""; + } + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + message = getUnicode(data); + outOfBand = getUnicode(data); + counter = getInt(data); + subject = getUnicode(data); + + getAscii(data); // "SWG" + galaxy = getAscii(data); + recipient = getAscii(data); + } + + @Override + public ByteBuffer encode() { + int dataLength = 31 + message.length()*2+outOfBand.length()*2+subject.length()*2+galaxy.length()+recipient.length(); + ByteBuffer data = ByteBuffer.allocate(dataLength); + addUnicode(data, message); + addUnicode(data, outOfBand); + addInt(data, counter); + addUnicode(data, subject); + addAscii(data, "SWG"); + addAscii(data, galaxy); + addAscii(data, recipient); + return data; + } + + public String getMessage() { + return message; + } + + public String getOutOfBand() { + return outOfBand; + } + + public int getCounter() { + return counter; + } + + public String getSubject() { + return subject; + } + + public String getCluster() { + return galaxy; + } + + public String getRecipient() { + return recipient; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setOutOfBand(String outOfBand) { + this.outOfBand = outOfBand; + } + + public void setCounter(int counter) { + this.counter = counter; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public void setCluster(String cluster) { + this.galaxy = cluster; + } + + public void setRecipient(String recipient) { + this.recipient = recipient; + } + +} diff --git a/src/network/packets/swg/zone/chat/ChatRequestPersistentMessage.java b/src/network/packets/swg/zone/chat/ChatRequestPersistentMessage.java new file mode 100644 index 00000000..2f2d8770 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatRequestPersistentMessage.java @@ -0,0 +1,21 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatRequestPersistentMessage extends SWGPacket { + public static final int CRC = 0x07E3559F; + + private int mailId; + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getInt(data); + mailId = getInt(data); + } + + public int getMailId() { return this.mailId; } +} diff --git a/src/network/packets/swg/zone/chat/ChatRoomMessage.java b/src/network/packets/swg/zone/chat/ChatRoomMessage.java new file mode 100644 index 00000000..d74def7a --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatRoomMessage.java @@ -0,0 +1,51 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; +import network.packets.swg.zone.insertion.ChatRoomList.ChatRoom.User; + +public class ChatRoomMessage extends SWGPacket { + + public static final int CRC = 0xCD4CE444; + private User user = new User(); + private int roomId = 0; + private String message = ""; + + public ChatRoomMessage() { + + } + + public ChatRoomMessage(String game, String server, String name, int roomId, String message) { + this.user.game = game; + this.user.server = server; + this.user.name = name; + this.roomId = roomId; + this.message = message; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + user.game = getAscii(data); + user.server = getAscii(data); + user.name = getAscii(data); + roomId = getInt(data); + message = getUnicode(data); + getUnicode(data); + } + + public ByteBuffer encode() { + int length = 24 + user.game.length() + user.server.length() + user.name.length() + message.length() * 2; + ByteBuffer data = ByteBuffer.allocate(length); + addShort( data, 5); + addInt( data, CRC); + addAscii( data, user.game); + addAscii( data, user.server); + addAscii( data, user.name); + addInt( data, roomId); + addUnicode(data, message); + addUnicode(data, ""); + return data; + } +} diff --git a/src/network/packets/swg/zone/chat/ChatSystemMessage.java b/src/network/packets/swg/zone/chat/ChatSystemMessage.java new file mode 100644 index 00000000..1d02a2ba --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatSystemMessage.java @@ -0,0 +1,80 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import resources.encodables.OutOfBand; +import network.packets.swg.SWGPacket; + +public class ChatSystemMessage extends SWGPacket { + + public static final int CRC = 0x6D2A6413; + private int type = 0; + private String message = ""; + private OutOfBand oob; + + public ChatSystemMessage() { + + } + + public ChatSystemMessage(int type, String message) { + this.type = type; + this.message = message; + } + + public ChatSystemMessage(int type, OutOfBand oob) { + this.type = type; + this.oob = oob; + } + + public ChatSystemMessage(SystemChatType type, String message) { + this(type.ordinal(), message); + } + + public ChatSystemMessage(SystemChatType type, OutOfBand oob) { + this(type.ordinal(), oob); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + type = getByte(data); + message = getUnicode(data); + getUnicode(data); + } + + public ByteBuffer encode() { + byte[] oobData = (oob != null ? oob.encode() : null); + int length = 7; + + if (oobData == null) length+= 15 + message.length() * 2; + else length+= 4 + oobData.length; + + ByteBuffer data = ByteBuffer.allocate(length); + addShort( data, 4); + addInt( data, CRC); + addByte( data, type); + if (oobData == null) { + addUnicode(data, message); + addUnicode(data, ""); + } else { + addInt(data, 0); + data.put(oobData); + } + + return data; + } + + public SystemChatType getType() { + for (SystemChatType t : SystemChatType.values()) { + if (type == t.ordinal()) return t; + } + return SystemChatType.SCREEN_AND_CHAT; + } + public String getMessage() { return message; } + + public enum SystemChatType { + SCREEN_AND_CHAT, + SCREEN, + CHAT + } +} diff --git a/src/network/packets/swg/zone/chat/ConGenericMessage.java b/src/network/packets/swg/zone/chat/ConGenericMessage.java new file mode 100644 index 00000000..dbd0024c --- /dev/null +++ b/src/network/packets/swg/zone/chat/ConGenericMessage.java @@ -0,0 +1,41 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ConGenericMessage extends SWGPacket { + + public static final int CRC = 0x08C5FC76; + + private String message; + + public ConGenericMessage() { + this(""); + } + + public ConGenericMessage(String message) { + this.message = message; + } + + public ConGenericMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + message = getAscii(data); + getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(8 + message.length()); + addShort(data, 3); + addInt (data, CRC); + addAscii(data, message); + addInt (data, 0); + return data; + } + +} diff --git a/src/network/packets/swg/zone/chat/VoiceChatStatus.java b/src/network/packets/swg/zone/chat/VoiceChatStatus.java new file mode 100644 index 00000000..71011573 --- /dev/null +++ b/src/network/packets/swg/zone/chat/VoiceChatStatus.java @@ -0,0 +1,33 @@ +package network.packets.swg.zone.chat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class VoiceChatStatus extends SWGPacket { + + public static final int CRC = 0x9E601905; + + public VoiceChatStatus() { + + } + + public VoiceChatStatus(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(10); + addShort(data, 2); + addInt (data, CRC); + addInt (data, 1); + return data; + } + +} diff --git a/src/network/packets/swg/zone/combat/GrantCommandMessage.java b/src/network/packets/swg/zone/combat/GrantCommandMessage.java new file mode 100644 index 00000000..4e16271c --- /dev/null +++ b/src/network/packets/swg/zone/combat/GrantCommandMessage.java @@ -0,0 +1,47 @@ +package network.packets.swg.zone.combat; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class GrantCommandMessage extends SWGPacket { + + public static final int CRC = 0xE67E3875; + + private String command; + + public GrantCommandMessage() { + command = ""; + } + + public GrantCommandMessage(String command) { + this.command = command; + } + + public GrantCommandMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + this.command = getAscii(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(8 + command.length()); + addShort(data, 2); + addInt( data, CRC); + addAscii(data, command); + return data; + } + + public String getCommand() { + return command; + } + + public void setCommand(String command) { + this.command = command; + } + +} diff --git a/src/network/packets/swg/zone/deltas/DeltasMessage.java b/src/network/packets/swg/zone/deltas/DeltasMessage.java new file mode 100644 index 00000000..19bfd4fc --- /dev/null +++ b/src/network/packets/swg/zone/deltas/DeltasMessage.java @@ -0,0 +1,69 @@ +package network.packets.swg.zone.deltas; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; +import network.packets.swg.zone.baselines.Baseline.BaselineType; + +public class DeltasMessage extends SWGPacket { + + public static final int CRC = 0x12862153; + + private long objId; + private BaselineType type; + private int num; + private byte [] deltaData; + private int update; + + public DeltasMessage() { } + + public DeltasMessage(long objId, BaselineType type, int typeNumber, byte [] data) { + this.objId = objId; + this.type = type; + this.num = typeNumber; + this.deltaData = data; + } + + public DeltasMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objId = getLong(data); + byte [] str = new byte[4]; data.get(str); + String strType = new StringBuffer(new String(str, ascii)).reverse().toString(); + for (BaselineType baseType : BaselineType.values()) + if (baseType.toString().equals(strType)) + type = baseType; + num = getByte(data); + int length = getInt(data); + this.deltaData = getArray(data, length); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(27 + deltaData.length); + addShort(data, 5); + addInt( data, CRC); + addLong(data, objId); + data.put(new StringBuffer(type.toString()).reverse().toString().getBytes(ascii)); + addByte(data, num); + addInt(data, deltaData.length + 4); + addShort(data, 1); // TODO: How many updates there is (1 always for now until a queue system is built + addShort(data, update); // TODO: This should be part of the data, for now we'll keep it here until the queue system is in + data.put(deltaData); + return data; + } + + public long getObjectId() { return objId; } + public BaselineType getType() { return type; } + public int getNum() { return num; } + public byte [] getDeltaData() { return deltaData; } + + public void setType(BaselineType type) { this.type = type; } + public void setNum(int num) { this.num = num; } + public void setId(long id) { this.objId = id; } + public void setData(byte[] data) { this.deltaData = data; } + public void setUpdate(int update) { this.update = update; } +} diff --git a/src/network/packets/swg/zone/insertion/ChatRoomList.java b/src/network/packets/swg/zone/insertion/ChatRoomList.java new file mode 100644 index 00000000..6a06628b --- /dev/null +++ b/src/network/packets/swg/zone/insertion/ChatRoomList.java @@ -0,0 +1,209 @@ +package network.packets.swg.zone.insertion; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +import network.packets.swg.SWGPacket; +import network.packets.swg.zone.insertion.ChatRoomList.ChatRoom.User; + +public class ChatRoomList extends SWGPacket { + + public static final int CRC = 0x70DEB197; + private List chatrooms = new ArrayList(); + + public ChatRoomList() { + + } + + public ChatRoomList(ChatRoom room) { + chatrooms.add(room); + } + + public ChatRoomList(ChatRoom [] rooms) { + for (ChatRoom r : rooms) { + chatrooms.add(r); + } + } + + public void addChatRoom(ChatRoom r) { + chatrooms.add(r); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + int chatroomCount = getInt(data); + for (int i = 0; i < chatroomCount; i++) { + ChatRoom room = new ChatRoom(); + room.setRoomId(getInt(data)); + room.setPrivateFlag(getInt(data)); + room.setModeratedFlag(getByte(data)); + room.setRoomPathName(getAscii(data)); + room.setGame(getAscii(data)); + room.setServer(getAscii(data)); + room.setOwner(getAscii(data)); + getAscii(data); // SWG + getAscii(data); // galaxy + room.setCreator(getAscii(data)); + room.setTitle(getUnicode(data)); + int moderatorCount = getInt(data); + for (int m = 0; m < moderatorCount; m++) { + User user = new User(); + user.setGame(getAscii(data)); + user.setServer(getAscii(data)); + user.setName(getAscii(data)); + room.addModerator(user); + } + int userCount = getInt(data); + for (int u = 0; u < userCount; u++) { + User user = new User(); + user.setGame(getAscii(data)); + user.setServer(getAscii(data)); + user.setName(getAscii(data)); + room.addUser(user); + } + } + } + + public ByteBuffer encode() { + int length = 10; + for (ChatRoom r : chatrooms) { + length += r.getSize(); + } + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 2); + addInt( data, CRC); + addInt( data, chatrooms.size()); + for (ChatRoom r : chatrooms) { + addInt(data, r.getRoomId()); + addInt(data, r.getPrivateFlag()); + addByte(data, r.getModeratedFlag()); + addAscii(data, r.getRoomPathName()); + addAscii(data, r.getGame()); + addAscii(data, r.getServer()); + addAscii(data, r.getOwner()); + addAscii(data, r.getCreator()); + addUnicode(data, r.getTitle()); + addInt(data, r.getModerators().size()); + for (User u : r.getModerators()) { + addAscii(data, u.game); + addAscii(data, u.server); + addAscii(data, u.name); + } + addInt(data, r.getUsers().size()); + for (User u : r.getUsers()) { + addAscii(data, u.game); + addAscii(data, u.server); + addAscii(data, u.name); + } + } + return data; + } + + public static class ChatRoom { + private int roomId = 0; + private int privateFlag = 0; + private int moderatedFlag = 0; + private String roomPathName = ""; + private String game = ""; + private String server = ""; + private String owner = ""; + private String creator = ""; + private String title = ""; + private Vector moderators = new Vector(); + private Vector users = new Vector(); + + public ChatRoom() { + + } + + public ChatRoom(int roomId, int privateFlag, int moderatedFlag, String roomPathName, String game, String server, String owner, String creator, String title) { + this.roomId = roomId; + this.privateFlag = privateFlag; + this.moderatedFlag = moderatedFlag; + this.roomPathName = roomPathName; + this.game = game; + this.server = server; + this.owner = owner; + this.creator = creator; + this.title = title; + } + + public void addModerator(String game, String server, String name) { + moderators.add(new User(game, server, name)); + } + + public void addUser(String game, String server, String name) { + users.add(new User(game, server, name)); + } + + public int getSize() { + int length = 31; + length += roomPathName.length(); + length += game.length(); + length += server.length(); + length += owner.length(); + length += creator.length(); + length += title.length() * 2; + for (User u : moderators) length += u.getSize(); + for (User u : users) length += u.getSize(); + return length; + } + + public int getRoomId() { return roomId; } + public int getPrivateFlag() { return privateFlag; } + public int getModeratedFlag() { return moderatedFlag; } + public String getRoomPathName() { return roomPathName; } + public String getGame() { return game; } + public String getServer() { return server; } + public String getOwner() { return owner; } + public String getCreator() { return creator; } + public String getTitle() { return title; } + public List getUsers() { return users; } + public List getModerators() { return moderators; } + + public void setRoomId(int id) { this.roomId = id; } + public void setPrivateFlag(int flag) { this.privateFlag = flag; } + public void setModeratedFlag(int flag) { this.moderatedFlag = flag; } + public void setRoomPathName(String path) { this.roomPathName = path; } + public void setGame(String game) { this.game = game; } + public void setServer(String server) { this.server = server; } + public void setOwner(String owner) { this.owner = owner; } + public void setCreator(String creator) { this.creator = creator; } + public void setTitle(String title) { this.title = title; } + public void setUsers(Vector users) { this.users = users; } + public void setModerators(Vector moderators) { this.moderators = moderators; } + public void addUser(User user) { this.users.add(user); } + public void addModerator(User moderator) { this.moderators.add(moderator); } + + public static class User { + public String game = ""; + public String server = ""; + public String name = ""; + + public User() { + + } + + public User(String game, String server, String name) { + this.game = game; + this.server = server; + this.name = name; + } + + public int getSize() { + return 6 + game.length() + server.length() + name.length(); + } + + public String getGame() { return game; } + public String getServer() { return server; } + public String getName() { return name; } + + public void setGame(String game) { this.game = game; } + public void setServer(String server) { this.server = server; } + public void setName(String name) { this.name = name; } + } + } +} diff --git a/src/network/packets/swg/zone/insertion/ChatServerStatus.java b/src/network/packets/swg/zone/insertion/ChatServerStatus.java new file mode 100644 index 00000000..2de5520a --- /dev/null +++ b/src/network/packets/swg/zone/insertion/ChatServerStatus.java @@ -0,0 +1,34 @@ +package network.packets.swg.zone.insertion; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ChatServerStatus extends SWGPacket { + + public static final int CRC = 0x7102B15F; + private boolean online = false; + + public ChatServerStatus() { + + } + + public ChatServerStatus(boolean online) { + this.online = online; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + online = getBoolean(data); + } + + public ByteBuffer encode() { + int length = 7; + ByteBuffer data = ByteBuffer.allocate(length); + addShort( data, 2); + addInt( data, CRC); + addBoolean(data, online); + return data; + } +} diff --git a/src/network/packets/swg/zone/insertion/CmdStartScene.java b/src/network/packets/swg/zone/insertion/CmdStartScene.java new file mode 100644 index 00000000..b9a11a29 --- /dev/null +++ b/src/network/packets/swg/zone/insertion/CmdStartScene.java @@ -0,0 +1,73 @@ +package network.packets.swg.zone.insertion; + +import java.nio.ByteBuffer; + +import resources.Location; +import resources.Race; +import resources.Terrain; +import network.packets.swg.SWGPacket; + +public class CmdStartScene extends SWGPacket { + + public static final int CRC = 0x3AE6DFAE; + + private boolean ignoreLayoutFiles; + private long charId; + private Race race; + private Location l; + private long galacticTime; + + public CmdStartScene() { + ignoreLayoutFiles = false; + charId = 0; + race = Race.HUMAN; + l = new Location(); + galacticTime = 0; + } + + public CmdStartScene(boolean ignoreLayoutFiles, long charId, Race race, Location l, long galacticTime) { + this.ignoreLayoutFiles = ignoreLayoutFiles; + this.charId = charId; + this.race = race; + this.l = l; + this.galacticTime = galacticTime; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + ignoreLayoutFiles = getBoolean(data); + charId = getLong(data); + l.setTerrain(Terrain.getTerrainFromName(getAscii(data))); + l.setX(getFloat(data)); + l.setY(getFloat(data)); + l.setZ(getFloat(data)); + getFloat(data); + race = Race.getRaceByFile(getAscii(data)); + galacticTime = getLong(data); + getInt(data); // 0x8EB5EA4E + } + + public ByteBuffer encode() { + int length = 47 + l.getTerrain().getFile().length() + race.getFilename().length(); + ByteBuffer data = ByteBuffer.allocate(length); + addShort( data, 2); + addInt( data, CRC); + addBoolean(data, ignoreLayoutFiles); + addLong( data, charId); + addAscii( data, l.getTerrain().getFile()); + addFloat( data, (float) l.getX()); + addFloat( data, (float) l.getY()); + addFloat( data, (float) l.getZ()); + addFloat( data, (float) l.getYaw()); + addAscii( data, race.getFilename()); + addLong( data, galacticTime); + addInt (data, 0x8EB5EA4E); + return data; + } + + public long getCharacterId() { return charId; } + public Location getLocation() { return l; } + public Race getRace() { return race; } + public long getGalacticTime() { return galacticTime; } +} diff --git a/src/network/packets/swg/zone/insertion/ConnectPlayerMessage.java b/src/network/packets/swg/zone/insertion/ConnectPlayerMessage.java new file mode 100644 index 00000000..e95efcda --- /dev/null +++ b/src/network/packets/swg/zone/insertion/ConnectPlayerMessage.java @@ -0,0 +1,28 @@ +package network.packets.swg.zone.insertion; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class ConnectPlayerMessage extends SWGPacket { + + public static final int CRC = 0x2E365218; + + public ConnectPlayerMessage() { + + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + } + + public ByteBuffer encode() { + int length = 10; + ByteBuffer data = ByteBuffer.allocate(length); + addShort(data, 2); + addInt( data, CRC); + addInt( data, 0); + return data; + } +} diff --git a/src/network/packets/swg/zone/insertion/SelectCharacter.java b/src/network/packets/swg/zone/insertion/SelectCharacter.java new file mode 100644 index 00000000..42f0cfa0 --- /dev/null +++ b/src/network/packets/swg/zone/insertion/SelectCharacter.java @@ -0,0 +1,36 @@ +package network.packets.swg.zone.insertion; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class SelectCharacter extends SWGPacket { + + public static final int CRC = 0xB5098D76; + + private long charId = 0; + + public SelectCharacter() { + + } + + public SelectCharacter(long id) { + this.charId = id; + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + charId = getLong(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(14); + addShort(data, 2); + addInt( data, CRC); + addLong( data, charId); + return data; + } + + public long getCharacterId() { return charId; } +} diff --git a/src/network/packets/swg/zone/object_controller/CommandQueueDequeue.java b/src/network/packets/swg/zone/object_controller/CommandQueueDequeue.java new file mode 100644 index 00000000..5013225e --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/CommandQueueDequeue.java @@ -0,0 +1,52 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + + +public class CommandQueueDequeue extends ObjectController { + + public static final int CRC = 0x0117; + + private int counter; + private float timer; + private int error; + private int action; + + public CommandQueueDequeue(long objectId) { + super(objectId, CRC); + } + + public CommandQueueDequeue(ByteBuffer data) { + super(CRC); + decode(data); + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + counter = getInt(data); + timer = getFloat(data); + error = getInt(data); + action = getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 16); + encodeHeader(data); + addInt(data, counter); + addFloat(data, timer); + addInt(data, error); + addInt(data, action); + return data; + } + + public int getCounter() { return counter; } + public float getTimer() { return timer; } + public int getError() { return error; } + public int getAction() { return action; } + + public void setCounter(int counter) { this.counter = counter; } + public void setTimer(float timer) { this.timer = timer; } + public void setError(int error) { this.error = error; } + public void setAction(int action) { this.action = action; } + +} diff --git a/src/network/packets/swg/zone/object_controller/CommandQueueEnqueue.java b/src/network/packets/swg/zone/object_controller/CommandQueueEnqueue.java new file mode 100644 index 00000000..858fb09d --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/CommandQueueEnqueue.java @@ -0,0 +1,50 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + + +public class CommandQueueEnqueue extends ObjectController { + + public static final int CRC = 0x0116; + + private int counter = 0; + private int crc = 0; + private long targetId = 0; + private String arguments = ""; + + public CommandQueueEnqueue(long objectId) { + super(objectId, CRC); + } + + public CommandQueueEnqueue(ByteBuffer data) { + super(CRC); + decode(data); + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + counter = getInt(data); + crc = getInt(data); + targetId = getLong(data); + arguments = getUnicode(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 20 + arguments.length()*2); + encodeHeader(data); + addInt(data, counter); + addInt(data, crc); + addLong(data, targetId); + addUnicode(data, arguments); + return data; + } + + public int getCommandCrc() { return crc; } + public String getArguments() { return arguments; } + public long getTargetId() { return targetId; } + + public void setCommandCrc(int crc) { this.crc = crc; } + public void setArguments(String args) { this.arguments = args; } + public void setTargetId(long targetId) { this.targetId = targetId; } + +} diff --git a/src/network/packets/swg/zone/object_controller/DataTransform.java b/src/network/packets/swg/zone/object_controller/DataTransform.java new file mode 100644 index 00000000..06dee473 --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/DataTransform.java @@ -0,0 +1,77 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + +import resources.Location; + + +public class DataTransform extends ObjectController { + + public static final int CRC = 0x0071; + + private int updateCounter = 0; + private Location l; + private float speed = 0; + + public DataTransform(long objectId, int counter, Location l, float speed) { + super(objectId, CRC); + if (l == null) + l = new Location(); + this.l = l; + } + + public DataTransform(ByteBuffer data) { + super(CRC); + this.l = new Location(); + decode(data); + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + getInt(data); + updateCounter = getInt(data); + l.setOrientationX(getFloat(data)); + l.setOrientationY(getFloat(data)); + l.setOrientationZ(getFloat(data)); + l.setOrientationW(getFloat(data)); + l.setX(getFloat(data)); + l.setY(getFloat(data)); + l.setZ(getFloat(data)); + speed = getFloat(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 36); + encodeHeader(data); + addInt(data, updateCounter); + addLocation(data, l); + addFloat(data, speed); + return data; + } + + public void setUpdateCounter(int counter) { this.updateCounter = counter; } + public void setLocation(Location l) { this.l = l; } + public void setSpeed(float speed) { this.speed = speed; } + + public int getUpdateCounter() { return updateCounter; } + public Location getLocation() { return l; } + public float getSpeed() { return speed; } + + public double getMovementAngle() { + byte movementAngle = (byte) 0.0f; + double wOrient = l.getOrientationW(); + double yOrient = l.getOrientationY(); + double sq = Math.sqrt(1 - (wOrient*wOrient)); + + if (sq != 0) { + if (l.getOrientationW() > 0 && l.getOrientationY() < 0) { + wOrient *= -1; + yOrient *= -1; + } + movementAngle = (byte) ((yOrient / sq) * (2 * Math.acos(wOrient) / 0.06283f)); + } + + return movementAngle; + } + +} diff --git a/src/network/packets/swg/zone/object_controller/ObjectController.java b/src/network/packets/swg/zone/object_controller/ObjectController.java new file mode 100644 index 00000000..47381e2e --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/ObjectController.java @@ -0,0 +1,70 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public abstract class ObjectController extends SWGPacket { + + public static final int CRC = 0x80CE5E46; + protected static final int HEADER_LENGTH = 26; + + private final int controllerCrc; + private int update = 0; + private long objectId = 0; + + public ObjectController(int controllerCrc) { + this(0, controllerCrc); + } + + public ObjectController(long objectId, int controllerCrc) { + this.objectId = objectId; + this.controllerCrc = controllerCrc; + this.update = 11; + } + + protected final void decodeHeader(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + update = getInt(data); + if (getInt(data) != controllerCrc) + System.err.println("ObjectController[" + getClass().getSimpleName() + "] Attempting to process invalid controller"); + objectId = getLong(data); + getInt(data); + return; + } + + protected final void encodeHeader(ByteBuffer data) { + addShort(data, 2); + addInt( data, CRC); + addInt (data, update); + addInt( data, controllerCrc); + addLong( data, objectId); + addInt( data, 0); + } + + public abstract void decode(ByteBuffer data); + public abstract ByteBuffer encode(); + + public long getObjectId() { return objectId; } + public int getUpdate() { return update; } + public int getControllerCrc() { return controllerCrc; } + + public void setUpdate(int update) { this.update = update; } + + public static final ObjectController decodeController(ByteBuffer data) { + if (data.array().length < 14) + return null; + int crc = data.getInt(10); + switch (crc) { + case 0x00000071: return new DataTransform(data); + case 0x00000116: return new CommandQueueEnqueue(data); + case 0x00000117: return new CommandQueueDequeue(data); + case 0x0000012E: return new PlayerEmote(data); + case 0x00000131: return new PostureUpdate(data); + case 0x00000146: return new ObjectMenuRequest(data); + } + return null; + } + +} diff --git a/src/network/packets/swg/zone/object_controller/ObjectMenuRequest.java b/src/network/packets/swg/zone/object_controller/ObjectMenuRequest.java new file mode 100644 index 00000000..463fa8df --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/ObjectMenuRequest.java @@ -0,0 +1,79 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import resources.RadialOption; + +public class ObjectMenuRequest extends ObjectController { + + public static final int CRC = 0x0146; + + private long targetId; + private long requesterId; + private List options; + private byte counter; + + public ObjectMenuRequest(long objectId) { + super(objectId, CRC); + options = new ArrayList(); + } + + public ObjectMenuRequest(ByteBuffer data) { + super(CRC); + options = new ArrayList(); + decode(data); + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + + targetId = getLong(data); + requesterId = getLong(data); + + int optionsCount = getInt(data); + for (int i = 0; i < optionsCount; i++) { + RadialOption option = new RadialOption(); + getByte(data); // option number + option.setParentId(getByte(data)); + option.setId(getShort(data)); + option.setOptionType(getByte(data)); + option.setText(getUnicode(data)); + options.add(option); + } + counter = getByte(data); + } + + public ByteBuffer encode() { + int optSize = 0; + for (RadialOption option : options) + optSize += 7 + option.getText().length()*2; + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 21 + optSize); + encodeHeader(data); + addLong(data, targetId); + addLong(data, requesterId); + addInt(data, options.size()); + int optNum = 0; + for (RadialOption option : options) { + addByte(data, ++optNum); // option number + addByte(data, option.getParentId()); + addShort(data, option.getId()); + addByte(data, option.getOptionType()); + addUnicode(data, option.getText()); + } + addByte(data, counter); + return data; + } + + public long getTargetId() { return targetId; } + public long getRequesterId() { return requesterId; } + public int getCounter() { return counter; } + public List getOptions() { return options; } + + public void setTargetId(long targetId) { this.targetId = targetId; } + public void setRequesterId(long requesterId) { this.requesterId = requesterId; } + public void setCounter(byte counter) { this.counter = counter; } + public void addOption(RadialOption opt) { options.add(opt); } + +} diff --git a/src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java b/src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java new file mode 100644 index 00000000..b06fb705 --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java @@ -0,0 +1,79 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import resources.RadialOption; + +public class ObjectMenuResponse extends ObjectController { + + public static final int CRC = 0x0147; + + private long targetId; + private long requesterId; + private List options; + private int counter; + + public ObjectMenuResponse(long objectId) { + super(objectId, CRC); + } + + public ObjectMenuResponse(long objectId, long targetId, long requesterId, List options, int counter) { + super(objectId, CRC); + this.targetId = targetId; + this.requesterId = requesterId; + this.options = options; + this.counter = counter; + } + + public ObjectMenuResponse(ByteBuffer data) { + super(CRC); + options = new ArrayList(); + decode(data); + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + targetId = getLong(data); + requesterId = getLong(data); + int optionCount = getInt(data); + for (int i = 0; i < optionCount; i++) { + RadialOption option = new RadialOption(); + getByte(data); // option number + option.setParentId(getByte(data)); + option.setId(getShort(data)); + option.setOptionType(getByte(data)); + option.setText(getUnicode(data)); + } + counter = getByte(data); + } + + public ByteBuffer encode() { + int optionsDataSize = 0; + for (RadialOption o : options) { + optionsDataSize += 9; + if (o.getText() != null || !o.getText().isEmpty()) + optionsDataSize += o.getText().length()*2; + } + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + optionsDataSize + 21); + encodeHeader(data); + + addLong(data, targetId); + addLong(data, requesterId); + + addInt(data, options.size()); + for (int i = 0; i < options.size(); i++) { + RadialOption option = options.get(i); + addByte(data, i + 1); + addByte(data, option.getParentId()); + addShort(data, option.getId()); + addByte(data, option.getOptionType()); + if (option.getText() != null || !option.getText().isEmpty()) + addUnicode(data, option.getText()); + else data.putInt(0); + } + addByte(data, counter); + return data; + } +} diff --git a/src/network/packets/swg/zone/object_controller/PlayerEmote.java b/src/network/packets/swg/zone/object_controller/PlayerEmote.java new file mode 100644 index 00000000..49b2db7e --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/PlayerEmote.java @@ -0,0 +1,56 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + +public class PlayerEmote extends ObjectController { + + public static final int CRC = 0x012E; + + private long sourceId; + private long targetId; + private short emoteId; + + public PlayerEmote(long objectId) { + super(objectId, CRC); + } + + public PlayerEmote(ByteBuffer data) { + super(CRC); + decode(data); + } + + public PlayerEmote(long objectId, long sourceId, long targetId, short emoteId) { + super(objectId, CRC); + this.sourceId = sourceId; + this.targetId = targetId; + this.emoteId = emoteId; + } + + public PlayerEmote(long objectId, PlayerEmote emote) { + super(objectId, CRC); + this.sourceId = emote.sourceId; + this.targetId = emote.targetId; + this.emoteId = emote.emoteId; + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + sourceId = getLong(data); + targetId = getLong(data); + emoteId = getShort(data); + getShort(data); // Should be 0 + getByte(data); // Should be 3 + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 21); + encodeHeader(data); + addLong(data, sourceId); + addLong(data, targetId); + addShort(data, emoteId); + addShort(data, (short) 0); + addByte(data, (byte) 3); + return data; + } + +} diff --git a/src/network/packets/swg/zone/object_controller/PostureUpdate.java b/src/network/packets/swg/zone/object_controller/PostureUpdate.java new file mode 100644 index 00000000..1d9cd803 --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/PostureUpdate.java @@ -0,0 +1,41 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + +import resources.Posture; + +public class PostureUpdate extends ObjectController { + + public static final int CRC = 0x0131; + + private Posture posture; + + public PostureUpdate(long objectId, Posture posture) { + super(objectId, CRC); + this.posture = posture; + } + + public PostureUpdate(ByteBuffer data) { + super(CRC); + decode(data); + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + posture = Posture.getFromId(getByte(data)); + getBoolean(data); // isClientImmediate + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 2); + encodeHeader(data); + addByte(data, posture.getId()); + addBoolean(data, true); // isClientImmediate + return data; + } + + public Posture getPosture() { return posture; } + + public void setPosture(Posture posture) { this.posture = posture; } + +} diff --git a/src/network/packets/swg/zone/object_controller/SitOnObject.java b/src/network/packets/swg/zone/object_controller/SitOnObject.java new file mode 100644 index 00000000..079461a4 --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/SitOnObject.java @@ -0,0 +1,61 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + +import network.packets.swg.zone.object_controller.ObjectController; + +public class SitOnObject extends ObjectController { + + public static final int CRC = 0x013B; + + private long cellId; + private float x; + private float y; + private float z; + + public SitOnObject(long objectId) { + super(objectId, CRC); + } + + public SitOnObject(ByteBuffer data) { + super(CRC); + decode(data); + } + + public SitOnObject(long objectId, long cellId, float x, float y, float z ) { + super(objectId, CRC); + this.cellId = cellId; + this.x = x; + this.y = y; + this.z = z; + } + + public SitOnObject(long objectId, SitOnObject sit) { + super(objectId, CRC); + this.cellId = sit.cellId; + this.x = sit.x; + this.y = sit.y; + this.z = sit.z; + } + + @Override + public void decode(ByteBuffer data) { + decodeHeader(data); + cellId = getLong(data); + x = getFloat(data); + z = getFloat(data); + y = getFloat(data); + } + + @Override + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 20); + encodeHeader(data); + addLong(data, cellId); + addFloat(data, x); + addFloat(data, z); + addFloat(data, y); + return data; + } + +} diff --git a/src/network/packets/swg/zone/object_controller/SpatialChat.java b/src/network/packets/swg/zone/object_controller/SpatialChat.java new file mode 100644 index 00000000..b415228e --- /dev/null +++ b/src/network/packets/swg/zone/object_controller/SpatialChat.java @@ -0,0 +1,102 @@ +package network.packets.swg.zone.object_controller; + +import java.nio.ByteBuffer; + + +public class SpatialChat extends ObjectController { + + public static final int CRC = 0x00F4; + + private long sourceId = 0; + private long targetId = 0; + private String text = ""; + private short balloonSize = 5; + private short balloonType = 0; + private short moodId = 0; + private byte languageId = 0; + private String outOfBand = ""; + private String sourceName = ""; + + public SpatialChat(long objectId) { + super(objectId, CRC); + } + + public SpatialChat(long objectId, long sourceId, long targetId, String text, short balloonType, short moodId) { + super(objectId, CRC); + this.sourceId = sourceId; + this.targetId = targetId; + this.text = text; + this.balloonType = balloonType; + this.moodId = moodId; + } + + public SpatialChat(long objectId, SpatialChat chat) { + super(objectId, CRC); + this.sourceId = chat.sourceId; + this.targetId = chat.targetId; + this.text = chat.text; + this.balloonSize = chat.balloonSize; + this.balloonType = chat.balloonType; + this.moodId = chat.moodId; + this.languageId = chat.languageId; + this.outOfBand = chat.outOfBand; + this.sourceName = chat.sourceName; + } + + public SpatialChat(ByteBuffer data) { + super(CRC); + decode(data); + } + + public void decode(ByteBuffer data) { + decodeHeader(data); + sourceId = getLong(data); + targetId = getLong(data); + text = getUnicode(data); + getInt(data); + balloonSize = getShort(data); + balloonType = getShort(data); + moodId = getShort(data); + languageId = getByte(data); + outOfBand = getUnicode(data); + sourceName = getUnicode(data); + } + + public ByteBuffer encode() { + int length = 39 + text.length()*2 + outOfBand.length()*2 + sourceName.length()*2; + ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + length); + encodeHeader(data); + addLong(data, sourceId); + addLong(data, targetId); + addUnicode(data, text); + addInt(data, 0); // flags + addShort(data, balloonSize); + addShort(data, balloonType); + addShort(data, moodId); + addByte(data, languageId); // languageId + addUnicode(data, outOfBand); + addUnicode(data, sourceName); + return data; + } + + public void setSourceId(long sourceId) { this.sourceId = sourceId; } + public void setTargetId(long targetId) { this.targetId = targetId; } + public void setText(String text) { this.text = text; } + public void setBalloonSize(short size) { this.balloonSize = size; } + public void setBalloonType(short type) { this.balloonType = type; } + public void setMoodId(short moodId) { this.moodId = moodId; } + public void setLanguageId(byte id) { this.languageId = id; } + public void setOutOfBand(String oob) { this.outOfBand = oob; } + public void setSourceName(String name) { this.sourceName = name; } + + public long getSourceId() { return sourceId; } + public long getTargetId() { return targetId; } + public String getText() { return text; } + public short getBalloonSize() { return balloonSize; } + public short getBalloonType() { return balloonType; } + public short getMoodId() { return moodId; } + public byte getLanguageId() { return languageId; } + public String getOutOfBand() { return outOfBand; } + public String getSourceName() { return sourceName; } + +} diff --git a/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java b/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java new file mode 100644 index 00000000..89d6e957 --- /dev/null +++ b/src/network/packets/swg/zone/server_ui/SuiCreatePageMessage.java @@ -0,0 +1,123 @@ +package network.packets.swg.zone.server_ui; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import network.packets.swg.SWGPacket; + +public class SuiCreatePageMessage extends SWGPacket { + + public static final int CRC = 0xD44B7259; + + private int windowId; + private String scriptName; + private List components; + private long objectId; + private float maxDistance; + + public SuiCreatePageMessage() { + this(0, "", new ArrayList(), 0, 0); + } + + public SuiCreatePageMessage(int windowId, String scriptName, List components, long objectId, float maxDistance) { + this.windowId = windowId; + this.scriptName = scriptName; + this.components = components; + this.objectId = objectId; + this.maxDistance = maxDistance; + } + + public SuiCreatePageMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + windowId = getInt(data); + scriptName = getAscii(data); + int compSize = getInt(data); + components.clear(); + for (int compI = 0; compI < compSize; compI++) { + SuiWindowComponent comp = new SuiWindowComponent(); + comp.setType(getByte(data)); + int wideSize = getInt(data); + for (int wideI = 0; wideI < wideSize; wideI++) + comp.getWideParams().add(getUnicode(data)); + int narrowSize = getInt(data); + for (int narrowI = 0; narrowI < narrowSize; narrowI++) + comp.getNarrowParams().add(getAscii(data)); + components.add(comp); + } + objectId = getLong(data); + maxDistance = getFloat(data); + getLong(data); + getInt(data); + } + + public ByteBuffer encode() { + int extraSize = 0; + for (SuiWindowComponent comp : components) { + extraSize += 9; + for (String s : comp.getWideParams()) + extraSize += 4 + s.length()*2; + for (String s : comp.getNarrowParams()) + extraSize += 2 + s.length(); + } + ByteBuffer data = ByteBuffer.allocate(40+scriptName.length()+extraSize); + addShort(data, 2); + addInt( data, CRC); + addInt (data, windowId); + addAscii(data, scriptName); + addInt (data, components.size()); + for (SuiWindowComponent comp : components) { + addByte(data, comp.getType()); + addInt (data, comp.getWideParams().size()); + for (String wide : comp.getWideParams()) + addUnicode(data, wide); + addInt (data, comp.getNarrowParams().size()); + for (String narrow : comp.getNarrowParams()) + addAscii(data, narrow); + } + addLong (data, objectId); + addFloat(data, maxDistance); + addLong (data, 0); + addInt (data, 0); + return data; + } + + public static class SuiWindowComponent { + + private byte type; + private List narrowParams = new ArrayList(); + private List wideParams = new ArrayList(); + + public byte getType() { + return type; + } + public void setType(byte type) { + this.type = type; + } + public List getNarrowParams() { + return narrowParams; + } + public void setNarrowParams(List narrowParams) { + this.narrowParams = narrowParams; + } + public List getWideParams() { + return wideParams; + } + public void setWideParams(List wideParams) { + this.wideParams = wideParams; + } + public void addNarrowParam(String param) { + narrowParams.add(param); + } + public void addWideParam(String param) { + wideParams.add(param); + } + + } + +} diff --git a/src/network/packets/swg/zone/server_ui/SuiEventNotification.java b/src/network/packets/swg/zone/server_ui/SuiEventNotification.java new file mode 100644 index 00000000..fe6af82e --- /dev/null +++ b/src/network/packets/swg/zone/server_ui/SuiEventNotification.java @@ -0,0 +1,47 @@ +package network.packets.swg.zone.server_ui; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import network.packets.swg.SWGPacket; + +public class SuiEventNotification extends SWGPacket { + + public static final int CRC = 0x092D3564; + + private int windowId; + private int eventId; + private int updateCount; + private List dataStrings; + + public SuiEventNotification() { + dataStrings = new ArrayList(); + } + + public SuiEventNotification(ByteBuffer data) { + this(); + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + windowId = getInt(data); + eventId = getInt(data); + int size = getInt(data); + updateCount = getInt(data); + for (int i = 0; i < size; i++) { + dataStrings.add(getUnicode(data)); + } + } + + public ByteBuffer encode() { + return null; + } + + public int getWindowId() { return this.windowId; } + public List getDataStrings() { return this.dataStrings; } + public int getEventId() { return this.eventId; } + public int getUpdateCount() { return this.updateCount; } +} diff --git a/src/network/packets/swg/zone/spatial/AttributeListMessage.java b/src/network/packets/swg/zone/spatial/AttributeListMessage.java new file mode 100644 index 00000000..f897b66f --- /dev/null +++ b/src/network/packets/swg/zone/spatial/AttributeListMessage.java @@ -0,0 +1,64 @@ +package network.packets.swg.zone.spatial; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import network.packets.swg.SWGPacket; + +public class AttributeListMessage extends SWGPacket { + + public static final int CRC = 0xF3F12F2A; + + private long objectId; + private Map attributes; + + public AttributeListMessage() { + this(0, new HashMap()); + } + + public AttributeListMessage(long objectId, Map attributes) { + this.objectId = objectId; + this.attributes = attributes; + } + + public AttributeListMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objectId = getLong(data); + getShort(data); + int count = getInt(data); + for (int i = 0; i < count; i++) { + String name = getAscii(data); + String attr = getUnicode(data); + attributes.put(name, attr); + } + getInt(data); + } + + public ByteBuffer encode() { + int size = 0; + for (Entry e : attributes.entrySet()) { + size += 6 + e.getKey().length() + (e.getValue().length() * 2); + } + ByteBuffer data = ByteBuffer.allocate(24 + size); + addShort(data, 3); + addInt (data, CRC); + addLong (data, objectId); + addShort(data, 0); + addInt (data, attributes.size()); + for (Entry e : attributes.entrySet()) { + addAscii(data, e.getKey()); + addUnicode(data, e.getValue()); + } + addInt (data, 0); + return data; + } + +} + diff --git a/src/network/packets/swg/zone/spatial/GetMapLocationsMessage.java b/src/network/packets/swg/zone/spatial/GetMapLocationsMessage.java new file mode 100644 index 00000000..0e81a07a --- /dev/null +++ b/src/network/packets/swg/zone/spatial/GetMapLocationsMessage.java @@ -0,0 +1,60 @@ +package network.packets.swg.zone.spatial; + +import java.nio.ByteBuffer; +import network.packets.swg.SWGPacket; + +public class GetMapLocationsMessage extends SWGPacket { + + public static final int CRC = 0x1A7AB839; + + private String planet; + private float x; + private float y; + private boolean category; + private boolean subcategory; + private boolean icon; + + public GetMapLocationsMessage() { + this("", 0, 0, false, false, false); + } + + public GetMapLocationsMessage(String planet, float x, float y, boolean category, boolean subcategory, boolean icon) { + this.planet = planet; + this.x = x; + this.y = y; + this.category = category; + this.subcategory = subcategory; + this.icon = icon; + } + + public GetMapLocationsMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + planet = getAscii(data); + x = getFloat(data); + y = getFloat(data); + category = getByte(data) != 0; + subcategory = getByte(data) != 0; + icon = getByte(data) != 0; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(19 + planet.length()); + addShort(data, 28); + addInt (data, CRC); + addAscii(data, planet); + addFloat(data, x); + addFloat(data, y); + addByte (data, category ? 1 : 0); + addByte (data, subcategory ? 1 : 0); + addByte (data, icon ? 1 : 0); + return data; + } + + public String getPlanet() { return planet; } +} + diff --git a/src/network/packets/swg/zone/spatial/GetMapLocationsResponseMessage.java b/src/network/packets/swg/zone/spatial/GetMapLocationsResponseMessage.java new file mode 100644 index 00000000..e58b57ed --- /dev/null +++ b/src/network/packets/swg/zone/spatial/GetMapLocationsResponseMessage.java @@ -0,0 +1,32 @@ +package network.packets.swg.zone.spatial; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class GetMapLocationsResponseMessage extends SWGPacket { + public static final int CRC = 0x9F80464C; + private String planet; + + public GetMapLocationsResponseMessage(String planet) { + this.planet = planet; + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(32 + planet.length()); + + addShort(data, 8); + addInt(data, CRC); + addAscii(data, planet); + addInt(data, 0); // map locations size + + // Unknowns + addInt(data, 0); + addInt(data, 0); + addInt(data, 0x480); + addInt(data, 0x48D); + addInt(data, 1); + return data; + } + +} diff --git a/src/network/packets/swg/zone/spatial/NewTicketActivityResponseMessage.java b/src/network/packets/swg/zone/spatial/NewTicketActivityResponseMessage.java new file mode 100644 index 00000000..89098a7e --- /dev/null +++ b/src/network/packets/swg/zone/spatial/NewTicketActivityResponseMessage.java @@ -0,0 +1,35 @@ +package network.packets.swg.zone.spatial; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class NewTicketActivityResponseMessage extends SWGPacket { + + public static final int CRC = 0x6EA42D80; + + public NewTicketActivityResponseMessage() { + + } + + public NewTicketActivityResponseMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + getByte(data); + getInt(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(11); + addShort(data, 2); + addInt (data, CRC); + addByte (data, 0); + addInt (data, 1); + return data; + } + +} diff --git a/src/network/packets/swg/zone/spatial/StopClientEffectObjectByLabelMessage.java b/src/network/packets/swg/zone/spatial/StopClientEffectObjectByLabelMessage.java new file mode 100644 index 00000000..5d6e986d --- /dev/null +++ b/src/network/packets/swg/zone/spatial/StopClientEffectObjectByLabelMessage.java @@ -0,0 +1,45 @@ +package network.packets.swg.zone.spatial; + +import java.nio.ByteBuffer; + +import network.packets.swg.SWGPacket; + +public class StopClientEffectObjectByLabelMessage extends SWGPacket { + + public static final int CRC = 0xAD6F6B26; + + private long objectId; + private String effect; + + public StopClientEffectObjectByLabelMessage() { + + } + + public StopClientEffectObjectByLabelMessage(long objectId, String effect) { + this.objectId = objectId; + this.effect = effect; + } + + public StopClientEffectObjectByLabelMessage(ByteBuffer data) { + decode(data); + } + + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + objectId = getLong(data); + effect = getAscii(data); + getByte(data); + } + + public ByteBuffer encode() { + ByteBuffer data = ByteBuffer.allocate(6); + addShort(data, 4); + addInt (data, CRC); + addLong (data, objectId); + addAscii(data, effect); + addByte (data, 1); + return data; + } + +} diff --git a/src/resources/Attributes.java b/src/resources/Attributes.java new file mode 100644 index 00000000..b37fd2b2 --- /dev/null +++ b/src/resources/Attributes.java @@ -0,0 +1,26 @@ +package resources; + + +public class Attributes { + + private int agility = 0; + private int constitution = 0; + private int luck = 0; + private int precision = 0; + private int stamina = 0; + private int strength = 0; + + public void setAgility(int agility) { this.agility = agility; } + public void setConstitution(int constitution) { this.constitution = constitution; } + public void setLuck(int luck) { this.luck = luck; } + public void setPrecision(int precision) { this.precision = precision; } + public void setStamina(int stamina) { this.stamina = stamina; } + public void setStrength(int strength) { this.strength = strength; } + + public int getAgility() { return agility; } + public int getConstitution() { return constitution; } + public int getLuck() { return luck; } + public int getPrecision() { return precision; } + public int getStamina() { return stamina; } + public int getStrength() { return strength; } +} diff --git a/src/resources/Galaxy.java b/src/resources/Galaxy.java new file mode 100644 index 00000000..0287c1b6 --- /dev/null +++ b/src/resources/Galaxy.java @@ -0,0 +1,80 @@ +package resources; + + +public class Galaxy { + + private int id = 0; + private String name = ""; + private String address = ""; + private int zonePort = 44463; + private int pingPort = 44462; + private int population = 0; + private int popStatus = 0; + private GalaxyStatus status = GalaxyStatus.DOWN; + private int timeZone = 0; + private int maxCharacters = 0; + private int onlinePlayerLimit = 0; + private int onlineFreeTrialLimit = 0; + private boolean recommended = true; + + public Galaxy() { + + } + + public int getId() { return id; } + public String getName() { return name; } + public String getAddress() { return address; } + public int getZonePort() { return zonePort; } + public int getPingPort() { return pingPort; } + public int getPopulation() { return population; } + public int getPopulationStatus() { return popStatus; } + public GalaxyStatus getStatus() { return status; } + public int getTimeZone() { return timeZone; } + public int getMaxCharacters() { return maxCharacters; } + public int getOnlinePlayerLimit() { return onlinePlayerLimit; } + public int getOnlineFreeTrialLimit() { return onlineFreeTrialLimit; } + public boolean isRecommended() { return recommended; } + + public void setId(int id) { this.id = id; } + public void setName(String name) { this.name = name; } + public void setAddress(String addr) { this.address = addr; } + public void setZonePort(int port) { this.zonePort = port; } + public void setPingPort(int port) { this.pingPort = port; } + public void setPopulation(int population) { this.population = population; } + public void setPopulationStatus(int status) { this.popStatus = status; } + public void setStatus(GalaxyStatus status) { this.status = status; } + public void setTimeZone(int timeZone) { this.timeZone = timeZone; } + public void setMaxCharacters(int max) { this.maxCharacters = max; } + public void setOnlinePlayerLimit(int max) { this.onlinePlayerLimit = max; } + public void setOnlineFreeTrialLimit(int max) { this.onlineFreeTrialLimit = max; } + public void setRecommended(boolean r) { this.recommended = r; } + + public void setStatus(int status) { + for (GalaxyStatus gs : GalaxyStatus.values()) { + if (gs.getStatus() == status) { + setStatus(gs); + return; + } + } + } + + public enum GalaxyStatus { + DOWN (0x00), + LOADING (0x01), + UP (0x02), + LOCKED (0x03), + RESTRICTED (0x04), + FULL (0x05); + + private byte status; + + GalaxyStatus(int status) { + this.status = (byte) status; + } + + public byte getStatus() { + return status; + } + } + +} diff --git a/src/resources/Location.java b/src/resources/Location.java new file mode 100644 index 00000000..57ef56fc --- /dev/null +++ b/src/resources/Location.java @@ -0,0 +1,202 @@ +package resources; + +import java.io.Serializable; + + +public class Location implements Serializable { + + private static final long serialVersionUID = 1L; + + private Terrain terrain = null; + + private double x = Double.NaN; + private double y = Double.NaN; + private double z = Double.NaN; + + private double oX = Double.NaN; + private double oY = Double.NaN; + private double oZ = Double.NaN; + private double oW = Double.NaN; + + public Location() { + + } + + public Location(double x, double y, double z, Terrain terrain) { + this.terrain = terrain; + this.x = x; + this.y = y; + this.z = z; + } + + public Location(Location l) { + this.terrain = l.terrain; + this.x = l.x; + this.y = l.y; + this.z = l.z; + this.oX = l.oX; + this.oY = l.oY; + this.oZ = l.oZ; + this.oW = l.oW; + } + + public void setTerrain(Terrain terrain) { this.terrain = terrain; } + public void setX(double x) { this.x = x; } + public void setY(double y) { this.y = y; } + public void setZ(double z) { this.z = z; } + public void setOrientationX(double oX) { this.oX = oX; } + public void setOrientationY(double oY) { this.oY = oY; } + public void setOrientationZ(double oZ) { this.oZ = oZ; } + public void setOrientationW(double oW) { this.oW = oW; } + + public Terrain getTerrain() { return terrain; } + public double getX() { return x; } + public double getY() { return y; } + public double getZ() { return z; } + public double getOrientationX() { return oX; } + public double getOrientationY() { return oY; } + public double getOrientationZ() { return oZ; } + public double getOrientationW() { return oW; } + + public boolean isWithinDistance(Location l, double x, double y, double z) { + double xD = Math.abs(this.x - l.getX()); + double yD = Math.abs(this.y - l.getY()); + double zD = Math.abs(this.z - l.getZ()); + return xD <= x && yD <= y && zD <= z; + } + + public void translatePosition(double x, double y, double z) { + this.x += x; + this.y += y; + this.z += z; + } + + public Location translate(double x, double y, double z) { + Location loc = new Location(this); + loc.translatePosition(x, y, z); + return loc; + } + + public Location translate(Location l) { + return translate(l.getX(), l.getY(), l.getZ()); + } + + public boolean mergeWith(Location l) { + boolean changed = false; + if (terrain == null || terrain != l.getTerrain()) { + terrain = l.getTerrain(); + changed = true; + } + changed = mergeLocation(l.getX(), l.getY(), l.getZ()) || true; + changed = mergeOrientation(l) || true; + return changed; + } + + public boolean mergeLocation(double lX, double lY, double lZ) { + boolean changed = false; + if (Double.isNaN(x) || x != lX) { + x = lX; + changed = true; + } + if (Double.isNaN(y) || y != lY) { + y = lY; + changed = true; + } + if (Double.isNaN(z) || z != lZ) { + z = lZ; + changed = true; + } + return changed; + } + + private boolean mergeOrientation(Location l) { + boolean changed = false; + if (Double.isNaN(oX) || oX != l.getOrientationX()) { + oX = l.getOrientationX(); + changed = true; + } + if (Double.isNaN(oY) || oY != l.getOrientationY()) { + oY = l.getOrientationY(); + changed = true; + } + if (Double.isNaN(oZ) || oZ != l.getOrientationZ()) { + oZ = l.getOrientationZ(); + changed = true; + } + if (Double.isNaN(oW) || oW != l.getOrientationW()) { + oW = l.getOrientationW(); + changed = true; + } + return changed; + } + + public double getSpeed(Location l, double deltaTime) { + double dist = Math.sqrt(square(x-l.x) + square(y-l.y) + square(z-l.z)); + return dist / deltaTime; + } + + public double getYaw() { + double w = oW; + double y = oY; + double angle = 0; + + if (w * w + y * y > 0) { + if (w > 0 && y < 0) + w *= -1; + angle = 2 * Math.acos(w); + } else { + angle = 0; + } + + return angle; + } + + private double square(double x) { + return x*x; + } + + public boolean isNaN() { + return Double.isNaN(x) && Double.isNaN(y) && Double.isNaN(z) && Double.isNaN(oX) && Double.isNaN(oY) && Double.isNaN(oZ) && Double.isNaN(oW); + } + + public boolean equals(Location l) { + if (terrain != l.terrain) + return false; + if (!isEqual(l.x, x)) + return false; + if (!isEqual(l.y, y)) + return false; + if (!isEqual(l.z, z)) + return false; + if (!isEqual(l.oX, oX)) + return false; + if (!isEqual(l.oY, oY)) + return false; + if (!isEqual(l.oZ, oZ)) + return false; + if (!isEqual(l.oW, oW)) + return false; + return true; + } + + public int hashCode() { + return hash(x)*13 + hash(y)*17 + hash(z)*19 + hash(oX)*23 + hash(oY)*29 + hash(oZ)*31 + hash(oW)*37; + } + + private int hash(double x) { + long v = Double.doubleToLongBits(x); + return (int)(v^(v>>>32)); + } + + private boolean isEqual(double x, double y) { + if (Double.isNaN(x)) + return Double.isNaN(y); + if (Double.isNaN(y)) + return false; + return x == y; + } + + public String toString() { + return "Location[TRN=" + terrain + ", POS=(" + x + ", " + y + ", " + z + ") ORTN=(" + oX + ", " + oY + ", " + oZ + ", " + oW + ")]"; + } +} diff --git a/src/resources/Posture.java b/src/resources/Posture.java new file mode 100644 index 00000000..bbdec940 --- /dev/null +++ b/src/resources/Posture.java @@ -0,0 +1,45 @@ +package resources; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public enum Posture { + UPRIGHT (0x00), + CROUCHED (0x01), + PRONE (0x02), + SNEAKING (0x03), + BLOCKING (0x04), + CLIMBING (0x05), + FLYING (0x06), + LYING_DOWN (0x07), + SITTING (0x08), + SKILL_ANIMATING (0x09), + DRIVING_VEHICLE (0x0A), + RIDING_CREATURE (0x0B), + KNOCKED_DOWN (0x0C), + INCAPACITATED (0x0D), + DEAD (0x0E), + INVALID (0x0E); + + private static final Map POSTURE_MAP = new ConcurrentHashMap(); + private byte id; + + static { + for (Posture p : values()) + POSTURE_MAP.put(p.getId(), p); + } + + Posture(int id) { + this.id = (byte)id; + } + + public byte getId() { return id; } + + public static final Posture getFromId(byte id) { + Posture p = POSTURE_MAP.get(id); + if (p == null) + return INVALID; + return p; + } + +} diff --git a/src/resources/Race.java b/src/resources/Race.java new file mode 100644 index 00000000..ae7bd9f4 --- /dev/null +++ b/src/resources/Race.java @@ -0,0 +1,121 @@ +package resources; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import resources.client_info.ClientFactory; + + +public enum Race { + HUMAN (true, 0x619BAE21, "human_male", 50, 0, 0, 50, 50, 50), + HUMAN_MALE (true, 0x060E51D5, "human_male", 50, 0, 0, 50, 50, 50), + HUMAN_FEMALE (false, 0xD4A72A70, "human_female", 50, 0, 0, 50, 50, 50), + TRANDOSHAN_MALE (true, 0x04FEC8FA, "trandoshan_male", 20, 65, 0, 0, 65, 50), + TRANDOSHAN_FEMALE (false, 0x64C24976, "trandoshan_female", 20, 65, 0, 0, 65, 50), + TWILEK_MALE (true, 0x32F6307A, "twilek_male", 60, 0, 40, 40, 60, 0), + TWILEK_FEMALE (false, 0x6F6EB65D, "twilek_female", 60, 0, 40, 40, 60, 0), + BOTHAN_MALE (true, 0x9B81AD32, "bothan_male", 50, 25, 60, 65, 0, 0), + BOTHAN_FEMALE (false, 0xF6AB978F, "bothan_female", 50, 25, 60, 65, 0, 0), + ZABRAK_MALE (true, 0x22727757, "zabrak_male", 50, 50, 0, 50, 0, 50), + ZABRAK_FEMALE (false, 0x421ABB7C, "zabrak_female", 50, 50, 0, 50, 0, 50), + RODIAN_MALE (true, 0xCB8F1F9D, "rodian_male", 80, 0, 20, 80, 20, 0), + RODIAN_FEMALE (false, 0x299DC0DA, "rodian_female", 80, 0, 20, 80, 20, 0), + MONCAL_MALE (true, 0x79BE87A9, "moncal_male", 0, 40, 40, 60, 60, 0), + MONCAL_FEMALE (false, 0x73D65B5F, "moncal_female", 0, 40, 40, 60, 60, 0), + WOOKIEE_MALE (true, 0x2E3CE884, "wookiee_male", 0, 85, 0, 10, 40, 85), + WOOKIEE_FEMALE (false, 0x1AAD09FA, "wookiee_female", 0, 85, 0, 10, 40, 85), + SULLUSTAN_MALE (true, 0x1C95F5BC, "sullustan_male", 60, 60, 40, 0, 0, 40), + SULLUSTAN_FEMALE (false, 0x44739CC1, "sullustan_female", 60, 60, 40, 0, 0, 40), + ITHORIAN_MALE (true, 0xD3432345, "ithorian_male", 0, 0, 30, 40, 70, 60), + ITHORIAN_FEMALE (false, 0xE7DA1366, "ithorian_female", 0, 0, 30, 40, 70, 60); + + private static final Map SPECIES_TO_CRC = new ConcurrentHashMap(); + private static final Map CRC_TO_IFF = new ConcurrentHashMap(); + private static final Map CRC_TO_RACE = new ConcurrentHashMap(); + private static final Map SPECIES_TO_RACE = new ConcurrentHashMap(); + private static final Map FILE_TO_RACE = new ConcurrentHashMap(); + + static { + for (Race r : values()) { + SPECIES_TO_CRC.put(r.getSpecies(), r.getCrc()); + SPECIES_TO_RACE.put(r.getSpecies(), r); + CRC_TO_IFF.put(r.getCrc(), r.getFilename()); + CRC_TO_RACE.put(r.getCrc(), r); + FILE_TO_RACE.put(r.getFilename(), r); + } + } + + private boolean male; + private int crc; + private String species; + private int agility; + private int constitution; + private int luck; + private int precision; + private int stamina; + private int strength; + + Race(boolean male, int crc, String species, int agility, int constitution, int luck, int precision, int stamina, int strength) { + this.male = male; + this.crc = crc; + this.species = species; + this.agility = agility; + this.constitution = constitution; + this.luck = luck; + this.precision = precision; + this.stamina = stamina; + this.strength = strength; + } + + public boolean isMale() { return male; } + public boolean isFemale() { return !male; } + public int getCrc() { return crc; } + public int getAgility() { return agility; } + public int getConstitution() { return constitution; } + public int getLuck() { return luck; } + public int getPrecision() { return precision; } + public int getStamina() { return stamina; } + public int getStrength() { return strength; } + public String getFilename() { return "object/creature/player/shared_"+species+".iff"; } + public String getSpecies() { return species.substring(0, species.indexOf('_')); } + + public static final Race getRace(int crc) { + return CRC_TO_RACE.get(crc); + } + + public static final Race getRace(String species) { + if (species.endsWith(".iff")) + return getRaceByFile(species); + + Race r = SPECIES_TO_RACE.get("object/creature/player/" + species + ".iff"); + if (r == null) + r = SPECIES_TO_RACE.get("object/creature/player/shared_" + species + ".iff"); + if (r == null) + r = SPECIES_TO_RACE.get(species); + if (r == null) + r = HUMAN; + return r; + } + + public static final Race getRaceByFile(String iffFile) { + if (!iffFile.endsWith(".iff")) + return getRace(iffFile); + + Race r = FILE_TO_RACE.get(iffFile); + if (r == null) + r = FILE_TO_RACE.get(ClientFactory.formatToSharedFile(iffFile)); + if (r == null) + r = FILE_TO_RACE.get(iffFile); + if (r == null) + r = HUMAN; + return r; + } + + public static final int getCrc(String iff) { + return SPECIES_TO_CRC.get(iff.trim().replace(".iff", "").replace("object/creature/player/shared_", "")); + } + + public static final String getIff(int crc) { + return "object/creature/player/" + CRC_TO_IFF.get(crc) + ".iff"; + } +} diff --git a/src/resources/RadialOption.java b/src/resources/RadialOption.java new file mode 100644 index 00000000..fb4eaf09 --- /dev/null +++ b/src/resources/RadialOption.java @@ -0,0 +1,29 @@ +package resources; + +public class RadialOption { + private short id; + private byte parentId; + private byte optionType; // 1 unless the option text isn't listed in the radial item list (datatable). - ANHWiki + private String text; + + public RadialOption() { } + public RadialOption(String text, short id, byte parentId, byte optionType) { + this.text = text; + this.id = id; + this.parentId = parentId; + this.optionType = (text == null || text.isEmpty()) ? (byte) 1 : optionType; + } + + public short getId() { return id; } + public void setId(short id) { this.id = id; } + public byte getParentId() { return parentId; } + public void setParentId(byte parentId) { this.parentId = parentId; } + public void setOptionType(byte optionType) { this.optionType = optionType; } + public void setText(String text) { this.text = text; } + public byte getOptionType() { return optionType; } + public String getText() { return text; } + @Override + public String toString() { + return String.valueOf(id) + ": parentId- " + String.valueOf(parentId) + " optionType:" + String.valueOf(optionType) + " text-" + text; + } +} \ No newline at end of file diff --git a/src/resources/SortedLinkedList.java b/src/resources/SortedLinkedList.java new file mode 100644 index 00000000..cfa8936e --- /dev/null +++ b/src/resources/SortedLinkedList.java @@ -0,0 +1,54 @@ +package resources; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.ListIterator; + +public class SortedLinkedList> extends LinkedList { + + private static final long serialVersionUID = -6776628467181994889L; + + public SortedLinkedList() { + + } + + @Override + public boolean add(E e) { + Comparable element = (Comparable) e; + ListIterator iter = listIterator(); + while (iter.hasNext()) { + E item = iter.next(); + if (element.compareTo(item) <= 0) { + iter.previous(); + iter.add(e); + return true; + } + } + super.addLast(e); + return true; + } + + @Override + public void add(int index, E element) { + throw new UnsupportedOperationException("The sorted nature of the list prohibits this action."); + } + + @Override + public boolean addAll(Collection c) { + for (E item : c) { + add(item); + } + return true; + } + + @Override + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException("The sorted nature of the list prohibits this action."); + } + + @Override + public E set(int index, E element) { + throw new UnsupportedOperationException("The sorted nature of the list prohibits this action."); + } + +} diff --git a/src/resources/Terrain.java b/src/resources/Terrain.java new file mode 100644 index 00000000..271c6f06 --- /dev/null +++ b/src/resources/Terrain.java @@ -0,0 +1,155 @@ +package resources; + +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; + +import resources.common.CRC; + + +public enum Terrain { + ADVENTURE1 ("terrain/adventure1.trn"), + ADVENTURE2 ("terrain/adventure2.trn"), + CHARACTER_FARM ("terrain/character_farm.trn"), + CINCO_CITY_TEST_M5 ("terrain/cinco_city_test_m5.trn"), + CORELLIA ("terrain/corellia.trn"), + CREATURE_TEST ("terrain/creature_test.trn"), + DANTOOINE ("terrain/dantooine.trn"), + DATHOMIR ("terrain/dathomir.trn"), + DUNGEON1 ("terrain/dungeon1.trn"), + ENDOR_ASOMMERS ("terrain/endor_asommers.trn"), + ENDOR ("terrain/endor.trn"), + FLORATEST ("terrain/floratest.trn"), + GODCLIENT_TEST ("terrain/godclient_test.trn"), + KASHYYYK_DEAD_FOREST ("terrain/kashyyyk_dead_forest.trn"), + KASHYYYK_HUNTING ("terrain/kashyyyk_hunting.trn"), + KASHYYYK_MAIN ("terrain/kashyyyk_main.trn"), + KASHYYYK_NORTH_DUNGEONS ("terrain/kashyyyk_north_dungeons.trn"), + KASHYYYK_POB_DUNGEONS ("terrain/kashyyyk_pob_dungeons.trn"), + KASHYYYK_RRYATT_TRAIL ("terrain/kashyyyk_rryatt_trail.trn"), + KASHYYYK_SOUTH_DUNGEONS ("terrain/kashyyyk_south_dungeons.trn"), + KASHYYYK ("terrain/kashyyyk.trn"), + LOK ("terrain/lok.trn"), + MUSTAFAR ("terrain/mustafar.trn"), + NABOO ("terrain/naboo.trn"), + OTOH_GUNGA ("terrain/otoh_gunga.trn"), + RIVERTEST ("terrain/rivertest.trn"), + RORI ("terrain/rori.trn"), + RUNTIMERULES ("terrain/runtimerules.trn"), + SIMPLE ("terrain/simple.trn"), + SPACE_CORELLIA_2 ("terrain/space_corellia_2.trn"), + SPACE_CORELLIA ("terrain/space_corellia.trn"), + SPACE_DANTOOINE ("terrain/space_dantooine.trn"), + SPACE_DATHOMIR ("terrain/space_dathomir.trn"), + SPACE_ENDOR ("terrain/space_endor.trn"), + SPACE_ENV ("terrain/space_env.trn"), + SPACE_HALOS ("terrain/space_halos.trn"), + SPACE_HEAVY1 ("terrain/space_heavy1.trn"), + SPACE_KASHYYYK ("terrain/space_kashyyyk.trn"), + SPACE_LIGHT1 ("terrain/space_light1.trn"), + SPACE_LOK ("terrain/space_lok.trn"), + SPACE_NABOO_2 ("terrain/space_naboo_2.trn"), + SPACE_NABOO ("terrain/space_naboo.trn"), + SPACE_NOVA_ORION ("terrain/space_nova_orion.trn"), + SPACE_NPE_FALCON_2 ("terrain/space_npe_falcon_2.trn"), + SPACE_NPE_FALCON_3 ("terrain/space_npe_falcon_3.trn"), + SPACE_NPE_FALCON ("terrain/space_npe_falcon.trn"), + SPACE_ORD_MANTELL_2 ("terrain/space_ord_mantell_2.trn"), + SPACE_ORD_MANTELL_3 ("terrain/space_ord_mantell_3.trn"), + SPACE_ORD_MANTELL_4 ("terrain/space_ord_mantell_4.trn"), + SPACE_ORD_MANTELL_5 ("terrain/space_ord_mantell_5.trn"), + SPACE_ORD_MANTELL_6 ("terrain/space_ord_mantell_6.trn"), + SPACE_ORD_MANTELL ("terrain/space_ord_mantell.trn"), + SPACE_TATOOINE_2 ("terrain/space_tatooine_2.trn"), + SPACE_TATOOINE ("terrain/space_tatooine.trn"), + SPACE_YAVIN4 ("terrain/space_yavin4.trn"), + TAANAB ("terrain/taanab.trn"), + TALUS ("terrain/talus.trn"), + TATOOINE ("terrain/tatooine.trn"), + TERRAIN_TEST ("terrain/terrain_test.trn"), + TEST_WEARABLES ("terrain/test_wearables.trn"), + TUSKAN_RAID_ENCOUNTER ("terrain/tuskan_raid_encounter.trn"), + TUTORIAL ("terrain/tutorial.trn"), + UMBRA ("terrain/umbra.trn"), + WATERTABLETEST ("terrain/watertabletest.trn"), + YAVIN4 ("terrain/yavin4.trn"); + + private static final Map CRC_TO_NAME = new ConcurrentHashMap(); + private static final Map NAME_TO_CRC = new ConcurrentHashMap(); + private static final Map NAME_TO_TERRAIN = new ConcurrentHashMap(); + private static final Map CRC_TO_TERRAIN = new ConcurrentHashMap(); + + private String file; + private String name; + private int crc; + + static { + for (Terrain p : values()) { + CRC_TO_TERRAIN.put(p.getCrc(), p); + CRC_TO_NAME.put(p.getCrc(), p.name()); + NAME_TO_CRC.put(p.name().toLowerCase(), p.getCrc()); + NAME_TO_CRC.put(p.name().toLowerCase(), p.getCrc()); + NAME_TO_TERRAIN.put(p.name().toLowerCase(), p); + } + } + + Terrain(String file) { + this.file = file; + this.crc = CRC.getCrc(file); + this.name = file.substring(8, file.length() - 4); + } + + public String getFile() { return file; } + public String getName() { return name; } + public int getCrc() { return crc; } + + public Location getStartLocation() { + Location l = new Location(); + Random r = new Random(); + if (this == TATOOINE) { + l.setOrientationX(0); + l.setOrientationY(0); + l.setOrientationZ(0); + l.setOrientationW(1); + l.setX(3828 + r.nextInt(100) / 10 - 5); + l.setY(4); + l.setZ(-4804 + r.nextInt(100) / 10 - 5); + } + return l; + } + + public static final String getNameFromCrc(int crc) { + String name = CRC_TO_NAME.get(crc); + if (name == null) + return ""; + return name; + } + + public static final int getCrcFromName(String name) { + Integer crc = NAME_TO_CRC.get(name); + if (crc == null) + return 0; + return crc; + } + + /** + * Note: Defaults to TATOOINE + */ + public static final Terrain getTerrainFromCrc(int crc) { + Terrain p = CRC_TO_TERRAIN.get(crc); + if (p == null) + return TATOOINE; + return p; + } + + /** + * Note: Defaults to TATOOINE + */ + public static final Terrain getTerrainFromName(String name) { + Terrain p = NAME_TO_TERRAIN.get(name); + if (p == null) + return TATOOINE; + return p; + } + +} diff --git a/src/resources/client_info/ClientFactory.java b/src/resources/client_info/ClientFactory.java new file mode 100644 index 00000000..7b8d7aec --- /dev/null +++ b/src/resources/client_info/ClientFactory.java @@ -0,0 +1,252 @@ +package resources.client_info; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Map; + +import resources.client_info.visitors.ClientData; +import resources.client_info.visitors.CrcStringTableData; +import resources.client_info.visitors.DatatableData; +import resources.client_info.visitors.ObjectData; +import resources.client_info.visitors.ProfTemplateData; +import resources.client_info.visitors.SlotArrangementData; +import resources.client_info.visitors.SlotDefinitionData; +import resources.client_info.visitors.SlotDescriptorData; +import utilities.ByteUtilities; + +public class ClientFactory { + + private Map dataMap = new HashMap(); + private Map typeMap = new HashMap(); + + /** + * Creates a new instance of ClientFactory. + *
+ *
+ * In order to add parsing for an IFF type which is not yet parsed: + *
    + *
  1. Create a new class which extends {@link ClientData}. + *
  2. Perform the parsing of each node within the handleData method using switch-case statements for different node names. + *
  3. Add a new entry to the typeMap through populateTypeMap() method by adding in the name of the folder/node you're parsing + * as the Key and the name of the class that was just created as the Value. + *
  4. Add in a case statement in the createDataObject method returning a new instance of the class, the case being the Value + * that was entered in Step 3. + *
+ */ + public ClientFactory() { + populateTypeMap(); + } + + /** + * Retrieves information from a client file used by SWG. Parsing of the file is done internally using {@link ClientData} which also + * stores the variables and is the returned type. Retrieving info from this file puts a reference of the returned + * {@link ClientData} into a {@link HashMap}. Future calls for this file will try and obtain this reference if it's not null to prevent + * the file from being parsed multiple times. + * @param file The SWG file you wish to get information from which resides in the ./clientdata/ folder. + * Example: creation/profession_defaults_combat_brawler.iff + * @param saveInfo This will save the information into the map for future calls to get information from this file. + * @return Specific visitor type of {@link ClientData} relating to the chosen file. For example, loading the file + * creation/profession_defaults_combat_brawler.iff would return an instance of {@link ProfTemplateData} extended from {@link ClientData}. + * A null instance of {@link ClientData} means that parsing for the type of file is not done, or a file was entered that doesn't exist on the + * file system. + */ + public synchronized ClientData getInfoFromFile(String file, boolean saveInfo) { + ClientData data = dataMap.get(file); + + if (data == null) { + data = readFile(file); + if (data == null) { + return null; + } + + /*weak = new WeakReference(strong); + + if (weak.get() != null) { + dataMap.put(file, weak); + }*/ + } + + return data; + } + + public synchronized ClientData getInfoFromFile(String file) { + return getInfoFromFile(file, true); + } + + public synchronized static String formatToSharedFile(String original) { + if (original.contains("shared_")) + return original; + + int index = original.lastIndexOf("/"); + return original.substring(0, index) + "/shared_" + original.substring(index+1); + } + + // readFile only called if dataMap doesn't contain the file as a key or it's value is null + private ClientData readFile(String file) { + FileInputStream stream = null; + try { + File f = new File("./clientdata/" + file); + if (!f.exists()) { + System.out.println("./clientdata/"+ file + " not found!"); + return null; + } + + stream = new FileInputStream(f); + ByteBuffer bb = readIntoBuffer(stream); + + ClientData visitor = getFileType(bb); + if (visitor == null) { // Visitor value will be null if parsing for a certain client file type doesn't exist yet. + return null; + } + + bb.position(8); // Skip first FORM, some forms only have a node and not a parent form + parseData(bb, visitor); + return visitor; + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + } + + private ByteBuffer readIntoBuffer(FileInputStream stream) throws IOException { + ByteBuffer bb = ByteBuffer.allocate(stream.available()).order(ByteOrder.LITTLE_ENDIAN); + stream.read(bb.array()); + return bb; + } + + private ClientData getFileType(ByteBuffer bb) { + bb.position(8); // Skip the first FORM and data size + String type = ByteUtilities.nextString(bb); // Get the specific form for this IFF so we know what visitor to use + + ClientData data = createDataObject(type); + + if (data == null) { + System.err.println("Handling for " + type + " not implemented!"); + return null; + } + + return data; + } + + // Any time a new ClientData is coded for parsing a file, it will need to be added in populateTypeMap() along with a new return + // of that instance so the file can be parsed. The type is the name of the folder/node which is then used to get the value associated + // with it in the typeMap (value being the name of the Class preferably). If populateTypeMap() does not contain that node, then null is returned + // and getFileType method will print out what the type is along with a "not implemented!" message. + private ClientData createDataObject(String type) { + String c = typeMap.get(type); + if (c == null) { + System.err.println("Don't know what class to use for " + type); + return null; + } + + switch (c) { + case "CrcStringTableData": return new CrcStringTableData(); + case "DatatableData": return new DatatableData(); + case "ObjectData": return new ObjectData(this); + case "ProfTemplateData": return new ProfTemplateData(); + case "SlotDescriptorData": return new SlotDescriptorData(); + case "SlotDefinitionData": return new SlotDefinitionData(); + case "SlotArrangementData": return new SlotArrangementData(); + + default: return null; + } + } + + private void parseData(ByteBuffer bb, ClientData visitor) throws Exception { + String name = null; + while (bb.hasRemaining()) { + name = ByteUtilities.nextString(bb); + if (name.contains("FORM")) { + parseFolder(name, bb, visitor); + } else { + parseNode(name, bb, visitor); + } + } + + } + + private void parseNode(String name, ByteBuffer bb, ClientData visitor) throws Exception { + int size = Integer.reverseBytes(bb.getInt()); // Size of this node/folder + + if (size == 0) + return; + + // Create a new buffer for parsing data specific to this node (excluding name bytes) + visitor.handleData(name, getData(bb, size), size); + + } + + private void parseFolder(String name, ByteBuffer bb, ClientData visitor) throws Exception { + ByteBuffer data = getData(bb, Integer.reverseBytes(bb.getInt())); + + // Notify visitor of the Folder? May be needed at some point. + + parseData(data, visitor); + } + + // Cut down a ByteBuffer from the current position so we are only working with a certain amount of bytes. Useful when we + // call the ClientData.handleData method. + private ByteBuffer getData(ByteBuffer source, int size) { + ByteBuffer data = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN); + int offset = source.position(); + data.put(source.array(), offset, size); + source.position(offset+size); + data.flip(); + + return data; + } + + // The typeMap is used for determining what ClientData class + private void populateTypeMap() { + + typeMap.put("ARGDFORM", "SlotArrangementData"); + typeMap.put("0006DATA", "SlotDefinitionData"); + typeMap.put("CSTBFORM", "CrcStringTableData"); + typeMap.put("DTIIFORM", "DatatableData"); + typeMap.put("PRFIFORM", "ProfTemplateData"); + typeMap.put("SLTDFORM", "SlotDescriptorData"); + + // Objects + typeMap.put("SBMKFORM", "ObjectData"); // object/battlefield_marker + typeMap.put("SBOTFORM", "ObjectData"); // object/building + typeMap.put("CCLTFORM", "ObjectData"); // object/cell + typeMap.put("SCNCFORM", "ObjectData"); // object/construction_contract + typeMap.put("SCOUFORM", "ObjectData"); // object/counting + typeMap.put("SCOTFORM", "ObjectData"); // object/creature && object/mobile + typeMap.put("SDSCFORM", "ObjectData"); // object/draft_schematic + typeMap.put("SFOTFORM", "ObjectData"); // object/factory + typeMap.put("SGRPFORM", "ObjectData"); // object/group + typeMap.put("SGLDFORM", "ObjectData"); // object/guild + typeMap.put("SIOTFORM", "ObjectData"); // object/installation + typeMap.put("SITNFORM", "ObjectData"); // object/intangible + typeMap.put("SJEDFORM", "ObjectData"); // object/jedi_manager + typeMap.put("SMSCFORM", "ObjectData"); // object/manufacture_schematic + typeMap.put("SMSOFORM", "ObjectData"); // object/mission + typeMap.put("SHOTFORM", "ObjectData"); // object/object + typeMap.put("STOTFORM", "ObjectData"); // object/path_waypoint && object/tangible + typeMap.put("SPLYFORM", "ObjectData"); // object/player + typeMap.put("SPQOFORM", "ObjectData"); // object/player_quest + typeMap.put("RCCTFORM", "ObjectData"); // object/resource_container + typeMap.put("SSHPFORM", "ObjectData"); // object/ship + typeMap.put("STATFORM", "ObjectData"); // object/soundobject && object/static + typeMap.put("STOKFORM", "ObjectData"); // object/token + typeMap.put("SUNIFORM", "ObjectData"); // object/universe + typeMap.put("SWAYFORM", "ObjectData"); // object/waypoint + typeMap.put("SWOTFORM", "ObjectData"); // object/weapon + // + + } + +} diff --git a/src/resources/client_info/visitors/ClientData.java b/src/resources/client_info/visitors/ClientData.java new file mode 100644 index 00000000..5ef7176a --- /dev/null +++ b/src/resources/client_info/visitors/ClientData.java @@ -0,0 +1,8 @@ +package resources.client_info.visitors; + +import java.nio.ByteBuffer; + +public abstract class ClientData { + + public abstract void handleData(String node, ByteBuffer data, int size); +} diff --git a/src/resources/client_info/visitors/CrcStringTableData.java b/src/resources/client_info/visitors/CrcStringTableData.java new file mode 100644 index 00000000..ce7668a1 --- /dev/null +++ b/src/resources/client_info/visitors/CrcStringTableData.java @@ -0,0 +1,69 @@ +package resources.client_info.visitors; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import utilities.ByteUtilities; + +public class CrcStringTableData extends ClientData { + + private ArrayList crcList = new ArrayList<>(); + private ArrayList startList = new ArrayList<>(); + private ArrayList stringList = new ArrayList<>(); + private Map crcMap = new HashMap<>(); + private int count; + + @Override + public void handleData(String node, ByteBuffer data, int size) { + switch (node) { + + case "0000DATA": + count = data.getInt(); + break; + + case "CRCT": + for(int i=0; i < count; ++i) { + crcList.add(data.getInt()); + } + break; + + case "STRT": + for(int i=0; i < count; ++i) { + startList.add(data.getInt()); + } + break; + + case "STNG": + for(int i=0; i < count; ++i) { + data.position(startList.get(i)); + String str = ByteUtilities.nextString(data); + crcMap.put(crcList.get(i), str); + stringList.add(str); + } + break; + } + + } + + public boolean isValidCrc(int crc) { + + if(!crcList.contains(crc)) + return false; + return true; + + } + + public String getTemplateString(int crc) { + return crcMap.get(crc); + } + + public int getCrcForString(String str) { + if (stringList.contains(str)) { + return crcList.get(stringList.indexOf(str)); + } else { + return 0; + } + } +} diff --git a/src/resources/client_info/visitors/DatatableData.java b/src/resources/client_info/visitors/DatatableData.java new file mode 100644 index 00000000..ada3db69 --- /dev/null +++ b/src/resources/client_info/visitors/DatatableData.java @@ -0,0 +1,171 @@ +package resources.client_info.visitors; + +import java.nio.ByteBuffer; + +import utilities.ByteUtilities; + +public class DatatableData extends ClientData { + + private String[] columnNames; + private String[] columnTypes; + private Object[][] table; + //private Map enums; + + @Override + public void handleData(String node, ByteBuffer data, int size) { + + switch(node) { + + case "0001COLS": + columnNames = new String[data.getInt()]; + + for (int i = 0; i < columnNames.length; i++) { + columnNames[i] = ByteUtilities.nextString(data); + data.get(); // empty separator byte + } + break; + + case "TYPE": + parseTypes(data); + break; + + case "ROWS": + parseRows(data); + } + } + + private void parseTypes(ByteBuffer data) { + columnTypes = new String[columnNames.length]; + + for (int t = 0; t < columnTypes.length; t++) { + String type = ByteUtilities.nextString(data); + + if (type.contains("[")) + type = type.split("\\[")[0]; + + if (type.contains("(")) // relevant only to enums + type = type.split("\\(")[0]; + + columnTypes[t] = type; + data.get(); // empty separator byte + +/* TODO: Need to come up with a better way of doing enums. Example of what this type looks like: +* e(RIFLE=0,CARBINE=1,PISTOL=2,HEAVY=3,1HAND_MELEE=4,2HAND_MELEE=5,UNARMED=6,POLEARM=7,THROWN=8,1HAND_LIGHTSABER=9,2HAND_LIGHTSABER=10,POLEARM_LIGHTSABER=11) + if (type.startsWith("e(")) { + // Cleanup string and put enum inside the enums map + String enumEntries = type; + enumEntries = type.replace("e(", "").replace(")", ""); + } +*/ + + } + } + + private void parseRows(ByteBuffer data) { + int rows = data.getInt(); + table = new Object[rows][columnTypes.length]; + + for (int r = 0; r < rows; r++) { + // Cell within row + for (int t = 0; t < columnTypes.length; t++) { + String type = columnTypes[t]; + + switch(type) { + + case "b": // Boolean + table[r][t] = (data.getInt() == 1); + break; + + case "e": // Enumerator + table[r][t] = data.getInt(); + break; + + case "f": // Float + table[r][t] = data.getFloat(); + break; + + case "h": // CRC + table[r][t] = data.getInt(); + break; + + case "i": // Integer + table[r][t] = data.getInt(); + break; + + case "s": // String + if (data.get() != 0) { + data.position(data.position() - 1); + table[r][t] = ByteUtilities.nextString(data); + data.get(); + } else { + table[r][t] = ""; + } + + break; + + case "v": + // TODO: Datatable Enums + data.getInt(); + break; + default: + System.err.println("FATAL: Don't know how to decode type " + type + " in row " + r + " column " + t); + break; + } + } + } + } + + public int getRowCount() { + if(table == null) + return 0; + return table.length; + } + + public int getColumnCount() { + if(table == null) + return 0; + return columnNames.length; + } + + public Object[] getRowsByColumnName(String columnName) { + + for(int i = 0; i < table.length; i++) { + for(int j=0; j < columnTypes.length; ++j) { + String currentName = columnNames[j]; + if(currentName.equals(columnName)) + return table[i]; + } + } + return null; + } + + public Object [] getRow(int row) { + return table[row]; + } + + public Object getCell(int row, int column) { + return table[row][column]; + } + + public Object getCell(String columnName, int rowIndex) { + for(int j=0; j < columnTypes.length; ++j) { + String currentName = columnNames[j]; + if(currentName.equals(columnName)) + return table[rowIndex][j]; + } + return null; + } + + public String getColumnName(int column) { + if (column < 0 || column >= columnNames.length) + return null; + return columnNames[column]; + } + + public String getColumnType(int column) { + if (column < 0 || column >= columnTypes.length) + return null; + return columnTypes[column]; + } + +} diff --git a/src/resources/client_info/visitors/ObjectData.java b/src/resources/client_info/visitors/ObjectData.java new file mode 100644 index 00000000..d6ea2070 --- /dev/null +++ b/src/resources/client_info/visitors/ObjectData.java @@ -0,0 +1,133 @@ +package resources.client_info.visitors; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import resources.client_info.ClientFactory; +import utilities.ByteUtilities; + +public class ObjectData extends ClientData { + + private Map attributes = new HashMap(); + private ClientFactory factory; + private List parsedFiles = new ArrayList(); + + public static final String APPEARANCE_FILE = "appearanceFilename"; + public static final String ARRANGEMENT_FILE = "arrangementDescriptorFilename"; + public static final String VOLUME_LIMIT = "containerVolumeLimit"; + public static final String DETAIL_STF = "detailedDescription"; + public static final String OBJ_STF = "objectName"; + public static final String PORTAL_LAYOUT = "portalLayoutFilename"; + public static final String SLOT_DESCRIPTOR = "slotDescriptorFilename"; + + public ObjectData(ClientFactory factory) { + this.factory = factory; + } + + @Override + public void handleData(String node, ByteBuffer data, int size) { + switch(node) { + + case "DERVXXXX": // Extended attributes + String file = ByteUtilities.nextString(data); + + if (parsedFiles.contains(file)) // some DERVXXX were repeated and we do not want to replace any attributes unless they're overriden by a more specific obj + break; + + ClientData attrData = factory.getInfoFromFile(file); + if (attrData == null || !(attrData instanceof ObjectData)) { + System.out.println("Could not load attribute data from file " + file + "!"); + return; // break out of whole method as we should only continue if we have all the extended attributes + } + + // Put all the extended attributes in this map so it's accessible. Note that some of these are overridden. + attributes.putAll(((ObjectData)attrData).getAttributes()); + + parsedFiles.add(file); + break; + + case "XXXX": + String attribute = ByteUtilities.nextString(data); + + data.get(); // always seems to be 0x00, separator byte after attr name most likely + + // Could put any unknown attributes in the map as a byte[], but most is just for the client which server doesn't need + parseAttribute(attribute, data); + + break; + + default: break; + } + } + + // Try and parse the attribute to map w/ appropriate Object type. + private boolean parseAttribute(String attr, ByteBuffer data) { + switch (attr) { + + case "appearanceFilename": putString(attr, data); break; + case "arrangementDescriptorFilename": putString(attr, data); break; + case "containerType": putInt(attr, data); break; + case "containerVolumeLimit": putInt(attr, data); break; + case "detailedDescription": putStfString(attr, data); break; + case "forceNoCollision": putBoolean(attr, data); break; + case "gender": putInt(attr, data); break; + case "objectName": putStfString(attr, data); break; + case "portalLayoutFilename": putString(attr, data); break; + case "slotDescriptorFilename": putString(attr, data); break; + case "structureFootprintFileName": putString(attr, data); break; + case "useStructureFootprintOutline": putBoolean(attr, data); break; + + default: break; + } + + return false; + } + + private void putStfString(String attr, ByteBuffer data) { + if (data.get() == 0) + return; + + data.get(); // 0x01 + String stfFile = ByteUtilities.nextString(data); + if (stfFile.isEmpty()) + return; + + data.getShort(); // 0x00, 0x01 (Shows up as well even if stfFile prior data.get() is 0) + + String stfName = ByteUtilities.nextString(data); + + attributes.put(attr, stfFile + ":" + stfName); + } + + private void putString(String attr, ByteBuffer data) { + if (data.get() != 0) { + String s = ByteUtilities.nextString(data); + if (s.isEmpty()) + return; + + attributes.put(attr, s); + } + } + + private void putInt(String attr, ByteBuffer data) { + if (data.get() != 0) { // This should always be 1 if there is an int (note that 0x20 follows after this even if it's 0) + data.get(); // 0x20 byte for all it seems, unsure what it means + attributes.put(attr, data.getInt()); + } + } + + private void putBoolean(String attr, ByteBuffer data) { + attributes.put(attr, (data.get() == 1 ? true : false)); + } + + public Object getAttribute(String attribute) { + return attributes.get(attribute); + } + + public Map getAttributes() { + return attributes; + } +} diff --git a/src/resources/client_info/visitors/ProfTemplateData.java b/src/resources/client_info/visitors/ProfTemplateData.java new file mode 100644 index 00000000..11c3e1f9 --- /dev/null +++ b/src/resources/client_info/visitors/ProfTemplateData.java @@ -0,0 +1,61 @@ +package resources.client_info.visitors; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import utilities.ByteUtilities; + +public class ProfTemplateData extends ClientData { + + private List