Thread: If Else/Switch Mega Blocks and Command Pattern

Page 1 of 7 123 ... LastLast
Results 1 to 10 of 63
  1. #1 If Else/Switch Mega Blocks and Command Pattern 
    Registered Member
    Join Date
    Jan 2015
    Posts
    195
    Thanks given
    137
    Thanks received
    28
    Rep Power
    27
    R-S Admin Response  Introduction
    I think every server source I've ever looked at has a 3k lines class with a huge switch or if else if code block on it, weather it's the commands class, the object or NPC handler classes, they all have one of these ugly ass mega code blocks and it bugs the shit out me. I wanna know what do you guys think and the reason behind this commonly used technique, what are the workarounds you guys have use, what other ways there are to handle a huge amount of content.


    R-S Admin Response  My Experience
    To share a little of my own experience, I'm currently working on a project over the Matrix3 source and the 3000 lines commands class simply annoyed me so much that deleted it entirely and made a new class with a different way of dealing with commands. Instead of having a huge class with the code for every command nested on a switch case case case case case statement, I used something called "Command pattern". I created one little class with 4 different Command hashmaps and distributed the commands code in 4 other classes depending on the nature of the command (player, moderator, administrator and debug command classes). Each with a method that is called on initialization which introduces the commands into the respective hashmap using lambda expressions.
    Example:

    Code:
    CommandHandler.addCommand("players", 0, (player, args) -> player.getPackets().sendGameMessage("There's currently " + World.getPlayers().size() + " players playing " + Settings.SERVER_NAME));

    Then when the user attempts to execute a command, the server simply searches for it on the corresponding hashmaps and executes it's code.

    One really nice advantage of this method is the generic "commands" command, if you use a switch/else if cascade you are going to have to hard-code a list of every command manually, while if you use hashmaps the "commands" command becomes really simply to code. On the other hand, this method might have a big disadvantage, efficiency. I don't really know weather HashMap.Get() is faster than switch statements or not, I've done some research but couldn't get a clear answer, but since there's rarely more than 100 commands used in a minute (depending on player base) I don't think performance is a big factor on this case, but it is on other stuff like NPC's, item clicks, etc. where the frequency of use is much bigger.

    The classes still get big with each command added, but they can be distributed in as many classes as wanted and can make small commands shrink down to a single line. Which all adds up to more maintainability and ease of reading


    R-S Admin Response  Conclusion
    So what do you guys think about the horribly looking switch and if else mega blocks? Do you think command pattern could be implemented to other classes like NPCHandler, ObjectHandler, etc. without losing performance?

    PS: If anyone is interested of implementing command patter on their server, just read this wiki article
    Spoiler for Careful seizure:
    penis
    Reply With Quote  
     

  2. Thankful users:


  3. #2  
    Registered Member
    Join Date
    May 2011
    Age
    29
    Posts
    2,246
    Thanks given
    2,469
    Thanks received
    1,120
    Rep Power
    943
    That's literally one of the first things I changed when I started using the matrix framework, I looked into commands.java and thought to myself, "yeah fuck that.. *deletes Commands.java*"

    Right now commands and stuff that used to go into 'ObjectHandler' etc are put into our plugin system. I haven't done any benchmarks on performance (probably should) but we have quite a few plugins and there is no visible performance difference when playing the game.

    Reply With Quote  
     

  4. Thankful user:


  5. #3  
    Registered Member
    Join Date
    Jan 2015
    Posts
    195
    Thanks given
    137
    Thanks received
    28
    Rep Power
    27
    Quote Originally Posted by Tylurr View Post
    That's literally one of the first things I changed when I started using the matrix framework, I looked into commands.java and thought to myself, "yeah fuck that.. *deletes Commands.java*"

    Right now commands and stuff that used to go into 'ObjectHandler' etc are put into our plugin system. I haven't done any benchmarks on performance (probably should) but we have quite a few plugins and there is no visible performance difference when playing the game.

    That plugin system looks really nice. I hate to have code for stuff that has nothing to do with each other all in the same class, like objects. I might implement something like what you guys did, but then I'd have to deal with re-adding all the item/objects that matrix already has >.<. Some code could be made to port it all over and save time tho
    Spoiler for Careful seizure:
    penis
    Reply With Quote  
     

  6. #4  
    rage against the dying of the light


    Join Date
    Sep 2016
    Posts
    293
    Thanks given
    103
    Thanks received
    92
    Rep Power
    197
    Quote Originally Posted by Tylurr View Post
    That's literally one of the first things I changed when I started using the matrix framework, I looked into commands.java and thought to myself, "yeah fuck that.. *deletes Commands.java*"

    Right now commands and stuff that used to go into 'ObjectHandler' etc are put into our plugin system. I haven't done any benchmarks on performance (probably should) but we have quite a few plugins and there is no visible performance difference when playing the game.

    Let me just say that I think your plugin system looks delicious. As you mentioned, I'm not sure about the efficiency of using a plugin system over switch or else/if statements, but I do remember reading a study that JavaScript (or probably inherently a scripting language of some sort) is a matter of milliseconds faster than hard-coded Java. I would, however, take that with a grain of salt, as I can't remember where that study came from lol. I would imagine that script would execute faster than traditional java, but I can't back that up with firsthand knowledge, so reh.

    I had a question tied to this post, but I figured asking it in your project thread would be more appropriate, seeing as other users might be interested in it as well. I'll be anxiously awaiting your answer!
    Last edited by Jintishi; 09-29-2016 at 04:11 AM. Reason: moved the question to the project thread
    Reply With Quote  
     

  7. #5  
    Registered Member

    Join Date
    Dec 2012
    Posts
    2,999
    Thanks given
    894
    Thanks received
    921
    Rep Power
    2555
    Quote Originally Posted by Terrowin View Post
    Let me just say that I think your plugin system looks delicious. As you mentioned, I'm not sure about the efficiency of using a plugin system over switch or else/if statements, but I do remember reading a study that JavaScript (or probably inherently a scripting language of some sort) is a matter of milliseconds faster than hard-coded Java. I would, however, take that with a grain of salt, as I can't remember where that study came from lol. I would imagine that script would execute faster than traditional java, but I can't back that up with firsthand knowledge, so reh.

    I had a question tied to this post, but I figured asking it in your project thread would be more appropriate, seeing as other users might be interested in it as well. I'll be anxiously awaiting your answer!
    Efficiency doesn't only have speed as a factor; maintenance is just as important. Having a huge block of conditional statements is clearly not very maintainable, and hence defining content in a modular fashion is better. Speed isn't an issue either, since the RS clock works on 0.6 seconds, we have a large gap to process whatever.

    Lookup is also probably o(1), and the only time where speed would matter is when it takes ridiculously long to obtain the interaction, such as when using reflection. So in short, the performance loss is negligible, and the usability of defining content separately is much better (prettier to look at, easier to maintain, easier to define in the first place, etc)
    Attached image
    Reply With Quote  
     

  8. Thankful users:


  9. #6  
    Contributor

    clem585's Avatar
    Join Date
    Sep 2013
    Posts
    3,788
    Thanks given
    706
    Thanks received
    702
    Rep Power
    570
    It's part of the things I plan on cleaning before I actually code more content. There's so many if else in the handlers, I feel like I'm gonna die of cancer everytime I go in there. At least I respect the creators for making up so much content.

    Tip for object/item interaction: There should probably be a constructor for both id and name. Sometimes it's easier to apply an action to all the items with the same name. To not reduce performances with something like this:

    Code:
    private boolean checkNameInteractions(String itemName) {
        for (ItemInteraction ii: nameItemInteractions) {
            if (itemName.contains(ii.getName()) {
                ii.execute();
                return true;
            }
        }
        return false;
    }
    You would probably have to convert these interactions:

    Code:
    private void hashNameInteractions() {
        for (ItemInteraction ii: nameItemInteractions) {
            for (int i = 0; i < Utils.getItemDefinitionsSize(); ++i) {
                ItemDefinitions defs = ItemDefinitions.getItemDefinitions(i);
                if (defs.getName().contains(ii.getName())) {
                    if (itemInteractions.get(i) == null) {
                         itemInteractions.put(i, ii);
                    } else {
                        System.out.println("Error: 2 item interactions overwriting each other for " +
                            item.getName() + "(" + ii.getName() +")");
                    }
                }
            }
        }
    }
    What do you guys think?
    Project thread
    Reply With Quote  
     

  10. #7  
    Registered Member

    Join Date
    Dec 2012
    Posts
    2,999
    Thanks given
    894
    Thanks received
    921
    Rep Power
    2555
    Quote Originally Posted by clem585 View Post
    It's part of the things I plan on cleaning before I actually code more content. There's so many if else in the handlers, I feel like I'm gonna die of cancer everytime I go in there. At least I respect the creators for making up so much content.

    Tip for object/item interaction: There should probably be a constructor for both id and name. Sometimes it's easier to apply an action to all the items with the same name. It might reduced performances though if it has to loop throught all the name-based interactions with:

    Code:

    Code:
    private boolean checkNameInteractions(String itemName) {
        for (ItemInteraction ii: nameItemInteractions) {
            if (itemName.contains(ii.getName()) {
                ii.execute();
                return true;
            }
        }
        return false;
    }
    You would probably have to convert these interactions:

    Code:
    private void hashNameInteractions() {
        for (ItemInteraction ii: nameItemInteractions) {
            for (int i = 0; i < Utils.getItemDefinitionsSize(); ++i) {
                ItemDefinitions defs = ItemDefinitions.getItemDefinitions(i);
                if (defs.getName().contains(ii.getName())) {
                    if (itemInteractions.get(i) == null) {
                         itemInteractions.put(i, ii);
                    } else {
                        System.out.println("Error: 2 item interactions overwriting each other for " +
                            item.getName() + "(" + ii.getName() +").");
                    }
                }
            }
        }
    }
    What do you guys think?
    Or you could just refer via ID's, there is literally no piece of content I can name that wouldn't work for it. Also there would be no severe performance change
    Attached image
    Reply With Quote  
     

  11. #8  
    Contributor

    clem585's Avatar
    Join Date
    Sep 2013
    Posts
    3,788
    Thanks given
    706
    Thanks received
    702
    Rep Power
    570
    Quote Originally Posted by Kaleem View Post
    Or you could just refer via ID's, there is literally no piece of content I can name that wouldn't work for it. Also there would be no severe performance change
    Well yea but with only an int, wouldn't you have to do something like this for multiple Ids?:

    Code:
    itemInteractions.add(new Interaction(id1, new TimerTask
        @Override
        public void run() {
            //code1
            //code2
            //code3
        }
    ));
    
    itemInteractions.add(new Interaction(id2, new TimerTask
        @Override
        public void run() {
            //code1
            //code2
            //code3
        }
    ));
    Even this would be kind of meh, wouldn't it:

    Code:
    WorldTask useTeleport = new TimerTask
        @Override
        public void run() {
            //code1
            //code2
            //code3
        }
    );
    
    itemInteractions.add(new Interaction(id1, useTeleport));
    itemInteractions.add(new Interaction(id2, useTeleport));
    Project thread
    Reply With Quote  
     

  12. #9  
    Ex Rune-Scaper

    Join Date
    Jun 2008
    Posts
    3,534
    Thanks given
    457
    Thanks received
    1,257
    Rep Power
    990
    In industry 50+ lines of code in a single method is considered bad design.

    Plugins is a nice way to make your code extensible and allows for easy addition/deletion of content. That's why it's important to design a nice foundation to build your code on. Interfaces are also useful because they allow for multiple inheritance and can force your team to follow a design.
    Attached image
    Reply With Quote  
     

  13. Thankful user:


  14. #10  
    Registered Member

    Join Date
    Dec 2012
    Posts
    2,999
    Thanks given
    894
    Thanks received
    921
    Rep Power
    2555
    Quote Originally Posted by clem585 View Post
    Well yea but with only an int, wouldn't you have to do something like this for multiple Ids?:

    Code:
    itemInteractions.add(new Interaction(id1, new TimerTask
        @Override
        public void run() {
            //code1
            //code2
            //code3
        }
    ));
    
    itemInteractions.add(new Interaction(id2, new TimerTask
        @Override
        public void run() {
            //code1
            //code2
            //code3
        }
    ));
    Even this would be kind of meh, wouldn't it:

    Code:
    WorldTask useTeleport = new TimerTask
        @Override
        public void run() {
            //code1
            //code2
            //code3
        }
    );
    
    itemInteractions.add(new Interaction(id1, useTeleport));
    itemInteractions.add(new Interaction(id2, useTeleport));
    Code:
    int[] array = new int[] { ... };
    forEach(id -> itemInteractions.add(new Interaction(id, useTeleport));
    is fine
    Attached image
    Reply With Quote  
     

  15. Thankful users:


Page 1 of 7 123 ... 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. Replies: 6
    Last Post: 12-18-2013, 10:27 AM
  2. Replies: 2
    Last Post: 07-03-2013, 04:53 PM
  3. Little command (if else)
    By jareq in forum Help
    Replies: 15
    Last Post: 02-14-2009, 12:06 AM
  4. Replies: 20
    Last Post: 06-28-2008, 01:10 PM
  5. [VB6] if-else structure and select case
    By Chimeric in forum Website Development
    Replies: 0
    Last Post: 01-11-2008, 10:52 PM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •