xq3e / engine

https://t.me/x_q3e
GNU General Public License v2.0
5 stars 3 forks source link

Does not detect OSP in baseq3 #1

Open wizq3 opened 3 years ago

wizq3 commented 3 years ago

I know a few people who are interested in this engine because of scoreboard but our servers run in baseq3 but support OSP clients. I believe OSP clients check if OSP server by looking at server var "gameversion" = "OSP v1.03a" not by looking at fs_game. Would it be possible for you to have engine check that too? Or at least add some local setting to override it. You can find our servers and discord invite from q3retro.com. Thank you.

JKornev commented 3 years ago

Hi,

The engine itself was developed on OSP mode and if I open all features for vanilla q3 (baseq3) or any other mode it's not probably going to work correctly cuz internal stuff on OSP is different to stuff on other modes. I checked xq3e engine in the past with vanilla q3, cpma, e+ etc and it doesn't work good. To be compatible with any additional mode it requires to make code changes, test and fix all features one by one.

We planned to make an engine compatible with vanilla q3, cpma, e+ modes but for now a project is frozen. So expect no way to run it with a scoreboard on baseq3.

Regards, JK

wizq3 commented 3 years ago

I understand you can't support special scoreboard with baseq3 clients. What I was trying to say is you can run OSP server in baseq3, and both vanilla and OSP clients can play, some have OSP some do not. I am only interested in making engine work with OSP clients. From OSP docs:

// osp_gamename <0|1> // Allows OSP to run as "baseq3" for UI server browser filtering. // This allows server ops to let clients use the in-game browser // and select their server if the client uses the FFA/1v1/etc. // filter types. // 0 - Shows up as "FFA/1V1/TDM/CTF/???" // * 1 - Shows up as "osp" // ---> Note: To use this properly, you will have to put everything // (configs, subdirectories, etc.) in the baseq3/ directory, copy // the "game" .pk3 in the paks/ directory into the baseq3/ // directory and rename it to something like "zzzosp-game099.pk3"

OSP clients check if server is running OSP by looking at server cvar "gameversion" not by checking "fs_game" since it can be baseq3. You can support it easily with this modification of UpdateSystemInfo in x_gamestate.c:

static void UpdateSystemInfo()
{
    char* systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SYSTEMINFO];
    char* serverInfo = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO];
    char* fs_game = Info_ValueForKey(systemInfo, "fs_game");
    char *gameversion = Info_ValueForKey(serverInfo, "gameversion");

    if (!strcmp(fs_game, "osp") || !strcmp(gameversion, "OSP v1.03a"))
        xmod.gs.mode = ModeOSP;
    else if (!strcmp(fs_game, "cpma"))
        xmod.gs.mode = ModeCPMA;
    else if (!strcmp(fs_game, "excessiveplus"))
        xmod.gs.mode = ModeExcessivePlus;
    else if (!strcmp(fs_game, "baseq3") || !*fs_game)
        xmod.gs.mode = ModeBaseQ3;
    else
        xmod.gs.mode = ModeUnknown;

    int svcheats = atoi(Info_ValueForKey(systemInfo, "sv_cheats"));
    xmod.gs.svcheats = (svcheats ? qtrue : qfalse);

    ParseXModCommands(systemInfo);
}

I just tried it and it works.

Edit: Actually you might want to check gameversion first, in case fs_game is "baseq3" and not blank. Otherwise first condition might be true. I'm not sure but fs_game might always be blank if baseq3 so first condition may never be true? I updated function.

wizq3 commented 3 years ago

Okay I realized the proper way to detect OSP is to compare the pak checksums. I kind of forgot about that but I think OSP client is checking server checksums not gameversion so that was my mistake. I added a simple method to check for osp checksums which can be used against server referenced paks and client referenced paks to know if both server and client are using OSP.

Also, in my testing I realized that your custom scoreboard does work with baseq3 without any OSP but the problem was you were only checking if "fs_game" was "baseq3" but it was always "" (empty) when I tried it so mode was always ModeUnknown. Once I added condition to treat "" same as baseq3 it worked.

Here is the final code:

static qboolean HasOspPak(const char *referencedPaks)
{
    // zz-osp-pak0, zz-osp-pak1, zz-osp-pak2, zz-osp-pak3
    static const char *osp_paks[] = { "1690942878", "1324571387", "68859308", "-1352694134" };
    int i;

    // you could use Com_TokenizeString instead
    for (i = 0; i < ARRAY_LEN(osp_paks); i++) {
        if (strstr(referencedPaks, osp_paks[i]))
            return qtrue;
    }
    return qfalse;
}

static void UpdateSystemInfo()
{
    char *systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SYSTEMINFO];
    char *fs_game = Info_ValueForKey(systemInfo, "fs_game");

    if (!*fs_game || !strcmp(fs_game, "baseq3"))
        xmod.gs.mode = ModeBaseQ3;
    else if (!strcmp(fs_game, "osp"))
        xmod.gs.mode = ModeOSP;
    else if (!strcmp(fs_game, "cpma"))
        xmod.gs.mode = ModeCPMA;
    else if (!strcmp(fs_game, "excessiveplus"))
        xmod.gs.mode = ModeExcessivePlus;
    else
        xmod.gs.mode = ModeUnknown;

    // check if OSP is loaded in baseq3 instead
    if (xmod.gs.mode == ModeBaseQ3)
    {
        char *sv_paks = Info_ValueForKey(systemInfo, "sv_referencedPaks");
        char *cl_paks = FS_ReferencedPakChecksums();
        if (HasOspPak(sv_paks) && HasOspPak(cl_paks))
            xmod.gs.mode = ModeOSP;
    }

    int svcheats = atoi(Info_ValueForKey(systemInfo, "sv_cheats"));
    xmod.gs.svcheats = (svcheats ? qtrue : qfalse);

    ParseXModCommands(systemInfo);
}