diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/OsrsJs5ChannelInitializer.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/OsrsJs5ChannelInitializer.kt index 9ddb8d8c..e146c4ef 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/OsrsJs5ChannelInitializer.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/OsrsJs5ChannelInitializer.kt @@ -6,13 +6,16 @@ import io.netty.handler.timeout.ReadTimeoutHandler import org.openrs2.protocol.Protocol import org.openrs2.protocol.Rs2Decoder import org.openrs2.protocol.Rs2Encoder +import org.openrs2.protocol.login.ClientOutOfDateCodec +import org.openrs2.protocol.login.InitJs5RemoteConnectionCodec +import org.openrs2.protocol.login.Js5OkCodec public class OsrsJs5ChannelInitializer(private val handler: OsrsJs5ChannelHandler) : ChannelInitializer() { override fun initChannel(ch: Channel) { ch.pipeline().addLast( ReadTimeoutHandler(30), - Rs2Encoder(Protocol.LOGIN_UPSTREAM), - Rs2Decoder(Protocol.JS5REMOTE_DOWNSTREAM) + Rs2Encoder(Protocol(InitJs5RemoteConnectionCodec())), + Rs2Decoder(Protocol(Js5OkCodec(), ClientOutOfDateCodec())) ) ch.pipeline().addLast("handler", handler) } diff --git a/game/src/main/kotlin/org/openrs2/game/GameModule.kt b/game/src/main/kotlin/org/openrs2/game/GameModule.kt index fcd9f90c..0ffb222c 100644 --- a/game/src/main/kotlin/org/openrs2/game/GameModule.kt +++ b/game/src/main/kotlin/org/openrs2/game/GameModule.kt @@ -18,6 +18,7 @@ import org.openrs2.game.cluster.SingleWorldCluster import org.openrs2.game.net.NetworkService import org.openrs2.game.net.js5.Js5Service import org.openrs2.net.NetworkModule +import org.openrs2.protocol.ProtocolModule public object GameModule : AbstractModule() { override fun configure() { @@ -25,6 +26,7 @@ public object GameModule : AbstractModule() { install(CacheModule) install(ConfigModule) install(NetworkModule) + install(ProtocolModule) val binder = Multibinder.newSetBinder(binder(), Service::class.java) binder.addBinding().to(GameService::class.java) diff --git a/game/src/main/kotlin/org/openrs2/game/net/Rs2ChannelInitializer.kt b/game/src/main/kotlin/org/openrs2/game/net/Rs2ChannelInitializer.kt index f49c4341..0e1c7e8e 100644 --- a/game/src/main/kotlin/org/openrs2/game/net/Rs2ChannelInitializer.kt +++ b/game/src/main/kotlin/org/openrs2/game/net/Rs2ChannelInitializer.kt @@ -7,6 +7,8 @@ import org.openrs2.game.net.login.LoginChannelHandler import org.openrs2.protocol.Protocol import org.openrs2.protocol.Rs2Decoder import org.openrs2.protocol.Rs2Encoder +import org.openrs2.protocol.login.LoginDownstream +import org.openrs2.protocol.login.LoginUpstream import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Provider @@ -14,13 +16,17 @@ import javax.inject.Singleton @Singleton public class Rs2ChannelInitializer @Inject constructor( - private val handlerProvider: Provider + private val handlerProvider: Provider, + @LoginUpstream + private val loginUpStreamProtocol: Protocol, + @LoginDownstream + private val loginDownStreamProtocol: Protocol ) : ChannelInitializer() { override fun initChannel(ch: Channel) { ch.pipeline().addLast( IdleStateHandler(true, TIMEOUT_SECS, TIMEOUT_SECS, TIMEOUT_SECS, TimeUnit.SECONDS), - Rs2Decoder(Protocol.LOGIN_UPSTREAM), - Rs2Encoder(Protocol.LOGIN_DOWNSTREAM), + Rs2Decoder(loginUpStreamProtocol), + Rs2Encoder(loginDownStreamProtocol), handlerProvider.get() ) } diff --git a/game/src/main/kotlin/org/openrs2/game/net/login/LoginChannelHandler.kt b/game/src/main/kotlin/org/openrs2/game/net/login/LoginChannelHandler.kt index 469edb2a..99b66873 100644 --- a/game/src/main/kotlin/org/openrs2/game/net/login/LoginChannelHandler.kt +++ b/game/src/main/kotlin/org/openrs2/game/net/login/LoginChannelHandler.kt @@ -20,11 +20,13 @@ import org.openrs2.protocol.Protocol import org.openrs2.protocol.Rs2Decoder import org.openrs2.protocol.Rs2Encoder import org.openrs2.protocol.jaggrab.JaggrabRequestDecoder +import org.openrs2.protocol.js5.Js5RemoteDownstream import org.openrs2.protocol.js5.Js5RequestDecoder import org.openrs2.protocol.js5.Js5ResponseEncoder import org.openrs2.protocol.js5.XorDecoder import org.openrs2.protocol.login.LoginRequest import org.openrs2.protocol.login.LoginResponse +import org.openrs2.protocol.world.WorldListDownstream import org.openrs2.protocol.world.WorldListResponse import javax.inject.Inject import javax.inject.Provider @@ -32,7 +34,11 @@ import javax.inject.Provider public class LoginChannelHandler @Inject constructor( private val cluster: Cluster, private val js5HandlerProvider: Provider, - private val jaggrabHandler: JaggrabChannelHandler + private val jaggrabHandler: JaggrabChannelHandler, + @Js5RemoteDownstream + private val js5RemoteDownstreamProtocol: Protocol, + @WorldListDownstream + private val worldListDownstreamProtocol: Protocol ) : SimpleChannelInboundHandler(LoginRequest::class.java) { override fun channelActive(ctx: ChannelHandlerContext) { ctx.read() @@ -50,7 +56,7 @@ public class LoginChannelHandler @Inject constructor( private fun handleInitJs5RemoteConnection(ctx: ChannelHandlerContext, msg: LoginRequest.InitJs5RemoteConnection) { val encoder = ctx.pipeline().get(Rs2Encoder::class.java) - encoder.protocol = Protocol.JS5REMOTE_DOWNSTREAM + encoder.protocol = js5RemoteDownstreamProtocol if (msg.build != BUILD) { ctx.write(LoginResponse.ClientOutOfDate).addListener(ChannelFutureListener.CLOSE) @@ -105,7 +111,7 @@ public class LoginChannelHandler @Inject constructor( } val encoder = ctx.pipeline().get(Rs2Encoder::class.java) - encoder.protocol = Protocol.WORLD_LIST_DOWNSTREAM + encoder.protocol = worldListDownstreamProtocol ctx.write(WorldListResponse(worldList, players)).addListener(ChannelFutureListener.CLOSE) } diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/Protocol.kt b/protocol/src/main/kotlin/org/openrs2/protocol/Protocol.kt index 6e843fe4..9345880a 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/Protocol.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/Protocol.kt @@ -1,17 +1,12 @@ package org.openrs2.protocol -import org.openrs2.protocol.login.ClientOutOfDateCodec -import org.openrs2.protocol.login.InitCrossDomainConnectionCodec -import org.openrs2.protocol.login.InitGameConnectionCodec -import org.openrs2.protocol.login.InitJaggrabConnectionCodec -import org.openrs2.protocol.login.InitJs5RemoteConnectionCodec -import org.openrs2.protocol.login.IpLimitCodec -import org.openrs2.protocol.login.Js5OkCodec -import org.openrs2.protocol.login.RequestWorldListCodec -import org.openrs2.protocol.login.ServerFullCodec -import org.openrs2.protocol.world.WorldListResponseCodec +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +public class Protocol @Inject constructor(codecs: Set>) { + public constructor(vararg codecs: PacketCodec<*>) : this(codecs.toSet()) -public class Protocol(vararg codecs: PacketCodec<*>) { private val decoders = arrayOfNulls>(256) private val encoders = codecs.associateBy(PacketCodec<*>::type) @@ -30,31 +25,4 @@ public class Protocol(vararg codecs: PacketCodec<*>) { public fun getEncoder(type: Class): PacketCodec? { return encoders[type] as PacketCodec? } - - public companion object { - public val LOGIN_UPSTREAM: Protocol = Protocol( - InitGameConnectionCodec, - InitJs5RemoteConnectionCodec, - InitJaggrabConnectionCodec, - RequestWorldListCodec, - InitCrossDomainConnectionCodec - ) - - public val LOGIN_DOWNSTREAM: Protocol = Protocol( - ClientOutOfDateCodec, - ServerFullCodec, - IpLimitCodec - ) - - public val JS5REMOTE_DOWNSTREAM: Protocol = Protocol( - Js5OkCodec, - ClientOutOfDateCodec, - ServerFullCodec, - IpLimitCodec - ) - - public val WORLD_LIST_DOWNSTREAM: Protocol = Protocol( - WorldListResponseCodec - ) - } } diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/ProtocolModule.kt b/protocol/src/main/kotlin/org/openrs2/protocol/ProtocolModule.kt new file mode 100644 index 00000000..b82c084f --- /dev/null +++ b/protocol/src/main/kotlin/org/openrs2/protocol/ProtocolModule.kt @@ -0,0 +1,81 @@ +package org.openrs2.protocol + +import com.google.inject.AbstractModule +import com.google.inject.PrivateModule +import com.google.inject.TypeLiteral +import com.google.inject.multibindings.Multibinder +import org.openrs2.buffer.BufferModule +import org.openrs2.crypto.CryptoModule +import org.openrs2.protocol.js5.Js5RemoteDownstream +import org.openrs2.protocol.login.ClientOutOfDateCodec +import org.openrs2.protocol.login.InitCrossDomainConnectionCodec +import org.openrs2.protocol.login.InitGameConnectionCodec +import org.openrs2.protocol.login.InitJaggrabConnectionCodec +import org.openrs2.protocol.login.InitJs5RemoteConnectionCodec +import org.openrs2.protocol.login.IpLimitCodec +import org.openrs2.protocol.login.Js5OkCodec +import org.openrs2.protocol.login.LoginDownstream +import org.openrs2.protocol.login.LoginUpstream +import org.openrs2.protocol.login.RequestWorldListCodec +import org.openrs2.protocol.login.ServerFullCodec +import org.openrs2.protocol.world.WorldListDownstream +import org.openrs2.protocol.world.WorldListResponseCodec + +public object ProtocolModule : AbstractModule() { + public override fun configure() { + install(BufferModule) + install(CryptoModule) + + bindProtocol( + LoginUpstream::class.java, + InitGameConnectionCodec::class.java, + InitJs5RemoteConnectionCodec::class.java, + InitJaggrabConnectionCodec::class.java, + RequestWorldListCodec::class.java, + InitCrossDomainConnectionCodec::class.java + ) + + bindProtocol( + LoginDownstream::class.java, + ClientOutOfDateCodec::class.java, + ServerFullCodec::class.java, + IpLimitCodec::class.java + ) + + bindProtocol( + Js5RemoteDownstream::class.java, + Js5OkCodec::class.java, + ClientOutOfDateCodec::class.java, + ServerFullCodec::class.java, + IpLimitCodec::class.java + ) + + bindProtocol( + WorldListDownstream::class.java, + WorldListResponseCodec::class.java + ) + } + + private fun bindProtocol( + annotation: Class, + vararg codecs: Class> + ) { + install(object : PrivateModule() { + override fun configure() { + val binder = Multibinder.newSetBinder(binder(), PACKET_CODEC_TYPE_LITERAL) + for (codec in codecs) { + binder.addBinding().to(codec) + } + + bind(Protocol::class.java) + .annotatedWith(annotation) + .to(Protocol::class.java) + + expose(Protocol::class.java) + .annotatedWith(annotation) + } + }) + } + + private val PACKET_CODEC_TYPE_LITERAL = object : TypeLiteral>() {} +} diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/js5/Js5RemoteDownstream.kt b/protocol/src/main/kotlin/org/openrs2/protocol/js5/Js5RemoteDownstream.kt new file mode 100644 index 00000000..e6afeee6 --- /dev/null +++ b/protocol/src/main/kotlin/org/openrs2/protocol/js5/Js5RemoteDownstream.kt @@ -0,0 +1,8 @@ +package org.openrs2.protocol.js5 + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION) +public annotation class Js5RemoteDownstream diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/ClientOutOfDateCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/ClientOutOfDateCodec.kt index 08c6ad3b..200c7ddf 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/ClientOutOfDateCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/ClientOutOfDateCodec.kt @@ -1,8 +1,10 @@ package org.openrs2.protocol.login import org.openrs2.protocol.EmptyPacketCodec +import javax.inject.Singleton -public object ClientOutOfDateCodec : EmptyPacketCodec( +@Singleton +public class ClientOutOfDateCodec : EmptyPacketCodec( packet = LoginResponse.ClientOutOfDate, opcode = 6 ) diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitCrossDomainConnectionCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitCrossDomainConnectionCodec.kt index 06ad927a..fda56965 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitCrossDomainConnectionCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitCrossDomainConnectionCodec.kt @@ -1,8 +1,10 @@ package org.openrs2.protocol.login import org.openrs2.protocol.EmptyPacketCodec +import javax.inject.Singleton -public object InitCrossDomainConnectionCodec : EmptyPacketCodec( +@Singleton +public class InitCrossDomainConnectionCodec : EmptyPacketCodec( opcode = 'G'.code, packet = LoginRequest.InitCrossDomainConnection ) diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitGameConnectionCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitGameConnectionCodec.kt index 2650ebcb..3021a953 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitGameConnectionCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitGameConnectionCodec.kt @@ -3,8 +3,10 @@ package org.openrs2.protocol.login import io.netty.buffer.ByteBuf import org.openrs2.crypto.StreamCipher import org.openrs2.protocol.PacketCodec +import javax.inject.Singleton -public object InitGameConnectionCodec : PacketCodec( +@Singleton +public class InitGameConnectionCodec : PacketCodec( opcode = 14, length = 1, type = LoginRequest.InitGameConnection::class.java diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJaggrabConnectionCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJaggrabConnectionCodec.kt index a8346f38..58d03a94 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJaggrabConnectionCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJaggrabConnectionCodec.kt @@ -1,8 +1,10 @@ package org.openrs2.protocol.login import org.openrs2.protocol.EmptyPacketCodec +import javax.inject.Singleton -public object InitJaggrabConnectionCodec : EmptyPacketCodec( +@Singleton +public class InitJaggrabConnectionCodec : EmptyPacketCodec( packet = LoginRequest.InitJaggrabConnection, opcode = 17 ) diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJs5RemoteConnectionCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJs5RemoteConnectionCodec.kt index 9402141c..31ced1da 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJs5RemoteConnectionCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/InitJs5RemoteConnectionCodec.kt @@ -3,8 +3,10 @@ package org.openrs2.protocol.login import io.netty.buffer.ByteBuf import org.openrs2.crypto.StreamCipher import org.openrs2.protocol.PacketCodec +import javax.inject.Singleton -public object InitJs5RemoteConnectionCodec : PacketCodec( +@Singleton +public class InitJs5RemoteConnectionCodec : PacketCodec( type = LoginRequest.InitJs5RemoteConnection::class.java, opcode = 15, length = 4 diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/IpLimitCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/IpLimitCodec.kt index 686c003a..abcc584c 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/IpLimitCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/IpLimitCodec.kt @@ -1,8 +1,10 @@ package org.openrs2.protocol.login import org.openrs2.protocol.EmptyPacketCodec +import javax.inject.Singleton -public object IpLimitCodec : EmptyPacketCodec( +@Singleton +public class IpLimitCodec : EmptyPacketCodec( packet = LoginResponse.IpLimit, opcode = 9 ) diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/Js5OkCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/Js5OkCodec.kt index 3cfa4f43..254752b4 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/Js5OkCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/Js5OkCodec.kt @@ -1,8 +1,10 @@ package org.openrs2.protocol.login import org.openrs2.protocol.EmptyPacketCodec +import javax.inject.Singleton -public object Js5OkCodec : EmptyPacketCodec( +@Singleton +public class Js5OkCodec : EmptyPacketCodec( packet = LoginResponse.Js5Ok, opcode = 0 ) diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/LoginDownstream.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/LoginDownstream.kt new file mode 100644 index 00000000..e9ba385a --- /dev/null +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/LoginDownstream.kt @@ -0,0 +1,8 @@ +package org.openrs2.protocol.login + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION) +public annotation class LoginDownstream diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/LoginUpstream.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/LoginUpstream.kt new file mode 100644 index 00000000..6089e8b3 --- /dev/null +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/LoginUpstream.kt @@ -0,0 +1,8 @@ +package org.openrs2.protocol.login + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION) +public annotation class LoginUpstream diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/RequestWorldListCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/RequestWorldListCodec.kt index 1d6fd3c9..aab88c2e 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/RequestWorldListCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/RequestWorldListCodec.kt @@ -3,8 +3,10 @@ package org.openrs2.protocol.login import io.netty.buffer.ByteBuf import org.openrs2.crypto.StreamCipher import org.openrs2.protocol.PacketCodec +import javax.inject.Singleton -public object RequestWorldListCodec : PacketCodec( +@Singleton +public class RequestWorldListCodec : PacketCodec( type = LoginRequest.RequestWorldList::class.java, opcode = 23, length = 4 diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/ServerFullCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/ServerFullCodec.kt index 1bc4a1ab..483b7ba8 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/ServerFullCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/ServerFullCodec.kt @@ -1,8 +1,10 @@ package org.openrs2.protocol.login import org.openrs2.protocol.EmptyPacketCodec +import javax.inject.Singleton -public object ServerFullCodec : EmptyPacketCodec( +@Singleton +public class ServerFullCodec : EmptyPacketCodec( packet = LoginResponse.ServerFull, opcode = 7 ) diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/world/WorldListDownstream.kt b/protocol/src/main/kotlin/org/openrs2/protocol/world/WorldListDownstream.kt new file mode 100644 index 00000000..b092d627 --- /dev/null +++ b/protocol/src/main/kotlin/org/openrs2/protocol/world/WorldListDownstream.kt @@ -0,0 +1,8 @@ +package org.openrs2.protocol.world + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION) +public annotation class WorldListDownstream diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/world/WorldListResponseCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/world/WorldListResponseCodec.kt index ac3f26a7..edd96999 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/world/WorldListResponseCodec.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/world/WorldListResponseCodec.kt @@ -8,19 +8,14 @@ import org.openrs2.buffer.writeVersionedString import org.openrs2.crypto.StreamCipher import org.openrs2.protocol.PacketCodec import org.openrs2.protocol.PacketLength +import javax.inject.Singleton -public object WorldListResponseCodec : PacketCodec( +@Singleton +public class WorldListResponseCodec : PacketCodec( type = WorldListResponse::class.java, opcode = 0, length = PacketLength.VARIABLE_SHORT ) { - private const val VERSION = 1 - - private const val FLAG_MEMBERS_ONLY = 0x1 - private const val FLAG_QUICK_CHAT = 0x2 - private const val FLAG_PVP = 0x4 - private const val FLAG_LOOT_SHARE = 0x8 - override fun decode(input: ByteBuf, cipher: StreamCipher): WorldListResponse { val version = input.readUnsignedByte().toInt() require(version == VERSION) { @@ -134,4 +129,13 @@ public object WorldListResponseCodec : PacketCodec( output.writeShort(count) } } + + private companion object { + private const val VERSION = 1 + + private const val FLAG_MEMBERS_ONLY = 0x1 + private const val FLAG_QUICK_CHAT = 0x2 + private const val FLAG_PVP = 0x4 + private const val FLAG_LOOT_SHARE = 0x8 + } }