Client Mods

The next stage of this project is going to involve a command to send the client off to a different server. Don’t actually want to change the client a whole lot because the more we do the more users have to customize and deal with. Don’t want to require a special client.

So wanted to look into client mods.

The demo

The source comes with a small demo client mod that just spits stuff out to the log. To enable this thing you have to enable client side mods. To do this you go to the settings, search for “client modding”, and set it to enabled/true.

You also have to add a new file to ./clientmods called “mods.conf”. In it you add “load_mod_preview = true”. Now the demo mod is added and enabled. It doesn’t do much, but it does allow you to print out the content of ‘core’ to see that it has a ‘disconnect’ function but no connect and no switch server functionality.

Finding the plugin point

So we need to add a new client mod command to ‘core’. First step is to understand the connect/disconnect procedure. Since we know we have a ‘disconnect’ function in lua, we look for where it is defined. That definition is in ./src/script/lua_api/l_client.{h,cpp}:

int ModApiClient::l_disconnect(lua_State *L)
{
    // protect against bad code...

    g_gamecallback->disconnect() // the one we want.

    // return the lua result to lua land.
}

We do a search for ‘g_gamecallback’:

find . -name "*.cpp" -exec grep g_gamecallback {} +

We learn that it is a MainGameCallback and is located in ./src/gui/mainmenumanager.h and it turns out it is just a bunch of flags bundled up in an object. WHY???

Well, it is used by the ClientLauncher in a menu handling loop within it’s “run” function:

while (m_rendering_engine->run() && !*kill &&
    !g_gamecallback->shutdown_requested)

Why would they chose to do this? This is where a little experience kinda helps. They did this so that this run loop and its decisions all happen in a single thread, while disconnects and such can come from any. This is one fairly straight forward method of solving that. Have disconnect calls not actually do any sort of disconnect activity, but simply request it be performed soon by just setting a simple boolean flag.

Analyzing this function in detail is what needs to happen. I already did some and it looks like I can simply add a new flag and a blob of data to add a “switch_server” command. There are flags in the loop to avoid showing the menu. So I should be able to just skip that start game menu and hop into the normal client connect procedure based on the information provided in the request.

This is nice because it’s a fairly safe thing. The client is still in charge of all communication that is needed to connect to a different place. It will still perform authentication as normal. Would be just as if you had selected it or entered it in the public server area. Yay! It’s possible that something this straight forward could get accepted into mainline and we would no longer need any special anything from the client.

Probably have enough to get a start.