From e46b7142c3c418f9a4f0cf3b2190c4067765614c Mon Sep 17 00:00:00 2001 From: MatthewBishop <55411296+MatthewBishop@users.noreply.github.com> Date: Sat, 28 Jan 2023 00:31:19 -0500 Subject: [PATCH] Network cleanup (#552) * Replaced packetType/Size with packet * Replace Instream with Packet Read data directly from packet to ease future network upgrade * Update Packet.java Removed unused methods to ease netty migration and network rewrite. * Moved packet sizes. * Removed unused stream methods * Added readhex method for buttons * preparing to replace mina * Packet->GamePacket for refactoring * Netty 3.6.6 * formatting * formatting * Apollo core * Update net.xml Added variables for 2006scape * Netty 4 migration. Jagcached replaced with Apollo Core * Porting network into apollo * WIP Packet Changes Do not merge. This is broken. * Packet read methods converted to netty buffer * Replacing game network and login with apollo * Netty 4 * Cleanup * Same port for update and game server. * Cleanup login for integration with apollo * Login works. fixing packets * Running on apollo netcode. * Server runs * Update apollo-core.jar * Disable encoder. write outstream directly to channel. * Update RS2ProtocolDecoder.java Added apollo decoder * Add constant * Synchronization not needed * Update apollo-core.jar * Better performance. * Commit pre PR * Update apollo-core.jar * Fixup Port Binding Based On World * Apollo files * Additional Commit --------- Co-authored-by: Dark98 --- .../src/main/java/ClientSettings.java | 7 + .../src/main/java/OnDemandFetcher.java | 2 +- 2006Scape Server/data/net.xml | 12 + 2006Scape Server/pom.xml | 23 +- .../src/main/java/com/rs2/GameEngine.java | 56 +- .../src/main/java/com/rs2/game/bots/Bot.java | 16 +- .../java/com/rs2/game/dialogues/Dialogue.java | 3 +- .../java/com/rs2/game/players/Client.java | 16 +- .../java/com/rs2/game/players/Player.java | 125 +-- .../com/rs2/game/players/PlayerHandler.java | 5 +- .../main/java/com/rs2/net/CodecFactory.java | 40 - .../java/com/rs2/net/ConnectionHandler.java | 131 +-- .../com/rs2/net/ConnectionThrottleFilter.java | 132 --- .../java/com/rs2/net/GameCodecFactory.java | 46 - .../java/com/rs2/net/GameDecoderState.java | 28 + .../src/main/java/com/rs2/net/HostList.java | 125 ++- .../src/main/java/com/rs2/net/Packet.java | 576 +++++++---- .../main/java/com/rs2/net/PacketBuffer.java | 104 -- .../main/java/com/rs2/net/PacketBuilder.java | 10 - .../main/java/com/rs2/net/PacketSender.java | 3 +- .../com/rs2/net/RS2LoginProtocolDecoder.java | 305 ------ .../java/com/rs2/net/RS2ProtocolDecoder.java | 315 +++--- .../java/com/rs2/net/RS2ProtocolEncoder.java | 108 +- .../java/com/rs2/net/StaticPacketBuilder.java | 385 ------- .../com/rs2/net/packets/PacketHandler.java | 9 +- .../java/com/rs2/net/packets/PacketType.java | 3 +- .../rs2/net/packets/impl/AttackPlayer.java | 13 +- .../java/com/rs2/net/packets/impl/Bank10.java | 9 +- .../java/com/rs2/net/packets/impl/Bank5.java | 9 +- .../com/rs2/net/packets/impl/BankAll.java | 9 +- .../java/com/rs2/net/packets/impl/BankX1.java | 13 +- .../rs2/net/packets/impl/ChallengePlayer.java | 7 +- .../net/packets/impl/ChangeAppearance.java | 9 +- .../rs2/net/packets/impl/ChangeRegions.java | 3 +- .../java/com/rs2/net/packets/impl/Chat.java | 15 +- .../com/rs2/net/packets/impl/ClickItem.java | 9 +- .../com/rs2/net/packets/impl/ClickNPC.java | 17 +- .../com/rs2/net/packets/impl/ClickObject.java | 29 +- .../com/rs2/net/packets/impl/ClickTab.java | 5 +- .../rs2/net/packets/impl/ClickingButtons.java | 5 +- .../rs2/net/packets/impl/ClickingInGame.java | 3 +- .../rs2/net/packets/impl/ClickingStuff.java | 3 +- .../com/rs2/net/packets/impl/Commands.java | 5 +- .../com/rs2/net/packets/impl/DropItem.java | 11 +- .../rs2/net/packets/impl/FollowPlayer.java | 5 +- .../com/rs2/net/packets/impl/IdleLogout.java | 3 +- .../com/rs2/net/packets/impl/InterfaceX.java | 5 +- .../com/rs2/net/packets/impl/ItemClick2.java | 5 +- .../packets/impl/ItemClick2OnGroundItem.java | 9 +- .../com/rs2/net/packets/impl/ItemClick3.java | 9 +- .../net/packets/impl/ItemOnGroundItem.java | 15 +- .../com/rs2/net/packets/impl/ItemOnItem.java | 7 +- .../com/rs2/net/packets/impl/ItemOnNpc.java | 9 +- .../rs2/net/packets/impl/ItemOnObject.java | 15 +- .../rs2/net/packets/impl/ItemOnPlayer.java | 7 +- .../net/packets/impl/MagicOnFloorItems.java | 11 +- .../rs2/net/packets/impl/MagicOnItems.java | 11 +- .../rs2/net/packets/impl/MagicOnObject.java | 11 +- .../com/rs2/net/packets/impl/MoveItems.java | 11 +- .../com/rs2/net/packets/impl/PickupItem.java | 9 +- .../net/packets/impl/PrivateMessaging.java | 27 +- .../com/rs2/net/packets/impl/RemoveItem.java | 9 +- .../java/com/rs2/net/packets/impl/Report.java | 5 +- .../rs2/net/packets/impl/ReportHandler.java | 9 +- .../rs2/net/packets/impl/SilentPacket.java | 3 +- .../java/com/rs2/net/packets/impl/Trade.java | 5 +- .../com/rs2/net/packets/impl/Walking.java | 29 +- .../com/rs2/net/packets/impl/WearItem.java | 9 +- .../java/com/rs2/util/ISAACRandomGen.java | 175 ---- .../src/main/java/com/rs2/util/Misc.java | 15 +- .../src/main/java/com/rs2/util/Stream.java | 150 +-- .../com/rs2/world/clip/ObjectDefinition.java | 4 +- .../com/rs2/world/clip/RegionFactory.java | 18 +- .../fs => cache}/FileDescriptor.java | 55 +- .../fs => cache}/FileSystemConstants.java | 38 +- .../apollo/{jagcached/fs => cache}/Index.java | 57 +- .../org/apollo/cache/IndexedFileSystem.java | 332 ++++++ .../apollo/{ => cache}/archive/Archive.java | 50 +- .../{ => cache}/archive/ArchiveEntry.java | 2 +- .../apollo/cache/archive/package-info.java | 4 + .../cache/decoder/ItemDefinitionDecoder.java | 130 +++ .../cache/decoder/NpcDefinitionDecoder.java | 149 +++ .../decoder/ObjectDefinitionDecoder.java | 142 +++ .../apollo/cache/decoder/package-info.java | 4 + .../apollo/cache/def/EquipmentDefinition.java | 310 ++++++ .../org/apollo/cache/def/ItemDefinition.java | 411 ++++++++ .../org/apollo/cache/def/NpcDefinition.java | 365 +++++++ .../apollo/cache/def/ObjectDefinition.java | 293 ++++++ .../org/apollo/cache/def/package-info.java | 4 + .../org/apollo/cache/map/MapConstants.java | 62 ++ .../java/org/apollo/cache/map/MapFile.java | 48 + .../org/apollo/cache/map/MapFileDecoder.java | 123 +++ .../java/org/apollo/cache/map/MapIndex.java | 125 +++ .../org/apollo/cache/map/MapIndexDecoder.java | 70 ++ .../java/org/apollo/cache/map/MapObject.java | 119 +++ .../apollo/cache/map/MapObjectsDecoder.java | 83 ++ .../java/org/apollo/cache/map/MapPlane.java | 90 ++ .../main/java/org/apollo/cache/map/Tile.java | 295 ++++++ .../java/org/apollo/cache/map/TileUtils.java | 161 +++ .../java/org/apollo/cache/package-info.java | 4 + .../apollo/cache/tools/EquipmentUpdater.java | 964 ++++++++++++++++++ .../org/apollo/cache/tools/package-info.java | 4 + .../apollo/game/session/ApolloHandler.java | 106 ++ .../org/apollo/game/session/GameSession.java | 66 ++ .../org/apollo/game/session/LoginSession.java | 171 ++++ .../java/org/apollo/game/session/Session.java | 49 + .../apollo/game/session/UpdateSession.java | 48 + .../org/apollo/game/session/package-info.java | 6 + .../java/org/apollo/jagcached/FileServer.java | 187 ++-- .../{dispatch => }/RequestWorkerPool.java | 31 +- .../jagcached/dispatch/HttpRequestWorker.java | 139 --- .../dispatch/JagGrabRequestWorker.java | 46 - .../dispatch/OnDemandRequestWorker.java | 61 -- .../jagcached/dispatch/RequestDispatcher.java | 112 -- .../jagcached/fs/IndexedFileSystem.java | 361 ------- .../jagcached/net/FileServerHandler.java | 63 -- .../jagcached/net/HttpPipelineFactory.java | 61 -- .../jagcached/net/JagGrabPipelineFactory.java | 86 -- .../jagcached/net/NetworkConstants.java | 37 - .../net/OnDemandPipelineFactory.java | 59 -- .../net/jaggrab/JagGrabRequestDecoder.java | 27 - .../net/jaggrab/JagGrabResponseEncoder.java | 22 - .../net/ondemand/OnDemandRequest.java | 109 -- .../net/ondemand/OnDemandRequestDecoder.java | 32 - .../net/ondemand/OnDemandResponseEncoder.java | 39 - .../jagcached/net/service/ServiceRequest.java | 40 - .../net/service/ServiceRequestDecoder.java | 39 - .../net/service/ServiceResponse.java | 9 - .../net/service/ServiceResponseEncoder.java | 25 - .../resource/HypertextResourceProvider.java | 64 -- .../jagcached/resource/ResourceProvider.java | 30 - .../resource/VirtualResourceProvider.java | 70 -- .../apollo/net/HttpChannelInitializer.java | 51 + .../apollo/net/JagGrabChannelInitializer.java | 77 ++ .../java/org/apollo/net/NetworkConstants.java | 81 ++ .../apollo/net/ServiceChannelInitializer.java | 40 + .../codec/handshake/HandshakeConstants.java | 27 + .../net/codec/handshake/HandshakeDecoder.java | 60 ++ .../net/codec/handshake/HandshakeMessage.java | 33 + .../net/codec/handshake/package-info.java | 4 + .../codec}/jaggrab/JagGrabRequest.java | 11 +- .../codec/jaggrab/JagGrabRequestDecoder.java | 25 + .../codec}/jaggrab/JagGrabResponse.java | 23 +- .../codec/jaggrab/JagGrabResponseEncoder.java | 20 + .../net/codec/jaggrab/package-info.java | 4 + .../net/codec/login/LoginConstants.java | 127 +++ .../apollo/net/codec/login/LoginDecoder.java | 232 +++++ .../net/codec/login/LoginDecoderState.java | 28 + .../apollo/net/codec/login/LoginEncoder.java | 31 + .../apollo/net/codec/login/LoginRequest.java | 132 +++ .../apollo/net/codec/login/LoginResponse.java | 65 ++ .../apollo/net/codec/login/package-info.java | 4 + .../net/codec/update/OnDemandRequest.java | 134 +++ .../codec/update}/OnDemandResponse.java | 80 +- .../net/codec/update/UpdateDecoder.java | 31 + .../net/codec/update/UpdateEncoder.java | 35 + .../apollo/net/codec/update/package-info.java | 4 + .../java/org/apollo/net/package-info.java | 5 + .../update}/ChannelRequest.java | 36 +- .../net/update/ComparableChannelRequest.java | 29 + .../apollo/net/update/HttpRequestWorker.java | 148 +++ .../net/update/JagGrabRequestWorker.java | 52 + .../net/update/OnDemandRequestWorker.java | 55 + .../update}/RequestWorker.java | 73 +- .../apollo/net/update/UpdateConstants.java | 17 + .../apollo/net/update/UpdateDispatcher.java | 109 ++ .../org/apollo/net/update/package-info.java | 4 + .../resource/CombinedResourceProvider.java | 19 +- .../resource/HypertextResourceProvider.java | 67 ++ .../net/update/resource/ResourceProvider.java | 33 + .../resource/VirtualResourceProvider.java | 71 ++ .../net/update/resource/package-info.java | 4 + .../main/java/org/apollo/util/BufferUtil.java | 80 ++ .../java/org/apollo/util/CollectionUtil.java | 40 + .../{archive => util}/CompressionUtil.java | 75 +- .../java/org/apollo/util/LanguageUtil.java | 50 + .../main/java/org/apollo/util/NameUtil.java | 96 ++ .../src/main/java/org/apollo/util/Point.java | 49 + .../org/apollo/util/StatefulFrameDecoder.java | 67 ++ .../main/java/org/apollo/util/StreamUtil.java | 54 + .../main/java/org/apollo/util/TextUtil.java | 148 +++ .../main/java/org/apollo/util/ThreadUtil.java | 88 ++ .../java/org/apollo/util/package-info.java | 4 + .../org/apollo/util/security/IsaacRandom.java | 287 ++++++ .../apollo/util/security/IsaacRandomPair.java | 51 + .../util/security/PlayerCredentials.java | 138 +++ .../apollo/util/security/package-info.java | 4 + .../apollo/util/tools/EquipmentConstants.java | 102 ++ .../apollo/util/tools/RsaKeyGenerator.java | 48 + .../org/apollo/util/tools/package-info.java | 4 + .../java/org/apollo/util/xml/XmlNode.java | 247 +++++ .../java/org/apollo/util/xml/XmlParser.java | 155 +++ .../org/apollo/util/xml/package-info.java | 4 + 193 files changed, 9830 insertions(+), 4090 deletions(-) create mode 100644 2006Scape Server/data/net.xml delete mode 100644 2006Scape Server/src/main/java/com/rs2/net/CodecFactory.java delete mode 100644 2006Scape Server/src/main/java/com/rs2/net/ConnectionThrottleFilter.java delete mode 100644 2006Scape Server/src/main/java/com/rs2/net/GameCodecFactory.java create mode 100644 2006Scape Server/src/main/java/com/rs2/net/GameDecoderState.java delete mode 100644 2006Scape Server/src/main/java/com/rs2/net/PacketBuffer.java delete mode 100644 2006Scape Server/src/main/java/com/rs2/net/PacketBuilder.java delete mode 100644 2006Scape Server/src/main/java/com/rs2/net/RS2LoginProtocolDecoder.java delete mode 100644 2006Scape Server/src/main/java/com/rs2/net/StaticPacketBuilder.java delete mode 100644 2006Scape Server/src/main/java/com/rs2/util/ISAACRandomGen.java rename 2006Scape Server/src/main/java/org/apollo/{jagcached/fs => cache}/FileDescriptor.java (61%) rename 2006Scape Server/src/main/java/org/apollo/{jagcached/fs => cache}/FileSystemConstants.java (83%) rename 2006Scape Server/src/main/java/org/apollo/{jagcached/fs => cache}/Index.java (67%) create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/IndexedFileSystem.java rename 2006Scape Server/src/main/java/org/apollo/{ => cache}/archive/Archive.java (60%) rename 2006Scape Server/src/main/java/org/apollo/{ => cache}/archive/ArchiveEntry.java (96%) create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/archive/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/decoder/ItemDefinitionDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/decoder/NpcDefinitionDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/decoder/ObjectDefinitionDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/decoder/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/def/EquipmentDefinition.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/def/ItemDefinition.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/def/NpcDefinition.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/def/ObjectDefinition.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/def/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapConstants.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapFile.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapFileDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapIndex.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapIndexDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapObject.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/MapPlane.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/Tile.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/map/TileUtils.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java create mode 100644 2006Scape Server/src/main/java/org/apollo/cache/tools/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/game/session/ApolloHandler.java create mode 100644 2006Scape Server/src/main/java/org/apollo/game/session/GameSession.java create mode 100644 2006Scape Server/src/main/java/org/apollo/game/session/LoginSession.java create mode 100644 2006Scape Server/src/main/java/org/apollo/game/session/Session.java create mode 100644 2006Scape Server/src/main/java/org/apollo/game/session/UpdateSession.java create mode 100644 2006Scape Server/src/main/java/org/apollo/game/session/package-info.java rename 2006Scape Server/src/main/java/org/apollo/jagcached/{dispatch => }/RequestWorkerPool.java (60%) delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/HttpRequestWorker.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/JagGrabRequestWorker.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/OnDemandRequestWorker.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestDispatcher.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/fs/IndexedFileSystem.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/FileServerHandler.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/HttpPipelineFactory.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/JagGrabPipelineFactory.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/NetworkConstants.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/OnDemandPipelineFactory.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequestDecoder.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponseEncoder.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequest.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequestDecoder.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponseEncoder.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequest.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequestDecoder.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponse.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponseEncoder.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/resource/HypertextResourceProvider.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/resource/ResourceProvider.java delete mode 100644 2006Scape Server/src/main/java/org/apollo/jagcached/resource/VirtualResourceProvider.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/HttpChannelInitializer.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/JagGrabChannelInitializer.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/NetworkConstants.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/ServiceChannelInitializer.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeMessage.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/handshake/package-info.java rename 2006Scape Server/src/main/java/org/apollo/{jagcached/net => net/codec}/jaggrab/JagGrabRequest.java (89%) create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java rename 2006Scape Server/src/main/java/org/apollo/{jagcached/net => net/codec}/jaggrab/JagGrabResponse.java (51%) create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginConstants.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoderState.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginEncoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginRequest.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginResponse.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/login/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/update/OnDemandRequest.java rename 2006Scape Server/src/main/java/org/apollo/{jagcached/net/ondemand => net/codec/update}/OnDemandResponse.java (80%) create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateEncoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/codec/update/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/package-info.java rename 2006Scape Server/src/main/java/org/apollo/{jagcached/dispatch => net/update}/ChannelRequest.java (57%) create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/ComparableChannelRequest.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/HttpRequestWorker.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/JagGrabRequestWorker.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/OnDemandRequestWorker.java rename 2006Scape Server/src/main/java/org/apollo/{jagcached/dispatch => net/update}/RequestWorker.java (68%) create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/UpdateConstants.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/UpdateDispatcher.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/package-info.java rename 2006Scape Server/src/main/java/org/apollo/{jagcached => net/update}/resource/CombinedResourceProvider.java (71%) create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/resource/HypertextResourceProvider.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/resource/ResourceProvider.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/resource/VirtualResourceProvider.java create mode 100644 2006Scape Server/src/main/java/org/apollo/net/update/resource/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/BufferUtil.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/CollectionUtil.java rename 2006Scape Server/src/main/java/org/apollo/{archive => util}/CompressionUtil.java (59%) create mode 100644 2006Scape Server/src/main/java/org/apollo/util/LanguageUtil.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/NameUtil.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/Point.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/StatefulFrameDecoder.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/StreamUtil.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/TextUtil.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/ThreadUtil.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandom.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandomPair.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/security/PlayerCredentials.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/security/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/tools/EquipmentConstants.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/tools/RsaKeyGenerator.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/tools/package-info.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/xml/XmlNode.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/xml/XmlParser.java create mode 100644 2006Scape Server/src/main/java/org/apollo/util/xml/package-info.java diff --git a/2006Scape Client/src/main/java/ClientSettings.java b/2006Scape Client/src/main/java/ClientSettings.java index a7001823..b033a1ef 100644 --- a/2006Scape Client/src/main/java/ClientSettings.java +++ b/2006Scape Client/src/main/java/ClientSettings.java @@ -30,6 +30,13 @@ public class ClientSettings { */ public static int SERVER_WORLD = 1; + /** + * If false, the server will run the on demand server on every world. If true it will + * only connect to the server on world 1. + */ + public static boolean SINGLE_ONDEMAND = true; + + /** * Enables/Disables FileServer CRC Checking For Cache Updates * FileServer Must Be Running Before Starting The Client If This Is True diff --git a/2006Scape Client/src/main/java/OnDemandFetcher.java b/2006Scape Client/src/main/java/OnDemandFetcher.java index ef52b982..bccd85e0 100644 --- a/2006Scape Client/src/main/java/OnDemandFetcher.java +++ b/2006Scape Client/src/main/java/OnDemandFetcher.java @@ -235,7 +235,7 @@ public final class OnDemandFetcher extends OnDemandFetcherParent implements Runn return; } openSocketTime = l; - socket = clientInstance.openSocket(43596 + Game.portOff); + socket = clientInstance.openSocket((ClientSettings.SINGLE_ONDEMAND || ClientSettings.SERVER_WORLD == 1) ? 43594 : 43596 + ClientSettings.SERVER_WORLD + Game.portOff); inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); outputStream.write(15); diff --git a/2006Scape Server/data/net.xml b/2006Scape Server/data/net.xml new file mode 100644 index 00000000..b81b2a2f --- /dev/null +++ b/2006Scape Server/data/net.xml @@ -0,0 +1,12 @@ + + + 91553247461173033466542043374346300088148707506479543786501537350363031301992107112953015516557748875487935404852620239974482067336878286174236183516364787082711186740254168914127361643305190640280157664988536979163450791820893999053469529344247707567448479470137716627440246788713008490213212272520901741443 + 33280025241734061313051117678670856264399753710527826596057587687835856000539511539311834363046145710983857746766009612538140077973762171163294453513440619295457626227183742315140865830778841533445402605660729039310637444146319289077374748018792349647460850308384280105990607337322160553135806205784213241305 + + + + 8080 + 43594 + 43595 + + \ No newline at end of file diff --git a/2006Scape Server/pom.xml b/2006Scape Server/pom.xml index 9784cc6e..0c74a85d 100644 --- a/2006Scape Server/pom.xml +++ b/2006Scape Server/pom.xml @@ -32,7 +32,7 @@ org.apache.commons commons-compress - 1.0 + 1.21 @@ -70,12 +70,6 @@ logging-interceptor 4.3.1 - - - org.apache.mina - mina-core - 1.1.7 - mysql @@ -86,7 +80,7 @@ io.netty netty-all - 4.1.44.Final + 4.0.34.Final @@ -161,16 +155,11 @@ system ${project.basedir}/libs/everythingrs-api.jar + - com.google.collections - google-collections - 1.0 - - - io.netty - netty - 3.6.6.Final - compile + com.google.guava + guava + 19.0 diff --git a/2006Scape Server/src/main/java/com/rs2/GameEngine.java b/2006Scape Server/src/main/java/com/rs2/GameEngine.java index fc2bcaea..9d9b0fa8 100644 --- a/2006Scape Server/src/main/java/com/rs2/GameEngine.java +++ b/2006Scape Server/src/main/java/com/rs2/GameEngine.java @@ -13,10 +13,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.apollo.jagcached.FileServer; + import com.rs2.game.bots.BotHandler; -import org.apache.mina.common.IoAcceptor; -import org.apache.mina.transport.socket.nio.SocketAcceptor; -import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; +import com.google.common.base.Stopwatch; import com.rs2.event.CycleEventHandler; import com.rs2.game.content.minigames.FightCaves; import com.rs2.game.content.minigames.FightPits; @@ -37,8 +37,6 @@ import com.rs2.integrations.PlayersOnlineWebsite; import com.rs2.integrations.RegisteredAccsWebsite; import com.rs2.integrations.discord.DiscordActivity; import com.rs2.integrations.discord.JavaCord; -import com.rs2.net.ConnectionHandler; -import com.rs2.net.ConnectionThrottleFilter; import com.rs2.tick.Scheduler; import com.rs2.tick.Tick; import com.rs2.util.HostBlacklist; @@ -48,7 +46,9 @@ import com.rs2.world.ObjectHandler; import com.rs2.world.ObjectManager; import com.rs2.world.clip.ObjectDefinition; import com.rs2.world.clip.RegionFactory; -import org.apollo.jagcached.FileServer; + +import io.netty.util.ResourceLeakDetector; +import io.netty.util.ResourceLeakDetector.Level; /** * Server.java @@ -111,13 +111,9 @@ public class GameEngine { public static boolean sleeping; public static boolean updateServer = false; public static long lastMassSave = System.currentTimeMillis(); - private static IoAcceptor acceptor; - private static ConnectionHandler connectionHandler; - private static ConnectionThrottleFilter throttleFilter; public static boolean shutdownServer = false; public static int garbageCollectDelay = 40; public static boolean shutdownClientHandler; - private static int serverlistenerPort; public static ItemHandler itemHandler = new ItemHandler(); public static PlayerHandler playerHandler = new PlayerHandler(); public static NpcHandler npcHandler = new NpcHandler(); @@ -152,7 +148,6 @@ public class GameEngine { } } } - serverlistenerPort = (GameConstants.WORLD == 1) ? 43594 : 43596 + GameConstants.WORLD; System.out.println("Starting game engine.."); if (GameConstants.SERVER_DEBUG) { @@ -177,18 +172,6 @@ public class GameEngine { */ System.out.println("Launching " + GameConstants.SERVER_NAME + " World: " + GameConstants.WORLD + "..."); - /** - * Starts The File Server If Enabled In GameConstants - */ - if (GameConstants.FILE_SERVER) { - FileServer fs = new FileServer(); - try { - fs.start(); - } catch (Exception e) { - e.printStackTrace(); - } - } - /** * Start Integration Services **/ @@ -198,17 +181,15 @@ public class GameEngine { /** * Accepting Connections */ - acceptor = new SocketAcceptor(); - connectionHandler = new ConnectionHandler(); - - SocketAcceptorConfig sac = new SocketAcceptorConfig(); - sac.getSessionConfig().setTcpNoDelay(false); - sac.setReuseAddress(true); - sac.setBacklog(100); - - throttleFilter = new ConnectionThrottleFilter(GameConstants.CONNECTION_DELAY); - sac.getFilterChain().addFirst("throttleFilter", throttleFilter); - acceptor.bind(new InetSocketAddress(serverlistenerPort), connectionHandler, sac); + //TODO debug ResourceLeakDetector.setLevel(Level.PARANOID); + ResourceLeakDetector.setLevel(Level.DISABLED); + FileServer fs = new FileServer(); + try { + fs.start(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } /** * Initialise Handlers @@ -232,7 +213,7 @@ public class GameEngine { /** * Server Successfully Loaded */ - System.out.println("Server listening on port " + serverlistenerPort); + System.out.println("World Server listening on " + fs.service.toString()); /** * Main Server Tick @@ -245,6 +226,7 @@ public class GameEngine { */ scheduler.scheduleAtFixedRate(new Runnable() { public void run() { + //TODO debug Stopwatch stopwatch = Stopwatch.createStarted(); /** * Main Server Tick */ @@ -298,6 +280,7 @@ public class GameEngine { } scheduler.shutdown(); // Kills the tickloop thread if Exception is thrown. } + //TODO debug System.out.println("Cycle took " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms."); } }, 0, GameConstants.CYCLE_TIME, TimeUnit.MILLISECONDS); @@ -316,9 +299,6 @@ public class GameEngine { e.printStackTrace(); } - acceptor = null; - connectionHandler = null; - sac = null; System.exit(0); } diff --git a/2006Scape Server/src/main/java/com/rs2/game/bots/Bot.java b/2006Scape Server/src/main/java/com/rs2/game/bots/Bot.java index b0854eed..a884866c 100644 --- a/2006Scape Server/src/main/java/com/rs2/game/bots/Bot.java +++ b/2006Scape Server/src/main/java/com/rs2/game/bots/Bot.java @@ -5,19 +5,23 @@ import static com.rs2.game.players.PlayerSave.loadPlayerInfo; import java.text.DecimalFormat; import java.util.*; +import com.rs2.GameConstants; import com.rs2.GameEngine; import com.rs2.game.items.ItemAssistant; import com.rs2.game.players.Client; import com.rs2.util.Misc; +import com.rs2.util.Stream; public class Bot { private Client botClient; static Timer timer = new Timer(); - + private Stream inStream; + public Bot(String username, Integer x, Integer y, Integer z) { botClient = new Client(null); - + inStream = new Stream(new byte[GameConstants.BUFFER_SIZE]); + inStream.currentOffset = 0; botClient.playerName = username; botClient.playerName2 = botClient.playerName; botClient.properName = Character.toUpperCase(username.charAt(1)) + username.substring(2); @@ -78,10 +82,10 @@ public class Bot { // Normal chat from here down: botClient.setChatTextColor(Misc.random(11)); botClient.setChatTextEffects(Misc.random(5)); - Misc.textPack(botClient.inStream, _message); - botClient.setChatTextSize((byte) botClient.inStream.currentOffset); - botClient.setChatText(botClient.inStream.buffer); - botClient.inStream.currentOffset = 0; + Misc.textPack(inStream, _message); + botClient.setChatTextSize((byte) inStream.currentOffset); + botClient.setChatText(inStream.buffer); + inStream.currentOffset = 0; botClient.setChatTextUpdateRequired(true); } diff --git a/2006Scape Server/src/main/java/com/rs2/game/dialogues/Dialogue.java b/2006Scape Server/src/main/java/com/rs2/game/dialogues/Dialogue.java index 0ac640cb..2e02e0fb 100644 --- a/2006Scape Server/src/main/java/com/rs2/game/dialogues/Dialogue.java +++ b/2006Scape Server/src/main/java/com/rs2/game/dialogues/Dialogue.java @@ -1,6 +1,7 @@ package com.rs2.game.dialogues; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -10,7 +11,7 @@ import com.rs2.net.packets.PacketType; public class Dialogue implements PacketType { @Override - public void processPacket(Player c, int packetType, int packetSize) { + public void processPacket(Player c, Packet packet) { if (c.nextChat > 0) { c.getDialogueHandler().sendDialogues(c.nextChat, c.talkingNpc); } else { diff --git a/2006Scape Server/src/main/java/com/rs2/game/players/Client.java b/2006Scape Server/src/main/java/com/rs2/game/players/Client.java index f9b18739..0b5f08d1 100644 --- a/2006Scape Server/src/main/java/com/rs2/game/players/Client.java +++ b/2006Scape Server/src/main/java/com/rs2/game/players/Client.java @@ -1,30 +1,32 @@ package com.rs2.game.players; -import org.apache.mina.common.IoSession; +import org.apollo.game.session.GameSession; import com.rs2.GameConstants; import com.rs2.util.Stream; +import io.netty.channel.Channel; + public class Client extends Player { - public Client(IoSession s, int _playerId) { + public Client(GameSession s, int _playerId) { super(_playerId); session = s; outStream = new Stream(new byte[GameConstants.BUFFER_SIZE]); outStream.currentOffset = 0; - inStream = new Stream(new byte[GameConstants.BUFFER_SIZE]); - inStream.currentOffset = 0; buffer = new byte[GameConstants.BUFFER_SIZE]; } //bots - public Client(IoSession s) { + public Client(GameSession s) { super(-1); isBot = true; session = null; - inStream = new Stream(new byte[GameConstants.BUFFER_SIZE]); - inStream.currentOffset = 0; buffer = new byte[GameConstants.BUFFER_SIZE]; } + public void setSession(GameSession session) { + this.session = session; + } + } diff --git a/2006Scape Server/src/main/java/com/rs2/game/players/Player.java b/2006Scape Server/src/main/java/com/rs2/game/players/Player.java index 0c3cad6f..9f98f8c2 100644 --- a/2006Scape Server/src/main/java/com/rs2/game/players/Player.java +++ b/2006Scape Server/src/main/java/com/rs2/game/players/Player.java @@ -51,21 +51,26 @@ import com.rs2.game.npcs.NpcHandler; import com.rs2.game.npcs.impl.Pets; import com.rs2.game.objects.ObjectsActions; import com.rs2.game.shops.ShopAssistant; -import com.rs2.net.HostList; import com.rs2.net.Packet; +import com.rs2.net.Packet.Type; import com.rs2.net.PacketSender; -import com.rs2.net.StaticPacketBuilder; import com.rs2.net.packets.PacketHandler; import com.rs2.net.packets.impl.ChallengePlayer; import com.rs2.plugin.PluginService; -import com.rs2.util.ISAACRandomGen; import com.rs2.util.Misc; import com.rs2.util.Stream; import com.rs2.world.Boundary; import com.rs2.world.ObjectManager; -import org.apache.mina.common.IoSession; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import java.util.*; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +import org.apollo.game.session.GameSession; +import org.apollo.util.security.IsaacRandom; public abstract class Player { @@ -85,8 +90,8 @@ public abstract class Player { private SpecialPlantOne specialPlantOne = new SpecialPlantOne(this); private SpecialPlantTwo specialPlantTwo = new SpecialPlantTwo(this); private ToolLeprechaun toolLeprechaun = new ToolLeprechaun(this); - public Stream inStream = null, outStream = null; - public IoSession session; + public Stream outStream = null; + public GameSession session; private final ItemAssistant itemAssistant = new ItemAssistant(this); private final ShopAssistant shopAssistant = new ShopAssistant(this); private final MageTrainingArena mageArena = new MageTrainingArena(this); @@ -96,7 +101,7 @@ public abstract class Player { private final CombatAssistant combatAssistant = new CombatAssistant(this); private final ObjectsActions actionHandler = new ObjectsActions(this); private final NpcActions npcs = new NpcActions(this); - private final Queue queuedPackets = new LinkedList(); + private final BlockingQueue queuedPackets = new ArrayBlockingQueue(25); private final Potions potions = new Potions(this); private final PotionMixing potionMixing = new PotionMixing(this); private final EmoteHandler emoteHandler = new EmoteHandler(this); @@ -356,18 +361,6 @@ public abstract class Player { return bankPin; } - public synchronized Stream getInStream() { - return inStream; - } - - public synchronized int getPacketType() { - return packetType; - } - - public synchronized int getPacketSize() { - return packetSize; - } - public synchronized Stream getOutStream() { return outStream; } @@ -412,7 +405,7 @@ public abstract class Player { return npcs; } - public IoSession getSession() { + public GameSession getSession() { return session; } @@ -534,17 +527,21 @@ public abstract class Player { } public void flushOutStream() { - if (disconnected || outStream == null || outStream.currentOffset == 0) { + if (!session.isActive() || disconnected || outStream == null || outStream.currentOffset == 0) { return; } - synchronized (this) { - StaticPacketBuilder out = new StaticPacketBuilder().setBare(true); byte[] temp = new byte[outStream.currentOffset]; System.arraycopy(outStream.buffer, 0, temp, 0, temp.length); - out.addBytes(temp); - session.write(out.toPacket()); + + // Packet packet = new Packet(-1, Type.FIXED, Unpooled.wrappedBuffer(temp)); + // session.write(packet); + session.write(Unpooled.buffer().writeBytes(temp)); outStream.currentOffset = 0; - } + + + // ByteBuf buffer = Unpooled.buffer(); + // buffer.writeBytes(temp); + } public void sendClan(String name, String message, String clan, int rights) { @@ -558,34 +555,6 @@ public abstract class Player { } } - public static final int PACKET_SIZES[] = { 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, // 0 - 0, 0, 0, 0, 8, 0, 6, 2, 2, 0, // 10 - 0, 2, 0, 6, 0, 12, 0, 0, 0, 0, // 20 - 0, 0, 0, 0, 0, 8, 4, 0, 0, 2, // 30 - 2, 6, 0, 6, 0, -1, 0, 0, 0, 0, // 40 - 0, 0, 0, 12, 0, 0, 0, 8, 8, 12, // 50 - 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, // 60 - 6, 0, 2, 2, 8, 6, 0, -1, 0, 6, // 70 - 0, 0, 0, 0, 0, 1, 4, 6, 0, 0, // 80 - 0, 0, 0, 0, 0, 3, 0, 0, -1, 0, // 90 - 0, 13, 0, -1, 0, 0, 0, 0, 0, 0,// 100 - 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, // 110 - 1, 0, 6, 0, 0, 0, -1, 0, 2, 6, // 120 - 0, 4, 6, 8, 0, 6, 0, 0, 0, 2, // 130 - 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, // 140 - 0, 0, 1, 2, 0, 2, 6, 0, 0, 0, // 150 - 0, 0, 0, 0, -1, -1, 0, 0, 0, 0,// 160 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170 - 0, 8, 0, 3, 0, 2, 0, 0, 8, 1, // 180 - 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, // 190 - 2, 0, 0, 0, 0, 0, 0, 0, 4, 0, // 200 - 4, 0, 0, 0, 7, 8, 0, 0, 10, 0, // 210 - 0, 0, 0, 0, 0, 0, -1, 0, 6, 0, // 220 - 1, 0, 0, 0, 6, 0, 6, 8, 1, 0, // 230 - 0, 4, 0, 0, 0, 0, -1, 0, -1, 4,// 240 - 0, 0, 6, 6, 0, 0, 0 // 250 - }; - public void destruct() { if (session == null) { return; @@ -636,12 +605,11 @@ public abstract class Player { } Misc.println("[DEREGISTERED]: " + playerName + ""); - HostList.getHostList().remove(session); + // HostList.getHostList().remove(session); CycleEventHandler.getSingleton().stopEvents(this); disconnected = true; session.close(); session = null; - inStream = null; outStream = null; isActive = false; buffer = null; @@ -787,7 +755,6 @@ public abstract class Player { return eventProvider; } - public int packetSize = 0, packetType = -1; public boolean wildernessWarning; public int axeAnimation = -1; @@ -1099,42 +1066,18 @@ public abstract class Player { } public void queueMessage(Packet arg1) { - queuedPackets.add(arg1); + if (queuedPackets.size() < 25) { + queuedPackets.add(arg1); + } } - public synchronized boolean processQueuedPackets() { - Packet p = null; - synchronized (queuedPackets) { - p = queuedPackets.poll(); - } - if (p == null) { - return false; - } - inStream.currentOffset = 0; - packetType = p.getId(); - packetSize = p.getLength(); - inStream.buffer = p.getData(); - if (packetType > 0) { - PacketHandler.processPacket(this, packetType, packetSize); - } - timeOutCounter = 0; - return true; - } - - public synchronized boolean processPacket(Packet p) { - synchronized (this) { - if (p == null) { - return false; - } - inStream.currentOffset = 0; - packetType = p.getId(); - packetSize = p.getLength(); - inStream.buffer = p.getData(); - if (packetType > 0) { - PacketHandler.processPacket(this, packetType, packetSize); + public void processQueuedPackets() { + while (!queuedPackets.isEmpty()) { + Packet p = queuedPackets.poll(); + if (p.getOpcode() > 0) { + PacketHandler.processPacket(this, p); } timeOutCounter = 0; - return true; } } @@ -3140,11 +3083,11 @@ public abstract class Player { return newWalkCmdIsRunning; } - public void setInStreamDecryption(ISAACRandomGen inStreamDecryption) { + public void setInStreamDecryption(IsaacRandom inStreamDecryption) { } - public void setOutStreamDecryption(ISAACRandomGen outStreamDecryption) { + public void setOutStreamDecryption(IsaacRandom outStreamDecryption) { } diff --git a/2006Scape Server/src/main/java/com/rs2/game/players/PlayerHandler.java b/2006Scape Server/src/main/java/com/rs2/game/players/PlayerHandler.java index d9bc69d3..470650fe 100644 --- a/2006Scape Server/src/main/java/com/rs2/game/players/PlayerHandler.java +++ b/2006Scape Server/src/main/java/com/rs2/game/players/PlayerHandler.java @@ -110,7 +110,6 @@ public class PlayerHandler { } public void process() { - // synchronized (PlayerHandler.players) { updatePlayerNames(); if (kickAllPlayers) { for (int i = 0; i < PlayerHandler.players.length; i++) { @@ -182,9 +181,7 @@ public class PlayerHandler { } - while (players[i].processQueuedPackets()) { - ; - } + players[i].processQueuedPackets(); players[i].process(); players[i].postProcessing(); diff --git a/2006Scape Server/src/main/java/com/rs2/net/CodecFactory.java b/2006Scape Server/src/main/java/com/rs2/net/CodecFactory.java deleted file mode 100644 index 51dd49e0..00000000 --- a/2006Scape Server/src/main/java/com/rs2/net/CodecFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.rs2.net; - -import org.apache.mina.filter.codec.ProtocolCodecFactory; -import org.apache.mina.filter.codec.ProtocolDecoder; -import org.apache.mina.filter.codec.ProtocolEncoder; - -/** - * Provides access to the encoders and decoders for the 508 protocol. - * - * @author Graham - */ -public class CodecFactory implements ProtocolCodecFactory { - - /** - * The encoder. - */ - private final ProtocolEncoder encoder = new RS2ProtocolEncoder(); - - /** - * The decoder. - */ - private final ProtocolDecoder decoder = new RS2LoginProtocolDecoder(); - - @Override - /** - * Get the encoder. - */ - public ProtocolEncoder getEncoder() throws Exception { - return encoder; - } - - @Override - /** - * Get the decoder. - */ - public ProtocolDecoder getDecoder() throws Exception { - return decoder; - } - -} diff --git a/2006Scape Server/src/main/java/com/rs2/net/ConnectionHandler.java b/2006Scape Server/src/main/java/com/rs2/net/ConnectionHandler.java index 267fb472..b145c17f 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/ConnectionHandler.java +++ b/2006Scape Server/src/main/java/com/rs2/net/ConnectionHandler.java @@ -1,63 +1,76 @@ package com.rs2.net; -import org.apache.mina.common.IdleStatus; -import org.apache.mina.common.IoHandler; -import org.apache.mina.common.IoSession; -import org.apache.mina.filter.codec.ProtocolCodecFilter; - -import com.rs2.game.players.Client; - -public class ConnectionHandler implements IoHandler { - - @Override - public void exceptionCaught(IoSession arg0, Throwable arg1) - throws Exception { - // TODO Auto-generated method stub - - } - - @Override - public void messageReceived(IoSession arg0, Object arg1) throws Exception { - if (arg0.getAttachment() != null) { - Client plr = (Client) arg0.getAttachment(); - plr.queueMessage((Packet) arg1); - } - } - - @Override - public void messageSent(IoSession arg0, Object arg1) throws Exception { - // TODO Auto-generated method stub - - } - - @Override - public void sessionClosed(IoSession arg0) throws Exception { - if (arg0.getAttachment() != null) { - Client plr = (Client) arg0.getAttachment(); - plr.disconnected = true; - } - HostList.getHostList().remove(arg0); - } - - @Override - public void sessionCreated(IoSession arg0) throws Exception { - if (!HostList.getHostList().add(arg0)) { - arg0.close(); - } else { - arg0.setAttribute("inList", Boolean.TRUE); - } - } - - @Override - public void sessionIdle(IoSession arg0, IdleStatus arg1) throws Exception { - arg0.close(); - } - - @Override - public void sessionOpened(IoSession arg0) throws Exception { - arg0.setIdleTime(IdleStatus.BOTH_IDLE, 60); - arg0.getFilterChain().addLast("protocolFilter", - new ProtocolCodecFilter(new CodecFactory())); - } +import io.netty.channel.ChannelInboundHandlerAdapter; +/** + * Old class that was used with netty 4 impl. This is no longer needed but will be a reference for re-adding the HostList stuff into the ApolloHandler. + * @author Advocatus + * + */ +public class ConnectionHandler extends ChannelInboundHandlerAdapter { + +//// public static final AttributeKey SESSION_KEY = AttributeKey.valueOf("session"); +// +// private Session session = null; +// +//// @Override +//// public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { +//// if (session == null) { +//// session = new Session(ctx.getChannel()); +//// if (!HostList.getHostList().add(session)) { +//// ctx.getChannel().close(); +//// } else { +//// session.setInList(true); +//// } +//// } +//// } +// +// +// @Override +// public void channelInactive(ChannelHandlerContext ctx) { +// if (session != null) { +// // HostList.getHostList().remove(session); +// Client client = session.getClient(); +// if (client != null) { +// client.disconnected = true; +// } +// session = null; +// } +// Channel channel = ctx.channel(); +// channel.close(); +// } +// +// @Override +// public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) { +// if (!e.getMessage().contains("An existing connection was forcibly closed by the remote host")) { +// e.printStackTrace(); +// // logger.log(Level.WARNING, "Exception occured for channel: " + ctx.channel() + ", closing...", e); +// } +// ctx.channel().close(); +// } +// +// @Override +// public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception { +//// System.out.println(message.getClass()); +// if (session == null) { +// session = new Session(ctx.channel()); +//// if (!HostList.getHostList().add(session)) { +//// ctx.channel().close(); +//// } else { +//// session.setInList(true); +//// } +// } +// if (message instanceof Client) { +// session.setClient((Client) message); +// } else if (message instanceof Packet) { +// if (session.getClient() != null) { +// session.getClient().queueMessage((Packet) message); +// } +// } +// } +// +// @Override +// public void channelReadComplete(ChannelHandlerContext ctx) { +// ctx.flush(); +// } } diff --git a/2006Scape Server/src/main/java/com/rs2/net/ConnectionThrottleFilter.java b/2006Scape Server/src/main/java/com/rs2/net/ConnectionThrottleFilter.java deleted file mode 100644 index 54a0e960..00000000 --- a/2006Scape Server/src/main/java/com/rs2/net/ConnectionThrottleFilter.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.rs2.net; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.mina.common.IoFilter; -import org.apache.mina.common.IoFilterAdapter; -import org.apache.mina.common.IoSession; - -/** - * A {@link IoFilter} which blocks connections from connecting at a rate faster - * than the specified interval. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - */ -public class ConnectionThrottleFilter extends IoFilterAdapter { - - private long allowedInterval; - private final Map clients; - private final Map counts; - private final Set connectedAddresses; - - /** - * Constructor that takes in a specified wait time. - * - * @param allowedInterval - * The number of milliseconds a client is allowed to wait before - * making another successful connection - */ - public ConnectionThrottleFilter(long allowedInterval) { - this.allowedInterval = allowedInterval; - clients = Collections.synchronizedMap(new HashMap()); - counts = Collections - .synchronizedMap(new HashMap()); - connectedAddresses = new HashSet(); - } - - /** - * Sets the interval between connections from a client. This value is - * measured in milliseconds. - * - * @param allowedInterval - * The number of milliseconds a client is allowed to wait before - * making another successful connection - */ - public void setAllowedInterval(long allowedInterval) { - this.allowedInterval = allowedInterval; - } - - public void delayClient(IoSession session, int delay) { - long d = System.currentTimeMillis() - delay; - clients.put(getAddress(session), d); - } - - private InetAddress getAddress(IoSession io) { - return ((InetSocketAddress) io.getRemoteAddress()).getAddress(); - } - - /** - * Method responsible for deciding if a connection is OK to continue - * - * @param session - * The new session that will be verified - * @return True if the session meets the criteria, otherwise false - */ - public boolean isConnectionOk(IoSession session) { - InetAddress addr = getAddress(session); - long now = System.currentTimeMillis(); - if (clients.containsKey(addr)) { - long lastConnTime = clients.get(addr); - - if (now - lastConnTime < allowedInterval) { - int c = 0; - if (!counts.containsKey(addr)) { - counts.put(addr, 0); - } else { - c = counts.get(addr) + 1; - } - if (c >= 350) { - - c = 0; - } - counts.put(addr, c); - // Logger.err("["+host+"] Session dropped (delay="+(now-lastConnTime)+"ms)"); - return false; - } else { - clients.put(addr, now); - return true; - } - } else { - clients.put(addr, now); - return true; - } - } - - public void closedSession(IoSession io) { - connectedAddresses.remove(getAddress(io)); - } - - public void acceptedLogin(IoSession io) { - connectedAddresses.add(getAddress(io)); - } - - public boolean isConnected(IoSession io) { - return connectedAddresses.contains(getAddress(io)); - } - - public int[] getSizes() { - return new int[] { clients.size(), counts.size(), - connectedAddresses.size() }; - } - - public void connectionOk(IoSession io) { - counts.remove(getAddress(io)); - } - - @Override - public void sessionCreated(NextFilter nextFilter, IoSession session) - throws Exception { - if (!isConnectionOk(session)) { - session.close(); - return; - } - nextFilter.sessionCreated(session); - } -} diff --git a/2006Scape Server/src/main/java/com/rs2/net/GameCodecFactory.java b/2006Scape Server/src/main/java/com/rs2/net/GameCodecFactory.java deleted file mode 100644 index c0c8475a..00000000 --- a/2006Scape Server/src/main/java/com/rs2/net/GameCodecFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.rs2.net; - -import org.apache.mina.filter.codec.ProtocolCodecFactory; -import org.apache.mina.filter.codec.ProtocolDecoder; -import org.apache.mina.filter.codec.ProtocolEncoder; - -import com.rs2.util.ISAACRandomGen; - -/** - * Provides access to the encoders and decoders for the 508 protocol. - * - * @author Graham - */ -public class GameCodecFactory implements ProtocolCodecFactory { - - /** - * The encoder. - */ - private final ProtocolEncoder encoder = new RS2ProtocolEncoder(); - - /** - * The decoder. - */ - private final ProtocolDecoder decoder; - - public GameCodecFactory(ISAACRandomGen inC) { - decoder = new RS2ProtocolDecoder(inC); - } - - @Override - /** - * Get the encoder. - */ - public ProtocolEncoder getEncoder() throws Exception { - return encoder; - } - - @Override - /** - * Get the decoder. - */ - public ProtocolDecoder getDecoder() throws Exception { - return decoder; - } - -} diff --git a/2006Scape Server/src/main/java/com/rs2/net/GameDecoderState.java b/2006Scape Server/src/main/java/com/rs2/net/GameDecoderState.java new file mode 100644 index 00000000..fe3f96fa --- /dev/null +++ b/2006Scape Server/src/main/java/com/rs2/net/GameDecoderState.java @@ -0,0 +1,28 @@ +package com.rs2.net; + +/** + * An enumeration with the different states the {@link GamePacketDecoder} can be in. + * + * @author Graham + */ +public enum GameDecoderState { + + /** + * The game length state waits for the packet length. Once it has been received, it sets the state to the payload + * state. + */ + GAME_LENGTH, + + /** + * The game opcode state waits for an encrypted opcode. It decrypts it, and will either set the next state to the + * length (if the packet is variably- sized) or the payload (if it is not variably-sized) state. + */ + GAME_OPCODE, + + /** + * The payload state will wait for the whole packet to be received. Then, it will pass a {@link GamePacket} object + * to Netty and reset the state back to the game opcode state, ready for the next packet. + */ + GAME_PAYLOAD; + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/com/rs2/net/HostList.java b/2006Scape Server/src/main/java/com/rs2/net/HostList.java index 9e790078..46046e37 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/HostList.java +++ b/2006Scape Server/src/main/java/com/rs2/net/HostList.java @@ -1,57 +1,90 @@ package com.rs2.net; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.apache.mina.common.IoSession; - import com.rs2.Connection; import com.rs2.GameConstants; public class HostList { - - private static HostList list = new HostList(); - - public static HostList getHostList() { - return list; - } - - private final Map connections = new HashMap(); - - public synchronized boolean add(IoSession session) { - String addr = ((InetSocketAddress) session.getRemoteAddress()) - .getAddress().getHostAddress(); - Integer amt = connections.get(addr); - if (amt == null) { - amt = 1; - } else { - amt += 1; - } - if (amt > GameConstants.IPS_ALLOWED || Connection.isIpBanned(addr)) { - return false; - } else { - connections.put(addr, amt); - return true; - } - } - - public synchronized void remove(IoSession session) { - if (session.getAttribute("inList") != Boolean.TRUE) { - return; - } - String addr = ((InetSocketAddress) session.getRemoteAddress()) - .getAddress().getHostAddress(); - Integer amt = connections.get(addr); - if (amt == null) { - return; - } - amt -= 1; - if (amt <= 0) { - connections.remove(addr); - } else { - connections.put(addr, amt); - } - } - +// +// private final Map clients; +// +// private HostList() { +// clients = Collections.synchronizedMap(new HashMap()); +// } +// +// private static HostList list = new HostList(); +// +// public static HostList getHostList() { +// return list; +// } +// +// private final Map connections = new HashMap(); +// +// public synchronized boolean add(Session session) { +// if(!isConnectionOk(session)) { +// return false; +// } +// String addr = ((InetSocketAddress) session.getChannel().remoteAddress()).getAddress().getHostAddress(); +// Integer amt = connections.get(addr); +// if (amt == null) { +// amt = 1; +// } else { +// amt += 1; +// } +// if (amt > GameConstants.IPS_ALLOWED || Connection.isIpBanned(addr)) { +// return false; +// } else { +// connections.put(addr, amt); +// return true; +// } +// } +// +// public synchronized void remove(Session session) { +// if (!session.isInList()) { +// return; +// } +// String addr = ((InetSocketAddress) session.getChannel().remoteAddress()) +// .getAddress().getHostAddress(); +// Integer amt = connections.get(addr); +// if (amt == null) { +// return; +// } +// amt -= 1; +// if (amt <= 0) { +// connections.remove(addr); +// } else { +// connections.put(addr, amt); +// } +// } +// +// private InetAddress getAddress(Session io) { +// return ((InetSocketAddress) io.getChannel().remoteAddress()).getAddress(); +// } +// +// /** +// * Method responsible for deciding if a connection is OK to continue +// * +// * @param session +// * The new session that will be verified +// * @return True if the session meets the criteria, otherwise false +// */ +// private boolean isConnectionOk(Session session) { +// InetAddress addr = getAddress(session); +// long now = System.currentTimeMillis(); +// if (clients.containsKey(addr)) { +// long lastConnTime = clients.get(addr); +// +// if (now - lastConnTime < GameConstants.CONNECTION_DELAY) { +// System.out.println("["+addr+"] Session dropped (delay="+(now-lastConnTime)+"ms)"); +// return false; +// } +// } +// clients.put(addr, now); +// return true; +// } } diff --git a/2006Scape Server/src/main/java/com/rs2/net/Packet.java b/2006Scape Server/src/main/java/com/rs2/net/Packet.java index d71110e0..6563846f 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/Packet.java +++ b/2006Scape Server/src/main/java/com/rs2/net/Packet.java @@ -1,304 +1,472 @@ package com.rs2.net; -import org.apache.mina.common.IoSession; +import io.netty.buffer.ByteBuf; /** - * Immutable packet object. + * Represents a single packet. + * + * @author Graham Edgecombe * - * @author Graham */ -public final class Packet { - - public static enum Size { - Fixed, VariableByte, VariableShort - }; +public class Packet { /** - * The associated IO session - */ - private final IoSession session; - /** - * The ID of the packet - */ - private final int pID; - /** - * The length of the payload - */ - private final int pLength; - /** - * The payload - */ - private final byte[] pData; - /** - * The current index into the payload buffer for reading - */ - private int caret = 0; - /** - * Whether this packet is without the standard packet header - */ - private final boolean bare; - private Size size = Size.Fixed; - - public Packet(IoSession session, int pID, byte[] pData, boolean bare, Size s) { - this.session = session; - this.pID = pID; - this.pData = pData; - pLength = pData.length; - this.bare = bare; - size = s; - } - - /** - * Creates a new packet with the specified parameters. + * The type of packet. + * + * @author Graham Edgecombe * - * @param session - * The session to associate with the packet - * @param pID - * The ID of the packet - * @param pData - * The payload of the packet - * @param bare - * Whether this packet is bare, which means that it does not - * include the standard packet header */ - public Packet(IoSession session, int pID, byte[] pData, boolean bare) { - this(session, pID, pData, bare, Size.Fixed); + public enum Type { + + /** + * A fixed size packet where the size never changes. + */ + FIXED, + + /** + * A variable packet where the size is described by a byte. + */ + VARIABLE, + + /** + * A variable packet where the size is described by a word. + */ + VARIABLE_SHORT; + } /** - * Creates a new packet with the specified parameters. The packet is - * considered not to be a bare packet. - * - * @param session - * The session to associate with the packet - * @param pID - * The ID of the packet - * @param pData - * The payload the packet + * The opcode. */ - public Packet(IoSession session, int pID, byte[] pData) { - this(session, pID, pData, false); + private final int opcode; + + /** + * The type. + */ + private final Type type; + + /** + * The payload. + */ + private final ByteBuf payload; + + /** + * Creates a packet. + * + * @param opcode The opcode. + * @param type The type. + * @param payload The payload. + */ + public Packet(final int opcode, final Type type, final ByteBuf payload) { + this.opcode = opcode; + this.type = type; + this.payload = payload; } /** - * Returns the IO session associated with the packet, if any. + * Checks if this packet is raw. A raw packet does not have the usual headers + * such as opcode or size. * - * @return The IoSession object, or null if none. + * @return true if so, false if not. */ - public IoSession getSession() { - return session; + public boolean isRaw() { + return opcode == -1; } /** - * Checks if this packet is considered to be a bare packet, which means that - * it does not include the standard packet header (ID and length values). + * Gets the opcode. * - * @return Whether this packet is a bare packet + * @return The opcode. */ - public boolean isBare() { - return bare; - } - - public Size getSize() { - return size; + public int getOpcode() { + return opcode; } /** - * Returns the packet ID. + * Gets the type. * - * @return The packet ID + * @return The type. */ - public int getId() { - return pID; + public Type getType() { + return type; } /** - * Returns the length of the payload of this packet. + * Gets the payload. * - * @return The length of the packet's payload + * @return The payload. + */ + public ByteBuf getPayload() { + return payload; + } + + /** + * Gets the length. + * + * @return The length. */ public int getLength() { - return pLength; + return payload.capacity(); } /** - * Returns the entire payload data of this packet. + * Reads a single byte. * - * @return The payload byte array + * @return A single byte. */ - public byte[] getData() { - return pData; + public byte get() { + return payload.readByte(); } /** - * Returns the remaining payload data of this packet. + * Reads several bytes. * - * @return The payload byte array + * @param b The target array. */ - public byte[] getRemainingData() { - byte[] data = new byte[pLength - caret]; - for (int i = 0; i < data.length; i++) { - data[i] = pData[i + caret]; - } - caret += data.length; - return data; - + public void get(final byte[] b) { + payload.readBytes(b); } /** - * Reads the next byte from the payload. + * Reads a byte. * - * @return A byte + * @return A single byte. */ - public byte readByte() { - return pData[caret++]; + public byte getByte() { + return get(); } /** - * Reads the next short from the payload. + * Reads an unsigned byte. * - * @return A short + * @return An unsigned byte. */ - public short readShort() { - return (short) ((short) ((pData[caret++] & 0xff) << 8) | (short) (pData[caret++] & 0xff)); + public int getUnsignedByte() { + return payload.readByte() & 0xff; } - public int readLEShortA() { - int i = (pData[caret++] - 128 & 0xff) + ((pData[caret++] & 0xff) << 8); - if (i > 32767) { + /** + * Reads a short. + * + * @return A short. + */ + public short getShort() { + return payload.readShort(); + } + + /** + * Reads an unsigned short. + * + * @return An unsigned short. + */ + public int getUnsignedShort() { + int value = 0; + value |= (get() & 0xff) << 8; + value |= (get() & 0xff); + return value; + } + + public int getUnsignedShortA() { + int value = 0; + value |= (get() & 0xff) << 8; + value |= ((get() - 128) & 0xff); + return value; + } + + /** + * Reads an integer. + * + * @return An integer. + */ + public int getInt() { + return payload.readInt(); + } + + /** + * Reads a long. + * + * @return A long. + */ + public long getLong() { + return payload.readLong(); + } + + /** + * Reads a type C byte. + * + * @return A type C byte. + */ + public byte getByteC() { + return (byte) (-get()); + } + + /** + * Gets a type S byte. + * + * @return A type S byte. + */ + public byte getByteS() { + return (byte) (128 - get()); + } + + /** + * Reads a little-endian type A short. + * + * @return A little-endian type A short. + */ + public short getLEShortA() { + int i = (get() - 128 & 0xFF) | ((get() & 0xFF) << 8); + if (i > 32767) i -= 0x10000; - } - return i; + return (short) i; } - public int readLEShort() { - int i = (pData[caret++] & 0xff) + ((pData[caret++] & 0xff) << 8); - if (i > 32767) { + /** + * Reads a little-endian short. + * + * @return A little-endian short. + */ + public short getLEShort() { + int i = (get() & 0xFF) | ((get() & 0xFF) << 8); + if (i > 32767) i -= 0x10000; + return (short) i; + } + + /** + * Reads a V1 integer. + * + * @return A V1 integer. + */ + public int getInt1() { + final byte b1 = get(); + final byte b2 = get(); + final byte b3 = get(); + final byte b4 = get(); + return ((b3 << 24) & 0xFF) | ((b4 << 16) & 0xFF) | ((b1 << 8) & 0xFF) | (b2 & 0xFF); + } + + /** + * Reads a V2 integer. + * + * @return A V2 integer. + */ + public int getInt2() { + final int b1 = get() & 0xFF; + final int b2 = get() & 0xFF; + final int b3 = get() & 0xFF; + final int b4 = get() & 0xFF; + return ((b2 << 24) & 0xFF) | ((b1 << 16) & 0xFF) | ((b4 << 8) & 0xFF) | (b3 & 0xFF); + } + + /** + * Gets a 3-byte integer. + * + * @return The 3-byte integer. + */ + public int getTriByte() { + return ((get() << 16) & 0xFF) | ((get() << 8) & 0xFF) | (get() & 0xFF); + } + + /** + * Reads a type A byte. + * + * @return A type A byte. + */ + public byte getByteA() { + return (byte) (get() - 128); + } + + /** + * Reads a RuneScape string. + * + * @return The string. + */ + public String getRS2String() { + byte temp; + StringBuilder b = new StringBuilder(); + while ((temp = payload.readByte()) != 10) { + b.append((char) temp); } - return i; + return b.toString(); } /** - * Reads the next int from the payload. + * Reads a type A short. * - * @return An int + * @return A type A short. */ - public int readInt() { - return (pData[caret++] & 0xff) << 24 | (pData[caret++] & 0xff) << 16 - | (pData[caret++] & 0xff) << 8 | pData[caret++] & 0xff; - } - - public int readLEInt() { - return pData[caret++] & 0xff | (pData[caret++] & 0xff) << 8 - | (pData[caret++] & 0xff) << 16 | (pData[caret++] & 0xff) << 24; + public short getShortA() { + int i = ((get() & 0xFF) << 8) | (get() - 128 & 0xFF); + if (i > 32767) + i -= 0x10000; + return (short) i; } /** - * Reads the next long from the payload. + * Reads a series of bytes in reverse. * - * @return A long + * @param is The target byte array. + * @param offset The offset. + * @param length The length. */ - public long readLong() { - return (long) (pData[caret++] & 0xff) << 56 - | (long) (pData[caret++] & 0xff) << 48 - | (long) (pData[caret++] & 0xff) << 40 - | (long) (pData[caret++] & 0xff) << 32 - | (long) (pData[caret++] & 0xff) << 24 - | (long) (pData[caret++] & 0xff) << 16 - | (long) (pData[caret++] & 0xff) << 8 | pData[caret++] & 0xff; + public void getReverse(final byte[] is, final int offset, final int length) { + for (int i = (offset + length - 1); i >= offset; i--) + is[i] = get(); } /** - * Reads the string which is formed by the unread portion of the payload. + * Reads a series of type A bytes in reverse. * - * @return A String + * @param is The target byte array. + * @param offset The offset. + * @param length The length. */ + public void getReverseA(final byte[] is, final int offset, final int length) { + for (int i = (offset + length - 1); i >= offset; i--) + is[i] = getByteA(); + } + + /** + * Reads a series of bytes. + * + * @param is The target byte array. + * @param offset The offset. + * @param length The length. + */ + public void get(final byte[] is, final int offset, final int length) { + for (int i = 0; i < length; i++) + is[offset + i] = get(); + } + + /** + * Gets a smart. + * + * @return The smart. + */ + public int getSmart() { + final int peek = payload.getByte(payload.readerIndex()); + if (peek < 128) + return (get() & 0xFF); + else + return (getShort() & 0xFFFF) - 32768; + } + + /** + * Gets a signed smart. + * + * @return The signed smart. + */ + public int getSignedSmart() { + final int peek = payload.getByte(payload.readerIndex()); + if (peek < 128) + return ((get() & 0xFF) - 64); + else + return ((getShort() & 0xFFFF) - 49152); + } + + /* Legacy methods here */ + + public int readUnsignedByte() { + return get() & 0xff; + } + + public byte readSignedByte() { + return get(); + } + + public byte readSignedByteC() { + return (byte) -get(); + } + + public int readUnsignedByteS() { + return 128 - get() & 0xff; + } + + public int readHex() { + return ((get() & 0xFF) * 1000) + (get() & 0xFF); + } + + public void readBytes(byte abyte0[], int length, int offset) { + for (int i = 0; i < length; i++) + abyte0[offset + i] = get(); + } + + public void readBytes_reverseA(byte abyte0[], int length, int offset) { + for (int i = (offset + length - 1); i >= offset; i--) + abyte0[i] = getByteA(); + } + public String readString() { - return readString(pLength - caret); - } - - public String readRS2String() { - int start = caret; - while (pData[caret++] != 0) { - ; + byte temp; + StringBuilder b = new StringBuilder(); + while ((temp = payload.readByte()) != 10) { + b.append((char) temp); } - return new String(pData, start, caret - start - 1); + return b.toString(); } - public void readBytes(byte[] buf, int off, int len) { - for (int i = 0; i < len; i++) { - buf[off + i] = pData[caret++]; + public int readDWord() { + return ((readUnsignedByte()) << 24) + ((readUnsignedByte()) << 16) + ((readUnsignedByte()) << 8) + (readUnsignedByte()); + } + + public long readQWord() { + long l = readDWord() & 0xffffffffL; + long l1 = readDWord() & 0xffffffffL; + return (l << 32) + l1; + } + + public long readQWord2() { + final long l = readDWord() & 0xffffffffL; + final long l1 = readDWord() & 0xffffffffL; + return (l << 32) + l1; + } + + public int readSignedWordA() { + int i = ((readUnsignedByte()) << 8) + (get() - 128 & 0xff); + if (i > 32767) { + i -= 0x10000; } + return i; } - /** - * Reads a string of the specified length from the payload. - * - * @param length - * The length of the string to be read - * @return A String - */ - public String readString(int length) { - String rv = new String(pData, caret, length); - caret += length; - return rv; + public int readUnsignedWordA() { + return ((readUnsignedByte()) << 8) + (get() - 128 & 0xff); } - /** - * Skips the specified number of bytes in the payload. - * - * @param x - * The number of bytes to be skipped - */ - public void skip(int x) { - caret += x; + public int readUnsignedWord() { + return ((readUnsignedByte()) << 8) + (readUnsignedByte()); } - public int remaining() { - return pData.length - caret; - } - - /** - * Returns this packet in string form. - * - * @return A String representing this packet - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[id=" + pID + ",len=" + pLength + ",data=0x"); - for (int x = 0; x < pLength; x++) { - sb.append(byteToHex(pData[x], true)); + public int readSignedWord() { + int i = ((readUnsignedByte()) << 8) + (readUnsignedByte()); + if (i > 32767) { + i -= 0x10000; } - sb.append("]"); - return sb.toString(); + return i; } - private static String byteToHex(byte b, boolean forceLeadingZero) { - StringBuilder out = new StringBuilder(); - int ub = b & 0xff; - if (ub / 16 > 0 || forceLeadingZero) { - out.append(hex[ub / 16]); + public int readSignedWordBigEndian() { + int i = (readUnsignedByte()) + ((readUnsignedByte()) << 8); + if (i > 32767) { + i -= 0x10000; } - out.append(hex[ub % 16]); - return out.toString(); + return i; } - private static final char[] hex = "0123456789ABCDEF".toCharArray(); - - public int readShortA() { - caret += 2; - return ((pData[caret - 2] & 0xFF) << 8) - + (pData[caret - 1] - 128 & 0xFF); + public int readSignedWordBigEndianA() { + int i = (get() - 128 & 0xff) + ((readUnsignedByte()) << 8); + if (i > 32767) { + i -= 0x10000; + } + return i; } - public byte readByteC() { - return (byte) -readByte(); + public int readUnsignedWordBigEndian() { + return (readUnsignedByte()) + ((readUnsignedByte()) << 8); } - public byte readByteS() { - return (byte) (128 - readByte()); + public int readUnsignedWordBigEndianA() { + return (get() - 128 & 0xff) + ((readUnsignedByte()) << 8); } - } diff --git a/2006Scape Server/src/main/java/com/rs2/net/PacketBuffer.java b/2006Scape Server/src/main/java/com/rs2/net/PacketBuffer.java deleted file mode 100644 index 36790768..00000000 --- a/2006Scape Server/src/main/java/com/rs2/net/PacketBuffer.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.rs2.net; - -/** - * Represents a packet buffer. - * - * @author Ultimate1 - * @author blakeman8192 - */ - -public class PacketBuffer { - - private int caret; - private byte[] buffer; - - public PacketBuffer(int capcity) { - buffer = new byte[capcity]; - caret = 0; - } - - public void setBuffer(byte[] buffer) { - this.buffer = buffer; - caret = 0; - } - - public PacketBuffer setOpcode(int opcode) { - return addByte(opcode); - } - - public PacketBuffer addByte(int i) { - buffer[caret++] = (byte) i; - return this; - } - - public int getByte() { - return buffer[caret++] & 0xff; - } - - public PacketBuffer addBoolean(boolean val) { - return addByte(val ? 1 : 0); - } - - public boolean getBoolean() { - return getByte() == 1; - } - - public PacketBuffer addShort(int i) { - return addByte(i >> 8).addByte(i); - } - - public int getShort() { - return getByte() << 8 | getByte(); - } - - public PacketBuffer addInt(int i) { - return addShort(i >> 16).addShort(i); - } - - public int getInt() { - return getShort() << 16 | getShort(); - } - - public PacketBuffer addLong(long i) { - return addInt((int) (i >> 32)).addInt((int) i); - } - - public long getLong() { - return (long) getInt() << 32L | getInt(); - } - - public PacketBuffer addString(String s) { - for (byte b : s.getBytes()) { - addByte(b); - } - return addByte('\n'); - } - - public String getString() { - int c; - StringBuilder builder = new StringBuilder(); - while ((c = getByte()) != '\n') { - builder.append((char) c); - } - return builder.toString(); - } - - public byte[] getBuffer() { - byte[] newBuffer = new byte[caret + 1]; - newBuffer[0] = (byte) caret; - System.arraycopy(buffer, 0, newBuffer, 1, caret); - return newBuffer; - } - - public int getLength() { - return buffer.length; - } - - public void reset() { - caret = 0; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = 0; - } - buffer = null; - } -} diff --git a/2006Scape Server/src/main/java/com/rs2/net/PacketBuilder.java b/2006Scape Server/src/main/java/com/rs2/net/PacketBuilder.java deleted file mode 100644 index b2f0e44e..00000000 --- a/2006Scape Server/src/main/java/com/rs2/net/PacketBuilder.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.rs2.net; - -/** - * Packet builder interface - * - * @author Graham - */ -public interface PacketBuilder { - -} diff --git a/2006Scape Server/src/main/java/com/rs2/net/PacketSender.java b/2006Scape Server/src/main/java/com/rs2/net/PacketSender.java index 8ef6e169..3cb1dc00 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/PacketSender.java +++ b/2006Scape Server/src/main/java/com/rs2/net/PacketSender.java @@ -336,7 +336,8 @@ public class PacketSender { player.getOutStream().writeWordA(id); player.getOutStream().endFrameVarSizeWord(); player.flushOutStream(); - } + }//send(new SetWidgetTextMessage(id, s)); + return this; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/RS2LoginProtocolDecoder.java b/2006Scape Server/src/main/java/com/rs2/net/RS2LoginProtocolDecoder.java deleted file mode 100644 index 158cb7d3..00000000 --- a/2006Scape Server/src/main/java/com/rs2/net/RS2LoginProtocolDecoder.java +++ /dev/null @@ -1,305 +0,0 @@ -package com.rs2.net; - -import java.math.BigInteger; -import java.net.InetSocketAddress; - -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IoFuture; -import org.apache.mina.common.IoFutureListener; -import org.apache.mina.common.IoSession; -import org.apache.mina.filter.codec.CumulativeProtocolDecoder; -import org.apache.mina.filter.codec.ProtocolCodecFilter; -import org.apache.mina.filter.codec.ProtocolDecoderOutput; - -import com.rs2.Connection; -import com.rs2.GameConstants; -import com.rs2.GameEngine; -import com.rs2.game.players.Client; -import com.rs2.game.players.PlayerHandler; -import com.rs2.game.players.PlayerSave; -import com.rs2.util.HostBlacklist; -import com.rs2.util.ISAACRandomGen; - -/** - * Login protocol decoder. - * - * @author Graham - * @author Ryan / Lmctruck30 <- login Protocol fixes - */ - -public class RS2LoginProtocolDecoder extends CumulativeProtocolDecoder { - - private static final BigInteger RSA_MODULUS = new BigInteger("91553247461173033466542043374346300088148707506479543786501537350363031301992107112953015516557748875487935404852620239974482067336878286174236183516364787082711186740254168914127361643305190640280157664988536979163450791820893999053469529344247707567448479470137716627440246788713008490213212272520901741443"); - private static final BigInteger RSA_EXPONENT = new BigInteger("33280025241734061313051117678670856264399753710527826596057587687835856000539511539311834363046145710983857746766009612538140077973762171163294453513440619295457626227183742315140865830778841533445402605660729039310637444146319289077374748018792349647460850308384280105990607337322160553135806205784213241305"); - - - /** - * Parses the data in the provided byte buffer and writes it to - * out as a Packet. - * - * @param session - * The IoSession the data was read from - * @param in - * The buffer - * @param out - * The decoder output stream to which to write the - * Packet - * @return Whether enough data was available to create a packet - */ - @Override - public boolean doDecode(IoSession session, ByteBuffer in, - ProtocolDecoderOutput out) { - synchronized (session) { - Object loginStageObj = session.getAttribute("LOGIN_STAGE"); - int loginStage = 0; - if (loginStageObj != null) { - loginStage = (Integer) loginStageObj; - } - // Logger.log("recv login packet, stage: "+loginStage); - switch (loginStage) { - case 0: - if (2 <= in.remaining()) { - int protocol = in.get() & 0xff; - @SuppressWarnings("unused") - int nameHash = in.get() & 0xff; - if (protocol == 14) { - long serverSessionKey = ((long) (java.lang.Math - .random() * 99999999D) << 32) - + (long) (java.lang.Math.random() * 99999999D); - StaticPacketBuilder s1Response = new StaticPacketBuilder(); - s1Response - .setBare(true) - .addBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }) - .addByte((byte) 0).addLong(serverSessionKey); - session.setAttribute("SERVER_SESSION_KEY", - serverSessionKey); - session.write(s1Response.toPacket()); - session.setAttribute("LOGIN_STAGE", 1); - } - return true; - } else { - in.rewind(); - return false; - } - case 1: - @SuppressWarnings("unused") - int loginType = -1, - loginPacketSize = -1, - loginEncryptPacketSize = -1; - if (2 <= in.remaining()) { - loginType = in.get() & 0xff; // should be 16 or 18 - loginPacketSize = in.get() & 0xff; - loginEncryptPacketSize = loginPacketSize - (36 + 1 + 1 + 2); - if (loginPacketSize <= 0 || loginEncryptPacketSize <= 0) { - System.out.println("Zero or negative login size."); - session.close(); - return false; - } - } else { - in.rewind(); - return false; - } - if (loginPacketSize <= in.remaining()) { - int magic = in.get() & 0xff; - int version = in.getUnsignedShort(); - if (magic != 255) { - // System.out.println("Wrong magic id."); - session.close(); - return false; - } - if (version != 1) { - // Dont Add Anything - } - @SuppressWarnings("unused") - int lowMem = in.get() & 0xff; - for (int i = 0; i < 9; i++) { - in.getInt(); - } - loginEncryptPacketSize--; - if(loginEncryptPacketSize != (in.get() & 0xff)) { - System.out.println("Encrypted size mismatch."); - session.close(); - return false; - } - byte[] encryptionBytes = new byte[loginEncryptPacketSize]; - in.get(encryptionBytes); - ByteBuffer rsaBuffer = ByteBuffer.wrap(new BigInteger(encryptionBytes).modPow(RSA_EXPONENT, RSA_MODULUS).toByteArray()); - if((rsaBuffer.get() & 0xff) != 10) { - System.out.println("Encrypted id != 10."); - session.close(); - return false; - } - long clientSessionKey = rsaBuffer.getLong(); - long serverSessionKey = rsaBuffer.getLong(); - int uid = rsaBuffer.getInt(); - if(uid != 314268572) { - session.close(); - return false; - } - String name = readRS2String(rsaBuffer); - String pass = readRS2String(rsaBuffer); - int sessionKey[] = new int[4]; - sessionKey[0] = (int) (clientSessionKey >> 32); - sessionKey[1] = (int) clientSessionKey; - sessionKey[2] = (int) (serverSessionKey >> 32); - sessionKey[3] = (int) serverSessionKey; - ISAACRandomGen inC = new ISAACRandomGen(sessionKey); - for (int i = 0; i < 4; i++) - sessionKey[i] += 50; - ISAACRandomGen outC = new ISAACRandomGen(sessionKey); - load(session, uid, name, pass, inC, outC, version); - session.getFilterChain().remove("protocolFilter"); - session.getFilterChain().addLast("protocolFilter", new ProtocolCodecFilter(new GameCodecFactory(inC))); - return true; - } else { - in.rewind(); - return false; - } - } - } - return false; - } - - - private synchronized void load(final IoSession session, final int uid, - String name, String pass, final ISAACRandomGen inC, - ISAACRandomGen outC, int version) { - session.setAttribute("opcode", -1); - session.setAttribute("size", -1); - int returnCode = 2; - - name = name.trim(); - name = name.toLowerCase(); - // pass = pass.toLowerCase(); - - String hostName = ((InetSocketAddress) session.getRemoteAddress()) - .getAddress().getHostName(); - - //if (version != 1) { - //returnCode = 31; - //d} - - if (HostBlacklist.isBlocked(hostName)) { - returnCode = 11; - } - - if (!name.matches("[A-Za-z0-9 ]+")) { - returnCode = 4; - } - - if (name.length() > 12) { - returnCode = 8; - } - - if (pass.length() == 0) { - returnCode = 4; - } - - Client cl = new Client(session, -1); - cl.playerName = name; - cl.playerName2 = cl.playerName; - cl.playerPass = pass; - - cl.setInStreamDecryption(inC); - cl.setOutStreamDecryption(outC); - cl.outStream.packetEncryption = outC; - cl.saveCharacter = false; - char first = name.charAt(0); - cl.properName = Character.toUpperCase(first) - + name.substring(1, name.length()); - - if (Connection.isNamedBanned(cl.playerName)) { - returnCode = 4; - } - - - if (PlayerHandler.isPlayerOn(name)) { - returnCode = 5; - } - - if (PlayerHandler.playerCount >= GameConstants.MAX_PLAYERS) { - returnCode = 7; - } - - if (GameEngine.updateServer) { - returnCode = 14; - } - - if (returnCode == 2) { - int load = PlayerSave.loadGame(cl, cl.playerName, cl.playerPass); - if (load == 0) { - cl.addStarter = true; - } - if (load == 3) { - returnCode = 3; - cl.saveFile = false; - } else { - for (int i = 0; i < cl.playerEquipment.length; i++) { - if (cl.playerEquipment[i] == 0) { - cl.playerEquipment[i] = -1; - cl.playerEquipmentN[i] = 0; - } - } - if (!GameEngine.playerHandler.newPlayerClient(cl)) { - returnCode = 7; - cl.saveFile = false; - } else { - cl.saveFile = true; - } - } - } - - cl.packetType = -1; - cl.packetSize = 0; - - StaticPacketBuilder bldr = new StaticPacketBuilder(); - bldr.setBare(true); - bldr.addByte((byte) returnCode); - if (returnCode == 2) { - cl.saveCharacter = true; - if (cl.playerRights == 3) { - bldr.addByte((byte) 2); - } else { - bldr.addByte((byte) cl.playerRights); - } - } else { - bldr.addByte((byte) 0); - } - bldr.addByte((byte) 0); - cl.isActive = true; - Packet pkt = bldr.toPacket(); - session.setAttachment(cl); - session.write(pkt).addListener(new IoFutureListener() { - - @Override - public void operationComplete(IoFuture arg0) { - session.getFilterChain().remove("protocolFilter"); - session.getFilterChain().addFirst("protocolFilter", - new ProtocolCodecFilter(new GameCodecFactory(inC))); - } - }); - } - - private synchronized String readRS2String(ByteBuffer in) { - StringBuilder sb = new StringBuilder(); - byte b; - while ((b = in.get()) != 10) { - sb.append((char) b); - } - return sb.toString(); - } - - /** - * Releases the buffer used by the given session. - * - * @param session - * The session for which to release the buffer - * @throws Exception - * if failed to dispose all resources - */ - @Override - public void dispose(IoSession session) throws Exception { - super.dispose(session); - } - -} diff --git a/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolDecoder.java b/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolDecoder.java index 9099730b..2d19c095 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolDecoder.java +++ b/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolDecoder.java @@ -1,145 +1,210 @@ package com.rs2.net; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IoSession; -import org.apache.mina.filter.codec.CumulativeProtocolDecoder; -import org.apache.mina.filter.codec.ProtocolDecoderOutput; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; -import com.rs2.game.players.Client; -import com.rs2.util.ISAACRandomGen; +import java.util.List; -public class RS2ProtocolDecoder extends CumulativeProtocolDecoder { +import org.apollo.util.StatefulFrameDecoder; +import org.apollo.util.security.IsaacRandom; - private final ISAACRandomGen isaac; +import com.google.common.base.Preconditions; +import com.rs2.net.Packet.Type; + +public class RS2ProtocolDecoder extends StatefulFrameDecoder { + + private int opcode = -1; + private int length = -1; + private final IsaacRandom random; + public static final int PACKET_SIZES[] = { 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, // 0 + 0, 0, 0, 0, 8, 0, 6, 2, 2, 0, // 10 + 0, 2, 0, 6, 0, 12, 0, 0, 0, 0, // 20 + 0, 0, 0, 0, 0, 8, 4, 0, 0, 2, // 30 + 2, 6, 0, 6, 0, -1, 0, 0, 0, 0, // 40 + 0, 0, 0, 12, 0, 0, 0, 8, 8, 12, // 50 + 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, // 60 + 6, 0, 2, 2, 8, 6, 0, -1, 0, 6, // 70 + 0, 0, 0, 0, 0, 1, 4, 6, 0, 0, // 80 + 0, 0, 0, 0, 0, 3, 0, 0, -1, 0, // 90 + 0, 13, 0, -1, 0, 0, 0, 0, 0, 0,// 100 + 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, // 110 + 1, 0, 6, 0, 0, 0, -1, 0, 2, 6, // 120 + 0, 4, 6, 8, 0, 6, 0, 0, 0, 2, // 130 + 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, // 140 + 0, 0, 1, 2, 0, 2, 6, 0, 0, 0, // 150 + 0, 0, 0, 0, -1, -1, 0, 0, 0, 0,// 160 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170 + 0, 8, 0, 3, 0, 2, 0, 0, 8, 1, // 180 + 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, // 190 + 2, 0, 0, 0, 0, 0, 0, 0, 4, 0, // 200 + 4, 0, 0, 0, 7, 8, 0, 0, 10, 0, // 210 + 0, 0, 0, 0, 0, 0, -1, 0, 6, 0, // 220 + 1, 0, 0, 0, 6, 0, 6, 8, 1, 0, // 230 + 0, 4, 0, 0, 0, 0, -1, 0, -1, 4,// 240 + 0, 0, 6, 6, 0, 0, 0 // 250 + }; /** * To make sure only the CodecFactory can initialise us. */ - protected RS2ProtocolDecoder(ISAACRandomGen isaac) { - this.isaac = isaac; + public RS2ProtocolDecoder(IsaacRandom isaac) { + super(GameDecoderState.GAME_OPCODE); + this.random = isaac; } + +// /** +// * Decodes a message. +// * +// * @param session +// * @param in +// * @param out +// * @return +// */ +// @Override +// protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { +// /* +// * If the opcode is not present. +// */ +// if (opcode == -1) { +// /* +// * Check if it can be read. +// */ +// if (in.readableBytes() >= 1) { +// /* +// * Read and decrypt the opcode. +// */ +// opcode = in.readByte() & 0xFF; +// opcode = (opcode - random.nextInt()) & 0xFF; +// /* +// * Find the packet size. +// */ +// length = PACKET_SIZES[opcode]; +// } else { +// /* +// * We need to wait for more data. +// */ +// return; +// } +// } +// +// /* +// * If the packet is variable-length. +// */ +// if (length == -1) { +// /* +// * Check if the size can be read. +// */ +// if (in.readableBytes() >= 1) { +// /* +// * Read the packet size and cache it. +// */ +// length = in.readByte() & 0xFF; +// } else { +// /* +// * We need to wait for more data. +// */ +// return; +// } +// } +// +// /* +// * If the packet payload (data) can be read. +// */ +// if (in.readableBytes() >= length) { +// /* +// * Read it. +// */ +// ByteBuf payload = in.readBytes(length); +// /* +// * Produce and write the packet object. +// */ +// out.add(new Packet(opcode, Type.FIXED, payload)); +// opcode = -1; +// length = -1; +// } +// +// /* +// * We need to wait for more data. +// */ +// return; +// } - /** - * Decodes a message. - * - * @param session - * @param in - * @param out - * @return - */ @Override - protected boolean doDecode(IoSession session, ByteBuffer in, - ProtocolDecoderOutput out) throws Exception { - synchronized (session) { - /* - * Fetch the ISAAC cipher for this session. - */ - // ISAACRandomGen inCipher = ((Player) - // session.getAttribute("player")).getInStreamDecryption(); - - /* - * Fetch any cached opcodes and sizes, reset to -1 if not present. - */ - int opcode = (Integer) session.getAttribute("opcode"); - int size = (Integer) session.getAttribute("size"); - - /* - * If the opcode is not present. - */ - if (opcode == -1) { - /* - * Check if it can be read. - */ - if (in.remaining() >= 1) { - /* - * Read and decrypt the opcode. - */ - opcode = in.get() & 0xFF; - opcode = opcode - isaac.getNextKey() & 0xFF; - - /* - * Find the packet size. - */ - size = Client.PACKET_SIZES[opcode]; - - /* - * Set the cached opcode and size. - */ - session.setAttribute("opcode", opcode); - session.setAttribute("size", size); - } else { - /* - * We need to wait for more data. - */ - return false; - } - } - - /* - * If the packet is variable-length. - */ - if (size == -1) { - /* - * Check if the size can be read. - */ - if (in.remaining() >= 1) { - /* - * Read the packet size and cache it. - */ - size = in.get() & 0xFF; - session.setAttribute("size", size); - } else { - /* - * We need to wait for more data. - */ - return false; - } - } - - /* - * If the packet payload (data) can be read. - */ - if (in.remaining() >= size) { - /* - * Read it. - */ - byte[] data = new byte[size]; - in.get(data); - ByteBuffer payload = ByteBuffer.allocate(data.length); - payload.put(data); - payload.flip(); - - /* - * Produce and write the packet object. - */ - out.write(new Packet(session, opcode, data)); - - /* - * Reset the cached opcode and sizes. - */ - session.setAttribute("opcode", -1); - session.setAttribute("size", -1); - - /* - * Indicate we are ready to read another packet. - */ - return true; - } - - /* - * We need to wait for more data. - */ - return false; + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out, GameDecoderState state) { + switch (state) { + case GAME_OPCODE: + decodeOpcode(in, out); + break; + case GAME_LENGTH: + decodeLength(in); + break; + case GAME_PAYLOAD: + decodePayload(in, out); + break; + default: + throw new IllegalStateException("Invalid game decoder state."); } } - @Override /** - * Releases resources used by this decoder. - * @param session + * Decodes the length state. + * + * @param buffer The buffer. */ - public void dispose(IoSession session) throws Exception { - super.dispose(session); + private void decodeLength(ByteBuf buffer) { + if (buffer.isReadable()) { + length = buffer.readUnsignedByte(); + if (length != 0) { + setState(GameDecoderState.GAME_PAYLOAD); + } + } } + /** + * Decodes the opcode state. + * + * @param buffer The buffer. + * @param out The {@link List} of objects to be passed along the pipeline. + */ + private void decodeOpcode(ByteBuf buffer, List out) { + if (buffer.isReadable()) { + int encryptedOpcode = buffer.readUnsignedByte(); + opcode = encryptedOpcode - random.nextInt() & 0xFF; + + int s = PACKET_SIZES[opcode]; + + switch (s) { + default: + length = s; + if (length == 0) { + setState(GameDecoderState.GAME_OPCODE); + out.add(new Packet(opcode, Type.FIXED, Unpooled.EMPTY_BUFFER)); + } else { + setState(GameDecoderState.GAME_PAYLOAD); + } + break; + case -1: + setState(GameDecoderState.GAME_LENGTH); + break; +// default: +// throw new IllegalStateException("Illegal packet type: " + type + "."); + } + } + } + + /** + * Decodes the payload state. + * + * @param buffer The buffer. + * @param out The {@link List} of objects to be passed along the pipeline. + */ + private void decodePayload(ByteBuf buffer, List out) { + if (buffer.readableBytes() >= length) { + ByteBuf payload = buffer.readBytes(length); + setState(GameDecoderState.GAME_OPCODE); + out.add(new Packet(opcode, Type.FIXED, payload)); + } + } } diff --git a/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolEncoder.java b/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolEncoder.java index f69a0099..dac6a3c5 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolEncoder.java +++ b/2006Scape Server/src/main/java/com/rs2/net/RS2ProtocolEncoder.java @@ -1,82 +1,26 @@ -package com.rs2.net; - -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.IoSession; -import org.apache.mina.filter.codec.ProtocolEncoder; -import org.apache.mina.filter.codec.ProtocolEncoderOutput; - -public class RS2ProtocolEncoder implements ProtocolEncoder { - - /** - * Only CodecFactory can create us. - */ - protected RS2ProtocolEncoder() { - } - - @Override - /** - * Encodes a message. - * @param session - * @param message - * @param out - */ - public void encode(IoSession session, Object message, - ProtocolEncoderOutput out) throws Exception { - try { - synchronized (session) { - Packet p = (Packet) message; - byte[] data = p.getData(); - int dataLength = p.getLength(); - ByteBuffer buffer; - if (!p.isBare()) { - buffer = ByteBuffer.allocate(dataLength + 3); - int id = p.getId(); - buffer.put((byte) id); - if (p.getSize() != Packet.Size.Fixed) { // variable length - // Logger.log("variable length: id="+id+",dataLength="+dataLength); - if (p.getSize() == Packet.Size.VariableByte) { - if (dataLength > 255) { - // then we can represent - // with 8 bits! - throw new IllegalArgumentException( - "Tried to send packet length " - + dataLength - + " in 8 bits [pid=" - + p.getId() + "]"); - } - buffer.put((byte) dataLength); - } else if (p.getSize() == Packet.Size.VariableShort) { - if (dataLength > 65535) { - // then we can represent - // with 16 bits! - throw new IllegalArgumentException( - "Tried to send packet length " - + dataLength - + " in 16 bits [pid=" - + p.getId() + "]"); - } - buffer.put((byte) (dataLength >> 8)); - buffer.put((byte) dataLength); - } - } - } else { - buffer = ByteBuffer.allocate(dataLength); - } - buffer.put(data, 0, dataLength); - buffer.flip(); - out.write(buffer); - } - } catch (Exception err) { - err.printStackTrace(); - } - } - - @Override - /** - * Releases resources used by this encoder. - * @param session - */ - public void dispose(IoSession session) throws Exception { - } - -} +//package com.rs2.net; +// +//import io.netty.buffer.ByteBuf; +//import io.netty.channel.ChannelHandlerContext; +//import io.netty.handler.codec.MessageToByteEncoder; +// +//public class RS2ProtocolEncoder extends MessageToByteEncoder { +// +// /** +// * Only CodecFactory can create us. +// */ +// public RS2ProtocolEncoder() { +// } +// +// @Override +// /** +// * Encodes a message. +// * @param session +// * @param message +// * @param out +// */ +// protected void encode(ChannelHandlerContext ctx, Packet msg, ByteBuf out) throws Exception { +// out.writeBytes(msg.getPayload());//return ((Packet) object).getPayload(); Do we need to go bldr->packet? +// } +// +//} diff --git a/2006Scape Server/src/main/java/com/rs2/net/StaticPacketBuilder.java b/2006Scape Server/src/main/java/com/rs2/net/StaticPacketBuilder.java deleted file mode 100644 index 651ded33..00000000 --- a/2006Scape Server/src/main/java/com/rs2/net/StaticPacketBuilder.java +++ /dev/null @@ -1,385 +0,0 @@ -package com.rs2.net; - -/** - * A mutable sequence of bytes used to construct the immutable - * Packet objects. By default, methods use big endian byte - * ordering. - */ -public class StaticPacketBuilder implements PacketBuilder { - - /** - * Default capacity - */ - private static final int DEFAULT_SIZE = 32; - /** - * The payload buffer - */ - private byte[] payload; - /** - * Current number of bytes used in the buffer - */ - private int curLength; - /** - * ID of the packet - */ - private int id; - /** - * Current index into the buffer by bits - */ - private int bitPosition = 0; - private Packet.Size size = Packet.Size.Fixed; - /** - * Whether this packet does not use the standard packet header - */ - private boolean bare = false; - - /** - * Bitmasks for addBits() - */ - private static int bitmasks[] = { 0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, - 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff, - 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff, - 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, 0x1fffffff, - 0x3fffffff, 0x7fffffff, -1 }; - - /** - * Constructs a packet builder with no data and an initial capacity of - * DEFAULT_SIZE. - * - * @see DEFAULT_SIZE - */ - public StaticPacketBuilder() { - this(DEFAULT_SIZE); - } - - public byte[] getPayload() { - return payload; - } - - /** - * Constructs a packet builder with no data and an initial capacity of - * capacity. - * - * @param capacity - * The initial capacity of the buffer - */ - public StaticPacketBuilder(int capacity) { - payload = new byte[capacity]; - } - - /** - * Ensures that the buffer is at least minimumBytes bytes. - * - * @param minimumCapacity - * The size needed - */ - private void ensureCapacity(int minimumCapacity) { - if (minimumCapacity >= payload.length) { - expandCapacity(minimumCapacity); - } - } - - /** - * Expands the buffer to the specified size. - * - * @param minimumCapacity - * The minimum capacity to which to expand - * @see java.lang.AbstractStringBuilder#expandCapacity(int) - */ - private void expandCapacity(int minimumCapacity) { - int newCapacity = (payload.length + 1) * 2; - if (newCapacity < 0) { - newCapacity = Integer.MAX_VALUE; - } else if (minimumCapacity > newCapacity) { - newCapacity = minimumCapacity; - } - byte[] newPayload = new byte[newCapacity]; - try { - while (curLength > payload.length) { - curLength--; - } - System.arraycopy(payload, 0, newPayload, 0, curLength); - } catch (Exception e) { - - } - payload = newPayload; - } - - /** - * Sets this packet as bare. A bare packet will contain only the payload - * data, rather than having the standard packet header prepended. - * - * @param bare - * Whether this packet is to be sent bare - */ - public StaticPacketBuilder setBare(boolean bare) { - this.bare = bare; - return this; - } - - /** - * Sets the ID for this packet. - * - * @param id - * The ID of the packet - */ - public StaticPacketBuilder setId(int id) { - this.id = id; - return this; - } - - public StaticPacketBuilder setSize(Packet.Size s) { - size = s; - return this; - } - - public StaticPacketBuilder initBitAccess() { - bitPosition = curLength * 8; - return this; - } - - public StaticPacketBuilder finishBitAccess() { - curLength = (bitPosition + 7) / 8; - return this; - } - - /** - * TODO needs a proper description. - */ - public StaticPacketBuilder addBits(int numBits, int value) { - int bytePos = bitPosition >> 3; - int bitOffset = 8 - (bitPosition & 7); - bitPosition += numBits; - curLength = (bitPosition + 7) / 8; - ensureCapacity(curLength); - for (; numBits > bitOffset; bitOffset = 8) { - payload[bytePos] &= ~bitmasks[bitOffset]; // mask out the desired - // area - payload[bytePos++] |= value >> numBits - bitOffset - & bitmasks[bitOffset]; - - numBits -= bitOffset; - } - if (numBits == bitOffset) { - payload[bytePos] &= ~bitmasks[bitOffset]; - payload[bytePos] |= value & bitmasks[bitOffset]; - } else { - payload[bytePos] &= ~(bitmasks[numBits] << bitOffset - numBits); - payload[bytePos] |= (value & bitmasks[numBits]) << bitOffset - - numBits; - } - return this; - } - - /** - * Adds the contents of byte array data to the - * packet. The size of this packet will grow by the length of the provided - * array. - * - * @param data - * The bytes to add to this packet - * @return A reference to this object - */ - public StaticPacketBuilder addBytes(byte[] data) { - return addBytes(data, 0, data.length); - } - - /** - * Adds the contents of byte array data, starting - * at index offset. The size of this packet will grow by - * len bytes. - * - * @param data - * The bytes to add to this packet - * @param offset - * The index of the first byte to append - * @param len - * The number of bytes to append - * @return A reference to this object - */ - public StaticPacketBuilder addBytes(byte[] data, int offset, int len) { - int newLength = curLength + len; - ensureCapacity(newLength); - System.arraycopy(data, offset, payload, curLength, len); - curLength = newLength; - return this; - } - - public StaticPacketBuilder addLEShortA(int i) { - ensureCapacity(curLength + 2); - addByte((byte) (i + 128), false); - addByte((byte) (i >> 8), false); - return this; - } - - public StaticPacketBuilder addShortA(int i) { - ensureCapacity(curLength + 2); - addByte((byte) (i >> 8), false); - addByte((byte) (i + 128), false); - return this; - } - - /** - * Adds a byte to the data buffer. The size of this packet will - * grow by one byte. - * - * @param val - * The byte value to add - * @return A reference to this object - */ - public StaticPacketBuilder addByte(byte val) { - return addByte(val, true); - } - - public StaticPacketBuilder addByteA(int i) { - return addByte((byte) (i + 128), true); - } - - /** - * Adds a byte to the data buffer. The size of this packet will - * grow by one byte. - * - * @param val - * The byte value to add - * @param checkCapacity - * Whether the buffer capacity should be checked - * @return A reference to this object - */ - private StaticPacketBuilder addByte(byte val, boolean checkCapacity) { - if (checkCapacity) { - ensureCapacity(curLength + 1); - } - payload[curLength++] = val; - return this; - } - - /** - * Adds a short to the data stream. The size of this packet - * will grow by two bytes. - * - * @param val - * The short value to add - * @return A reference to this object - */ - public StaticPacketBuilder addShort(int val) { - ensureCapacity(curLength + 2); - addByte((byte) (val >> 8), false); - addByte((byte) val, false); - return this; - } - - public StaticPacketBuilder addLEShort(int val) { - ensureCapacity(curLength + 2); - addByte((byte) val, false); - addByte((byte) (val >> 8), false); - return this; - } - - public StaticPacketBuilder setShort(int val, int offset) { - payload[offset++] = (byte) (val >> 8); - payload[offset++] = (byte) val; - if (curLength < offset + 2) { - curLength += 2; - } - return this; - } - - /** - * Adds a int to the data stream. The size of this packet will - * grow by four bytes. - * - * @param val - * The int value to add - * @return A reference to this object - */ - public StaticPacketBuilder addInt(int val) { - ensureCapacity(curLength + 4); - addByte((byte) (val >> 24), false); - addByte((byte) (val >> 16), false); - addByte((byte) (val >> 8), false); - addByte((byte) val, false); - return this; - } - - public StaticPacketBuilder addInt1(int val) { - ensureCapacity(curLength + 4); - addByte((byte) (val >> 8), false); - addByte((byte) val, false); - addByte((byte) (val >> 24), false); - addByte((byte) (val >> 16), false); - return this; - } - - public StaticPacketBuilder addInt2(int val) { - ensureCapacity(curLength + 4); - addByte((byte) (val >> 16), false); - addByte((byte) (val >> 24), false); - addByte((byte) val, false); - addByte((byte) (val >> 8), false); - return this; - } - - public StaticPacketBuilder addLEInt(int val) { - ensureCapacity(curLength + 4); - addByte((byte) val, false); - addByte((byte) (val >> 8), false); - addByte((byte) (val >> 16), false); - addByte((byte) (val >> 24), false); - return this; - } - - /** - * Adds a long to the data stream. The size of this packet will - * grow by eight bytes. - * - * @param val - * The long value to add - * @return A reference to this object - */ - public StaticPacketBuilder addLong(long val) { - addInt((int) (val >> 32)); - addInt((int) (val & -1L)); - return this; - } - - public StaticPacketBuilder addLELong(long val) { - addLEInt((int) (val & -1L)); - addLEInt((int) (val >> 32)); - return this; - } - - @SuppressWarnings("deprecation") - public StaticPacketBuilder addString(String s) { - ensureCapacity(curLength + s.length() + 1); - s.getBytes(0, s.length(), payload, curLength); - curLength += s.length(); - payload[curLength++] = 0; - return this; - } - - public int getLength() { - return curLength; - } - - /** - * Returns a Packet object for the data contained in this - * builder. - * - * @return A Packet object - */ - public Packet toPacket() { - byte[] data = new byte[curLength]; - System.arraycopy(payload, 0, data, 0, curLength); - return new Packet(null, id, data, bare, size); - } - - public StaticPacketBuilder addByteC(int val) { - addByte((byte) -val); - return this; - } - - public StaticPacketBuilder addByteS(int val) { - addByte((byte) (128 - val)); - return this; - } -} diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/PacketHandler.java b/2006Scape Server/src/main/java/com/rs2/net/packets/PacketHandler.java index 7054f9ba..db7a4471 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/PacketHandler.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/PacketHandler.java @@ -3,6 +3,7 @@ package com.rs2.net.packets; import com.rs2.GameConstants; import com.rs2.game.dialogues.Dialogue; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.impl.AttackPlayer; import com.rs2.net.packets.impl.Bank10; import com.rs2.net.packets.impl.Bank5; @@ -156,14 +157,16 @@ public class PacketHandler { } }*/ - public static void processPacket(Player player, int packetType, int packetSize) { + public static void processPacket(Player player, Packet packet) { + int packetType = packet.getOpcode(); + int packetSize = packet.getLength(); PacketType p = packetId[packetType]; - if(p != null && packetType > 0 && packetType < 257 && packetType == player.packetType && packetSize == player.packetSize) { + if(p != null && packetType > 0 && packetType < 257) { if (GameConstants.sendServerPackets && player.playerRights == 3) { player.getPacketSender().sendMessage("PacketType: " + packetType + ". PacketSize: " + packetSize + "."); } try { - p.processPacket(player, packetType, packetSize); + p.processPacket(player, packet); } catch(Exception e) { e.printStackTrace(); } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/PacketType.java b/2006Scape Server/src/main/java/com/rs2/net/packets/PacketType.java index 6d2a44f4..a96a7b75 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/PacketType.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/PacketType.java @@ -1,8 +1,9 @@ package com.rs2.net.packets; import com.rs2.game.players.Player; +import com.rs2.net.Packet; public interface PacketType { - public void processPacket(Player player, int packetType, int packetSize); + public void processPacket(Player player, Packet packet); } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/AttackPlayer.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/AttackPlayer.java index 96af1ed8..4435d28c 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/AttackPlayer.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/AttackPlayer.java @@ -8,6 +8,7 @@ import com.rs2.game.content.combat.range.RangeData; import com.rs2.game.items.ItemAssistant; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class AttackPlayer implements PacketType { @@ -15,23 +16,23 @@ public class AttackPlayer implements PacketType { public static final int ATTACK_PLAYER = 73, MAGE_PLAYER = 249; @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { player.endCurrentTask(); player.playerIndex = 0; player.npcIndex = 0; - switch (packetType) { + switch (packet.getOpcode()) { /** * Attack player **/ case ATTACK_PLAYER: - player.playerIndex = player.getInStream().readSignedWordBigEndian(); + player.playerIndex = packet.readSignedWordBigEndian(); if (PlayerHandler.players[player.playerIndex] == null) { break; } if (player.inDuelArena() && !player.duelingArena()) { - player.getChallengePlayer().processPacket(player, packetType, packetSize); + player.getChallengePlayer().processPacket(player, null); } if (player.respawnTimer > 0) { @@ -149,8 +150,8 @@ public class AttackPlayer implements PacketType { break; } - player.playerIndex = player.getInStream().readSignedWordA(); - int castingSpellId = player.getInStream().readSignedWordBigEndian(); + player.playerIndex = packet.readSignedWordA(); + int castingSpellId = packet.readSignedWordBigEndian(); player.castingSpellId = castingSpellId; player.usingMagic = false; diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank10.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank10.java index 6d9d3fe6..394cdd7d 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank10.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank10.java @@ -4,6 +4,7 @@ import com.rs2.GameConstants; import com.rs2.game.content.random.PartyRoom; import com.rs2.game.content.skills.crafting.JewelryMaking; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.Boundary; @@ -13,10 +14,10 @@ import com.rs2.world.Boundary; public class Bank10 implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int interfaceId = player.getInStream().readUnsignedWordBigEndian(); - int removeId = player.getInStream().readUnsignedWordA(); - int removeSlot = player.getInStream().readUnsignedWordA(); + public void processPacket(Player player, Packet packet) { + int interfaceId = packet.readUnsignedWordBigEndian(); + int removeId = packet.readUnsignedWordA(); + int removeSlot = packet.readUnsignedWordA(); player.endCurrentTask(); switch (interfaceId) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank5.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank5.java index 151ef121..d6d7e9ef 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank5.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Bank5.java @@ -4,6 +4,7 @@ import com.rs2.GameConstants; import com.rs2.game.content.random.PartyRoom; import com.rs2.game.content.skills.crafting.JewelryMaking; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.Boundary; @@ -13,10 +14,10 @@ import com.rs2.world.Boundary; public class Bank5 implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int interfaceId = player.getInStream().readSignedWordBigEndianA(); - int removeId = player.getInStream().readSignedWordBigEndianA(); - int removeSlot = player.getInStream().readSignedWordBigEndian(); + public void processPacket(Player player, Packet packet) { + int interfaceId = packet.readSignedWordBigEndianA(); + int removeId = packet.readSignedWordBigEndianA(); + int removeSlot = packet.readSignedWordBigEndian(); player.endCurrentTask(); switch (interfaceId) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankAll.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankAll.java index b13c4a6a..2a6ecc1e 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankAll.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankAll.java @@ -4,6 +4,7 @@ import com.rs2.game.content.random.PartyRoom; import com.rs2.game.items.GameItem; import com.rs2.game.items.ItemData; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.Boundary; @@ -13,10 +14,10 @@ import com.rs2.world.Boundary; public class BankAll implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int removeSlot = player.getInStream().readUnsignedWordA(); - int interfaceId = player.getInStream().readUnsignedWord(); - int removeId = player.getInStream().readUnsignedWordA(); + public void processPacket(Player player, Packet packet) { + int removeSlot = packet.readUnsignedWordA(); + int interfaceId = packet.readUnsignedWord(); + int removeId = packet.readUnsignedWordA(); player.endCurrentTask(); switch (interfaceId) { case 2274: diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankX1.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankX1.java index f7e400c3..baa22729 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankX1.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/BankX1.java @@ -1,6 +1,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -13,19 +14,19 @@ public class BankX1 implements PacketType { public int XremoveSlot, XinterfaceID, XremoveID, Xamount; @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { player.endCurrentTask(); - if (packetType == 135) { - player.xRemoveSlot = player.getInStream().readSignedWordBigEndian(); - player.xInterfaceId = player.getInStream().readUnsignedWordA(); - player.xRemoveId = player.getInStream().readSignedWordBigEndian(); + if (packet.getOpcode() == 135) { + player.xRemoveSlot = packet.readSignedWordBigEndian(); + player.xInterfaceId = packet.readUnsignedWordA(); + player.xRemoveId = packet.readSignedWordBigEndian(); } else { if (player.xInterfaceId == 7423) { player.getItemAssistant().bankItem(player.xRemoveId, player.xRemoveSlot, Xamount);// Depo 1 player.getItemAssistant().resetItems(7423); } } - if (packetType == PART1) { + if (packet.getOpcode() == PART1) { synchronized (player) { player.getOutStream().createFrame(27); } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChallengePlayer.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChallengePlayer.java index 604b2102..6b2fef48 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChallengePlayer.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChallengePlayer.java @@ -2,6 +2,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -10,10 +11,10 @@ import com.rs2.net.packets.PacketType; public class ChallengePlayer implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - switch (packetType) { + public void processPacket(Player player, Packet packet) { + switch (packet.getOpcode()) { case 128: - int answerPlayer = player.getInStream().readUnsignedWord(); + int answerPlayer = packet.readUnsignedWord(); if(PlayerHandler.players[answerPlayer] == null || answerPlayer == player.playerId) return; diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeAppearance.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeAppearance.java index f2d494d5..a3c33309 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeAppearance.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeAppearance.java @@ -1,6 +1,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -35,8 +36,8 @@ public class ChangeAppearance implements PacketType { }; @Override - public void processPacket(final Player player, final int packetType, final int packetSize) { - final int gender = player.getInStream().readSignedByte(); + public void processPacket(final Player player, Packet packet) { + final int gender = packet.readSignedByte(); if (gender != 0 && gender != 1) { return; @@ -44,7 +45,7 @@ public class ChangeAppearance implements PacketType { final int[] apperances = new int[MALE_VALUES.length]; // appearance values check for (int i = 0; i < apperances.length; i++) { - int value = player.getInStream().readSignedByte(); + int value = packet.readSignedByte(); if (value < (gender == 0 ? MALE_VALUES[i][0] : FEMALE_VALUES[i][0]) || value > (gender == 0 ? MALE_VALUES[i][1] : FEMALE_VALUES[i][1])) { @@ -55,7 +56,7 @@ public class ChangeAppearance implements PacketType { final int[] colors = new int[ALLOWED_COLORS.length]; // color value check for (int i = 0; i < colors.length; i++) { - int value = player.getInStream().readSignedByte(); + int value = packet.readSignedByte(); if (value < ALLOWED_COLORS[i][0] || value > ALLOWED_COLORS[i][1]) { value = ALLOWED_COLORS[i][0]; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeRegions.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeRegions.java index 0e4e0c23..8f54bc8d 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeRegions.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ChangeRegions.java @@ -5,6 +5,7 @@ import com.rs2.GameEngine; import com.rs2.game.content.music.Music; import com.rs2.game.globalworldobjects.Doors; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.GlobalDropsHandler; @@ -14,7 +15,7 @@ import com.rs2.world.GlobalDropsHandler; public class ChangeRegions implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { if (GameConstants.SOUND && player.musicOn) { Music.playMusic(player); } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Chat.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Chat.java index 6dbef47b..e2a507f1 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Chat.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Chat.java @@ -3,6 +3,7 @@ package com.rs2.net.packets.impl; import com.rs2.Connection; import com.rs2.game.players.Player; import com.rs2.game.players.antimacro.AntiSpam; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; @@ -12,13 +13,13 @@ import com.rs2.util.Misc; public class Chat implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - player.setChatTextEffects(player.getInStream().readUnsignedByteS()); - player.setChatTextColor(player.getInStream().readUnsignedByteS()); - player.setChatTextSize((byte) (player.packetSize - 2)); - player.inStream.readBytes_reverseA(player.getChatText(), player.getChatTextSize(), 0); - ReportHandler.addText(player.playerName, player.getChatText(), packetSize - 2); - String word = Misc.textUnpack(player.getChatText(), player.packetSize - 2).toLowerCase(); + public void processPacket(Player player, Packet packet) { + player.setChatTextEffects(packet.readUnsignedByteS()); + player.setChatTextColor(packet.readUnsignedByteS()); + player.setChatTextSize((byte) (packet.getLength() - 2)); + packet.readBytes_reverseA(player.getChatText(), player.getChatTextSize(), 0); + ReportHandler.addText(player.playerName, player.getChatText(), packet.getLength() - 2); + String word = Misc.textUnpack(player.getChatText(), packet.getLength() - 2).toLowerCase(); if (AntiSpam.blockedWords(player, word, true) && !Connection.isMuted(player)) { player.setChatTextUpdateRequired(true); } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickItem.java index f1ef35a2..8f1f8114 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickItem.java @@ -17,6 +17,7 @@ import com.rs2.game.items.impl.ExperienceLamp; import com.rs2.game.items.impl.Flowers; import com.rs2.game.items.impl.GodBooks; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.GameLogger; import com.rs2.util.Misc; @@ -27,11 +28,11 @@ import com.rs2.util.Misc; public class ClickItem implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { player.endCurrentTask(); - player.getInStream().readSignedWordBigEndianA(); - int itemSlot = player.getInStream().readUnsignedWordA(); - int itemId = player.getInStream().readUnsignedWordBigEndian(); + packet.readSignedWordBigEndianA(); + int itemSlot = packet.readUnsignedWordA(); + int itemId = packet.readUnsignedWordBigEndian(); if (itemId != player.playerItems[itemSlot] - 1) { return; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickNPC.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickNPC.java index 9dc57b90..0a6942f4 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickNPC.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickNPC.java @@ -12,6 +12,7 @@ import com.rs2.game.content.combat.range.RangeData; import com.rs2.game.items.ItemAssistant; import com.rs2.game.npcs.NpcHandler; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -23,7 +24,7 @@ public class ClickNPC implements PacketType { SECOND_CLICK = 17, THIRD_CLICK = 21; @Override - public void processPacket(final Player player, int packetType, int packetSize) { + public void processPacket(final Player player, Packet packet) { player.npcIndex = 0; player.npcClickIndex = 0; player.playerIndex = 0; @@ -32,7 +33,7 @@ public class ClickNPC implements PacketType { player.getCombatAssistant().resetPlayerAttack(); player.getPlayerAssistant().requestUpdates(); player.endCurrentTask(); - switch (packetType) { + switch (packet.getOpcode()) { /** * Attack npc melee or range @@ -61,7 +62,7 @@ public class ClickNPC implements PacketType { player.getPacketSender().sendMessage("I can't reach that."); break; } - player.npcIndex = player.getInStream().readUnsignedWordA(); + player.npcIndex = packet.readUnsignedWordA(); if (NpcHandler.npcs[player.npcIndex] == null) { player.npcIndex = 0; break; @@ -188,8 +189,8 @@ public class ClickNPC implements PacketType { // c.usingSpecial = false; // c.getItems().updateSpecialBar(); - player.npcIndex = player.getInStream().readSignedWordBigEndianA(); - int castingSpellId = player.getInStream().readSignedWordA(); + player.npcIndex = packet.readSignedWordBigEndianA(); + int castingSpellId = packet.readSignedWordA(); player.usingMagic = false; if (NpcHandler.npcs[player.npcIndex] == null) { @@ -230,7 +231,7 @@ public class ClickNPC implements PacketType { break; case FIRST_CLICK: - player.npcClickIndex = player.inStream.readSignedWordBigEndian(); + player.npcClickIndex = packet.readSignedWordBigEndian(); player.npcType = NpcHandler.npcs[player.npcClickIndex].npcType; if (player.goodDistance(NpcHandler.npcs[player.npcClickIndex].getX(), @@ -274,7 +275,7 @@ public class ClickNPC implements PacketType { } break; case SECOND_CLICK: - player.npcClickIndex = player.inStream.readUnsignedWordBigEndianA(); + player.npcClickIndex = packet.readUnsignedWordBigEndianA(); player.npcType = NpcHandler.npcs[player.npcClickIndex].npcType; if (player.goodDistance(NpcHandler.npcs[player.npcClickIndex].getX(), NpcHandler.npcs[player.npcClickIndex].getY(), player.getX(), @@ -318,7 +319,7 @@ public class ClickNPC implements PacketType { break; case THIRD_CLICK: - player.npcClickIndex = player.inStream.readSignedWord(); + player.npcClickIndex = packet.readSignedWord(); player.npcType = NpcHandler.npcs[player.npcClickIndex].npcType; if (player.goodDistance(NpcHandler.npcs[player.npcClickIndex].getX(), NpcHandler.npcs[player.npcClickIndex].getY(), player.getX(), diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickObject.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickObject.java index 4217c1fa..4495ece6 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickObject.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickObject.java @@ -16,6 +16,7 @@ import com.rs2.game.globalworldobjects.Doors; import com.rs2.game.npcs.NpcHandler; import com.rs2.game.objects.Objects; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.clip.Region; @@ -78,40 +79,40 @@ public class ClickObject implements PacketType { } @Override - public void processPacket(final Player player, int packetType, int packetSize) { + public void processPacket(final Player player, Packet packet) { player.clickObjectType = player.objectX = player.objectId = player.objectY = 0; player.getPlayerAssistant().resetFollow(); player.getCombatAssistant().resetPlayerAttack(); player.getPlayerAssistant().requestUpdates(); player.endCurrentTask(); - switch (packetType) { + switch (packet.getOpcode()) { case FIRST_CLICK: - player.objectX = player.getInStream().readSignedWordBigEndianA(); - player.objectId = player.getInStream().readUnsignedWord(); - player.objectY = player.getInStream().readUnsignedWordA(); + player.objectX = packet.readSignedWordBigEndianA(); + player.objectId = packet.readUnsignedWord(); + player.objectY = packet.readUnsignedWordA(); onObjectReached(player, (p) -> completeObjectClick(p, 1)); break; case SECOND_CLICK: - player.objectId = player.getInStream().readUnsignedWordBigEndianA(); - player.objectY = player.getInStream().readSignedWordBigEndian(); - player.objectX = player.getInStream().readUnsignedWordA(); + player.objectId = packet.readUnsignedWordBigEndianA(); + player.objectY = packet.readSignedWordBigEndian(); + player.objectX = packet.readUnsignedWordA(); onObjectReached(player, (p) -> completeObjectClick(p, 2)); break; case THIRD_CLICK: // 'F' - player.objectX = player.getInStream().readSignedWordBigEndian(); - player.objectY = player.getInStream().readUnsignedWord(); - player.objectId = player.getInStream().readUnsignedWordBigEndianA(); + player.objectX = packet.readSignedWordBigEndian(); + player.objectY = packet.readUnsignedWord(); + player.objectId = packet.readUnsignedWordBigEndianA(); onObjectReached(player, (p) -> completeObjectClick(p, 3)); break; case FOURTH_CLICK: - player.objectX = player.getInStream().readSignedWordBigEndianA(); - player.objectId = player.getInStream().readUnsignedWordA(); - player.objectY = player.getInStream().readUnsignedWordBigEndianA(); + player.objectX = packet.readSignedWordBigEndianA(); + player.objectId = packet.readUnsignedWordA(); + player.objectY = packet.readUnsignedWordBigEndianA(); onObjectReached(player, (p) -> completeObjectClick(p, 4)); break; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickTab.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickTab.java index 4a6f46e9..5f81e597 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickTab.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickTab.java @@ -2,13 +2,14 @@ package com.rs2.net.packets.impl; import com.rs2.game.items.ItemAssistant; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class ClickTab implements PacketType { @Override - public void processPacket(final Player player, int packetType, int packetSize) { - switch (packetSize) { + public void processPacket(final Player player, Packet packet) { + switch (packet.getLength()) { case 1:// first part. if (player.tutorialProgress == 0) { // wrench player.getPacketSender().chatbox(6180); diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingButtons.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingButtons.java index 50228c2e..f55de7ec 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingButtons.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingButtons.java @@ -34,6 +34,7 @@ import com.rs2.game.objects.impl.Climbing; import com.rs2.game.players.Client; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; import com.rs2.world.Boundary; @@ -44,8 +45,8 @@ import com.rs2.world.Boundary; public class ClickingButtons implements PacketType { @Override - public void processPacket(final Player player, int packetType, int packetSize) { - int actionButtonId = Misc.hexToInt(player.getInStream().buffer, 0, packetSize); + public void processPacket(final Player player, Packet packet) { + int actionButtonId = packet.readHex(); player.getGlassBlowing().handleActionButtin(actionButtonId); GnomeGlider.flightButtons(player, actionButtonId); player.getEmoteHandler().startEmote(actionButtonId); diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingInGame.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingInGame.java index 56790746..fb05fd26 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingInGame.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingInGame.java @@ -1,12 +1,13 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class ClickingInGame implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingStuff.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingStuff.java index 0abca27a..bc8473cc 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingStuff.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ClickingStuff.java @@ -2,6 +2,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; @@ -11,7 +12,7 @@ import com.rs2.util.Misc; public class ClickingStuff implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { if (player.playerIsBusy()) { player.playerIsBusy = false; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Commands.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Commands.java index b721cb1b..2dc75fe2 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Commands.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Commands.java @@ -11,6 +11,7 @@ import com.rs2.game.bots.BotHandler; import com.rs2.game.npcs.NpcHandler; import com.rs2.game.players.*; import com.rs2.game.players.antimacro.AntiSpam; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; import com.rs2.world.clip.Region; @@ -21,8 +22,8 @@ import java.util.GregorianCalendar; public class Commands implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - String[] messageArr = player.getInStream().readString().split(" "); + public void processPacket(Player player, Packet packet) { + String[] messageArr = packet.readString().split(" "); String playerCommand = messageArr[0]; String[] commandArguments = Arrays.copyOfRange(messageArr, 1, messageArr.length); if ((playerCommand.startsWith("ban") || playerCommand.startsWith("ip") || playerCommand.startsWith("mute") || playerCommand.startsWith("un")) && player.playerRights > 0 && player.playerRights < 4) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/DropItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/DropItem.java index 1e748e99..de6a86e4 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/DropItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/DropItem.java @@ -10,6 +10,7 @@ import com.rs2.game.items.ItemConstants; import com.rs2.game.items.impl.RareProtection; import com.rs2.game.npcs.impl.Pets; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -18,11 +19,11 @@ import com.rs2.net.packets.PacketType; public class DropItem implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int itemId = player.getInStream().readUnsignedWordA(); - player.getInStream().readUnsignedByte(); - player.getInStream().readUnsignedByte(); - int slot = player.getInStream().readUnsignedWordA(); + public void processPacket(Player player, Packet packet) { + int itemId = packet.readUnsignedWordA(); + packet.readUnsignedByte(); + packet.readUnsignedByte(); + int slot = packet.readUnsignedWordA(); if (!player.getItemAssistant().playerHasItem(itemId) || !RareProtection.removeItemOtherActions(player, itemId) || System.currentTimeMillis() - player.alchDelay < 1800 || player.stopPlayerPacket || System.currentTimeMillis() - player.buryDelay < 1800 || !CastleWars.deleteCastleWarsItems(player, itemId)) { return; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/FollowPlayer.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/FollowPlayer.java index 7801547d..3a1f45b5 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/FollowPlayer.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/FollowPlayer.java @@ -2,13 +2,14 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class FollowPlayer implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int followPlayer = player.getInStream().readUnsignedWordBigEndian(); + public void processPacket(Player player, Packet packet) { + int followPlayer = packet.readUnsignedWordBigEndian(); if (PlayerHandler.players[followPlayer] == null) { return; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/IdleLogout.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/IdleLogout.java index e6c9c56a..6026d3fc 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/IdleLogout.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/IdleLogout.java @@ -1,6 +1,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -10,7 +11,7 @@ import com.rs2.net.packets.PacketType; public class IdleLogout implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { if (player.underAttackBy > 0 || player.underAttackBy2 > 0 || player.isBot) { return; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/InterfaceX.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/InterfaceX.java index bbfbd8dd..91610617 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/InterfaceX.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/InterfaceX.java @@ -4,15 +4,16 @@ import com.rs2.game.content.random.PartyRoom; import com.rs2.game.content.skills.cooking.Cooking; import com.rs2.game.content.skills.smithing.Smelting; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.Boundary; public class InterfaceX implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { player.endCurrentTask(); - int Xamount = player.getInStream().readDWord(); + int Xamount = packet.readDWord(); if (Xamount < 0) { Xamount = player.getItemAssistant().getItemAmount(player.xRemoveId); } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2.java index ca3b6216..061765c3 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2.java @@ -3,6 +3,7 @@ package com.rs2.net.packets.impl; import com.rs2.event.impl.ItemSecondClickEvent; import com.rs2.game.items.impl.HandleEmpty; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -13,8 +14,8 @@ import com.rs2.net.packets.PacketType; public class ItemClick2 implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int itemId = player.getInStream().readSignedWordA(); + public void processPacket(Player player, Packet packet) { + int itemId = packet.readSignedWordA(); if (!player.getItemAssistant().playerHasItem(itemId, 1)) { return; diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2OnGroundItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2OnGroundItem.java index d0d35d9c..19643cf8 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2OnGroundItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick2OnGroundItem.java @@ -3,15 +3,16 @@ package com.rs2.net.packets.impl; import com.rs2.game.content.skills.firemaking.Firemaking; import com.rs2.game.content.skills.firemaking.LogData; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class ItemClick2OnGroundItem implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - final int itemX = player.getInStream().readSignedWordBigEndian(); - final int itemY = player.getInStream().readSignedWordBigEndianA(); - final int itemId = player.getInStream().readUnsignedWordA(); + public void processPacket(Player player, Packet packet) { + final int itemX = packet.readSignedWordBigEndian(); + final int itemY = packet.readSignedWordBigEndianA(); + final int itemId = packet.readUnsignedWordA(); System.out.println("ItemClick2OnGroundItem - " + player.playerName + " - " + itemId + " - " + itemX + " - " + itemY); // Reset position for the telekinetic guardian statue if (itemId == 6888) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick3.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick3.java index bd4061d0..7550b89d 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick3.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemClick3.java @@ -5,6 +5,7 @@ import com.rs2.game.content.skills.runecrafting.Runecrafting; import com.rs2.game.items.impl.HandleEmpty; import com.rs2.game.items.impl.Teles; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; @@ -17,10 +18,10 @@ import com.rs2.util.Misc; public class ItemClick3 implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int itemId11 = player.getInStream().readSignedWordBigEndianA(); - int itemId1 = player.getInStream().readSignedWordA(); - int itemId = player.getInStream().readSignedWordA(); + public void processPacket(Player player, Packet packet) { + int itemId11 = packet.readSignedWordBigEndianA(); + int itemId1 = packet.readSignedWordA(); + int itemId = packet.readSignedWordA(); if (!player.getItemAssistant().playerHasItem(itemId, 1)) { return; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnGroundItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnGroundItem.java index 984a2399..f5d0c5ab 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnGroundItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnGroundItem.java @@ -3,19 +3,20 @@ package com.rs2.net.packets.impl; import com.rs2.GameEngine; import com.rs2.game.content.skills.firemaking.Firemaking; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; public class ItemOnGroundItem implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - player.getInStream().readSignedWordBigEndian(); - int itemUsed = player.getInStream().readSignedWordA(); - int groundItem = player.getInStream().readUnsignedWord(); - int gItemY = player.getInStream().readSignedWordA(); - int itemUsedSlot = player.getInStream().readSignedWordBigEndianA(); - int gItemX = player.getInStream().readUnsignedWord(); + public void processPacket(Player player, Packet packet) { + packet.readSignedWordBigEndian(); + int itemUsed = packet.readSignedWordA(); + int groundItem = packet.readUnsignedWord(); + int gItemY = packet.readSignedWordA(); + int itemUsedSlot = packet.readSignedWordBigEndianA(); + int gItemX = packet.readUnsignedWord(); if (!player.getItemAssistant().playerHasItem(itemUsed, 1, itemUsedSlot)) { return; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnItem.java index 0064e1a0..5ad1a921 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnItem.java @@ -2,14 +2,15 @@ package com.rs2.net.packets.impl; import com.rs2.game.items.UseItem; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class ItemOnItem implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int usedWithSlot = player.getInStream().readUnsignedWord(); - int itemUsedSlot = player.getInStream().readUnsignedWordA(); + public void processPacket(Player player, Packet packet) { + int usedWithSlot = packet.readUnsignedWord(); + int itemUsedSlot = packet.readUnsignedWordA(); int useWith = player.playerItems[usedWithSlot] - 1; int itemUsed = player.playerItems[itemUsedSlot] - 1; if (!player.getItemAssistant().playerHasItem(useWith, 1, usedWithSlot)|| !player.getItemAssistant().playerHasItem(itemUsed, 1, itemUsedSlot)) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnNpc.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnNpc.java index 31492b89..93b8c5ed 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnNpc.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnNpc.java @@ -5,15 +5,16 @@ import com.rs2.game.content.skills.SkillHandler; import com.rs2.game.items.UseItem; import com.rs2.game.npcs.NpcHandler; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class ItemOnNpc implements PacketType { @Override - public void processPacket(final Player player, int packetType, int packetSize) { - final int itemId = player.getInStream().readSignedWordA(); - final int i = player.getInStream().readSignedWordA(); - final int slot = player.getInStream().readSignedWordBigEndian(); + public void processPacket(final Player player, Packet packet) { + final int itemId = packet.readSignedWordA(); + final int i = packet.readSignedWordA(); + final int slot = packet.readSignedWordBigEndian(); final int npcId = NpcHandler.npcs[i].npcType; SkillHandler.resetItemOnNpc(player); player.endCurrentTask(); diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnObject.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnObject.java index 735058ca..0c395b81 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnObject.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnObject.java @@ -12,6 +12,7 @@ import com.rs2.game.content.skills.prayer.Ectofuntus; import com.rs2.game.items.UseItem; import com.rs2.game.items.impl.Fillables; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.Boundary; import com.rs2.world.clip.Region; @@ -19,13 +20,13 @@ import com.rs2.world.clip.Region; public class ItemOnObject implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - player.getInStream().readUnsignedWord(); - int objectId = player.getInStream().readSignedWordBigEndian(); - int objectY = player.getInStream().readSignedWordBigEndianA(); - player.getInStream().readUnsignedWord(); - int objectX = player.getInStream().readSignedWordBigEndianA(); - int itemId = player.getInStream().readUnsignedWord(); + public void processPacket(Player player, Packet packet) { + packet.readUnsignedWord(); + int objectId = packet.readSignedWordBigEndian(); + int objectY = packet.readSignedWordBigEndianA(); + packet.readUnsignedWord(); + int objectX = packet.readSignedWordBigEndianA(); + int itemId = packet.readUnsignedWord(); player.turnPlayerTo(objectX, objectY); player.objectX = objectX; player.objectY = objectY; diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnPlayer.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnPlayer.java index 0d132a64..5af0ef47 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnPlayer.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ItemOnPlayer.java @@ -3,6 +3,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.items.impl.RareProtection; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; @@ -13,9 +14,9 @@ import com.rs2.util.Misc; public class ItemOnPlayer implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int playerId = player.inStream.readUnsignedWord(); - int itemId = player.playerItems[player.inStream.readSignedWordBigEndian()] - 1; + public void processPacket(Player player, Packet packet) { + int playerId = packet.readUnsignedWord(); + int itemId = player.playerItems[packet.readSignedWordBigEndian()] - 1; player.endCurrentTask(); switch (itemId) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnFloorItems.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnFloorItems.java index ba391f6c..6f37f9e6 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnFloorItems.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnFloorItems.java @@ -7,6 +7,7 @@ import com.rs2.event.CycleEventContainer; import com.rs2.event.CycleEventHandler; import com.rs2.game.content.combat.magic.MagicData; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.GlobalDropsHandler; import com.rs2.world.clip.PathFinder; @@ -18,11 +19,11 @@ import com.rs2.world.clip.PathFinder; public class MagicOnFloorItems implements PacketType { @Override - public void processPacket(final Player player, int packetType, int packetSize) { - final int itemY = player.getInStream().readSignedWordBigEndian(); - int itemId = player.getInStream().readUnsignedWord(); - final int itemX = player.getInStream().readSignedWordBigEndian(); - player.getInStream().readUnsignedWordA(); + public void processPacket(final Player player, Packet packet) { + final int itemY = packet.readSignedWordBigEndian(); + int itemId = packet.readUnsignedWord(); + final int itemX = packet.readSignedWordBigEndian(); + packet.readUnsignedWordA(); player.stopMovement(); if (!GameEngine.itemHandler.itemExists(itemId, itemX, itemY)) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnItems.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnItems.java index f975c809..bba8370e 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnItems.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnItems.java @@ -2,6 +2,7 @@ package com.rs2.net.packets.impl; import com.rs2.event.impl.MagicOnItemEvent; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -11,11 +12,11 @@ import com.rs2.net.packets.PacketType; public class MagicOnItems implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int slot = player.getInStream().readSignedWord(); - int itemId = player.getInStream().readSignedWordA(); - player.getInStream().readSignedWord(); - int spellId = player.getInStream().readSignedWordA(); + public void processPacket(Player player, Packet packet) { + int slot = packet.readSignedWord(); + int itemId = packet.readSignedWordA(); + packet.readSignedWord(); + int spellId = packet.readSignedWordA(); player.endCurrentTask(); if(!player.getItemAssistant().playerHasItem(itemId, 1, slot)) { return; diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnObject.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnObject.java index 10e664ec..4f3b7a06 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnObject.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MagicOnObject.java @@ -2,16 +2,17 @@ package com.rs2.net.packets.impl; import com.rs2.game.content.skills.crafting.OrbCharging; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class MagicOnObject implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int x = player.getInStream().readSignedWordBigEndian(); - int magicId = player.getInStream().readUnsignedWord(); - int y = player.getInStream().readUnsignedWordA(); - int objectId = player.getInStream().readSignedWordBigEndian(); + public void processPacket(Player player, Packet packet) { + int x = packet.readSignedWordBigEndian(); + int magicId = packet.readUnsignedWord(); + int y = packet.readUnsignedWordA(); + int objectId = packet.readSignedWordBigEndian(); player.turnPlayerTo(x, y); switch (objectId) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MoveItems.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MoveItems.java index af0df0e2..8af8d02c 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MoveItems.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/MoveItems.java @@ -1,6 +1,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -9,11 +10,11 @@ import com.rs2.net.packets.PacketType; public class MoveItems implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int interfaceId = player.getInStream().readSignedWordBigEndianA(); - boolean insertMode = player.getInStream().readSignedByteC() == 1; - int from = player.getInStream().readSignedWordBigEndianA(); - int to = player.getInStream().readSignedWordBigEndian(); + public void processPacket(Player player, Packet packet) { + int interfaceId = packet.readSignedWordBigEndianA(); + boolean insertMode = packet.readSignedByteC() == 1; + int from = packet.readSignedWordBigEndianA(); + int to = packet.readSignedWordBigEndian(); if (player.inTrade) { player.getTrading().declineTrade(); return; diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PickupItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PickupItem.java index 1655d006..29024fe8 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PickupItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PickupItem.java @@ -11,6 +11,7 @@ import com.rs2.game.content.skills.firemaking.LogData; import com.rs2.game.items.ItemAssistant; import com.rs2.game.items.impl.RareProtection; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.GameLogger; import com.rs2.world.Boundary; @@ -24,10 +25,10 @@ public class PickupItem implements PacketType { @Override - public void processPacket(final Player player, int packetType, int packetSize) { - player.pItemY = player.getInStream().readSignedWordBigEndian(); - player.pItemId = player.getInStream().readUnsignedWord(); - player.pItemX = player.getInStream().readSignedWordBigEndian(); + public void processPacket(final Player player, Packet packet) { + player.pItemY = packet.readSignedWordBigEndian(); + player.pItemId = packet.readUnsignedWord(); + player.pItemX = packet.readSignedWordBigEndian(); // Cannot pickup the telekinetic guardian statue, should show overview of current maze if (player.pItemId == 6888) { player.getMageTrainingArena().telekinetic.observeStatue(player.pItemX, player.pItemY); diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PrivateMessaging.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PrivateMessaging.java index e6be52a4..ba164806 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PrivateMessaging.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/PrivateMessaging.java @@ -6,6 +6,7 @@ import com.rs2.game.players.Client; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; import com.rs2.game.players.antimacro.AntiSpam; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.GameLogger; import com.rs2.util.Misc; @@ -19,12 +20,12 @@ public class PrivateMessaging implements PacketType { CHANGE_PM_STATUS = 95, REMOVE_IGNORE = 59, ADD_IGNORE = 133; @Override - public void processPacket(Player player, int packetType, int packetSize) { - switch (packetType) { + public void processPacket(Player player, Packet packet) { + switch (packet.getOpcode()) { case ADD_FRIEND: player.friendUpdate = true; - long friendToAdd = player.getInStream().readQWord(); + long friendToAdd = packet.readQWord(); boolean canAdd = true; for (long friend : player.friends) { @@ -55,13 +56,13 @@ public class PrivateMessaging implements PacketType { break; case SEND_PM: - long sendMessageToFriendId = player.getInStream().readQWord(); + long sendMessageToFriendId = packet.readQWord(); byte pmchatText[] = new byte[100]; - int pmchatTextSize = (byte) (packetSize - 8); - player.getInStream().readBytes(pmchatText, pmchatTextSize, 0); - String word = Misc.textUnpack(pmchatText, player.packetSize - 2).toLowerCase();// used + int pmchatTextSize = (byte) (packet.getLength() - 8); + packet.readBytes(pmchatText, pmchatTextSize, 0); + String word = Misc.textUnpack(pmchatText, packet.getLength() - 2).toLowerCase();// used if (player.getPlayerAssistant().isPlayer()) { - GameLogger.writeLog(player.playerName, "pmsent", player.playerName + " said " + Misc.textUnpack(pmchatText, packetSize - 8) + ""); + GameLogger.writeLog(player.playerName, "pmsent", player.playerName + " said " + Misc.textUnpack(pmchatText, packet.getLength() - 8) + ""); } if (!AntiSpam.blockedWords(player, word, false) || Connection.isMuted(player)) { return; @@ -78,7 +79,7 @@ public class PrivateMessaging implements PacketType { if (friend == sendMessageToFriendId) { o.getPacketSender().sendPM(Misc.playerNameToInt64(player.playerName), player.playerRights, pmchatText, pmchatTextSize); if (player.getPlayerAssistant().isPlayer()) { - GameLogger.writeLog(o.playerName, "pmrecieved", player.playerName + " said to " + o.playerName + " " + Misc.textUnpack(pmchatText, packetSize - 8) + ""); + GameLogger.writeLog(o.playerName, "pmrecieved", player.playerName + " said to " + o.playerName + " " + Misc.textUnpack(pmchatText, packet.getLength() - 8) + ""); } pmSent = true; } @@ -97,7 +98,7 @@ public class PrivateMessaging implements PacketType { case REMOVE_FRIEND: player.friendUpdate = true; - long friendToRemove = player.getInStream().readQWord(); + long friendToRemove = packet.readQWord(); for (int i1 = 0; i1 < player.friends.length; i1++) { if (player.friends[i1] == friendToRemove) { @@ -118,7 +119,7 @@ public class PrivateMessaging implements PacketType { case REMOVE_IGNORE: player.friendUpdate = true; - long ignore = player.getInStream().readQWord(); + long ignore = packet.readQWord(); for (int i = 0; i < player.ignores.length; i++) { if (player.ignores[i] == ignore) { @@ -129,7 +130,7 @@ public class PrivateMessaging implements PacketType { break; case CHANGE_PM_STATUS: - player.privateChat = player.getInStream().readUnsignedByte(); + player.privateChat = packet.readUnsignedByte(); for (int i1 = 1; i1 < PlayerHandler.players.length; i1++) { if (PlayerHandler.players[i1] != null && PlayerHandler.players[i1].isActive) { @@ -143,7 +144,7 @@ public class PrivateMessaging implements PacketType { case ADD_IGNORE: player.friendUpdate = true; - long ignoreAdd = player.getInStream().readQWord(); + long ignoreAdd = packet.readQWord(); for (int i = 0; i < player.ignores.length; i++) { if (player.ignores[i] == 0) { player.ignores[i] = ignoreAdd; diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/RemoveItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/RemoveItem.java index b8c24c28..ece1fa47 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/RemoveItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/RemoveItem.java @@ -6,6 +6,7 @@ import com.rs2.game.content.skills.crafting.JewelryMaking; import com.rs2.game.items.Weight; import com.rs2.game.items.impl.RareProtection; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.world.Boundary; @@ -15,10 +16,10 @@ import com.rs2.world.Boundary; public class RemoveItem implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int interfaceId = player.getInStream().readUnsignedWordA(); - int removeSlot = player.getInStream().readUnsignedWordA(); - int removeId = player.getInStream().readUnsignedWordA(); + public void processPacket(Player player, Packet packet) { + int interfaceId = packet.readUnsignedWordA(); + int removeSlot = packet.readUnsignedWordA(); + int removeId = packet.readUnsignedWordA(); if (!RareProtection.removeItem(player, removeId)) { return; } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Report.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Report.java index 5a1f7535..2a49e299 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Report.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Report.java @@ -1,14 +1,15 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; public class Report implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { try { - ReportHandler.handleReport(player); + ReportHandler.handleReport(player, packet); } catch (Exception e) { e.printStackTrace(); } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ReportHandler.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ReportHandler.java index 3c46bc94..4e8ed0d6 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ReportHandler.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/ReportHandler.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.util.Misc; public class ReportHandler { @@ -59,11 +60,11 @@ public class ReportHandler { * ex */ - public static void handleReport(Player c) throws Exception { - String player = Misc.longToReportPlayerName(c.inStream.readQWord2()); + public static void handleReport(Player c, Packet packet) throws Exception { + String player = Misc.longToReportPlayerName(packet.readQWord2()); player = player.replaceAll("_", " "); - byte rule = (byte) c.inStream.readUnsignedByte(); - int mute = c.getInStream().readUnsignedByte(); + byte rule = (byte) packet.readUnsignedByte(); + int mute = packet.readUnsignedByte(); if (c.lastReported.equalsIgnoreCase(player) && System.currentTimeMillis() - c.lastReport < 60000) { c.getPacketSender().sendMessage("You can only report a player once every 60 seconds."); diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/SilentPacket.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/SilentPacket.java index 2fe77250..00f75fda 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/SilentPacket.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/SilentPacket.java @@ -1,6 +1,7 @@ package com.rs2.net.packets.impl; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -9,7 +10,7 @@ import com.rs2.net.packets.PacketType; public class SilentPacket implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { } } diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Trade.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Trade.java index 11d5b62b..e0ee0109 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Trade.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Trade.java @@ -2,6 +2,7 @@ package com.rs2.net.packets.impl; import com.rs2.GameConstants; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -11,8 +12,8 @@ import com.rs2.net.packets.PacketType; public class Trade implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - int tradeId = player.getInStream().readSignedWordBigEndian(); + public void processPacket(Player player, Packet packet) { + int tradeId = packet.readSignedWordBigEndian(); player.getPlayerAssistant().resetFollow(); player.endCurrentTask(); if (player.disconnected) { diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Walking.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Walking.java index d3da2904..89930748 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Walking.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/Walking.java @@ -11,6 +11,7 @@ import com.rs2.game.items.impl.Greegree.MonkeyData; import com.rs2.game.players.Client; import com.rs2.game.players.Player; import com.rs2.game.players.PlayerHandler; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; /** @@ -19,7 +20,7 @@ import com.rs2.net.packets.PacketType; public class Walking implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { + public void processPacket(Player player, Packet packet) { player.getDueling().checkDuelWalk(); if (player.playerIsBusy()) { player.playerIsBusy = false; @@ -87,7 +88,7 @@ public class Walking implements PacketType { if (player.getPlayerAction().checkWalking() == false) { return; } - if (packetType == 248 || packetType == 164) { + if (packet.getOpcode() == 248 || packet.getOpcode() == 164) { player.faceUpdate(0); player.npcIndex = 0; player.playerIndex = 0; @@ -118,12 +119,12 @@ public class Walking implements PacketType { if (player.goodDistance(player.getX(), player.getY(), PlayerHandler.players[player.playerIndex].getX(), PlayerHandler.players[player.playerIndex].getY(), 1) - && packetType != 98) { + && packet.getOpcode() != 98) { player.playerIndex = 0; return; } } - if (packetType != 98) { + if (packet.getOpcode() != 98) { player.getPacketSender().sendMessage("A magical force stops you from moving."); player.playerIndex = 0; } @@ -136,7 +137,7 @@ public class Walking implements PacketType { return; } - if (packetType == 98) { + if (packet.getOpcode() == 98) { player.mageAllowed = true; } @@ -170,8 +171,8 @@ public class Walking implements PacketType { } player.endCurrentTask(); - - if (packetType == 248) { + int packetSize = packet.getLength(); + if (packet.getOpcode() == 248) { packetSize -= 14; } // @@ -234,20 +235,20 @@ public class Walking implements PacketType { int realY = 0; if (player.clickToTele) { - firstStepX = player.getInStream().readSignedWordBigEndianA(); + firstStepX = packet.readSignedWordBigEndianA(); } else { - realX = player.getInStream().readSignedWordBigEndianA(); + realX = packet.readSignedWordBigEndianA(); firstStepX = realX - player.getMapRegionX() * 8; } for (int i = 1; i < player.newWalkCmdSteps; i++) { - player.getNewWalkCmdX()[i] = player.getInStream().readSignedByte(); - player.getNewWalkCmdY()[i] = player.getInStream().readSignedByte(); + player.getNewWalkCmdX()[i] = packet.readSignedByte(); + player.getNewWalkCmdY()[i] = packet.readSignedByte(); } if (player.clickToTele) { - firstStepY = player.getInStream().readSignedWordBigEndian(); + firstStepY = packet.readSignedWordBigEndian(); } else { - realY = player.getInStream().readSignedWordBigEndian(); + realY = packet.readSignedWordBigEndian(); firstStepY = realY - player.getMapRegionY() * 8; } @@ -257,7 +258,7 @@ public class Walking implements PacketType { } } - player.setNewWalkCmdIsRunning(player.getInStream().readSignedByteC() == 1 && player.playerEnergy > 0); + player.setNewWalkCmdIsRunning(packet.readSignedByteC() == 1 && player.playerEnergy > 0); for (int i1 = 0; i1 < player.newWalkCmdSteps; i1++) { if (player.clickToTele) player.getPlayerAssistant().movePlayer(player.getNewWalkCmdX()[i1] + firstStepX, player.getNewWalkCmdY()[i1] + firstStepY, player.heightLevel); diff --git a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/WearItem.java b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/WearItem.java index 334262f0..a5bae4af 100644 --- a/2006Scape Server/src/main/java/com/rs2/net/packets/impl/WearItem.java +++ b/2006Scape Server/src/main/java/com/rs2/net/packets/impl/WearItem.java @@ -4,6 +4,7 @@ import com.rs2.GameConstants; import com.rs2.game.items.Weight; import com.rs2.game.items.impl.RareProtection; import com.rs2.game.players.Player; +import com.rs2.net.Packet; import com.rs2.net.packets.PacketType; import com.rs2.util.Misc; @@ -13,10 +14,10 @@ import com.rs2.util.Misc; public class WearItem implements PacketType { @Override - public void processPacket(Player player, int packetType, int packetSize) { - player.wearId = player.getInStream().readUnsignedWord(); - player.wearSlot = player.getInStream().readUnsignedWordA(); - player.interfaceId = player.getInStream().readUnsignedWordA(); + public void processPacket(Player player, Packet packet) { + player.wearId = packet.readUnsignedWord(); + player.wearSlot = packet.readUnsignedWordA(); + player.interfaceId = packet.readUnsignedWordA(); Weight.updateWeight(player); if (!RareProtection.equipItem(player)) { return; diff --git a/2006Scape Server/src/main/java/com/rs2/util/ISAACRandomGen.java b/2006Scape Server/src/main/java/com/rs2/util/ISAACRandomGen.java deleted file mode 100644 index fff0e16f..00000000 --- a/2006Scape Server/src/main/java/com/rs2/util/ISAACRandomGen.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.rs2.util; - -public class ISAACRandomGen { - - public int count; - public int[] results; - public int[] memory; - public int accumulator; - public int lastResult; - public int counter; - - public ISAACRandomGen(int[] seed) { - memory = new int[256]; - results = new int[256]; - System.arraycopy(seed, 0, results, 0, seed.length); - initializeKeySet(); - } - - public int getNextKey() { - // Server.add(Thread.currentThread().getName()); - // System.out.println(Thread.currentThread().getName()); - if (count-- == 0) { - generateNextKeySet(); - count = 255; - } - return results[count]; - } - - public void generateNextKeySet() { - lastResult += ++counter; - for (int i = 0; i < 256; i++) { - int j = memory[i]; - if ((i & 3) == 0) { - accumulator ^= accumulator << 13; - } else if ((i & 3) == 1) { - accumulator ^= accumulator >>> 6; - } else if ((i & 3) == 2) { - accumulator ^= accumulator << 2; - } else if ((i & 3) == 3) { - accumulator ^= accumulator >>> 16; - } - accumulator += memory[i + 128 & 0xff]; - int k; - memory[i] = k = memory[(j & 0x3fc) >> 2] + accumulator + lastResult; - results[i] = lastResult = memory[(k >> 8 & 0x3fc) >> 2] + j; - } - - } - - public void initializeKeySet() { - int i1; - int j1; - int k1; - int l1; - int i2; - int j2; - int k2; - int l = i1 = j1 = k1 = l1 = i2 = j2 = k2 = 0x9e3779b9; - for (int i = 0; i < 4; i++) { - l ^= i1 << 11; - k1 += l; - i1 += j1; - i1 ^= j1 >>> 2; - l1 += i1; - j1 += k1; - j1 ^= k1 << 8; - i2 += j1; - k1 += l1; - k1 ^= l1 >>> 16; - j2 += k1; - l1 += i2; - l1 ^= i2 << 10; - k2 += l1; - i2 += j2; - i2 ^= j2 >>> 4; - l += i2; - j2 += k2; - j2 ^= k2 << 8; - i1 += j2; - k2 += l; - k2 ^= l >>> 9; - j1 += k2; - l += i1; - } - - for (int j = 0; j < 256; j += 8) { - l += results[j]; - i1 += results[j + 1]; - j1 += results[j + 2]; - k1 += results[j + 3]; - l1 += results[j + 4]; - i2 += results[j + 5]; - j2 += results[j + 6]; - k2 += results[j + 7]; - l ^= i1 << 11; - k1 += l; - i1 += j1; - i1 ^= j1 >>> 2; - l1 += i1; - j1 += k1; - j1 ^= k1 << 8; - i2 += j1; - k1 += l1; - k1 ^= l1 >>> 16; - j2 += k1; - l1 += i2; - l1 ^= i2 << 10; - k2 += l1; - i2 += j2; - i2 ^= j2 >>> 4; - l += i2; - j2 += k2; - j2 ^= k2 << 8; - i1 += j2; - k2 += l; - k2 ^= l >>> 9; - j1 += k2; - l += i1; - memory[j] = l; - memory[j + 1] = i1; - memory[j + 2] = j1; - memory[j + 3] = k1; - memory[j + 4] = l1; - memory[j + 5] = i2; - memory[j + 6] = j2; - memory[j + 7] = k2; - } - - for (int k = 0; k < 256; k += 8) { - l += memory[k]; - i1 += memory[k + 1]; - j1 += memory[k + 2]; - k1 += memory[k + 3]; - l1 += memory[k + 4]; - i2 += memory[k + 5]; - j2 += memory[k + 6]; - k2 += memory[k + 7]; - l ^= i1 << 11; - k1 += l; - i1 += j1; - i1 ^= j1 >>> 2; - l1 += i1; - j1 += k1; - j1 ^= k1 << 8; - i2 += j1; - k1 += l1; - k1 ^= l1 >>> 16; - j2 += k1; - l1 += i2; - l1 ^= i2 << 10; - k2 += l1; - i2 += j2; - i2 ^= j2 >>> 4; - l += i2; - j2 += k2; - j2 ^= k2 << 8; - i1 += j2; - k2 += l; - k2 ^= l >>> 9; - j1 += k2; - l += i1; - memory[k] = l; - memory[k + 1] = i1; - memory[k + 2] = j1; - memory[k + 3] = k1; - memory[k + 4] = l1; - memory[k + 5] = i2; - memory[k + 6] = j2; - memory[k + 7] = k2; - } - - generateNextKeySet(); - count = 256; - } -} diff --git a/2006Scape Server/src/main/java/com/rs2/util/Misc.java b/2006Scape Server/src/main/java/com/rs2/util/Misc.java index 5d7ec279..064f31ff 100644 --- a/2006Scape Server/src/main/java/com/rs2/util/Misc.java +++ b/2006Scape Server/src/main/java/com/rs2/util/Misc.java @@ -124,20 +124,7 @@ public class Misc { } return temp.toUpperCase().trim(); } - - public static int hexToInt(byte data[], int offset, int len) { - int temp = 0; - int i = 1000; - for (int cntr = 0; cntr < len; cntr++) { - int num = (data[offset + cntr] & 0xFF) * i; - temp += num; - if (i > 1) { - i = i / 1000; - } - } - return temp; - } - + public static int random2(int range) { return (int) (java.lang.Math.random() * range + 1); } diff --git a/2006Scape Server/src/main/java/com/rs2/util/Stream.java b/2006Scape Server/src/main/java/com/rs2/util/Stream.java index 9717d5cc..9c62e080 100644 --- a/2006Scape Server/src/main/java/com/rs2/util/Stream.java +++ b/2006Scape Server/src/main/java/com/rs2/util/Stream.java @@ -1,5 +1,7 @@ package com.rs2.util; +import org.apollo.util.security.IsaacRandom; + import com.rs2.GameConstants; public class Stream { @@ -12,36 +14,6 @@ public class Stream { currentOffset = 0; } - public long readQWord2() { - final long l = readDWord() & 0xffffffffL; - final long l1 = readDWord() & 0xffffffffL; - return (l << 32) + l1; - } - - public byte readSignedByteA() { - return (byte) (buffer[currentOffset++] - 128); - } - - public byte readSignedByteC() { - return (byte) -buffer[currentOffset++]; - } - - public byte readSignedByteS() { - return (byte) (128 - buffer[currentOffset++]); - } - - public int readUnsignedByteA() { - return buffer[currentOffset++] - 128 & 0xff; - } - - public int readUnsignedByteC() { - return -buffer[currentOffset++] & 0xff; - } - - public int readUnsignedByteS() { - return 128 - buffer[currentOffset++] & 0xff; - } - public void writeByteA(int i) { ensureCapacity(1); buffer[currentOffset++] = (byte) (i + 128); @@ -56,49 +28,7 @@ public class Stream { ensureCapacity(1); buffer[currentOffset++] = (byte) -i; } - - public int readSignedWordBigEndian() { - currentOffset += 2; - int i = ((buffer[currentOffset - 1] & 0xff) << 8) + (buffer[currentOffset - 2] & 0xff); - if (i > 32767) { - i -= 0x10000; - } - return i; - } - - public int readSignedWordA() { - currentOffset += 2; - int i = ((buffer[currentOffset - 2] & 0xff) << 8) + (buffer[currentOffset - 1] - 128 & 0xff); - if (i > 32767) { - i -= 0x10000; - } - return i; - } - - public int readSignedWordBigEndianA() { - currentOffset += 2; - int i = ((buffer[currentOffset - 1] & 0xff) << 8) + (buffer[currentOffset - 2] - 128 & 0xff); - if (i > 32767) { - i -= 0x10000; - } - return i; - } - - public int readUnsignedWordBigEndian() { - currentOffset += 2; - return ((buffer[currentOffset - 1] & 0xff) << 8) + (buffer[currentOffset - 2] & 0xff); - } - - public int readUnsignedWordA() { - currentOffset += 2; - return ((buffer[currentOffset - 2] & 0xff) << 8) + (buffer[currentOffset - 1] - 128 & 0xff); - } - - public int readUnsignedWordBigEndianA() { - currentOffset += 2; - return ((buffer[currentOffset - 1] & 0xff) << 8) + (buffer[currentOffset - 2] - 128 & 0xff); - } - + public void writeWordBigEndianA(int i) { ensureCapacity(2); buffer[currentOffset++] = (byte) (i + 128); @@ -149,13 +79,6 @@ public class Stream { buffer[currentOffset++] = (byte) (i >> 8); } - public void readBytes_reverse(byte abyte0[], int i, int j) { - for (int k = j + i - 1; k >= j; k--) { - abyte0[k] = buffer[currentOffset++]; - } - - } - public void writeBytes_reverse(byte abyte0[], int i, int j) { ensureCapacity(i); for (int k = j + i - 1; k >= j; k--) { @@ -163,14 +86,6 @@ public class Stream { } } - public void readBytes_reverseA(byte abyte0[], int i, int j) { - ensureCapacity(i); - for (int k = j + i - 1; k >= j; k--) { - abyte0[k] = (byte) (buffer[currentOffset++] - 128); - } - - } - public void writeBytes_reverseA(byte abyte0[], int i, int j) { ensureCapacity(i); for (int k = j + i - 1; k >= j; k--) { @@ -181,7 +96,7 @@ public class Stream { public void createFrame(int id) { ensureCapacity(1); - buffer[currentOffset++] = (byte) (id + packetEncryption.getNextKey()); + buffer[currentOffset++] = (byte) (id + packetEncryption.nextInt()); } private static final int frameStackSize = 10; @@ -190,7 +105,7 @@ public class Stream { public void createFrameVarSize(int id) { ensureCapacity(3); - buffer[currentOffset++] = (byte) (id + packetEncryption.getNextKey()); + buffer[currentOffset++] = (byte) (id + packetEncryption.nextInt()); buffer[currentOffset++] = 0; if (frameStackPtr >= frameStackSize - 1) { throw new RuntimeException("Stack overflow"); @@ -201,7 +116,7 @@ public class Stream { public void createFrameVarSizeWord(int id) { ensureCapacity(2); - buffer[currentOffset++] = (byte) (id + packetEncryption.getNextKey()); + buffer[currentOffset++] = (byte) (id + packetEncryption.nextInt()); writeWord(0); if (frameStackPtr >= frameStackSize - 1) { throw new RuntimeException("Stack overflow"); @@ -301,57 +216,6 @@ public class Stream { buffer[currentOffset - i - 1] = (byte) i; } - public int readUnsignedByte() { - return buffer[currentOffset++] & 0xff; - } - - public byte readSignedByte() { - return buffer[currentOffset++]; - } - - public int readUnsignedWord() { - currentOffset += 2; - return ((buffer[currentOffset - 2] & 0xff) << 8) + (buffer[currentOffset - 1] & 0xff); - } - - public int readSignedWord() { - currentOffset += 2; - int i = ((buffer[currentOffset - 2] & 0xff) << 8) + (buffer[currentOffset - 1] & 0xff); - if (i > 32767) { - i -= 0x10000; - } - return i; - } - - public int readDWord() { - currentOffset += 4; - return ((buffer[currentOffset - 4] & 0xff) << 24) - + ((buffer[currentOffset - 3] & 0xff) << 16) - + ((buffer[currentOffset - 2] & 0xff) << 8) - + (buffer[currentOffset - 1] & 0xff); - } - - public long readQWord() { - long l = readDWord() & 0xffffffffL; - long l1 = readDWord() & 0xffffffffL; - return (l << 32) + l1; - } - - public java.lang.String readString() { - int i = currentOffset; - while (buffer[currentOffset++] != 10) { - ; - } - return new String(buffer, i, currentOffset - i - 1); - } - - public void readBytes(byte abyte0[], int i, int j) { - for (int k = j; k < j + i; k++) { - abyte0[k] = buffer[currentOffset++]; - } - - } - public void initBitAccess() { bitPosition = currentOffset * 8; } @@ -414,6 +278,6 @@ public class Stream { } } - public ISAACRandomGen packetEncryption = null; + public IsaacRandom packetEncryption = null; } diff --git a/2006Scape Server/src/main/java/com/rs2/world/clip/ObjectDefinition.java b/2006Scape Server/src/main/java/com/rs2/world/clip/ObjectDefinition.java index 6263b010..5393c76b 100644 --- a/2006Scape Server/src/main/java/com/rs2/world/clip/ObjectDefinition.java +++ b/2006Scape Server/src/main/java/com/rs2/world/clip/ObjectDefinition.java @@ -3,8 +3,8 @@ package com.rs2.world.clip; import java.io.IOException; import java.nio.ByteBuffer; -import org.apollo.archive.Archive; -import org.apollo.jagcached.fs.IndexedFileSystem; +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.archive.Archive; public final class ObjectDefinition { diff --git a/2006Scape Server/src/main/java/com/rs2/world/clip/RegionFactory.java b/2006Scape Server/src/main/java/com/rs2/world/clip/RegionFactory.java index 104db83d..aaf43bcc 100644 --- a/2006Scape Server/src/main/java/com/rs2/world/clip/RegionFactory.java +++ b/2006Scape Server/src/main/java/com/rs2/world/clip/RegionFactory.java @@ -1,15 +1,13 @@ package com.rs2.world.clip; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; import java.nio.ByteBuffer; +import java.nio.file.Paths; -import org.apollo.archive.Archive; -import org.apollo.archive.ArchiveEntry; -import org.apollo.archive.CompressionUtil; +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.archive.Archive; +import org.apollo.cache.archive.ArchiveEntry; import org.apollo.jagcached.Constants; -import org.apollo.jagcached.fs.IndexedFileSystem; +import org.apollo.util.CompressionUtil; public class RegionFactory { @@ -22,7 +20,7 @@ public class RegionFactory { public static void load() { //GameEngine.getLogger(Region.class).info("Loading region configurations..."); try { - IndexedFileSystem fs = new IndexedFileSystem(new File(Constants.FILE_SYSTEM_DIR), true); + IndexedFileSystem fs = new IndexedFileSystem(Paths.get(Constants.FILE_SYSTEM_DIR), true); ObjectDefinition.loadConfig(fs); Archive archive = Archive.decode(fs.getFile(0, 5)); @@ -56,8 +54,8 @@ public class RegionFactory { for (int i = 0; i < size; i++) { //GameEngine.getLogger(Region.class).info("Region: " + i + " RegionId: " + regionIds[i] + " ObjectsId: " + mapObjectsFileIds[i] // + " ClippingsId: " + mapGroundFileIds[i]); - byte[] file1 = CompressionUtil.degzip(fs.getFileBytes(4, mapObjectsFileIds[i])); - byte[] file2 = CompressionUtil.degzip(fs.getFileBytes(4, mapGroundFileIds[i])); + byte[] file1 = CompressionUtil.degzip(fs.getFile(4, mapObjectsFileIds[i])); + byte[] file2 = CompressionUtil.degzip(fs.getFile(4, mapGroundFileIds[i])); if (file1 == null || file2 == null) { continue; } diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/FileDescriptor.java b/2006Scape Server/src/main/java/org/apollo/cache/FileDescriptor.java similarity index 61% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/fs/FileDescriptor.java rename to 2006Scape Server/src/main/java/org/apollo/cache/FileDescriptor.java index 64587343..e5df5b4e 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/FileDescriptor.java +++ b/2006Scape Server/src/main/java/org/apollo/cache/FileDescriptor.java @@ -1,23 +1,27 @@ -package org.apollo.jagcached.fs; +package org.apollo.cache; + +import java.io.File; /** * A class which points to a file in the cache. + * * @author Graham */ public final class FileDescriptor { - - /** - * The file type. - */ - private final int type; - + /** * The file id. */ private final int file; - + + /** + * The file type. + */ + private final int type; + /** * Creates the file descriptor. + * * @param type The file type. * @param file The file id. */ @@ -25,21 +29,38 @@ public final class FileDescriptor { this.type = type; this.file = file; } - - /** - * Gets the file type. - * @return The file type. - */ - public int getType() { - return type; + + @Override + public boolean equals(Object obj) { + if (obj instanceof FileDescriptor) { + FileDescriptor other = (FileDescriptor) obj; + return type == other.type && file == other.file; + } + + return false; } - + /** * Gets the file id. + * * @return The file id. */ public int getFile() { return file; } -} + /** + * Gets the file type. + * + * @return The file type. + */ + public int getType() { + return type; + } + + @Override + public int hashCode() { + return file * FileSystemConstants.ARCHIVE_COUNT + type; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/FileSystemConstants.java b/2006Scape Server/src/main/java/org/apollo/cache/FileSystemConstants.java similarity index 83% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/fs/FileSystemConstants.java rename to 2006Scape Server/src/main/java/org/apollo/cache/FileSystemConstants.java index d9c9f1aa..d0c523ba 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/FileSystemConstants.java +++ b/2006Scape Server/src/main/java/org/apollo/cache/FileSystemConstants.java @@ -1,46 +1,42 @@ -package org.apollo.jagcached.fs; +package org.apollo.cache; /** * Holds file system related constants. + * * @author Graham */ public final class FileSystemConstants { - - /** - * The number of caches. - */ - public static final int CACHE_COUNT = 5; - + /** * The number of archives in cache 0. */ public static final int ARCHIVE_COUNT = 9; - - /** - * The size of an index. - */ - public static final int INDEX_SIZE = 6; - - /** - * The size of a header. - */ - public static final int HEADER_SIZE = 8; - + /** * The size of a chunk. */ public static final int CHUNK_SIZE = 512; - + + /** + * The size of a header. + */ + public static final int HEADER_SIZE = 8; + /** * The size of a block. */ public static final int BLOCK_SIZE = HEADER_SIZE + CHUNK_SIZE; + /** + * The size of an index. + */ + public static final int INDEX_SIZE = 6; + /** * Default private constructor to prevent instantiation. */ private FileSystemConstants() { - + } -} +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/Index.java b/2006Scape Server/src/main/java/org/apollo/cache/Index.java similarity index 67% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/fs/Index.java rename to 2006Scape Server/src/main/java/org/apollo/cache/Index.java index 647f8fe1..a0399697 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/Index.java +++ b/2006Scape Server/src/main/java/org/apollo/cache/Index.java @@ -1,40 +1,43 @@ -package org.apollo.jagcached.fs; +package org.apollo.cache; + +import com.google.common.base.Preconditions; /** * An {@link Index} points to a file in the {@code main_file_cache.dat} file. + * * @author Graham */ public final class Index { /** * Decodes a buffer into an index. + * * @param buffer The buffer. * @return The decoded {@link Index}. - * @throws IllegalArgumentException if the buffer length is invalid. + * @throws IllegalArgumentException If the buffer length is invalid. */ public static Index decode(byte[] buffer) { - if (buffer.length != FileSystemConstants.INDEX_SIZE) { - throw new IllegalArgumentException("Incorrect buffer length."); - } - - int size = ((buffer[0] & 0xFF) << 16) | ((buffer[1] & 0xFF) << 8) | (buffer[2] & 0xFF); - int block = ((buffer[3] & 0xFF) << 16) | ((buffer[4] & 0xFF) << 8) | (buffer[5] & 0xFF); - + Preconditions.checkArgument(buffer.length == FileSystemConstants.INDEX_SIZE, "Incorrect buffer length."); + + int size = (buffer[0] & 0xFF) << 16 | (buffer[1] & 0xFF) << 8 | buffer[2] & 0xFF; + int block = (buffer[3] & 0xFF) << 16 | (buffer[4] & 0xFF) << 8 | buffer[5] & 0xFF; + return new Index(size, block); } - - /** - * The size of the file. - */ - private final int size; - + /** * The first block of the file. */ private final int block; - + + /** + * The size of the file. + */ + private final int size; + /** * Creates the index. + * * @param size The size of the file. * @param block The first block of the file. */ @@ -42,21 +45,23 @@ public final class Index { this.size = size; this.block = block; } - - /** - * Gets the size of the file. - * @return The size of the file. - */ - public int getSize() { - return size; - } - + /** * Gets the first block of the file. + * * @return The first block of the file. */ public int getBlock() { return block; } -} + /** + * Gets the size of the file. + * + * @return The size of the file. + */ + public int getSize() { + return size; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/IndexedFileSystem.java b/2006Scape Server/src/main/java/org/apollo/cache/IndexedFileSystem.java new file mode 100644 index 00000000..43c83746 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/IndexedFileSystem.java @@ -0,0 +1,332 @@ +package org.apollo.cache; + +import com.google.common.base.Preconditions; +import org.apollo.cache.archive.Archive; + +import java.io.Closeable; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.CRC32; + +/** + * A file system based on top of the operating system's file system. It consists of a data file and index files. Index + * files point to blocks in the data file, which contains the actual data. + * + * @author Graham + */ +public final class IndexedFileSystem implements Closeable { + + /** + * The Map that caches already-decoded Archives. + */ + private final Map cache = new HashMap<>(FileSystemConstants.ARCHIVE_COUNT); + + /** + * The index files. + */ + private final RandomAccessFile[] indices = new RandomAccessFile[256]; + + /** + * Read only flag. + */ + private final boolean readOnly; + + /** + * The cached CRC table. + */ + private ByteBuffer crcTable; + + /** + * The {@link #crcTable} represented as an {@code int} array. + */ + private int[] crcs; + + /** + * The data file. + */ + private RandomAccessFile data; + + /** + * Creates the file system with the specified base directory. + * + * @param base The base directory. + * @param readOnly Indicates whether the file system will be read only or not. + * @throws FileNotFoundException If the data files could not be found. + */ + public IndexedFileSystem(Path base, boolean readOnly) throws FileNotFoundException { + this.readOnly = readOnly; + detectLayout(base); + } + + @Override + public void close() throws IOException { + if (data != null) { + synchronized (data) { + data.close(); + } + } + + for (RandomAccessFile index : indices) { + if (index != null) { + synchronized (index) { + index.close(); + } + } + } + } + + /** + * Gets the {@link Archive} pointed to by the specified {@link FileDescriptor}. + * + * @param type The file type. + * @param file The file id. + * @return The Archive. + * @throws IOException If there is an error decoding the Archive. + */ + public Archive getArchive(int type, int file) throws IOException { + FileDescriptor descriptor = new FileDescriptor(type, file); + Archive cached = cache.get(descriptor); + + if (cached == null) { + cached = Archive.decode(getFile(descriptor)); + + synchronized (this) { + cache.put(descriptor, cached); + } + } + + return cached; + } + + /** + * Gets the CRC table. + * + * @return The CRC table. + * @throws IOException If there is an error accessing files to create the table. + * @throws IllegalStateException If this file system is not read-only. + */ + public ByteBuffer getCrcTable() throws IOException { + if (readOnly) { + synchronized (this) { + if (crcTable != null) { + return crcTable.duplicate(); + } + } + + int archives = getFileCount(0); + int hash = 1234; + int[] crcs = new int[archives]; + + CRC32 crc32 = new CRC32(); + for (int i = 1; i < crcs.length; i++) { + crc32.reset(); + + ByteBuffer buffer = getFile(0, i); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes, 0, bytes.length); + crc32.update(bytes, 0, bytes.length); + + crcs[i] = (int) crc32.getValue(); + } + + ByteBuffer buffer = ByteBuffer.allocate((crcs.length + 1) * Integer.BYTES); + for (int crc : crcs) { + hash = (hash << 1) + crc; + buffer.putInt(crc); + } + + buffer.putInt(hash); + buffer.flip(); + + synchronized (this) { + crcTable = buffer.asReadOnlyBuffer(); + return crcTable.duplicate(); + } + } + + throw new IllegalStateException("Cannot get CRC table from a writable file system."); + } + + /** + * Gets the CRC table as an {@code int} array. + * + * @return The CRC table as an {@code int} array. + * @throws IOException If there is an error accessing files to create the table. + */ + public int[] getCrcs() throws IOException { + if (crcs == null) { + ByteBuffer buffer = getCrcTable(); + crcs = new int[(buffer.remaining() / Integer.BYTES) - 1]; + Arrays.setAll(crcs, crc -> buffer.getInt()); + } + return crcs; + } + + /** + * Gets a file. + * + * @param descriptor The {@link FileDescriptor} pointing to the file. + * @return A {@link ByteBuffer} containing the contents of the file. + * @throws IOException If there is an error decoding the file. + */ + public ByteBuffer getFile(FileDescriptor descriptor) throws IOException { + Index index = getIndex(descriptor); + ByteBuffer buffer = ByteBuffer.allocate(index.getSize()); + + long position = index.getBlock() * FileSystemConstants.BLOCK_SIZE; + int read = 0; + int size = index.getSize(); + int blocks = size / FileSystemConstants.CHUNK_SIZE; + if (size % FileSystemConstants.CHUNK_SIZE != 0) { + blocks++; + } + + for (int i = 0; i < blocks; i++) { + byte[] header = new byte[FileSystemConstants.HEADER_SIZE]; + synchronized (data) { + data.seek(position); + data.readFully(header); + } + + position += FileSystemConstants.HEADER_SIZE; + + int nextFile = (header[0] & 0xFF) << 8 | header[1] & 0xFF; + int curChunk = (header[2] & 0xFF) << 8 | header[3] & 0xFF; + int nextBlock = (header[4] & 0xFF) << 16 | (header[5] & 0xFF) << 8 | header[6] & 0xFF; + int nextType = header[7] & 0xFF; + + Preconditions.checkArgument(i == curChunk, "Chunk id mismatch."); + + int chunkSize = size - read; + if (chunkSize > FileSystemConstants.CHUNK_SIZE) { + chunkSize = FileSystemConstants.CHUNK_SIZE; + } + + byte[] chunk = new byte[chunkSize]; + synchronized (data) { + data.seek(position); + data.readFully(chunk); + } + buffer.put(chunk); + + read += chunkSize; + position = (long) nextBlock * (long) FileSystemConstants.BLOCK_SIZE; + + // if we still have more data to read, check the validity of the header + if (size > read) { + if (nextType != descriptor.getType() + 1) { + throw new IOException("File type mismatch."); + } + + if (nextFile != descriptor.getFile()) { + throw new IOException("File id mismatch."); + } + } + } + + buffer.flip(); + return buffer; + } + + /** + * Gets a file. + * + * @param type The file type. + * @param file The file id. + * @return A {@link ByteBuffer} which contains the contents of the file. + * @throws IOException If an I/O error occurs. + */ + public ByteBuffer getFile(int type, int file) throws IOException { + return getFile(new FileDescriptor(type, file)); + } + + /** + * Checks if this {@link IndexedFileSystem} is read only. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isReadOnly() { + return readOnly; + } + + /** + * Automatically detect the layout of the specified directory. + * + * @param base The base directory. + * @throws FileNotFoundException If the data files could not be found. + */ + private void detectLayout(Path base) throws FileNotFoundException { + int indexCount = 0; + for (int index = 0; index < indices.length; index++) { + Path idx = base.resolve("main_file_cache.idx" + index); + if (Files.exists(idx) && !Files.isDirectory(idx)) { + indexCount++; + indices[index] = new RandomAccessFile(idx.toFile(), readOnly ? "r" : "rw"); + } + } + if (indexCount <= 0) { + throw new FileNotFoundException("No index file(s) present in " + base + "."); + } + + Path resources = base.resolve("main_file_cache.dat"); + if (Files.exists(resources) && !Files.isDirectory(resources)) { + data = new RandomAccessFile(resources.toFile(), readOnly ? "r" : "rw"); + } else { + throw new FileNotFoundException("No data file present."); + } + } + + /** + * Gets the number of files with the specified type. + * + * @param type The type. + * @return The number of files. + * @throws IOException If there is an error getting the length of the specified index file. + * @throws IndexOutOfBoundsException If {@code type} is less than 0, or greater than or equal to the amount of + * indices. + */ + private int getFileCount(int type) throws IOException { + Preconditions.checkElementIndex(type, indices.length, "File type out of bounds."); + + RandomAccessFile indexFile = indices[type]; + synchronized (indexFile) { + return (int) (indexFile.length() / FileSystemConstants.INDEX_SIZE); + } + } + + /** + * Gets the index of a file. + * + * @param descriptor The {@link FileDescriptor} which points to the file. + * @return The {@link Index}. + * @throws IOException If there is an error reading from the index file. + * @throws IndexOutOfBoundsException If the descriptor type is less than 0, or greater than or equal to the amount + * of indices. + */ + private Index getIndex(FileDescriptor descriptor) throws IOException { + int index = descriptor.getType(); + Preconditions.checkElementIndex(index, indices.length, "File descriptor type out of bounds."); + + byte[] buffer = new byte[FileSystemConstants.INDEX_SIZE]; + RandomAccessFile indexFile = indices[index]; + synchronized (indexFile) { + long position = descriptor.getFile() * FileSystemConstants.INDEX_SIZE; + if (position >= 0 && indexFile.length() >= position + FileSystemConstants.INDEX_SIZE) { + indexFile.seek(position); + indexFile.readFully(buffer); + } else { + throw new FileNotFoundException("Could not find find index."); + } + } + + return Index.decode(buffer); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/archive/Archive.java b/2006Scape Server/src/main/java/org/apollo/cache/archive/Archive.java similarity index 60% rename from 2006Scape Server/src/main/java/org/apollo/archive/Archive.java rename to 2006Scape Server/src/main/java/org/apollo/cache/archive/Archive.java index 03c0eba0..896e202b 100644 --- a/2006Scape Server/src/main/java/org/apollo/archive/Archive.java +++ b/2006Scape Server/src/main/java/org/apollo/cache/archive/Archive.java @@ -1,12 +1,11 @@ -package org.apollo.archive; +package org.apollo.cache.archive; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; +import org.apollo.util.BufferUtil; +import org.apollo.util.CompressionUtil; /** * Represents an archive. @@ -23,15 +22,15 @@ public final class Archive { * @throws IOException If there is an error decompressing the archive. */ public static Archive decode(ByteBuffer buffer) throws IOException { - int extractedSize = Archive.readUnsignedMedium(buffer); - int size = Archive.readUnsignedMedium(buffer); + int extractedSize = BufferUtil.readUnsignedMedium(buffer); + int size = BufferUtil.readUnsignedMedium(buffer); boolean extracted = false; if (size != extractedSize) { byte[] compressed = new byte[size]; byte[] decompressed = new byte[extractedSize]; buffer.get(compressed); - Archive.debzip2(compressed, decompressed); + CompressionUtil.debzip2(compressed, decompressed); buffer = ByteBuffer.wrap(decompressed); extracted = true; } @@ -43,8 +42,8 @@ public final class Archive { for (int i = 0; i < entryCount; i++) { identifiers[i] = buffer.getInt(); - extractedSizes[i] = Archive.readUnsignedMedium(buffer); - sizes[i] = Archive.readUnsignedMedium(buffer); + extractedSizes[i] = BufferUtil.readUnsignedMedium(buffer); + sizes[i] = BufferUtil.readUnsignedMedium(buffer); } ArchiveEntry[] entries = new ArchiveEntry[entryCount]; @@ -54,7 +53,7 @@ public final class Archive { byte[] compressed = new byte[sizes[entry]]; byte[] decompressed = new byte[extractedSizes[entry]]; buffer.get(compressed); - Archive.debzip2(compressed, decompressed); + CompressionUtil.debzip2(compressed, decompressed); entryBuffer = ByteBuffer.wrap(decompressed); } else { byte[] buf = new byte[extractedSizes[entry]]; @@ -107,36 +106,5 @@ public final class Archive { public static int hash(String name) { return name.toUpperCase().chars().reduce(0, (hash, character) -> hash * 61 + character - 32); } - - /** - * Debzip2s the compressed array and places the result into the decompressed array. - * - * @param compressed The compressed array, without the header. - * @param decompressed The decompressed array. - * @throws IOException If there is an error decompressing the array. - */ - private static void debzip2(byte[] compressed, byte[] decompressed) throws IOException { - byte[] newCompressed = new byte[compressed.length + 4]; - newCompressed[0] = 'B'; - newCompressed[1] = 'Z'; - newCompressed[2] = 'h'; - newCompressed[3] = '1'; - System.arraycopy(compressed, 0, newCompressed, 4, compressed.length); - - try (DataInputStream is = new DataInputStream(new BZip2CompressorInputStream(new ByteArrayInputStream(newCompressed)))) { - is.readFully(decompressed); - } - } - - /** - * Reads a 24-bit medium integer from the specified {@link ByteBuffer}s current position and increases the buffers - * position by 3. - * - * @param buffer The {@link ByteBuffer} to read from. - * @return The read 24-bit medium integer. - */ - private static int readUnsignedMedium(ByteBuffer buffer) { - return (buffer.getShort() & 0xFFFF) << 8 | buffer.get() & 0xFF; - } } \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/archive/ArchiveEntry.java b/2006Scape Server/src/main/java/org/apollo/cache/archive/ArchiveEntry.java similarity index 96% rename from 2006Scape Server/src/main/java/org/apollo/archive/ArchiveEntry.java rename to 2006Scape Server/src/main/java/org/apollo/cache/archive/ArchiveEntry.java index 53ee35ef..ce95a437 100644 --- a/2006Scape Server/src/main/java/org/apollo/archive/ArchiveEntry.java +++ b/2006Scape Server/src/main/java/org/apollo/cache/archive/ArchiveEntry.java @@ -1,4 +1,4 @@ -package org.apollo.archive; +package org.apollo.cache.archive; import java.nio.ByteBuffer; diff --git a/2006Scape Server/src/main/java/org/apollo/cache/archive/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/archive/package-info.java new file mode 100644 index 00000000..35b89a22 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/archive/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains classes which deal with archives. + */ +package org.apollo.cache.archive; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/decoder/ItemDefinitionDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/decoder/ItemDefinitionDecoder.java new file mode 100644 index 00000000..5ba66621 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/decoder/ItemDefinitionDecoder.java @@ -0,0 +1,130 @@ +package org.apollo.cache.decoder; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.archive.Archive; +import org.apollo.cache.def.ItemDefinition; +import org.apollo.util.BufferUtil; + +/** + * Decodes item data from the {@code obj.dat} file into {@link ItemDefinition}s. + * + * @author Graham + */ +public final class ItemDefinitionDecoder implements Runnable { + + /** + * The IndexedFileSystem. + */ + private final IndexedFileSystem fs; + + /** + * Creates the ItemDefinitionDecoder. + * + * @param fs The {@link IndexedFileSystem}. + */ + public ItemDefinitionDecoder(IndexedFileSystem fs) { + this.fs = fs; + } + + @Override + public void run() { + try { + Archive config = fs.getArchive(0, 2); + ByteBuffer data = config.getEntry("obj.dat").getBuffer(); + ByteBuffer idx = config.getEntry("obj.idx").getBuffer(); + + int count = idx.getShort(), index = 2; + int[] indices = new int[count]; + for (int i = 0; i < count; i++) { + indices[i] = index; + index += idx.getShort(); + } + + ItemDefinition[] definitions = new ItemDefinition[count]; + for (int i = 0; i < count; i++) { + data.position(indices[i]); + definitions[i] = decode(i, data); + } + + ItemDefinition.init(definitions); + } catch (IOException e) { + throw new UncheckedIOException("Error decoding ItemDefinitions.", e); + } + } + + /** + * Decodes a single definition. + * + * @param id The item's id. + * @param buffer The buffer. + * @return The {@link ItemDefinition}. + */ + private ItemDefinition decode(int id, ByteBuffer buffer) { + ItemDefinition definition = new ItemDefinition(id); + while (true) { + int opcode = buffer.get() & 0xFF; + + if (opcode == 0) { + return definition; + } else if (opcode == 1) { + buffer.getShort(); + } else if (opcode == 2) { + definition.setName(BufferUtil.readString(buffer)); + } else if (opcode == 3) { + definition.setDescription(BufferUtil.readString(buffer)); + } else if (opcode >= 4 && opcode <= 8 || opcode == 10) { + buffer.getShort(); + } else if (opcode == 11) { + definition.setStackable(true); + } else if (opcode == 12) { + definition.setValue(buffer.getInt()); + } else if (opcode == 16) { + definition.setMembersOnly(true); + } else if (opcode == 23) { + buffer.getShort(); + buffer.get(); + } else if (opcode == 24) { + buffer.getShort(); + } else if (opcode == 25) { + buffer.getShort(); + buffer.get(); + } else if (opcode == 26) { + buffer.getShort(); + } else if (opcode >= 30 && opcode < 35) { + String str = BufferUtil.readString(buffer); + if (str.equalsIgnoreCase("hidden")) { + str = null; + } + definition.setGroundAction(opcode - 30, str); + } else if (opcode >= 35 && opcode < 40) { + definition.setInventoryAction(opcode - 35, BufferUtil.readString(buffer)); + } else if (opcode == 40) { + int colourCount = buffer.get() & 0xFF; + for (int i = 0; i < colourCount; i++) { + buffer.getShort(); + buffer.getShort(); + } + } else if (opcode == 78 || opcode == 79 || (opcode >= 90 && opcode <= 93) || opcode == 95) { + buffer.getShort(); + } else if (opcode == 97) { + definition.setNoteInfoId(buffer.getShort() & 0xFFFF); + } else if (opcode == 98) { + definition.setNoteGraphicId(buffer.getShort() & 0xFFFF); + } else if (opcode >= 100 && opcode < 110) { + buffer.getShort(); + buffer.getShort(); + } else if (opcode >= 110 && opcode <= 112) { + buffer.getShort(); + } else if (opcode == 113 || opcode == 114) { + buffer.get(); + } else if (opcode == 115) { + definition.setTeam(buffer.get() & 0xFF); + } + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/decoder/NpcDefinitionDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/decoder/NpcDefinitionDecoder.java new file mode 100644 index 00000000..aa5dfd20 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/decoder/NpcDefinitionDecoder.java @@ -0,0 +1,149 @@ +package org.apollo.cache.decoder; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.archive.Archive; +import org.apollo.cache.def.NpcDefinition; +import org.apollo.util.BufferUtil; + +/** + * Decodes npc data from the {@code npc.dat} file into {@link NpcDefinition}s. + * + * @author Major + */ +public final class NpcDefinitionDecoder implements Runnable { + + /** + * The IndexedFileSystem. + */ + private final IndexedFileSystem fs; + + /** + * Creates the NpcDefinitionDecoder. + * + * @param fs The {@link IndexedFileSystem}. + */ + public NpcDefinitionDecoder(IndexedFileSystem fs) { + this.fs = fs; + } + + @Override + public void run() { + try { + Archive config = fs.getArchive(0, 2); + ByteBuffer data = config.getEntry("npc.dat").getBuffer(); + ByteBuffer idx = config.getEntry("npc.idx").getBuffer(); + + int count = idx.getShort(), index = 2; + int[] indices = new int[count]; + + for (int i = 0; i < count; i++) { + indices[i] = index; + index += idx.getShort(); + } + + NpcDefinition[] definitions = new NpcDefinition[count]; + for (int i = 0; i < count; i++) { + data.position(indices[i]); + definitions[i] = decode(i, data); + } + + NpcDefinition.init(definitions); + } catch (IOException e) { + throw new UncheckedIOException("Error decoding NpcDefinitions.", e); + } + } + + /** + * Decodes a single definition. + * + * @param id The npc's id. + * @param buffer The buffer. + * @return The {@link NpcDefinition}. + */ + private NpcDefinition decode(int id, ByteBuffer buffer) { + NpcDefinition definition = new NpcDefinition(id); + + while (true) { + int opcode = buffer.get() & 0xFF; + + if (opcode == 0) { + return definition; + } else if (opcode == 1) { + int length = buffer.get() & 0xFF; + int[] models = new int[length]; + for (int index = 0; index < length; index++) { + models[index] = buffer.getShort(); + } + } else if (opcode == 2) { + definition.setName(BufferUtil.readString(buffer)); + } else if (opcode == 3) { + definition.setDescription(BufferUtil.readString(buffer)); + } else if (opcode == 12) { + definition.setSize(buffer.get()); + } else if (opcode == 13) { + definition.setStandAnimation(buffer.getShort()); + } else if (opcode == 14) { + definition.setWalkAnimation(buffer.getShort()); + } else if (opcode == 17) { + definition + .setWalkAnimations(buffer.getShort(), buffer.getShort(), buffer.getShort(), buffer.getShort()); + } else if (opcode >= 30 && opcode < 40) { + String action = BufferUtil.readString(buffer); + if (action.equals("hidden")) { + action = null; + } + + definition.setInteraction(opcode - 30, action); + } else if (opcode == 40) { + int length = buffer.get() & 0xFF; + int[] originalColours = new int[length]; + int[] replacementColours = new int[length]; + + for (int index = 0; index < length; index++) { + originalColours[index] = buffer.getShort(); + replacementColours[index] = buffer.getShort(); + } + } else if (opcode == 60) { + int length = buffer.get() & 0xFF; + int[] additionalModels = new int[length]; + + for (int index = 0; index < length; index++) { + additionalModels[index] = buffer.getShort(); + } + } else if (opcode >= 90 && opcode <= 92) { + buffer.getShort(); // Dummy + } else if (opcode == 95) { + definition.setCombatLevel(buffer.getShort()); + } else if (opcode == 97 || opcode == 98) { + buffer.getShort(); + } else if (opcode == 100 || opcode == 101) { + buffer.get(); + } else if (opcode == 102 || opcode == 103) { + buffer.getShort(); + } else if (opcode == 106) { + wrap(buffer.getShort()); + wrap(buffer.getShort()); + + int count = buffer.get() & 0xFF; + int[] morphisms = new int[count + 1]; + Arrays.setAll(morphisms, index -> wrap(buffer.getShort())); + } + } + } + + /** + * Wraps a morphism value around, returning -1 if the specified value is 65,535. + * + * @param value The value. + * @return -1 if {@code value} is 65,535, otherwise {@code value}. + */ + private int wrap(int value) { + return value == 65_535 ? -1 : value; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/decoder/ObjectDefinitionDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/decoder/ObjectDefinitionDecoder.java new file mode 100644 index 00000000..3ffc797a --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/decoder/ObjectDefinitionDecoder.java @@ -0,0 +1,142 @@ +package org.apollo.cache.decoder; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.archive.Archive; +import org.apollo.cache.def.ItemDefinition; +import org.apollo.cache.def.ObjectDefinition; +import org.apollo.util.BufferUtil; + +/** + * Decodes object data from the {@code loc.dat} file into {@link ObjectDefinition}s. + * + * @author Major + */ +public final class ObjectDefinitionDecoder implements Runnable { + + /** + * The IndexedFileSystem. + */ + private final IndexedFileSystem fs; + + /** + * Creates the ObjectDefinitionDecoder. + * + * @param fs The {@link IndexedFileSystem}. + */ + public ObjectDefinitionDecoder(IndexedFileSystem fs) { + this.fs = fs; + } + + @Override + public void run() { + try { + Archive config = fs.getArchive(0, 2); + ByteBuffer data = config.getEntry("loc.dat").getBuffer(); + ByteBuffer idx = config.getEntry("loc.idx").getBuffer(); + + int count = idx.getShort(), index = 2; + int[] indices = new int[count]; + for (int i = 0; i < count; i++) { + indices[i] = index; + index += idx.getShort(); + } + + ObjectDefinition[] definitions = new ObjectDefinition[count]; + for (int i = 0; i < count; i++) { + data.position(indices[i]); + definitions[i] = decode(i, data); + } + + ObjectDefinition.init(definitions); + } catch (IOException e) { + throw new UncheckedIOException("Error decoding ObjectDefinitions.", e); + } + } + + /** + * Decodes data from the cache into an {@link ObjectDefinition}. + * + * @param id The id of the object. + * @param data The {@link ByteBuffer} containing the data. + * @return The object definition. + */ + private ObjectDefinition decode(int id, ByteBuffer data) { + ObjectDefinition definition = new ObjectDefinition(id); + while (true) { + int opcode = data.get() & 0xFF; + + if (opcode == 0) { + return definition; + } else if (opcode == 1) { + int amount = data.get() & 0xFF; + for (int i = 0; i < amount; i++) { + data.getShort(); + data.get(); + } + } else if (opcode == 2) { + definition.setName(BufferUtil.readString(data)); + } else if (opcode == 3) { + definition.setDescription(BufferUtil.readString(data)); + } else if (opcode == 5) { + int amount = data.get() & 0xFF; + for (int i = 0; i < amount; i++) { + data.getShort(); + } + } else if (opcode == 14) { + definition.setWidth(data.get() & 0xFF); + } else if (opcode == 15) { + definition.setLength(data.get() & 0xFF); + } else if (opcode == 17) { + definition.setSolid(false); + } else if (opcode == 18) { + definition.setImpenetrable(false); + } else if (opcode == 19) { + definition.setInteractive((data.get() & 0xFF) == 1); + } else if (opcode == 24) { + data.getShort(); + } else if (opcode == 28 || opcode == 29) { + data.get(); + } else if (opcode >= 30 && opcode < 39) { + String[] actions = definition.getMenuActions(); + if (actions == null) { + actions = new String[10]; + } + String action = BufferUtil.readString(data); + actions[opcode - 30] = action; + definition.setMenuActions(actions); + } else if (opcode == 39) { + data.get(); + } else if (opcode == 40) { + int amount = data.get() & 0xFF; + for (int i = 0; i < amount; i++) { + data.getShort(); + data.getShort(); + } + } else if (opcode == 60 || opcode >= 65 && opcode <= 68) { + data.getShort(); + } else if (opcode == 69) { + data.get(); + } else if (opcode >= 70 && opcode <= 72) { + data.getShort(); + } else if (opcode == 73) { + definition.setObstructive(true); + } else if (opcode == 75) { + data.get(); + } else if (opcode == 77) { + data.getShort(); + data.getShort(); + int count = data.get(); + for (int i = 0; i <= count; i++) { + data.getShort(); + } + } else { + continue; + } + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/decoder/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/decoder/package-info.java new file mode 100644 index 00000000..43381ac2 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/decoder/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains classes which parse files within the game's cache. + */ +package org.apollo.cache.decoder; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/EquipmentDefinition.java b/2006Scape Server/src/main/java/org/apollo/cache/def/EquipmentDefinition.java new file mode 100644 index 00000000..9af643ad --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/def/EquipmentDefinition.java @@ -0,0 +1,310 @@ +package org.apollo.cache.def; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.base.Preconditions; + +/** + * Represents a type of Item that may be equipped. + * + * @author Graham + */ +public final class EquipmentDefinition { + + /** + * The attack id. + */ + private static final int ATTACK = 0; + + /** + * The defence id. + */ + private static final int DEFENCE = 1; + + /** + * The strength id. + */ + private static final int STRENGTH = 2; + + /** + * The hitpoints id. + */ + private static final int HITPOINTS = 3; + + /** + * The ranged id. + */ + private static final int RANGED = 4; + + /** + * The prayer id. + */ + private static final int PRAYER = 5; + + /** + * The magic id. + */ + private static final int MAGIC = 6; + + /** + * The equipment definitions. + */ + private static final Map definitions = new HashMap<>(); + + /** + * Gets the total number of equipment definitions. + * + * @return The count. + */ + public static int count() { + return definitions.size(); + } + + /** + * Initialises the equipment definitions. + * + * @param definitions The definitions. + * @throws RuntimeException If there is an id mismatch. + */ + public static void init(EquipmentDefinition[] definitions) { + for (int id = 0; id < definitions.length; id++) { + EquipmentDefinition def = definitions[id]; + if (def != null) { + if (def.getId() != id) { + throw new RuntimeException("Equipment definition id mismatch."); + } + EquipmentDefinition.definitions.put(def.getId(), def); + } + } + } + + /** + * Gets an equipment definition by its id. + * + * @param id The id. + * @return {@code null} if the item is not equipment, the definition otherwise. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public static EquipmentDefinition lookup(int id) { + Preconditions.checkElementIndex(id, ItemDefinition.count(), "Id out of bounds."); + return definitions.get(id); + } + + /** + * The item id. + */ + private final int id; + + /** + * The array of skill requirement levels. + */ + private final int[] levels = { 1, 1, 1, 1, 1, 1, 1 }; + + /** + * The slot this equipment goes into. + */ + private int slot; + + /** + * Various flags. + */ + private boolean twoHanded, fullBody, fullHat, fullMask; + + /** + * Creates a new equipment definition. + * + * @param id The id. + */ + public EquipmentDefinition(int id) { + this.id = id; + } + + /** + * Gets the minimum attack level required to equip this item. + * + * @return The level. + */ + public int getAttackLevel() { + return levels[ATTACK]; + } + + /** + * Gets the minimum defence level required to equip this item. + * + * @return The level. + */ + public int getDefenceLevel() { + return levels[DEFENCE]; + } + + /** + * Gets the minimum hitpoints level required to equip this item. + * + * @return The level. + */ + public int getHitpointsLevel() { + return levels[HITPOINTS]; + } + + /** + * Gets the minimum magic level required to equip this item. + * + * @return The level. + */ + public int getMagicLevel() { + return levels[MAGIC]; + } + + /** + * Gets the minimum prayer level required to equip this item. + * + * @return The level. + */ + public int getPrayerLevel() { + return levels[PRAYER]; + } + + /** + * Gets the minimum ranged level required to equip this item. + * + * @return The level. + */ + public int getRangedLevel() { + return levels[RANGED]; + } + + /** + * Gets the minimum strength level required to equip this item. + * + * @return The level. + */ + public int getStrengthLevel() { + return levels[STRENGTH]; + } + + /** + * Gets the id. + * + * @return The id. + */ + public int getId() { + return id; + } + + /** + * Gets the minimum level required to equip this item for a specific skill. + * + * @param skill The skill id. + * @return The level. + */ + public int getLevel(int skill) { + Preconditions.checkArgument(skill >= ATTACK && skill <= MAGIC, "Skill id out of bounds."); + return levels[skill]; + } + + /** + * Gets the target slot. + * + * @return The target slot. + */ + public int getSlot() { + return slot; + } + + /** + * Checks if this equipment is a full body. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isFullBody() { + return fullBody; + } + + /** + * Checks if this equipment is a full hat. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isFullHat() { + return fullHat; + } + + /** + * Checks if this equipment is a full mask. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isFullMask() { + return fullMask; + } + + /** + * Checks if this equipment is two-handed. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isTwoHanded() { + return twoHanded; + } + + /** + * Sets the flags. + * + * @param twoHanded The two handed flag. + * @param fullBody The full body flag. + * @param fullHat The full hat flag. + * @param fullMask The full mask flag. + */ + public void setFlags(boolean twoHanded, boolean fullBody, boolean fullHat, boolean fullMask) { + this.twoHanded = twoHanded; + this.fullBody = fullBody; + this.fullHat = fullHat; + this.fullMask = fullMask; + } + + /** + * Sets the required levels. + * + * @param attack The required attack level. + * @param strength The required strength level. + * @param defence The required defence level. + * @param ranged The required ranged level. + * @param prayer The required prayer level. + * @param magic The required magic level. + */ + public void setLevels(int attack, int strength, int defence, int ranged, int prayer, int magic) { + setLevels(attack, strength, defence, 1, ranged, prayer, magic); + } + + /** + * Sets the required levels. + * + * @param attack The required attack level. + * @param strength The required strength level. + * @param defence The required defence level. + * @param hitpoints The required hitpoints level. + * @param ranged The required ranged level. + * @param prayer The required prayer level. + * @param magic The required magic level. + */ + public void setLevels(int attack, int strength, int defence, int hitpoints, int ranged, int prayer, int magic) { + levels[ATTACK] = attack; + levels[STRENGTH] = strength; + levels[DEFENCE] = defence; + levels[HITPOINTS] = hitpoints; + levels[RANGED] = ranged; + levels[PRAYER] = prayer; + levels[MAGIC] = magic; + } + + /** + * Sets the target slot. + * + * @param slot The target slot. + */ + public void setSlot(int slot) { + this.slot = slot; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/ItemDefinition.java b/2006Scape Server/src/main/java/org/apollo/cache/def/ItemDefinition.java new file mode 100644 index 00000000..9c678f1d --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/def/ItemDefinition.java @@ -0,0 +1,411 @@ +package org.apollo.cache.def; + +import com.google.common.base.Preconditions; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +/** + * Represents a type of Item. + * + * @author Graham + */ +public final class ItemDefinition { + + /** + * The item definitions. + */ + private static ItemDefinition[] definitions; + + /** + * A map of item ids to noted ids. + */ + private static final BiMap notes = HashBiMap.create(); + + /** + * A map of noted ids to item ids. + */ + private static final BiMap notesInverse = notes.inverse(); + + /** + * Gets the total number of item definitions. + * + * @return The count. + */ + public static int count() { + return definitions.length; + } + + /** + * Gets the array of item definitions. + * + * @return The definitions. + */ + public static ItemDefinition[] getDefinitions() { + return definitions; + } + + /** + * Initialises the class with the specified set of definitions. + * + * @param definitions The definitions. + * @throws RuntimeException If there is an id mismatch. + */ + public static void init(ItemDefinition[] definitions) { + ItemDefinition.definitions = definitions; + for (int id = 0; id < definitions.length; id++) { + ItemDefinition def = definitions[id]; + if (def.getId() != id) { + throw new RuntimeException("Item definition id mismatch."); + } + if (def.isNote()) { + def.toNote(); + notes.put(def.getNoteInfoId(), def.getId()); + } + } + } + + /** + * Converts an item id to a noted id. + * + * @param id The item id. + * @return The noted id. + */ + public static int itemToNote(int id) { + Integer entry = notes.get(id); + if (entry == null) { + return id; + } + return entry; + } + + /** + * Gets the item definition for the specified id. + * + * @param id The id. + * @return The definition. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public static ItemDefinition lookup(int id) { + Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds."); + return definitions[id]; + } + + /** + * Converts a noted id to the normal item id. + * + * @param id The note id. + * @return The item id. + */ + public static int noteToItem(int id) { + Integer entry = notesInverse.get(id); + if (entry == null) { + return id; + } + return entry; + } + + /** + * The description of the item. + */ + private String description; + + /** + * The ground actions array. + */ + private final String[] groundActions = new String[5]; + + /** + * The item's id. + */ + private final int id; + + /** + * The inventory actions array. + */ + private final String[] inventoryActions = new String[5]; + + /** + * A flag indicating if this item is members only. + */ + private boolean members = false; + + /** + * The name of the item. + */ + private String name; + + /** + * The id of the item to copy note graphics from. + */ + private int noteGraphicId = -1; + + /** + * The id of the item to copy note info from. + */ + private int noteInfoId = -1; + + /** + * A flag indicating if this item is stackable. + */ + private boolean stackable = false; + + /** + * This item's team. + */ + private int team; + + /** + * The item's floor value. + */ + private int value = 1; + + /** + * Creates an item definition with the default values. + * + * @param id The item's id. + */ + public ItemDefinition(int id) { + this.id = id; + } + + /** + * Gets the description of this item. + * + * @return The item's description. + */ + public String getDescription() { + return description; + } + + /** + * Gets a ground action. + * + * @param id The id. + * @return The action. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public String getGroundAction(int id) { + Preconditions.checkElementIndex(id, groundActions.length, "Ground action id is out of bounds."); + return groundActions[id]; + } + + /** + * Gets this item's id. + * + * @return The id. + */ + public int getId() { + return id; + } + + /** + * Gets an inventory action. + * + * @param id The id. + * @return The action. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public String getInventoryAction(int id) { + Preconditions.checkElementIndex(id, inventoryActions.length, "Inventory action id is out of bounds."); + return inventoryActions[id]; + } + + /** + * Gets this item's name. + * + * @return The name. + */ + public String getName() { + return name; + } + + /** + * Gets this item's note graphic id. + * + * @return The note graphic id. + */ + public int getNoteGraphicId() { + return noteGraphicId; + } + + /** + * Gets this item's note info id. + * + * @return The note info id. + */ + public int getNoteInfoId() { + return noteInfoId; + } + + /** + * Gets this item's team. + * + * @return The team. + */ + public int getTeam() { + return team; + } + + /** + * Gets this item's value. + * + * @return The value. + */ + public int getValue() { + return value; + } + + /** + * Checks if this item is members only. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isMembersOnly() { + return members; + } + + /** + * Checks if this item is a note. + * + * @return {@code true} if so, {@code false} otherwise. + */ + public boolean isNote() { + return noteGraphicId != -1 && noteInfoId != -1; + } + + /** + * Checks if the item specified by this definition is stackable. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isStackable() { + return stackable; + } + + /** + * Sets this item's description. + * + * @param description The description. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Sets a ground action. + * + * @param id The id. + * @param action The action. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public void setGroundAction(int id, String action) { + Preconditions.checkElementIndex(id, groundActions.length, "Ground action id is out of bounds."); + groundActions[id] = action; + } + + /** + * Sets an inventory action. + * + * @param id The id. + * @param action The action. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public void setInventoryAction(int id, String action) { + Preconditions.checkElementIndex(id, inventoryActions.length, "Inventory action id is out of bounds."); + inventoryActions[id] = action; + } + + /** + * Sets this item's members only flag. + * + * @param members The flag. + */ + public void setMembersOnly(boolean members) { + this.members = members; + } + + /** + * Sets this item's name. + * + * @param name The name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Sets this item's note graphic id. + * + * @param noteGraphicId The note graphic id. + */ + public void setNoteGraphicId(int noteGraphicId) { + this.noteGraphicId = noteGraphicId; + } + + /** + * Sets this item's note info id. + * + * @param noteInfoId The note info id. + */ + public void setNoteInfoId(int noteInfoId) { + this.noteInfoId = noteInfoId; + } + + /** + * Sets this item's stackable flag. + * + * @param stackable The stackable flag. + */ + public void setStackable(boolean stackable) { + this.stackable = stackable; + } + + /** + * Sets this item's team. + * + * @param team The team. + */ + public void setTeam(int team) { + this.team = team; + } + + /** + * sets this item's value. + * + * @param value The value. + */ + public void setValue(int value) { + this.value = value; + } + + /** + * Converts this item to a note, if possible. + * + * @throws IllegalStateException If {@link ItemDefinition#isNote()} returns {@code false}. + */ + public void toNote() { + if (isNote()) { + if (description != null && description.startsWith("Swap this note at any bank for ")) { + return; // already converted. + } + + ItemDefinition infoDef = lookup(noteInfoId); + name = infoDef.name; + members = infoDef.members; + + String prefix = "a"; + char firstChar = name == null ? 'n' : name.charAt(0); + + if (firstChar == 'A' || firstChar == 'E' || firstChar == 'I' || firstChar == 'O' || firstChar == 'U') { + prefix = "an"; + } + + description = "Swap this note at any bank for " + prefix + " " + name + "."; + value = infoDef.value; + stackable = true; + } else { + throw new IllegalStateException("Item cannot be noted."); + } + } + +} diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/NpcDefinition.java b/2006Scape Server/src/main/java/org/apollo/cache/def/NpcDefinition.java new file mode 100644 index 00000000..0e81396d --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/def/NpcDefinition.java @@ -0,0 +1,365 @@ +package org.apollo.cache.def; + +import com.google.common.base.Preconditions; + +/** + * Represents a type of Npc. + * + * @author Chris Fletcher + */ +public final class NpcDefinition { + + /** + * The npc definitions. + */ + private static NpcDefinition[] definitions; + + /** + * Gets the total number of npc definitions. + * + * @return The count. + */ + public static int count() { + return definitions.length; + } + + /** + * Gets the array of npc definitions. + * + * @return The definitions. + */ + public static NpcDefinition[] getDefinitions() { + return definitions; + } + + /** + * Initialises the class with the specified set of definitions. + * + * @param definitions The definitions. + * @throws IllegalStateException If there is an id mismatch. + */ + public static void init(NpcDefinition[] definitions) { + NpcDefinition.definitions = definitions; + for (int id = 0; id < definitions.length; id++) { + NpcDefinition def = definitions[id]; + if (def.getId() != id) { + throw new IllegalStateException("Npc definition id mismatch."); + } + } + } + + /** + * Gets the npc definition for the specified id. + * + * @param id The id. + * @return The definition. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public static NpcDefinition lookup(int id) { + Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds."); + return definitions[id]; + } + + /** + * The combat level of the npc. + */ + private int combatLevel = -1; + + /** + * The description of the npc. + */ + private String description; + + /** + * The npc id. + */ + private final int id; + + /** + * An array of interaction options. + */ + private final String[] interactions = new String[5]; + + /** + * The name of the npc. + */ + private String name; + + /** + * The npc's size, in tiles. + */ + private int size = 1; + + /** + * The various animation ids. + */ + private int standAnim = -1, walkAnim = -1, walkBackAnim = -1, walkLeftAnim = -1, walkRightAnim = -1; + + /** + * Creates a new npc definition. + * + * @param id The npc id. + */ + public NpcDefinition(int id) { + this.id = id; + } + + /** + * Gets the npc's combat level. + * + * @return The combat level, or -1 if it doesn't have one. + */ + public int getCombatLevel() { + return combatLevel; + } + + /** + * Gets the description of the npc. + * + * @return The description. + */ + public String getDescription() { + return description; + } + + /** + * Gets the npc id. + * + * @return The npc id. + */ + public int getId() { + return id; + } + + /** + * Gets an interaction option. + * + * @param slot The slot of the option. + * @return The option, or {@code null} if there isn't any at the specified slot. + * @throws IndexOutOfBoundsException If the slot is out of bounds. + */ + public String getInteraction(int slot) { + Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds."); + return interactions[slot]; + } + + /** + * Gets the array of interaction options. + * + * @return The interaction options. + */ + public String[] getInteractions() { + return interactions; + } + + /** + * Gets the name of the npc. + * + * @return The name of the npc. + */ + public String getName() { + return name; + } + + /** + * Gets the npc's size, in tiles. + * + * @return The size. + */ + public int getSize() { + return size; + } + + /** + * Gets the id of the npc's standing animation. + * + * @return The stand animation id, or -1 if it doesn't have one. + */ + public int getStandAnimation() { + return standAnim; + } + + /** + * Gets the walking animation of the npc. + * + * @return The walking animation. + */ + public int getWalkAnimation() { + return walkAnim; + } + + /** + * Gets the walk-back animation of the npc. + * + * @return The walk-back animation. + */ + public int getWalkBackAnimation() { + return walkBackAnim; + } + + /** + * Gets the walk-left animation of the npc. + * + * @return The walk-left animation. + */ + public int getWalkLeftAnimation() { + return walkLeftAnim; + } + + /** + * Gets the walk-right animation of the npc. + * + * @return The walk-right animation. + */ + public int getWalkRightAnimation() { + return walkRightAnim; + } + + /** + * Checks if the npc has a combat level. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean hasCombatLevel() { + return combatLevel != -1; + } + + /** + * Checks if there is an interaction option present. + * + * @param slot The slot to check. + * @return {@code true} if so, {@code false} if not. + * @throws IndexOutOfBoundsException If the slot is out of bounds. + */ + public boolean hasInteraction(int slot) { + Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds."); + return interactions[slot] != null; + } + + /** + * Checks if the npc has a standing animation id. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean hasStandAnimation() { + return standAnim != -1; + } + + /** + * Checks if the npc has a walking animation. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean hasWalkAnimation() { + return walkAnim != -1; + } + + /** + * Checks if the npc has a walk-back animation. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean hasWalkBackAnimation() { + return walkBackAnim != -1; + } + + /** + * Checks if the npc has a walk-left animation. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean hasWalkLeftAnimation() { + return walkLeftAnim != -1; + } + + /** + * Checks if the npc has a walk-right animation. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean hasWalkRightAnimation() { + return walkRightAnim != -1; + } + + /** + * Sets the npc's combat level. + * + * @param combatLevel The combat level. + */ + public void setCombatLevel(int combatLevel) { + this.combatLevel = combatLevel; + } + + /** + * Sets the description of the npc. + * + * @param description The description. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Sets an interaction option. + * + * @param slot The slot of the option. + * @param interaction The interaction options. + * @throws IndexOutOfBoundsException If the slot is out of bounds. + */ + public void setInteraction(int slot, String interaction) { + Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds."); + interactions[slot] = interaction; + } + + /** + * Sets the name of the npc. + * + * @param name The name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Sets the size of the npc, in tiles. + * + * @param size The size. + */ + public void setSize(int size) { + this.size = size; + } + + /** + * Sets the id of the npc's standing animation. + * + * @param standAnim The stand animation id. + */ + public void setStandAnimation(int standAnim) { + this.standAnim = standAnim; + } + + /** + * Sets the walking animation of the npc. + * + * @param walkAnim The walking animation. + */ + public void setWalkAnimation(int walkAnim) { + this.walkAnim = walkAnim; + } + + /** + * Sets the various walking animations of the npc. + * + * @param walkAnim The walking animation. + * @param walkBackAnim The walk-back animation. + * @param walkLeftAnim The walk-left animation. + * @param walkRightAnim The walk-right animation. + */ + public void setWalkAnimations(int walkAnim, int walkBackAnim, int walkLeftAnim, int walkRightAnim) { + this.walkAnim = walkAnim; + this.walkBackAnim = walkBackAnim; + this.walkLeftAnim = walkLeftAnim; + this.walkRightAnim = walkRightAnim; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/ObjectDefinition.java b/2006Scape Server/src/main/java/org/apollo/cache/def/ObjectDefinition.java new file mode 100644 index 00000000..8f054307 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/def/ObjectDefinition.java @@ -0,0 +1,293 @@ +package org.apollo.cache.def; + +import com.google.common.base.Preconditions; + +/** + * Represents a type of GameObject. + * + * @author Major + */ +public final class ObjectDefinition { + + /** + * The array of game object definitions. + */ + private static ObjectDefinition[] definitions; + + /** + * Gets the total number of object definitions. + * + * @return The count. + */ + public static int count() { + return definitions.length; + } + + /** + * Gets the array of object definitions. + * + * @return The definitions. + */ + public static ObjectDefinition[] getDefinitions() { + return definitions; + } + + /** + * Initialises the object definitions. + * + * @param definitions The decoded definitions. + * @throws RuntimeException If there is an id mismatch. + */ + public static void init(ObjectDefinition[] definitions) { + ObjectDefinition.definitions = definitions; + for (int id = 0; id < definitions.length; id++) { + ObjectDefinition def = definitions[id]; + if (def.getId() != id) { + throw new RuntimeException("Item definition id mismatch."); + } + } + } + + /** + * Gets the object definition for the specified id. + * + * @param id The id of the object. + * @return The definition. + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + public static ObjectDefinition lookup(int id) { + Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds."); + return definitions[id]; + } + + /** + * The object's description. + */ + private String description; + + /** + * The object's id. + */ + private final int id; + + /** + * Denotes whether this object is impenetrable or not. + */ + private boolean impenetrable = true; + + /** + * Denotes whether this object has actions associated with it or not. + */ + private boolean interactive; + + /** + * Denotes whether or not this object obstructs the ground. + */ + private boolean obstructive; + + /** + * This object's length. + */ + private int length = 1; + + /** + * The object's menu actions. + */ + private String[] menuActions; + + /** + * The object's name. + */ + private String name; + + /** + * Denotes whether the object can be walked over or not. + */ + private boolean solid = true; + + /** + * This object's width. + */ + private int width = 1; + + /** + * Creates a new object definition. + * + * @param id The id of the object. + */ + public ObjectDefinition(int id) { + this.id = id; + } + + /** + * Gets the description of this object. + * + * @return The description. + */ + public String getDescription() { + return description; + } + + /** + * Gets the id of this object. + * + * @return The id. + */ + public int getId() { + return id; + } + + /** + * Gets the length of this object. + * + * @return The length. + */ + public int getLength() { + return length; + } + + /** + * Gets the menu actions of this object. + * + * @return The menu actions. + */ + public String[] getMenuActions() { + return menuActions; + } + + /** + * Gets the name of this object. + * + * @return The name. + */ + public String getName() { + return name; + } + + /** + * Gets the with of this object. + * + * @return The width. + */ + public int getWidth() { + return width; + } + + /** + * Indicates the impenetrability of this object. + * + * @return {@code true} if this object is impenetrable, otherwise {@code false}. + */ + public boolean isImpenetrable() { + return impenetrable; + } + + /** + * Indicates the interactivity of this object. + * + * @return {@code true} if the object is interactive, otherwise {@code false}. + */ + public boolean isInteractive() { + return interactive; + } + + /** + * Indicates whether or not this object obstructs the ground. + * + * @return {@code true} if the object obstructs the ground otherwise {@code false}. + */ + public boolean isObstructive() { + return obstructive; + } + + /** + * Indicates the solidity of this object. + * + * @return {@code true} if this object is solid, otherwise {@code false}. + */ + public boolean isSolid() { + return solid; + } + + /** + * Sets the description of this object. + * + * @param description The description. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Sets the impenetrability of this object. + * + * @param impenetrable The impenetrability. + */ + public void setImpenetrable(boolean impenetrable) { + this.impenetrable = impenetrable; + } + + /** + * Sets the interactivity of this object. + * + * @param interactive The interactivity. + */ + public void setInteractive(boolean interactive) { + this.interactive = interactive; + } + + /** + * Sets the length of this object. + * + * @param length The length. + */ + public void setLength(int length) { + this.length = length; + } + + /** + * Sets the menu actions of this object. + * + * @param menuActions The menu actions. + */ + public void setMenuActions(String[] menuActions) { + this.menuActions = menuActions; + } + + /** + * Sets the name of this object. + * + * @param name The name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Sets the solidity of this object. + * + * @param solid The solidity. + */ + public void setSolid(boolean solid) { + this.solid = solid; + } + + /** + * Sets the width of this object. + * + * @param width The width. + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * Sets whether or not this object is obstructive to the ground. + * + * @param obstructive Whether or not this object obstructs the ground. + */ + public void setObstructive(boolean obstructive) { + this.obstructive = obstructive; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/def/package-info.java new file mode 100644 index 00000000..a0298a85 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/def/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains definition classes which contain information about types of items, NPCs, etc. + */ +package org.apollo.cache.def; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapConstants.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapConstants.java new file mode 100644 index 00000000..63492978 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapConstants.java @@ -0,0 +1,62 @@ +package org.apollo.cache.map; + +/** + * Contains {@link MapFile}-related constants. + * + * @author Major + */ +public final class MapConstants { + + /** + * The index containing the map files. + */ + public static final int MAP_INDEX = 4; + + /** + * The width (and length) of a {@link MapFile} in {@link Tile}s. + */ + public static final int MAP_WIDTH = 64; + + /** + * The amount of planes in a MapFile. + */ + public static final int MAP_PLANES = 4; + + /** + * The multiplicand for height values. + */ + static final int HEIGHT_MULTIPLICAND = 8; + + /** + * The lowest type value that will result in the decoding of a Tile being continued. + */ + static final int LOWEST_CONTINUED_TYPE = 2; + + /** + * The minimum type that specifies the Tile attributes. + */ + static final int MINIMUM_ATTRIBUTES_TYPE = 81; + + /** + * The minimum type that specifies the Tile underlay id. + */ + static final int MINIMUM_OVERLAY_TYPE = 49; + + /** + * The amount of possible overlay orientations. + */ + static final int ORIENTATION_COUNT = 4; + + /** + * The height difference between two planes. + */ + static final int PLANE_HEIGHT_DIFFERENCE = 240; + + /** + * Sole private constructor to prevent instantiation. + */ + private MapConstants() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapFile.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFile.java new file mode 100644 index 00000000..b1e6d646 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFile.java @@ -0,0 +1,48 @@ +package org.apollo.cache.map; + +import com.google.common.base.Preconditions; + +/** + * A 3-dimensional 64x64 area of the map. + * + * @author Major + */ +public final class MapFile { + + /** + * The array of MapPlanes. + */ + private final MapPlane[] planes; + + /** + * Creates the MapFile. + * + * @param planes The {@link MapPlane}s. + */ + public MapFile(MapPlane[] planes) { + this.planes = planes.clone(); + } + + /** + * Gets the {@link MapPlane} with the specified level. + * + * @param plane The plane. + * @return The MapPlane. + * @throws ArrayIndexOutOfBoundsException If {@code plane} is out of bounds. + */ + public MapPlane getPlane(int plane) { + int length = planes.length; + Preconditions.checkElementIndex(plane, length, "Plane index out of bounds, must be [0, " + length + ")."); + return planes[plane]; + } + + /** + * Gets all of the {@link MapPlane}s in this MapFile. + * + * @return The MapPlanes. + */ + public MapPlane[] getPlanes() { + return planes.clone(); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapFileDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFileDecoder.java new file mode 100644 index 00000000..e85ae5e2 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFileDecoder.java @@ -0,0 +1,123 @@ +package org.apollo.cache.map; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.util.CompressionUtil; + +import java.nio.ByteBuffer; +import java.io.IOException; + +/** + * A decoder for the terrain data stored in {@link MapFile}s. + * + * @author Major + */ +public class MapFileDecoder { + /** + * Creates a MapFileDecoder for the specified map file. + * + * @param fs The {@link IndexedFileSystem} to get the file from. + * @param index The {@link MapIndex} to get the file index from. + * @return The MapFileDecoder. + * @throws IOException If there is an error reading or decompressing the file. + */ + public static MapFileDecoder create(IndexedFileSystem fs, MapIndex index) throws IOException { + ByteBuffer compressed = fs.getFile(MapConstants.MAP_INDEX, index.getMapFile()); + ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(compressed)); + + return new MapFileDecoder(decompressed); + } + + /** + * The DataBuffer containing the MapFile data. + */ + private final ByteBuffer buffer; + + /** + * Creates the MapIndexDecoder. + *

+ * This constructor expects the {@link ByteBuffer} to not be compressed. + * + * @param buffer The DataBuffer containing the MapFile data. + */ + public MapFileDecoder(ByteBuffer buffer) { + this.buffer = buffer.asReadOnlyBuffer(); + } + + /** + * Decodes the data into a {@link MapFile}. + * + * @return The MapFile. + */ + public MapFile decode() { + MapPlane[] planes = new MapPlane[MapConstants.MAP_PLANES]; + + for (int level = 0; level < MapConstants.MAP_PLANES; level++) { + planes[level] = decodePlane(planes, level); + } + + return new MapFile(planes); + } + + /** + * Decodes a {@link MapPlane} with the specified level. + * + * @param planes The previously-decoded {@link MapPlane}s, for calculating the height of the tiles. + * @param level The level. + * @return The MapPlane. + */ + private MapPlane decodePlane(MapPlane[] planes, int level) { + Tile[][] tiles = new Tile[MapConstants.MAP_WIDTH][MapConstants.MAP_WIDTH]; + + for (int x = 0; x < MapConstants.MAP_WIDTH; x++) { + for (int z = 0; z < MapConstants.MAP_WIDTH; z++) { + tiles[x][z] = decodeTile(planes, level, x, z); + } + } + + return new MapPlane(level, tiles); + } + + /** + * Decodes the data into a {@link Tile}. + * + * @param planes The previously-decoded {@link MapPlane}s, for calculating the height of the Tile. + * @param level The level the Tile is on. + * @param x The x coordinate of the Tile. + * @param z The z coordinate of the Tile. + * @return The MapFile. + */ + private Tile decodeTile(MapPlane[] planes, int level, int x, int z) { + Tile.Builder builder = Tile.builder(x, z, level); + + int type; + do { + type = buffer.get() & 0xFF; + + if (type == 0) { + if (level == 0) { + builder.setHeight(TileUtils.calculateHeight(x, z)); + } else { + Tile below = planes[level - 1].getTile(x, z); + builder.setHeight(below.getHeight() + MapConstants.PLANE_HEIGHT_DIFFERENCE); + } + } else if (type == 1) { + int height = buffer.get(); + int below = (level == 0) ? 0 : planes[level - 1].getTile(x, z).getHeight(); + + builder.setHeight((height == 1 ? 0 : height) * MapConstants.HEIGHT_MULTIPLICAND + below); + } else if (type <= MapConstants.MINIMUM_OVERLAY_TYPE) { + builder.setOverlay(buffer.get()); + builder.setOverlayType((type - MapConstants.LOWEST_CONTINUED_TYPE) + / MapConstants.ORIENTATION_COUNT); + builder.setOverlayOrientation(type - MapConstants.LOWEST_CONTINUED_TYPE + % MapConstants.ORIENTATION_COUNT); + } else if (type <= MapConstants.MINIMUM_ATTRIBUTES_TYPE) { + builder.setAttributes(type - MapConstants.MINIMUM_OVERLAY_TYPE); + } else { + builder.setUnderlay(type - MapConstants.MINIMUM_ATTRIBUTES_TYPE); + } + } while (type >= MapConstants.LOWEST_CONTINUED_TYPE); + + return builder.build(); + } +} diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndex.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndex.java new file mode 100644 index 00000000..9b707c85 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndex.java @@ -0,0 +1,125 @@ +package org.apollo.cache.map; + +import org.apollo.cache.def.ItemDefinition; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A definition for a map. + */ +public final class MapIndex { + + /** + * Indicates whether or not this map is members-only. + */ + private final boolean members; + + /** + * The object file id. + */ + private final int objects; + + /** + * The packed coordinates. + */ + private final int packedCoordinates; + + /** + * The terrain file id. + */ + private final int terrain; + + /** + * A mapping of region ids to {@link MapIndex}es. + */ + private static Map indices; + + /** + * Initialises the class with the specified set of indices. + */ + public static void init(Map indices) { + MapIndex.indices = Collections.unmodifiableMap(indices); + } + + /** + * Gets the {@code Map} of {@link MapIndex} instances. + * + * @return The map of {@link MapIndex} instances. + */ + public static Map getIndices() { + return indices; + } + + /** + * Creates the {@link MapIndex}. + * + * @param packedCoordinates The packed coordinates. + * @param terrain The terrain file id. + * @param objects The object file id. + * @param members Indicates whether or not this map is members-only. + */ + public MapIndex(int packedCoordinates, int terrain, int objects, boolean members) { + this.packedCoordinates = packedCoordinates; + this.terrain = terrain; + this.objects = objects; + this.members = members; + } + + /** + * Gets the id of the file containing the object data. + * + * @return The file id. + */ + public int getObjectFile() { + return objects; + } + + /** + * Gets the packed coordinates. + * + * @return The packed coordinates. + */ + public int getPackedCoordinates() { + return packedCoordinates; + } + + /** + * Gets the id of the file containing the terrain data. + * + * @return The file id. + */ + public int getMapFile() { + return terrain; + } + + /** + * Gets the X coordinate of this map. + * + * @return The X coordinate of this map. + */ + public int getX() { + return (packedCoordinates >> 8 & 0xFF) * MapConstants.MAP_WIDTH; + } + + /** + * Gets the Y coordinate of this map. + * + * @return The y coordinate of this map. + */ + public int getY() { + return (packedCoordinates & 0xFF) * MapConstants.MAP_WIDTH; + + } + + /** + * Returns whether or not this MapIndex is for a members-only area of the world. + * + * @return {@code true} if this MapIndex is for a members-only area, {@code false} if not. + */ + public boolean isMembersOnly() { + return members; + } + +} diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndexDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndexDecoder.java new file mode 100644 index 00000000..7bca2add --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndexDecoder.java @@ -0,0 +1,70 @@ +package org.apollo.cache.map; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.archive.Archive; +import org.apollo.cache.archive.ArchiveEntry; +import org.apollo.cache.map.MapIndex; + +/** + * Decodes {@link MapIndex}s from the {@link IndexedFileSystem}. + * + * @author Ryley + * @author Major + */ +public final class MapIndexDecoder implements Runnable { + + /** + * The file id of the versions archive. + */ + private static final int VERSIONS_ARCHIVE_FILE_ID = 5; + + /** + * The IndexedFileSystem. + */ + private final IndexedFileSystem fs; + + public MapIndexDecoder(IndexedFileSystem fs) { + this.fs = fs; + } + + /** + * Decodes {@link MapIndex}s from the specified {@link IndexedFileSystem}. + * + * @return A {@link Map} of packed coordinates to their MapDefinitions. + * @throws IOException If there is an error reading or decoding the Archive. + */ + public Map decode() throws IOException { + Archive archive = fs.getArchive(0, VERSIONS_ARCHIVE_FILE_ID); + ArchiveEntry entry = archive.getEntry("map_index"); + Map definitions = new HashMap<>(); + + ByteBuffer buffer = entry.getBuffer(); + int count = buffer.capacity() / (3 * Short.BYTES + Byte.BYTES); + + for (int times = 0; times < count; times++) { + int id = buffer.getShort() & 0xFFFF; + int terrain = buffer.getShort() & 0xFFFF; + int objects = buffer.getShort() & 0xFFFF; + boolean members = buffer.get() == 1; + + definitions.put(id, new MapIndex(id, terrain, objects, members)); + } + + return definitions; + } + + @Override + public void run() { + try { + MapIndex.init(decode()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapObject.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObject.java new file mode 100644 index 00000000..72980add --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObject.java @@ -0,0 +1,119 @@ +package org.apollo.cache.map; + +/** + * Represents a static world object in a map file. + */ +public final class MapObject { + + /** + * The object definition id of this {@code MapObject}. + */ + private final int id; + + /** + * The packed coordinates (local XY and height) for this object. + */ + private int packedCoordinates; + + /** + * The type of this object. + */ + private final int type; + + /** + * The orientation of this object. + */ + private final int orientation; + + /** + * Creates a new {@code MapObject}. + * + * @param id The object ID of this map object. + * @param packedCoordinates A packed integer containing the coordinates of this map object. + * @param type The type of object. + * @param orientation The object facing direction. + */ + public MapObject(int id, int packedCoordinates, int type, int orientation) { + this.id = id; + this.packedCoordinates = packedCoordinates; + this.type = type; + this.orientation = orientation; + } + + /** + * Create a new {@code MapObject}. + * + * @param id The object ID of this map object. + * @param x The local X coordinate of this object. + * @param y The local Y coordinate of this object. + * @param height The height level of this object. + * @param type The type of this object. + * @param orientation The orientation of this object. + */ + public MapObject(int id, int x, int y, int height, int type, int orientation) { + this(id, (height & 0x3f) << 12 | (x & 0x3f) << 6 | (y & 0x3f), type, orientation); + } + + /** + * Get the object ID of this map object. + * + * @return The object ID for {@link org.apollo.cache.def.ObjectDefinition} lookups. + */ + public int getId() { + return id; + } + + /** + * Get the plane this map object exists on. + * + * @return The plane this map object is on. + */ + public int getHeight() { + return packedCoordinates >> 12 & 0x3; + } + + /** + * Get the X coordinate of this object relative to the map position. + * + * @return The local X coordinate. + */ + public int getLocalX() { + return packedCoordinates >> 6 & 0x3F; + } + + /** + * Get the Y coordinate of this object relative to the map position. + * + * @return The local Y coordinate. + */ + public int getLocalY() { + return packedCoordinates & 0x3F; + } + + /** + * Get the integer representation of this objects orientation (0 indexed, starting West-North-East-South). + * + * @return The orientation of this object. + */ + public int getOrientation() { + return orientation; + } + + /** + * Get a packed integer containing the x/y coordinates and height for this object. + * + * @return The packed coordinates. + */ + public int getPackedCoordinates() { + return packedCoordinates; + } + + /** + * Get the type of this object. + * + * @return The type of this object. + */ + public int getType() { + return type; + } +} diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java new file mode 100644 index 00000000..351ea7d7 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java @@ -0,0 +1,83 @@ +package org.apollo.cache.map; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.map.MapIndex; +import org.apollo.cache.map.MapConstants; +import org.apollo.cache.map.MapObject; +import org.apollo.util.BufferUtil; +import org.apollo.util.CompressionUtil; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * A decoder for reading the map objects for a given map. + * + * @author Major + */ +public final class MapObjectsDecoder { + /** + * Creates a MapObjectsDecoder for the specified map file. + * + * @param fs The {@link IndexedFileSystem} to get the file from. + * @param index The map index to decode objects for. + * @return The MapObjectsDecoder. + * @throws IOException If there is an error reading or decompressing the file. + */ + public static MapObjectsDecoder create(IndexedFileSystem fs, MapIndex index) throws IOException { + ByteBuffer compressed = fs.getFile(MapConstants.MAP_INDEX, index.getObjectFile()); + ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(compressed)); + + return new MapObjectsDecoder(decompressed); + } + + /** + * The buffer to decode {@link MapObject}s from. + */ + private final ByteBuffer buffer; + + /** + * Create a new {@link MapObjectsDecoder} from the given buffer and map coordinates. + * + * @param buffer The decompressed object file buffer. + */ + public MapObjectsDecoder(ByteBuffer buffer) { + this.buffer = buffer.asReadOnlyBuffer(); + } + + /** + * Decodes the data in the {@code buffer} to a list of {@link MapObject}s. + * + * @return A list of decoded {@link MapObject}s. + */ + public List decode() { + List objects = new ArrayList<>(); + + int id = -1; + int idOffset = BufferUtil.readSmart(buffer); + + while (idOffset != 0) { + id += idOffset; + + int packed = 0; + int positionOffset = BufferUtil.readSmart(buffer); + + while (positionOffset != 0) { + packed += positionOffset - 1; + + int attributes = buffer.get() & 0xFF; + int type = attributes >> 2; + int orientation = attributes & 0x3; + objects.add(new MapObject(id, packed, type, orientation)); + + positionOffset = BufferUtil.readSmart(buffer); + } + + idOffset = BufferUtil.readSmart(buffer); + } + + return objects; + } +} diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapPlane.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapPlane.java new file mode 100644 index 00000000..1dfc3a01 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapPlane.java @@ -0,0 +1,90 @@ +package org.apollo.cache.map; + +import java.util.Arrays; +import java.util.stream.Stream; + +/** + * A plane of a map, which is a distinct height level. + * + * @author Major + */ +public final class MapPlane { + + /** + * Returns a shallow copy of the specified 2-dimensional array. + * + * @param array The array to copy. Must not be {@code null}. + * @return The copy. + */ + private static T[][] clone(T[][] array) { + T[][] copy = array.clone(); + for (int index = 0; index < copy.length; index++) { + copy[index] = array[index].clone(); + } + + return copy; + } + + /** + * The level of this MapPlane. + */ + private final int level; + + /** + * The 2-dimensional array of Tiles. + */ + private final Tile[][] tiles; + + /** + * Creates the MapPlane. + * + * @param level The level of the MapPlane. + * @param tiles The 2D array of {@link Tile}s. Must not be {@code null}. Must be square. + */ + public MapPlane(int level, Tile[][] tiles) { + this.level = level; + this.tiles = clone(tiles); + } + + /** + * Gets the level of this MapPlane. + * + * @return The level. + */ + public int getLevel() { + return level; + } + + /** + * Gets the amount of tiles in this MapPlane. + * + * @return The amount of tiles. + */ + public int getSize() { + return tiles.length * tiles[0].length; + } + + /** + * Gets the {@link Tile} at the specified (x, z) coordinate. + * + * @param x The x coordinate. + * @param z The z coordinate. + * @return The Tile. + */ + public Tile getTile(int x, int z) { + return tiles[x][z]; + } + + /** + * Gets the {@link Tile}s in this MapPlane. + *

+ * This method returns the Tiles according on a column-based ordering: for a 2x2 tile set, the order will be + * {@code (0, 0), (0, 1), (1, 0), (1, 1)}. + * + * @return The Tiles. + */ + public Stream getTiles() { + return Arrays.stream(tiles).flatMap(Arrays::stream); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/Tile.java b/2006Scape Server/src/main/java/org/apollo/cache/map/Tile.java new file mode 100644 index 00000000..e19d8133 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/Tile.java @@ -0,0 +1,295 @@ +package org.apollo.cache.map; + +/** + * A single tile on the map. + * + * @author Major + */ +public final class Tile { + + /** + * A builder class for a Tile. + */ + public static final class Builder { + + /** + * The attributes of the Tile. + */ + private int attributes; + + /** + * The height of the Tile. + */ + private int height; + + /** + * The overlay id of the Tile. + */ + private int overlay; + + /** + * The overlay orientation of the Tile. + */ + private int overlayOrientation; + + /** + * The overlay type of the Tile. + */ + private int overlayType; + + /** + * The x coordinate of the Tile. + */ + private int x; + + /** + * The y coordinate of the Tile. + */ + private int y; + + /** + * The underlay id of the Tile. + */ + private int underlay; + + /** + * Creates the Builder. + * + * @param x The x position of the Tile. + * @param y The y position of the Tile. + * @param height The height level of the Tile. + */ + public Builder(int x, int y, int height) { + this.x = x; + this.y = y; + this.height = height; + } + + /** + * Builds the contents of this Builder into a Tile. + * + * @return The Tile. + */ + public Tile build() { + return new Tile(x, y, attributes, height, overlay, overlayType, overlayOrientation, underlay); + } + + /** + * Sets the attributes of the Tile. + * + * @param attributes The attributes. + */ + public void setAttributes(int attributes) { + this.attributes = attributes; + } + + /** + * Sets the height of the Tile. + * + * @param height The height. + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * Sets the overlay id of the Tile. + * + * @param overlay The overlay id. + */ + public void setOverlay(int overlay) { + this.overlay = overlay; + } + + /** + * Sets the overlay orientation of the Tile. + * + * @param orientation The overlay orientation. + */ + public void setOverlayOrientation(int orientation) { + this.overlayOrientation = orientation; + } + + /** + * Sets the overlay type of the Tile. + * + * @param type The overlay type. + */ + public void setOverlayType(int type) { + this.overlayType = type; + } + + /** + * Sets the position of the Tile. + * + * @param x The x coordinate of the Tile. + * @param y the y coordinate of the Tile + * @param height The height level of the Tile. + */ + public void setPosition(int x, int y, int height) { + this.x = x; + this.y = y; + this.height = height; + } + + /** + * Sets the underlay id of the Tile. + * + * @param underlay The underlay. + */ + public void setUnderlay(int underlay) { + this.underlay = underlay; + } + + } + + /** + * Creates a {@link Builder} for a Tile. + * + * @param x The x coordinate of the Tile. + * @param y the y coordinate of the Tile. + * @param height The height level of the Tile. + * @return The Builder. + */ + public static Builder builder(int x, int y, int height) { + return new Builder(x, y, height); + } + + /** + * The attributes of this Tile. + */ + private final int attributes; + + /** + * The height of this Tile. + */ + private final int height; + + /** + * The overlay id of this Tile. + */ + private final int overlay; + + /** + * The overlay orientation of this Tile. + */ + private final int overlayOrientation; + + /** + * The overlay type of this Tile. + */ + private final int overlayType; + + /** + * The x coordinate of this Tile. + */ + private final int x; + + /** + * The y coordinate of this Tile. + */ + private final int y; + + /** + * The underlay id of this Tile. + */ + private final int underlay; + + /** + * Creates the Tile. + * + * @param x The x coordinate of the Tile. + * @param y The y coordinate of the Tile. + * @param attributes The attributes. + * @param height The height. + * @param overlay The overlay id. + * @param overlayType The overlay type. + * @param overlayOrientation The overlay orientation. + * @param underlay The underlay id. + */ + public Tile(int x, int y, int attributes, int height, int overlay, int overlayType, int overlayOrientation, + int underlay) { + this.x = x; + this.y = y; + this.attributes = attributes; + this.height = height; + this.overlay = overlay; + this.overlayType = overlayType; + this.overlayOrientation = overlayOrientation; + this.underlay = underlay; + } + + /** + * Gets the attributes of this Tile. + * + * @return The attributes. + */ + public int getAttributes() { + return attributes; + } + + /** + * Gets the height of this Tile. + * + * @return The height. + */ + public int getHeight() { + return height; + } + + /** + * Gets the overlay id of this Tile. + * + * @return The overlay id. + */ + public int getOverlay() { + return overlay; + } + + /** + * Gets the overlay orientation of this Tile. + * + * @return The overlay orientation. + */ + public int getOverlayOrientation() { + return overlayOrientation; + } + + /** + * Gets the overlay type of this Tile. + * + * @return The overlay types. + */ + public int getOverlayType() { + return overlayType; + } + + /** + * Gets the underlay id of this Tile. + * + * @return The underlay id. + */ + public int getUnderlay() { + return underlay; + } + + + /** + * Gets the x coordinate of this Tile. + * + * @return The x coordinate. + */ + public int getX() { + return x; + } + + /** + * Gets the y coordinate of this Tile. + * + * @return The y coordinate. + */ + public int getY() { + return y; + } + +} diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/TileUtils.java b/2006Scape Server/src/main/java/org/apollo/cache/map/TileUtils.java new file mode 100644 index 00000000..977e9562 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/map/TileUtils.java @@ -0,0 +1,161 @@ +package org.apollo.cache.map; + +/* + * Copyright (c) 2012-2013 Jonathan Edgecombe + * Copyright (c) 2015 Major + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * Contains tile-related utility methods. + * + * @author Johnny + * @author Major + */ +public final class TileUtils { + + /** + * The x coordinate offset, used for computing the Tile height. + */ + static final int TILE_HEIGHT_X_OFFSET = 0xe3b7b; + + /** + * The z coordinate offset, used for computing the Tile height. + */ + static final int TILE_HEIGHT_Z_OFFSET = 0x87cce; + + /** + * The cosine table used for interpolation. + */ + private static final int[] COSINE = new int[2048]; + + static { + for (int index = 0; index < COSINE.length; index++) { + COSINE[index] = (int) (65536 * Math.cos(2 * Math.PI * index / COSINE.length)); + } + } + + /** + * Calculates the height offset for the specified coordinate pair. + * + * @param x The x coordinate of the Tile. + * @param z The z coordinate of the Tile. + * @return The height offset. + */ + public static int calculateHeight(int x, int z) { + int regionSize = 8; + int regionOffset = 6; + int offset = regionOffset * regionSize; + + int baseX = x - offset; + int baseZ = z - offset; + + return computeHeight(x + TILE_HEIGHT_X_OFFSET - baseX, z + TILE_HEIGHT_Z_OFFSET - baseZ) + * MapConstants.HEIGHT_MULTIPLICAND; + } + + /** + * Gets the height offset for the specified coordinate pair. + * + * @param x The offset-x coordinate of the tile. + * @param z The offset-z coordinate of the tile. + * @return The tile height offset. + */ + private static int computeHeight(int x, int z) { + int total = interpolatedNoise(x + 45365, z + 91923, 4) - 128; + + total += (interpolatedNoise(x + 10294, z + 37821, 2) - 128) / 2; + total += (interpolatedNoise(x, z, 1) - 128) / 4; + + total = (int) Math.max(total * 0.3 + 35, 10); + return Math.min(total, 60); + } + + /** + * Interpolates two smooth noise values. + * + * @param a The first smooth noise value. + * @param b The second smooth noise value. + * @param theta The angle. + * @param reciprocal The frequency reciprocal. + * @return The interpolated value. + */ + private static int interpolate(int a, int b, int theta, int reciprocal) { + int cosine = 65536 - COSINE[theta * COSINE.length / (2 * reciprocal)] / 2; + return (a * (65536 - cosine)) / 65536 + (b * cosine) / 65536; + } + + /** + * Gets interpolated noise for the specified coordinate pair, using the specified frequency reciprocal. + * + * @param x The x coordinate. + * @param z The z coordinate. + * @param reciprocal The frequency reciprocal. + * @return The interpolated noise. + */ + private static int interpolatedNoise(int x, int z, int reciprocal) { + int xt = x % reciprocal; + int zt = z % reciprocal; + + x /= reciprocal; + z /= reciprocal; + + int c = smoothNoise(x, z); + int e = smoothNoise(x + 1, z); + int ce = interpolate(c, e, xt, reciprocal); + + int n = smoothNoise(x, z + 1); + int ne = smoothNoise(x + 1, z + 1); + int u = interpolate(n, ne, xt, reciprocal); + + return interpolate(ce, u, zt, reciprocal); + } + + /** + * Computes noise for the specified coordinate pair. + * + * @param x The x coordinate. + * @param z The z coordinate. + * @return The noise. + */ + private static int noise(int x, int z) { + int n = x + z * 57; + n = (n << 13) ^ n; + n = (n * (n * n * 15731 + 789221) + 1376312589) & Integer.MAX_VALUE; + return (n >> 19) & 0xff; + } + + /** + * Computes smooth noise for the specified coordinate pair. + * + * @param x The x coordinate. + * @param z The z coordinate. + * @return The smooth noise. + */ + private static int smoothNoise(int x, int z) { + int corners = noise(x - 1, z - 1) + noise(x + 1, z - 1) + noise(x - 1, z + 1) + noise(x + 1, z + 1); + int sides = noise(x - 1, z) + noise(x + 1, z) + noise(x, z - 1) + noise(x, z + 1); + int center = noise(x, z); + + return corners / 16 + sides / 8 + center / 4; + } + + /** + * Sole private constructor to prevent instantiation. + */ + private TileUtils() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/package-info.java new file mode 100644 index 00000000..73873276 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains classes which deal with the file system that the client uses to store game data files. + */ +package org.apollo.cache; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java b/2006Scape Server/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java new file mode 100644 index 00000000..7345704c --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java @@ -0,0 +1,964 @@ +package org.apollo.cache.tools; + +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.FileOutputStream; +import java.nio.file.Paths; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.cache.decoder.ItemDefinitionDecoder; +import org.apollo.cache.def.ItemDefinition; +import org.apollo.util.tools.EquipmentConstants; + +import com.google.common.base.Preconditions; + +/** + * A tool for updating the equipment data. + * + * @author Graham + * @author Palidino76 + */ +public final class EquipmentUpdater { + + /** + * The entry point of the application. + * + * @param args The command line arguments. + * @throws Exception If an error occurs. + */ + public static void main(String[] args) throws Exception { + Preconditions.checkArgument(args.length == 1, "Usage:\njava -cp ... org.apollo.tools.EquipmentUpdater [release]."); + String release = args[0]; + + try (DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data/equipment-" + release + ".dat"))); + IndexedFileSystem fs = new IndexedFileSystem(Paths.get("data/fs/", release), true)) { + ItemDefinitionDecoder decoder = new ItemDefinitionDecoder(fs); + decoder.run(); + + int count = ItemDefinition.count(); + os.writeShort(count); + + for (int id = 0; id < count; id++) { + ItemDefinition definition = ItemDefinition.lookup(id); + int type = getWeaponType(definition); + os.writeByte(type); + + if (type != -1) { + os.writeBoolean(isTwoHanded(definition)); + os.writeBoolean(isFullBody(definition)); + os.writeBoolean(isFullHat(definition)); + os.writeBoolean(isFullMask(definition)); + os.writeByte(getAttackRequirement(definition)); + os.writeByte(getStrengthRequirement(definition)); + os.writeByte(getDefenceRequirement(definition)); + os.writeByte(getRangedRequirement(definition)); + os.writeByte(getPrayerRequirement(definition)); + os.writeByte(getMagicRequirement(definition)); + } + } + } + } + + /** + * Gets the attack requirement. + * + * @param definition The item definition. + * @return The required level. + */ + private static int getAttackRequirement(ItemDefinition definition) { + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + if (name.equals("Black sword")) { + return 10; + } else if (name.equals("Black dagger")) { + return 10; + } else if (name.equals("Black spear")) { + return 10; + } else if (name.equals("Black longsword")) { + return 10; + } else if (name.equals("Black scimitar")) { + return 10; + } else if (name.equals("Black axe")) { + return 10; + } else if (name.equals("Black battleaxe")) { + return 10; + } else if (name.equals("Black mace")) { + return 10; + } else if (name.equals("Black halberd")) { + return 10; + } else if (name.equals("Mithril sword")) { + return 20; + } else if (name.equals("Mithril dagger")) { + return 20; + } else if (name.equals("Mithril spear")) { + return 20; + } else if (name.equals("Mihril longsword")) { + return 20; + } else if (name.equals("Mithril scimitar")) { + return 20; + } else if (name.equals("Mithril axe")) { + return 20; + } else if (name.equals("Mithril battleaxe")) { + return 20; + } else if (name.equals("Mithril mace")) { + return 20; + } else if (name.equals("Mithril halberd")) { + return 20; + } else if (name.equals("Adamant sword")) { + return 30; + } else if (name.equals("Adamant dagger")) { + return 30; + } else if (name.equals("Adamant spear")) { + return 30; + } else if (name.equals("Adamant longsword")) { + return 30; + } else if (name.equals("Adamant scimitar")) { + return 30; + } else if (name.equals("Adamant axe")) { + return 30; + } else if (name.equals("Adamant battleaxe")) { + return 30; + } else if (name.equals("Adamant mace")) { + return 30; + } else if (name.equals("Adamant halberd")) { + return 30; + } else if (name.equals("Rune sword")) { + return 40; + } else if (name.equals("Rune dagger")) { + return 40; + } else if (name.equals("Rune spear")) { + return 40; + } else if (name.equals("Rune longsword")) { + return 40; + } else if (name.equals("Rune scimitar")) { + return 40; + } else if (name.equals("Rune axe")) { + return 40; + } else if (name.equals("Rune battleaxe")) { + return 40; + } else if (name.equals("Rune mace")) { + return 40; + } else if (name.equals("Rune halberd")) { + return 40; + } else if (name.equals("Dragon sword")) { + return 60; + } else if (name.equals("Dragon dagger(s)")) { + return 60; + } else if (name.equals("Dragon dagger")) { + return 60; + } else if (name.startsWith("Dragon spear")) { + return 60; + } else if (name.equals("Dragon longsword")) { + return 60; + } else if (name.equals("Dragon scimitar")) { + return 60; + } else if (name.equals("Dragon axe")) { + return 60; + } else if (name.equals("Dragon battleaxe")) { + return 60; + } else if (name.equals("Dragon mace")) { + return 60; + } else if (name.equals("Dragon halberd")) { + return 60; + } else if (name.equals("Abyssal whip")) { + return 70; + } else if (name.equals("Veracs flail")) { + return 70; + } else if (name.equals("Torags hammers")) { + return 70; + } else if (name.equals("Dharoks greataxe")) { + return 70; + } else if (name.equals("Guthans warspear")) { + return 70; + } else if (name.equals("Ahrims staff")) { + return 70; + } else if (name.equals("Granite maul")) { + return 50; + } else if (name.equals("Toktz-xil-ak")) { + return 60; + } else if (name.equals("Tzhaar-ket-em")) { + return 60; + } else if (name.equals("Toktz-xil-ek")) { + return 60; + } else if (name.equals("Granite legs")) { + return 99; + } else if (name.equals("Mud staff")) { + return 30; + } else if (name.equals("Armadyl godsword")) { + return 75; + } else if (name.equals("Bandos godsword")) { + return 75; + } else if (name.equals("Saradomin godsword")) { + return 75; + } else if (name.equals("Zamorak godsword")) { + return 75; + } else if (name.equals("Lava battlestaff")) { + return 30; + } else if (name.equals("Toktz-mej-tal")) { + return 60; + } else if (name.equals("Ancient staff")) { + return 50; + } + + return 1; + } + + /** + * Gets the defence requirement. + * + * @param definition The item definition. + * @return The required level. + */ + private static int getDefenceRequirement(ItemDefinition definition) { + int id = definition.getId(); + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + if (name.equals("Rune boots")) { + return 40; + } else if (id == 2499) { + return 40; + } else if (id == 4123) { + return 5; + } else if (id == 4125) { + return 10; + } else if (id == 4127) { + return 20; + } else if (id == 4129) { + return 30; + } else if (id == 7990) { + return 60; + } else if (id == 2501) { + return 40; + } else if (id == 1131) { + return 10; + } else if (id == 2503) { + return 40; + } else if (id == 1135) { + return 40; + } else if (id == 7462) { + return 42; + } else if (id == 7461) { + return 42; + } else if (id == 7460) { + return 42; + } else if (id == 7459) { + return 20; + } else if (id == 7458) { + return 1; + } else if (id == 7457) { + return 1; + } else if (id == 7456) { + return 1; + } else if (id == 2661) { + return 40; + } else if (id == 2667) { + return 40; + } else if (id == 3479) { + return 40; + } else if (name.equals("White med helm")) { + return 10; + } else if (name.equals("White chainbody")) { + return 10; + } else if (name.startsWith("White full helm")) { + return 10; + } else if (name.startsWith("White platebody")) { + return 10; + } else if (name.startsWith("White plateskirt")) { + return 10; + } else if (name.startsWith("White platelegs")) { + return 10; + } else if (name.startsWith("White kiteshield")) { + return 10; + } else if (name.startsWith("White sq shield")) { + return 10; + } else if (name.startsWith("Studded chaps")) { + return 1; + } else if (name.startsWith("Studded")) { + return 20; + } else if (name.startsWith("Black kiteshield(h)")) { + return 10; + } else if (name.startsWith("Rune kiteshield(h)")) { + return 40; + } else if (name.equals("Black med helm")) { + return 10; + } else if (name.equals("Black chainbody")) { + return 10; + } else if (name.startsWith("Black full helm")) { + return 10; + } else if (name.startsWith("Black platebody")) { + return 10; + } else if (name.startsWith("Black plateskirt")) { + return 10; + } else if (name.startsWith("Black platelegs")) { + return 10; + } else if (name.startsWith("Black kiteshield")) { + return 10; + } else if (name.startsWith("Black sq shield")) { + return 10; + } else if (name.equals("Mithril med helm")) { + return 20; + } else if (name.equals("Mithril chainbody")) { + return 20; + } else if (name.startsWith("Mithril full helm")) { + return 20; + } else if (name.startsWith("Mithril platebody")) { + return 20; + } else if (name.startsWith("Mithril plateskirt")) { + return 20; + } else if (name.startsWith("Mithril platelegs")) { + return 20; + } else if (name.startsWith("Mithril kiteshield")) { + return 20; + } else if (name.startsWith("Mithril sq shield")) { + return 20; + } else if (name.equals("Adamant med helm")) { + return 30; + } else if (name.equals("Adamant chainbody")) { + return 30; + } else if (name.startsWith("Adamant full helm")) { + return 30; + } else if (name.startsWith("Adamant platebody")) { + return 30; + } else if (name.startsWith("Adamant plateskirt")) { + return 30; + } else if (name.startsWith("Adamant platelegs")) { + return 30; + } else if (name.startsWith("Adamant kiteshield")) { + return 30; + } else if (name.startsWith("Adamant sq shield")) { + return 30; + } else if (name.startsWith("Adam full helm")) { + return 30; + } else if (name.startsWith("Adam platebody")) { + return 30; + } else if (name.startsWith("Adam plateskirt")) { + return 30; + } else if (name.startsWith("Adam platelegs")) { + return 30; + } else if (name.startsWith("Adam kiteshield")) { + return 30; + } else if (name.startsWith("Adam kiteshield(h)")) { + return 30; + } else if (name.startsWith("D-hide body(g)")) { + return 40; + } else if (name.startsWith("D-hide body(t)")) { + return 40; + } else if (name.equals("Dragon sq shield")) { + return 60; + } else if (name.equals("Dragon med helm")) { + return 60; + } else if (name.equals("Dragon chainbody")) { + return 60; + } else if (name.equals("Dragon plateskirt")) { + return 60; + } else if (name.equals("Dragon platelegs")) { + return 60; + } else if (name.equals("Dragon sq shield")) { + return 60; + } else if (name.equals("Rune med helm")) { + return 40; + } else if (name.equals("Rune chainbody")) { + return 40; + } else if (name.startsWith("Rune full helm")) { + return 40; + } else if (name.startsWith("Rune platebody")) { + return 40; + } else if (name.startsWith("Rune plateskirt")) { + return 40; + } else if (name.startsWith("Rune platelegs")) { + return 40; + } else if (name.startsWith("Rune kiteshield")) { + return 40; + } else if (name.startsWith("Zamorak full helm")) { + return 40; + } else if (name.startsWith("Zamorak platebody")) { + return 40; + } else if (name.startsWith("Zamorak plateskirt")) { + return 40; + } else if (name.startsWith("Zamorak platelegs")) { + return 40; + } else if (name.startsWith("Zamorak kiteshield")) { + return 40; + } else if (name.startsWith("Guthix full helm")) { + return 40; + } else if (name.startsWith("Guthix platebody")) { + return 40; + } else if (name.startsWith("Guthix plateskirt")) { + return 40; + } else if (name.startsWith("Guthix platelegs")) { + return 40; + } else if (name.startsWith("Guthix kiteshield")) { + return 40; + } else if (name.startsWith("Saradomin full")) { + return 40; + } else if (name.startsWith("Saradomrangedin plate")) { + return 40; + } else if (name.startsWith("Saradomin plateskirt")) { + return 40; + } else if (name.startsWith("Saradomin legs")) { + return 40; + } else if (name.startsWith("Zamorak kiteshield")) { + return 40; + } else if (name.startsWith("Rune sq shield")) { + return 40; + } else if (name.equals("Gilded full helm")) { + return 40; + } else if (name.equals("Gilded platebody")) { + return 40; + } else if (name.equals("Gilded plateskirt")) { + return 40; + } else if (name.equals("Gilded platelegs")) { + return 40; + } else if (name.equals("Gilded kiteshield")) { + return 40; + } else if (name.equals("Fighter torso")) { + return 40; + } else if (name.equals("Granite legs")) { + return 99; + } else if (name.equals("Toktz-ket-xil")) { + return 60; + } else if (name.equals("Dharoks helm")) { + return 70; + } else if (name.equals("Dharoks platebody")) { + return 70; + } else if (name.equals("Dharoks platelegs")) { + return 70; + } else if (name.equals("Guthans helm")) { + return 70; + } else if (name.equals("Guthans platebody")) { + return 70; + } else if (name.equals("Guthans chainskirt")) { + return 70; + } else if (name.equals("Torags helm")) { + return 70; + } else if (name.equals("Torags platebody")) { + return 70; + } else if (name.equals("Torags platelegs")) { + return 70; + } else if (name.equals("Veracs helm")) { + return 70; + } else if (name.equals("Veracs brassard")) { + return 70; + } else if (name.equals("Veracs plateskirt")) { + return 70; + } else if (name.equals("Ahrims hood")) { + return 70; + } else if (name.equals("Ahrims robetop")) { + return 70; + } else if (name.equals("Ahrims robeskirt")) { + return 70; + } else if (name.equals("Karils coif")) { + return 70; + } else if (name.equals("Karils leathertop")) { + return 70; + } else if (name.equals("Karils leatherskirt")) { + return 70; + } else if (name.equals("Granite shield")) { + return 50; + } else if (name.equals("New crystal shield")) { + return 70; + } else if (name.equals("Archer helm")) { + return 45; + } else if (name.equals("Berserker helm")) { + return 45; + } else if (name.equals("Warrior helm")) { + return 45; + } else if (name.equals("Farseer helm")) { + return 45; + } else if (name.equals("Initiate helm")) { + return 20; + } else if (name.equals("Initiate platemail")) { + return 20; + } else if (name.equals("Initiate platelegs")) { + return 20; + } else if (name.equals("Dragonhide body")) { + return 40; + } else if (name.equals("Mystic hat")) { + return 20; + } else if (name.equals("Mystic robe top")) { + return 20; + } else if (name.equals("Mystic robe bottom")) { + return 20; + } else if (name.equals("Mystic gloves")) { + return 20; + } else if (name.equals("Mystic boots")) { + return 20; + } else if (name.equals("Enchanted hat")) { + return 20; + } else if (name.equals("Enchanted top")) { + return 20; + } else if (name.equals("Enchanted robe")) { + return 20; + } else if (name.equals("Splitbark helm")) { + return 40; + } else if (name.equals("Splitbark body")) { + return 40; + } else if (name.equals("Splitbark gauntlets")) { + return 40; + } else if (name.equals("Splitbark legs")) { + return 40; + } else if (name.equals("Splitbark greaves")) { + return 40; + } else if (name.equals("Infinity gloves")) { + return 25; + } else if (name.equals("Infinity hat")) { + return 25; + } else if (name.equals("Infinity top")) { + return 25; + } else if (name.equals("Infinity bottoms")) { + return 25; + } else if (name.equals("Infinity boots")) { + return 25; + } + + return 1; + } + + /** + * Gets the magic requirement. + * + * @param definition The item definition. + * @return The required level. + */ + private static int getMagicRequirement(ItemDefinition definition) { + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + if (name.equals("Mystic hat")) { + return 40; + } else if (name.equals("Mystic robe top")) { + return 40; + } else if (name.equals("Mystic robe bottom")) { + return 40; + } else if (name.equals("Mystic gloves")) { + return 40; + } else if (name.equals("Mystic boots")) { + return 40; + } else if (name.equals("Slayer's staff")) { + return 50; + } else if (name.equals("Enchanted hat")) { + return 40; + } else if (name.equals("Enchanted top")) { + return 40; + } else if (name.equals("Enchanted robe")) { + return 40; + } else if (name.equals("Splitbark helm")) { + return 40; + } else if (name.equals("Splitbark body")) { + return 40; + } else if (name.equals("Splitbark gauntlets")) { + return 40; + } else if (name.equals("Splitbark legs")) { + return 40; + } else if (name.equals("Splitbark greaves")) { + return 40; + } else if (name.equals("Infinity gloves")) { + return 50; + } else if (name.equals("Infinity hat")) { + return 50; + } else if (name.equals("Infinity top")) { + return 50; + } else if (name.equals("Infinity bottoms")) { + return 50; + } else if (name.equals("Infinity boots")) { + return 50; + } else if (name.equals("Ahrims hood")) { + return 70; + } else if (name.equals("Ahrims robetop")) { + return 70; + } else if (name.equals("Ahrims robeskirt")) { + return 70; + } else if (name.equals("Ahrims staff")) { + return 70; + } else if (name.equals("Saradomin cape")) { + return 60; + } else if (name.equals("Saradomin staff")) { + return 60; + } else if (name.equals("Zamorak cape")) { + return 60; + } else if (name.equals("Zamorak staff")) { + return 60; + } else if (name.equals("Guthix cape")) { + return 60; + } else if (name.equals("Guthix staff")) { + return 60; + } else if (name.equals("mud staff")) { + return 30; + } else if (name.equals("Fire battlestaff")) { + return 30; + } else if (name.equals("Toktz-mej-tal")) { + return 60; + } + return 1; + } + + /** + * Gets the prayer requirement. + * + * @param definition the item. + * @return The required level. + */ + private static int getPrayerRequirement(ItemDefinition definition) { + String name = definition.getName(); + if (name == null) { + name = "null"; + } + if (name.contains("Initiate")) { + return 10; + } + if (name.contains("Proselyte")) { + return 20; + } + return 1; + } + + /** + * Gets the ranged requirement. + * + * @param definition The item. + * @return The required level. + */ + private static int getRangedRequirement(ItemDefinition definition) { + int id = definition.getId(); + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + if (id == 2499) { + return 50; + } else if (id == 1135) { + return 40; + } else if (id == 1099) { + return 40; + } else if (id == 1065) { + return 40; + } else if (id == 2501) { + return 60; + } else if (id == 2503) { + return 70; + } else if (id == 2487) { + return 50; + } else if (id == 2489) { + return 60; + } else if (id == 2495) { + return 60; + } else if (id == 2491) { + return 70; + } else if (id == 2493) { + return 50; + } else if (id == 2505) { + return 60; + } else if (id == 2507) { + return 70; + } else if (id == 859) { + return 40; + } else if (id == 861) { + return 40; + } else if (id == 7370) { + return 40; + } else if (id == 7372) { + return 40; + } else if (id == 7378) { + return 40; + } else if (id == 7380) { + return 40; + } else if (id == 7374) { + return 50; + } else if (id == 7376) { + return 50; + } else if (id == 7382) { + return 50; + } else if (id == 7384) { + return 50; + } else if (name.equals("Coif")) { + return 20; + } else if (name.startsWith("Studded chaps")) { + return 20; + } else if (name.startsWith("Studded")) { + return 20; + } else if (name.equals("Karils coif")) { + return 70; + } else if (name.equals("Karils leathertop")) { + return 70; + } else if (name.equals("Karils leatherskirt")) { + return 70; + } else if (name.equals("Robin hood hat")) { + return 40; + } else if (name.equals("Ranger boots")) { + return 40; + } else if (name.equals("Crystal bow full")) { + return 70; + } else if (name.equals("New crystal bow")) { + return 70; + } else if (name.equals("Karils crossbow")) { + return 70; + } else if (id == 2497) { + return 70; + } else if (name.equals("Rune thrownaxe")) { + return 40; + } else if (name.equals("Rune dart")) { + return 40; + } else if (name.equals("Rune javelin")) { + return 40; + } else if (name.equals("Rune knife")) { + return 40; + } else if (name.equals("Adamant thrownaxe")) { + return 30; + } else if (name.equals("Adamant dart")) { + return 30; + } else if (name.equals("Adamant javelin")) { + return 30; + } else if (name.equals("Adamant knife")) { + return 30; + } else if (name.equals("Toktz-xil-ul")) { + return 60; + } else if (name.equals("Seercull")) { + return 50; + } else if (name.equals("Bolt rack")) { + return 70; + } else if (name.equals("Rune arrow")) { + return 40; + } else if (name.equals("Adamant arrow")) { + return 30; + } else if (name.equals("Mithril arrow")) { + return 1; + } + + return 1; + } + + /** + * Gets the strength requirement. + * + * @param def The item. + * @return The required level. + */ + private static int getStrengthRequirement(ItemDefinition def) { + String name = def.getName(); + if (name == null) { + name = "null"; + } + + if (name.equals("Torags hammers")) { + return 70; + } else if (name.equals("Dharoks greataxe")) { + return 70; + } else if (name.equals("Granite maul")) { + return 50; + } else if (name.equals("Granite legs")) { + return 99; + } else if (name.equals("Tzhaar-ket-om")) { + return 60; + } else if (name.equals("Granite shield")) { + return 50; + } + + return 1; + } + + /** + * Gets the weapon type. + * + * @param definition The item. + * @return The weapon type, or {@code -1} if it is not a weapon. + */ + private static int getWeaponType(ItemDefinition definition) { + String name = definition.getName(); + if (name == null) { + name = "null"; + } + for (String element : EquipmentConstants.CAPES) { + if (name.contains(element)) { + return 1; + } + } + for (String element : EquipmentConstants.HATS) { + if (name.contains(element)) { + return 0; + } + } + for (String element : EquipmentConstants.BOOTS) { + if (name.endsWith(element) || name.startsWith(element)) { + return 10; + } + } + for (String element : EquipmentConstants.GLOVES) { + if (name.endsWith(element) || name.startsWith(element)) { + return 9; + } + } + for (String element : EquipmentConstants.SHIELDS) { + if (name.contains(element)) { + return 5; + } + } + for (String element : EquipmentConstants.AMULETS) { + if (name.endsWith(element) || name.startsWith(element)) { + return 2; + } + } + for (String element : EquipmentConstants.ARROWS) { + if (name.endsWith(element) || name.startsWith(element)) { + return 13; + } + } + for (String element : EquipmentConstants.RINGS) { + if (name.endsWith(element) || name.startsWith(element)) { + return 12; + } + } + for (String element : EquipmentConstants.BODY) { + if (name.contains(element)) { + return 4; + } + } + for (String element : EquipmentConstants.LEGS) { + if (name.contains(element)) { + return 7; + } + } + for (String element : EquipmentConstants.WEAPONS) { + if (name.endsWith(element) || name.startsWith(element)) { + return 3; + } + } + return -1; + } + + /** + * Checks if the item is a full body item. + * + * @param definition The item. + * @return {@code true} if so, {@code false} otherwise. + */ + private static boolean isFullBody(ItemDefinition definition) { + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + for (String element : EquipmentConstants.FULL_BODIES) { + if (name.contains(element)) { + return true; + } + } + + return false; + } + + /** + * Checks if the item is a full hat item. + * + * @param definition The item. + * @return {@code true} if so, {@code false} otherwise. + */ + private static boolean isFullHat(ItemDefinition definition) { + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + for (String element : EquipmentConstants.FULL_HATS) { + if (name.endsWith(element)) { + return true; + } + } + + return false; + } + + /** + * Checks if the item is a full mask item. + * + * @param definition The item. + * @return {@code true} if so, {@code false} otherwise. + */ + private static boolean isFullMask(ItemDefinition definition) { + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + for (String element : EquipmentConstants.FULL_MASKS) { + if (name.endsWith(element)) { + return true; + } + } + + return false; + } + + /** + * Checks if the item is two handed. + * + * @param definition The item. + * @return {@code true} if so, {@code false} otherwise. + */ + private static boolean isTwoHanded(ItemDefinition definition) { + int id = definition.getId(); + String name = definition.getName(); + if (name == null) { + name = "null"; + } + + if (id == 4212) { + return true; + } else if (id == 4214) { + return true; + } else if (id == 6526) { + return true; + } else if (name.endsWith("2h sword")) { + return true; + } else if (name.endsWith("longbow")) { + return true; + } else if (name.equals("Seercull")) { + return true; + } else if (name.endsWith("shortbow")) { + return true; + } else if (name.endsWith("Longbow")) { + return true; + } else if (name.endsWith("Shortbow")) { + return true; + } else if (name.endsWith("bow full")) { + return true; + } else if (name.endsWith("halberd")) { + return true; + } else if (name.equals("Granite maul")) { + return true; + } else if (name.equals("Karils crossbow")) { + return true; + } else if (name.equals("Torags hammers")) { + return true; + } else if (name.equals("Veracs flail")) { + return true; + } else if (name.equals("Dharoks greataxe")) { + return true; + } else if (name.equals("Guthans warspear")) { + return true; + } else if (name.equals("Tzhaar-ket-om")) { + return true; + } else if (name.endsWith("godsword")) { + return true; + } else if (name.equals("Saradomin sword")) { + return true; + } + + return false; + } + + /** + * Default private constructor to prevent instantiation. + */ + private EquipmentUpdater() { + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/cache/tools/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/tools/package-info.java new file mode 100644 index 00000000..c885d57d --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/cache/tools/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains cache-related tools. + */ +package org.apollo.cache.tools; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/ApolloHandler.java b/2006Scape Server/src/main/java/org/apollo/game/session/ApolloHandler.java new file mode 100644 index 00000000..9a04936f --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/game/session/ApolloHandler.java @@ -0,0 +1,106 @@ +package org.apollo.game.session; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.util.Attribute; +import io.netty.util.AttributeKey; +import io.netty.util.ReferenceCountUtil; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apollo.net.codec.handshake.HandshakeConstants; +import org.apollo.net.codec.handshake.HandshakeMessage; +import org.apollo.net.codec.jaggrab.JagGrabRequest; + +import com.rs2.GameConstants; + +/** + * An implementation of {@link ChannelInboundHandlerAdapter} which handles incoming upstream events from Netty. + * + * @author Graham + */ +@Sharable +public final class ApolloHandler extends ChannelInboundHandlerAdapter { + + /** + * The logger for this class. + */ + private static final Logger logger = Logger.getLogger(ApolloHandler.class.getName()); + + /** + * The {@link Session} {@link AttributeKey}. + */ + public static final AttributeKey SESSION_KEY = AttributeKey.valueOf("session"); + + /** + * Creates the Apollo event handler. + * + * @param context The server context. + */ + public ApolloHandler() { + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + Channel channel = ctx.channel(); + Session session = channel.attr(ApolloHandler.SESSION_KEY).getAndRemove(); + if (session != null) { + session.destroy(); + } + logger.fine("Channel disconnected: " + channel); + channel.close(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) { + if (!e.getMessage().contains("An existing connection was forcibly closed by the remote host")) { + logger.log(Level.WARNING, "Exception occured for channel: " + ctx.channel() + ", closing...", e); + } + ctx.channel().close(); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception { + Channel channel = ctx.channel(); + Attribute attribute = channel.attr(ApolloHandler.SESSION_KEY); + Session session = attribute.get(); + + if (message instanceof HttpRequest || message instanceof JagGrabRequest) { + session = new UpdateSession(channel); + } + + if (session != null) { + session.messageReceived(message); + return; + } + + // TODO: Perhaps let HandshakeMessage implement Message to remove this explicit check + if (message instanceof HandshakeMessage) { + HandshakeMessage handshakeMessage = (HandshakeMessage) message; + + switch (handshakeMessage.getServiceId()) { + case HandshakeConstants.SERVICE_GAME: + attribute.set(new LoginSession(channel)); + break; + + case HandshakeConstants.SERVICE_UPDATE: + if(!GameConstants.FILE_SERVER) { + ctx.close(); + return; + } + attribute.set(new UpdateSession(channel)); + break; + } + } + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + ctx.flush(); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/GameSession.java b/2006Scape Server/src/main/java/org/apollo/game/session/GameSession.java new file mode 100644 index 00000000..eb43f74b --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/game/session/GameSession.java @@ -0,0 +1,66 @@ +package org.apollo.game.session; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; + +import java.net.SocketAddress; + +import com.rs2.game.players.Player; +import com.rs2.net.Packet; + +/** + * Temporary quick and tear integration with apollo netcode. This needs redone when the the packets are fully redone. + * @author Advocatus + * + */ +public final class GameSession extends Session { + + private Player player; + + public void setPlayer(Player player) { + this.player = player; + } + + private final boolean reconnecting; + + public GameSession(Channel channel, Player player, boolean reconnecting) { + super(channel); + this.player = player; + this.reconnecting = reconnecting; + } + + @Override + public void destroy() { + player.disconnected = true; + } + + public boolean isReconnecting() { + return reconnecting; + } + + @Override + public void messageReceived(Object message) { + player.queueMessage((Packet) message); + } + + public SocketAddress getRemoteAddress() { + return channel.remoteAddress(); + } + + public void close() { + channel.close(); + } + + public boolean isActive() { + return channel.isActive(); + } + +// public void write(Packet packet) { +// channel.write(packet); +// } + + public void write(ByteBuf buf) { + channel.writeAndFlush(buf); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/LoginSession.java b/2006Scape Server/src/main/java/org/apollo/game/session/LoginSession.java new file mode 100644 index 00000000..1c6649fb --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/game/session/LoginSession.java @@ -0,0 +1,171 @@ +package org.apollo.game.session; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.Optional; + +import org.apollo.net.codec.login.LoginConstants; +import org.apollo.net.codec.login.LoginRequest; +import org.apollo.net.codec.login.LoginResponse; +import org.apollo.util.security.IsaacRandom; +import org.apollo.util.security.IsaacRandomPair; +import org.apollo.util.security.PlayerCredentials; + +import com.rs2.Connection; +import com.rs2.GameConstants; +import com.rs2.GameEngine; +import com.rs2.game.players.Client; +import com.rs2.game.players.PlayerHandler; +import com.rs2.game.players.PlayerSave; +import com.rs2.net.RS2ProtocolDecoder; +import com.rs2.util.HostBlacklist; + +/** + * Temporary quick and tear integration with apollo netcode. This needs redone when the Apollo Service system is added. + * @author Advocatus + * + */ +public final class LoginSession extends Session { + + public LoginSession(Channel channel) { + super(channel); + } + + @Override + public void destroy() { + + } + + @Override + public void messageReceived(Object message) throws Exception { + if (message.getClass() == LoginRequest.class) { + handleLoginRequest((LoginRequest) message); + } + } + + public static void load(Channel channel, + PlayerCredentials credentials, IsaacRandomPair randomPair, boolean reconnecting) { + + int returnCode = 2; + + String username = credentials.getUsername().trim(); + String password = credentials.getPassword().trim(); + username = username.toLowerCase(); + // pass = pass.toLowerCase(); + + String hostName = ((InetSocketAddress) channel.remoteAddress()) + .getAddress().getHostName(); + +// if (uid != 314268572) { +// channel.close(); +// return; +// } +// if (version != 1) { +// returnCode = 31; +// } + + if (HostBlacklist.isBlocked(hostName)) { + returnCode = 11; + } + + if (!username.matches("[A-Za-z0-9 ]+")) { + returnCode = 4; + } + if (username.length() > 12) { + returnCode = 8; + } + + if (password.length() == 0) { + returnCode = 4; + } + GameSession session = new GameSession(channel, null, reconnecting); + Client cl = new Client(session, -1); + session.setPlayer(cl); + cl.playerName = username; + cl.playerName2 = cl.playerName; + cl.playerPass = password; + cl.outStream.packetEncryption = randomPair.getEncodingRandom(); + cl.saveCharacter = false; + char first = username.charAt(0); + cl.properName = Character.toUpperCase(first) + + username.substring(1, username.length()); + if (Connection.isNamedBanned(cl.playerName)) { + returnCode = 4; + } + + if (PlayerHandler.isPlayerOn(username)) { + returnCode = 5; + } + + if (PlayerHandler.getPlayerCount() >= GameConstants.MAX_PLAYERS) { + returnCode = 7; + } + + if (GameEngine.updateServer) { + returnCode = 14; + } + + if (returnCode == 2) { + int load = PlayerSave.loadGame(cl, cl.playerName, cl.playerPass); + if (load == 0) + cl.addStarter = true; + if (load == 3) { + returnCode = 3; + cl.saveFile = false; + } else { + for (int i = 0; i < cl.playerEquipment.length; i++) { + if (cl.playerEquipment[i] == 0) { + cl.playerEquipment[i] = -1; + cl.playerEquipmentN[i] = 0; + } + } + if (!GameEngine.playerHandler.newPlayerClient(cl)) { + returnCode = 7; + cl.saveFile = false; + } else { + cl.saveFile = true; + } + } + } + if (returnCode == 2) { + cl.saveCharacter = true; + ByteBuf response = channel.alloc().buffer(3); + response.writeByte((byte) 2); + if (cl.playerRights == 3) { + response.writeByte((byte) 2); + } else { + response.writeByte((byte) cl.playerRights); + } + response.writeByte((byte) 0); + channel.write(response); + } else { + System.out.println("returncode:" + returnCode); + ByteBuf buffer = channel.alloc().buffer(1); + buffer.writeByte(returnCode); + channel.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE); + return; + } + cl.isActive = true; + channel.attr(ApolloHandler.SESSION_KEY).set(session); + + channel.pipeline().addBefore("handler", "gameDecoder", new RS2ProtocolDecoder(randomPair.getDecodingRandom())); + channel.pipeline().remove("loginDecoder"); + channel.pipeline().remove("loginEncoder"); + } + + /** + * Handles a login request. + * + * @param request The login request. + * @throws IOException If some I/O exception occurs. + */ + private void handleLoginRequest(LoginRequest request) throws IOException { + load(channel, request.getCredentials(), request.getRandomPair(), request.isReconnecting()); + } +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/Session.java b/2006Scape Server/src/main/java/org/apollo/game/session/Session.java new file mode 100644 index 00000000..9fa0233f --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/game/session/Session.java @@ -0,0 +1,49 @@ +package org.apollo.game.session; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +/** + * A session which is used as an attribute of a {@link ChannelHandlerContext} in Netty. + * + * @author Graham + */ +public abstract class Session { + + /** + * The channel. + */ + protected final Channel channel; + + /** + * Creates a session for the specified channel. + * + * @param channel The channel. + */ + public Session(Channel channel) { + this.channel = channel; + } + + /** + * Destroys this session. + */ + public abstract void destroy(); + + /** + * Processes a message received from the channel. + * + * @param message The message. + * @throws Exception If some error occurs. + */ + public abstract void messageReceived(Object message) throws Exception; + + /** + * Gets the channel. + * + * @return The channel. + */ + protected final Channel getChannel() { + return channel; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/UpdateSession.java b/2006Scape Server/src/main/java/org/apollo/game/session/UpdateSession.java new file mode 100644 index 00000000..0435b473 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/game/session/UpdateSession.java @@ -0,0 +1,48 @@ +package org.apollo.game.session; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpRequest; + +import org.apollo.jagcached.RequestWorkerPool; +import org.apollo.net.codec.jaggrab.JagGrabRequest; +import org.apollo.net.codec.update.OnDemandRequest; +import org.apollo.net.update.UpdateDispatcher; + +/** + * An update session. + * + * @author Graham + */ +public final class UpdateSession extends Session { + + /** + * Creates an update session for the specified channel. + * + * @param channel The channel. + * @param context The server context. + */ + public UpdateSession(Channel channel) { + super(channel); + } + + @Override + public void destroy() { + channel.close(); + } + + @Override + public void messageReceived(Object message) { + UpdateDispatcher dispatcher = RequestWorkerPool.getDispatcher(); + + if (message instanceof OnDemandRequest) { + dispatcher.dispatch(getChannel(), (OnDemandRequest) message); + } else if (message instanceof JagGrabRequest) { + dispatcher.dispatch(getChannel(), (JagGrabRequest) message); + } else if (message instanceof HttpRequest) { + dispatcher.dispatch(getChannel(), (HttpRequest) message); + } else { + throw new IllegalArgumentException("Unknown message type."); + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/package-info.java b/2006Scape Server/src/main/java/org/apollo/game/session/package-info.java new file mode 100644 index 00000000..1d20a30a --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/game/session/package-info.java @@ -0,0 +1,6 @@ +/** + * Contains {@link org.apollo.game.session.Session} classes which are the equivalent of Netty's + * {@link io.netty.channel.Channel}s but are designed for Apollo to use itself - unlike Netty's which are purely + * designed for networking. + */ +package org.apollo.game.session; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java b/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java index df330ff4..77ef6685 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java +++ b/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java @@ -1,25 +1,33 @@ package org.apollo.jagcached; import java.io.File; +import java.io.IOException; +import java.net.BindException; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.nio.file.Paths; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.logging.Logger; +import org.apollo.cache.IndexedFileSystem; +import org.apollo.game.session.ApolloHandler; +import org.apollo.net.HttpChannelInitializer; +import org.apollo.net.JagGrabChannelInitializer; +import org.apollo.net.NetworkConstants; +import org.apollo.net.ServiceChannelInitializer; -import org.apollo.jagcached.dispatch.RequestWorkerPool; -import org.apollo.jagcached.net.FileServerHandler; -import org.apollo.jagcached.net.HttpPipelineFactory; -import org.apollo.jagcached.net.JagGrabPipelineFactory; -import org.apollo.jagcached.net.NetworkConstants; -import org.apollo.jagcached.net.OnDemandPipelineFactory; -import org.jboss.netty.bootstrap.ServerBootstrap; -import org.jboss.netty.channel.ChannelPipelineFactory; -import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; -import org.jboss.netty.util.HashedWheelTimer; -import org.jboss.netty.util.Timer; +import com.rs2.GameConstants; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timer; /** * The core class of the file server. @@ -27,47 +35,45 @@ import org.jboss.netty.util.Timer; */ public final class FileServer { + /** + * The {@link ServerBootstrap} for the HTTP listener. + */ + private ServerBootstrap httpBootstrap; + + /** + * The {@link ServerBootstrap} for the JAGGRAB listener. + */ + private ServerBootstrap jaggrabBootstrap; + + /** + * The event loop group. + */ + private final EventLoopGroup loopGroup = new NioEventLoopGroup(); + + /** + * The {@link ServerBootstrap} for the service listener. + */ + private final ServerBootstrap serviceBootstrap = new ServerBootstrap(); + + /** * The logger for this class. */ private static final Logger logger = Logger.getLogger(FileServer.class.getName()); - /** - * The entry point of the application. - * @param args The command-line arguments. - */ - public static void main(String[] args) { - try { - new FileServer().start(); - } catch (Throwable t) { - logger.log(Level.SEVERE, "Error starting server.", t); - } - } - - /** - * The executor service. - */ - private final ExecutorService service = Executors.newCachedThreadPool(); /** * The request worker pool. */ - private final RequestWorkerPool pool = new RequestWorkerPool(); - - /** - * The file server event handler. - */ - private final FileServerHandler handler = new FileServerHandler(); - - /** - * The timer used for idle checking. - */ - private final Timer timer = new HashedWheelTimer(); - + private RequestWorkerPool pool; + + /** * Starts the file server. * @throws Exception if an error occurs. */ + public SocketAddress service = new InetSocketAddress((GameConstants.WORLD == 1) ? 43594 : 43596 + GameConstants.WORLD); + public void start() throws Exception { if (!new File(Constants.FILE_SYSTEM_DIR).exists()) { @@ -84,37 +90,92 @@ public final class FileServer { System.exit(1); } - logger.info("Starting workers..."); - pool.start(); - - logger.info("Starting services..."); - try { - start("HTTP", new HttpPipelineFactory(handler, timer), NetworkConstants.HTTP_PORT); - } catch (Throwable t) { - logger.log(Level.SEVERE, "Failed to start HTTP service.", t); - logger.warning("HTTP will be unavailable. JAGGRAB will be used as a fallback by clients but this isn't reccomended!"); + if(GameConstants.FILE_SERVER) { + httpBootstrap = new ServerBootstrap(); + jaggrabBootstrap = new ServerBootstrap(); + pool = new RequestWorkerPool(); + logger.info("Starting workers..."); + pool.start(); } - start("JAGGRAB", new JagGrabPipelineFactory(handler, timer), NetworkConstants.JAGGRAB_PORT); - start("ondemand", new OnDemandPipelineFactory(handler, timer), NetworkConstants.SERVICE_PORT); + logger.info("Starting services..."); + + init(); + SocketAddress http = new InetSocketAddress(NetworkConstants.HTTP_PORT); + SocketAddress jaggrab = new InetSocketAddress(NetworkConstants.JAGGRAB_PORT); + + bind(service, http, jaggrab); logger.info("Ready for connections."); } /** - * Starts the specified service. - * @param name The name of the service. - * @param pipelineFactory The pipeline factory. - * @param port The port. + * Initialises the server. + * + * @param releaseName The class name of the current active {@link Release}. + * @throws Exception If an error occurs. */ - private void start(String name, ChannelPipelineFactory pipelineFactory, int port) { - SocketAddress address = new InetSocketAddress(port); + public void init() throws Exception { - logger.info("Binding " + name + " service to " + address + "..."); - - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.setFactory(new NioServerSocketChannelFactory(service, service)); - bootstrap.setPipelineFactory(pipelineFactory); - bootstrap.bind(address); - } + serviceBootstrap.group(loopGroup); + if(GameConstants.FILE_SERVER) { + httpBootstrap.group(loopGroup); + jaggrabBootstrap.group(loopGroup); + } + ApolloHandler handler = new ApolloHandler(); + ChannelInitializer service = new ServiceChannelInitializer(handler); + serviceBootstrap.channel(NioServerSocketChannel.class); + serviceBootstrap.childHandler(service); + + if(!GameConstants.FILE_SERVER) + return; + ChannelInitializer http = new HttpChannelInitializer(handler); + httpBootstrap.channel(NioServerSocketChannel.class); + httpBootstrap.childHandler(http); + + ChannelInitializer jaggrab = new JagGrabChannelInitializer(handler); + jaggrabBootstrap.channel(NioServerSocketChannel.class); + jaggrabBootstrap.childHandler(jaggrab); + } + + /** + * Binds the server to the specified address. + * + * @param service The service address to bind to. + * @param http The HTTP address to bind to. + * @param jaggrab The JAGGRAB address to bind to. + * @throws BindException If the ServerBootstrap fails to bind to the SocketAddress. + */ + public void bind(SocketAddress service, SocketAddress http, SocketAddress jaggrab) throws IOException { + logger.fine("Binding service listener to address: " + service + "..."); + bind(serviceBootstrap, service); + if (GameConstants.FILE_SERVER) { + try { + logger.fine("Binding HTTP listener to address: " + http + "..."); + bind(httpBootstrap, http); + } catch (IOException cause) { + logger.log(Level.WARNING, "Unable to bind to HTTP - JAGGRAB will be used as a fallback.", cause); + } + + logger.fine("Binding JAGGRAB listener to address: " + jaggrab + "..."); + bind(jaggrabBootstrap, jaggrab); + } + logger.info("Ready for connections."); + } + + /** + * Attempts to bind the specified ServerBootstrap to the specified SocketAddress. + * + * @param bootstrap The ServerBootstrap. + * @param address The SocketAddress. + * @throws IOException If the ServerBootstrap fails to bind to the SocketAddress. + */ + private void bind(ServerBootstrap bootstrap, SocketAddress address) throws IOException { + try { + bootstrap.bind(address).sync(); + } catch (Exception cause) { + throw new IOException("Failed to bind to " + address, cause); + } + } + } diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorkerPool.java b/2006Scape Server/src/main/java/org/apollo/jagcached/RequestWorkerPool.java similarity index 60% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorkerPool.java rename to 2006Scape Server/src/main/java/org/apollo/jagcached/RequestWorkerPool.java index da3856df..87805a95 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorkerPool.java +++ b/2006Scape Server/src/main/java/org/apollo/jagcached/RequestWorkerPool.java @@ -1,13 +1,18 @@ -package org.apollo.jagcached.dispatch; +package org.apollo.jagcached; -import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import org.apollo.jagcached.Constants; -import org.apollo.jagcached.fs.IndexedFileSystem; +import org.apollo.cache.IndexedFileSystem; +import org.apollo.net.update.HttpRequestWorker; +import org.apollo.net.update.JagGrabRequestWorker; +import org.apollo.net.update.OnDemandRequestWorker; +import org.apollo.net.update.RequestWorker; +import org.apollo.net.update.UpdateDispatcher; /** * A class which manages the pool of request workers. @@ -36,6 +41,15 @@ public final class RequestWorkerPool { */ private final List> workers = new ArrayList>(); + /** + * Gets the update dispatcher. + * + * @return The update dispatcher. + */ + public static UpdateDispatcher getDispatcher() { + return dispatcher; + } + /** * The request worker pool. */ @@ -43,17 +57,18 @@ public final class RequestWorkerPool { int totalThreads = REQUEST_TYPES * THREADS_PER_REQUEST_TYPE; service = Executors.newFixedThreadPool(totalThreads); } + private static final UpdateDispatcher dispatcher = new UpdateDispatcher(); /** * Starts the threads in the pool. * @throws Exception if the file system cannot be created. */ public void start() throws Exception { - File base = new File(Constants.FILE_SYSTEM_DIR); + Path base = Paths.get(Constants.FILE_SYSTEM_DIR); for (int i = 0; i < THREADS_PER_REQUEST_TYPE; i++) { - workers.add(new JagGrabRequestWorker(new IndexedFileSystem(base, true))); - workers.add(new OnDemandRequestWorker(new IndexedFileSystem(base, true))); - workers.add(new HttpRequestWorker(new IndexedFileSystem(base, true))); + workers.add(new JagGrabRequestWorker(dispatcher, new IndexedFileSystem(base, true))); + workers.add(new OnDemandRequestWorker(dispatcher, new IndexedFileSystem(base, true))); + workers.add(new HttpRequestWorker(dispatcher, new IndexedFileSystem(base, true))); } for (RequestWorker worker : workers) { diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/HttpRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/HttpRequestWorker.java deleted file mode 100644 index e3770f8d..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/HttpRequestWorker.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.apollo.jagcached.dispatch; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Date; - -import org.apollo.jagcached.fs.IndexedFileSystem; -import org.apollo.jagcached.resource.CombinedResourceProvider; -import org.apollo.jagcached.resource.HypertextResourceProvider; -import org.apollo.jagcached.resource.ResourceProvider; -import org.apollo.jagcached.resource.VirtualResourceProvider; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelFutureListener; -import org.jboss.netty.handler.codec.http.DefaultHttpResponse; -import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpResponse; -import org.jboss.netty.handler.codec.http.HttpResponseStatus; - -/** - * A worker which services HTTP requests. - * @author Graham - */ -public final class HttpRequestWorker extends RequestWorker { - - /** - * The value of the server header. - */ - private static final String SERVER_IDENTIFIER = "JAGeX/3.1"; - - /** - * The directory with web files. - */ - private static final File WWW_DIRECTORY = new File("./data/www/"); - - /** - * The default character set. - */ - private static final Charset CHARACTER_SET = Charset.forName("ISO-8859-1"); - - /** - * Creates the HTTP request worker. - * @param fs The file system. - */ - public HttpRequestWorker(IndexedFileSystem fs) { - super(new CombinedResourceProvider(new VirtualResourceProvider(fs), new HypertextResourceProvider(WWW_DIRECTORY))); - } - - @Override - protected ChannelRequest nextRequest() throws InterruptedException { - return RequestDispatcher.nextHttpRequest(); - } - - @Override - protected void service(ResourceProvider provider, Channel channel, HttpRequest request) throws IOException { - String path = request.getUri(); - ByteBuffer buf = provider.get(path); - - ChannelBuffer wrappedBuf; - HttpResponseStatus status = HttpResponseStatus.OK; - - String mimeType = getMimeType(request.getUri()); - - if (buf == null) { - status = HttpResponseStatus.NOT_FOUND; - wrappedBuf = createErrorPage(status, "The page you requested could not be found."); - mimeType = "text/html"; - } else { - wrappedBuf = ChannelBuffers.wrappedBuffer(buf); - } - - HttpResponse resp = new DefaultHttpResponse(request.getProtocolVersion(), status); - - resp.setHeader("Date", new Date()); - resp.setHeader("Server", SERVER_IDENTIFIER); - resp.setHeader("Content-type", mimeType + ", charset=" + CHARACTER_SET.name()); - resp.setHeader("Cache-control", "no-cache"); - resp.setHeader("Pragma", "no-cache"); - resp.setHeader("Expires", new Date(0)); - resp.setHeader("Connection", "close"); - resp.setHeader("Content-length", wrappedBuf.readableBytes()); - resp.setChunked(false); - resp.setContent(wrappedBuf); - - channel.write(resp).addListener(ChannelFutureListener.CLOSE); - } - - /** - * Gets the MIME type of a file by its name. - * @param name The file name. - * @return The MIME type. - */ - private String getMimeType(String name) { - if (name.endsWith(".htm") || name.endsWith(".html")) { - return "text/html"; - } else if (name.endsWith(".css")) { - return "text/css"; - } else if (name.endsWith(".js")) { - return "text/javascript"; - } else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) { - return "image/jpeg"; - } else if (name.endsWith(".gif")) { - return "image/gif"; - } else if (name.endsWith(".png")) { - return "image/png"; - } else if (name.endsWith(".txt")) { - return "text/plain"; - } - return "application/octect-stream"; - } - - /** - * Creates an error page. - * @param status The HTTP status. - * @param description The error description. - * @return The error page as a buffer. - */ - private ChannelBuffer createErrorPage(HttpResponseStatus status, String description) { - String title = status.getCode() + " " + status.getReasonPhrase(); - - StringBuilder bldr = new StringBuilder(); - - bldr.append(""); - bldr.append(title); - bldr.append("

"); - bldr.append(title); - bldr.append("

"); - bldr.append(description); - bldr.append("


"); - bldr.append(SERVER_IDENTIFIER); - bldr.append(" Server
"); - - return ChannelBuffers.copiedBuffer(bldr.toString(), Charset.defaultCharset()); - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/JagGrabRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/JagGrabRequestWorker.java deleted file mode 100644 index b2222a79..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/JagGrabRequestWorker.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.apollo.jagcached.dispatch; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import org.apollo.jagcached.fs.IndexedFileSystem; -import org.apollo.jagcached.net.jaggrab.JagGrabRequest; -import org.apollo.jagcached.net.jaggrab.JagGrabResponse; -import org.apollo.jagcached.resource.ResourceProvider; -import org.apollo.jagcached.resource.VirtualResourceProvider; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelFutureListener; - -/** - * A worker which services JAGGRAB requests. - * @author Graham - */ -public final class JagGrabRequestWorker extends RequestWorker { - - /** - * Creates the JAGGRAB request worker. - * @param fs The file system. - */ - public JagGrabRequestWorker(IndexedFileSystem fs) { - super(new VirtualResourceProvider(fs)); - } - - @Override - protected ChannelRequest nextRequest() throws InterruptedException { - return RequestDispatcher.nextJagGrabRequest(); - } - - @Override - protected void service(ResourceProvider provider, Channel channel, JagGrabRequest request) throws IOException { - ByteBuffer buf = provider.get(request.getFilePath()); - if (buf == null) { - channel.close(); - } else { - ChannelBuffer wrapped = ChannelBuffers.wrappedBuffer(buf); - channel.write(new JagGrabResponse(wrapped)).addListener(ChannelFutureListener.CLOSE); - } - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/OnDemandRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/OnDemandRequestWorker.java deleted file mode 100644 index 98d4a421..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/OnDemandRequestWorker.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.apollo.jagcached.dispatch; - -import java.io.IOException; -import java.nio.ByteBuffer; - - -import org.apollo.jagcached.fs.FileDescriptor; -import org.apollo.jagcached.fs.IndexedFileSystem; -import org.apollo.jagcached.net.ondemand.OnDemandRequest; -import org.apollo.jagcached.net.ondemand.OnDemandResponse; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; - -/** - * A worker which services 'on-demand' requests. - * @author Graham - */ -public final class OnDemandRequestWorker extends RequestWorker { - - /** - * The maximum length of a chunk, in bytes. - */ - private static final int CHUNK_LENGTH = 500; - - /** - * Creates the 'on-demand' request worker. - * @param fs The file system. - */ - public OnDemandRequestWorker(IndexedFileSystem fs) { - super(fs); - } - - @Override - protected ChannelRequest nextRequest() throws InterruptedException { - return RequestDispatcher.nextOnDemandRequest(); - } - - @Override - protected void service(IndexedFileSystem fs, Channel channel, OnDemandRequest request) throws IOException { - FileDescriptor desc = request.getFileDescriptor(); - - ByteBuffer buf = fs.getFile(desc); - int length = buf.remaining(); - - for (int chunk = 0; buf.remaining() > 0; chunk++) { - int chunkSize = buf.remaining(); - if (chunkSize > CHUNK_LENGTH) { - chunkSize = CHUNK_LENGTH; - } - - byte[] tmp = new byte[chunkSize]; - buf.get(tmp, 0, tmp.length); - ChannelBuffer chunkData = ChannelBuffers.wrappedBuffer(tmp, 0, chunkSize); - - OnDemandResponse response = new OnDemandResponse(desc, length, chunk, chunkData); - channel.write(response); - } - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestDispatcher.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestDispatcher.java deleted file mode 100644 index da6af96d..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestDispatcher.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.apollo.jagcached.dispatch; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.PriorityBlockingQueue; - - -import org.apollo.jagcached.net.jaggrab.JagGrabRequest; -import org.apollo.jagcached.net.ondemand.OnDemandRequest; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.handler.codec.http.HttpRequest; - -/** - * A class which dispatches requests to worker threads. - * @author Graham - */ -public final class RequestDispatcher { - - /** - * The maximum size of a queue before requests are rejected. - */ - private static final int MAXIMUM_QUEUE_SIZE = 1024; - - /** - * A queue for pending 'on-demand' requests. - */ - private static final BlockingQueue> onDemandQueue = new PriorityBlockingQueue>(); - - /** - * A queue for pending JAGGRAB requests. - */ - private static final BlockingQueue> jagGrabQueue = new LinkedBlockingQueue>(); - - /** - * A queue for pending HTTP requests. - */ - private static final BlockingQueue> httpQueue = new LinkedBlockingQueue>(); - - /** - * Gets the next 'on-demand' request from the queue, blocking if none are - * available. - * @return The 'on-demand' request. - * @throws InterruptedException if the thread is interrupted. - */ - static ChannelRequest nextOnDemandRequest() throws InterruptedException { - return onDemandQueue.take(); - } - - /** - * Gets the next JAGGRAB request from the queue, blocking if none are - * available. - * @return The JAGGRAB request. - * @throws InterruptedException if the thread is interrupted. - */ - static ChannelRequest nextJagGrabRequest() throws InterruptedException { - return jagGrabQueue.take(); - } - - /** - * Gets the next HTTP request from the queue, blocking if none are - * available. - * @return The HTTP request. - * @throws InterruptedException if the thread is interrupted. - */ - static ChannelRequest nextHttpRequest() throws InterruptedException { - return httpQueue.take(); - } - - /** - * Dispatches an 'on-demand' request. - * @param channel The channel. - * @param request The request. - */ - public static void dispatch(Channel channel, OnDemandRequest request) { - if (onDemandQueue.size() >= MAXIMUM_QUEUE_SIZE) { - channel.close(); - } - onDemandQueue.add(new ChannelRequest(channel, request)); - } - - /** - * Dispatches a JAGGRAB request. - * @param channel The channel. - * @param request The request. - */ - public static void dispatch(Channel channel, JagGrabRequest request) { - if (jagGrabQueue.size() >= MAXIMUM_QUEUE_SIZE) { - channel.close(); - } - jagGrabQueue.add(new ChannelRequest(channel, request)); - } - - /** - * Dispatches a HTTP request. - * @param channel The channel. - * @param request The request. - */ - public static void dispatch(Channel channel, HttpRequest request) { - if (httpQueue.size() >= MAXIMUM_QUEUE_SIZE) { - channel.close(); - } - httpQueue.add(new ChannelRequest(channel, request)); - } - - /** - * Default private constructor to prevent instantiation. - */ - private RequestDispatcher() { - - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/IndexedFileSystem.java b/2006Scape Server/src/main/java/org/apollo/jagcached/fs/IndexedFileSystem.java deleted file mode 100644 index 2e53372b..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/IndexedFileSystem.java +++ /dev/null @@ -1,361 +0,0 @@ -package org.apollo.jagcached.fs; - -import java.io.Closeable; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.util.zip.CRC32; - -/** - * A file system based on top of the operating system's file system. It - * consists of a data file and index files. Index files point to blocks in the - * data file, which contains the actual data. - * @author Graham - * @author Ryley Kimmel - */ -public final class IndexedFileSystem implements Closeable { - - /** - * Read only flag. - */ - private final boolean readOnly; - - /** - * The index files. - */ - private RandomAccessFile[] indices = new RandomAccessFile[256]; - - /** - * The data file. - */ - private RandomAccessFile data; - - /** - * The cached CRC table. - */ - private ByteBuffer crcTable; - - /** - * Creates the file system with the specified base directory. - * @param base The base directory. - * @param readOnly A flag indicating if the file system will be read only. - * @throws Exception if the file system is invalid. - */ - public IndexedFileSystem(File base, boolean readOnly) throws Exception { - this.readOnly = readOnly; - detectLayout(base); - } - - /** - * Checks if this {@link IndexedFileSystem} is read only. - * @return {@code true} if so, {@code false} if not. - */ - public boolean isReadOnly() { - return readOnly; - } - - /** - * Automatically detect the layout of the specified directory. - * @param base The base directory. - * @throws Exception if the file system is invalid. - */ - private void detectLayout(File base) throws Exception { - int indexCount = 0; - for (int index = 0; index < indices.length; index++) { - File f = new File(base.getAbsolutePath() + "/main_file_cache.idx" + index); - if (f.exists() && !f.isDirectory()) { - indexCount++; - indices[index] = new RandomAccessFile(f, readOnly ? "r" : "rw"); - } - } - if (indexCount <= 0) { - throw new Exception("No index file(s) present"); - } - - File dataFile = new File(base.getAbsolutePath() + "/main_file_cache.dat"); - if (dataFile.exists() && !dataFile.isDirectory()) { - data = new RandomAccessFile(dataFile, readOnly ? "r" : "rw"); - } else { - throw new Exception("No data file present"); - } - } - - /** - * Gets the index of a file. - * @param fd The {@link FileDescriptor} which points to the file. - * @return The {@link Index}. - * @throws IOException if an I/O error occurs. - */ - private Index getIndex(FileDescriptor fd) throws IOException { - int index = fd.getType(); - if (index < 0 || index >= indices.length) { - throw new IndexOutOfBoundsException(); - } - - byte[] buffer = new byte[FileSystemConstants.INDEX_SIZE]; - RandomAccessFile indexFile = indices[index]; - synchronized (indexFile) { - long ptr = (long) fd.getFile() * (long) FileSystemConstants.INDEX_SIZE; - if (ptr >= 0 && indexFile.length() >= (ptr + FileSystemConstants.INDEX_SIZE)) { - indexFile.seek(ptr); - indexFile.readFully(buffer); - } else { - throw new FileNotFoundException(); - } - } - - return Index.decode(buffer); - } - - /** - * Gets the number of files with the specified type. - * @param type The type. - * @return The number of files. - * @throws IOException if an I/O error occurs. - */ - private int getFileCount(int type) throws IOException { - if (type < 0 || type >= indices.length) { - throw new IndexOutOfBoundsException(); - } - - RandomAccessFile indexFile = indices[type]; - synchronized (indexFile) { - return (int) (indexFile.length() / FileSystemConstants.INDEX_SIZE); - } - } - - /** - * Gets the CRC table. - * @return The CRC table. - * @throws IOException if an I/O erorr occurs. - */ - public ByteBuffer getCrcTable() throws IOException { - if (readOnly) { - synchronized (this) { - if (crcTable != null) { - return crcTable.slice(); - } - } - - // the number of archives - int archives = getFileCount(0); - - // the hash - int hash = 1234; - - // the CRCs - int[] crcs = new int[archives]; - - // calculate the CRCs - CRC32 crc32 = new CRC32(); - for (int i = 1; i < crcs.length; i++) { - crc32.reset(); - - ByteBuffer bb = getFile(0, i); - byte[] bytes = new byte[bb.remaining()]; - bb.get(bytes, 0, bytes.length); - crc32.update(bytes, 0, bytes.length); - - crcs[i] = (int) crc32.getValue(); - } - - // hash the CRCs and place them in the buffer - ByteBuffer buf = ByteBuffer.allocate(crcs.length * 4 + 4); - for (int i = 0; i < crcs.length; i++) { - hash = (hash << 1) + crcs[i]; - buf.putInt(crcs[i]); - } - - // place the hash into the buffer - buf.putInt(hash); - buf.flip(); - - synchronized (this) { - crcTable = buf; - return crcTable.slice(); - } - } else { - throw new IOException("cannot get CRC table from a writable file system"); - } - } - - /** - * Gets a file. - * @param type The file type. - * @param file The file id. - * @return A {@link ByteBuffer} which contains the contents of the file. - * @throws IOException if an I/O error occurs. - */ - public ByteBuffer getFile(int type, int file) throws IOException { - return getFile(new FileDescriptor(type, file)); - } - - /** - * Gets a file. - * @param fd The {@link FileDescriptor} which points to the file. - * @return A {@link ByteBuffer} which contains the contents of the file. - * @throws IOException if an I/O error occurs. - */ - public ByteBuffer getFile(FileDescriptor fd) throws IOException { - Index index = getIndex(fd); - ByteBuffer buffer = ByteBuffer.allocate(index.getSize()); - - // calculate some initial values - long ptr = (long) index.getBlock() * (long) FileSystemConstants.BLOCK_SIZE; - int read = 0; - int size = index.getSize(); - int blocks = size / FileSystemConstants.CHUNK_SIZE; - if (size % FileSystemConstants.CHUNK_SIZE != 0) { - blocks++; - } - - for (int i = 0; i < blocks; i++) { - - // read header - byte[] header = new byte[FileSystemConstants.HEADER_SIZE]; - synchronized (data) { - data.seek(ptr); - data.readFully(header); - } - - // increment pointers - ptr += FileSystemConstants.HEADER_SIZE; - - // parse header - int nextFile = ((header[0] & 0xFF) << 8) | (header[1] & 0xFF); - int curChunk = ((header[2] & 0xFF) << 8) | (header[3] & 0xFF); - int nextBlock = ((header[4] & 0xFF) << 16) | ((header[5] & 0xFF) << 8) | (header[6] & 0xFF); - int nextType = header[7] & 0xFF; - - // check expected chunk id is correct - if (i != curChunk) { - throw new IOException("Chunk id mismatch."); - } - - // calculate how much we can read - int chunkSize = size - read; - if (chunkSize > FileSystemConstants.CHUNK_SIZE) { - chunkSize = FileSystemConstants.CHUNK_SIZE; - } - - // read the next chunk and put it in the buffer - byte[] chunk = new byte[chunkSize]; - synchronized (data) { - data.seek(ptr); - data.readFully(chunk); - } - buffer.put(chunk); - - // increment pointers - read += chunkSize; - ptr = (long) nextBlock * (long) FileSystemConstants.BLOCK_SIZE; - - // if we still have more data to read, check the validity of the - // header - if (size > read) { - if (nextType != (fd.getType() + 1)) { - throw new IOException("File type mismatch."); - } - - if (nextFile != fd.getFile()) { - throw new IOException("File id mismatch."); - } - } - } - - buffer.flip(); - return buffer; - } - - public byte[] getFileBytes(int type, int file) throws IOException { - return getFileBytes(new FileDescriptor(type, file)); - } - - public byte[] getFileBytes(FileDescriptor fd) throws IOException { - Index index = getIndex(fd); - byte[] decompressed = new byte[index.getSize()]; - - // calculate some initial values - long ptr = (long) index.getBlock() * (long) FileSystemConstants.BLOCK_SIZE; - int read = 0; - int size = index.getSize(); - int blocks = size / FileSystemConstants.CHUNK_SIZE; - if (size % FileSystemConstants.CHUNK_SIZE != 0) { - blocks++; - } - - for (int i = 0; i < blocks; i++) { - - // read header - byte[] header = new byte[FileSystemConstants.HEADER_SIZE]; - synchronized (data) { - data.seek(ptr); - data.readFully(header); - } - - // increment pointers - ptr += FileSystemConstants.HEADER_SIZE; - - // parse header - int nextFile = ((header[0] & 0xFF) << 8) | (header[1] & 0xFF); - int curChunk = ((header[2] & 0xFF) << 8) | (header[3] & 0xFF); - int nextBlock = ((header[4] & 0xFF) << 16) | ((header[5] & 0xFF) << 8) | (header[6] & 0xFF); - int nextType = header[7] & 0xFF; - - // check expected chunk id is correct - if (i != curChunk) { - throw new IOException("Chunk id mismatch."); - } - - // calculate how much we can read - int chunkSize = size - read; - if (chunkSize > FileSystemConstants.CHUNK_SIZE) { - chunkSize = FileSystemConstants.CHUNK_SIZE; - } - - // read the next chunk and put it in the buffer - synchronized (data) { - data.seek(ptr); - data.readFully(decompressed, read, chunkSize); - } - - // increment pointers - read += chunkSize; - ptr = (long) nextBlock * (long) FileSystemConstants.BLOCK_SIZE; - - // if we still have more data to read, check the validity of the - // header - if (size > read) { - if (nextType != (fd.getType() + 1)) { - throw new IOException("File type mismatch."); - } - - if (nextFile != fd.getFile()) { - throw new IOException("File id mismatch."); - } - } - } - - return decompressed; - } - - @Override - public void close() throws IOException { - if (data != null) { - synchronized (data) { - data.close(); - } - } - - for (RandomAccessFile index : indices) { - if (index != null) { - synchronized (index) { - index.close(); - } - } - } - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/FileServerHandler.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/FileServerHandler.java deleted file mode 100644 index 4383724d..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/FileServerHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.apollo.jagcached.net; - -import java.util.logging.Level; -import java.util.logging.Logger; - - -import org.apollo.jagcached.FileServer; -import org.apollo.jagcached.dispatch.RequestDispatcher; -import org.apollo.jagcached.net.jaggrab.JagGrabRequest; -import org.apollo.jagcached.net.ondemand.OnDemandRequest; -import org.apollo.jagcached.net.service.ServiceRequest; -import org.apollo.jagcached.net.service.ServiceResponse; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.MessageEvent; -import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler; -import org.jboss.netty.handler.timeout.IdleStateEvent; - -/** - * An {@link IdleStateAwareChannelUpstreamHandler} for the {@link FileServer}. - * @author Graham - */ -public final class FileServerHandler extends IdleStateAwareChannelUpstreamHandler { - - /** - * The logger for this class. - */ - private static final Logger logger = Logger.getLogger(FileServerHandler.class.getName()); - - @Override - public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception { - e.getChannel().close(); - } - - @Override - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { - Object msg = e.getMessage(); - if (msg instanceof ServiceRequest) { - ServiceRequest request = (ServiceRequest) msg; - if (request.getId() != ServiceRequest.SERVICE_ONDEMAND) { - e.getChannel().close(); - } else { - e.getChannel().write(new ServiceResponse()); - } - } else if (msg instanceof OnDemandRequest) { - RequestDispatcher.dispatch(e.getChannel(), (OnDemandRequest) msg); - } else if (msg instanceof JagGrabRequest) { - RequestDispatcher.dispatch(e.getChannel(), (JagGrabRequest) msg); - } else if (msg instanceof HttpRequest) { - RequestDispatcher.dispatch(e.getChannel(), (HttpRequest) msg); - } else { - throw new Exception("unknown message type"); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - logger.log(Level.SEVERE, "Exception occured, closing channel...", e.getCause()); - e.getChannel().close(); - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/HttpPipelineFactory.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/HttpPipelineFactory.java deleted file mode 100644 index 66df879d..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/HttpPipelineFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.apollo.jagcached.net; - -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelPipelineFactory; -import org.jboss.netty.channel.Channels; -import org.jboss.netty.handler.codec.http.HttpChunkAggregator; -import org.jboss.netty.handler.codec.http.HttpRequestDecoder; -import org.jboss.netty.handler.codec.http.HttpResponseEncoder; -import org.jboss.netty.handler.timeout.IdleStateHandler; -import org.jboss.netty.util.Timer; - -/** - * A {@link ChannelPipelineFactory} for the HTTP protocol. - * @author Graham - */ -public final class HttpPipelineFactory implements ChannelPipelineFactory { - - /** - * The maximum length of a request, in bytes. - */ - private static final int MAX_REQUEST_LENGTH = 8192; - - /** - * The file server event handler. - */ - private final FileServerHandler handler; - - /** - * The timer used for idle checking. - */ - private final Timer timer; - - /** - * Creates the HTTP pipeline factory. - * @param handler The file server event handler. - * @param timer The timer used for idle checking. - */ - public HttpPipelineFactory(FileServerHandler handler, Timer timer) { - this.handler = handler; - this.timer = timer; - } - - @Override - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = Channels.pipeline(); - - // decoders - pipeline.addLast("decoder", new HttpRequestDecoder()); - pipeline.addLast("chunker", new HttpChunkAggregator(MAX_REQUEST_LENGTH)); - - // encoders - pipeline.addLast("encoder", new HttpResponseEncoder()); - - // handler - pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0)); - pipeline.addLast("handler", handler); - - return pipeline; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/JagGrabPipelineFactory.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/JagGrabPipelineFactory.java deleted file mode 100644 index 5c0f7250..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/JagGrabPipelineFactory.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.apollo.jagcached.net; - -import java.nio.charset.Charset; - - -import org.apollo.jagcached.net.jaggrab.JagGrabRequestDecoder; -import org.apollo.jagcached.net.jaggrab.JagGrabResponseEncoder; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelPipelineFactory; -import org.jboss.netty.channel.Channels; -import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; -import org.jboss.netty.handler.codec.string.StringDecoder; -import org.jboss.netty.handler.timeout.IdleStateHandler; -import org.jboss.netty.util.Timer; - -/** - * A {@link ChannelPipelineFactory} for the JAGGRAB protocol. - * @author Graham - */ -public final class JagGrabPipelineFactory implements ChannelPipelineFactory { - - /** - * The maximum length of a request, in bytes. - */ - private static final int MAX_REQUEST_LENGTH = 8192; - - /** - * The character set used in the request. - */ - private static final Charset JAGGRAB_CHARSET = Charset.forName("US-ASCII"); - - /** - * A buffer with two line feed (LF) characters in it. - */ - private static final ChannelBuffer DOUBLE_LINE_FEED_DELIMITER = ChannelBuffers.buffer(2); - - /** - * Populates the double line feed buffer. - */ - static { - DOUBLE_LINE_FEED_DELIMITER.writeByte(10); - DOUBLE_LINE_FEED_DELIMITER.writeByte(10); - } - - /** - * The file server event handler. - */ - private final FileServerHandler handler; - - /** - * The timer used for idle checking. - */ - private final Timer timer; - - /** - * Creates a {@code JAGGRAB} pipeline factory. - * @param handler The file server event handler. - * @param timer The timer used for idle checking. - */ - public JagGrabPipelineFactory(FileServerHandler handler, Timer timer) { - this.handler = handler; - this.timer = timer; - } - - @Override - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = Channels.pipeline(); - - // decoders - pipeline.addLast("framer", new DelimiterBasedFrameDecoder(MAX_REQUEST_LENGTH, DOUBLE_LINE_FEED_DELIMITER)); - pipeline.addLast("string-decoder", new StringDecoder(JAGGRAB_CHARSET)); - pipeline.addLast("jaggrab-decoder", new JagGrabRequestDecoder()); - - // encoders - pipeline.addLast("jaggrab-encoder", new JagGrabResponseEncoder()); - - // handler - pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0)); - pipeline.addLast("handler", handler); - - return pipeline; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/NetworkConstants.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/NetworkConstants.java deleted file mode 100644 index 04c2bf76..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/NetworkConstants.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.apollo.jagcached.net; - -/** - * A class which holds network-related constants. - * @author Graham - */ -public final class NetworkConstants { - - /** - * The HTTP port. - */ - public static final int HTTP_PORT = 8080; - - /** - * The JAGGRAB port. - */ - public static final int JAGGRAB_PORT = 43595; - - /** - * The service port (which is also used for the 'on-demand' protocol). - */ - public static final int SERVICE_PORT = 43596; - - /** - * The number of seconds a channel can be idle before being closed - * automatically. - */ - public static final int IDLE_TIME = 15; - - /** - * Default private constructor to prevent instantiaton. - */ - private NetworkConstants() { - - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/OnDemandPipelineFactory.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/OnDemandPipelineFactory.java deleted file mode 100644 index 7dcad1e2..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/OnDemandPipelineFactory.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.apollo.jagcached.net; - - -import org.apollo.jagcached.net.ondemand.OnDemandRequestDecoder; -import org.apollo.jagcached.net.ondemand.OnDemandResponseEncoder; -import org.apollo.jagcached.net.service.ServiceRequestDecoder; -import org.apollo.jagcached.net.service.ServiceResponseEncoder; -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelPipelineFactory; -import org.jboss.netty.channel.Channels; -import org.jboss.netty.handler.timeout.IdleStateHandler; -import org.jboss.netty.util.Timer; - -/** - * A {@link ChannelPipelineFactory} for the 'on-demand' protocol. - * @author Graham - */ -public final class OnDemandPipelineFactory implements ChannelPipelineFactory { - - /** - * The file server event handler. - */ - private final FileServerHandler handler; - - /** - * The timer used for idle checking. - */ - private final Timer timer; - - /** - * Creates an 'on-demand' pipeline factory. - * @param handler The file server event handler. - * @param timer The timer used for idle checking. - */ - public OnDemandPipelineFactory(FileServerHandler handler, Timer timer) { - this.handler = handler; - this.timer = timer; - } - - @Override - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = Channels.pipeline(); - - // decoders - pipeline.addLast("serviceDecoder", new ServiceRequestDecoder()); - pipeline.addLast("decoder", new OnDemandRequestDecoder()); - - // encoders - pipeline.addLast("serviceEncoder", new ServiceResponseEncoder()); - pipeline.addLast("encoder", new OnDemandResponseEncoder()); - - // handler - pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0)); - pipeline.addLast("handler", handler); - - return pipeline; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequestDecoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequestDecoder.java deleted file mode 100644 index 924d5bac..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequestDecoder.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.apollo.jagcached.net.jaggrab; - -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; - -/** - * A {@link OneToOneDecoder} for the JAGGRAB protocol. - * @author Graham - */ -public final class JagGrabRequestDecoder extends OneToOneDecoder { - - @Override - protected Object decode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception { - if (msg instanceof String) { - String str = ((String) msg); - if (str.startsWith("JAGGRAB /")) { - String filePath = str.substring(8).trim(); - return new JagGrabRequest(filePath); - } else { - throw new Exception("corrupted request line"); - } - } - return msg; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponseEncoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponseEncoder.java deleted file mode 100644 index c24e1066..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponseEncoder.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.apollo.jagcached.net.jaggrab; - -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; - -/** - * A {@link OneToOneEncoder} for the JAGGRAB protocol. - * @author Graham - */ -public final class JagGrabResponseEncoder extends OneToOneEncoder { - - @Override - protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception { - if (msg instanceof JagGrabResponse) { - JagGrabResponse resp = (JagGrabResponse) msg; - return resp.getFileData(); - } - return msg; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequest.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequest.java deleted file mode 100644 index 0eac7c3f..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequest.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.apollo.jagcached.net.ondemand; - -import org.apollo.jagcached.fs.FileDescriptor; - -/** - * Represents a single 'on-demand' request. - * @author Graham - * @author Ryley Kimmel - */ -public final class OnDemandRequest implements Comparable { - - /** - * An enumeration containing the different request priorities. - * @author Graham - */ - public enum Priority { - - /** - * High priority - used in-game when data is required immediately but - * has not yet been received. - */ - HIGH, - - /** - * Medium priority - used while loading the 'bare minimum' required to - * run the game. - */ - MEDIUM, - - /** - * Low priority - used when a file is not required urgently. The client - * login screen says "loading extra files.." when low priority loading - * is being performed. - */ - LOW; - - /** - * Converts the integer value to a priority. - * @param v The integer value. - * @return The priority. - * @throws IllegalArgumentException if the value is outside of the - * range 1-3 inclusive. - */ - public static Priority valueOf(int v) { - switch (v) { - case 0: - return HIGH; - case 1: - return MEDIUM; - case 2: - return LOW; - default: - throw new IllegalArgumentException("priority out of range"); - } - } - - } - - /** - * The file descriptor. - */ - private final FileDescriptor fileDescriptor; - - /** - * The request priority. - */ - private final Priority priority; - - /** - * Creates the 'on-demand' request. - * @param fileDescriptor The file descriptor. - * @param priority The priority. - */ - public OnDemandRequest(FileDescriptor fileDescriptor, Priority priority) { - this.fileDescriptor = fileDescriptor; - this.priority = priority; - } - - /** - * Gets the file descriptor. - * @return The file descriptor. - */ - public FileDescriptor getFileDescriptor() { - return fileDescriptor; - } - - /** - * Gets the priority. - * @return The priority. - */ - public Priority getPriority() { - return priority; - } - - @Override - public int compareTo(OnDemandRequest o) { - int thisPriority = priority.ordinal(); - int otherPriority = o.priority.ordinal(); - - if (thisPriority < otherPriority) { - return 1; - } else if (thisPriority == otherPriority) { - return 0; - } else { - return -1; - } - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequestDecoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequestDecoder.java deleted file mode 100644 index 130de142..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequestDecoder.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.apollo.jagcached.net.ondemand; - - -import org.apollo.jagcached.fs.FileDescriptor; -import org.apollo.jagcached.net.ondemand.OnDemandRequest.Priority; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.frame.FrameDecoder; - -/** - * A {@link FrameDecoder} for the 'on-demand' protocol. - * @author Graham - */ -public final class OnDemandRequestDecoder extends FrameDecoder { - - @Override - protected Object decode(ChannelHandlerContext ctx, Channel c, ChannelBuffer buf) throws Exception { - if (buf.readableBytes() >= 4) { - int type = buf.readUnsignedByte() + 1; - int file = buf.readUnsignedShort(); - int priority = buf.readUnsignedByte(); - - FileDescriptor desc = new FileDescriptor(type, file); - Priority p = Priority.valueOf(priority); - - return new OnDemandRequest(desc, p); - } - return null; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponseEncoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponseEncoder.java deleted file mode 100644 index 965a24ba..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponseEncoder.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.apollo.jagcached.net.ondemand; - - -import org.apollo.jagcached.fs.FileDescriptor; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; - -/** - * A {@link OneToOneEncoder} for the 'on-demand' protocol. - * @author Graham - */ -public final class OnDemandResponseEncoder extends OneToOneEncoder { - - @Override - protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception { - if (msg instanceof OnDemandResponse) { - OnDemandResponse resp = (OnDemandResponse) msg; - - FileDescriptor fileDescriptor = resp.getFileDescriptor(); - int fileSize = resp.getFileSize(); - int chunkId = resp.getChunkId(); - ChannelBuffer chunkData = resp.getChunkData(); - - ChannelBuffer buf = ChannelBuffers.buffer(6 + chunkData.readableBytes()); - buf.writeByte(fileDescriptor.getType() - 1); - buf.writeShort(fileDescriptor.getFile()); - buf.writeShort(fileSize); - buf.writeByte(chunkId); - buf.writeBytes(chunkData); - - return buf; - } - return msg; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequest.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequest.java deleted file mode 100644 index 36833128..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequest.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.apollo.jagcached.net.service; - -/** - * Represents a service request message. - * @author Graham - */ -public final class ServiceRequest { - - /** - * The game service id. - */ - public static final int SERVICE_GAME = 14; - - /** - * The 'on-demand' service id. - */ - public static final int SERVICE_ONDEMAND = 15; - - /** - * The service id. - */ - private final int id; - - /** - * Creates a service request. - * @param id The service id. - */ - public ServiceRequest(int id) { - this.id = id; - } - - /** - * Gets the service id. - * @return The service id. - */ - public int getId() { - return id; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequestDecoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequestDecoder.java deleted file mode 100644 index 4128c83f..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequestDecoder.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.apollo.jagcached.net.service; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.handler.codec.frame.FrameDecoder; - -/** - * A {@link FrameDecoder} which decodes {@link ServiceRequest} messages. - * @author Graham - */ -public final class ServiceRequestDecoder extends FrameDecoder { - - /** - * Creates the decoder, enabling the 'unfold' mechanism. - */ - public ServiceRequestDecoder() { - super(true); - } - - @Override - protected Object decode(ChannelHandlerContext ctx, Channel c, ChannelBuffer buf) throws Exception { - if (buf.readable()) { - ServiceRequest request = new ServiceRequest(buf.readUnsignedByte()); - - ChannelPipeline pipeline = ctx.getPipeline(); - pipeline.remove(this); - - if (buf.readable()) { - return new Object[] { request, buf.readBytes(buf.readableBytes()) }; - } else { - return request; - } - } - return null; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponse.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponse.java deleted file mode 100644 index 9648d01e..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.apollo.jagcached.net.service; - -/** - * Represents a response to a service request. - * @author Graham - */ -public final class ServiceResponse { - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponseEncoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponseEncoder.java deleted file mode 100644 index af580379..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponseEncoder.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.apollo.jagcached.net.service; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; - -/** - * A {@link OneToOneEncoder} which encodes {@link ServiceResponse} messages. - * @author Graham - */ -public final class ServiceResponseEncoder extends OneToOneEncoder { - - @Override - protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception { - if (msg instanceof ServiceResponse) { - ChannelBuffer buf = ChannelBuffers.buffer(8); - buf.writeLong(0); - return buf; - } - return msg; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/HypertextResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/jagcached/resource/HypertextResourceProvider.java deleted file mode 100644 index bbddd593..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/HypertextResourceProvider.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.apollo.jagcached.resource; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.net.URI; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel.MapMode; - -/** - * A {@link ResourceProvider} which provides additional hypertext resources. - * @author Graham Edgecombe - */ -public final class HypertextResourceProvider extends ResourceProvider { - - /** - * The base directory from which documents are served. - */ - private final File base; - - /** - * Creates a new hypertext resource provider with the specified base - * directory. - * @param base The base directory. - */ - public HypertextResourceProvider(File base) { - this.base = base; - } - - @Override - public boolean accept(String path) throws IOException { - File f = new File(base, path); - URI target = f.toURI().normalize(); - if (target.toASCIIString().startsWith(base.toURI().normalize().toASCIIString())) { - if (f.isDirectory()) { - f = new File(f, "index.html"); - } - return f.exists(); - } - return false; - } - - @Override - public ByteBuffer get(String path) throws IOException { - File f = new File(base, path); - if (f.isDirectory()) { - f = new File(f, "index.html"); - } - if (!f.exists()) { - return null; - } - - RandomAccessFile raf = new RandomAccessFile(f, "r"); - ByteBuffer buf; - try { - buf = raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length()); - } finally { - raf.close(); - } - - return buf; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/ResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/jagcached/resource/ResourceProvider.java deleted file mode 100644 index 2a38d407..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/ResourceProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.apollo.jagcached.resource; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * A class which provides resources. - * @author Graham Edgecombe - */ -public abstract class ResourceProvider { - - /** - * Checks that this provider can fulfil a request to the specified - * resource. - * @param path The path to the resource, e.g. {@code /crc}. - * @return {@code true} if the provider can fulfil a request to the - * resource, {@code false} otherwise. - * @throws IOException if an I/O error occurs. - */ - public abstract boolean accept(String path) throws IOException; - - /** - * Gets a resource by its path. - * @param path The path. - * @return The resource, or {@code null} if it doesn't exist. - * @throws IOException if an I/O error occurs. - */ - public abstract ByteBuffer get(String path) throws IOException; - -} diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/VirtualResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/jagcached/resource/VirtualResourceProvider.java deleted file mode 100644 index f474adf1..00000000 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/VirtualResourceProvider.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.apollo.jagcached.resource; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import org.apollo.jagcached.fs.IndexedFileSystem; - -/** - * A {@link ResourceProvider} which maps virtual resources (such as - * {@code /media}) to files in an {@link IndexedFileSystem}. - * @author Graham Edgecombe - */ -public final class VirtualResourceProvider extends ResourceProvider { - - /** - * An array of valid prefixes. - */ - private static final String[] VALID_PREFIXES = { - "crc", "title", "config", "interface", "media", "versionlist", - "textures", "wordenc", "sounds" - }; - - /** - * The file system. - */ - private final IndexedFileSystem fs; - - /** - * Creates a new virtual resource provider with the specified file system. - * @param fs The file system. - */ - public VirtualResourceProvider(IndexedFileSystem fs) { - this.fs = fs; - } - - @Override - public boolean accept(String path) throws IOException { - for (String prefix : VALID_PREFIXES) { - if (path.startsWith("/" + prefix)) { - return true; - } - } - return false; - } - - @Override - public ByteBuffer get(String path) throws IOException { - if (path.startsWith("/crc")) { - return fs.getCrcTable(); - } else if (path.startsWith("/title")) { - return fs.getFile(0, 1); - } else if (path.startsWith("/config")) { - return fs.getFile(0, 2); - } else if (path.startsWith("/interface")) { - return fs.getFile(0, 3); - } else if (path.startsWith("/media")) { - return fs.getFile(0, 4); - } else if (path.startsWith("/versionlist")) { - return fs.getFile(0, 5); - } else if (path.startsWith("/textures")) { - return fs.getFile(0, 6); - } else if (path.startsWith("/wordenc")) { - return fs.getFile(0, 7); - } else if (path.startsWith("/sounds")) { - return fs.getFile(0, 8); - } - return null; - } - -} diff --git a/2006Scape Server/src/main/java/org/apollo/net/HttpChannelInitializer.java b/2006Scape Server/src/main/java/org/apollo/net/HttpChannelInitializer.java new file mode 100644 index 00000000..5aa29a13 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/HttpChannelInitializer.java @@ -0,0 +1,51 @@ +package org.apollo.net; + +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.timeout.IdleStateHandler; + +/** + * A {@link ChannelInitializer} for the HTTP protocol. + * + * @author Graham + */ +public final class HttpChannelInitializer extends ChannelInitializer { + + /** + * The maximum length of a request, in bytes. + */ + private static final int MAX_REQUEST_LENGTH = 8192; + + /** + * The server event handler. + */ + private final ChannelInboundHandlerAdapter handler; + + /** + * Creates the HTTP pipeline factory. + * + * @param handler The file server event handler. + */ + public HttpChannelInitializer(ChannelInboundHandlerAdapter handler) { + this.handler = handler; + } + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + + pipeline.addLast("decoder", new HttpRequestDecoder()); + pipeline.addLast("chunker", new HttpObjectAggregator(MAX_REQUEST_LENGTH)); + + pipeline.addLast("encoder", new HttpResponseEncoder()); + + pipeline.addLast("timeout", new IdleStateHandler(NetworkConstants.IDLE_TIME, 0, 0)); + pipeline.addLast("handler", handler); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/JagGrabChannelInitializer.java b/2006Scape Server/src/main/java/org/apollo/net/JagGrabChannelInitializer.java new file mode 100644 index 00000000..a882f494 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/JagGrabChannelInitializer.java @@ -0,0 +1,77 @@ +package org.apollo.net; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.DelimiterBasedFrameDecoder; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.timeout.IdleStateHandler; + +import java.nio.charset.Charset; + +import org.apollo.net.codec.jaggrab.JagGrabRequestDecoder; +import org.apollo.net.codec.jaggrab.JagGrabResponseEncoder; + +import com.google.common.base.Charsets; + +/** + * A {@link ChannelInitializer} for the JAGGRAB protocol. + * + * @author Graham + */ +public final class JagGrabChannelInitializer extends ChannelInitializer { + + /** + * A buffer with two line feed (LF) characters in it. + */ + private static final ByteBuf DOUBLE_LINE_FEED_DELIMITER = Unpooled.buffer(2); + + /** + * The character set used in the request. + */ + private static final Charset JAGGRAB_CHARSET = Charsets.US_ASCII; + + /** + * The maximum length of a request, in bytes. + */ + private static final int MAX_REQUEST_LENGTH = 8192; + + /** + * Populates the double line feed buffer. + */ + static { + DOUBLE_LINE_FEED_DELIMITER.writeByte(10).writeByte(10); + } + + /** + * The file server event handler. + */ + private final ChannelInboundHandlerAdapter handler; + + /** + * Creates a {@code JAGGRAB} pipeline factory. + * + * @param handler The file server event handler. + */ + public JagGrabChannelInitializer(ChannelInboundHandlerAdapter handler) { + this.handler = handler; + } + + @Override + public void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + + pipeline.addLast("framer", new DelimiterBasedFrameDecoder(MAX_REQUEST_LENGTH, DOUBLE_LINE_FEED_DELIMITER)); + pipeline.addLast("string-decoder", new StringDecoder(JAGGRAB_CHARSET)); + pipeline.addLast("jaggrab-decoder", new JagGrabRequestDecoder()); + + pipeline.addLast("jaggrab-encoder", new JagGrabResponseEncoder()); + + pipeline.addLast("timeout", new IdleStateHandler(NetworkConstants.IDLE_TIME, 0, 0)); + pipeline.addLast("handler", handler); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/NetworkConstants.java b/2006Scape Server/src/main/java/org/apollo/net/NetworkConstants.java new file mode 100644 index 00000000..4aa69447 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/NetworkConstants.java @@ -0,0 +1,81 @@ +package org.apollo.net; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; + +import com.google.common.base.Preconditions; +import org.apollo.util.xml.XmlNode; +import org.apollo.util.xml.XmlParser; + +/** + * Holds various network-related constants such as port numbers. + * + * @author Graham + * @author Major + */ +public final class NetworkConstants { + + /** + * The HTTP port. + */ + public static final int HTTP_PORT; + + /** + * The number of seconds before a connection becomes idle. + */ + public static final int IDLE_TIME = 15; + + /** + * The JAGGRAB port. + */ + public static final int JAGGRAB_PORT; + + /** + * The exponent used when decrypting the RSA block. + */ + public static final BigInteger RSA_EXPONENT; + + /** + * The modulus used when decrypting the RSA block. + */ + public static final BigInteger RSA_MODULUS; + + static { + try (InputStream is = new FileInputStream("data/net.xml")) { + XmlNode net = new XmlParser().parse(is); + if (!net.getName().equals("net")) { + throw new IOException("Root node name is not 'net'."); + } + + XmlNode rsa = net.getChild("rsa"); + Preconditions.checkState(rsa != null, "Root node must have a child named 'rsa'."); + + XmlNode modulus = rsa.getChild("modulus"), exponent = rsa.getChild("private-exponent"); + Preconditions.checkState(modulus != null && exponent != null, "Rsa node must have two children: 'modulus' and 'private-exponent'."); + + RSA_MODULUS = new BigInteger(modulus.getValue()); + RSA_EXPONENT = new BigInteger(exponent.getValue()); + + XmlNode ports = net.getChild("ports"); + Preconditions.checkState(ports != null, "Root node must have a child named 'ports'."); + + XmlNode http = ports.getChild("http"), jaggrab = ports.getChild("jaggrab"); + Preconditions.checkState(http != null && jaggrab != null, "Ports node must have two children: 'http', and 'jaggrab'."); + + HTTP_PORT = Integer.parseInt(http.getValue()); + JAGGRAB_PORT = Integer.parseInt(jaggrab.getValue()); + } catch (Exception exception) { + throw new ExceptionInInitializerError(new IOException("Error parsing net.xml.", exception)); + } + } + + /** + * Sole private constructor to prevent instantiation. + */ + private NetworkConstants() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/ServiceChannelInitializer.java b/2006Scape Server/src/main/java/org/apollo/net/ServiceChannelInitializer.java new file mode 100644 index 00000000..9e4419e8 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/ServiceChannelInitializer.java @@ -0,0 +1,40 @@ +package org.apollo.net; + +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.timeout.IdleStateHandler; + +import org.apollo.net.codec.handshake.HandshakeDecoder; + +/** + * A {@link ChannelInitializer} for the service pipeline. + * + * @author Graham + */ +public final class ServiceChannelInitializer extends ChannelInitializer { + + /** + * The network event handler. + */ + private final ChannelInboundHandlerAdapter handler; + + /** + * Creates the service pipeline factory. + * + * @param handler The networking event handler. + */ + public ServiceChannelInitializer(ChannelInboundHandlerAdapter handler) { + this.handler = handler; + } + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast("handshakeDecoder", new HandshakeDecoder()); + pipeline.addLast("timeout", new IdleStateHandler(NetworkConstants.IDLE_TIME, 0, 0)); + pipeline.addLast("handler", handler); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java new file mode 100644 index 00000000..94861b7b --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java @@ -0,0 +1,27 @@ +package org.apollo.net.codec.handshake; + +/** + * Holds handshake-related constants. + * + * @author Graham + */ +public final class HandshakeConstants { + + /** + * The id of the game service. + */ + public static final int SERVICE_GAME = 14; + + /** + * The id of the update service. + */ + public static final int SERVICE_UPDATE = 15; + + /** + * Default private constructor to prevent instantiation by other classes. + */ + private HandshakeConstants() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java new file mode 100644 index 00000000..aa768ae8 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java @@ -0,0 +1,60 @@ +package org.apollo.net.codec.handshake; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; +import java.util.logging.Logger; + +import org.apollo.net.codec.login.LoginDecoder; +import org.apollo.net.codec.login.LoginEncoder; +import org.apollo.net.codec.update.UpdateDecoder; +import org.apollo.net.codec.update.UpdateEncoder; + +/** + * A {@link ByteToMessageDecoder} which decodes the handshake and makes changes to the pipeline as appropriate for the + * selected service. + * + * @author Graham + */ +public final class HandshakeDecoder extends ByteToMessageDecoder { + + /** + * The logger for this class. + */ + private static final Logger logger = Logger.getLogger(HandshakeDecoder.class.getName()); + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) { + if (!buffer.isReadable()) { + return; + } + + int id = buffer.readUnsignedByte(); + + switch (id) { + case HandshakeConstants.SERVICE_GAME: + ctx.pipeline().addFirst("loginEncoder", new LoginEncoder()); + ctx.pipeline().addAfter("handshakeDecoder", "loginDecoder", new LoginDecoder()); + break; + + case HandshakeConstants.SERVICE_UPDATE: + ctx.pipeline().addFirst("updateEncoder", new UpdateEncoder()); + ctx.pipeline().addBefore("handler", "updateDecoder", new UpdateDecoder()); + + ByteBuf buf = ctx.alloc().buffer(8).writeLong(0); + ctx.channel().writeAndFlush(buf); + break; + + default: + ByteBuf data = buffer.readBytes(buffer.readableBytes()); + logger.info(String.format("Unexpected handshake request received: %d data: %s", id, data.toString())); + return; + } + + ctx.pipeline().remove(this); + out.add(new HandshakeMessage(id)); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeMessage.java b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeMessage.java new file mode 100644 index 00000000..c21a5311 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeMessage.java @@ -0,0 +1,33 @@ +package org.apollo.net.codec.handshake; + +/** + * A handshake message in the service handshake protocol. + * + * @author Graham + */ +public final class HandshakeMessage { + + /** + * The service id. + */ + private final int serviceId; + + /** + * Creates the handshake message. + * + * @param serviceId The service id. + */ + public HandshakeMessage(int serviceId) { + this.serviceId = serviceId; + } + + /** + * Gets the service id. + * + * @return The service id. + */ + public int getServiceId() { + return serviceId; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/package-info.java b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/package-info.java new file mode 100644 index 00000000..2575b407 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains codecs for the handshake protocol. + */ +package org.apollo.net.codec.handshake; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequest.java b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequest.java similarity index 89% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequest.java rename to 2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequest.java index fd8328b8..4ef7f0db 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequest.java +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequest.java @@ -1,11 +1,12 @@ -package org.apollo.jagcached.net.jaggrab; +package org.apollo.net.codec.jaggrab; /** * Represents the request for a single file using the JAGGRAB protocol. + * * @author Graham */ public final class JagGrabRequest { - + /** * The path to the file. */ @@ -13,18 +14,20 @@ public final class JagGrabRequest { /** * Creates the request. + * * @param filePath The file path. */ public JagGrabRequest(String filePath) { this.filePath = filePath; } - + /** * Gets the file path. + * * @return The file path. */ public String getFilePath() { return filePath; } -} +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java new file mode 100644 index 00000000..4d8706c3 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java @@ -0,0 +1,25 @@ +package org.apollo.net.codec.jaggrab; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageDecoder; + +import java.util.List; + +/** + * A {@link MessageToMessageDecoder} for the JAGGRAB protocol. + * + * @author Graham + */ +public final class JagGrabRequestDecoder extends MessageToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, String request, List out) { + if (request.startsWith("JAGGRAB /")) { + String filePath = request.substring(8).trim(); + out.add(new JagGrabRequest(filePath)); + } else { + throw new IllegalArgumentException("Corrupted request line."); + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponse.java b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponse.java similarity index 51% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponse.java rename to 2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponse.java index 67890ec4..b82a13bd 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponse.java +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponse.java @@ -1,9 +1,10 @@ -package org.apollo.jagcached.net.jaggrab; +package org.apollo.net.codec.jaggrab; -import org.jboss.netty.buffer.ChannelBuffer; +import io.netty.buffer.ByteBuf; /** - * Represents a single JAGGRAB reponse. + * Represents a single JAGGRAB response. + * * @author Graham */ public final class JagGrabResponse { @@ -11,22 +12,24 @@ public final class JagGrabResponse { /** * The file data. */ - private final ChannelBuffer fileData; - + private final ByteBuf fileData; + /** * Creates the response. + * * @param fileData The file data. */ - public JagGrabResponse(ChannelBuffer fileData) { + public JagGrabResponse(ByteBuf fileData) { this.fileData = fileData; } - + /** * Gets the file data. + * * @return The file data. */ - public ChannelBuffer getFileData() { + public ByteBuf getFileData() { return fileData; } - -} + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java new file mode 100644 index 00000000..d2c67936 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java @@ -0,0 +1,20 @@ +package org.apollo.net.codec.jaggrab; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; + +import java.util.List; + +/** + * A {@link MessageToMessageEncoder} for the JAGGRAB protocol. + * + * @author Graham + */ +public final class JagGrabResponseEncoder extends MessageToMessageEncoder { + + @Override + protected void encode(ChannelHandlerContext ctx, JagGrabResponse response, List out) { + out.add(response.getFileData()); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/package-info.java b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/package-info.java new file mode 100644 index 00000000..5ec5c65d --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/jaggrab/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains codecs for the JAGGRAB protocol. + */ +package org.apollo.net.codec.jaggrab; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginConstants.java b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginConstants.java new file mode 100644 index 00000000..fb345efd --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginConstants.java @@ -0,0 +1,127 @@ +package org.apollo.net.codec.login; + +/** + * Holds login-related constants. + * + * @author Graham + */ +public final class LoginConstants { + + /** + * Exchange data login status. + */ + public static final int STATUS_EXCHANGE_DATA = 0; + + /** + * Delay for 2 seconds login status. + */ + public static final int STATUS_DELAY = 1; + + /** + * OK login status. + */ + public static final int STATUS_OK = 2; + + /** + * Invalid credentials login status. + */ + public static final int STATUS_INVALID_CREDENTIALS = 3; + + /** + * Account disabled login status. + */ + public static final int STATUS_ACCOUNT_DISABLED = 4; + + /** + * Account online login status. + */ + public static final int STATUS_ACCOUNT_ONLINE = 5; + + /** + * Game updated login status. + */ + public static final int STATUS_GAME_UPDATED = 6; + + /** + * Server full login status. + */ + public static final int STATUS_SERVER_FULL = 7; + + /** + * Login server offline login status. + */ + public static final int STATUS_LOGIN_SERVER_OFFLINE = 8; + + /** + * Too many connections login status. + */ + public static final int STATUS_TOO_MANY_CONNECTIONS = 9; + + /** + * Bad session id login status. + */ + public static final int STATUS_BAD_SESSION_ID = 10; + + /** + * Login server rejected session login status. + */ + public static final int STATUS_LOGIN_SERVER_REJECTED_SESSION = 11; + + /** + * Members account required login status. + */ + public static final int STATUS_MEMBERS_ACCOUNT_REQUIRED = 12; + + /** + * Could not complete login status. + */ + public static final int STATUS_COULD_NOT_COMPLETE = 13; + + /** + * Server updating login status. + */ + public static final int STATUS_UPDATING = 14; + + /** + * Reconnection OK login status. + */ + public static final int STATUS_RECONNECTION_OK = 15; + + /** + * Too many login attempts login status. + */ + public static final int STATUS_TOO_MANY_LOGINS = 16; + + /** + * Standing in members area on free world status. + */ + public static final int STATUS_IN_MEMBERS_AREA = 17; + + /** + * Invalid login server status. + */ + public static final int STATUS_INVALID_LOGIN_SERVER = 20; + + /** + * Profile transfer login status. + */ + public static final int STATUS_PROFILE_TRANSFER = 21; + + /** + * Standard login type id. + */ + public static final int TYPE_STANDARD = 16; + + /** + * Reconnection login type id. + */ + public static final int TYPE_RECONNECTION = 18; + + /** + * Default private constructor to prevent instantiation. + */ + private LoginConstants() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoder.java new file mode 100644 index 00000000..b4f13f04 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoder.java @@ -0,0 +1,232 @@ +package org.apollo.net.codec.login; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; + +import java.math.BigInteger; +import java.net.InetSocketAddress; +import java.security.SecureRandom; +import java.util.List; +import java.util.logging.Logger; + +import org.apollo.cache.FileSystemConstants; +import org.apollo.net.NetworkConstants; +import org.apollo.util.BufferUtil; +import org.apollo.util.StatefulFrameDecoder; +import org.apollo.util.security.IsaacRandom; +import org.apollo.util.security.IsaacRandomPair; +import org.apollo.util.security.PlayerCredentials; + +import com.google.common.net.InetAddresses; + +/** + * A {@link StatefulFrameDecoder} which decodes the login request frames. + * + * @author Graham + */ +public final class LoginDecoder extends StatefulFrameDecoder { + + /** + * The logger for this class. + */ + private static final Logger logger = Logger.getLogger(LoginDecoder.class.getName()); + + /** + * The secure random number generator. + */ + private static final SecureRandom RANDOM = new SecureRandom(); + + /** + * The login packet length. + */ + private int loginLength; + + /** + * The reconnecting flag. + */ + private boolean reconnecting; + + /** + * The server-side session key. + */ + private long serverSeed; + + /** + * The username hash. + */ + private int usernameHash; + + /** + * Creates the login decoder with the default initial state. + */ + public LoginDecoder() { + super(LoginDecoderState.LOGIN_HANDSHAKE); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out, LoginDecoderState state) { + switch (state) { + case LOGIN_HANDSHAKE: + decodeHandshake(ctx, in, out); + break; + case LOGIN_HEADER: + decodeHeader(ctx, in, out); + break; + case LOGIN_PAYLOAD: + decodePayload(ctx, in, out); + break; + default: + throw new IllegalStateException("Invalid login decoder state: " + state); + } + } + + /** + * Decodes in the handshake state. + * + * @param ctx The channel handler context. + * @param buffer The buffer. + * @param out The {@link List} of objects to pass forward through the pipeline. + */ + private void decodeHandshake(ChannelHandlerContext ctx, ByteBuf buffer, List out) { + if (buffer.isReadable()) { + usernameHash = buffer.readUnsignedByte(); + serverSeed = RANDOM.nextLong(); + + ByteBuf response = ctx.alloc().buffer(17); + response.writeByte(LoginConstants.STATUS_EXCHANGE_DATA); + response.writeLong(0); + response.writeLong(serverSeed); + ctx.channel().write(response); + + setState(LoginDecoderState.LOGIN_HEADER); + } + } + + /** + * Decodes in the header state. + * + * @param ctx The channel handler context. + * @param buffer The buffer. + * @param out The {@link List} of objects to pass forward through the pipeline. + */ + private void decodeHeader(ChannelHandlerContext ctx, ByteBuf buffer, List out) { + if (buffer.readableBytes() >= 2) { + int type = buffer.readUnsignedByte(); + + if (type != LoginConstants.TYPE_STANDARD && type != LoginConstants.TYPE_RECONNECTION) { + logger.fine("Failed to decode login header."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; + } + + reconnecting = type == LoginConstants.TYPE_RECONNECTION; + loginLength = buffer.readUnsignedByte(); + + setState(LoginDecoderState.LOGIN_PAYLOAD); + } + } + + /** + * Decodes in the payload state. + * + * @param ctx The channel handler context. + * @param buffer The buffer. + * @param out The {@link List} of objects to pass forward through the pipeline. + */ + private void decodePayload(ChannelHandlerContext ctx, ByteBuf buffer, List out) { + if (buffer.readableBytes() >= loginLength) { + ByteBuf payload = buffer.readBytes(loginLength); + int version = 255 - payload.readUnsignedByte(); + + int release = payload.readUnsignedShort(); + + int memoryStatus = payload.readUnsignedByte(); + if (memoryStatus != 0 && memoryStatus != 1) { + logger.fine("Login memoryStatus (" + memoryStatus + ") not in expected range of [0, 1]."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; + } + + boolean lowMemory = memoryStatus == 1; + + int[] crcs = new int[FileSystemConstants.ARCHIVE_COUNT]; + for (int index = 0; index < 9; index++) { + crcs[index] = payload.readInt(); + } + + int length = payload.readUnsignedByte(); + if (length != loginLength - 41) { + logger.fine("Login packet unexpected length (" + length + ")"); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; + } + + byte[] val = new byte[length]; + payload.readBytes(val); + + BigInteger value = new BigInteger(val); + value = value.modPow(NetworkConstants.RSA_EXPONENT, NetworkConstants.RSA_MODULUS); + ByteBuf secure = Unpooled.wrappedBuffer(value.toByteArray()); + + int id = secure.readUnsignedByte(); + if (id != 10) { + logger.fine("Unable to read id from secure payload."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; + } + + long clientSeed = secure.readLong(); + long reportedSeed = secure.readLong(); + if (reportedSeed != serverSeed) { + logger.fine("Reported seed differed from server seed."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; + } + + int uid = secure.readInt(); + String username = BufferUtil.readString(secure); + String password = BufferUtil.readString(secure); + InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + String hostAddress = InetAddresses.toAddrString(socketAddress.getAddress()); + +// if (password.length() < 6 || password.length() > 20 || username.isEmpty() || username.length() > 12) { +// logger.fine("Username ('" + username + "') or password did not pass validation."); +// writeResponseCode(ctx, LoginConstants.STATUS_INVALID_CREDENTIALS); +// return; +// } + + int[] seed = new int[4]; + seed[0] = (int) (clientSeed >> 32); + seed[1] = (int) clientSeed; + seed[2] = (int) (serverSeed >> 32); + seed[3] = (int) serverSeed; + + IsaacRandom decodingRandom = new IsaacRandom(seed); + for (int index = 0; index < seed.length; index++) { + seed[index] += 50; + } + + IsaacRandom encodingRandom = new IsaacRandom(seed); + + PlayerCredentials credentials = new PlayerCredentials(username, password, usernameHash, uid, hostAddress); + IsaacRandomPair randomPair = new IsaacRandomPair(encodingRandom, decodingRandom); + + out.add(new LoginRequest(credentials, randomPair, reconnecting, lowMemory, release, crcs, version)); + } + } + + /** + * Writes a response code to the client and closes the current channel. + * + * @param ctx The context of the channel handler. + * @param response The response code to write. + */ + private void writeResponseCode(ChannelHandlerContext ctx, int response) { + ByteBuf buffer = ctx.alloc().buffer(Byte.BYTES); + buffer.writeByte(response); + ctx.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoderState.java b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoderState.java new file mode 100644 index 00000000..bdef7345 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginDecoderState.java @@ -0,0 +1,28 @@ +package org.apollo.net.codec.login; + +/** + * An enumeration with the different states the {@link LoginDecoder} can be in. + * + * @author Graham + */ +public enum LoginDecoderState { + + /** + * The login handshake state will wait for the username hash to be received. Once it is, a server session key will + * be sent to the client and the state will be set to the login header state. + */ + LOGIN_HANDSHAKE, + + /** + * The login header state will wait for the login type and payload length to be received. These are saved, and then + * the state will be set to the login payload state. + */ + LOGIN_HEADER, + + /** + * The login payload state will wait for all login information (such as client release number, username and + * password). + */ + LOGIN_PAYLOAD; + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginEncoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginEncoder.java new file mode 100644 index 00000000..466f11c5 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginEncoder.java @@ -0,0 +1,31 @@ +package org.apollo.net.codec.login; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +/** + * A {@link MessageToByteEncoder} which encodes login response messages. + * + * @author Graham + */ +public final class LoginEncoder extends MessageToByteEncoder { + + /** + * Creates the login encoder. + */ + public LoginEncoder() { + super(LoginResponse.class); + } + + @Override + protected void encode(ChannelHandlerContext ctx, LoginResponse response, ByteBuf out) { + out.writeByte(response.getStatus()); + + if (response.getStatus() == LoginConstants.STATUS_OK) { + out.writeByte(response.getRights()); + out.writeByte(response.isFlagged() ? 1 : 0); + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginRequest.java b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginRequest.java new file mode 100644 index 00000000..356cf87c --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginRequest.java @@ -0,0 +1,132 @@ +package org.apollo.net.codec.login; + +import org.apollo.util.security.IsaacRandomPair; +import org.apollo.util.security.PlayerCredentials; + +/** + * Represents a login request. + * + * @author Graham + */ +public final class LoginRequest { + + /** + * The archive CRCs. + */ + private final int[] archiveCrcs; + + /** + * The version denoting whether the client has been modified or not. + */ + private final int clientVersion; + + /** + * The player's credentials. + */ + private final PlayerCredentials credentials; + + /** + * The low memory flag. + */ + private final boolean lowMemory; + + /** + * The pair of random number generators. + */ + private final IsaacRandomPair randomPair; + + /** + * The reconnecting flag. + */ + private final boolean reconnecting; + + /** + * The release number. + */ + private final int releaseNumber; + + /** + * Creates a login request. + * + * @param credentials The player credentials. + * @param randomPair The pair of random number generators. + * @param lowMemory The low memory flag. + * @param reconnecting The reconnecting flag. + * @param releaseNumber The release number. + * @param archiveCrcs The archive CRCs. + * @param clientVersion The client version. + */ + public LoginRequest(PlayerCredentials credentials, IsaacRandomPair randomPair, boolean lowMemory, boolean reconnecting, int releaseNumber, int[] archiveCrcs, int clientVersion) { + this.credentials = credentials; + this.randomPair = randomPair; + this.lowMemory = lowMemory; + this.reconnecting = reconnecting; + this.releaseNumber = releaseNumber; + this.archiveCrcs = archiveCrcs; + this.clientVersion = clientVersion; + } + + /** + * Gets the archive CRCs. + * + * @return The array of archive CRCs. + */ + public int[] getArchiveCrcs() { + return archiveCrcs; + } + + /** + * Gets the value denoting the client's (modified) version. + * + * @return The client version. + */ + public int getClientVersion() { + return clientVersion; + } + + /** + * Gets the player's credentials. + * + * @return The player's credentials. + */ + public PlayerCredentials getCredentials() { + return credentials; + } + + /** + * Gets the pair of random number generators. + * + * @return The pair of random number generators. + */ + public IsaacRandomPair getRandomPair() { + return randomPair; + } + + /** + * Gets the release number. + * + * @return The release number. + */ + public int getReleaseNumber() { + return releaseNumber; + } + + /** + * Checks if this client is in low memory mode. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isLowMemory() { + return lowMemory; + } + + /** + * Checks if this client is reconnecting. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean isReconnecting() { + return reconnecting; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginResponse.java b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginResponse.java new file mode 100644 index 00000000..bf1fa5b7 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/login/LoginResponse.java @@ -0,0 +1,65 @@ +package org.apollo.net.codec.login; + +/** + * Represents a login response. + * + * @author Graham + */ +public final class LoginResponse { + + /** + * The flagged flag. + */ + private final boolean flagged; + + /** + * The rights level. + */ + private final int rights; + + /** + * The login status. + */ + private final int status; + + /** + * Creates the login response. + * + * @param status The login status. + * @param rights The rights level. + * @param flagged The flagged flag. + */ + public LoginResponse(int status, int rights, boolean flagged) { + this.status = status; + this.rights = rights; + this.flagged = flagged; + } + + /** + * Gets the rights level. + * + * @return The rights level. + */ + public int getRights() { + return rights; + } + + /** + * Gets the status. + * + * @return The status. + */ + public int getStatus() { + return status; + } + + /** + * Checks if the player should be flagged. + * + * @return The flagged flag. + */ + public boolean isFlagged() { + return flagged; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/login/package-info.java b/2006Scape Server/src/main/java/org/apollo/net/codec/login/package-info.java new file mode 100644 index 00000000..3fbda626 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/login/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains codecs for the login protocol. + */ +package org.apollo.net.codec.login; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/update/OnDemandRequest.java b/2006Scape Server/src/main/java/org/apollo/net/codec/update/OnDemandRequest.java new file mode 100644 index 00000000..1ad253eb --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/update/OnDemandRequest.java @@ -0,0 +1,134 @@ +package org.apollo.net.codec.update; + +import org.apollo.cache.FileDescriptor; + +/** + * Represents a single 'on-demand' request. + * + * @author Graham + */ +public final class OnDemandRequest implements Comparable { + + /** + * An enumeration containing the different request priorities. + */ + public enum Priority { + + /** + * High priority - used when a player is in-game and data is required immediately. + */ + HIGH(0), + + /** + * Medium priority - used while loading extra resources when the client is not logged in. + */ + MEDIUM(1), + + /** + * Low priority - used when a file is not required urgently (such as when serving the rest of the cache whilst + * the player is in-game). + */ + LOW(2); + + /** + * Converts the integer value to a Priority. + * + * @param value The integer value. + * @return The priority. + * @throws IllegalArgumentException If the value is outside of the range 1-3 inclusive. + */ + public static Priority valueOf(int value) { + switch (value) { + case 0: + return HIGH; + case 1: + return MEDIUM; + case 2: + return LOW; + default: + throw new IllegalArgumentException("Priority out of range - received " + value + "."); + } + } + + /** + * The integer value. + */ + private final int value; + + /** + * Creates the Priority. + * + * @param value The integer value. + */ + private Priority(int value) { + this.value = value; + } + + /** + * Compares this Priority with the specified other Priority. + *

+ * Used as an ordinal-independent variant of {@link #compareTo}. + * + * @param other The other Priority. + * @return 1 if this Priority is greater than {@code other}, 0 if they are equal, otherwise -1. + */ + public int compareWith(Priority other) { + return Integer.compare(value, other.value); + } + + /** + * Converts the priority to an integer. + * + * @return The integer value. + */ + public int toInteger() { + return value; + } + + } + + /** + * The FileDescriptor. + */ + private final FileDescriptor descriptor; + + /** + * The request Priority. + */ + private final Priority priority; + + /** + * Creates the OnDemandRequest. + * + * @param descriptor The {@link FileDescriptor}. + * @param priority The {@link Priority}. + */ + public OnDemandRequest(FileDescriptor descriptor, Priority priority) { + this.descriptor = descriptor; + this.priority = priority; + } + + @Override + public int compareTo(OnDemandRequest other) { + return priority.compareWith(other.priority); + } + + /** + * Gets the {@link FileDescriptor}. + * + * @return The FileDescriptor. + */ + public FileDescriptor getFileDescriptor() { + return descriptor; + } + + /** + * Gets the {@link Priority}. + * + * @return The Priority. + */ + public Priority getPriority() { + return priority; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponse.java b/2006Scape Server/src/main/java/org/apollo/net/codec/update/OnDemandResponse.java similarity index 80% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponse.java rename to 2006Scape Server/src/main/java/org/apollo/net/codec/update/OnDemandResponse.java index 2d479e69..750331b9 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponse.java +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/update/OnDemandResponse.java @@ -1,79 +1,85 @@ -package org.apollo.jagcached.net.ondemand; +package org.apollo.net.codec.update; +import io.netty.buffer.ByteBuf; -import org.apollo.jagcached.fs.FileDescriptor; -import org.jboss.netty.buffer.ChannelBuffer; +import org.apollo.cache.FileDescriptor; /** * Represents a single 'on-demand' response. + * * @author Graham */ public final class OnDemandResponse { - + /** - * The file descriptor. + * The chunk data. */ - private final FileDescriptor fileDescriptor; - - /** - * The file size. - */ - private final int fileSize; - + private final ByteBuf chunkData; + /** * The chunk id. */ private final int chunkId; - + /** - * The chunk data. + * The file descriptor. */ - private final ChannelBuffer chunkData; - + private final FileDescriptor fileDescriptor; + + /** + * The file size. + */ + private final int fileSize; + /** * Creates the 'on-demand' response. + * * @param fileDescriptor The file descriptor. * @param fileSize The file size. * @param chunkId The chunk id. * @param chunkData The chunk data. */ - public OnDemandResponse(FileDescriptor fileDescriptor, int fileSize, int chunkId, ChannelBuffer chunkData) { + public OnDemandResponse(FileDescriptor fileDescriptor, int fileSize, int chunkId, ByteBuf chunkData) { this.fileDescriptor = fileDescriptor; this.fileSize = fileSize; this.chunkId = chunkId; this.chunkData = chunkData; } - + /** - * Gets the file descriptor. - * @return The file descriptor. + * Gets the chunk data. + * + * @return The chunk data. */ - public FileDescriptor getFileDescriptor() { - return fileDescriptor; + public ByteBuf getChunkData() { + return chunkData; } - - /** - * Gets the file size. - * @return The file size. - */ - public int getFileSize() { - return fileSize; - } - + /** * Gets the chunk id. + * * @return The chunk id. */ public int getChunkId() { return chunkId; } - + /** - * Gets the chunk data. - * @return The chunk data. + * Gets the file descriptor. + * + * @return The file descriptor. */ - public ChannelBuffer getChunkData() { - return chunkData; + public FileDescriptor getFileDescriptor() { + return fileDescriptor; } -} + /** + * Gets the file size. + * + * @return The file size. + */ + public int getFileSize() { + return fileSize; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateDecoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateDecoder.java new file mode 100644 index 00000000..80743577 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateDecoder.java @@ -0,0 +1,31 @@ +package org.apollo.net.codec.update; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +import org.apollo.cache.FileDescriptor; +import org.apollo.net.codec.update.OnDemandRequest.Priority; + +/** + * A {@link ByteToMessageDecoder} for the 'on-demand' protocol. + * + * @author Graham + */ +public final class UpdateDecoder extends ByteToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) { + if (buffer.readableBytes() >= 4) { + int type = buffer.readUnsignedByte() + 1; + int file = buffer.readUnsignedShort(); + Priority priority = Priority.valueOf(buffer.readUnsignedByte()); + + FileDescriptor desc = new FileDescriptor(type, file); + out.add(new OnDemandRequest(desc, priority)); + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateEncoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateEncoder.java new file mode 100644 index 00000000..5c6592a9 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/update/UpdateEncoder.java @@ -0,0 +1,35 @@ +package org.apollo.net.codec.update; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; + +import java.util.List; + +import org.apollo.cache.FileDescriptor; + +/** + * A {@link MessageToMessageEncoder} for the 'on-demand' protocol. + * + * @author Graham + */ +public final class UpdateEncoder extends MessageToMessageEncoder { + + @Override + protected void encode(ChannelHandlerContext ctx, OnDemandResponse response, List out) { + FileDescriptor descriptor = response.getFileDescriptor(); + int fileSize = response.getFileSize(); + int chunkId = response.getChunkId(); + ByteBuf chunkData = response.getChunkData(); + + ByteBuf buffer = ctx.alloc().buffer(2 * Byte.BYTES + 2 * Short.BYTES + chunkData.readableBytes()); + buffer.writeByte(descriptor.getType() - 1); + buffer.writeShort(descriptor.getFile()); + buffer.writeShort(fileSize); + buffer.writeByte(chunkId); + buffer.writeBytes(chunkData); + + out.add(buffer); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/update/package-info.java b/2006Scape Server/src/main/java/org/apollo/net/codec/update/package-info.java new file mode 100644 index 00000000..32b04530 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/codec/update/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains codecs for the ondemand (update) protocol. + */ +package org.apollo.net.codec.update; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/package-info.java b/2006Scape Server/src/main/java/org/apollo/net/package-info.java new file mode 100644 index 00000000..96ae9898 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/package-info.java @@ -0,0 +1,5 @@ +/** + * Contains classes related to networking. Many of these extend Netty's set of classes - such as the pipeline factory, + * handler and codecs. + */ +package org.apollo.net; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/ChannelRequest.java b/2006Scape Server/src/main/java/org/apollo/net/update/ChannelRequest.java similarity index 57% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/ChannelRequest.java rename to 2006Scape Server/src/main/java/org/apollo/net/update/ChannelRequest.java index 024d2ce4..70e5901b 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/ChannelRequest.java +++ b/2006Scape Server/src/main/java/org/apollo/net/update/ChannelRequest.java @@ -1,27 +1,28 @@ -package org.apollo.jagcached.dispatch; +package org.apollo.net.update; -import org.jboss.netty.channel.Channel; +import io.netty.channel.Channel; /** - * A specialised request which contains a channel as well as the request object - * itself. + * A specialised request which contains a channel as well as the request object itself. + * * @author Graham * @param The type of request. */ -public final class ChannelRequest implements Comparable> { - +public class ChannelRequest { + /** * The channel. */ private final Channel channel; - + /** * The request. */ - private final T request; - + protected final T request; + /** * Creates a new channel request. + * * @param channel The channel. * @param request The request. */ @@ -29,30 +30,23 @@ public final class ChannelRequest implements Comparable> { this.channel = channel; this.request = request; } - + /** * Gets the channel. + * * @return The channel. */ public Channel getChannel() { return channel; } - + /** * Gets the request. + * * @return The request. */ public T getRequest() { return request; } - @SuppressWarnings("unchecked") - @Override - public int compareTo(ChannelRequest o) { - if (request instanceof Comparable && o.request instanceof Comparable) { - return ((Comparable) request).compareTo(o.request); - } - return 0; - } - -} +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/ComparableChannelRequest.java b/2006Scape Server/src/main/java/org/apollo/net/update/ComparableChannelRequest.java new file mode 100644 index 00000000..78205c41 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/ComparableChannelRequest.java @@ -0,0 +1,29 @@ +package org.apollo.net.update; + +import io.netty.channel.Channel; + +/** + * A {@link ChannelRequest} with a {@link Comparable} request type. + * + * @author Major + * + * @param The type of request. + */ +public final class ComparableChannelRequest> extends ChannelRequest implements Comparable> { + + /** + * Creates the ComparableChannelRequest. + * + * @param channel The {@link Channel} making the request. + * @param request The request. + */ + public ComparableChannelRequest(Channel channel, T request) { + super(channel, request); + } + + @Override + public int compareTo(ComparableChannelRequest o) { + return request.compareTo(o.request); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/HttpRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/net/update/HttpRequestWorker.java new file mode 100644 index 00000000..4e9a91a2 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/HttpRequestWorker.java @@ -0,0 +1,148 @@ +package org.apollo.net.update; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; +import java.util.Optional; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.net.update.resource.CombinedResourceProvider; +import org.apollo.net.update.resource.HypertextResourceProvider; +import org.apollo.net.update.resource.ResourceProvider; +import org.apollo.net.update.resource.VirtualResourceProvider; + +import com.google.common.base.Charsets; + +/** + * A worker which services HTTP requests. + * + * @author Graham + */ +public final class HttpRequestWorker extends RequestWorker { + + /** + * The default character set. + */ + private static final Charset CHARACTER_SET = Charsets.ISO_8859_1; + + /** + * The value of the server header. + */ + private static final String SERVER_IDENTIFIER = "JAGeX/3.1"; + + /** + * The directory with web files. + */ + private static final Path WWW_DIRECTORY = Paths.get("data/www"); + + /** + * Creates the HTTP request worker. + * + * @param dispatcher The dispatcher. + * @param fs The file system. + */ + public HttpRequestWorker(UpdateDispatcher dispatcher, IndexedFileSystem fs) { + super(dispatcher, new CombinedResourceProvider(new VirtualResourceProvider(fs), new HypertextResourceProvider(WWW_DIRECTORY))); + } + + /** + * Creates an error page. + * + * @param status The HTTP status. + * @param description The error description. + * @return The error page as a buffer. + */ + private static ByteBuf createErrorPage(HttpResponseStatus status, String description) { + String title = status.code() + " " + status.reasonPhrase(); + StringBuilder builder = new StringBuilder(""); + + builder.append(title); + builder.append("

"); + builder.append(title); + builder.append("

"); + builder.append(description); + builder.append("


"); + builder.append(SERVER_IDENTIFIER); + builder.append(" Server
"); + + return Unpooled.copiedBuffer(builder.toString(), Charset.defaultCharset()); + } + + /** + * Gets the MIME type of a file by its name. + * + * @param name The file name. + * @return The MIME type. + */ + private static String getMimeType(String name) { + if (name.endsWith("/")) { + name = name.concat("index.html"); + } + + if (name.endsWith(".htm") || name.endsWith(".html")) { + return "text/html"; + } else if (name.endsWith(".css")) { + return "text/css"; + } else if (name.endsWith(".js")) { + return "text/javascript"; + } else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) { + return "image/jpeg"; + } else if (name.endsWith(".gif")) { + return "image/gif"; + } else if (name.endsWith(".png")) { + return "image/png"; + } else if (name.endsWith(".txt")) { + return "text/plain"; + } + + return "application/octet-stream"; + } + + @Override + protected ChannelRequest nextRequest(UpdateDispatcher dispatcher) throws InterruptedException { + return dispatcher.nextHttpRequest(); + } + + @Override + protected void service(ResourceProvider provider, Channel channel, HttpRequest request) throws IOException { + String path = request.getUri(); + Optional buf = provider.get(path); + + HttpResponseStatus status = HttpResponseStatus.OK; + String mime = getMimeType(request.getUri()); + + if (!buf.isPresent()) { + status = HttpResponseStatus.NOT_FOUND; + mime = "text/html"; + } + + ByteBuf wrapped = buf.isPresent() ? Unpooled.wrappedBuffer(buf.get()) : createErrorPage(status, "The page you requested could not be found."); + + HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), status); + + response.headers().set("Date", new Date()); + response.headers().set("Server", SERVER_IDENTIFIER); + response.headers().set("Content-type", mime + ", charset=" + CHARACTER_SET.name()); + response.headers().set("Cache-control", "no-cache"); + response.headers().set("Pragma", "no-cache"); + response.headers().set("Expires", new Date(0)); + response.headers().set("Connection", "close"); + response.headers().set("Content-length", wrapped.readableBytes()); + + channel.write(response); + channel.writeAndFlush(wrapped).addListener(ChannelFutureListener.CLOSE); + } + +} diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/JagGrabRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/net/update/JagGrabRequestWorker.java new file mode 100644 index 00000000..4d895b5a --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/JagGrabRequestWorker.java @@ -0,0 +1,52 @@ +package org.apollo.net.update; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Optional; + +import org.apollo.cache.IndexedFileSystem; +import org.apollo.net.codec.jaggrab.JagGrabRequest; +import org.apollo.net.codec.jaggrab.JagGrabResponse; +import org.apollo.net.update.resource.ResourceProvider; +import org.apollo.net.update.resource.VirtualResourceProvider; + +/** + * A worker which services JAGGRAB requests. + * + * @author Graham + */ +public final class JagGrabRequestWorker extends RequestWorker { + + /** + * Creates the JAGGRAB request worker. + * + * @param dispatcher The dispatcher. + * @param fs The file system. + */ + public JagGrabRequestWorker(UpdateDispatcher dispatcher, IndexedFileSystem fs) { + super(dispatcher, new VirtualResourceProvider(fs)); + } + + @Override + protected ChannelRequest nextRequest(UpdateDispatcher dispatcher) throws InterruptedException { + return dispatcher.nextJagGrabRequest(); + } + + @Override + protected void service(ResourceProvider provider, Channel channel, JagGrabRequest request) throws IOException { + Optional buffer = provider.get(request.getFilePath()); + + if (buffer.isPresent()) { + ByteBuf wrapped = Unpooled.wrappedBuffer(buffer.get()); + channel.writeAndFlush(new JagGrabResponse(wrapped)).addListener(ChannelFutureListener.CLOSE); + } else { + channel.close(); + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/OnDemandRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/net/update/OnDemandRequestWorker.java new file mode 100644 index 00000000..89eb6526 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/OnDemandRequestWorker.java @@ -0,0 +1,55 @@ +package org.apollo.net.update; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; + +import java.io.IOException; + +import org.apollo.cache.FileDescriptor; +import org.apollo.cache.IndexedFileSystem; +import org.apollo.net.codec.update.OnDemandRequest; +import org.apollo.net.codec.update.OnDemandResponse; + +/** + * A worker which services 'on-demand' requests. + * + * @author Graham + */ +public final class OnDemandRequestWorker extends RequestWorker { + + /** + * The maximum length of a chunk, in {@code byte}s. + */ + private static final int CHUNK_LENGTH = 500; + + /** + * Creates the 'on-demand' request worker. + * + * @param dispatcher The dispatcher. + * @param fs The file system. + */ + public OnDemandRequestWorker(UpdateDispatcher dispatcher, IndexedFileSystem fs) { + super(dispatcher, fs); + } + + @Override + protected ChannelRequest nextRequest(UpdateDispatcher dispatcher) throws InterruptedException { + return dispatcher.nextOnDemandRequest(); + } + + @Override + protected void service(IndexedFileSystem fs, Channel channel, OnDemandRequest request) throws IOException { + FileDescriptor descriptor = request.getFileDescriptor(); + ByteBuf buffer = Unpooled.wrappedBuffer(fs.getFile(descriptor)); + int length = buffer.readableBytes(); + + for (int chunk = 0; buffer.readableBytes() > 0; chunk++) { + int chunkSize = Math.min(buffer.readableBytes(), CHUNK_LENGTH); + OnDemandResponse response = new OnDemandResponse(descriptor, length, chunk, buffer.readBytes(chunkSize)); + channel.writeAndFlush(response); + } + buffer.release(); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorker.java b/2006Scape Server/src/main/java/org/apollo/net/update/RequestWorker.java similarity index 68% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorker.java rename to 2006Scape Server/src/main/java/org/apollo/net/update/RequestWorker.java index 3c14aa94..b07f0966 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorker.java +++ b/2006Scape Server/src/main/java/org/apollo/net/update/RequestWorker.java @@ -1,67 +1,71 @@ -package org.apollo.jagcached.dispatch; +package org.apollo.net.update; + +import io.netty.channel.Channel; import java.io.IOException; -import org.jboss.netty.channel.Channel; - /** * The base class for request workers. + * * @author Graham * @param The type of request. * @param

The type of provider. */ public abstract class RequestWorker implements Runnable { - + + /** + * The update dispatcher. + */ + private final UpdateDispatcher dispatcher; + /** * The resource provider. */ private final P provider; - - /** - * An object used for locking checks to see if the worker is running. - */ - private final Object lock = new Object(); - + /** * A flag indicating if the worker should be running. */ private boolean running = true; - + /** * Creates the request worker with the specified file system. + * + * @param dispatcher The update dispatcher. * @param provider The resource provider. */ - public RequestWorker(P provider) { + public RequestWorker(UpdateDispatcher dispatcher, P provider) { this.provider = provider; + this.dispatcher = dispatcher; } /** - * Stops this worker. The worker's thread may need to be interrupted. + * Gets the next request. + * + * @param dispatcher The dispatcher. + * @return The next request. + * @throws InterruptedException If the thread is interrupted. */ - public final void stop() { - synchronized (lock) { - running = false; - } - } - + protected abstract ChannelRequest nextRequest(UpdateDispatcher dispatcher) throws InterruptedException; + @Override public final void run() { while (true) { - synchronized (lock) { + synchronized (this) { if (!running) { break; } } - + ChannelRequest request; try { - request = nextRequest(); + request = nextRequest(dispatcher); } catch (InterruptedException e) { continue; } - + Channel channel = request.getChannel(); - + try { service(provider, channel, request.getRequest()); } catch (IOException e) { @@ -71,20 +75,23 @@ public abstract class RequestWorker implements Runnable { } } - /** - * Gets the next request. - * @return The next request. - * @throws InterruptedException if the thread is interrupted. - */ - protected abstract ChannelRequest nextRequest() throws InterruptedException; - /** * Services a request. + * * @param provider The resource provider. * @param channel The channel. * @param request The request to service. - * @throws IOException if an I/O error occurs. + * @throws IOException If an I/O error occurs. */ protected abstract void service(P provider, Channel channel, T request) throws IOException; -} + /** + * Stops this worker. The worker's thread may need to be interrupted. + */ + public final void stop() { + synchronized (this) { + running = false; + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/UpdateConstants.java b/2006Scape Server/src/main/java/org/apollo/net/update/UpdateConstants.java new file mode 100644 index 00000000..3e10ad04 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/UpdateConstants.java @@ -0,0 +1,17 @@ +package org.apollo.net.update; + +/** + * Holds update-related constants. + * + * @author Graham + */ +public final class UpdateConstants { + + /** + * Default private constructor to prevent instantiation by other classes. + */ + private UpdateConstants() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/UpdateDispatcher.java b/2006Scape Server/src/main/java/org/apollo/net/update/UpdateDispatcher.java new file mode 100644 index 00000000..5730fed8 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/UpdateDispatcher.java @@ -0,0 +1,109 @@ +package org.apollo.net.update; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; + +import org.apollo.net.codec.jaggrab.JagGrabRequest; +import org.apollo.net.codec.update.OnDemandRequest; + +/** + * Dispatches update requests to worker threads. + * + * @author Graham + */ +public final class UpdateDispatcher { + + /** + * The maximum size of a queue before requests are rejected. + */ + private static final int MAXIMUM_QUEUE_SIZE = 1024; + + /** + * A queue for pending 'on-demand' requests. + */ + private final BlockingQueue> demand = new PriorityBlockingQueue<>(); + + /** + * A queue for pending HTTP requests. + */ + private final BlockingQueue> http = new LinkedBlockingQueue<>(); + + /** + * A queue for pending JAGGRAB requests. + */ + private final BlockingQueue> jaggrab = new LinkedBlockingQueue<>(); + + /** + * Dispatches a HTTP request. + * + * @param channel The channel. + * @param request The request. + */ + public void dispatch(Channel channel, HttpRequest request) { + if (http.size() >= MAXIMUM_QUEUE_SIZE) { + channel.close(); + } + http.add(new ChannelRequest<>(channel, request)); + } + + /** + * Dispatches a JAGGRAB request. + * + * @param channel The channel. + * @param request The request. + */ + public void dispatch(Channel channel, JagGrabRequest request) { + if (jaggrab.size() >= MAXIMUM_QUEUE_SIZE) { + channel.close(); + } + jaggrab.add(new ChannelRequest<>(channel, request)); + } + + /** + * Dispatches an 'on-demand' request. + * + * @param channel The channel. + * @param request The request. + */ + public void dispatch(Channel channel, OnDemandRequest request) { + if (demand.size() >= MAXIMUM_QUEUE_SIZE) { + channel.close(); + } + demand.add(new ComparableChannelRequest<>(channel, request)); + } + + /** + * Gets the next HTTP request from the queue, blocking if none are available. + * + * @return The HTTP request. + * @throws InterruptedException If the thread is interrupted. + */ + ChannelRequest nextHttpRequest() throws InterruptedException { + return http.take(); + } + + /** + * Gets the next JAGGRAB request from the queue, blocking if none are available. + * + * @return The JAGGRAB request. + * @throws InterruptedException If the thread is interrupted. + */ + ChannelRequest nextJagGrabRequest() throws InterruptedException { + return jaggrab.take(); + } + + /** + * Gets the next 'on-demand' request from the queue, blocking if none are available. + * + * @return The 'on-demand' request. + * @throws InterruptedException If the thread is interrupted. + */ + ChannelRequest nextOnDemandRequest() throws InterruptedException { + return demand.take(); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/package-info.java b/2006Scape Server/src/main/java/org/apollo/net/update/package-info.java new file mode 100644 index 00000000..21170ec0 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains classes related to the update server. + */ +package org.apollo.net.update; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/CombinedResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/net/update/resource/CombinedResourceProvider.java similarity index 71% rename from 2006Scape Server/src/main/java/org/apollo/jagcached/resource/CombinedResourceProvider.java rename to 2006Scape Server/src/main/java/org/apollo/net/update/resource/CombinedResourceProvider.java index d52c55e2..21431c91 100644 --- a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/CombinedResourceProvider.java +++ b/2006Scape Server/src/main/java/org/apollo/net/update/resource/CombinedResourceProvider.java @@ -1,21 +1,24 @@ -package org.apollo.jagcached.resource; +package org.apollo.net.update.resource; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.Optional; /** * A resource provider composed of multiple resource providers. - * @author Graham Edgecombe + * + * @author Graham */ -public final class CombinedResourceProvider extends ResourceProvider { - +public final class CombinedResourceProvider implements ResourceProvider { + /** * An array of resource providers. */ private final ResourceProvider[] providers; - + /** * Creates the combined resource providers. + * * @param providers The providers this provider delegates to. */ public CombinedResourceProvider(ResourceProvider... providers) { @@ -28,13 +31,13 @@ public final class CombinedResourceProvider extends ResourceProvider { } @Override - public ByteBuffer get(String path) throws IOException { + public Optional get(String path) throws IOException { for (ResourceProvider provider : providers) { if (provider.accept(path)) { return provider.get(path); } } - return null; + return Optional.empty(); } -} +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/resource/HypertextResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/net/update/resource/HypertextResourceProvider.java new file mode 100644 index 00000000..2c961e07 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/resource/HypertextResourceProvider.java @@ -0,0 +1,67 @@ +package org.apollo.net.update.resource; + +import java.io.IOException; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; + +/** + * A {@link ResourceProvider} which provides additional hypertext resources. + * + * @author Graham + */ +public final class HypertextResourceProvider implements ResourceProvider { + + /** + * The base {@link Path} from which documents are served. + */ + private final Path base; + + /** + * Creates a new hypertext resource provider with the specified base directory. + * + * @param base The base directory. + */ + public HypertextResourceProvider(Path base) { + this.base = base; + } + + @Override + public boolean accept(String path) throws IOException { + Path file = base.resolve(path); + + URI target = file.toUri().normalize(); + if (!target.toASCIIString().startsWith(base.toUri().normalize().toASCIIString())) { + return false; + } + + if (Files.isDirectory(file)) { + file = file.resolve("index.html"); + } + + return Files.exists(file); + } + + @Override + public Optional get(String path) throws IOException { + Path root = base.resolve(path); + + if (Files.isDirectory(root)) { + root = root.resolve("index.html"); + } + + if (!Files.exists(root)) { + return Optional.empty(); + } + + try (FileChannel channel = FileChannel.open(root)) { + ByteBuffer buf = channel.map(MapMode.READ_ONLY, 0, Files.size(root)); + return Optional.of(buf); + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/resource/ResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/net/update/resource/ResourceProvider.java new file mode 100644 index 00000000..e6c58be4 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/resource/ResourceProvider.java @@ -0,0 +1,33 @@ +package org.apollo.net.update.resource; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Optional; + +/** + * A class which provides resources. + * + * @author Graham + */ +public interface ResourceProvider { + + /** + * Checks that this provider can fulfil a request to the specified resource. + * + * @param path The path to the resource, e.g. {@code /crc}. + * @return {@code true} if the provider can fulfil a request to the resource, {@code false} otherwise. + * @throws IOException If an I/O error occurs. + */ + public boolean accept(String path) throws IOException; + + /** + * Gets the resource data, as a {@link ByteBuffer}, wrapped in an {@link Optional}. + * + * @param path The path to the resource. + * @return A {@code ByteBuffer} representation of a resource if it exists otherwise {@link Optional#empty()} is + * returned. + * @throws IOException If some I/O exception occurs. + */ + public Optional get(String path) throws IOException; + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/resource/VirtualResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/net/update/resource/VirtualResourceProvider.java new file mode 100644 index 00000000..54093b67 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/resource/VirtualResourceProvider.java @@ -0,0 +1,71 @@ +package org.apollo.net.update.resource; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.apollo.cache.IndexedFileSystem; + +/** + * A {@link ResourceProvider} which maps virtual resources (such as {@code /media}) to files in an + * {@link IndexedFileSystem}. + * + * @author Graham + */ +public final class VirtualResourceProvider implements ResourceProvider { + + /** + * A {@link List} of valid prefixes. + */ + private static final List VALID_PREFIXES = Arrays.asList("/crc", "/title", "/config", "/interface", "/media", "/versionlist", "/textures", "/wordenc", "/sounds"); + + /** + * The file system. + */ + private final IndexedFileSystem fs; + + /** + * Creates a new virtual resource provider with the specified file system. + * + * @param fs The file system. + */ + public VirtualResourceProvider(IndexedFileSystem fs) { + this.fs = fs; + } + + @Override + public boolean accept(String path) throws IOException { + Objects.requireNonNull(path); + + return VALID_PREFIXES.stream().anyMatch(path::startsWith); + } + + @Override + public Optional get(String path) throws IOException { + if (path.startsWith("/crc")) { + return Optional.of(fs.getCrcTable()); + } else if (path.startsWith("/title")) { + return Optional.of(fs.getFile(0, 1)); + } else if (path.startsWith("/config")) { + return Optional.of(fs.getFile(0, 2)); + } else if (path.startsWith("/interface")) { + return Optional.of(fs.getFile(0, 3)); + } else if (path.startsWith("/media")) { + return Optional.of(fs.getFile(0, 4)); + } else if (path.startsWith("/versionlist")) { + return Optional.of(fs.getFile(0, 5)); + } else if (path.startsWith("/textures")) { + return Optional.of(fs.getFile(0, 6)); + } else if (path.startsWith("/wordenc")) { + return Optional.of(fs.getFile(0, 7)); + } else if (path.startsWith("/sounds")) { + return Optional.of(fs.getFile(0, 8)); + } + + return Optional.empty(); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/net/update/resource/package-info.java b/2006Scape Server/src/main/java/org/apollo/net/update/resource/package-info.java new file mode 100644 index 00000000..dc71dbee --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/net/update/resource/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains resource providers for the update server. + */ +package org.apollo.net.update.resource; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/BufferUtil.java b/2006Scape Server/src/main/java/org/apollo/util/BufferUtil.java new file mode 100644 index 00000000..14676379 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/BufferUtil.java @@ -0,0 +1,80 @@ +package org.apollo.util; + +import io.netty.buffer.ByteBuf; + +import java.nio.ByteBuffer; + +/** + * A utility class which contains {@link ByteBuffer}-related utility methods. + * + * @author Graham + */ +public final class BufferUtil { + + /** + * Reads a 'smart' (either a {@code byte} or {@code short} depending on the value) from the specified buffer. + * + * @param buffer The buffer. + * @return The 'smart'. + */ + public static int readSmart(ByteBuffer buffer) { + // Reads a single byte from the buffer without modifying the current position. + int peek = buffer.get(buffer.position()) & 0xFF; + int value = peek > Byte.MAX_VALUE ? (buffer.getShort() & 0xFFFF) + Short.MIN_VALUE : buffer.get() & 0xFF; + return value; + } + + /** + * Reads a string from the specified {@link ByteBuffer}. + * + * @param buffer The buffer. + * @return The string. + */ + public static String readString(ByteBuffer buffer) { + StringBuilder bldr = new StringBuilder(); + char character; + while ((character = (char) buffer.get()) != BufferUtil.STRING_TERMINATOR) { + bldr.append(character); + } + return bldr.toString(); + } + + /** + * Reads a string from the specified {@link ByteBuf}. + * + * @param buffer The buffer. + * @return The string. + */ + public static String readString(ByteBuf buffer) { + StringBuilder builder = new StringBuilder(); + int character; + while (buffer.isReadable() && (character = buffer.readUnsignedByte()) != BufferUtil.STRING_TERMINATOR) { + builder.append((char) character); + } + return builder.toString(); + } + + /** + * Reads a 24-bit medium integer from the specified {@link ByteBuffer}s current position and increases the buffers + * position by 3. + * + * @param buffer The {@link ByteBuffer} to read from. + * @return The read 24-bit medium integer. + */ + public static int readUnsignedMedium(ByteBuffer buffer) { + return (buffer.getShort() & 0xFFFF) << 8 | buffer.get() & 0xFF; + } + + /** + * The terminator of a string. + */ + public static final int STRING_TERMINATOR = 10; + + /** + * Default private constructor to prevent instantiation. + */ + private BufferUtil() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/CollectionUtil.java b/2006Scape Server/src/main/java/org/apollo/util/CollectionUtil.java new file mode 100644 index 00000000..cf116e4b --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/CollectionUtil.java @@ -0,0 +1,40 @@ +package org.apollo.util; + +import com.google.common.base.Preconditions; + +import java.util.Collection; +import java.util.Queue; +import java.util.function.Consumer; + +/** + * A utility class containing helper methods for various {@link Collection} objects. + * + * @author Ryley + */ +public final class CollectionUtil { + + /** + * Polls every element within the specified {@link Queue} and performs the specified {@link Consumer} event for + * each element. + * + * @param queue The {@link Queue} to poll elements from. Must not be {@code null}. + * @param consumer The {@link Consumer} to execute for each polled element. Must not be {@code null}. + */ + public static void pollAll(Queue queue, Consumer consumer) { + Preconditions.checkNotNull(queue, "Queue may not be null"); + Preconditions.checkNotNull(consumer, "Consumer may not be null"); + + T element; + while ((element = queue.poll()) != null) { + consumer.accept(element); + } + } + + /** + * Suppresses the default public constructor to discourage normal instantiation outside of this class. + */ + private CollectionUtil() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/archive/CompressionUtil.java b/2006Scape Server/src/main/java/org/apollo/util/CompressionUtil.java similarity index 59% rename from 2006Scape Server/src/main/java/org/apollo/archive/CompressionUtil.java rename to 2006Scape Server/src/main/java/org/apollo/util/CompressionUtil.java index d17aeb07..8934b329 100644 --- a/2006Scape Server/src/main/java/org/apollo/archive/CompressionUtil.java +++ b/2006Scape Server/src/main/java/org/apollo/util/CompressionUtil.java @@ -1,4 +1,4 @@ -package org.apollo.archive; +package org.apollo.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -10,6 +10,7 @@ import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; /** @@ -19,6 +20,47 @@ import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream */ public final class CompressionUtil { + /** + * Bzip2s the specified array, removing the header. + * + * @param uncompressed The uncompressed array. + * @return The compressed array. + * @throws IOException If there is an error compressing the array. + */ + public static byte[] bzip2(byte[] uncompressed) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + try (BZip2CompressorOutputStream os = new BZip2CompressorOutputStream(bout, 1)) { + os.write(uncompressed); + os.finish(); + + byte[] compressed = bout.toByteArray(); + byte[] newCompressed = new byte[compressed.length - 4]; // Strip the header + System.arraycopy(compressed, 4, newCompressed, 0, newCompressed.length); + return newCompressed; + } + } + + /** + * Debzip2s the compressed array and places the result into the decompressed array. + * + * @param compressed The compressed array, without the header. + * @param decompressed The decompressed array. + * @throws IOException If there is an error decompressing the array. + */ + public static void debzip2(byte[] compressed, byte[] decompressed) throws IOException { + byte[] newCompressed = new byte[compressed.length + 4]; + newCompressed[0] = 'B'; + newCompressed[1] = 'Z'; + newCompressed[2] = 'h'; + newCompressed[3] = '1'; + System.arraycopy(compressed, 0, newCompressed, 4, compressed.length); + + try (DataInputStream is = new DataInputStream(new BZip2CompressorInputStream(new ByteArrayInputStream(newCompressed)))) { + is.readFully(decompressed); + } + } + /** * Degzips the compressed array and places the results into the decompressed array. * @@ -81,35 +123,4 @@ public final class CompressionUtil { } - /** - * Was originally from RegionFactory and titled getBuffer where it loaded off the FS rather than cache. - * #TODO testing on this vs the methods from Apollo above. - */ - public static byte[] degzip(byte[] buffer) throws Exception { - byte[] gzipInputBuffer = new byte[999999]; - int bufferlength = 0; - GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream( - buffer)); - do { - if (bufferlength == gzipInputBuffer.length) { - System.out - .println("Error inflating data.\nGZIP buffer overflow."); - break; - } - int readByte = gzip.read(gzipInputBuffer, bufferlength, - gzipInputBuffer.length - bufferlength); - if (readByte == -1) { - break; - } - bufferlength += readByte; - } while (true); - byte[] inflated = new byte[bufferlength]; - System.arraycopy(gzipInputBuffer, 0, inflated, 0, bufferlength); - buffer = inflated; - if (buffer.length < 10) { - return null; - } - return buffer; - } - } \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/LanguageUtil.java b/2006Scape Server/src/main/java/org/apollo/util/LanguageUtil.java new file mode 100644 index 00000000..745b4ffb --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/LanguageUtil.java @@ -0,0 +1,50 @@ +package org.apollo.util; + +/** + * Contains language-related utility methods. + * + * @author Graham + * @author Major + */ +public final class LanguageUtil { + + /** + * Gets the indefinite article of the specified String. + * + * @param string The String. + * @return The indefinite article. + */ + public static String getIndefiniteArticle(String string) { + char first = Character.toLowerCase(string.charAt(0)); + if (allUpperCase(string) && (first == 'f' || first == 'l' || first == 'm' || first == 'n' || first == 's')) { + return "an"; + } + + boolean vowel = first == 'a' || first == 'e' || first == 'i' || first == 'o' || first == 'u'; + return vowel ? "an" : "a"; + } + + /** + * Returns whether or not the each letter in the specified String is upper case (i.e. digits etc are ignored). + * + * @param string The string. + * @return {@code true} if no letters in the specified String are lower case, otherwise {@code false}. + */ + private static boolean allUpperCase(String string) { + for (char character : string.toCharArray()) { + if (Character.isLowerCase(character)) { + return false; + } + } + + return true; + } + + /** + * Sole private constructor to prevent instantiation. + */ + private LanguageUtil() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/NameUtil.java b/2006Scape Server/src/main/java/org/apollo/util/NameUtil.java new file mode 100644 index 00000000..f65362c2 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/NameUtil.java @@ -0,0 +1,96 @@ +package org.apollo.util; + +/** + * Contains name-related utility methods. + * + * @author Graham + */ +public final class NameUtil { + + /** + * The name with the minimum possible value. + */ + private static final long FIRST_VALID_NAME = encodeBase37(""); + + /** + * The name with the maximum possible value. + */ + private static final long LAST_VALID_NAME = encodeBase37("999999999999"); + + /** + * Decodes a base-37 encoded String, from a {@code long}. + * + * @param value The encoded value. + * @return The decoded String. Will never be {@code null}. + * @throws IllegalArgumentException If the {@code value} does not represent a valid name. + */ + public static String decodeBase37(long value) { + if (value < FIRST_VALID_NAME || value > LAST_VALID_NAME) { + throw new IllegalArgumentException("Invalid name."); + } + + char[] chars = new char[12]; + int length = 0; + + while (value != 0) { + int remainder = (int) (value % 37); + value /= 37; + char character; + + if (remainder >= 1 && remainder <= 26) { + character = (char) ('a' + remainder - 1); + } else if (remainder >= 27 && remainder <= 36) { + character = (char) ('0' + remainder - 27); + } else { + character = '_'; + } + + chars[chars.length - length++ - 1] = character; + } + + return new String(chars, chars.length - length, length); + } + + /** + * Encodes a String into a {@code long}. + * + * @param string The String to encode. Must not be {@code null}. Must be less than 12 characters in length. + * @return The encoded value, as a {@code long}. + * @throws IllegalArgumentException If the String is too long, or contains illegal characters ([^a-zA-Z0-9 _]). + */ + public static long encodeBase37(String string) { + int length = string.length(); + if (length > 12) { + throw new IllegalArgumentException("String too long."); + } + + long value = 0; + for (char character : string.toCharArray()) { + value *= 37; + + if (character >= 'A' && character <= 'Z') { + value += character - 'A' + 1; + } else if (character >= 'a' && character <= 'z') { + value += character - 'a' + 1; + } else if (character >= '0' && character <= '9') { + value += character - '0' + 27; + } else if (character != ' ' && character != '_') { + throw new IllegalArgumentException("Illegal character: " + character + "."); + } + } + + while (value != 0 && (value % 37) == 0) { + value /= 37; + } + + return value; + } + + /** + * Default private constructor to prevent instantiation. + */ + private NameUtil() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/Point.java b/2006Scape Server/src/main/java/org/apollo/util/Point.java new file mode 100644 index 00000000..f4810b43 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/Point.java @@ -0,0 +1,49 @@ +package org.apollo.util; + +/** + * Represents a point on a 2-dimensional Cartesian plane. + * + * @author Major + */ +public final class Point { + + /** + * The x coordinate. + */ + private final int x; + + /** + * The y coordinate. + */ + private final int y; + + /** + * Creates a new point with the specified coordinates. + * + * @param x The x coordinate. + * @param y The y coordinate. + */ + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + /** + * Gets the x coordinate of this point. + * + * @return The x coordinate. + */ + public int getX() { + return x; + } + + /** + * Gets the y coordinate of this point. + * + * @return The y coordinate. + */ + public int getY() { + return y; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/StatefulFrameDecoder.java b/2006Scape Server/src/main/java/org/apollo/util/StatefulFrameDecoder.java new file mode 100644 index 00000000..8d3aeda8 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/StatefulFrameDecoder.java @@ -0,0 +1,67 @@ +package org.apollo.util; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; +import java.util.Objects; + +/** + * A stateful implementation of a {@link ByteToMessageDecoder} which may be extended and used by other classes. The + * current state is tracked by this class and is a user-specified enumeration. + * + * The state may be changed by calling the {@link StatefulFrameDecoder#setState} method. + * + * The current state is supplied as a parameter in the {@link StatefulFrameDecoder#decode} and + * {@link StatefulFrameDecoder#decodeLast} methods. + * + * This class is not thread safe: it is recommended that the state is only set in the decode methods overridden. + * + * @author Graham + * @param The state enumeration. + */ +public abstract class StatefulFrameDecoder> extends ByteToMessageDecoder { + + /** + * The current state. + */ + private T state; + + /** + * Creates the stateful frame decoder with the specified initial state. + * + * @param state The initial state. + * @throws NullPointerException If the state is {@code null}. + */ + public StatefulFrameDecoder(T state) { + setState(state); + } + + /** + * Sets a new state. + * + * @param state The new state. + * @throws NullPointerException If the state is {@code null}. + */ + public final void setState(T state) { + this.state = Objects.requireNonNull(state, "State cannot be null."); + } + + @Override + protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + decode(ctx, in, out, state); + } + + /** + * Decodes the received packets into a frame. + * + * @param ctx The current context of this handler. + * @param in The cumulative buffer, which may contain zero or more bytes. + * @param out The {@link List} of objects to pass forward through the pipeline. + * @param state The current state. The state may be changed by calling {@link #setState}. + * @throws Exception If there is an exception when decoding a frame. + */ + protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List out, T state) throws Exception; + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/StreamUtil.java b/2006Scape Server/src/main/java/org/apollo/util/StreamUtil.java new file mode 100644 index 00000000..e015b900 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/StreamUtil.java @@ -0,0 +1,54 @@ +package org.apollo.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Contains utility methods for {@link InputStream}s and {@link OutputStream}s. + * + * @author Graham + */ +public final class StreamUtil { + + /** + * Reads a String from the specified {@link InputStream}. + * + * @param input The {@link InputStream}. Must not be {@code null}. + * @return The String. Will never be {@code null}. May be empty. + * @throws IOException If an error occurs when reading from the {@link InputStream}. + */ + public static String readString(InputStream input) throws IOException { + StringBuilder builder = new StringBuilder(); + int character; + + while ((character = input.read()) != -1 && character != '\0') { + builder.append((char) character); + } + + return builder.toString(); + } + + /** + * Writes an ASCII String to the specified {@link OutputStream}. + * + * @param output The {@link OutputStream}. Must not be {@code null}. + * @param string The String. Must be ASCII. Must not be {@code null}. + * @throws IOException If an error occurs when writing to the {@link OutputStream}. + */ + public static void writeString(OutputStream output, String string) throws IOException { + for (char character : string.toCharArray()) { + output.write(character); + } + + output.write('\0'); + } + + /** + * Default private constructor to prevent instantiation. + */ + private StreamUtil() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/TextUtil.java b/2006Scape Server/src/main/java/org/apollo/util/TextUtil.java new file mode 100644 index 00000000..af262f34 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/TextUtil.java @@ -0,0 +1,148 @@ +package org.apollo.util; + +/** + * A class which contains text-related utility methods. + * + * @author Graham + */ +public final class TextUtil { + + /** + * An array of characters ordered by frequency - the elements with lower indices (generally) appear more often in + * chat messages. + */ + public static final char[] FREQUENCY_ORDERED_CHARS = { ' ', 'e', 't', 'a', 'o', 'i', 'h', 'n', 's', 'r', 'd', 'l', + 'u', 'm', 'w', 'c', 'y', 'f', 'g', 'p', 'b', 'v', 'k', 'x', 'j', 'q', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', ' ', '!', '?', '.', ',', ':', ';', '(', ')', '-', '&', '*', '\\', '\'', '@', '#', '+', + '=', '\243', '$', '%', '"', '[', ']' }; + + /** + * Capitalizes the string correctly. + * + * @param string The input string. + * @return The string with correct capitalization. + */ + public static String capitalize(String string) { + boolean capitalize = true; + StringBuilder builder = new StringBuilder(string); + int length = string.length(); + + for (int index = 0; index < length; index++) { + char character = builder.charAt(index); + + if (character == '.' || character == '!' || character == '?') { + capitalize = true; + } else if (capitalize && !Character.isWhitespace(character)) { + builder.setCharAt(index, Character.toUpperCase(character)); + capitalize = false; + } else { + builder.setCharAt(index, Character.toLowerCase(character)); + } + } + + return builder.toString(); + } + + /** + * Compresses the input text ({@code in}) and places the result in the {@code out} array. + * + * @param in The input text. + * @param out The output array. + * @return The number of bytes written to the output array. + */ + public static int compress(String in, byte[] out) { + if (in.length() > 80) { + in = in.substring(0, 80); + } + in = in.toLowerCase(); + + int carry = -1; + int outPos = 0; + for (int inPos = 0; inPos < in.length(); inPos++) { + char c = in.charAt(inPos); + int tblPos = 0; + for (int i = 0; i < FREQUENCY_ORDERED_CHARS.length; i++) { + if (c == FREQUENCY_ORDERED_CHARS[i]) { + tblPos = i; + break; + } + } + if (tblPos > 12) { + tblPos += 195; + } + if (carry == -1) { + if (tblPos < 13) { + carry = tblPos; + } else { + out[outPos++] = (byte) tblPos; + } + } else if (tblPos < 13) { + out[outPos++] = (byte) ((carry << 4) + tblPos); + carry = -1; + } else { + out[outPos++] = (byte) ((carry << 4) + (tblPos >> 4)); + carry = tblPos & 0xF; + } + } + if (carry != -1) { + out[outPos++] = (byte) (carry << 4); + } + return outPos; + } + + /** + * Filters invalid characters from the specified string. + * + * @param str The input string. + * @return The filtered string. + */ + public static String filterInvalidCharacters(String str) { + StringBuilder builder = new StringBuilder(); + for (char c : str.toLowerCase().toCharArray()) { + for (char validChar : FREQUENCY_ORDERED_CHARS) { + if (c == validChar) { + builder.append(c); + break; + } + } + } + return builder.toString(); + } + + /** + * Uncompresses the compressed data ({@code in}) with the length ({@code len}) and returns the uncompressed + * {@link String}. + * + * @param in The compressed input data. + * @param len The length. + * @return The uncompressed {@link String}. + */ + public static String decompress(byte[] in, int len) { + byte[] out = new byte[4096]; + int outPos = 0; + int carry = -1; + + for (int i = 0; i < len * 2; i++) { + int tblPos = in[i / 2] >> 4 - 4 * (i % 2) & 0xF; + if (carry == -1) { + if (tblPos < 13) { + out[outPos++] = (byte) FREQUENCY_ORDERED_CHARS[tblPos]; + } else { + carry = tblPos; + } + } else { + out[outPos++] = (byte) FREQUENCY_ORDERED_CHARS[(carry << 4) + tblPos - 195]; + carry = -1; + } + } + return new String(out, 0, outPos); + } + + /** + * Default private constructor to prevent instantiation. + */ + private TextUtil() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/ThreadUtil.java b/2006Scape Server/src/main/java/org/apollo/util/ThreadUtil.java new file mode 100644 index 00000000..47c3d0a3 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/ThreadUtil.java @@ -0,0 +1,88 @@ +package org.apollo.util; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.Objects; +import java.util.concurrent.ThreadFactory; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A static utility class which provides ease of use functionality for {@link Thread}s + * + * @author Ryley + * @author Major + */ +public final class ThreadUtil { + + /** + * Returns the amount of available processors available to the Java virtual machine. + */ + public static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors(); + + /** + * A {@link Logger} used to debug messages to the console. + */ + private static final Logger logger = Logger.getLogger(ThreadUtil.class.getSimpleName()); + + /** + * The default {@link UncaughtExceptionHandler} which raises an error from the logger with the exception and name + * of + * the specified thread the exception occurred in. + */ + private static final UncaughtExceptionHandler DEFAULT_EXCEPTION_HANDLER = + (thread, exception) -> logger.log(Level.SEVERE, "Exception in thread " + thread.getName(), exception); + + /** + * Builds a {@link ThreadFactory} using the specified {@code String} name-format, normal thread priority and the + * default {@link UncaughtExceptionHandler}, which simply logs exception messages. + * + * @param name The name-format used when creating threads. Must not be {@code null}. + * @return The {@link ThreadFactory}. Will never be {@code null}. + */ + public static ThreadFactory create(String name) { + return create(name, Thread.NORM_PRIORITY, DEFAULT_EXCEPTION_HANDLER); + } + + /** + * Builds a {@link ThreadFactory} using the specified {@code String} name-format, priority and the + * {@link #DEFAULT_EXCEPTION_HANDLER}. + * + * @param name The name-format used when creating threads. Must not be {@code null}. + * @param priority The priority used when creating threads. Must be {@code 1 <= priority <= 10}. + * @return The {@link ThreadFactory}. Will never be {@code null}. + */ + public static ThreadFactory create(String name, int priority) { + return create(name, priority, DEFAULT_EXCEPTION_HANDLER); + } + + /** + * Creates a {@link ThreadFactory} using the specified {@code String} name-format, priority and + * {@link UncaughtExceptionHandler}. + * + * @param name The name-format used when creating threads. Must not be {@code null}. + * @param priority The priority used when creating threads. Must be {@code 1 <= priority <= 10}. + * @param handler The {@link UncaughtExceptionHandler} used when creating threads. Must not be {@code null}. + * @return The {@link ThreadFactory}. Will never be {@code null}. + */ + public static ThreadFactory create(String name, int priority, UncaughtExceptionHandler handler) { + Objects.requireNonNull(name, "ThreadFactory name must not be null."); + Objects.requireNonNull(handler, "UncaughtExceptionHandler must not be null."); + + ThreadFactoryBuilder builder = new ThreadFactoryBuilder(); + builder.setNameFormat(name); + builder.setPriority(priority); + builder.setUncaughtExceptionHandler(handler); + + return builder.build(); + } + + /** + * Sole private constructor to prevent instantiation. + */ + private ThreadUtil() { + + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/package-info.java b/2006Scape Server/src/main/java/org/apollo/util/package-info.java new file mode 100644 index 00000000..6209ca8f --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains utility classes. + */ +package org.apollo.util; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandom.java b/2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandom.java new file mode 100644 index 00000000..8a534f2e --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandom.java @@ -0,0 +1,287 @@ +package org.apollo.util.security; + +/** + *

+ * An implementation of the ISAAC psuedorandom number + * generator. + *

+ * + *
+ * ------------------------------------------------------------------------------
+ * Rand.java: By Bob Jenkins.  My random number generator, ISAAC.
+ *   rand.init() -- initialize
+ *   rand.val()  -- get a random value
+ * MODIFIED:
+ *   960327: Creation (addition of randinit, really)
+ *   970719: use context, not global variables, for internal state
+ *   980224: Translate to Java
+ * ------------------------------------------------------------------------------
+ * 
+ *

+ * This class has been changed to be more conformant to Java and javadoc conventions. + *

+ * + * @author Bob Jenkins + */ +public final class IsaacRandom { + + /** + * The golden ratio. + */ + private static final int GOLDEN_RATIO = 0x9e3779b9; + + /** + * The log of the size of the result and state arrays. + */ + private static final int LOG_SIZE = Long.BYTES; + + /** + * The size of the result and states arrays. + */ + private static final int SIZE = 1 << LOG_SIZE; + + /** + * A mask for pseudo-random lookup. + */ + private static int MASK = SIZE - 1 << 2; + + /** + * The results given to the user. + */ + private final int[] results = new int[SIZE]; + + /** + * The internal state. + */ + private final int[] state = new int[SIZE]; + + /** + * The count through the results in the results array. + */ + private int count = SIZE; + + /** + * The accumulator. + */ + private int accumulator; + + /** + * The last result. + */ + private int last; + + /** + * The counter. + */ + private int counter; + + /** + * Creates the random number generator with the specified seed. + * + * @param seed The seed. + */ + public IsaacRandom(int[] seed) { + int length = Math.min(seed.length, results.length); + System.arraycopy(seed, 0, results, 0, length); + init(); + } + + /** + * Generates 256 results. + */ + private void isaac() { + int i, j, x, y; + + last += ++counter; + for (i = 0, j = SIZE / 2; i < SIZE / 2;) { + x = state[i]; + accumulator ^= accumulator << 13; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + + x = state[i]; + accumulator ^= accumulator >>> 6; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + + x = state[i]; + accumulator ^= accumulator << 2; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + + x = state[i]; + accumulator ^= accumulator >>> 16; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + } + + for (j = 0; j < SIZE / 2;) { + x = state[i]; + accumulator ^= accumulator << 13; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + + x = state[i]; + accumulator ^= accumulator >>> 6; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + + x = state[i]; + accumulator ^= accumulator << 2; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + + x = state[i]; + accumulator ^= accumulator >>> 16; + accumulator += state[j++]; + state[i] = y = state[(x & MASK) >> 2] + accumulator + last; + results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x; + } + } + + /** + * Initializes this random number generator. + */ + private void init() { + int i; + int a, b, c, d, e, f, g, h; + a = b = c = d = e = f = g = h = GOLDEN_RATIO; + + for (i = 0; i < 4; ++i) { + a ^= b << 11; + d += a; + b += c; + b ^= c >>> 2; + e += b; + c += d; + c ^= d << 8; + f += c; + d += e; + d ^= e >>> 16; + g += d; + e += f; + e ^= f << 10; + h += e; + f += g; + f ^= g >>> 4; + a += f; + g += h; + g ^= h << 8; + b += g; + h += a; + h ^= a >>> 9; + c += h; + a += b; + } + + for (i = 0; i < SIZE; i += 8) { /* fill in mem[] with messy stuff */ + a += results[i]; + b += results[i + 1]; + c += results[i + 2]; + d += results[i + 3]; + e += results[i + 4]; + f += results[i + 5]; + g += results[i + 6]; + h += results[i + 7]; + + a ^= b << 11; + d += a; + b += c; + b ^= c >>> 2; + e += b; + c += d; + c ^= d << 8; + f += c; + d += e; + d ^= e >>> 16; + g += d; + e += f; + e ^= f << 10; + h += e; + f += g; + f ^= g >>> 4; + a += f; + g += h; + g ^= h << 8; + b += g; + h += a; + h ^= a >>> 9; + c += h; + a += b; + state[i] = a; + state[i + 1] = b; + state[i + 2] = c; + state[i + 3] = d; + state[i + 4] = e; + state[i + 5] = f; + state[i + 6] = g; + state[i + 7] = h; + } + + for (i = 0; i < SIZE; i += 8) { + a += state[i]; + b += state[i + 1]; + c += state[i + 2]; + d += state[i + 3]; + e += state[i + 4]; + f += state[i + 5]; + g += state[i + 6]; + h += state[i + 7]; + a ^= b << 11; + d += a; + b += c; + b ^= c >>> 2; + e += b; + c += d; + c ^= d << 8; + f += c; + d += e; + d ^= e >>> 16; + g += d; + e += f; + e ^= f << 10; + h += e; + f += g; + f ^= g >>> 4; + a += f; + g += h; + g ^= h << 8; + b += g; + h += a; + h ^= a >>> 9; + c += h; + a += b; + state[i] = a; + state[i + 1] = b; + state[i + 2] = c; + state[i + 3] = d; + state[i + 4] = e; + state[i + 5] = f; + state[i + 6] = g; + state[i + 7] = h; + } + + isaac(); + } + + /** + * Gets the next random value. + * + * @return The next random value. + */ + public int nextInt() { + if (0 == count--) { + isaac(); + count = SIZE - 1; + } + return results[count]; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandomPair.java b/2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandomPair.java new file mode 100644 index 00000000..fa3c6dce --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/security/IsaacRandomPair.java @@ -0,0 +1,51 @@ +package org.apollo.util.security; + + +/** + * A pair of two {@link IsaacRandom} random number generators used as a stream cipher. One takes the role of an encoder + * for this endpoint, the other takes the role of a decoder for this endpoint. + * + * @author Graham + */ +public final class IsaacRandomPair { + + /** + * The random number generator used to decode data. + */ + private final IsaacRandom decodingRandom; + + /** + * The random number generator used to encode data. + */ + private final IsaacRandom encodingRandom; + + /** + * Creates the pair of random number generators. + * + * @param encodingRandom The random number generator used for encoding. + * @param decodingRandom The random number generator used for decoding. + */ + public IsaacRandomPair(IsaacRandom encodingRandom, IsaacRandom decodingRandom) { + this.encodingRandom = encodingRandom; + this.decodingRandom = decodingRandom; + } + + /** + * Gets the random number generator used for decoding. + * + * @return The random number generator used for decoding. + */ + public IsaacRandom getDecodingRandom() { + return decodingRandom; + } + + /** + * Gets the random number generator used for encoding. + * + * @return The random number generator used for encoding. + */ + public IsaacRandom getEncodingRandom() { + return encodingRandom; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/security/PlayerCredentials.java b/2006Scape Server/src/main/java/org/apollo/util/security/PlayerCredentials.java new file mode 100644 index 00000000..7bfc466f --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/security/PlayerCredentials.java @@ -0,0 +1,138 @@ +package org.apollo.util.security; + +import org.apollo.util.NameUtil; + +/** + * Holds the credentials for a player. + * + * @author Graham + */ +public final class PlayerCredentials { + + /** + * The player's username encoded as a long. + */ + private final long encodedUsername; + + /** + * The player's password. + */ + private String password; + + /** + * The computer's unique identifier. + */ + private final int uid; + + /** + * The player's username. + */ + private final String username; + + /** + * The hash of the player's username. + */ + private final int usernameHash; + + /** + * The Player's host address, represented as a String. + */ + private final String hostAddress; + + /** + * Creates a new {@link PlayerCredentials} object with the specified name, password and uid. + * + * @param username The player's username. + * @param password The player's password. + * @param usernameHash The hash of the player's username. + * @param uid The computer's uid. + * @param hostAddress The Player's connecting host address. + */ + public PlayerCredentials(String username, String password, int usernameHash, int uid, String hostAddress) { + this.username = username; + encodedUsername = NameUtil.encodeBase37(username); + this.password = password; + this.usernameHash = usernameHash; + this.uid = uid; + this.hostAddress = hostAddress; + } + + /** + * Gets the player's username encoded as a long. + * + * @return The username as encoded by {@link NameUtil#encodeBase37(String)}. + */ + public long getEncodedUsername() { + return encodedUsername; + } + + /** + * Sets the player's password + * + * @param password The player's new password + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Gets the player's password. + * + * @return The player's password. + */ + public String getPassword() { + return password; + } + + /** + * Gets the computer's uid. + * + * @return The computer's uid. + */ + public int getUid() { + return uid; + } + + /** + * Gets the player's username. + * + * @return The player's username. + */ + public String getUsername() { + return username; + } + + /** + * Gets the username hash. + * + * @return The username hash. + */ + public int getUsernameHash() { + return usernameHash; + } + + /** + * Gets the Player's connecting host address. + * + * @return The Player's host address, represented as a String. + */ + public String getHostAddress() { + return hostAddress; + } + + @Override + public int hashCode() { + return Long.hashCode(encodedUsername); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PlayerCredentials) { + PlayerCredentials other = (PlayerCredentials) obj; + return encodedUsername == other.encodedUsername; + } + + return false; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/security/package-info.java b/2006Scape Server/src/main/java/org/apollo/util/security/package-info.java new file mode 100644 index 00000000..184fa6a6 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/security/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains classes related to security and cryptography. + */ +package org.apollo.util.security; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/tools/EquipmentConstants.java b/2006Scape Server/src/main/java/org/apollo/util/tools/EquipmentConstants.java new file mode 100644 index 00000000..b20b23cb --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/tools/EquipmentConstants.java @@ -0,0 +1,102 @@ +package org.apollo.util.tools; + +/** + * Contains equipment name constants. + * + * @author Graham + * @author Palidino76 + */ +public final class EquipmentConstants { + + /** + * Amulets. + */ + public static final String[] AMULETS = { "amulet", "necklace", "Amulet of" }; + + /** + * Arrows. + */ + public static final String[] ARROWS = { "arrow", "arrows", "arrow(p)", "arrow(+)", "arrow(s)", "bolt", "Bolt rack", + "Opal bolts", "Dragon bolts" }; + + /** + * Bodies. + */ + public static final String[] BODY = { "platebody", "chainbody", "robetop", "leathertop", "platemail", "top", + "brassard", "Robe top", "body", "platebody (t)", "platebody (g)", "body(g)", "body_(g)", "chestplate", + "torso", "shirt" }; + + /** + * Boots. + */ + public static final String[] BOOTS = { "boots", "Boots" }; + + /** + * Capes. + */ + public static final String[] CAPES = { "cape", "Cape" }; + + /** + * Full bodies. + */ + public static final String[] FULL_BODIES = { "top", "shirt", "platebody", "Ahrims robetop", "Karils leathertop", + "brassard", "Robe top", "robetop", "platebody (t)", "platebody (g)", "chestplate", "torso" }; + + /** + * Full hats. + */ + public static final String[] FULL_HATS = { "med helm", "coif", "Dharoks helm", "hood", "Initiate helm", "Coif", + "Helm of neitiznot" }; + + /** + * Full masks. + */ + public static final String[] FULL_MASKS = { "full helm", "mask", "Veracs helm", "Guthans helm", "Torags helm", + "Karils coif", "full helm (t)", "full helm (g)", "mask" }; + + /** + * Gloves. + */ + public static final String[] GLOVES = { "gloves", "gauntlets", "Gloves", "vambraces", "vamb", "bracers" }; + + /** + * Hats. + */ + public static final String[] HATS = { "tiara", "helm", "hood", "coif", "Coif", "hat", "partyhat", "Hat", + "full helm (t)", "full helm (g)", "hat (t)", "hat (g)", "cav", "boater", "helmet", "mask", + "Helm of neitiznot" }; + + /** + * Legs. + */ + public static final String[] LEGS = { "platelegs", "plateskirt", "skirt", "bottoms", "chaps", "platelegs (t)", + "platelegs (g)", "bottom", "skirt", "skirt (g)", "skirt (t)", "chaps (g)", "chaps (t)", "tassets", "legs", + "Flared trousers" }; + + /** + * Rings. + */ + public static final String[] RINGS = { "ring", "Ring of" }; + + /** + * Shields. + */ + public static final String[] SHIELDS = { "kiteshield", "sq shield", "Toktz-ket", "books", "book", "kiteshield (t)", + "kiteshield (g)", "kiteshield(h)", "defender", "shield" }; + + /** + * Weapons. + */ + public static final String[] WEAPONS = { "scimitar", "longsword", "sword", "longbow", "shortbow", "dagger", "mace", + "halberd", "spear", "Abyssal whip", "axe", "flail", "crossbow", "Torags hammers", "dagger(p)", "dagger(+)", + "dagger(s)", "spear(p)", "spear(+)", "spear(s)", "spear(kp)", "maul", "dart", "dart(p)", "javelin", + "javelin(p)", "knife", "knife(p)", "Longbow", "Shortbow", "Crossbow", "Toktz-xil", "Toktz-mej", + "Tzhaar-ket", "staff", "Staff", "godsword", "c'bow", "Crystal bow", "Dark bow", "Magic butterfly net" }; + + /** + * Default private constructor to prevent instantiation. + */ + private EquipmentConstants() { + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/tools/RsaKeyGenerator.java b/2006Scape Server/src/main/java/org/apollo/util/tools/RsaKeyGenerator.java new file mode 100644 index 00000000..f5c6ab5e --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/tools/RsaKeyGenerator.java @@ -0,0 +1,48 @@ +package org.apollo.util.tools; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * An RSA key generator. + * + * @author Graham + * @author Major + * @author Cube + * @author Advocatus + */ +public final class RsaKeyGenerator { + + /** + * The bit count. + * Note: 2048 bits and above are not compatible with the client without modifications + */ + private static final int BIT_COUNT = 1024; + + /** + * The entry point of the RsaKeyGenerator. + * + * @param args The application arguments. + */ + public static void main(String[] args) throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(BIT_COUNT); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + + System.out.println("Place these keys in the client:"); + System.out.println("--------------------"); + System.out.println("public key: " + publicKey.getPublicExponent()); + System.out.println("modulus: " + publicKey.getModulus()); + + System.out.println("Place these keys in the server:"); + System.out.println("--------------------"); + System.out.println("private key: " + privateKey.getPrivateExponent()); + System.out.println("modulus: " + privateKey.getModulus()); + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/tools/package-info.java b/2006Scape Server/src/main/java/org/apollo/util/tools/package-info.java new file mode 100644 index 00000000..c33b70fc --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/tools/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains several stand-alone utilities. + */ +package org.apollo.util.tools; \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/xml/XmlNode.java b/2006Scape Server/src/main/java/org/apollo/util/xml/XmlNode.java new file mode 100644 index 00000000..cadddcfa --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/xml/XmlNode.java @@ -0,0 +1,247 @@ +package org.apollo.util.xml; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * A class which represents a single node in the DOM tree, maintaining information about its children, attributes, value + * and name. + * + * @author Graham + */ +public final class XmlNode implements Iterable { + + /** + * The attribute map. + */ + private final Map attributes = new HashMap<>(); + + /** + * The list of child nodes. + */ + private final List children = new ArrayList<>(); + + /** + * The name of this node. + */ + private String name; + + /** + * The value of this node, or {@code null} if it has no value. + */ + private String value; + + /** + * Creates a new {@link XmlNode} with the specified name. + * + * @param name The name of this node. + */ + public XmlNode(String name) { + this.name = name; + } + + /** + * Adds a child {@link XmlNode}. + * + * @param child The child to add. + */ + public void addChild(XmlNode child) { + children.add(child); + } + + /** + * Checks if an attribute with the specified name exists. + * + * @param name The attribute's name. + * @return {@code true} if an attribute with that name exists, {@code false} otherwise. + */ + public boolean containsAttribute(String name) { + return attributes.containsKey(name); + } + + /** + * Gets an attribute by it's name. + * + * @param name The name of the attribute. + * @return The attribute's value, or {@code null} if it doesn't exist. + */ + public String getAttribute(String name) { + return attributes.get(name); + } + + /** + * Gets the attribute count. + * + * @return The number of attributes. + */ + public int getAttributeCount() { + return attributes.size(); + } + + /** + * Gets a {@link Set} of attribute names. + * + * @return The set of names. + */ + public Set getAttributeNames() { + return attributes.keySet(); + } + + /** + * Gets a {@link Set} of attribute map entries. + * + * @return The set of entries. + */ + public Set> getAttributes() { + return attributes.entrySet(); + } + + /** + * Gets the first child with the specified name. + * + * @param name The name of the child. + * @return The {@link XmlNode} if a child was found with a matching name, {@code null} otherwise. + */ + public XmlNode getChild(String name) { + for (XmlNode child : children) { + if (child.getName().equals(name)) { + return child; + } + } + return null; + } + + /** + * Gets the child count. + * + * @return The number of child {@link XmlNode}s. + */ + public int getChildCount() { + return children.size(); + } + + /** + * Gets a {@link Collection} of child {@link XmlNode}s. + * + * @return The collection. + */ + public Collection getChildren() { + return Collections.unmodifiableCollection(children); + } + + /** + * Gets the name of this node. + * + * @return The name of this node. + */ + public String getName() { + return name; + } + + /** + * Gets the value of this node. + * + * @return The value of this node, or {@code null} if it has no value. + */ + public String getValue() { + return value; + } + + /** + * Gets the value of this node, wrapped in an {@link Optional} + * + * @return The value of this node if it exists otherwise {@link Optional#empty()} is returned + */ + public Optional getOptionalValue() { + return Optional.ofNullable(value); + } + + /** + * Checks if this node has a value. + * + * @return {@code true} if so, {@code false} if not. + */ + public boolean hasValue() { + return value != null; + } + + @Override + public Iterator iterator() { + return children.iterator(); + } + + /** + * Removes all attributes. + */ + public void removeAllAttributes() { + attributes.clear(); + } + + /** + * Removes all children. + */ + public void removeAllChildren() { + children.clear(); + } + + /** + * Removes an attribute. + * + * @param name The name of the attribute. + */ + public void removeAttribute(String name) { + attributes.remove(name); + } + + /** + * Removes a child {@link XmlNode}. + * + * @param child The child to remove. + */ + public void removeChild(XmlNode child) { + children.remove(child); + } + + /** + * Removes the value of this node. + */ + public void removeValue() { + value = null; + } + + /** + * Adds an attribute. It will overwrite an existing attribute if it exists. + * + * @param name The name of the attribute. + * @param value The value of the attribute. + */ + public void setAttribute(String name, String value) { + attributes.put(name, value); + } + + /** + * Sets the name of this node. + * + * @param name The name of this node. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Sets the value of this node. + * + * @param value The value of this node. + */ + public void setValue(String value) { + this.value = value; + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/xml/XmlParser.java b/2006Scape Server/src/main/java/org/apollo/util/xml/XmlParser.java new file mode 100644 index 00000000..3ed8e850 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/xml/XmlParser.java @@ -0,0 +1,155 @@ +package org.apollo.util.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * A simple XML parser that uses the internal {@link org.xml.sax} API to create a tree of {@link XmlNode} objects. + * + * @author Graham + */ +public final class XmlParser { + + /** + * A class which handles SAX events. + * + * @author Graham + */ + private final class XmlHandler extends DefaultHandler { + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + currentNode.setValue(new String(ch, start, length)); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (!nodeStack.isEmpty()) { + currentNode = nodeStack.pop(); + } + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + XmlNode next = new XmlNode(localName); + + if (rootNode == null) { + rootNode = currentNode = next; + } else { + currentNode.addChild(next); + nodeStack.add(currentNode); + currentNode = next; + } + + if (attributes != null) { + int attributeCount = attributes.getLength(); + for (int i = 0; i < attributeCount; i++) { + String attribLocalName = attributes.getLocalName(i); + currentNode.setAttribute(attribLocalName, attributes.getValue(i)); + } + } + } + + } + + /** + * The current node. + */ + private XmlNode currentNode; + + /** + * The SAX event handler. + */ + private final XmlHandler eventHandler; + + /** + * The stack of nodes, used when traversing the document and going through child nodes. + */ + private final Stack nodeStack = new Stack<>(); + + /** + * The current root node. + */ + private XmlNode rootNode; + + /** + * The {@link XMLReader} backing this {@link XmlParser}. + */ + private final XMLReader xmlReader; + + /** + * Creates the XML parser. + * + * @throws SAXException If a SAX error occurs. + */ + public XmlParser() throws SAXException { + xmlReader = XMLReaderFactory.createXMLReader(); + eventHandler = this.new XmlHandler(); + init(); + } + + /** + * Initialises this parser. + */ + private void init() { + xmlReader.setContentHandler(eventHandler); + xmlReader.setDTDHandler(eventHandler); + xmlReader.setEntityResolver(eventHandler); + xmlReader.setErrorHandler(eventHandler); + } + + /** + * Parses XML data from the {@link InputSource}. + * + * @param source The {@link InputSource}. + * @return The root {@link XmlNode}. + * @throws IOException If an I/O error occurs. + * @throws SAXException If a SAX error occurs. + */ + private XmlNode parse(InputSource source) throws IOException, SAXException { + rootNode = null; + xmlReader.parse(source); + if (rootNode == null) { + throw new SAXException("No root element."); + } + return rootNode; + } + + /** + * Parses XML data from the given {@link InputStream}. + * + * @param is The {@link InputStream}. + * @return The root {@link XmlNode}. + * @throws IOException If an I/O error occurs. + * @throws SAXException If a SAX error occurs. + */ + public XmlNode parse(InputStream is) throws IOException, SAXException { + synchronized (this) { + return parse(new InputSource(is)); + } + } + + /** + * Parses XML data from the given {@link Reader}. + * + * @param reader The {@link Reader}. + * @return The root {@link XmlNode}. + * @throws IOException If an I/O error occurs. + * @throws SAXException If a SAX error occurs. + */ + public XmlNode parse(Reader reader) throws IOException, SAXException { + synchronized (this) { + return parse(new InputSource(reader)); + } + } + +} \ No newline at end of file diff --git a/2006Scape Server/src/main/java/org/apollo/util/xml/package-info.java b/2006Scape Server/src/main/java/org/apollo/util/xml/package-info.java new file mode 100644 index 00000000..dd4f8677 --- /dev/null +++ b/2006Scape Server/src/main/java/org/apollo/util/xml/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains classes which parse XML data into an object tree. + */ +package org.apollo.util.xml; \ No newline at end of file