The Road to Aeven
A long time ago I decided I wanted to make my own Endless Online, I even wrote Vult-R asking for old versions of the source code (I was a kid and not particularly well adjusted... not like that changed much.) so I could understand how it worked. I remember looking at the technology stack he had listed and wondering what each part was for.
Today's Music: https://www.youtube.com/watch?v=fngETb9TncM
Ultimately the most important thing to me is to make a game I would want to play, channeling those things that I loved about the games that had the most profound impact on me into something I can share with the world. Of course, this is easier said than done. The games that had the biggest effect on me are rather complex.
We're talking Morrowind, Final Fantasy XI, Ocarina of Time, Most of Bioware's catalog (Pre-Inquisition) and various MMOs and RPGs I played. The most important thing I found in MMOs for one thing is that if I made friends there I had much more fun and stayed wayyyyy longer.
Endless Online when I joined was very simple. Basically it was just a loot grind where you could talk to people. All enemies died in one hit and could not fight back, there was no experience, no leveling, no quests outside of crafting items. But I loved that game, I played it every chance I had and I had so many friends even though I was a shy and awkward kid.
Those friends were a large part of what made that game so engrossing to me. Without them I wouldn't have played very long at all. Another game where I made friends and had fun was Archage, we had a hell of a good time there. Also Dream of Mirror Online and FFXI... all these games I have the fondest memories of and all have one thing in common; friends.
Nowadays I am an anomic hermit, friends have grown apart and I haven't really made any new ones over the years because I became too absorbed in my own mind and projects to reach out. I hope that in my quest to build my own little Endless Online here where people will make friends and forge good memories to carry them through hard times. Maybe I'll even make some new friends along the way, who knows?
The goals for this game are:
- Create the Endless Online project I dreamed of as a kid
- Channel the things I like into it (Tamagotchi, Endless Online, Morrowind, Zelda, Music, etc...)
- Build a community within
- Maybe make a few dollars, though realistically if I was trying to get rich I would not be making games.
Welp, moving on... Today I suppose I have enough to get started on the apartment server. I'll need to modify the login server a bit of course, since it has to send the login token to the Apartment server in order to reliably transfer the player in.
I'll also need to make a base apartment scene and write the code in the client to connect and recieve, then set up the apartment for the player. Then of course I need to write the code to retrieve the character data and set that up in the client as well.
I may need to split the character data processing to it's own server but for now I will keep it simple with the idea I will probably have to do that later in mind.
Currently the Apartment Server will be responsible for Creating, Reading and Updating apartments, characters and geru, as well as running the main tick of the care system and all care system interactions players do.
Given that we're not tracking player or geru movement here I think it'll be able to handle everything fine, if not of course I can break off things into smaller sub-servers later on like I think I may need to do for the character data but I may not need to, ultimately it will depend on how I write the thing and how many players end up playing it.
I expect the apartment server as designed should be able to hold thousands of players since we're not having to process all their movement data or combat or anything like that and most interactions will be slow-paced as far as the server is concerned.
The Adventure server and Hub servers will be different, since we need to be aware of player position, interpolating the data from multiple clients and handling collisions and NPCs and all that. But that comes later on, for now I only have to concern myself with the apartments, geru and care systems.
Alright, so, where to begin? I suppose setting up the project for the Apartment server and getting it set up for container deployment would be wise.
I'll have the login server listen on port 14975 for the apartment server connections. The apartment server will connect and hand it's IP to the login server so if I have multiple apartment servers later it will be able to handle some sort of load balancing.
Now, since this is all going to run in containers I will have an auto-restart system built right in. Knowing that I can just exit the apartment server if the login server goes down or if on boot we can't reach it.
func _server_disconnected():
print("Login Server is DOWN")
get_tree().quit()
func _connected_fail():
print("Can not connect to login server! Exiting.")
get_tree().quit()
This also means I only have to close one server to get both to close during dev. Saves a second, but seconds add up.
Now that I have the code in place for the token exchange I will have to figure out how to make the network peers separate so both connections can exist simultaneously. Seems Godot doesn't handle that automatically, not sure why it would really or why I expected it to.
Simple enough, found someone else who did the same thing... well not exactly but they had the same problem of needing a secondary network peer and solved it. Saved me some R&D.
Alright, there was one issue, maybe two with this...
Setting the root node to self causes errors during polling (node not found) setting root node to actual ROOT fixes this. However...
ID sent from apt server: 431336182
Apt Server Registration ID: 431336182
The RPC ID of the Apartment server, so we can call it directly when we set tokens. It's not changing at all, it is set and stays that. I had to make sure because...
E 0:01:24.654 _send_rpc: Attempt to remote call unexisting ID: 431336182.
<C++ Error> Method failed.
<C++ Source> core/io/multiplayer_api.cpp:473 @ _send_rpc()
<Stack Trace> ApartmentConnection.gd:62 @ set_token()
ConnectionManager.gd:86 @ handle_login()
I think it may be accessing the RPC from the login server's network peer...
Yep, that's it. That is because I set root node to ROOT I think, but if I set it to self(the node in question, which is created as a Singleton and is part of the tree and IS where we are looking) we get a funny little error.
E 0:00:08.344 get_node: (Node not found: "APTLOGIN" (relative to "/root/APTLOGIN").)
<C++ Error> Method failed. Returning: nullptr
<C++ Source> scene/main/node.cpp:1465 @ get_node()
<Stack Trace> ApartmentConnection.gd:68 @ _process()
Alright, what if I make a node in the scene tree and add this script on there and call it the same thing?
Ah...
E 0:00:00.630 create_server: Couldn't create an ENet multiplayer server.
<C++ Error> Condition "!host" is true. Returned: ERR_CANT_CREATE
<C++ Source> modules/enet/networked_multiplayer_enet.cpp:101 @ create_server()
<Stack Trace> ApartmentConnection.gd:17 @ _ready()
It's not a port issue as far as I can tell, I have changed the port a few times and no dice.
Returning to the Singleton pattern I was previously using...
So I found the problem. You do not want to use the default network peer on a client connection when you are using a custom peer on the server. They both have to be default or custom and they both have to have the same name in the scene tree.
After rewriting the Apartment server's connection code I can now connect all the way through from the login to the Apartment server (sort of.) I will need to write yet another custom multiplayer peer on the Apartment server and then a custom one for the Client in order to handle the communication for them. This is fine.
Token is passed through to the Apartment Server from the login server as it should be and now we can connect the Client to the Apartment Server with it. The User ID there is internal to the servers and should never be given to any client or all hell could break loose.
I should encrypt the traffic for:
- Client <-> Login
- Login -> Apartment
- Login -> BBS
- Login -> Hub
- Hub -> Adventure
I could use a self-signed SSL certificate, I wonder if I can use PEM or if I should just use X.509... I should look into SSL and encryption for this soon, I know it's here because there's https built in... right?
It's 3:30 now and given the next major task is the Client <-> Apartment Server networking I think I will take my remaining time in the office to set up the Dockerfile and docker-compose, then make a few little wafer thin issues for encryption and the next steps I think I will have to take.
Tomorrow I will get our client connecting to the Apartment server, create the base apartment and a variant to test different accounts with different apartments loading correctly.
I should also test my redeployment system for the login server since I made so many changes to it today, the only other change I will have to make for a while will be adding the encryption to the connections so passwords and IDs aren't sent in plain text over the network.
So before I clock out I hope to have the Apartment Server core running on Valoria(The lab R710) and the redeployment of updated code being correctly handled by the containers.
Making sure the Apartment Server will go into infinite reboot when it can't see the login server
Alright, there's some interesting stuff going on when the Apartment Server inside it's container tries to connect to the Login Server. I have no problem connecting Apartment -> Login Container when I run Apartment from here.
But then I get to connecting from inside the container and it wont have it.
I wonder if there's some silly buggers with the ports in the container, gonna rebuild it and see.
I tried using a loopback IP, tried adding them to their own network, tried a few different NIC IPs on the server and no dice. Interesting.
It appears to be a normal timeout but why it's not able to reach I am not sure. I'll have to spend some time troubleshooting it tomorrow as it's time to clock out.
Glad I took the time to do this now and found there was an anomolous problem before I got too far, I will try running the container from my Pi server and see if that works before I leave... just curious.
This could come in handy, let's see...
Or not, the issues with containerized versions of godot server are numerous as it turns out, I am sure this is a library issue and I would need to get the right sort of libs for ARM I guess and it's just beyond what I am going to bother with right now. Suffice it to say it wont work on Pi4 without some elbow grease.
Troubleshooting to be resumed tomorrow.