[C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

Results 1 to 14 of 14
  1. #1
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]
    Introduction:
    Project Sirius: Arcturus 2.0 Emulator is an emulator trying to closely emulate Habbo. Duh

    Well, I've decided to ditch Java because the original Arcturus source code base is just a pile of shit. I mean, its just really difficult to maintain and easy to break something with every change. And as the author of it, its okay to say it (And should be a massive red flag!!). Fixing it up in order to bring it up to standards would've cost a lot of time, perhaps even more than starting from scratch. Sooooo I've started from scratch. Because I'm a bit done with Java, in my opinion its bloated, I decided to rebuild the emulator from scratch in C#. C# allows for beautiful elegant code. You'll love it :)

    The difference
    If you're running Arcturus, or any of its derived versions, you know stuff gets broken over and over again with each change and release, sometimes the same bug gets fixed a couple times. So whats new here? Well for a start I'm building it using backed unit tests. If you're unfamilar with unit tests, they basically try to take a small piece of code and verify its behavior against some inputs and known result. If you change the logic of a piece of code, it will come up that the behavior has been modified and no longer according to spec. Using this method, its the first defence preventing bugs being introduced.

    With the rise of all different client types, I decided to make it modular to use different clients. For now Flash is supported and soon Nitro will be integrated. With a simple to use interface, you can build any type of project against it, wether this is an Rest API, discord bots or custom protocols.

    Arcturus 2.0 is build using a modular architecture in mind with multiple components. For example, rooms can be hosted on multiple servers in order to distribute CPU work load. An unique feature of this makes it possible to do live testing on a hotel without rebooting the emulator or having to deal with portforwarding.

    The whole game logic & architecture is standalone implemented. This also allows smaller components to be tested and not having to deal with packets.

    Features:
    Build using Visual Studio Professional.
    C# .NET 5
    Microsoft Abstractions Dependency Injection.
    NUnit & Moq for unit testing.
    Multiple database support, MariaDB, PostgreSQL, SQLite etc.
    Dapper object mapper.
    JSON Configuration & live reload.
    Distributed architecture.
    Custom Game Protocol to communicate with different clients.

    Game Features:
    Quite a bit of features have already been implemented.
    - Furniture (Placing, Moving, Clicking, Picking up)
    - Bots
    - Mod Tools
    - Wired (Triggers, Effects & Conditions (Excluding Game Wired))
    - Catalog
    - Messenger
    - Flash landing view, hall of fame, news list.
    - User preferences
    - Navigator

    Examples:

    Here is how in in the latest Java Arcturus 1.21.2 version give badge command is implemented:

    Spoiler:

    Code:
    public class BadgeCommand extends Command
    {
        public BadgeCommand()
        {
            super("cmd_badge", Emulator.getTexts().getValue("commands.keys.cmd_badge").split(";"));
        }
    
         @Override
        public boolean handle(GameClient gameClient, String[] params) throws Exception
        {
            if(params.length == 1)
            {
                gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_badge.forgot_username"), RoomChatMessageBubbles.ALERT);
                return true;
            }
            if(params.length == 2)
            {
                gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_badge.forgot_badge").replace("%user%", params[1]), RoomChatMessageBubbles.ALERT);
                return true;
            }
    
            if(params.length == 3)
            {
                Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(params[1]);
    
                if(habbo != null)
                {
                    if (habbo.addBadge(params[2]))
                    {
                        gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.succes.cmd_badge.given").replace("%user%", params[1]).replace("%badge%", params[2]), RoomChatMessageBubbles.ALERT);
                    }
                    else
                    {
                        gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_badge.already_owned").replace("%user%", params[1]).replace("%badge%", params[2]), RoomChatMessageBubbles.ALERT);
                    }
    
                    return true;
                }
                else
                {
                    try (Connection connection = Emulator.getDatabase().getDataSource().getConnection())
                    {
                        boolean found;
    
                        try (PreparedStatement statement = connection.prepareStatement("SELECT badge_code FROM users_badges INNER JOIN users ON users.id = user_id WHERE users.username = ? AND badge_code = ? LIMIT 1"))
                        {
                            statement.setString(1, params[1]);
                            statement.setString(2, params[2]);
                            try (ResultSet set = statement.executeQuery())
                            {
                                found = set.next();
                            }
                        }
    
                        if(found)
                        {
                            gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_badge.already_owns").replace("%user%", params[1]).replace("%badge%", params[2]), RoomChatMessageBubbles.ALERT);
                            return true;
                        }
                        else
                        {
                            try (PreparedStatement statement = connection.prepareStatement("INSERT INTO users_badges VALUES (null, (SELECT id FROM users WHERE username = ? LIMIT 1), 0, ?)"))
                            {
                                statement.setString(1, params[1]);
                                statement.setString(2, params[2]);
                                statement.execute();
                            }
    
                            gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.succes.cmd_badge.given").replace("%user%", params[1]).replace("%badge%", params[2]), RoomChatMessageBubbles.ALERT);
                            return true;
                        }
                    }
                    catch (SQLException e)
                    {
                        Emulator.getLogging().logSQLException(e);
                    }
                }
            }
    
            return true;
        }
    }


    Here is the same thing in Arcturus 2.0:

    Spoiler:

    Code:
        public class BadgeCommand : ICommand
        {
            private readonly IBadgesService _badgesService;
            public string Key => "badge";
    
            public BadgeCommand(IBadgesService badgesService)
            {
                _badgesService = badgesService;
            }
    
            public async Task<string> Handle(IHabbo habbo, string[] parameters)
            {
                if (parameters.Length == 0 || string.IsNullOrWhiteSpace(parameters[0])) return "forgot_username";
                if (parameters.Length == 1 || string.IsNullOrWhiteSpace(parameters[1])) return "forgot_badge";
                var username = parameters[0];
                var badgeCode = parameters[1];
                return await _badgesService.GiveBadge(username, badgeCode) ? "given" : "already_owned";
            }
        }


    From this example we can see that the original badge command had a lot of responsibilities, verifying that someone does not have the badge, inserting the badge in to the database etc. Starting with 2.0, all responsibilities are split up in small classes. In this case the IBadgesService is responsible to give a badge. No need to worry about it in the command if someone is online. Simple, clean & elegant code.

    Last edited by The General; 27-01-21 at 02:46 PM.


  2. #2
    Moderator Quackster is offline
    ModeratorRank
    Dec 2010 Join Date
    AustraliaLocation
    3,413Posts

    Re: Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    Thread approved, good luck.
    The Habbo archives: http://alex-dev.org/archive/

  3. #3
    Evil Scottish Overlord Joopie is online now
    LegendRank
    Jun 2010 Join Date
    The NetherlandsLocation
    2,753Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    I'm glad to see some .NET development back in the community. I think it's an awesome language that got plagued by bad code in this section. Judging by your command snippet, I think it's a good step in the right direction.

    I'd suggest you use Microsoft's naming convention. For example append all async methods with Async to mark them as being asynchonious. Also read up on best practisches when working with asynchonious methods.

    What are your thoughts about being open source for this project? One of the biggest complains about Arcturus 1.0.


    Join Our RaGEZONE Discord Now!


    Send me a PM | send me a mail

    Still waiting for XenForo to hit RaGEZONE.

  4. #4
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    Quote Originally Posted by Joopie View Post
    I'd suggest you use Microsoft's naming convention. For example append all async methods with Async to mark them as being asynchonious.
    Yeah still not sure about this one. Imo, if you're not doing async work, don't return a Task. Therefor the assumption can be made that anything that returns a Task is async. Its only useful if you have multiple implementations of an interface that could possibly be async but I dont want to define the possible implementation in the interface.

    What are your thoughts about being open source for this project? One of the biggest complains about Arcturus 1.0.
    Arcturus 1.0 was open source. Then renames started. If you tell people if they dont like something and to use something else, they just take that as an approval to decompile & rename your work. We'll slap a new name on it and its something else.

    Nah, people have no respect for eachothers work, its something I was hoping to build in the community in the past. The community doesnt deserve access to the full source code. Morningcrap has shown that nothing good comes out of it. I keep getting daily messages from people who think I am still working on that and I would have to tell them that I do not run that rename.

    Nope, people shot themselves in the foot. No source code from me.

    Hurr durr we'll crack & decompile thats what we do arguments coming in. Well, thats exactly the reason why this community is dead. I dont know in what form this will be released. I am not going to discuss that here, this is a development thread and not a release thread.
    Last edited by The General; 27-01-21 at 03:08 PM.

  5. #5
    V.I.P Member Beny. is offline
    True MemberRank
    Aug 2009 Join Date
    535Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    Quote Originally Posted by The General View Post
    Morningcrap has shown that nothing good comes out of it. I keep getting daily messages from people who think I am still working on that and I would have to tell them that I do not run that rename.

    Nope, people shot themselves in the foot. No source code from me.

    Hurr durr we'll crack & decompile thats what we do arguments coming in. Well, thats exactly the reason why this community is dead.
    Arcturus would have been nothing without Morningstar. It's now the most used Emulator in the scene thanks to the community taking over. There are updates weekly, instead of every 3-6 months, bugs are fixed promptly and there's an active community of 1500+ members for hotel owners to receive support. If thats "nothing good" then you are delusional as fuck.

    Looking at your code snippets, it's returning a string. What is it used for? Also what would happen if the user doesn't exist?



    Quote Originally Posted by The General View Post
    I dont know in what form this will be released. I am not going to discuss that here, this is a development thread and not a release thread.
    Take a read of the section rules. Your project doesn't belong here if you aren't releasing it.
    Last edited by Beny.; 27-01-21 at 05:48 PM.

  6. #6
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    Looking at your code snippets, it's returning a string. What is it used for? Also what would happen if the user doesn't exist?
    The command system is currently in a crude implementation and will be refactored in the near future. Right now it just simply returns a status key which is used to automatically resolve the message displayed to the user, room whisper, private chat, alert, bubble alert etc.

    Quote Originally Posted by Beny. View Post

    Take a read of the section rules. Your project doesn't belong here if you aren't releasing it.
    As an ex section moderator, I am fully aware of the Habbo Hotel development rules.
    I never said I wasnt going to release it.

  7. #7
    Software Engineer Moogly is offline
    Alpha MaleRank
    Feb 2008 Join Date
    Vault 101Location
    2,319Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    That code snippet is so bad. You're returning a string why exactly??? Have you not heard of other data types? Maybe you should consider taking some basic computer science classes at a local college. Also if you're comparing your code to original Arcturus which is GPL licensed based on several factors I have proven time and time again, you must license this version of it under the GNU GPL as well. The GPL is so toxic that for years Microsoft forbade employees from looking at GPL code because all it takes is a few lines of GPL'd code to poison a project.
    Why Arcturus is GPL Licensed:

    * Original license.
    * Contributions were GPL'd.
    * Arcturus uses MySQL Connector which is GPL Licensed, therefore Arcturus is a GPL Licensed project and anybody can fork it.

    GPL License ELI5:

    You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions.

  8. #8
    V.I.P Member Beny. is offline
    True MemberRank
    Aug 2009 Join Date
    535Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    Quote Originally Posted by The General View Post
    The command system is currently in a crude implementation and will be refactored in the near future. Right now it just simply returns a status key which is used to automatically resolve the message displayed to the user, room whisper, private chat, alert, bubble alert etc.
    So why are you writing that it's better than Arcturus 1 in OP and then saying here that it needs refactoring already? Just do shit properly to begin with so it doesn't turn out as a failure like before.

  9. #9
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    Quote Originally Posted by Beny. View Post
    So why are you writing that it's better than Arcturus 1 in OP and then saying here that it needs refactoring already? Just do shit properly to begin with so it doesn't turn out as a failure like before.
    Oh look, all the professional software engineers appeared! Please post the emulator you wrote from scratch.

    Yes lets go all in and implement all the features in one go. Sure your boss would love to hear that the project will only be able to be used when everything is implemented after 5 years and meanwhile he just has to suck it up that it won't compile. Why bother keeping small features working and extending and improving your code when you can do everything correctly in one go.

    You're saying it as if you're never allowed to touch any of the code you've written and must do it in one go correctly. Sorry to break it to you, but in the real world everything gets refactored all the time due to changing requirements.

    Quote Originally Posted by Moogly View Post
    That code snippet is so bad. You're returning a string why exactly??? Have you not heard of other data types? Maybe you should consider taking some basic computer science classes at a local college. Also if you're comparing your code to original Arcturus which is GPL licensed based on several factors I have proven time and time again, you must license this version of it under the GNU GPL as well. The GPL is so toxic that for years Microsoft forbade employees from looking at GPL code because all it takes is a few lines of GPL'd code to poison a project.
    Yes because GPLv3'ed Java code can be compiled by csc. The original Arcturus source isnt referenced in this project.

  10. #10
    xHosts G0D NOC is offline
    Gold SubscriberRank
    Sep 2011 Join Date
    Liverpool, UKLocation
    831Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    I will be watching the dev, sounds good that .NET will be used for the project. Good luck

  11. #11
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    I'll just manually update this thread. If you think you can do it better, then do it without stealing other peoples work. No need to start drama here, go back to your own toxic circles.

    /closed

  12. #12
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    Working with bill to make Nitro adhere to the same flash client -> server packets. A lot of emulators just send all the client data upon login. This isnt preferred but as Nitro kind of expects this, proxy-ing nitro to the flash interface doesnt make the client work out of the box. For example nitro expects the server to send the user info upon login while in the Flash client, the client explicitly asks for it using the InfoRetrieve packet.

    Hopefully this gets fixed in Nitro soon so I dont have to do weird hacks.

  13. #13
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    So I had not touched this project in 2 months and decided to get back into it seeing that the Habbo flash client isnt dead and they're actually bringing snowstorm back :D

    Couple things that I noticed was the total clusterfuck of message subscriptions which is what I spend the last couple days on working on refactoring.

    For example given an ExampleService which would require some additional dependencies and registers subscriptions on messages would look like something like this:

    Code:
    public class ExampleService : IExampleService
        {
            public ExampleService(IGameServerConnectionRegistry connectionRegistry)
            {
                connectionRegistry.Subscribe<UserUsernameUpdatedNotification>(OnUserUsernameUpdatedNotification);
            }
    
            private Task OnUserUsernameUpdatedNotification(UserUsernameUpdatedNotification payload)
            {
                return DoSomething();
            }
    
            public Task DoSomething()
            {
                return Task.CompletedTask;
            }
        }
    Now, this in itself isnt that bad. It just gets bad when you have a lot of subscriptions as the class file would grow in since quite quickly and any dependecies for those message handlers would also have to be injected.

    I changed this around so that I now use a NotificationHandler for Events / Notifications and RequestHandler for Requests (Requires reply)

    Code:
    public class UserUsernameUpdatedNotificationHandler : NotificationHandler<UserUsernameUpdatedNotification>
        {
            private readonly IExampleService _exampleService;
    
            public UserUsernameUpdatedNotificationHandler(IExampleService exampleService)
            {
                _exampleService = exampleService;
            }
    
            public override Task Handle(UserUsernameUpdatedNotification payload)
            {
                return _exampleService.DoSomething();
            }
        }
    All handlers will be automatically registered. I also have to only inject the dependencies it really needs whereas the services before would get bloated quickly with multiple dependencies.
    The other upside of this is that they're smaller in general, standalone and dont have any dependencies on their own. Its very easy to test them due to the minimal dependencies.

    There is no need to manually register any handlers as they'll be automatically scanned.
    Code:
    services.Scan(scan => scan.FromAssemblies(Assembly.GetAssembly(typeof(CoreModule))).
                    AddClasses(classes => classes.Where(c => c.IsAssignableTo(typeof(IRequestHandler))))
                    .AsImplementedInterfaces()
                    .WithScopedLifetime());

  14. #14
    Retired The General is offline
    DeveloperRank
    Aug 2011 Join Date
    7,569Posts

    Re: [C#] Arcturus Version 2.0 Emulator by The General [C#, .NET, Windows, Linux, Mac]

    PLUGINS!

    Who doesnt like them. Adding in custom interaction without having to modify the emulator (hehe). Well I do love them and I know a lot of folks out there love them aswell. Sooo thats why in that spirit I'm trying to make developing plugins as easy as possible. How easy you might wonder? Well... So simple that you dont even need to register anything. No more having to restart your hotel because you forgot to register a command to the commands service.

    With Arcturus, you're actually relatively limited to what you can do in a non reflection way. Yeah you could possibly replace some core services, though anything that might cache the reference to the service created before override might still use the old one. With this plugin system however you can do literally anything. And as I try to keep core services as small as possible, it doesnt take a whole lot of effort to replace the implementation of an interface.

    The following code is subject to change and is definitely not final.

    So to make a plugin, its fairly straight forward. And as I hate configuration files, I like to have everything done in one place: In code.

    Here is an example plugin that just prints "Hello World!" to the command line. How fascinating!

    Code:
        public class BasicPluginDefinition : IPluginDefinition
        {
            public string Name => "Basic Plugin Example";
            public string Description => "Basic Plugin example to demonstrate developing plugins in Sirius";
            public Version Version => new(1, 0);
            public void ConfigureServices(IServiceCollection serviceCollection)
            {
            }
    
            public Type PluginClass() => typeof(BasicPlugin);
        }
    
        public class BasicPlugin : IPlugin
        {
            public BasicPlugin()
            {
                Console.WriteLine("Hello World!");
            }
        }
    As you see, you can use the ConfigureServices to add additional dependency injection registrations if you like. Or REPLACE core services with your own implemention. Everything is dependency injected into the server. Heck you could rewrite the whole emulator as a plugin (hmmm ideas....)

    So given the example, we can easily create a command:

    Code:
        public class CommandPluginDefinition : IPluginDefinition
        {
            // Snip boilerplate as before ^
            public Type PluginClass() => typeof(CommandPlugin);
        }
    
        public class CommandPlugin : IPlugin
        {
            public CommandPlugin()
            {
            }
        }
    
        public class PingCommand : ICommand
        {
            public string Key => "ping";
    
            public Task<CommandResult> Handle(IHabbo habbo, string[] parameters)
            {
                habbo.Alert("Pong!");
                return Task.FromResult(CommandResult.Ok);
            }
        }
    So now when you run :commands, the :ping command is shown and when you type ping, well you probably guessed it, you get a Pong! alert. Breathtaking.




    Anyway, again, you can just inject whatever service you fancy.

    Now this is a basic but already quite powerful plugin system. While Arcturus / Sirus is split up in multiple services that can run standalone, for example multiple servers hosting rooms and a single core entry point, right now plugins are only loaded into the core and not in the room hosting scope yet.



Advertisement