- Joined
- Oct 26, 2012
- Messages
- 2,357
- Reaction score
- 1,086
[C#] [DotNetty] [Fluent NHibernate] [R38] [v9] Project Tornaado
Before flaming and disallowing this thread, first read the following text. (Spoiler because too much text otherwise...)
Enough about this, this is the thread of my big project, a full R38 server working for both shockwave as flash, written from scratch in C# (since C# is my best language, I have no intention to learn C/C++/Swift for it and I dislike Java, oh yeah Moogly I KNOW THERE'S ALSO PYTHON!!!), and a full v9 server in Java (because of problems I had with MUS in v9, so camera would be a bit harder). Some tech poop:
- Written from scratch
- C#
- R38 both shockwave and flash
- Using Fluent NHibernate (you can use any DBMS in the future: SQL Server, MySQL, PostgreSQL, ...)
- Using DotNetty
- Configuration in .xml except of .ini
- WeakCache (Thanks Cecer1)
- Intention to complete most of it.
Oh yeah, I've changed; any people who have CONSTRUCTIVE criticism, feel free to let me know (this means: "You shouldn't be doing X because Y" and not "OMFG U USE X SO BAD")
Oh yeah, fun fact: the database will contain relations (unlike most databases out there) as it's much cleaner and if you do it correctly it's much better than getting multiple errors because somebody uses item definition id 1002 when he meant 1001 and 1002 doesn't exist.
More information about te rewrite is on http://forum.ragezone.com/f331/project-r38-server-1118079/index8.html.
Some snippets:
Another 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.
PLEASE NOTE: I won't be using any queries, don't come here with anything about queries: everything is done with the mapping. Thanks.
Also, screenies will be added again soon as this is a rewrite I don't have the functionality anymore I used to have.
Before flaming and disallowing this thread, first read the following text. (Spoiler because too much text otherwise...)
This project is originally made a WHILE (!) back. I wanted to create a fully oldskool project written from scratch including most of the features available. Alas, I got busy with school and internship, and I had some stress, so features were never made after a certain point. Also, I lost my interest for Habbo, mostly due to the lack of time & the stress. The thread got closed and I didn't really care much, until I started doing some Habbo stuff again. I did 2 releases, one of the being v36 dcrs with more catalogue icons and a v36 server with furnidata matching the database. These 2 things were the start of one project, originally called HSR (Habbo Shockwave Revival), as a way to create the best shockwave stuff.
Of course, the more I used Holo, the more I realised it is pretty crap (No hate Nillus, vista4life, and idkWHOELSEWORKEDONIT), so yeah, I decided to start from scratch. My intention was to use my old source but it was messed up and lost the database so I started over.
I have a bit more time now and no stress so that's why I decided to try this out..
Of course, the more I used Holo, the more I realised it is pretty crap (No hate Nillus, vista4life, and idkWHOELSEWORKEDONIT), so yeah, I decided to start from scratch. My intention was to use my old source but it was messed up and lost the database so I started over.
I have a bit more time now and no stress so that's why I decided to try this out..
Enough about this, this is the thread of my big project, a full R38 server working for both shockwave as flash, written from scratch in C# (since C# is my best language, I have no intention to learn C/C++/Swift for it and I dislike Java, oh yeah Moogly I KNOW THERE'S ALSO PYTHON!!!), and a full v9 server in Java (because of problems I had with MUS in v9, so camera would be a bit harder). Some tech poop:
- Written from scratch
- C#
- R38 both shockwave and flash
- Using Fluent NHibernate (you can use any DBMS in the future: SQL Server, MySQL, PostgreSQL, ...)
- Using DotNetty
- Configuration in .xml except of .ini
- WeakCache (Thanks Cecer1)
- Intention to complete most of it.
Oh yeah, I've changed; any people who have CONSTRUCTIVE criticism, feel free to let me know (this means: "You shouldn't be doing X because Y" and not "OMFG U USE X SO BAD")
Oh yeah, fun fact: the database will contain relations (unlike most databases out there) as it's much cleaner and if you do it correctly it's much better than getting multiple errors because somebody uses item definition id 1002 when he meant 1001 and 1002 doesn't exist.
More information about te rewrite is on http://forum.ragezone.com/f331/project-r38-server-1118079/index8.html.
Some snippets:
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.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;
}
}
}
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);
}
}
}
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()}.");
}
}
}
PHP:
using System;
using Tornaado.Game.Clients;
namespace Tornaado.Communication.Incoming.Handshake
{
[HabboPacketHeader(206)]
class InitCryptoMessageEvent : IMessageEvent
{
public void InvokeHandler(GameClient client, ClientMessage request)
{
}
}
}
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;
}
}
}
Another 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.
PLEASE NOTE: I won't be using any queries, don't come here with anything about queries: everything is done with the mapping. Thanks.
Also, screenies will be added again soon as this is a rewrite I don't have the functionality anymore I used to have.
Last edited: