Pages: 1 2 3 [4] 5 6 7
  Print  
Author Topic: The server-side demos thread, rebooted!  (Read 110598 times)
Gig
In the year 3000
***

Cakes 45
Posts: 4386


WWW
« Reply #75 on: February 24, 2012, 09:12:21 AM »

I will try some tests with that game_restart <modname> command in the next days...
Logged

I never want to be aggressive, offensive or ironic with my posts. If you find something offending in my posts, read them again searching for a different mood there. If you still see something bad with them, please ask me infos. I can be wrong at times, but I never want to upset anyone.
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #76 on: February 24, 2012, 09:38:04 AM »

I will try some tests with that game_restart <modname> command in the next days...

Ok, I can tell you from my tests that to be used effectively, one needs to issue an /exec <config.cfg> just after because the config is completely unloaded, or just to do tests you at least need to load a map /map oasago2 for example. But it really hotswap the gamemod!

I'll try to include the gamemod in the demos files Smiley

-------

Another example of the resetting of the CS_SCORES:
Code:
DebugGBOgameCommand: print "UnnamedPlayer^7 captured the BLUE flag!
"
broadcast: print "UnnamedPlayer^7 captured the BLUE flag!\n"
DebugGBOserverCommand: print "UnnamedPlayer^7 captured the BLUE flag!
"
broadcast: print "UnnamedPlayer^7 captured the BLUE flag!\n"
DebugGBOconfigString: 6 2
DebugGBOconfigString: 23 00
DebugGBOgameCommand: scores 4 2 0 39840 0 14 13 1 0 0 11 0 0 0 0 0 0 2 0 1 5 0 1 0 0 34 0 0 0 0 0 0 0 0 2 3 0 1 0 0 12 0 0 0 1 0 0 0 0 3 2 0 1 0 0 43 0 0 0 0 0 0 0 0
DGBO G_SET_CONFIGSTRING: 6 0
DGBO G_SET_CONFIGSTRING: 7 0

/EDIT: ok I've located where it comes from, I've made a mistake just before, I misplaced my debug print.
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #77 on: February 24, 2012, 09:44:29 AM »

Grey Matter, a precise question: since there's no nice way to access gamecode vars from engine, can it be done the other way around? accessing engine's vars from gamecode?
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #78 on: February 24, 2012, 10:12:23 AM »

@Grey Matter, I'm still interested in the previous question even if now I've fixed the problem because it came from a bug Wink

--------------

Capture scores FIXED and player status FIXED too !!!!!! All main problems are FIXED NOW!!!!

For those that are interested, it simply came from a buggy check that Amanieu implemented:

Code:
void SV_SetConfigstring (int index, const char *val) {
int i;
client_t *client;

if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
Com_Error (ERR_DROP, "SV_SetConfigstring: bad index %i\n", index);
}

// Don't allow the game to overwrite demo player configstrings
if ( sv.demoState == DS_PLAYBACK && index >= CS_PLAYERS && index < CS_PLAYERS + sv_democlients->integer ) {
return;
}
...

As you can see, when SV_SetConfigstring was called to set a client configstring, it was simply ignored. This was a safeguard against the engine resetting configstrings (which was happening for CS_SCORES1/2 because I didn't add CS_SCORES1/2 in this check).

BUT, the problem is that in the demo, it was SV_SetConfigstring that was called to set democlients configstrings! So it was rejected, even if it was legit!

I simply moved this check directly in the trap calls:

Code:
case G_SET_CONFIGSTRING:
// Don't allow the game to overwrite demo configstrings
if ( sv.demoState != DS_PLAYBACK ) {
SV_SetConfigstring( args[1], VMA(2) );
}

And now it works beautifully, because it both prevents the game from overwriting the configstrings with irrelevant data, and accepts legit configstring setting from the demo! (edit: this fix above is not completely correct: it fixes the problem stated above but other problems are spawned such as allowing normal clients configstrings to be overwritten, else real clients connecting during a playback won't have any infos loaded inside, this is fixed in my local repository by adding a few more conditions in the check).

-------------

Ok so from now on, my plan is to fix a few other things, try the server-side demos with other gametypes, record a few complete games (with capturelimit/timelimit/fraglimit reaching), and add a few more important data recording (such as SendConsoleCommand).

The completed patch should be released soon!
« Last Edit: February 25, 2012, 08:29:32 PM by GrosBedo » Logged
grey matter
Member


Cakes 8
Posts: 381

>9k


« Reply #79 on: February 24, 2012, 10:50:38 AM »

since there's no nice way to access gamecode vars from engine, can it be done the other way around? accessing engine's vars from gamecode?

No, not directly. You can "access" anything that the engine wraps via it's trap calls. Or store your data in the common player struct, user commands, cvars or configstrings.
Maybe you find some buffer overflow, but usually engine and gamecode are not supposed to access each other's memory directly. Gamecode should not be able to modify any of the engine's memory (possible security problem), the engine on the other hand controls the entire gamecode (at least in QVM compile and interpret) environment, but does not know that e.g. player struct + offset 0xDEADBEEF is splashMethodOfDeath. You can of course access that very location of memory if your engine hack is just targeted at that specific gamecode, but you rather shouldn't.

Just to make sure, you are talking about e.g. structs/fields like svs.nextHeartbeatTime, svEntity_t.areanum in engine and level.voteExecuteTime, gentity_t.gentity in gamecode?
You can easily access and modify c-vars in both directions.
Logged

This space is for rent.
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #80 on: February 24, 2012, 10:53:45 AM »

@Grey Matter: ok thank's a lot! And what about client_t, is it also shared?
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #81 on: February 25, 2012, 08:20:22 PM »

MEMENTO: Understood another thing about player's status management: clients configstrings are derived from their userinfo string.

Clients configstrings are constructed in the gamecode, in g_client.c in function ClientUserinfoChanged( int clientNum ):

Code:
void ClientUserinfoChanged( int clientNum ) {
...
// send over a subset of the userinfo keys so other clients can
// print scoreboards, display models, and play custom sounds
if (ent->r.svFlags & SVF_BOT)
{
s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d",
client->pers.netname, team, model, headModel, c1, c2,
client->pers.maxHealth, client->sess.wins, client->sess.losses,
Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader );
}
else
{
s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d",
client->pers.netname, client->sess.sessionTeam, model, headModel, redTeam, blueTeam, c1, c2,
client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader);
}

trap_SetConfigstring( CS_PLAYERS+clientNum, s );

// this is not the userinfo, more like the configstring actually
G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s );

And that explains a lot of things! Actually, this explains why players statuses couldn't be updated in the scoreboard (even if now I could do it by a clever manipulation of configstrings), why configstrings would get reset if I didn't prevent the engine from rewriting them (see my post above about CS_SCORES1/2), and why this damn ClientUserinfoChanged wasn't logical when I was debugging (could not find where these configstrings came from, now I know! from userinfo!).

Now it makes no doubt as to the cause why Amanieu's patch was so buggy, it left a big part of the players management aside.

Also as a side-note, all client_t fields (client_t is, with player_t and gentity, the 3 main vars for players management) can be almost completely filled using a single userinfo string by using the function SV_UpdateUserinfo_f() which:
1- store the new userinfo string to the client.
2- call SV_UserinfoChanged to fill the other fields of client_t by deriving from userinfo string and some other functions call (eg: IP is directly fetched from networks functions).
3- issue a vm_call to update server gamecode and broadcast change to every clients (GAME_CLIENT_USERINFO_CHANGED).

Also, there are 2 main entries in the engine to set userinfo:
- G_SET_USERINFO trap in sv_game.c, which then calls SV_SetUserinfo() in sv_init.c (but this function only store the new userinfo, step 2 and 3 aren't processed - I suspect it's an error because name is copied manually when SV_UserinfoChanged could be used instead to fill all the blanks, name included). Not sure about this one.
- SV_UpdateUserinfo_f() in sv_client.c, which does all the steps outlined above.
- It seems there's a third one, at map_restart or when a client connects (because of client->csUpdated? in SV_UpdateConfigstrings() ?).
« Last Edit: February 25, 2012, 08:49:21 PM by GrosBedo » Logged
Gig
In the year 3000
***

Cakes 45
Posts: 4386


WWW
« Reply #82 on: February 26, 2012, 05:51:52 AM »

Gig, could you please add it to the wiki please? I don't know where this should belong, but it's important enough to be noted in the wiki.

Okay, I wrote about the "game_restart <modfolder>" command here:
(DO NOT LINK) h t t p s : / / openarena . wikia . com/wiki/Manual/Using_mods#How_to_launch_a_mod
(DO NOT LINK) h t t p s : / / openarena . wikia . com/wiki/Command_console#Some_commands
(DO NOT LINK) h t t p s : / / openarena . wikia . com/wiki/FAQ#When_I_launch_a_Mod.2C_the_sound_stops_working

Bye! Smiley
Logged

I never want to be aggressive, offensive or ironic with my posts. If you find something offending in my posts, read them again searching for a different mood there. If you still see something bad with them, please ask me infos. I can be wrong at times, but I never want to upset anyone.
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #83 on: February 26, 2012, 01:54:40 PM »

@Gig: thank's a lot, that's perfect!
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #84 on: February 26, 2012, 07:41:29 PM »

News: userinfo is correctly updated and a few other things fixed. I also reordered the code a lot to aggregate as much changes as possible in the new sv_demo.c file (eg: all checks that were previously done in standard Q3 functions are now done directly in sv_demo.c functions), and I cleaned the code a lot. I will do some more cleaning by splitting the demo read frame function into several parts (because for now it's a BIG and messy switch, not really readable nor extendable). Also added a lot of comments, should ease a lot future modifications of this module.

I still have a few other things to fix, notably the health updating problem. Player's health is still not updated, I don't yet know if it's because the field is not properly recorded or not properly replayed.

/EDIT: forgot to say that userinfo is filtered (easy using Info_RemoveKey): cl_guid and ip are removed, cl_voip is set to 0 (anyway voip packets aren't recorded at all).
« Last Edit: February 27, 2012, 08:08:15 AM by GrosBedo » Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #85 on: February 27, 2012, 09:42:09 AM »

MEMENTO: about team management:

- teamcvarset only done at clientbegin (teamcvarset updates the cvars g_blueTeamClientNumbers and g_red... that contains the clientID of each player belonging to the team).
- broadcastteamchange done at clientconnect (broadcastteamchange() notify other clients about a team change for this client).
- clientuserinfochanged just trap_setconfigstring from userinfo and client fields (such as sessionTeam)
- setteam auto broadcastteamchange and clientuserinfochanged
- SV_DropClient calls ClientDisconnect which calls trap_SetConfigString to set an empty client configstring (since it will be blocked at replaying, we have to do it ourselves)
- ClientBegin only called when team change or at level load or a client connects (this is what is said in the comment)
Logged
sago007
Posts a lot
*

Cakes 62
Posts: 1664


Open Arena Developer


WWW
« Reply #86 on: February 27, 2012, 11:37:50 AM »

- teamcvarset only done at clientbegin (teamcvarset updates the cvars g_blueTeamClientNumbers and g_red... that contains the clientID of each player belonging to the team).
These cvars are OpenArena specific. They are used to limit VOIP to your own team.
Logged

There are nothing offending in my posts.
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #87 on: February 27, 2012, 01:27:22 PM »

@sago007: AH OK! That explains a lot of things! So i do not need to manage them in demos (anyway they will be since I now completely simulate demo clients management).

/EDIT: thinking about it, why is TeamCvarSet() only called in ClientBegin? There are other ways that a client can be put in a team without ClientBegin being summoned (eg: forceteam?). Putting it in the SetTeam() function seems more logical as it is the standard way for the engine to manage teams.
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #88 on: February 28, 2012, 08:19:56 AM »

MEMENTO: gamecode management of clients statuses:

in cg_local.h
Code:
// each client has an associated clientInfo_t
// that contains media references necessary to present the
// client model and other color coded effects
// this is regenerated each time a client's configstring changes,
// usually as a result of a userinfo (name, model, etc) change
Logged
sago007
Posts a lot
*

Cakes 62
Posts: 1664


Open Arena Developer


WWW
« Reply #89 on: February 28, 2012, 09:28:03 AM »

Putting it in the SetTeam() function seems more logical as it is the standard way for the engine to manage teams.
Yes, it would be more logical but SetTeam is not called if the player start on a team (after a map-change).

Quote
/*
===========
ClientBegin

called when a client has finished connecting, and is ready
to be placed into the level.  This will happen every level load,
and on transition between teams
, but doesn't happen on respawns
============
*/

ForceTeam is bugged if ClientBegin is not executed before the next respawn. It might be bugged. I know my shuffle team is bugged that is why it always execute a map_restart afterwards so that all necessary logic is executed.
Logged

There are nothing offending in my posts.
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #90 on: February 28, 2012, 11:27:51 AM »

@sago: ok thank's for the precision Smiley

----

News: fixed a few more stuffs, it becomes more and more stable. Also I could force clients to spectators and prevent them from joining in, all engine-side.
Logged
grey matter
Member


Cakes 8
Posts: 381

>9k


« Reply #91 on: February 28, 2012, 11:48:56 AM »

While this all sounds nice, does it work with any mod? It seems like e.g. your configstring/userinfo fiddling is very mod (baseoa) specific.
Logged

This space is for rent.
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #92 on: February 28, 2012, 12:03:52 PM »

While this all sounds nice, does it work with any mod? It seems like e.g. your configstring/userinfo fiddling is very mod (baseoa) specific.

I've quickly tried with ExcessivePlus mod and an older version of the patch and it seems it works nice. Now it should work even better. Anyway, I did not yet try extensively, I plan to do some more testing when everything I want to fix will be.

Anyway, normally everything should be alright with any mod, because I tried to use standard functions and mechanisms of the engine, and I don't interfer with the processing of configstrings and userinfo, I just store them as-is.

Normally, since mods can't edit the engine functions, everything should work alright, because the same mechanisms will be used. My patch's philosophy is: store as-is and restore as-is, with no or little processing involved.

An exception is my management of clientbegin and client team management, I had to do my own detection code (because this part of the clients management is fully gamecode-side), but this behaviour (of managing clients) should not change with any mod.

And on the subject, I'm now pretty satisfied how democlients are managed, everything seems pretty stable and faithful to the original.

Now onto the health bugfix!

/EDIT: also as a side-note, I think this patch should totally be compatible with ioquake3 because I believe the parts of the engine I'm touching and interacting are not modified at all by OA, so I'm basically working directly on the ioquake3 code.
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #93 on: February 28, 2012, 01:11:10 PM »

Tested again with ExcessivePlus with the latest patch: everything I've implemented works pretty well, but there's a bug which makes the client reload the map every few seconds - but the demo still continues and replays everything faithfully!

I'm pretty sure this is caused by a small glitch, probably some consistency check that is specific to ExcessivePlus and which is not reproduced in the demo. I'll take a look later, but mods support for this functionnality should be ok in the end.
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #94 on: February 28, 2012, 04:00:22 PM »

DEV HELP NEEDED: I don't know how the mechanism that manages health work. I guess that:
- Either clients send their health in their packets (so that the server's engine process them somewhere even if not knowing it),
- Either clients only send their actions and the server deduce their health (so health is computed serverside by the server's gamecode).

Can someone tell me which mechanism is true?

/EDIT: Ok anyway it seems gentities is shared between the gamecode and the engine, so the health variable should always be accessible. But I don't know how it will be updated to the clients... I guess the second way I described above is the right one, it seems logical and natural to avoid easy cheating. Is it right?
« Last Edit: February 28, 2012, 04:44:52 PM by GrosBedo » Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #95 on: February 28, 2012, 06:13:29 PM »

MEMENTO: OMG this one clarification was rather hard, not intended for the dyslexic!

sharedEntity_t = gentity_t != entityShared_t

gentity_t manages every aspect of a game entity, in the gamecode, concretely stored in level.gentities.
sharedEntity_t is the engine-side version and is concretely stored in sv.gentities
On the other side, entityShared_t is a field of gentity_t which, from what I understand, manages entities that are shared between several entities = relations between entities in the big picture.

Code:
// the server looks at a sharedEntity, which is the start of the game's gentity_t structure
typedef struct {
entityState_t s; // communicated by server to clients
entityShared_t r; // shared by both the server system and game
} sharedEntity_t;

In the server-side demos patch, demoEntities (sv.demoEntities) are the recorded version of sv.entities, but only sharedEntity_t and entityState_t (another field of gentity_t) are recorded, health field was not.

I'm not going to record all the fields (even if that would be the best solution ideally, but practically this would be a huge storage hog and some filtering would be needed, for example netchan and other networks fields shouldn't be stored nor replayed), but I'm going to do a quick fix for the health field and see how that works out.

But really, the sharedEntity_t vs entityShared_t made me laugh.
« Last Edit: February 28, 2012, 07:52:10 PM by GrosBedo » Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #96 on: February 28, 2012, 06:53:50 PM »

NEWS: I've found a HUGE storage, memory and CPU hog. entityShared and entityState was stored TWICE in the demo.

This fix should divide the storage space of demos and CPU usage by 2.
Logged
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #97 on: February 28, 2012, 07:54:07 PM »

PROBLEM: the sharedEntity_t is not exactly gentity_t: it seems it only contains entityShared_t and entityState_t. The problem is that I need to store and update the health variable. How can I do that if I can't even access that field? Do someone have a genius idea?

A side solution maybe: necessarily, clients have to send their actions, right? I could maybe recompute a whole simulation of the damages then, but is there a command that clients send with their actions? Can someone tell me a big picture of how clients damages on their target is communicated from client to server (I know that everything gets processed in g_damage, but where are those data updated and from where?).
« Last Edit: February 28, 2012, 08:25:04 PM by GrosBedo » Logged
grey matter
Member


Cakes 8
Posts: 381

>9k


« Reply #98 on: February 29, 2012, 03:33:15 PM »

Why not just memcpy the entire gentity_t? Take a look at trap_LocateGameData() to get its size from the engine.
gentity_t->health and STAT_HEALTH are gamecode and thus mod specific. The interesting damage code is in G_Damage() after the "// do the damage" comment.

What do you mean by "damage from client to server"? The client just sends a "shoot in this direction" command to the server, which then does the hit checks. Are you talking about things like EV_PAIN or PERS_HITS (from server to clients)?
Logged

This space is for rent.
GrosBedo
Member


Cakes 20
Posts: 710


« Reply #99 on: February 29, 2012, 06:23:22 PM »

@grey matter: thank's a lot. I was indeed talking about data from clients to servers, so this anwers my question.

I didn't think about memcpy, maybe I could do it the other way (ie: move from demo constructed gentity_t to the gamecode's gentity_t). I will look towards this way.
Logged
Pages: 1 2 3 [4] 5 6 7
  Print  
 
Jump to: