Thread: [#181] RS Mod - Let's Do This Together

Page 1 of 13 12311 ... LastLast
Results 1 to 10 of 128
  1. #1 [#181] RS Mod - Let's Do This Together 
    Renown Programmer

    Join Date
    Oct 2017
    Posts
    198
    Thanks given
    167
    Thanks received
    302
    Rep Power
    1567
    Attached image


    RS Mod has been open-sourced on GitHub:
    https://github.com/Tomm0017/rsmod


    • What is RS Mod?

    RS Mod is an OSRS framework made in Kotlin. The server started as a personal side-project, but then we had an idea of making it into more than just that. We will be providing a platform/community where both developers and server owners can benefit!


    • Why Kotlin instead of Java?

    Java is by far more popular in the RSPS scene, however Kotlin not only removes a lot of the boilerplate that comes with Java, but has a lot of other features which lack in native Java, including Coroutines, giving us the ability to suspend/"pause" code.


    • What is this platform you mentioned?

    The basic idea of the platform is similar to Minecraft's Bukkit. We'll have a marketplace that developers can sell plugins and server owners can purchase them. Some info can be found near the media section of this post.


    • Will I need to use this platform if I want to use the RS Mod server?

    Of course not! RS Mod will be available from our platform, but will also be publicly released on GitHub (the link will be posted here once I have had some feedback on it from others).


    • Can you show some examples of a plugin?

    Before I show the code, I do have to mention that plugins use KotlinScript, which may seem weird at first, but it does decrease the amount of code you would have to write to simply register a plugin.

    Searching bookcases:
    Spoiler for code:
    Code:
    package gg.rsmod.plugins.content.objs.bookcase
    
    import com.google.common.collect.ImmutableSet
    
    val BOOKCASES = ImmutableSet.of(Objs.BOOKCASE_380, Objs.BOOKCASE_381)
    
    BOOKCASES.forEach { case ->
       on_obj_option(obj = case, option = "search") {
           player.queue { // Use ``queue`` to allow the call to a ``suspend`` function
               search(this, player)
           }
       }
    }
    
    suspend fun search(it: QueueTask, p: Player) {
        p.lock()
        p.message("You search the books...")
        it.wait(3)
        p.unlock()
        p.message("You don't find anything that you'd ever want to read.")
    }


    Speaking to Abbot Langley in Edgeville Monastery
    Spoiler for code:
    Code:
    package gg.rsmod.plugins.content.areas.edgeville.chat
    
    on_npc_option(npc = Npcs.ABBOT_LANGLEY, option = "talk-to") {
         player.queue {  // Use ``queue`` to allow the call to a ``suspend`` function
           dialog(this) 
        }
    }
    
    suspend fun dialog(it: QueueTask) {
        it.chatNpc("Greetings traveller.", animation = 588)
        when (it.options("Can you heal me? I'm injured.", "Isn't this place built a bit out of the way?")) {
            1 -> {
                it.chatPlayer("Can you heal me? I'm injured.", animation = 554)
                it.chatNpc("Ok.", animation = 588)
                heal(it.player)
                it.messageBox("Abbot Langley places his hands on your head. You feel a little better.")
            }
            2 -> {
                it.chatPlayer("Isn't this place built a bit out of the way?", animation = 554)
                it.chatNpc("We like it that way actually! We get disturbed less. We<br>still get rather a large amount of travellers looking for<br>sanctuary and healing here as it is!", animation = 590)
            }
        }
    }
    
    fun heal(p: Player) {
        if (p.getSkills().getCurrentLevel(Skills.HITPOINTS) < p.getSkills().getMaxLevel(Skills.HITPOINTS)) {
            p.getSkills().setCurrentLevel(Skills.HITPOINTS, p.getSkills().getMaxLevel(Skills.HITPOINTS))
        }
    }



    • Media

    Since RS Mod tries its best to completely decouple content from one another, we're able to completely remove most content without affecting any other content! This of course has its limitations since some content directly communicate with one another, such as combat needing to get prayer information from the player. If you simply want a blank source with no content, you can easily remove all the content and not have to worry about any of the core features such as walking, logging in, etc!

    Spoiler for GIF (1-minute long):
    Attached image


    I will be providing basic content including all content inside a single city (Edgeville) and 6-8 basic skills on the basic server, here are some features that are working:

    Spoiler for Media:

    Attached image

    Attached image

    Attached image


    Attached image

    Attached image

    Attached image

    Attached image

    Attached image

    Attached image
    Attached image


    Spoiler for Platform Teasers:

    Attached image


    • Other "interesting" features


    Packet structures
    Since packet structures change every revision for OSRS, I implemented a way to load the structures externally so that developers have the convenience of changing structures in just one file instead of 20-40 different files.
    An example of a packet structure is as followed; note: it's currently being loaded using yml simply because I had the game configs loaded through yml and wanted to keep it constistent, but I do want to change the file format. Been suggested to use dsl, but still thinking about the final decision

    Code:
    - message: gg.rsmod.game.message.impl.LocAddChangeMessage
      type: FIXED
      opcode: 6
      structure:
        - name: tile
          type: BYTE
          trans: ADD
        - name: settings
          type: BYTE
          trans: SUBTRACT
        - name: id
          type: SHORT
          trans: ADD
    The values are read from top to bottom in the structure so in this example "tile" is read first as a Byte with a transformation of "ADD" (readByteA)

    Coroutines in content
    Thanks to Kotlin's Coroutines, we are able to completely remove the concept of (what is known commonly in RSPS as) "Tasks" or "Events". We can pause code for as many ticks as we would like as long as we mark the code as "suspendable". I did show an example above for bookcases and for dialogs, but we will post another example:

    Code:
    package gg.rsmod.plugins.content
    
    on_login {
        player.queue { // We use the queue method so that we can use suspend methods such as ``wait``
            player.message("Waiting to send an important message...")
            wait(2) // Wait 2 game cycles (1200 ms)
            player.message("Welcome to our server.")
            wait(1) // Wait 1 game cycle (600 ms)
            player.message("Remember to have fun!")
        }
    }
    Attribute System
    We have a unique attribute system that provides type-safety & persistence (if required). Not only that, but they can be defined in a plugin itself and do not need to be defined explicitly in the game module. For example:

    Code:
    package gg.rsmod.plugins.content
    
    val AN_ATTRIBUTE = AttributeKey<Int>() // Attribute will reset on logout
    val A_PERSISTENT_ATTRIBUTE = AttributeKey<Boolean>("unique_attribute_name") // Attribute will save on logout
    
    on_command("set_attribute") {
        player.attr.put(AN_ATTRIBUTE, 1)
        player.attr.put(A_PERSISTENT_ATTRIBUTE, true)
    }
    
    on_command("get_attribute") {
        val attribValue = player.attr.get(AN_ATTRIBUTE)
        val persistentAttribValue = player.attr.get(A_PERSISTENT_ATTRIBUTE)
    
        player.message("Attribute value: $attribValue")
        player.message("Persistent value: $persistentAttribValue")
    }

    Timer System
    The timers system allows us to assign a timer to an entity, which will then invoke the respective timer plugin (if one is found) once the timer hits a time value of 0. Each time value is equal to a single game cycle (600 ms). Similar to the Attribute System, timers are defined in the plugin itself. For example:

    Code:
    package gg.rsmod.plugins.content
    
    val A_TIMER = TimerKey()
    
    on_login {
        player.timers.put(A_TIMER, 1) // We need to start the timer with a time value of 1
    }
    
    on_timer(A_TIMER) {
        player.message("Timer has hit a time of 0!")
    }
    Acknowledgements
    Spoiler for Credits:

    • Graham Edgecombe
      • Project setup based off Apollo
      • Using StatefulFrameDecoder, AccessMode, DataConstants, DataOrder, DataTransformation, DataType, GamePacket & GamePacketBuilder from Apollo


    • Major
      • Using Collision Detection from Apollo
      • Basic idea behind the Region system (known as Chunk on RS Mod)


    • Polar


    • Kris
      • Always willing to lend a hand and share some code


    • Bart and Scu11
      • Helped me solve an issue with setting up KotlinScript


    • Ryley
      • Suggested the usage of KotlinScript


    • Bart (from the original OSS team)
      • The naming of certain features such as TimerSystem, AttributeSystem and Services
      • The idea behind the TimerSystem
      • The basic idea behind user-friendly plugin binding




    Join our brand new discord by clicking the icon below

    Attached image
    Reply With Quote  
     


  2. #2  
    2021
    SoulSplit's Avatar
    Join Date
    Nov 2011
    Posts
    830
    Thanks given
    620
    Thanks received
    654
    Rep Power
    528
    Good luck
    Reply With Quote  
     

  3. Thankful user:


  4. #3  
    Registered Member
    Join Date
    Apr 2016
    Posts
    26
    Thanks given
    6
    Thanks received
    15
    Rep Power
    71
    Looks impressive, good luck.
    Reply With Quote  
     

  5. Thankful user:


  6. #4  
    Renown Programmer

    Join Date
    Oct 2017
    Posts
    198
    Thanks given
    167
    Thanks received
    302
    Rep Power
    1567
    Quote Originally Posted by Private Byte View Post
    Looks impressive, good luck.
    Quote Originally Posted by Technotik View Post
    Good luck
    Cheers
    Reply With Quote  
     

  7. #5  
    Registered Member Snijder's Avatar
    Join Date
    May 2014
    Posts
    167
    Thanks given
    18
    Thanks received
    58
    Rep Power
    27
    Damn, that's cool! Good luck!
    Reply With Quote  
     

  8. #6  
    Blurite

    Corey's Avatar
    Join Date
    Feb 2012
    Age
    26
    Posts
    1,491
    Thanks given
    1,245
    Thanks received
    1,729
    Rep Power
    5000
    Good stuff Tom, looking forward to see what this can become and if it's worth contributing towards.

    As for packet format, using a DSL or something like a protobuf schema could be potential solutions.
    Attached image
    Reply With Quote  
     

  9. #7  
    Registered Member
    Brainpower's Avatar
    Join Date
    Jan 2019
    Posts
    130
    Thanks given
    13
    Thanks received
    13
    Rep Power
    101
    Looks interesting, good luck
    Reply With Quote  
     

  10. #8  
    Registered Member

    Join Date
    Feb 2013
    Posts
    1,682
    Thanks given
    401
    Thanks received
    402
    Rep Power
    446
    The concept is really interesting. Following to see the future progress.

    Good luck.
    Reply With Quote  
     

  11. #9  
    Registered Member

    Join Date
    Oct 2011
    Posts
    2,084
    Thanks given
    0
    Thanks received
    1,043
    Rep Power
    3608
    look great, good luck.
    Reply With Quote  
     

  12. #10  
    Extreme Donator


    Join Date
    Nov 2011
    Posts
    311
    Thanks given
    15
    Thanks received
    94
    Rep Power
    361
    Oh i can make plugins and get rich then.
    Reply With Quote  
     

  13. Thankful user:


Page 1 of 13 12311 ... LastLast

Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. Would you let your girl do this?
    By Rukin1 in forum Videos
    Replies: 3
    Last Post: 02-20-2012, 04:20 AM
  2. Why/How does RS do this?
    By relex lawl in forum Help
    Replies: 3
    Last Post: 01-19-2012, 06:32 PM
  3. Replies: 1
    Last Post: 01-06-2012, 05:08 PM
  4. Replies: 12
    Last Post: 12-26-2009, 11:28 AM
  5. how can i do this?
    By Joe in forum General
    Replies: 2
    Last Post: 12-30-2007, 02:11 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •