Sirius Emulator - From Scratch - C# 6.0

Status
Not open for further replies.

Seriosk

Programmer;
Oct 29, 2016
256
105
You got any release date in mind? And it's looking really well right now, carry on!


Skickat från min FRD-L09 via Tapatalk
I don't really want to put a date on it in case I cant stick to it, but probably around January time.
 

Seriosk

Programmer;
Oct 29, 2016
256
105
You might aswell close the thread, If your going to be so disactive​
Sorry but I have been busy studying... among other things

On-Topic:
I have finished the GameItem library and most of the catalog (as far as I need to go to finish the rest of the packets), the code does need a litttttttleeee tidy up but I can just refactor it and tidy it up at a later date (Only like 2 methods I went a bit messy on) and yes I have added a //todo to remind me to fix the problem.

Im starting to work on Groups library (I did start it but didn't finish it) but I am definitely going to try and finish that by next weekend. I have kept the database structure the same to the default Plus so if any of you guys did want to transfer you wouldn't have to do anything.

I will be looking for people to test it out when it gets closer to being completed, I also have ideas for improving the sockets by using a different type (Not sure if any of you have seen) but C# sockets can be written in a different way since they have been done on Plus etc, but of course improvements can come after I have actually completed this.. at the moment I see no issue with the current way of doing things.

I am also sorry that I had been inactive around a week ago, I was working on a side project with a few of the DevBest members and find of neglected this project, but I am back on the ball now.
I'll post some screenshots soon, and some code snippets since my GitHub repository fell through, Thanks!
 
Not sure if I should include a downloadable DLL file that automatically updates the emulator when a new version is out, maybe it can be a config element? Let me know what you guys think, I think Azure did something similar when they were going to update to Azure 2.0 and push the update for all users.
 

TheGeneral

Active Member
Dec 27, 2016
135
152
I don't like it how you call components of your emulator libraries. It would indicated that they are easily exchangeable and could be used for other projects.

Your github repo returns a 404.
 

Seriosk

Programmer;
Oct 29, 2016
256
105
UPDATED NEWS - 31/01/2017 - 18:00
Hello. I have decided to resume the development of Sahara as I believe it will be a good project to focus my mind. I will be analyzing the memory of Sahara (Jetbrains DotMemory), and furthering the progress of it by a large amount from what was done before the development was paused.

I'll post updates as soon as there are some! I've also added code in places where I had hoped to implement some kind of functionality or feature but then decided against it, overall I will just be making the code more pure, with increased productivity and considering the abstraction of Sahara.

I am also considering releasing Sahara in console version and a design version, the design version will have a stop/start button with extra features such as MUS functionality and more. I have many plans for Sahara and hopefully we can execute them.
 
I don't like it how you call components of your emulator libraries. It would indicated that they are easily exchangeable and could be used for other projects.

Your github repo returns a 404.
I wasn't aware any of the code was view able to the public? Unless you saw it for the short time I had a github up.
 
Updates - 01/02/2017 12:16
- Storing position cords better (1 column split by ,) so 2,9,14.5 instead of 3 individual columns for x,y,z
- Reduced memory slightly by finding out what parts are using the most memory.
- Coded a few more packets.
- Created GameMapping (assigned to every room, accessible on a GetGameMapping() function

Will I have to manually convert my DB structure over to the new x,y,z system?
No, I'll include a script upon release to do it.

I have also took a different route to other emulators. Other emulators don't really extend their functionality beyond what is needed and what the developer might want to do. Most functions are set with extra parameters to extend its functionality and choose if certain parts of the functions are executed, such as:
Code:
private void MyVoid(bool clearBefore = false)
{
    if (clearBefore && _myDictionary.Count > 0)
    {
        _myDictionary.Clear();
    }
}

Small steps, but still progress.
 
Last edited:

CosmoPeak

PeakRP.com
May 15, 2016
271
268
- Storing position cords better (1 column split by ,) so 2,9,14.5 instead of 3 individual columns for x,y,z

This isn't better at all. MySQL has an int data type for a reason. This is bad practice and doesn't improve performance or functionality at all.

- Reduced memory slightly by finding out what parts are using the most memory.

What parts used the most memory and how did you reduce it?

- Coded a few more packets.

What packets, and what did you do?

- Created GameMapping (assigned to every room, accessible on a GetGameMapping() function

What does this do?

I have also took a different route to other emulators. Other emulators don't really extend their functionality beyond what is needed and what the developer might want to do. Most functions are set with extra parameters to extend its functionality and choose if certain parts of the functions are executed, such as:
Code:
private void MyVoid(bool clearBefore = false)
{
    if (clearBefore && _myDictionary.Count > 0)
    {
        _myDictionary.Clear();
    }
}

Small steps, but still progress.

What's the purpose of this?

I'm not trying to sound rude, but the changes you have decided to share are either bad practice or don't give any information at all. Perhaps you could share a little more information about your changes?
 

Seriosk

Programmer;
Oct 29, 2016
256
105
This isn't better at all. MySQL has an int data type for a reason. This is bad practice and doesn't improve performance or functionality at all.



What parts used the most memory and how did you reduce it?



What packets, and what did you do?



What does this do?


What's the purpose of this?

I'm not trying to sound rude, but the changes you have decided to share are either bad practice or don't give any information at all. Perhaps you could share a little more information about your changes?
About your mysql data int type thing, I never said it would increase performance, and I wasn't referring to item positioning like you probably thought I was (unsure).

I'll start with the first question, "What parts used the most memory and how did you reduce it?"
Mainly the console updating every 10 seconds as it was constant and was using a lot of resources when it could of easily been reduced.

Second question, "What packets, and what did you do?"
I thought it was a bit boring constantly reading a list of packets that I had completed so I stopped posting ID's and all that, mainly Catalog packets, initializing of opening catalog and loading pages etc.

Third question, "What does this do?"
It allows you to pass a Boolean to the void/method (what ever you call it) that decides if you want to clear the previously cached items in the dictionary, it's used in a different sense as what its written as, that was just an example to show you guys what I meant by that. You'll see a better purpose for it when you see it all put together and develop inside it.

Thanks for the interest and answering probably some questions I should of explained a bit more about, I just don't really bother going in to detail much unless asked.
 
Not much updates but I have been cleaning up a few of the methods today. It seems I was violating the SRP (Single Responsibility Principle) in that I was merging multiple actions into one method, I have now organised my methods better.
 
UPDATES - 01/02 15:52
I have been working on all the class constructors. Most constructors are over 50 lines long, yes you read that right, 50 lines long. I've organised constructor parameters better and lowered the amount of parameters also needed. Also fixed up a few very long switch statements that could be made shorter.

Random post, I counted 6 fields in the model classes for just a door. I have moved them in to a separate file.
 
Development still very much alive!
GameManager:
eb8d976d946a484ebc4d7dedc8b590b7.png
Server rewards:
058b92d1213c47478aa8949bf96fed04.png


SE:
5e46dfe820c340d2a3d37c6372338e89.png

 

JynX

Posting Freak
Feb 6, 2016
710
438
Looks good, glad to see you're back on this. Good luck with this and hope to see it released in the near future.
 

Seriosk

Programmer;
Oct 29, 2016
256
105
Looks good, glad to see you're back on this. Good luck with this and hope to see it released in the near future.
Thanks bud.

Coded the prize system, think its called Rewards on Plus/Azure? anyway.. I thought I would share the code for a change, as @LukeOx said, I don't really share much and explain things well so I'll try and keep you guys in the loop in the near future

Code:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Sahara.Base.Game.Players;

namespace Sahara.Base.Game.Prizes
{
    internal sealed class PrizeManager
    {
        private readonly ConcurrentDictionary<int, Prize> _prizes;
        private readonly ConcurrentDictionary<int, List<int>>  _prizeLogs;

        public PrizeManager()
        {
            _prizes = new ConcurrentDictionary<int, Prize>();
            _prizeLogs = new ConcurrentDictionary<int, List<int>>();

            LoadPrizes(false);
        }

        private void LoadPrizes(bool clearBefore)
        {
            if (clearBefore && _prizes.Count > 0)
            {
                _prizes.Clear();
            }

            using (var mysqlConnection = Sahara.GetServer().GetMySql().GetConnection())
            {
                mysqlConnection.OpenConnection();
                mysqlConnection.SetQuery("SELECT * FROM `server_rewards` WHERE `enabled` = @enabled");
                mysqlConnection.AddParameter("enabled", "1");

                var dataTable = mysqlConnection.GetTable();

                if (dataTable == null)
                {
                    return;
                }

                foreach (DataRow prizeRow in dataTable.Rows)
                {
                    _prizes.TryAdd(Convert.ToInt32(prizeRow["id"]), new Prize(Convert.ToInt32(prizeRow["id"]), Convert.ToInt32(prizeRow["reward_start"]), Convert.ToInt32(prizeRow["reward_end"]), Sahara.GetServer().GetUtility().GetPrizeTypeFromString(Convert.ToString(prizeRow["reward_type"])), Convert.ToString(prizeRow["reward_data"]), Convert.ToString(prizeRow["message"])));
                }

                mysqlConnection.CloseConnection();
            }
        }

        public void CheckPrizes(Player player)
        {
            if (player?.GetPlayerData() == null)
            {
                return;
            }

            foreach (var prizeEntry in _prizes.Where(prizeEntry => !ReceivedPrize(player.GetPlayerData().PlayerId, prizeEntry.Key)).Where(prizeEntry => prizeEntry.Value.Ready()))
            {
                prizeEntry.Value.OnReceive(player);
            }
        }

        public void LogReceivedPrize(int playerId, int prizeId)
        {
            if (!_prizeLogs.ContainsKey(playerId))
            {
                _prizeLogs.TryAdd(playerId, new List<int>());
            }

            if (!_prizeLogs[playerId].Contains(prizeId))
            {
                _prizeLogs[playerId].Add(prizeId);
            }

            using (var mysqlConnection = Sahara.GetServer().GetMySql().GetConnection())
            {
                mysqlConnection.OpenConnection();

                mysqlConnection.SetQuery("INSERT INTO `server_reward_logs` VALUES (@playerId, @prizeId)");
                mysqlConnection.AddParameter("playerId", playerId);
                mysqlConnection.AddParameter("prizeId", prizeId);
                mysqlConnection.RunQuery();

                mysqlConnection.CloseConnection();
            }
        }

        private bool ReceivedPrize(int playerId, int prizeId) => _prizeLogs.ContainsKey(playerId) && _prizeLogs[playerId].Contains(prizeId);
    }
}
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sahara.Base.Game.Players;
using Sahara.Core.Net.Messages.Outgoing.Packets.Inventory.Purse;

namespace Sahara.Base.Game.Prizes
{
    internal sealed class Prize : IPrize
    {
        private readonly int _prizeId;
        private readonly int _prizeStart;
        private readonly int _prizeEnd;
        private readonly PrizeType _prizeType;
        private readonly string _prizeData;
        private readonly string _prizeMessage;

        public Prize(int prizeId, int prizeStart, int prizeEnd, PrizeType prizeType, string prizeData, string prizeMessage)
        {
            _prizeId = prizeId;
            _prizeStart = prizeStart;
            _prizeEnd = prizeEnd;
            _prizeType = prizeType;
            _prizeData = prizeData;
            _prizeMessage = prizeMessage;
        }

        public bool Ready()
        {
            var now = Sahara.GetServer().GetUtility().GetUnixNow();
            return (now >= _prizeStart && now <= _prizeEnd);
        }

        public void OnReceive(Player player)
        {
            switch (_prizeType)
            {
                case PrizeType.None:
                    return;
                case PrizeType.Badge:
                    if (!player.GetPlayerData().GetBadgeManagement().HasBadge(_prizeData))
                    {
                        player.GetPlayerData().GetBadgeManagement().GiveBadge(_prizeData, true);
                    }
                    break;
                case PrizeType.Credits:
                    player.GetPlayerData().Credits += Convert.ToInt32(_prizeData);
                    player.SendMessage(new CreditBalanceMessageComposer(player.GetPlayerData().Credits));
                    break;
                case PrizeType.Duckets:
                    player.GetPlayerData().Duckets += Convert.ToInt32(_prizeData);
                    player.SendMessage(new HabboActivityPointNotificationMessageComposer(player.GetPlayerData().Duckets, Convert.ToInt32(_prizeData)));
                    break;
                case PrizeType.Diamonds:
                    player.GetPlayerData().Diamonds += Convert.ToInt32(_prizeData);
                    player.SendMessage(new HabboActivityPointNotificationMessageComposer(player.GetPlayerData().Diamonds, Convert.ToInt32(_prizeData)));
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
}
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sahara.Base.Game.Prizes
{
    internal enum PrizeType
    {
        Credits,
        Badge,
        Duckets,
        Diamonds, 
        None,
    }  
}
 

NeedForSpreed

Member
May 18, 2014
326
71
Thanks bud.

Coded the prize system, think its called Rewards on Plus/Azure? anyway.. I thought I would share the code for a change, as @LukeOx said, I don't really share much and explain things well so I'll try and keep you guys in the loop in the near future

Code:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Sahara.Base.Game.Players;

namespace Sahara.Base.Game.Prizes
{
    internal sealed class PrizeManager
    {
        private readonly ConcurrentDictionary<int, Prize> _prizes;
        private readonly ConcurrentDictionary<int, List<int>>  _prizeLogs;

        public PrizeManager()
        {
            _prizes = new ConcurrentDictionary<int, Prize>();
            _prizeLogs = new ConcurrentDictionary<int, List<int>>();

            LoadPrizes(false);
        }

        private void LoadPrizes(bool clearBefore)
        {
            if (clearBefore && _prizes.Count > 0)
            {
                _prizes.Clear();
            }

            using (var mysqlConnection = Sahara.GetServer().GetMySql().GetConnection())
            {
                mysqlConnection.OpenConnection();
                mysqlConnection.SetQuery("SELECT * FROM `server_rewards` WHERE `enabled` = @enabled");
                mysqlConnection.AddParameter("enabled", "1");

                var dataTable = mysqlConnection.GetTable();

                if (dataTable == null)
                {
                    return;
                }

                foreach (DataRow prizeRow in dataTable.Rows)
                {
                    _prizes.TryAdd(Convert.ToInt32(prizeRow["id"]), new Prize(Convert.ToInt32(prizeRow["id"]), Convert.ToInt32(prizeRow["reward_start"]), Convert.ToInt32(prizeRow["reward_end"]), Sahara.GetServer().GetUtility().GetPrizeTypeFromString(Convert.ToString(prizeRow["reward_type"])), Convert.ToString(prizeRow["reward_data"]), Convert.ToString(prizeRow["message"])));
                }

                mysqlConnection.CloseConnection();
            }
        }

        public void CheckPrizes(Player player)
        {
            if (player?.GetPlayerData() == null)
            {
                return;
            }

            foreach (var prizeEntry in _prizes.Where(prizeEntry => !ReceivedPrize(player.GetPlayerData().PlayerId, prizeEntry.Key)).Where(prizeEntry => prizeEntry.Value.Ready()))
            {
                prizeEntry.Value.OnReceive(player);
            }
        }

        public void LogReceivedPrize(int playerId, int prizeId)
        {
            if (!_prizeLogs.ContainsKey(playerId))
            {
                _prizeLogs.TryAdd(playerId, new List<int>());
            }

            if (!_prizeLogs[playerId].Contains(prizeId))
            {
                _prizeLogs[playerId].Add(prizeId);
            }

            using (var mysqlConnection = Sahara.GetServer().GetMySql().GetConnection())
            {
                mysqlConnection.OpenConnection();

                mysqlConnection.SetQuery("INSERT INTO `server_reward_logs` VALUES (@playerId, @prizeId)");
                mysqlConnection.AddParameter("playerId", playerId);
                mysqlConnection.AddParameter("prizeId", prizeId);
                mysqlConnection.RunQuery();

                mysqlConnection.CloseConnection();
            }
        }

        private bool ReceivedPrize(int playerId, int prizeId) => _prizeLogs.ContainsKey(playerId) && _prizeLogs[playerId].Contains(prizeId);
    }
}
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sahara.Base.Game.Players;
using Sahara.Core.Net.Messages.Outgoing.Packets.Inventory.Purse;

namespace Sahara.Base.Game.Prizes
{
    internal sealed class Prize : IPrize
    {
        private readonly int _prizeId;
        private readonly int _prizeStart;
        private readonly int _prizeEnd;
        private readonly PrizeType _prizeType;
        private readonly string _prizeData;
        private readonly string _prizeMessage;

        public Prize(int prizeId, int prizeStart, int prizeEnd, PrizeType prizeType, string prizeData, string prizeMessage)
        {
            _prizeId = prizeId;
            _prizeStart = prizeStart;
            _prizeEnd = prizeEnd;
            _prizeType = prizeType;
            _prizeData = prizeData;
            _prizeMessage = prizeMessage;
        }

        public bool Ready()
        {
            var now = Sahara.GetServer().GetUtility().GetUnixNow();
            return (now >= _prizeStart && now <= _prizeEnd);
        }

        public void OnReceive(Player player)
        {
            switch (_prizeType)
            {
                case PrizeType.None:
                    return;
                case PrizeType.Badge:
                    if (!player.GetPlayerData().GetBadgeManagement().HasBadge(_prizeData))
                    {
                        player.GetPlayerData().GetBadgeManagement().GiveBadge(_prizeData, true);
                    }
                    break;
                case PrizeType.Credits:
                    player.GetPlayerData().Credits += Convert.ToInt32(_prizeData);
                    player.SendMessage(new CreditBalanceMessageComposer(player.GetPlayerData().Credits));
                    break;
                case PrizeType.Duckets:
                    player.GetPlayerData().Duckets += Convert.ToInt32(_prizeData);
                    player.SendMessage(new HabboActivityPointNotificationMessageComposer(player.GetPlayerData().Duckets, Convert.ToInt32(_prizeData)));
                    break;
                case PrizeType.Diamonds:
                    player.GetPlayerData().Diamonds += Convert.ToInt32(_prizeData);
                    player.SendMessage(new HabboActivityPointNotificationMessageComposer(player.GetPlayerData().Diamonds, Convert.ToInt32(_prizeData)));
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
}
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sahara.Base.Game.Prizes
{
    internal enum PrizeType
    {
        Credits,
        Badge,
        Duckets,
        Diamonds, 
        None,
    }  
}
Looks good, good luck and carry on bro. Glad you continued this project :)

Skickat från min FRD-L09 via Tapatalk
 

Seriosk

Programmer;
Oct 29, 2016
256
105
I got a question @Sage . Have you started working on the pathfinder? :)

Skickat från min FRD-L09 via Tapatalk
Some work related to it has been completed such as the game map, although the structure and basics of pathfinder have been planned out, can't say its in a usable state at the moment.
 

NeedForSpreed

Member
May 18, 2014
326
71
Some work related to it has been completed such as the game map, although the structure and basics of pathfinder have been planned out, can't say its in a usable state at the moment.
I got an idea, it's up to you though. I think that the pathfinder should be like DreamPathFinder where it calculates closest tile instead of doing nothing like comet and plus, if the path isn't walkable. ( If the path is blocked or something) :)

Skickat från min FRD-L09 via Tapatalk
 

Seriosk

Programmer;
Oct 29, 2016
256
105
I'll definitely add that in, maybe as a configuration option so its optional? Also, please PM me any other ideas you may have as I do like that idea :)

Updates (tonight): I'm going to try and get most of the AI stuff out of the way tonight, pets and bots. Coding a new AI manager that handles AI globally across the whole emulator, not sure how Plus did it.
 

NeedForSpreed

Member
May 18, 2014
326
71
I'll definitely add that in, maybe as a configuration option so its optional? Also, please PM me any other ideas you may have as I do like that idea :)

Updates (tonight): I'm going to try and get most of the AI stuff out of the way tonight, pets and bots. Coding a new AI manager that handles AI globally across the whole emulator, not sure how Plus did it.
Cool, thanks bud, and I sure will, good luck and carry on! [emoji14]

Skickat från min FRD-L09 via Tapatalk
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
Make this available for Mono or Wine, because we need more emulators capable of running on Linux, so we dont have to go with useless Windows

Sent from my SM-G928F using Tapatalk
 

Seriosk

Programmer;
Oct 29, 2016
256
105
Make this available for Mono or Wine, because we need more emulators capable of running on Linux, so we dont have to go with useless Windows

Sent from my SM-G928F using Tapatalk
Windows is far from useless, anyway Mono Support will be implemented upon release.
 
Status
Not open for further replies.

Users who are viewing this thread

Top