INACTIVE Panda - Stable - Clean - Humanizer - NLog - C#

Status
Not open for further replies.

Seriosk

Programmer;
Oct 29, 2016
256
105
PaNdA
Greetings DevBest community, I am here today with a brand new development that I would like to boast about. Not really but I thought I would create a new thread to just share this with you guys and get some thoughts and opinions back from users and developers.

I have created emulation systems before, I have even finished one before. Hopefully I'll finish this one.. I have learnt a great deal from past projects and tips from developers on using better practices and making my code overall much better. My development career has nothing to do with Habbo, infact I have never played Habbo only developed for it for a short while. I was taught mainly from the StackOverflow and MSDN community (in C# that is). I also spent a little time in CodeProject that taught me a bit.

Getting back on topic, I am starting this development mainly because I think this emulator is pretty decently wrote (so far) and developers could probably learn a thing or two from the code in it. I am also hoping I'll finish it so hotel creators can enjoy it too.

Improved since my last Emulators
  • Disposing classes correctly
  • No redundant code
  • Better call-stacks
  • Better naming conventions
  • Taking advantage of modern practices
  • String Interpolation
  • Null propagation
  • Better class names
  • Better Structure
  • Overall better coding standards
  • Version Control
  • Concurrency

Whats been done?
  • Initialization
  • Console Worker
  • Sockets
  • Configuration
  • Networking
  • Handler System
  • Utilities
  • Sessions
  • Packets

Library's used
  • NLog
  • Humanizer

Here's some of the Core snippets...
private static PandaServer _pandaServer;

private static void Main()
{
LogManager.Configuration = new XmlLoggingConfiguration("assets/config/nlog.config");

_pandaServer = new PandaServer();
_pandaServer.Initialize();

while (true)
{
Console.ReadKey(true);
}
}

public static PandaServer GetPandaServer() => _pandaServer;

using System;
using System.Collections.Generic;
using NLog;
using Panda.Root.Core.Other;
using Panda.Root.Utilities;
using Panda.Root.Core.Configuration;
using Panda.Root.Core.Network.Sockets;

namespace Panda.Root
{
public class PandaServer
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

public string ServerName { get; private set; }
public double ServerVersion { get; private set; }
public string ServerAuthor { get; private set; }
public DateTime ServerStarted { get; private set; }

private readonly Dictionary<string, IPandaClass> _handlers;

public PandaServer()
{
_handlers = new Dictionary<string, IPandaClass>(StringComparer.InvariantCultureIgnoreCase);
}

private void RegisterHandler(string handlerName, IPandaClass handler)
{
_handlers[handlerName] = handler;
}

public IPandaClass GetHandler(string handlerName)
{
return _handlers[handlerName];
}

public void Initialize()
{
try
{
ServerName = "Panda";
ServerVersion = 0.1;
ServerAuthor = "Seriosk";

var config = CoreUtilities.CreateInstanceOf<ConfigurationManager>();

if (config != null)
{
RegisterHandler("configuration", config);
config.Load("/assets/config/config.ini");
}

ServerStarted = DateTime.Now;
}
catch (Exception exception)
{
Logger.Error(exception, "Failed to load the application.");
}
}
}
}

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
using Panda.Root.Core.Other;
using Panda.Root.Utilities;

namespace Panda.Root.Core.Configuration
{
public class ConfigurationManager : IPandaClass
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

private Dictionary<string, string> _configItems;

public ConfigurationManager()
{
_configItems = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
}

public void Load(string configFile)
{
try
{
if (!File.Exists(configFile) || CoreUtilities.IsFileLocked(new FileInfo(configFile)))
{
Logger.Error($"Failed to open {configFile}. It either does not exist or is locked.");

System.Console.ReadKey(true);
Environment.Exit(0);
}

_configItems = File.ReadLines(configFile).Where(IsConfigurationLine).Select(line => line.Split('='))
.ToDictionary(line => line[0], line => line[1]);
}
catch (DirectoryNotFoundException exception)
{
Logger.Error(exception, "Failed to load configuration because the directory was not found.");
}
catch (Exception exception)
{
Logger.Fatal(exception, "Error while trying to load configuration.");
}
}

private static bool IsConfigurationLine(string line)
{
return !line.StartsWith("#") && line.Contains("=");
}

public string GetValueByKey(string key)
{
if (!_configItems.TryGetValue(key, out string value))
{
Logger.Warn($"Key not found: {key}");
}

return value;
}

public int GetValueByKeyInt(string key)
{
if (!_configItems.TryGetValue(key, out string value))
{
Logger.Warn($"Key not found: {key}");
}

return int.Parse(value);
}
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace Panda.Root.Core.Console
{
class ConsoleWorker : IDisposable
{
private Timer _serverTimer;

public ConsoleWorker()
{
_serverTimer = new Timer { Interval = 1000 };
_serverTimer.Elapsed += ElapsedTimer;

StartWorker();
}

private void StartWorker()
{
_serverTimer.Enabled = true;
}

private static void ElapsedTimer(object sender, ElapsedEventArgs e)
{
System.Console.Title = Program.GetPandaServer().ServerName + " - Started: " + Program.GetPandaServer().ServerStarted.Humanize() + " - Online: " + Program.GetPandaServer().GetHandler("session_management").OnlineCount;
}

public void Dispose()
{
Dispose(true);
}

private void Dispose(bool disposing)
{
if (!disposing)
{
return;
}

_serverTimer.Stop();
_serverTimer.Dispose();
_serverTimer = null;
}
}
}

FAQ

What revision will this run on?

It'll have support for R63 (Phoenix) and the latest Production upon release date.

Whats unique?
It's clean, robust and its really easy to develop inside of. I also hope it'll turn out easy for hotel owners to use it because its clear to see Plus Emulator challenges many hotel creators with the amount of help questions asked. Its also got a lot more functionality and supports a lot more things that I haven't really mentioned in here but to do with networking and database.

Repository?
Its coming, when I can finally get back to my main development environment to make it.

Database Structure?
I'll try and make it similar to the original Habbo structure, any changes will include SQL query's to convert that if possible anyway, I'll talk more about it closer to the time.

Finally, don't expect multiple daily updates from this. I'll probably be pushing an update every 3 or 4 days, instead of daily like my old projects. The reasoning for this is I have a lot on right now and don't want to put too much effort in to this project to eventually get bored of it by working on it too much, because trust me it does happen.
 
Last edited:

Seriosk

Programmer;
Oct 29, 2016
256
105
I have some updated news on this development.

I've just finished coding a handler system that will allow me to store multiple classes inside a dictionary under a parent Key (that parent being the interface of IPandaClass)

Object Initializing (dictionary)
Code:
_handlers = new Dictionary<string, IPandaClass>(StringComparer.InvariantCultureIgnoreCase)
{
    ["messages"] = Utilities.CreateInstanceOf<MessageHandler>(),
    ["configuration"] = Utilities.CreateInstanceOf<ConfigurationData>(),
    ["console_worker"] = Utilities.CreateInstanceOf<ConsoleWorker>(),
    ["base_handler"] = Utilities.CreateInstanceOf<BaseHandler>()
};

Getting a handler:
Code:
public IPandaClass GetHandler(string handlerName)
{
    return _handlers[handlerName];
}

You'll need to do something like this to explicitly get the type, instead of using the IPandaClass return type, that way you'll be able to use the methods on that handler, something like this...
Code:
var myHandler = GetHandler("myHandler_Name") as myHandlerClassName;

That way you'll have full control as if it was a field. I think this way is much more organised, has a better call stack and overall is much better for an emulator. You're wasting hundreds of lines of code just to declare classes.. that's without your methods.
 
Last edited:
Feb 1, 2014
165
137
I have some updated news on this development.

I've just finished coding a handler system that will allow me to store multiple classes inside a dictionary under a parent Key (that parent being the interface of IPandaClass)

Object Initializing (dictionary)
Code:
_handlers = new Dictionary<string, IPandaClass>(StringComparer.InvariantCultureIgnoreCase)
{
    ["messages"] = Utilities.CreateInstanceOf<MessageHandler>(),
    ["configuration"] = Utilities.CreateInstanceOf<ConfigurationData>(),
    ["console_worker"] = Utilities.CreateInstanceOf<ConsoleWorker>(),
    ["base_handler"] = Utilities.CreateInstanceOf<BaseHandler>()
};

Getting a handler:
Code:
public IPandaClass GetHandler(string handlerName)
{
    return _handlers[handlerName];
}

You'll need to do something like this to explicitly get the type, instead of using the IPandaClass return type, that way you'll be able to use the methods on that handler, something like this...
Code:
var myHandler = GetHandler("myHandler_Name") as myHandlerClassName;

That way you'll have full control as if it was a field. I think this way is much more organised, has a better call stack and overall is much better for an emulator. You're wasting hundreds of lines of code just to declare classes.. that's without your methods.

It's an interesting project and its good that you're testing the waters with new libraries.

However, this is not a good method at all, its not necessary, slower and you're actually making it harder to debug the call stack. Polymorphism is great when you're handling things such as item events, etc but its not needed for class management. Make sure of the "this" keyword and stick to strict convention. You appear to be using "readonly" keyword in random situations rather then exploiting full coverage.

When using iDisposable, have a look at protected methods and Garbage Collection suppression.

Interfaces shouldn't contain the word "Class" either when addressed. Afterall, its an interface... not a class. Check out MSDN for more information.


Pretty cool though man, there's a few other faults too but good job overall. :)
 

Seriosk

Programmer;
Oct 29, 2016
256
105
It's an interesting project and its good that you're testing the waters with new libraries.

However, this is not a good method at all, its not necessary, slower and you're actually making it harder to debug the call stack. Polymorphism is great when you're handling things such as item events, etc but its not needed for class management. Make sure of the "this" keyword and stick to strict convention. You appear to be using "readonly" keyword in random situations rather then exploiting full coverage.

When using iDisposable, have a look at protected methods and Garbage Collection suppression.

Interfaces shouldn't contain the word "Class" either when addressed. Afterall, its an interface... not a class. Check out MSDN for more information.


Pretty cool though man, there's a few other faults too but good job overall. :)
I appreciate your constructive criticism, I'll definitely read up on that and fix all the bad parts.

Just a quick thing about the part where you said I was putting readonly on things that shouldn't really be readonly, I use an extension that automatically does that for me named ReSharper, I'll look more closely next time on what it's actually applying readonly to and be more consistent with it.

As for using the this qualifier, I think you were saying I should use it? sorry if you weren't.. but.. I've kind of implemented the fact that the this qualifier is redundant and should only be used when explicitly referring to something in the class when you have a situation for instances where you have something the same same, so to separate the confusion you would use this. (same parameter name maybe).

That and passing the current class's instance.. (this);
 
Put together a quick utilities class for randomization, also added a percent method because I noticed in other emulators it was all over the place, very messy and sometimes hard coded in multiple classes all over the solution.

Code:
namespace Panda.Root.Core.Utilities
{
    using System;

    public static class Randomizer
    {
        private static readonly Random Random = new Random();

        public static int Next(int minimum, int maximum)
        {
            return Random.Next(minimum, maximum);
        }

        public static int NewNext(int minimum, int maximum)
        {
            return new Random().Next(minimum, maximum);
        }

        public static byte NextByte(int minimum, int maximum)
        {
            return (byte)Next(Math.Min(minimum, Math.Min(maximum, 255)), Math.Min(maximum, 255));
        }

        public static int GetPercent(int number, int percent)
        {
            return (int)Math.Round((double)number * percent / 100);
        }
    }
}
 
Last edited:

Lotus

Legacy, it's all anyone leaves behind.
Jun 8, 2012
1,637
501
Interesting choice in a name for this, but this sounds pretty amazing, I wish you the best of luck with this project.
 
Status
Not open for further replies.

Users who are viewing this thread

Top