mleo1
-
Content Count
314 -
Joined
-
Last visited
Reputation Activity
-
mleo1 reacted to pan in Multi-threaded Hercules
Long time no see!
I've been dabbling with adding multi-thread support to Hercules for quite some time and even started quite a few server projects from scratch, and having failed in most of my attempts - last year I tried again with a new core design and it seems to be working so far. A lot of the systems that the server core is reliant were reworked, I believe some of these changes can even be used upstream but they would need to be revised first. This is mostly a proof of concept.
I'm still planning on finishing the map-server but as of now only login and char servers have multi-thread enabled - I didn't test with multiple users yet. There's no linux / FreeBSD support because I want to have everything in working condition before trying to add another I/O paradigm, the architecture is very reliant on the way that this module works so I thought it'd better to implement the whole server before trying to add other paradigms.
Lately I haven't got much free time to finish the map-server, but sometime later this year I think I can finish it.
The code is at https://github.com/panikon/HerculesMT , I forked from stable v2021.08.04
Server architecture
Hercules employs a multi-server approach in order to better load balance player requests, so for each game world there'll be at least three separate program instances running at all times. These instrances are: login-server, char-server and map-server. Each of which can only access a subset of the world's SQL tables and is responsible for a different step of the game experience.
Authentication and account database changes are segregated to the login-server, while character selection and character specific information are to the char-server, and the actual gameplay to the map-server.
The login-server is the player entry-point and can be responsible for multiple different world instances, so it's possible to use the same account table (login) for multiple worlds (char-server + map-server) and to dynamically change their IP without needing to push a new patch. After authentication the player is queried for which service they'll use and then the server relays the proper address so the client can connect.
In the char-server the player usually is queried again for a four digit PIN (PACKETVER >= 20180124), after which they can select which playable character will be used to play. The server then relays the address of the proper map-server to the client.
A single world instance can have multiple map-servers where each is responsible for a zone (set of maps), all inter map connectivity is managed by the char-server. When the player requests to change character the char-server IP is then relayed.
A single map-server can be responsible for multiple different zones, and each will be a different thread.
Relationship of each of the possible server instances
Brown - Game world | White - program instances
Core design
All servers are multi-threaded. Basic server functions are assigned to different threads:
Console (../src/common/console.c):
This thread is responsible for all console input operations. Timer (../src/common/timer.c):
The timer thread manages the `timer_heap` and dequeues timer actions from the `timer_queue`. Each timer can be ran in a different thread depending on the `timer_target`, this is accomplished by either queuing an action in one of the available action queues (`target_id`) or by running the specified function in the main timer loop (`do_timer`).
Other threads queue different timer actions (add, delete, set tick) to the `timer_queue`.
The timer module is also responsible for tick acquiral via (`timer->gettick` and `timer->gettick_nocache`). Message(../src/common/showmsg.c):
The message thread is used to synchronize the output of multiple different threads, each call to `Show*` instead of being directly outputted to `STDOUT` is queued in the `showmsg_queue` and then dequeued by the main thread function `showmsg_worker`. I/O Worker(../src/common/socket.c):
All I/O operations are asynchronous and implemented via I/O completion ports and a thread pool. The main workers are defined in `socket_worker` and after a operation is dequeued it's converted into an action (`socket_operation_process`) that is then queued to the proper action worker (each session has a responsible worker, and it's obtained by the I/O worker via `action->queue_get`).
These workers don't execute any "business logic" so we can minimize the time that they are blocked by any given operation, and also so we can better isolate different session groups without having to take into account in I/O operations (e.g. in map-server each zone has a different action worker and multiple actions can be queued simultaneously without having to block any of the threads for a longer period of time). Action Worker(../src/common/action.c):
Action workers perform all the "business logic" of each of the servers, and each is responsible for a different session group. After every action loop all send actions are queued to the completion port.
Login-server:
Each char-server connection has a different worker. Player connections are randomly assigned. Char-server:
Each map-server connection has a different worker. Player connections are randomly assigned. Map-server:
Player connections are assigned depending on the current map according to the different configured zones. The char-server connection is randomly assigned.
Thread relationships
-
mleo1 reacted to Yommy in I miss Ind :'(
If you read this, please email or message me.
I miss you lots
<3
-
mleo1 reacted to Kubix in Queue BG rewrite
Hello!
I find eAmod BGs in public and rewrite some src and scripts for Hercules.
BG:
Conquest Rush Flavius TD Register - @joinbg or NPC, leave - @leavebg
This is queue BG with multiple windows checking by Gepard ID or IP.
Items:
56 BG consumable items (using only on BG) with boxes 56 WoE consumable items (using only on WoE) with boxes Item list New script commands:
bg_reward bg_team_reveal flooritem flooritem2xy bg_getitem bg_getkafrapoints bg_single bg_create_team (added OnPCDie and OnPCLogout events.) Settings:
OnInit: // ===== Multiple Windows checking by ? // = 1 - Gepard Shield // = 2 - IP .MultipleCheck = 1; // ===== BG Colors setarray .BG_Color$[0], "0xDDA0DD", "0x7CCD7C", "0xFFA500"; // ===== BG NPC & Arena Names setarray .BG_Names$[0], "Rush", "Flavius TD", "Conquest"; setarray .BG_Arena$[0], "Rush", "Flavius_TD", "Conquest"; // ===== BG Player Amount setarray .BG_Min[0], 2, 2, 2; setarray .BG_Max[0], 30, 30, 30; // ===== BG Locations setarray .BG_Map$[0], "rush_cas04", "bat_b03", "schg_cas06"; // ===== BG X/Y Coordinates setarray .BG_GuillX[0], 270, 390, 264; setarray .BG_GuillY[0], 292, 10, 379; setarray .BG_CroixX[0], 270, 10, 295; setarray .BG_CroixY[0], 288, 290, 379; bindatcmd "joinbg", strnpcinfo(0) + "::OnJoinBG", 0, 99; bindatcmd "leavebg", strnpcinfo(0) + "::OnLeaveBG", 0, 99; // ===== Time to flood in seconds. .Flood_Time = 180; // ===== Enable debug mode? .debug = false; Sorry, not all instructions translated to English now.
Github: https://github.com/kubixservice/QueueBG
-
-
-
-
-
mleo1 reacted to Dastgir in Community Help Needed for Quick Development.
Hello all,
You might see we don't have quite a lot npc scripts(from official servers), thats mostly because of lack of info, not due to lack of active scripters..
So what can be done?
Well, alot of people does play official servers(iRO,kRO, or any other) and most script matches even if its iRO,jRO,idRO,kRO...
So we can boost the development with your help.
Someone might wonder if what would happen if some npc/instances are exclusive to jRO only or any other server, well, we might still need those, those may/may not be added to repository, but that will make a nice release over script release section.
Almost all servers have Replay System, we can record the gameplay of any official script, so that can help us get all info we want...
So I request you (if you want new official scripts), (and if you play ANY official server), that either record a video or start the replay, and share the replay/video file, so we can get it quickly converted, and release it..
Or some of your friends might play those servers?, you can ask them for videos/replays?
If you don't want to share the replay/video publicly, you can PM me as well with the file.
I bet, that we will try our best to implement it quickly.
-
mleo1 reacted to AnnieRuru in Last Man Standing (using queue iterator script commands)
Haru has fixed the queue iterator script commands
its time to spread out this technique
Download: 1.2
script
Make sure your hercules server is compile after 2015-12-21
errr ... maybe too strict xD
good for server owner and scripter alike
this can use in live server, and also can be a reference script for scripters
Next, might want to bump the battleground queue again xD
-
mleo1 reacted to Dastgir in hello can you code this for me?
It wasn't until now: https://github.com/dastgir/HPM-Plugins/blob/master/src/plugins/storeequip.c
-
mleo1 reacted to Samuel in hello can you code this for me?
there's a command plugin for this, i think dastgir uploaded an updated version in his git repo
-
-
mleo1 reacted to Z3R0 in Which rates do you prefer?
maybe so @@Mysterious but to me it's the journey not the destination
-
mleo1 got a reaction from jTynne in [Release] ExtendedBG for Hercules (with eAmod BG modes)
I can't wait to leech
-
mleo1 reacted to AnnieRuru in (Guild) Antagonism System
writing this as patch is just a few line
src/map/battle.c | 7 +++++++ 1 file changed, 7 insertions(+)diff --git a/src/map/battle.c b/src/map/battle.cindex 24f39a3..3d3284e 100644--- a/src/map/battle.c+++ b/src/map/battle.c@@ -6020,6 +6020,13 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if( (s_bl = battle->get_master(src)) == NULL ) s_bl = src; + if ( s_bl->type == BL_PC && t_bl->type == BL_PC ) {+ TBL_PC *sd = BL_CAST( BL_PC, s_bl );+ TBL_PC *pl_sd = BL_CAST( BL_PC, t_bl );+ if ( guild->check_alliance( sd->status.guild_id, pl_sd->status.guild_id, 1 ) && !map->list[sd->bl.m].flag.town && !map->list[sd->bl.m].flag.nowarpto )+ return 1;+ }+ if ( s_bl->type == BL_PC ) { switch( t_bl->type ) { case BL_MOB: // Source => PC, Target => MOBits more fun to make this as pluginhttp://upaste.me/28fd11097df8e9a10
-
-
mleo1 reacted to kyeme in Progress bar
In official, you're not able to move when the ProgressBar is still active. I'm also the one who report this.
Topic: http://herc.ws/board/tracker/issue-7380-showprocgressbar-improper-behaviour/?gopid=18578#entry18578
https://github.com/HerculesWS/Hercules/commit/962d203f95fd8b81d504f60aa28bb17cc268395d
-
mleo1 reacted to - Mariel in [Release] ExtendedBG for Hercules (with eAmod BG modes)
You want sexy pics of mine Dastgir? P.S. I'm a guy.
-
mleo1 reacted to Dastgir in [Release] ExtendedBG for Hercules (with eAmod BG modes)
Today's update: optimizing memory usage..
Upcoming weeks may see the finished product...
-
mleo1 got a reaction from guihleao in Loki Launcher
dunno man, check new just tested vb6 on win10, lel still use this they have restore login window diff
-
mleo1 reacted to Tokeiburu in Thor Patcher and Auto-Updater
Heya,
If you're going to do a patcher via C#, then you can download GRF Editor's sources over here : http://www.mediafire.com/download/7z6hkdag4ayj8rs
Add a reference to the dlls found in the "Output Libraries" folder to your project and you can use the following code to get you started :
using System;using System.Diagnostics;using System.IO;using System.Windows.Forms;using GRF.Core;using GRF.FileFormats.RgzFormat;using GRF.FileFormats.ThorFormat;using GRF.IO;using Utilities.Extension;namespace TestPatcher { public partial class Form1 : Form { public Form1() { InitializeComponent(); Patch(); } public void Patch() { var patchesPath = @"C:Patches"; var patcherExeName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName); var roDirectory = Directory.GetCurrentDirectory(); var serverGrfName = @"server.grf"; var temporaryGrfName = @"temp.grf"; using (var output = new GrfHolder(temporaryGrfName, GrfLoadOptions.New)) { foreach (var patchFile in Directory.GetFiles(patchesPath)) { if (patchFile.IsExtension(".grf", ".gpf")) { using (var grf = new GrfHolder(patchFile)) { output.QuickMerge(grf); } } else if (patchFile.IsExtension(".rgz")) { using (var rgz = new Rgz(patchFile)) { if (rgz.Table.ContainsFile(patcherExeName)) { // Updating on this executable, do something...! throw new NotImplementedException(); } foreach (var entry in rgz.Table) { entry.ExtractFromRelative(roDirectory); } } } else if (patchFile.IsExtension(".thor")) { using (var thor = new Thor(patchFile)) { if (thor.Header.UseGrfMerging) { string targetGrf = thor.Header.UseDefaultTargetGrf ? serverGrfName : thor.Header.TargetGrf; if (string.IsNullOrEmpty(targetGrf)) throw new Exception("THOR extraction failed : no target GRF identified."); if (String.Compare(serverGrfName, targetGrf, StringComparison.OrdinalIgnoreCase) == 0) { output.QuickMerge(thor.ToGrfHolderQuick()); } else { using (var grf = new GrfHolder(targetGrf, GrfLoadOptions.OpenOrNew)) { grf.QuickMerge(thor.ToGrfHolderQuick()); } } } else { if (thor.Table.ContainsFile(patcherExeName)) { // Updating on this executable, do something...! throw new NotImplementedException(); } foreach (var entry in thor.Table) { entry.ExtractFromRelative(roDirectory); } } } } } using (var serverGrf = new GrfHolder(serverGrfName, GrfLoadOptions.OpenOrNew)) { serverGrf.QuickMerge(output); } } GrfPath.Delete(temporaryGrfName); } }}
Obviously this is not optimized and errors are not handled at all, but it yields good results nonetheless. I would definitely not recommend you to start from scratch to make a patcher.
-
-
mleo1 reacted to zackdreaver in Client Translation Project
Yes, but i prefer 3 main servers in order :
kRO > iRO > jRO
-
mleo1 got a reaction from JulioCF in Tree of Savior
https://forum.treeofsavior.com/t/tree-of-savior-eng-ver-beta-test-schedule/3392
-
mleo1 got a reaction from Akaneharuka in RoBrowser play Ragnarok in the browser is it real ?
yep test it, some guys even makes a browser app in smartphones to link to their robrowser