Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[C#] Project H(S)R - 'Full' R38 Server

Status
Not open for further replies.
Custom Title Activated
Loyal Member
Joined
Oct 26, 2012
Messages
2,357
Reaction score
1,086
The General Yeah, it's not my main focus; the room map still needs some fixing up to do just like item placing as I haven't built in any checks yet (I was testing the packet stuff etc.). I might compare the packets from first entry with second entry someday when I got time.
 
git bisect -m
Loyal Member
Joined
Sep 2, 2011
Messages
2,171
Reaction score
916
Any new progress for Habbo Beta version?
I'm really curious of what's going on.

And i really want to be one of the beta testers.
I will create a Hotel only for that.

I don't want to create any other NewCrypto Hotel.
Let's do Old School Hotels!

Also i will create a CMS for this Emulator. If you want. That's something that i can do. And obviously the CMS will be from scratch and Holoed. (HoloCMS design.) Pure Holo CMS design. Totally PURE.
 
Custom Title Activated
Loyal Member
Joined
Oct 26, 2012
Messages
2,357
Reaction score
1,086
@saamus I don't want to work on it, one reason: I cannot use VS 2015 and the latest .NET Framework. I plan on maybe cleaning up my laptop and develop on my laptop itself but I'm not sure yet. You can make your CMS if you want, I'm not a big fan of the HoloCMS design to be honest but yeah, maybe making some kind of multi-template system (or however you want to call it) CMS would be cool. Or make it user-switchable. Even better!

I am actually cleaning up the MUS + camera stuff from Blunk for v9 but so far I haven't had much luck so I'll probably either try to fix it for hours or start the cleaning up a second time.
 
Custom Title Activated
Loyal Member
Joined
Oct 26, 2012
Messages
2,357
Reaction score
1,086
I started rewriting my v38 (C#), I downloaded and installed Visual Studio 2017 RC on my Windows 7 VM, and done some stuff. I haven't actually done much yet but I want to finish up to client login at least this night. Things different:

- The project is now called Tornaado.
- XML configuration instead of INI configuration
- DotNetty sockets
- Fluent NHibernate with multiple DBMS support (MySQL, PostgreSQL, MSSQL, ...)
- C# 7.0
- NuGet packages
- Database generator

Some code:

PHP:
 public static void BuildSessionFactory()
        {
            var configuration = Fluently.Configure()
                .Database(MySQLConfiguration.Standard.ConnectionString((sb) =>
                {
                    sb.Server("127.0.0.1").Username("root").Password("").Database("tornaado_db");
                }).Raw("hbm2ddl.keywords", "none"))
                .Mappings(m => m.FluentMappings.Add<MemberMap>());
            _sessionFactory = configuration.BuildSessionFactory();

            // following code is used to create all tables for example using the classmaps
            var exporter = new SchemaExport(configuration.BuildConfiguration());
            exporter.Execute(true, true, false);
        }

PHP:
using System;

namespace Tornaado.Core
{
    public class Log
    {
        public static void Debug(string line)
        {
            Console.WriteLine($"[DEBUG] {line}");
        }

        public static void Info(string line)
        {
            Console.WriteLine($"[INFO] {line}");
        }

        public static void Warn(string line)
        {
            Console.WriteLine($"[WARN] {line}");
        }

        public static void Error(string line)
        {
            Console.WriteLine($"[ERROR] {line}");
        }

        public static void Fatal(string line)
        {
            Console.WriteLine($"[FATAL] {line}");
        }
    }
}

There are 2 ways of starting the emulator and setting up the database, you could either use the database creator in order to create the tables etc. and insert data, or you can import a .sql file.

There will be a CMS made by me, it will most likely be done with Python using CherryPy (thanks Moogly for suggesting me it).
More code will come soon.
 
Joined
Aug 24, 2012
Messages
604
Reaction score
304
I started rewriting my v38 (C#), I downloaded and installed Visual Studio 2017 RC on my Windows 7 VM, and done some stuff. I haven't actually done much yet but I want to finish up to client login at least this night. Things different:

- The project is now called Tornaado.
- XML configuration instead of INI configuration
- DotNetty sockets
- Fluent NHibernate with multiple DBMS support (MySQL, PostgreSQL, MSSQL, ...)
- C# 7.0
- NuGet packages
- Database generator

Some code:

PHP:
 public static void BuildSessionFactory()
        {
            var configuration = Fluently.Configure()
                .Database(MySQLConfiguration.Standard.ConnectionString((sb) =>
                {
                    sb.Server("127.0.0.1").Username("root").Password("").Database("tornaado_db");
                }).Raw("hbm2ddl.keywords", "none"))
                .Mappings(m => m.FluentMappings.Add<MemberMap>());
            _sessionFactory = configuration.BuildSessionFactory();

            // following code is used to create all tables for example using the classmaps
            var exporter = new SchemaExport(configuration.BuildConfiguration());
            exporter.Execute(true, true, false);
        }

PHP:
using System;

namespace Tornaado.Core
{
    public class Log
    {
        public static void Debug(string line)
        {
            Console.WriteLine($"[DEBUG] {line}");
        }

        public static void Info(string line)
        {
            Console.WriteLine($"[INFO] {line}");
        }

        public static void Warn(string line)
        {
            Console.WriteLine($"[WARN] {line}");
        }

        public static void Error(string line)
        {
            Console.WriteLine($"[ERROR] {line}");
        }

        public static void Fatal(string line)
        {
            Console.WriteLine($"[FATAL] {line}");
        }
    }
}

There are 2 ways of starting the emulator and setting up the database, you could either use the database creator in order to create the tables etc. and insert data, or you can import a .sql file.

There will be a CMS made by me, it will most likely be done with Python using CherryPy (thanks Moogly for suggesting me it).
More code will come soon.

Use log4net instead


 
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
@Dominic Thanks, I might do that. If I remember correctly, wasn't it faster?
It's a better logging system, it allows you to configure multiple log outputs. It has the [same, debug, log, warn, error] mechanism, and is highly configurable with less code effort.
 
Last edited:
Custom Title Activated
Loyal Member
Joined
Oct 26, 2012
Messages
2,357
Reaction score
1,086
@CodeDragon Okay thanks I'll implement it ASAP.

Updates will come in my Christmas holidays, I'm sorry but I got some private stuff going on so I didn't feel like working on the emulator. I did finish the socket system though, using DotNetty, more snippets coming Thursday and Friday. In case more stuff happens and I won't post anything: Happy Christmas people :).
 
Experienced Elementalist
Joined
Jun 7, 2012
Messages
288
Reaction score
250
Nice project love how you are trying to make the old habbo the new Habbo

Most of the things seems nice but is writing SQL not a little bit OLD?
Why didn't you just use entity framework if you did write it from scratch??

But nice project keep up the good work
 
Custom Title Activated
Loyal Member
Joined
Oct 26, 2012
Messages
2,357
Reaction score
1,086
Finished up the packet system, part of the network system and the configuration system works fine (as far as I know...). I think a lot of my code is messy, but I try to do it as clean as I can, so any tips are well appreciated.

A few quick notes:
- The code can still be changed; it's not final.
- For most of my code, I didn't use any C# example. For example, the DotNetty implementation is based off my Java Netty implementation. That one is - as far as I remember - written by me using the documentation.
- The packet system is something I am not sure of at this moment.
- I remove all the unnecessary 'using's in a class; why use a namespace if you don't use it at all? Maybe I should also use aliases so I use only certain classes in a namespace to make it even better.

Some snippets:

Configuration system
PHP:
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Linq;
using System.Xml.Linq;
using System;

namespace Tornaado.Core
{
    public class Configuration
    {
        private XmlDocument _document;
        private Dictionary<string, Dictionary<string, string>> _values;

        public Configuration(string file)
        {
            if (File.Exists(file))
            {
                _document = new XmlDocument();
                _document.Load(file);
                _values = new Dictionary<string, Dictionary<string, string>>();

                CacheValues();
            }
        }

        public void CacheValues()
        {
            foreach (XmlNode categoryNode in _document.GetElementsByTagName("configuration")[0].ChildNodes)
            {
                _values.Add(categoryNode.Name, new Dictionary<string, string>());

                foreach (XmlNode itemNode in categoryNode.ChildNodes)
                {
                    _values[categoryNode.Name].Add(itemNode.Name, itemNode.InnerText);
                }
            }
        }

        public string GetString(string category, string key)
        {
            string value = "";

            return (from kvp
                   in _values
                          where kvp.Key == category && kvp.Value.TryGetValue(key, out value)
                          select value).FirstOrDefault();
        }

        public int GetInt(string category, string key)
        {
            int value = 0;

            return (from kvp
                   in _values
                    where kvp.Key == category && kvp.Value.TryGetValue(key, out string rawval)
                    && int.TryParse(rawval, out value)
                    select value).FirstOrDefault();
        }

        public uint GetUInt(string category, string key)
        {
            uint value = 0;

            return (from kvp
                   in _values
                    where kvp.Key == category && kvp.Value.TryGetValue(key, out string rawval)
                    && uint.TryParse(rawval, out value)
                    select value).FirstOrDefault();
        }

        public static implicit operator bool(Configuration configuration)
        {
            return configuration != null && configuration._document != null && configuration._values != null;
        }
    }
}

(long life to C# 7.0 for inline out variables, whoo!)

GameNetworkHandler:

PHP:
using DotNetty.Transport.Channels;
using Tornaado.Core;
using System.Text;
using DotNetty.Buffers;
using Tornaado.Utilities.Encoding;
using Tornaado.Game.Clients;
using Tornaado.Communication;

namespace Tornaado.Network.Game
{
    internal class GameNetworkHandler : ChannelHandlerAdapter
    {
        public GameNetworkHandler()
        {
        }

        public override void ChannelActive(IChannelHandlerContext ctx)
        {
            base.ChannelActive(ctx);

            Engine.Game.GameClients.AddNewClient(ctx);

            Log.Debug($"Client connected to client: {ctx.Channel.RemoteAddress.ToString()}");
        }

        public override void ChannelInactive(IChannelHandlerContext ctx)
        {
            base.ChannelInactive(ctx);

            Engine.Game.GameClients.RemoveClient(ctx.Channel.Id);

            Log.Debug($"Client disconnected from client: {ctx.Channel.RemoteAddress.ToString()}");
        }

        public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush();

        public override void ChannelRead(IChannelHandlerContext ctx, object msg)
        {
            GameClient client = Engine.Game.GameClients.GetClient(ctx);
            var message = msg as IByteBuffer;

            if (message.ReadByte() == 60)
            {
                string policy = "<?xml version=\"1.0\"?>\r\n<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\r\n<cross-domain-policy>\r\n   <allow-access-from domain=\"*\" to-ports=\"1-65535\" />\r\n</cross-domain-policy>\0";
                ctx.Channel.WriteAndFlushAsync(Unpooled.CopiedBuffer(Encoding.Default.GetBytes(policy))).Wait();
            }
            else
            {
                int length = Base64Encoding.Decode(message.ReadBytes(2).ToArray());
                IByteBuffer packet = message.ReadBytes(length);

                Engine.CommunicationHandler.Handle(client, new ClientMessage(packet));
            }

            base.ChannelRead(ctx, msg);
        }
    }
}

CommunicationHandler
PHP:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Tornaado.Core;
using Tornaado.Game.Clients;

namespace Tornaado.Communication
{
    public class CommunicationHandler
    {
        private IDictionary<int, IMessageEvent> message_events;

        public CommunicationHandler()
        {
            message_events = new Dictionary<int, IMessageEvent>();

            // Code to automatically load 
            foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
            {
                if (type.Namespace.StartsWith("Tornaado.Communication.Incoming") && type.IsDefined(typeof(HabboPacketHeaderAttribute)) && type.GetInterfaces().Contains(typeof(IMessageEvent)))
                {
                    HabboPacketHeaderAttribute attr = type.GetCustomAttribute(typeof(HabboPacketHeaderAttribute)) as HabboPacketHeaderAttribute;
                    IMessageEvent message_event = type.GetConstructor(Type.EmptyTypes).Invoke(new object[] { }) as IMessageEvent;
                    message_events.Add(attr.Header, message_event);
                }
            }

            Log.Info($"Loaded {message_events.Count} message events.");
        }

        public void Handle(GameClient client, ClientMessage request)
        {
            if (message_events.TryGetValue(request.Header, out IMessageEvent message_event))
                message_event.InvokeHandler(client, request);
            else
                Log.Debug($"[{request.Header}] Unregistered handler -> {request.ToString()}.");
        }
    }
}

Example of a packet handler:

PHP:
using System;
using Tornaado.Game.Clients;

namespace Tornaado.Communication.Incoming.Handshake
{
    [HabboPacketHeader(206)]
    class InitCryptoMessageEvent : IMessageEvent
    {
        public void InvokeHandler(GameClient client, ClientMessage request)
        {

        }
    }
}

The reason I use the HabboPacketHeader attribute for my header instead of adding a new property to the IMessageEvent interface is to make the classes look cleaner. The process of loading all message events is - as far as I guess - a slow process. I'm not sure how much RAM and/or CPU the process uses. If anybody has constructive criticism, please let me know.

Oh yeah, I'd like to give credits to Cecer1 for the WeakCache class (as well as the required BluedotDictionary class). An example of where I use it:

PHP:
using NHibernate;
using NHibernate.Criterion;
using Tornaado.Core;
using Tornaado.Models;
using Tornaado.Utilities.Bluedot;

namespace Tornaado.Game
{
    public class GameMembers
    {
        public WeakCache<int, Member> MembersById { get; }
        public WeakCache<string, Member> MembersByName { get; }

        public GameMembers()
        {
            MembersById = new WeakCache<int, Member>((id) => GetMemberById(id));
            MembersByName = new WeakCache<string, Member>((name) => GetMemberByName(name));
        }

        private Member GetMemberById(int id)
        {
            Member member;

            using (ISession session = Engine.SessionFactory.OpenSession())
            {
                member = session.Get<Member>(id);
            }

            return member;
        }

        private Member GetMemberByName(string name)
        {
            Member member;

            using (ISession session = Engine.SessionFactory.GetCurrentSession())
            {
                member = session.CreateCriteria<Member>().Add(Restrictions.Eq("name", name)).UniqueResult<Member>();
            }

            return member;
        }
    }
}

This makes it so you can always use
PHP:
MembersById[KEY]

If the key exists, it'll fetch the value from the dictionary, if it doesn't exist, it will call the callback function. This is a much easier way of doing stuff.

A last note: I won't put this project on Github/Gitlab/any git platform. The only reason is me being lazy to update the git project etc. This project will be put onto a git platform when the first release is out (NOT the ALPHA/BETA). This way, anybody who wants can fork the project and work on it, or even use the project and make it work for example on the latest release. I'll put snippets here though. If you want to see how I've done something, you can
ask me and I can make a snippet out of it, no problem.

I also want to wish everybody a merry Christmas and already a happy new year (even though there will be more updates between Christmas and new year.
 
Custom Title Activated
Loyal Member
Joined
Oct 26, 2012
Messages
2,357
Reaction score
1,086
Started with FAQ because IDK.

PHP:
using NHibernate;
using System.Collections.Generic;
using Tornaado.Core;
using Tornaado.Models;
using Tornaado.Utilities.Bluedot;
using System;
using NHibernate.Criterion;

namespace Tornaado.Game.Help
{
    public class FaqLoader
    {
        private IList<FaqCategories> faq_categories;
        private IList<FaqTopics> faq_topics;

        public WeakCache<int, FaqCategories> FaqCategoriesById { get; }
        public WeakCache<int, FaqTopics> FaqTopicsById { get; }
        public WeakCache<int, IList<FaqTopics>> FaqTopicsByCategory { get; }

        public FaqLoader()
        {
            faq_categories = new List<FaqCategories>();
            faq_topics = new List<FaqTopics>();

            FaqCategoriesById = new WeakCache<int, FaqCategories>(GetCategory);
            FaqTopicsById = new WeakCache<int, FaqTopics>(GetTopic);
            FaqTopicsByCategory = new WeakCache<int, IList<FaqTopics>>(GetTopicsByCategory);
        }

        public void ReloadCategories()
        {
            using (ISession session = Engine.SessionFactory.OpenSession())
            {
                faq_categories = session.CreateCriteria<FaqCategories>().AddOrder(Order.Asc("id")).List<FaqCategories>();
            }

            Log.Info($"Loaded {faq_categories.Count} FAQ categories.");
        }

        public void ReloadTopics()
        {
            using (ISession session = Engine.SessionFactory.OpenSession())
            {
                faq_topics = session.CreateCriteria<FaqTopics>().AddOrder(Order.Asc("id")).List<FaqTopics>();
            }

            Log.Info($"Loaded {faq_categories.Count} FAQ topics.");
        }

        public IList<FaqCategories> GetCategories()
        {
            return faq_categories;
        }

        private IList<FaqTopics> GetTopicsByCategory(int categoryId)
        {
            IList<FaqTopics> topics = new List<FaqTopics>();

            foreach (FaqTopics topic in faq_topics)
            {
                if (topic.FaqCategories.Id == categoryId)
                    topics.Add(topic);
            }

            return topics;
        }

        private FaqCategories GetCategory(int categoryId)
        {
            foreach (FaqCategories category in faq_categories)
            {
                if (category.Id == categoryId)
                    return category;
            }

            return null;
        }

        private FaqTopics GetTopic(int topicId)
        {
            foreach(FaqTopics topic in faq_topics)
            {
                if (topic.Id == topicId)
                    return topic;
            }

            return null;
        }
    }
}

QV7gqOm - [C#] Project H(S)R - 'Full' R38 Server - RaGEZONE Forums

jGbH8fr - [C#] Project H(S)R - 'Full' R38 Server - RaGEZONE Forums

8STjMuK - [C#] Project H(S)R - 'Full' R38 Server - RaGEZONE Forums


The model names are wrong but I will correct them after the development.
 

Attachments

You must be registered for see attachments list
Status
Not open for further replies.
Back
Top