Thread: Unnamed C# server development thread

Page 4 of 6 FirstFirst ... 23456 LastLast
Results 31 to 40 of 55
  1. #31  
    Respected Member


    Kris's Avatar
    Join Date
    Jun 2016
    Age
    26
    Posts
    3,638
    Thanks given
    820
    Thanks received
    2,642
    Rep Power
    5000
    Quote Originally Posted by testicles View Post
    Yeah iterating the entire world object list isn't very practical, but for now it's faster than what was there and some bugs are fixed so I'm happy with it for now. I've had a look around the forums for the whole server objects map thing but not sure I really understand how it works. Basically if the server I'm working on doesn't currently use it I don't know about it. Something else to add to the list of things to learn about



    It'd be a lot easier to implement that if this source had any semblance of storing all related information in the same place, but sadly it doesn't. It's not like it would be unreasonable to store a base time and then calculate actual time based on player count. Old logic was as follows:
    • Find object base on ID and location
    • Remove that object from the list and replace it with the empty object (calculated by ID)
    • Set an event to wait X seconds (again calculated by ID) and then respawn it
    • Remove the depleted object from the list
    • Re-add original object to list


    The entire thing being such a clusterfuck right now would have meant a complete rewrite of the world object manager which is too closely tied to many other classes such as skills and therefore would also have required a rewrite (ad infinitum, at least until I've rewritten the whole thing from scratch). Having this separation of responsibility is an improvement in the long run IMO and will make it easier to make further changes down the line.

    Take the ThievingData class as it is right now for example.
    Code:
    protected static int[][] NPCS = {
    	new int[] {1, 2, 3, 7875, 7877, 7879}, // Men.
    	new int[] {4, 5, 6, 7881, 7883}, // Women.
    	new int[] {7}, // Farmer.
    	new int[] {1715}, // Female HAM members.
    	new int[] {1716}, // Male HAM members.
    	new int[] {15}, // Warrior
    	new int[] {187}, // Rogue
    	//Cave goblin here (no need for them in an RSPS..)
    	new int[] {2234}, // Master farmer.
    	new int[] {9, 32, 296, 297, 298, 299}, // Guard.
    	//'Fremmenik' here
    	new int[] {6174, 1880}, // Bandit guard.
    	new int[] {1926, 1931}, // Desert bandits.
    	new int[] {23, 26}, // Knights
    	new int[] {34}, // Watchman
    	//Menaphite thug here.
    	new int[] {20}, // Paladin
    	new int[] {66, 67, 68}, // Gnomes.
    	new int[] {21}, // Hero.
    	new int[] {2363, 2364, 2365, 2366, 2367}, // Elf
    };
    
    protected static int[] NPC_LVL = {
    	1, // Men.
    	1, // Women.
    	10, // Farmer.
    	15, // Female HAM.
    	20, // Male HAM.
    	25, // Warrior.
    	32, // Rogue.
    	38, // Master farmer.
    	40, // Guard.
    	45, // Bandit guard.
    	53, // Desert bandits.
    	55, // Knights.
    	65, // Watchman.
    	70, // Paladin.
    	75, // Gnome.
    	80, // Hero.
    	85, // Elf.
    };
    
    protected static int[][] NPC_REWARD = {
    	new int[] {995}, // Men.
    	new int[] {995}, // Women.
    	new int[] {995, 5318}, // Farmer
    	new int[] {4298, 4300, 4302, 4304, 4306, 4308, 4310, 1511, 688, 689, 687, 686, 1605, 314, 946, 995, 1267, 371, 199, 453, 444, 201, 203, 205, 175, 884, 2138, 385}, // Female H.A.M TODO - lvl 1 clue
    	new int[] {4298, 4300, 4302, 4304, 4306, 4308, 4310, 1511, 688, 689, 687, 686, 1605, 314, 946, 995, 1267, 371, 199, 453, 444, 201, 203, 205, 175, 884, 2138, 385}, // Male H.A.M TODO - lvl 1 clue
    	new int[] {995}, // Warrior
    	new int[] {995, 1523, 954, 554, 555, 556, 175}, // Rogue
    	new int[] {5318, 5319, 5320, 5321, 5322, 5323, 5324, 5305, 5306, 5307, 5308, 5309, 5310, 5311, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 5104, 5105, 5106}, // Master farmer.
    	new int[] {995}, // Guard
    	new int[] {995, 175, 1523, 1823}, // Bandit guard
    	new int[] {995, 175, 1523, 1823}, // Bandits
    	new int[] {995}, // Knight
    	new int[] {995, 2309}, // Watchman
    	new int[] {995, 562}, // Paladin
    	new int[] {995, 2357, 561}, // Gnome
    	new int[] {995}, // Hero
    	new int[] {995}, // Elf
    };
    
    protected static int[][] NPC_REWARD_AMOUNT = {
    	new int[] {35}, // Men.
    	new int[] {35}, // Women.
    	new int[] {150, 1}, // Farmer
    	new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 6000, 1, 1, 1, 1, 1, 1, 1, 1, 1, 100, 1, 1}, // Female H.A.M
    	new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 6000, 1, 1, 1, 1, 1, 1, 1, 1, 1, 100, 1, 1}, // Male H.A.M
    	new int[] {300}, // Warrior
    	new int[] {500, 1, 1, 10, 10, 10, 1}, // Rogue
    	new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // Master farmer.
    	new int[] {500}, // Guard
    	new int[] {400, 1, 1, 1}, // Bandit guard
    	new int[] {340, 1, 1, 1}, // Bandit
    	new int[] {550, 1}, // Knight
    	new int[] {600, 1}, // Watchman
    	new int[] {750, 5}, // Paladin
    	new int[] {900, 1, 2}, // Gnome
    	new int[] {1100}, // Hero
    	new int[] {1500}, // Elf
    };
    
    protected static double[] NPC_XP = {
    	8, // Men & women.
    	8, // Women.
    	14.5, // Farmer.
    	18.5, // Female HAM.
    	22.5, // Male HAM.
    	26, // Warrior.
    	35.5, // Rogue.
    	43, // Master farmer.
    	46.8, // Guard.
    	65, // Bandit guard.
    	79.4, // Desert bandit.
    	84.3, // Knights.
    	137.5, // Watchman.
    	151.75, // Paladin.
    	198.5, // Gnome.
    	275, // Hero
        353 // Elf
    };
    All of this should be stored together in SomeClass which contains IDs of NPCs, XP they give and so on. But unfortunately it's all stored separately and iterated over in its entirety. When this comes to a point where related data is stored together (and I'll probably store it on disk as well, hardcoded values in memory are meh) it'll be a lot easier to remove unnecessary information.
    Oh my god that's disgusting lol; I understand that the source may be old and whatever but what I don't understand is why people preferred storing different type of information regarding the same object in different arrays, as opposed to having it all inside an enum. I mean enums were added in java 5 which was released in 2005.. so that's no excuse. Clueless tbh.
    The way I have this type of data is this:
    Code:
    MAN(1, 8, true, 5, 1, 1, new String[] { "What do you think you're doing?" }, new ImmutableItem[] { new ImmutableItem(995, 3) }, "Man", "Woman"),
    FARMER(10, 14.5, true, 5, 1, 1, new String[] { "Cor blimey mate, what are ye doing in me pockets?" }, new ImmutableItem[] { new ImmutableItem(995, 9), new ImmutableItem(5318, 1) }, "Farmer"),
    Note: The reason I've chosen "ImmutableItem" over just Item is because it's a special obj allowing me to store more variables (min, max, % chance etc) which is used in certain cases.
    Also don't ask why I've kept the messages as an array; I can't think of any npc that'd have more than one forced message on failure but I might be wrong and there may be some.. I wrote this though so yeah.
    Attached image
    Reply With Quote  
     

  2. #32  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Quote Originally Posted by Kris View Post
    Oh my god that's disgusting lol; I understand that the source may be old and whatever but what I don't understand is why people preferred storing different type of information regarding the same object in different arrays, as opposed to having it all inside an enum. I mean enums were added in java 5 which was released in 2005.. so that's no excuse. Clueless tbh.
    The way I have this type of data is this:
    Code:
    MAN(1, 8, true, 5, 1, 1, new String[] { "What do you think you're doing?" }, new ImmutableItem[] { new ImmutableItem(995, 3) }, "Man", "Woman"),
    FARMER(10, 14.5, true, 5, 1, 1, new String[] { "Cor blimey mate, what are ye doing in me pockets?" }, new ImmutableItem[] { new ImmutableItem(995, 9), new ImmutableItem(5318, 1) }, "Farmer"),
    Note: The reason I've chosen "ImmutableItem" over just Item is because it's a special obj allowing me to store more variables (min, max, % chance etc) which is used in certain cases.
    Also don't ask why I've kept the messages as an array; I can't think of any npc that'd have more than one forced message on failure but I might be wrong and there may be some.. I wrote this though so yeah.
    One of the things that I like very much about enums in Java is that they can essentially be turned in to instances of a class and still have a unique identifier that can be called from anywhere with access to it. In C# we don't have that sort of luxury, an enum can only really go as far as dictating finite state and is intended to be used like any other field or property.

    I've had a few attempts over the years at writing C# wrapper classes which then behave in the same fashion as Java enums, but it always seems too messy vs just using an instance of a class
    Reply With Quote  
     

  3. #33  
    Extreme Donator


    Join Date
    Jul 2009
    Age
    27
    Posts
    4,351
    Thanks given
    826
    Thanks received
    1,239
    Rep Power
    1781
    Quote Originally Posted by testicles View Post
    One of the things that I like very much about enums in Java is that they can essentially be turned in to instances of a class and still have a unique identifier that can be called from anywhere with access to it. In C# we don't have that sort of luxury, an enum can only really go as far as dictating finite state and is intended to be used like any other field or property.

    I've had a few attempts over the years at writing C# wrapper classes which then behave in the same fashion as Java enums, but it always seems too messy vs just using an instance of a class
    Regarding enums this is something I ran into when programming a C# server I did a few months back. One of the nice things you can do though is use attributes, which isn't too much of a pain in the ass.

    Edit: included an example of attributes

    Here's an example I had from my Zen project.

    Code:
    using System;
    
    namespace Zen.Builder
    {
        public enum DataType
        {
            [DataTypeAttr(1)] Byte,
            [DataTypeAttr(2)] Short,
            [DataTypeAttr(3)] TriByte,
            [DataTypeAttr(4)] Int,
            [DataTypeAttr(8)] Long
        }
    
        public class DataTypeAttr : Attribute
        {
            internal DataTypeAttr(int bytes)
            {
                Bytes = bytes;
            }
    
            public int Bytes { get; }
        }
    }
    And here's a small example of usage
    Code:
    public void TestAttr(DataType type) {
    	var attr = GetAttr(type);
    	if (attr == null) return;
    	
    	// .. do something with the attribute
    	var length = attr.Bytes;
    	
    }
    The GetAttr function would be as follows:
    Code:
    	private static DataTypeAttr GetAttr(DataType t) => (DataTypeAttr) Attribute.GetCustomAttribute(ForValue(t), typeof(DataTypeAttr));
    Then the ForValue would be
    Code:
    	private static MemberInfo ForValue(DataType t) => typeof(DataType).GetField(Enum.GetName(typeof(DataType), t));

    You can find my GitHub here, for what I'm currently working on.
    Reply With Quote  
     

  4. #34  
    Registered Member
    Spyr0's Avatar
    Join Date
    Oct 2012
    Age
    31
    Posts
    2,043
    Thanks given
    404
    Thanks received
    295
    Rep Power
    345
    Best of luck bro
    Reply With Quote  
     

  5. #35  
    Registered Member

    Join Date
    Dec 2009
    Posts
    774
    Thanks given
    367
    Thanks received
    455
    Rep Power
    927
    Quote Originally Posted by Kris View Post
    Oh my god that's disgusting lol; I understand that the source may be old and whatever but what I don't understand is why people preferred storing different type of information regarding the same object in different arrays, as opposed to having it all inside an enum. I mean enums were added in java 5 which was released in 2005.. so that's no excuse. Clueless tbh.
    The way I have this type of data is this:
    Code:
    MAN(1, 8, true, 5, 1, 1, new String[] { "What do you think you're doing?" }, new ImmutableItem[] { new ImmutableItem(995, 3) }, "Man", "Woman"),
    FARMER(10, 14.5, true, 5, 1, 1, new String[] { "Cor blimey mate, what are ye doing in me pockets?" }, new ImmutableItem[] { new ImmutableItem(995, 9), new ImmutableItem(5318, 1) }, "Farmer"),
    Note: The reason I've chosen "ImmutableItem" over just Item is because it's a special obj allowing me to store more variables (min, max, % chance etc) which is used in certain cases.
    Also don't ask why I've kept the messages as an array; I can't think of any npc that'd have more than one forced message on failure but I might be wrong and there may be some.. I wrote this though so yeah.
    Nah, putting all related information in one array would be too logical
    Reply With Quote  
     

  6. Thankful user:


  7. #36  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    In between finishing off bits of work, I've been rewriting chunks of code to increase testability. Today I've been working on introducing a Continuous Integration system called TeamCity (free, supports most environments and is fully customizable) to automate my build process and test every time a commit hits a new branch. I'm hosting it locally for the time being and it took about half an hour to set up.

    Attached image

    The red square indicates that the default branch (master) in its current state is failing builds because it has no tests and NUnit exits with a failure exit code.

    Here's an isolated build, which uses MSBuild, Nuget and NUnit command line to restore packages, build the project and run all tests from their related DLL files. I've written 5 basic domain object tests as an example for the lad I'm teaching. Once we've gone through these together, we'll focus on writing useful tests to ensure we don't break behaviour going forward.

    Code coverage is also automated using DotCover and coverage reports are uploaded with each build:

    Attached image

    Using some basic project settings I can set my default branch as well as include/filter whatever branches I want TeamCity to monitor. In this case, I just want everything monitored, so using the wildcard with +:refs/heads/* to monitor all branches.

    Attached image

    Current build steps are super simple. I've set up my test runner with wildcards to find any files matching the file name structure that I'll be using for all tests.

    Attached image

    I can also set my own failure conditions. Using the code coverage report, I'm going to label a build a failure if the coverage has dropped by more than 0.1%. With a project this large, that's a significant enough drop that it'll allow for rounding errors to be ignored, while still catching large coverave drops.

    Attached image

    I'll be moving this to an AWS box ASAP, so I can start chewing up those free credits that I never use
    Reply With Quote  
     

  8. #37  
    WVWVWVWVWVWVWVW

    _jordan's Avatar
    Join Date
    Nov 2012
    Posts
    3,046
    Thanks given
    111
    Thanks received
    1,848
    Rep Power
    5000
    Goodluck with the server.
    Attached image
    Attached image
    Reply With Quote  
     

  9. #38  
    Registered Member
    Spyr0's Avatar
    Join Date
    Oct 2012
    Age
    31
    Posts
    2,043
    Thanks given
    404
    Thanks received
    295
    Rep Power
    345
    Good luck with the project.
    Reply With Quote  
     

  10. #39  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    I should probably make more of an effort to post in here.
    Nothing super exciting to talk about, but I've finally had some time to get some infrastructure in place to help guide the breakdown of tasks and their ordering etc.

    I've set up a VM with Azure with my juicy free credits, moved my TeamCity builds to it and turned it in to a 24/7 build agent (as opposed to running it on my home PC which is only on some evenings after work).
    I've spent a couple hours running through all this and am currently trialling free software called SonarQube. SonarQube is an analysis tool capable of crawling through most projects and slapping the developer(s) on the wrist for their unprofessional programming habits. Since we began working with a shitty 530 source we found on Github, I ran it through SonarQube for shit and giggles (and kind of wish I hadn't).

    At any rate, we now have some metrics on just how shit the project is overall.

    Attached image

    SonarQube is surprisingly intelligent, not only does it spot syntax issues (as well as potential for syntactical sugar such as string interpolation) it's spotted a lot of bugs which would have resulted in a server crash, such as this:

    Attached image

    If a null player in that list is possible (and it certainly is, since everything in this project seems to be mutable) the server would crash.

    It spots a ton of redundancies, quite a few of which are in code that's called quite frequently.

    Attached image

    It's also incredibly handy for weeding out unnecessarily complicated methods.

    Attached image

    The time estimates are very helpful as well. They're very conservative in their estimate (often estimating 10 minutes work for 2 at most, 30 minutes when 5 is more realistic and so on) and mean I can log on to SonarQube, pick up some random bit of work and have done something useful even if I only have 5-10 minutes.

    Their graphs are a bit shit, but that's my only gripe with it so far. Maybe I'll get some more use out of them when we start getting further in to the project.
    Here's one plotting the number of lines of code vs how long SonarQube estimates it would take to fix all the bugs.

    Attached image
    Reply With Quote  
     

  11. Thankful user:


  12. #40  
    Donator

    Join Date
    Dec 2015
    Posts
    46
    Thanks given
    4
    Thanks received
    6
    Rep Power
    39
    Best of luck with this project!
    Reply With Quote  
     

Page 4 of 6 FirstFirst ... 23456 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. Unnamed Project Development Thread
    By Moronic in forum Projects
    Replies: 25
    Last Post: 01-18-2014, 01:54 AM
  2. Project #448 - Server Developers thread
    By Mainframe in forum Requests
    Replies: 0
    Last Post: 01-04-2013, 12:00 AM
  3. *************.uk ~ Server Status Page Development Thread
    By Diesel in forum Website Development
    Replies: 11
    Last Post: 11-11-2012, 07:57 PM
  4. Replies: 12
    Last Post: 08-28-2010, 02:44 AM
  5. Nexus Server Developement Thread
    By Nexus old in forum Projects
    Replies: 8
    Last Post: 09-22-2009, 03:35 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
  •