OSRS emulator written in kotlin


Revision 211 OSRS server written in Kotlin.



Project structure

The server is broken up into multiple modules to make things easier to manage and test individual components.

  • application (This is used to bootstrap and launch the server. This ties all the modules together using guice)
  • game-server (This is used to hold all of the core game related code and submodules.)
  • http-server (This is used to setup an HTTP server to serve the OSRS client the static files. For example: jav_config.ws and latest gamepack.jar)

Getting Started

Client setup

  • Download the OpenOSRS client from our runetopic organization. This branch is configured to connect to the server automatically.

MongoDB Setup (Optional if local flag in ApplicationConfig is enabled)

  • This project has support for mongoDB for account creation and verification as well as local disk storage.
  • If you’re working on local development, and need to work offline, you may set the game.local flag to true in the application.conf
  • Please setup either a cloud instance, or a local instance. I will be providing this via docker in the future, but this is a manual process for now.
  • Create a database called api and a collection called account if they do not get created automatically.
  • Upon start of the server, an admin account will be created for you:
    • Credentials: (Username=admin, password=password)

Application configuration

This project uses ktor for the networking, therefore the application is powered via the application.conf file.

  • Create a new file called application.conf inside of the resources directory.
  • Place the following contents inside of the application.conf:ktor { development = true deployment { port = 43594 watch = [ classes, resources ] } } game { local = true benchmarking = false cores = 4 build { major = 211 minor = 1 token = "ElZAIrq5NpKN6D3mDdihco3oPeYN2KFy2DCquj7JMmECPmLrDP3Bnw" } packet { sizes = [ 11,-2,14,13,10,7,15,-1,7,6,5,9,-1,8,11,16,7,15,-1,3,3,3,-1,8,8,8,0,8,-1,8,4,-1,8,7,3,11,7,-1,3,3,-1,3,-1,-1,3,15,8,3,8,2,-1,8,-2,7,8,3,8,8,6,7,2,4,9,-1,8,4,-1,8,-2,8,7,-1,7,3,-1,0,7,0,-1,2,4,8,0,11,16,6,8,3,1,7,3,8,-1,0,-1,-1,-1,8,-1,2,3,-1,4,-1,2,15,16,22 ] } cache { path = "./data/cache/" parallel = true } configuration { players = "./players/" ui = "/ui/interface_info.yaml" xteas = "/map/xteas211.json" } rsa { exponent = "c1d3827d26f642394175bc3c67ed5edc848f2654b28977678b911008d30988f4a6425e0af3cf8dc27d6d4c986726f9a99308d5ad21cdd72e07782bdd82fddc74fab02d5650848b8867b72728a42eec96f85f1682e515cc0881932d80dc9d4e2664e3d4983b295b2cd8cd62871db459178d194c6ada9e4faf9ac49af0cb28a89" modulus = "9081ec4aacbe0be1718d5dcdf7bbfd3ba738b15b4ed5e7e9a4769f0fda07e8e2094b08553ae1b78c794a1e064d29613f80495e303fbaa4f056f77b8b162a96616b2ca50dcd1a76bee4ba9fb67c4b7cd463da1f8c610f9a2e108efd5a571a958c78c4e4a5bfb40ee9bd2d99ae56f7ba18574b5a71d037ad538aee992bbee56375" } } mongo { connection = "mongodb://username:password@ip:port" }
  • The mongo configuration is optional as well as the player’s directory configuration if the local flag is true
  • Update the connection string for mongo using the following format: mongodb://username:password@ip:portThis is also recommend injecting from an environment variable – checkout Ktor Environment Variables for more information

Server configuration (Required upon intial setup and revision upgrades)

  • Download the supported revision cache (.dat2 format) and map keys (.json format) from OpenRS2.
  • Place the cache files you downloaded into the ./data/cache/ directory. This directory is configurable from within the application.conf
  • Place the map keys you downloaded into the ./application/resources/map/ directory. xteas210.json is an example of how the file should be named.
  • Download the revision gamepack.jar from Runestats and place this in the ./application/resources/client_config/ directory. gamepack.jar is an example of how the file should be named.
  • You’ll also need to update the jav_config file if you update the build to a more recent one that’s included on this repo. To do this, grab the config from Runestats that you downloaded already, and update the params that are included in the one you downloaded. They will look like this for example:param=2=https://payments.jagex.com/ param=3=true param=4=1 param=5=1 param=6=0 param=7=0 param=8=true param=9=ElZAIrq5NpKN6D3mDdihco3oPeYN2KFy2DCquj7JMmECPmLrDP3Bnw param=10=5 param=11=https://auth.jagex.com/ param=12=337 param=13=.runescape.com param=14=0 param=15=0 param=16=false param=17=http://www.runescape.com/g=oldscape/slr.ws?order=LPWM param=18= param=19=196515767263-1oo20deqm6edn7ujlihl6rpadk9drhva.apps.googleusercontent.com param=20=https://social.auth.jagex.com/ param=21=0 param=25=210 param=28=https://account.jagex.com/
  • Run the application!




  • Clear out the previously tracked zones and zone buffer.
  • Collect a set of all the observed zones for each tick
  • Iterate through the observed zones and build out all of the updates.
  • Iterate through all of the players in the observed zones and write the updates.
  • Clear out the zone of any pending updates

Shared Updates:

  • Shared updates are for updates visible to everyone in the observed zones
  • This means we can generate the updates to send to each player every tick instead of having to build this out for each player.
  • Shared updates are always sent using enclosed packet and consist of:
    • ObjDelPacket
    • MapProjAnimPacket
    • LocAddPacket
    • LocDelPacket

Private Updates:

  • Private updates are used for things private to the player. These are things only the current observing player may see this tick.
  • Private updates are sent using the partial follows packet and consist of:
    • ObjUpdatePacket
    • ObjAddPacket
      • The way this works is they have an item collection that is serialized to the player. (This is used for instanced items, grave items, or when hopping worlds)
      • Each zone can hold up to 129 of the same item, and if another item is added, it replaces the least valuable item with the new one.
    • ObjDelPacket
      • This is used for picking up private items that only the player can see.


Client Packets Implemented:

  • Idle
  • IfButton
  • MoveGame
  • MoveMiniMap
  • NoTimeout
  • WindowStatus

Server Packets Implemented:

  • CameraReset
  • HintArrow
  • IfOpenSub
  • IfOpenTop
  • MessageGame
  • MidiSong
  • ObjAdd
  • PlayerInfo
  • RebuildNormal
  • RunClientScript
  • SetPlayerOption
  • UpdateContainerFull
  • UpdateRunEnergy
  • UpdateStat
  • UpdateZoneFullFollows
  • UpdateZonePartialEnclosed
  • UpdateZonePartialFollows
  • VarpLarge
  • VarpSmall



If you need help, have any questions, or just wanna chat, feel free to join our discord!


View Github

Leave a Reply

Your email address will not be published. Required fields are marked *