Tracking client connect time

Discuss programming in the QuakeC language.
Post Reply
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Tracking client connect time

Post by Cobalt »

Trying to make some QC that stores the clients "playtime" (total time connected to server) and keeps between level changes.

So far unsuccessful....) :(

Fundamantally, I believe we need to store the value of time when the client connects, so I used .connect_time for that.

Also I made .playtime and .client_time floats where I am thinking playtime will be the total time connected before the level change, and we add it to .client_time, then pass .client_time to a parm to be decoded next level. We then check playtime during the decode and if its not -1 we assume the client just connected , otherwise if its -1 we are carrying over the time from last level, so reset playtime to start counting from the start of the new level. Otherwise if we have client_time carried from last level, we just add it to the new playtime value which will be something like time / 60. I know it sounds crude, but for some reason I have been stuck on getting this right for a while, any help appreciated.
PrimalLove
Posts: 14
Joined: Sun Oct 19, 2014 2:37 am

Re: Tracking client connect time

Post by PrimalLove »

@Cobalt


Perhaps this would be helpful? This should basically do what you are wanting to accomplish.

Code: Select all

// Float Examples
.float time_check;
.float level_time;

// In PlayerPreThink

if (intermission_running)
	{
		// Here we just set the temp1 cvar to the amount of time passed for the next level
		cvar_set("temp1", ftos(self.level_time));
		IntermissionThink ();	// otherwise a button could be missed between
		return;					// the think tics
	}

	if (self.view_ofs == '0 0 0')
		return;		// intermission or finale
		
	// Place this after intermission stuff so the timer will stop counting...
	if (self.time_check < time)
	{
		// The bprint stuff is just for testing. 
		// This will take the temp1 value and add time to it which is just seconds. 
		self.level_time =cvar("temp1") + time; 
		bprint(ftos(self.level_time));
		bprint("\n");
		// So its not so spammy.... :/
		self.time_check = time + 1;
	}

If you are playing an ironman style play through you can have it set the temp1 back to 0 in Client connect or something

Code: Select all

//In ClientConnect	

if (world.model == "maps/Start.bsp")
		cvar_set("temp1", "0");
		
That would reset you for your next run.


This is pretty rudimentary but I would think all this would work... :/ For something basic anyway.

I may have misinterpreted what you want here tho. :/
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: Tracking client connect time

Post by Cobalt »

Still havent tried your code yet PL, but I noticed if you type "status", in DP at least, there is a total elapsed time field to the far right. It also keeps between level changes via changelevel. Wonder if there is a way to grab that from the engine somehow...? I guess an engine coder needs to weigh in to answer that.
PrimalLove
Posts: 14
Joined: Sun Oct 19, 2014 2:37 am

Re: Tracking client connect time

Post by PrimalLove »

Host_Status_f (located in host_cmd.c) is what is executed with status command. It uses (net_time - client->netconnection->connecttime) to give the accurate time on the server for each client. net_time uses Sys_DoubleTime (formally Sys_FloatTime) depending on what engine you are using. It gives the accurate 'realtime'. "sv.time" restarts with each new map started or server connect. Thinks use sv.time and host_frametime. Using time as I do will always reset after each map but will give (mostly) accurate connect time and actual time connected/played in seconds(milliseconds). Sv.time also pauses when the server pauses or you press escape for the menu, etc. So sv.time lines up with the moment a player joins the server. To get past the reset value I just save the number of seconds from the first map to the temp1 or similar cvar and it gets sent to the next map connect and is added to the leveltime plus any time that passes after that. I am not aware of another way to do this via qc. But my qc knowledge is limited. I started using this method myself after posting this and it works quite well. I use it to keep track of level time and total time played. It's possible there is a more accurate way to do this but for the purposes of basic connect/level time it seems to work as intended. If you want to convert your seconds into a better display for seconds and minutes then you can use something like this.. Assuming you are using sprintf builtin.

Code: Select all

// Use this to convert the time...
string time_conversion(float seconds) 
{
	float minutes;
	string timedisplay;
	
	minutes = seconds/60;
	seconds = seconds - 60 * floor(seconds/60);

	timedisplay = sprintf("%02d:%02d ", minutes, seconds);
	
	return timedisplay;
}

string level_time = strcat("Level Time: ", time_conversion(self.level_time));
// Print it to something.... Maybe better to use CSQC.... :/

Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: Tracking client connect time

Post by Cobalt »

Hey very good PL, looks like you dove into the engine code to answer this. thanks. I will have to try your code soon.

Makes me wonder if there would be a way to "Auto extension" any engine variable / global like that which is not available qc side. Sort of like how we addstat in csqc for a qc field.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Tracking client connect time

Post by Spike »

Cobalt wrote:Makes me wonder if there would be a way to "Auto extension" any engine variable / global like that which is not available qc side.
They're called cvars.

Alternatively, using some tricks popularised by QCCX, its possible to hack random parts of certain engine however you want, certainly you would be able to read the client's time field the same as you could read the client's ip. Typically used on proquake, this has resulted in proquake developers being too scared to actually change any part of the engine because this results in mods no longer working. Its not pretty. This is why DP+FTE sandbox qc code so that it cannot randomly generate native instructions and trick the engine to execute it, etc. I'm sure you'll aprechiate this if you ever run someone else's csqc.
Sort of like how we addstat in csqc for a qc field.
addstat (aka: clientstat) is called from ssqc, not csqc.
just as its the ssqc that decides what csqc sees, its the engine that decides what qc sees.
the alternative is basically an unmaintainable hacky nightmare.
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: Tracking client connect time

Post by Cobalt »

Similar to what I am thinking, however cvars can be operated by the client. What I am wondering is something that takes any engine specific float, vector or string thats not already being made available to qc, now avaialble, if the correct syntax of the field the engine knows is used. Yes, you have to know what you are doing, of course....and I would say this is for READ ONLY purposes. QC more or less does this as is for all the important stuff...so maybe I am trying to reinvent the wheel, but if PL did his research right we can find pass the field for the clients time that shows up in the status field as sv.time.slot1 (for player 1 / nextent(world) for arguments sake....like this:

Im guessing the time float he found is a vector ?

vector (svtime , entity slot) GetSvExtension;

Where svtime is that field that shows up in status, and slot is the player slot (1 - maxplayers). I know it probably sounds primitave coming from me who has no experience yet engine coding, but thats the basic idea I threw out.

Spike wrote: They're called cvars.
Post Reply