Development Log - 2023-12-10
Author: b0in
Wow we built some modules this time.
We have an explosion of modules and functionality. The login server works, both the client side and the “HA0” side. You can turn off the rathena login-server and run my own login-server and it uhhh works! (I'm using a 2020-03-04aRagexe_patched.exe. Come bug if you want the NEMO patch list).
An quick explanation
This was not adequately explained in the previous posts so here is some details about rathena: it's actually 3 servers PLUS mysql running together. The 3 servers are login-server, char-server, and map-server. Each server connects to each other and interoperates, uses the mysqldb in various ways, and waits for connections to them from the r*gnarok client.
For now, what I have done is implement the login server. Both the comminication protocol between the login and char server AND the communication protocol between the login server and the client.
What works?
If you have an rathena server setup AND the right packet version for your ragexe client,
then you can run the char-server and map-server and point the char-server to the
crow instance of the login server within crow.game.omnisrv.
My clientinfo.xml points directly to 127.0.0.1/6900 but the char-server points to 6909:
% grep login conf/char_athena.conf
// The character server connects to the login server using this IP address.
//login_ip: 127.0.0.1
login_port: 6909
This was actually a breakthrough in designing some of the initial workflows: that the HA port and the client port do not actually need to be on the same TCP port like they are in rathena.
There are some bonuses to this: the code is simpler, each port can have its own security and firewall policies applied. There is also a drawback… more ports mean more complexity. More to do and more to potentially go wrong. There could be more unintended consequences down the line as well.
Module Statuses
crow.game.codec.api - [95%]
We designed a PacketReader interface that helps us further decouple the netty code from our API. We still need to do PacketWriter.
crow.game.codec.netty - [95%]
Not a bunch of changes. We have attempted to add ‘size’ as a packet
detail for dynamically sized packets but we are still not reading it property. AccountReg2StoreRequestHandler
is an example where we have size but still have to read it again at the start of fromPacket.
(NEW) crow.game.login.api, proto, and server [???]
These 3 modules constitute the required business logic objects, the protocol details, and the tcp server and business logic-tcp bridge code. I had originally wanted to keep it to two modules, proto and server, which would act as sort of an API and Impl. However, the login API constitutes shared objects between multiple servers, such as ha0… which we will get to.
(NEW) crow.game.ha0.proto and server [???]
In order to best code and test this server, I wanted to have it interact with existing rathena servers. (See note1). This ha0 proto and server act as the protocol objects and netty server, respectively, in order to provide a dedicated port for the rathena char-server to connect to.
As mentioned in the login module notes, the ha0.server requires objects from the login.api module. This constitutes shared state that these two servers need to share in order to function.
Here is a sequence diagram showing the flow of messages.
Uppercase messages are TCP messages encoded and
decoded via the module crow.game.codec.netty. The red boxes are TCP servers listening on dedicated ports. The
Blue boxes are in-memory singletons shared between all the other components. Everything encaspulated in the
black line is part of this codebase so far.
(NEW) The OMNISRV!!!
This module will eventually be a single jar file that just contains everything you need. For now, since we need our login server to connect to the existing rathena servers then the omnisrv does the following:
- import ha0 tcp server
- import login tcp server
- implement the interfaces needed for both of those servers.
- The UserAuthenticator, the UserLoader.
- Inject these implementations int the tcp servers and start them.
For now, the omnisrv connects to mysql but eventually, if and when we get a char-server and a map-server done, then the omnisrv should be able to run on it's own. No MySQL (unless you want it), no other servers, etc.
Here is the psuedocode for this, showing off how we can build our own implementation details (in the dot-dot-dots) and how we can toggle components on and off via environment variables or flags:
public class Main {
public static void main(String[] args) {
UserLoader userLoader = new ...;
ActiveUserCollection activeUserCollection = ...;
UserAuthenticator userAuthenticator = ...;
PendingAuthCollection authCollection = ...;
ServerCollection servers = ...;
LoginServerMain loginServerMain =
new LoginServerMain(
activeUserCollection, userAuthenticator, userLoader, servers, authCollection);
Thread thr1 = new Thread(loginServerMain);
thr1.start();
if(System.getenv("USE_HA0")) {
HA0ServerMain ha0ServerMain =
new HA0ServerMain(activeUserCollection, servers, userLoader, authCollection);
Thread thr2 = new Thread(ha0ServerMain);
thr2.start();
}
}
}
What's missing?
A whole lot! The ports and db instance details are hardcoded within omnisrv. The DB schema stuff is all hardcoded within omnisrv. Lots of missing protocol details. Accreg2 storage stuff.
There is so much manual dependency injection the whole thing begs for Guice or Spring or something else everyone hates but that become evidently necessary if your brain is broken like mine.
The omnisrv should be built into a standalone-jar but currently is not.
