Thread: Unnamed C# server development thread

Page 1 of 6 123 ... LastLast
Results 1 to 10 of 55
  1. #1 Unnamed C# server development thread 
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Don't expect anything new or exciting in here for some time, there's a lot of infrastructure work to get done before I start expanding this at all.

    I wanted a place to keep logs of what I'll be working on and since I've been learning a fair amount from snippets/sources posted on here I figured I'd actually post something for once.

    I've been working with C# professionally for ~2 years and programming as a hobby for around 10 years. Recently I've been tutoring a friend with his uni work and he asked if I knew anything about Runescape private servers. I have experience with server emulation, but nothing Runescape related so I found a couple of existing 530 C# projects and dove in. While there's a lot of bad programming habits in there, I've understood enough to get started.

    Since he needed to learn about everything from source control to good design, we'll be using a variety of tech to help with project management and teach him some useful skills.
    • Visual Studio 2017 for general bits and pieces
    • GitLab for hosting and Github Desktop Client for source control
    • Hack n Plan for organisation and time management, which is very similar to what I use in my day job.
    • Resharper for the occasional kick up the ass
    • NUnit for writing unit/integration tests
    • Possibly EntityFramework for database work, or I may go with vanilla sql, or may even roll my own library, I haven't decided yet!



    It's pretty generic, it's missing a lot of data (stairs/ladders/doors/levers, music areas etc) and has a few bugs but it runs reliably and has a nice amount of features finished already.

    A lot of NPCs are missing, shops etc.
    Attached image

    Quest interfaces don't open, can't start quests etc. This is something I'm looking forward to working on.
    Achievement Diaries are the same of course, but in 530 they're a bit rubbish anyway.
    Attached image

    Although the server appears to support HD mode, the client is missing ...something. The download I've been using has a generic decompiled Java client, so there's no point trying to make sense of it as I have plans to ditch it in the future anyway.
    Attached image

    Roadmap as a way of tracking progress:
    Done:
    Lots of reading!

    In progress:
    Convert cache from XML to JSON, introduce JSON bindings and immutable objects for the cache.
    Separate out logic and information to conform to SOLID principle. - This is going to be a long process, as the code is messy and badly written from top to bottom.

    Future work:
    Write database solution. I didn't find many sources online that had database work done and those that do can be improved on.
    A good encryption solution for storing passwords, the amount of SHA1/SHA256/MD5 servers I see are insane. Currently this source saves passwords in plaintext, saving players as XML files
    Bug fixes in existing code.
    Investigate missing features and data.
    Write utilities for viewing, editing and saving information directly from the cache -> server's JSON format and vice versa.
    Ditch client and roll our own in Unity3D.
    Reply With Quote  
     

  2. Thankful users:


  3. #2  
    2021
    SoulSplit's Avatar
    Join Date
    Nov 2011
    Posts
    830
    Thanks given
    620
    Thanks received
    654
    Rep Power
    528
    Welcome to rune-server, sounds like a cool project
    Reply With Quote  
     

  4. #3  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Quote Originally Posted by Technotik View Post
    Welcome to rune-server, sounds like a cool project
    Thank you! Hopefully this will be a nice way of keeping me motivated.

    - Added some info on the websites and technology we'll be using to build the server.
    Reply With Quote  
     

  5. #4  
    Donator

    Join Date
    Dec 2013
    Posts
    491
    Thanks given
    569
    Thanks received
    123
    Rep Power
    55
    Looks really good! I'd love to see where this project can go.
    Reply With Quote  
     

  6. #5  
    Donator


    Join Date
    Jul 2011
    Posts
    570
    Thanks given
    135
    Thanks received
    142
    Rep Power
    291
    Good luck homie
    Reply With Quote  
     

  7. #6  
    Extreme Donator

    Kiana's Avatar
    Join Date
    May 2015
    Posts
    1,050
    Thanks given
    147
    Thanks received
    187
    Rep Power
    223
    Best of luck mate.
    Reply With Quote  
     

  8. #7  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Quote Originally Posted by Arseny View Post
    Having done my own little abstraction layer, I would say be careful if you take this route. It's really easy to do it poorly.

    If you're looking for a proper ORM, NHibernate is also not a bad option to add to the list.
    I appreciate the heads up
    My day job is closer to DevOps engineer than Software Engineer, so I have a lot of experience with SQL Server 2012 and up, MySQL etc. I'm hoping I have enough knowledge to avoid most of the obvious pot holes.

    Thanks for the words of encouragement everyone else. I'll be posting some resources about how I'm refactoring for performance and readability, hopefully people can learn from this project
    Reply With Quote  
     

  9. #8  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Well I promised to post some code snippets, so here we are. Focusing on improvements for data loading, here's an example of changes I've made going from XML to JSON.

    Before:
    Code:
    private void loadDoors()
    {
    	if (!File.Exists(Misc.getServerPath() + @"\data\doors.xml"))
    	{
    		Misc.WriteError(@"Missing data\doors.xml");
    		return;
    	}
    
    	try
    	{
    		StreamReader objStreamReader = new StreamReader(Misc.getServerPath() + @"\data\doors.xml");
    		XmlSerializer serializer = new XmlSerializer(typeof(List<Door>));
    		doors = (List<Door>)serializer.Deserialize(objStreamReader);
    	}
    	catch (Exception e)
    	{
    		Misc.WriteError((e.InnerException == null ? e.ToString() : e.InnerException.ToString()));
    	}
    
    	Console.WriteLine("Loaded " + doors.Count + " door configurations.");
    }
    After:
    Code:
    private void LoadDoors()
    {
        var doorPath = Misc.getServerPath() + @"\data\doors.json";
        if (!File.Exists(doorPath))
        {
            Misc.WriteError(@"Missing data\doors.json");
            return;
        }
    
        var json = File.ReadAllText(doorPath);
    
        var doorBindings = JsonConvert.DeserializeObject<DoorJsonBinding[]>(json);
    
        m_Doors = doorBindings.Select(ToDoor).ToList();
    
        Console.WriteLine("Loaded " + m_Doors.Count() + " door configurations.");
    }
    For those unfamiliar with C# and related libraries, JsonConvert comes from Newtonsoft Json, one of the most widely used libraries available on Nuget. It's a library for handling JSON with modules for converting XML to JSON and vice versa. Calling DeserializeObject<T> requires a type, which we use Json bindings for. This is a middle ground between json as a string and an object that can be used by the compiler. We can then take that Json binding and convert it to a concrete object which is fully or partially immutable. Here's what this particular Json Binding looks like

    Code:
    public sealed class DoorJsonBinding
    {
        [JsonProperty(Required = Required.Always)]
        public Door.DefaultState DefaultStatus { get; set; }
    
        [JsonProperty(Required = Required.Always)]
        public int OpenDoorId { get; set; }
    
        [JsonProperty(Required = Required.Always)]
        public int ClosedDoorId { get; set; }
    
        [JsonProperty(Required = Required.Always)]
        public CoordinateJsonBinding ClosedDoorLocation { get; set; }
    
        [JsonProperty(Required = Required.Always)]
        public CoordinateJsonBinding OpenDoorLocation { get; set; }
    
        [JsonProperty(Required = Required.Always)]
        public int OpenDirection { get; set; }
    
        [JsonProperty(Required = Required.Always)]
        public int ClosedDirection { get; set; }
    
        [JsonProperty(Required = Required.Always)]
        public bool Closable { get; set; }
    }
    The JsonProperty attributes that we can specify per property gives JsonConvert more restrictions (or freedom) to work with the input Json. We're using Required.Always to specify that there must always be a property matching these names (which are case insensitive) and they must always have a value (not null). Other options include allowing nulls, allowing the property to be absent but NOT be null when present and allowing anything at all.

    Another good attribute to use is PropertyName. Working with JSON that isn't written by you can lead to dealing with property names which don't describe behaviour, can be confusing to keep track of etc. Using PropertyName allows you to map a property within the JSON to a differently named property in a Json Binding.

    Given that the server I'm working with is a C&P conversion from Java, there are a lot of bad habits pasted over which can disappear. One of them is the unnecessary use of methods to get and set property values in a class. I'll keep going with our door example:

    Before:
    Code:
    public class Door
    {
    	public Location closedDoorLocation; // Why is this public when we have methods to get and set it :/
    
    	public Door() // Empty constructor :( Having no constructor does the same thing when calling new Door();
    	{
    	}
    
            // We should never be setting the closed door location manually, this should be
            // determined by data and never change once the object is constructed :(
    	public void setClosedDoorLocation(Location closedDoorLocation)
    	{
    		this.closedDoorLocation = closedDoorLocation; //Use of "this" to provide context is only necessary because parameter and property names are the same
    	}
    
    	public Location getClosedDoorLocation()
    	{
    		return closedDoorLocation;
    	}
    }
    After:
    Code:
    public class Door
    {
            // Can only be set inside object's constructor, trying to change the value will
            // lead to an error stating the property is readonly.
    	public Location ClosedDoorLocation { get; }
    
    	public Door(Location closedDoorLocation)
    	{
    		ClosedDoorLocation = closedDoorLocation;
    	}
    }
    We have exactly the level of functionality that we need, with a safety net in case anyone tries to set a door location by mistake.

    Once all the objects are converted, the next step will probably be to pull the skill data out of hardcoded anonymous objects and in to JSON as well. This way they can be expanded more easily, not need comments to denote field names and can be reloaded from disk.
    Reply With Quote  
     

  10. #9  
    Banned

    Join Date
    Apr 2013
    Posts
    1,614
    Thanks given
    410
    Thanks received
    475
    Rep Power
    0
    Enjoy your project bro. Good luck.
    Reply With Quote  
     

  11. #10  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Discovered and fixed an interesting bug which I'd introduced about a week ago while doing some refactoring. I thought I'd broken NPC spawning, but it turns out I'd caused all NPCs to spawn at 0, 0, 0. I think this was caused by some fragility with XML and mixing and matching JSON Bindings and XML. The Location data for all the spawns was read from XML and gave no errors when it broke and defaulted all data to Int32 default value. The rest of the NPC data was being read as JSON and used to spawn the right NPCs at their locations. As soon as I began reading the spawn info as JSON, all was right with the world again.

    Teleporting to 0, 0, 0 crashed the client very quickly, with a very unhelpful error message since I'm working with a decompiled, but I managed to spot all 850 NPCs stacked on top of me, including GWD bosses and so on. Couldn't grab screenshots in time

    I've implemented a basic generic method to read and convert JSON in to any type that I need, to avoid code duplication. Here's the method:
    Code:
    public static T DeserializeJsonFromFile<T>(string filePath)
    {
        if (!File.Exists(filePath))
        {
            //TODO: throw tailored exception later
        }
    
        //Assume that file read will be successful for now
        var json = File.ReadAllText(filePath);
    
        return JsonConvert.DeserializeObject<T>(json);
    }
    So instead of requiring something along the lines of this for every single JSON file I want to read from
    Code:
    var path = Misc.getServerPath() + @"\data\npcs.json";
    if (!File.Exists(path))
    {
        //TODO: Tear out and replace this shit error handling
        Misc.WriteError(@"Missing data\npcs.json");
        return;
    }
    
    var json = File.ReadAllText(path);
    var spawnBindings = JsonConvert.DeserializeObject<NpcSpawnJsonBinding[]>(json);
    I can cut out the code duplication and re-use my generic method
    Code:
    var path = Misc.getServerPath() + @"\data\npcs.json";
    var spawnBindings = DeserializeObject<NpcSpawnJsonBinding[]>(path);
    Reply With Quote  
     

Page 1 of 6 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. 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
  •