Hey there, I just started with a new project, called Horizon.
My goal is to write a fullstack Habbo Emulation (including Gameserver and Webserver / CMS) based on the Java Virtual Machine.
I just started with the Gameserver, which is in really early developement stage.
About the Gameserver:
- Written in Kotlin
- Using Spring Boot (Command Line Runner) as "Lifecycle"
- Using Spring Boot Data JPA as ORM
- Using Netty for Network Communication*
- Component based architechture (made possible by the awesome Spring Dependency Injection Framework)
- Targeting PRODUCTION-201611291003-338511768
It's a kind of experiment, to use the Spring Framework for an application like this.
* = I'm really new into TCP/IP communication, wherefore I mostly copied network architecture from other emulators (for yet, I will definitely refactor it to the component based approach).
Some code snippets:
HorizonGameserverApplication.kt (Main):
TcpServer.ktCode:package com.habbo.horizon.gameserver import com.habbo.horizon.gameserver.console.ConsoleHandler import org.springframework.boot.CommandLineRunner import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan import org.springframework.boot.runApplication @springBootApplication @ConfigurationPropertiesScan("com.habbo.horizon.gameserver") class HorizonGameserverApplication(val consoleHandler: ConsoleHandler) : CommandLineRunner { override fun run(vararg args: String?) { this.consoleHandler.start() } } fun main(args: Array<String>) { runApplication<HorizonGameserverApplication>(*args) }
ClientVariablesEvent.ktCode:package com.habbo.horizon.gameserver.network import com.habbo.horizon.gameserver.network.config.NetworkConfig import com.habbo.horizon.gameserver.network.handler.TcpServerInitializer import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.UnpooledByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.FixedRecvByteBufAllocator import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.socket.nio.NioServerSocketChannel import io.netty.handler.logging.LogLevel import io.netty.handler.logging.LoggingHandler import org.springframework.stereotype.Component @CoMponent class TcpServer( private val networkConfig: NetworkConfig, private val tcpServerInitializer: TcpServerInitializer ) { private val bossGroup = NioEventLoopGroup() private val workerGroup = NioEventLoopGroup() init { this.start() } fun start() { val server = ServerBootstrap() val tcpServerStatus = server .group(this.bossGroup, this.workerGroup) .channel(NioServerSocketChannel::class.java) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.SO_REUSEADDR, true) .childOption(ChannelOption.SO_RCVBUF, 5120) .childOption(ChannelOption.RCVBUF_ALLOCATOR, FixedRecvByteBufAllocator(5120)) .childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator(false)) .handler(LoggingHandler(LogLevel.INFO)) .childHandler(this.tcpServerInitializer) .bind(this.networkConfig.gamePort) .sync() if (!tcpServerStatus.isSuccess) { // TODO: Handle TCPServer Startup Failure } } fun shutdown() { this.bossGroup.shutdownGracefully() this.workerGroup.shutdownGracefully() } }
IncomingHandshakePacketHeaderConfig.ktCode:package com.habbo.horizon.gameserver.network.messages.incoming.handshake import com.habbo.horizon.gameserver.network.config.IncomingHandshakePacketHeaderConfig import com.habbo.horizon.gameserver.network.messages.ClientMessageEvent import com.habbo.horizon.gameserver.network.messages.NettyRequest import org.springframework.stereotype.Component @CoMponent class ClientVariablesEvent( private val incomingHandshakePacketHeaderConfig: IncomingHandshakePacketHeaderConfig ) : ClientMessageEvent { override val headerID: Short get() = this.incomingHandshakePacketHeaderConfig.clientVariables override fun read(message: NettyRequest) { val unknownInt = message.readInt() val swfsUrl = message.readString() val gamedataVariablesUrl = message.readString() // TODO("Check correct swfs & gamedata variables URL") } }
application.yml (Config) (Packet header will be outsourced, to external "incoming-packets.yml")Code:package com.habbo.horizon.gameserver.network.config import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.ConstructorBinding @constructorBinding @ConfigurationProperties(prefix = "horizon.network.incoming-packets.handshake") data class IncomingHandshakePacketHeaderConfig( val clientVariables: Short, val machineID: Short, val releaseVersion: Short, val secureLogin: Short )
I will upload the source code, once I'm satisfied with the base architecture from the emulator.Code:horizon: network: game-port: 30000 incoming-packets: handshake: clientVariables: 1053 machineId: 2490 releaseVersion: 4000 secureLogin: 2419 outgoing-packets: handshake: machineId: 1488 secureLogin: 2491
I will start to work on a CMS, once I got a stable Gameserver.
Many thanks go out to:
- @The General for Arcturus, from which I looked up some Netty- and Message related stuff
- @Quackster for Kepler, from which I looked up some Netty architecture related stuff
- @billsonnn for Nitro, from which I looked up some ClientMessage related stuff and his pre-hosted SWF's which I'm currently using



Reply With Quote


