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
Whats been done?
Library's used
Here's some of the Core snippets...
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.
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;
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.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.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;
}
}
}
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: