Do I need self.value in CSQC?

Discuss CSQC related programming.
Post Reply
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Do I need self.value in CSQC?

Post by toneddu2000 »

Let's make an example without introduction this time.
Let's say I create a code for a pickup weapon in SSQC. Once picked up, I set

Code: Select all

if(other.classname=="player"){
other.pickupRifle = TRUE;
}
In this case, in SSQC, the field is mandatory because in multiplayer the server needs to know which player picked up the rifle.
But, if I send a multicast to csqc

Code: Select all

WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, PE_PICKUPTAKEN);
WriteShort(MSG_MULTICAST, other.pickupRifle);
multicast('0 0 0', MULTICAST_ONE);		
and then, in csqc I read it

Code: Select all

if(byte == PE_PICKUPTAKEN){
pickupRifle = readshort();
}
In this case I used a simple float pickupRifle. Or should I use a field .pickupRifle? Does CSQC automatically handle only selected player so I don't need to struggle to let the engine knows which player is currently active? It's a question I'm asking myself in these days! :D
Meadow Fun!! - my first commercial game, made with FTEQW game engine
gnounc
Posts: 428
Joined: Mon Apr 06, 2009 6:26 am

Re: Do I need self.value in CSQC?

Post by gnounc »

global float will do fine.

Client Side QuakeC is handling things from the perspective of the client. that is the player seated at the game.
you can still use entities, you can even create one to hold all your player variables if you so desire.
but if you have RIFLE_USED; the other players games wont be able to override your variable, its local to you.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Do I need self.value in CSQC?

Post by toneddu2000 »

gnounc wrote:Client Side QuakeC is handling things from the perspective of the client. that is the player seated at the game.
That was exactly what I wanted to know! Thanks a lot, gnounc!
but if you have RIFLE_USED; the other players games wont be able to override your variable, its local to you.
So, in this case, the only method I could use, to share this piece of information with the other clients, would be to send it to server with sendevent, right (I'm usigin FTE)?
Meadow Fun!! - my first commercial game, made with FTEQW game engine
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Do I need self.value in CSQC?

Post by frag.machine »

As a rule of thumb, if you are creating a multiplayer game, the server stills being the right place to the core logic. CSQC won't change this (mostly).
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Do I need self.value in CSQC?

Post by toneddu2000 »

So, you're saying that CSQC should be considered only as a "destination point", not a "sharing point" with SSQC?
But let's take this example. I'm hadling all the skeletal stuff to CSQC (for obvious reason), so, animations, weapon models(not shooting behaviours) are handled client side. And inputs to control them are handled client side too, through InputEvent.
Now, if I write in my player_predraw function something like that:

Code: Select all

player.frame = runAnimation; 
I then add entity to view through

Code: Select all

PREDRAW_AUTOADD
in the predraw.
or

Code: Select all

addentity(player);
in UpdateView, it's the same.
The skeletal run animation is handled correctly, also with body splitting and bla bla, but now, how CSQC should propagate to other clients (through server) the new animation of player X ?
Should I write some code or it's handled automatically but CSQC? This last part always wondered me!
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Do I need self.value in CSQC?

Post by Spike »

if you might be tracking multiple such values at the same time then its going to have to be a field.
if there can be only one, then you can get away with using a global (and thereby save some field space).

think of it in terms of ownership. who owns the value? if its a field, then the owner is the entity that its a field of. and if its a global? then its singular and owned by the entire local csprogs - and as such can only be used for the local player's entity.

as a general rule, if its an animation thing, then you're going to want to be animating all players (us+them) with roughly the same code, and will thus need to use fields in order to stop them fighting over ownership/meaning.
you should not trust any csqc module for anything but user inputs (due to bots+hacks+cheats), and thus you should be determining frames based only upon snapshots from the ssqc (or your local csqc's prediction of said snapshots). for foot sync, using only the .origin+.angle should really be needed (you can determine if the player is onground etc with traceboxes based upon the player's origin, while frame1time can be updated based upon distance traveled instead of sliding on the ground when they're trying to run into a wall), with the ssqc's .frame or whatever just controlling the torso's animations.

splitscreen makes things more complicated. :s
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Do I need self.value in CSQC?

Post by frag.machine »

toneddu2000 wrote:So, you're saying that CSQC should be considered only as a "destination point", not a "sharing point" with SSQC?
Hence the "client" in CSQC. ;)
toneddu2000 wrote: But let's take this example. I'm hadling all the skeletal stuff to CSQC (for obvious reason), so, animations, weapon models(not shooting behaviours) are handled client side. And inputs to control them are handled client side too, through InputEvent.
Of course skeletal animations and VFX in general are much better handled client side.

But when you say "inputs to control them are handled client side too, through InputEvent"... Well, everyone needs to know you are walking or jumping or firing a weapon, then this should be informed by the server to the clients.

So, TL;DR:

- if what I am doing concerns *ONLY* to my client in the sense it won't affect the game state for other players, it's okay (and likely better) to be handled by CSQC;
- otherwise, SSQC is the way to go.
toneddu2000 wrote:The skeletal run animation is handled correctly, also with body splitting and bla bla, but now, how CSQC should propagate to other clients (through server) the new animation of player X ?
The answer is: it should NOT. Remember, the server MUST BE authoritative regarding game state. Player movement is a (very important) game state, therefore should "happen" in the server side first (trigggered by a client input), and only then "displayed" client side (using all the bells and whistles CSQC provides to the modder/developer).

(Unless you are entirely dropping the server part and going to a peer-to-peer approach. If that's the case then good luck, you will need it. :)
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Do I need self.value in CSQC?

Post by toneddu2000 »

Spike wrote:think of it in terms of ownership. who owns the value? if its a field, then the owner is the entity that its a field of. and if its a global? then its singular and owned by the entire local csprogs - and as such can only be used for the local player's entity.
Ok, at this point I wanted to arrive! This phrase littelarlly explains what I was thinking but this other phrase:
Spike wrote:as a general rule, if its an animation thing, then you're going to want to be animating all players (us+them) with roughly the same code, and will thus need to use fields in order to stop them fighting over ownership/meaning.
it sounds like as it'd put in contraddiction the first one. I mean, if I'm animating a player in CSQC, I'm animating the local one! Or not? I can't control in CSQC a different player than the local one. I think, at least.

a code like

Code: Select all

if (self.entnum == player_localentnum){
			playerActive = self;
			//self.renderflags = RF_EXTERNALMODEL;
		}
For me, in CSQC, it doesn't make any sense because " I " should be the local player ( or active player as you want to call it)! But if you don't put that code in playerpredraw, when 2 clients connect, one of them "encroaches" the other's view.
So, actually, in this case, the use of field is mandatory I guess.
Spike wrote:splitscreen makes things more complicated. :s
Well, I must say, splitscreen helped to find errors in code that probably I'd left untouched because "on single player works flawless"! But, when I create a server and connect 2 clients...bang! :D Obviously, the more correct way to test, it'd be to launch a dedicated server on a remote server and use 2 or more computers to connect to it, but I'll make it soon!! :D

IMPORTANT NOTE TO SPIKE: I think I found a bug in FTE: when you launch the dedicated server and the map loaded has meshcollide surfaceparm on it, server crashes!
frag.machine wrote:Hence the "client" in CSQC. ;)
I see.. I only asked because when once I said "So, CSQC can only be used for HUD and pure player stuff?" gnounc said: "NO, it's not like that!"
So I guess that I was understimating and misunderstanting real potentialities of CSQC.
frag.machine wrote:But when you say "inputs to control them are handled client side too, through InputEvent"... Well, everyone needs to know you are walking or jumping or firing a weapon, then this should be informed by the server to the clients.
I see. In my test code only the "weapon fire trigger" is handled by CSQC, the rest is SSQC (but when a bullet particle explodes, that part I manage it in CSQC). Should I completely remove it and rewrite also that part in SSQC, or at least that part is "safe"?
frag.machine wrote:The answer is: it should NOT. Remember, the server MUST BE authoritative regarding game state. Player movement is a (very important) game state, therefore should "happen" in the server side first (trigggered by a client input), and only then "displayed" client side (using all the bells and whistles CSQC provides to the modder/developer).
Ok, clear.

Thanks a lot guys! Now I've a lot of material to study on! :D
Meadow Fun!! - my first commercial game, made with FTEQW game engine
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Do I need self.value in CSQC?

Post by toneddu2000 »

OK, now I studied! :D This concept literally drives me crazy. Let's just use an example to demonstrate if I'm stupid or if this is a limit of CSQC.
DISCLAIMER: I use FTE. Dunno if this procedure is replicable on DP. Last time I took a look, CSQC_ParseEvent wasn't present in dpextensions.qc

Let's imagine we want to play a fire animation in CSQC (no, you don't want it, YOU MUST DO IT in CSQC, because, server side, you cannot split skeleton for upper / lower part)
I first used something like this

SERVER SIDE - weapons

Code: Select all

void MyWeaponFireFunc()
{
if(time < self.weaponRefireTime){
		SendCsShotOn();
		return;
	}
	else{
		SendCsShotOff();
	}
}
SERVER SIDE - send stuff

Code: Select all

void SendCsShotOn()
{
	msg_entity = self;
	WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
	WriteByte(MSG_MULTICAST, PE_WEAPONSHOT);
	WriteByte(MSG_MULTICAST, 1);
	multicast(self.origin, MULTICAST_ALL);
}

void SendCsShotOff()
{
	msg_entity = self;
	WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
	WriteByte(MSG_MULTICAST, PE_WEAPONSHOT);
	WriteByte(MSG_MULTICAST, 0);
	multicast(self.origin, MULTICAST_ALL);
}
CLIENT SIDE - main

Code: Select all

noref void() CSQC_Parse_Event =
{
	local float rb = readbyte();

	if(rb == PE_WEAPONSHOT){
		weaponShot = readbyte();
	}
}
CLIENT SIDE - player

Code: Select all

void PlayerAnimFire()
{
	if(weaponShot  == 1){
		self.frame = animFireShotgun;
	}
	else{
		self.frame = animFireShotgunIdle;
	}
}
If I start only a client, I can see my shadow changing animation so it works. BUT.. if I connect two clients to my local server, I position the two clients, facing each other, when I press fire only the other player in my own screen will change animation, but, in the other screen, the player I see (that is the one who pressed fire) remains still.

I also used .shot field instead of a float, both in SSQC and CSQC - I also tried MULTICAST_ONE instead of MULTICAST_ALL - same results.

********WORKING METHOD

INSTEAD, if I use .shot field in ssqc and, instead of using CSQC_ParseEvent I use SendEntity in PutClientServer and sending all the fields I need to update (.origin,.angles,.velocity,etc) and I add self.shot at the list,

Code: Select all

float SendPlayerData (entity playerent, float changedflags)
{
	//entity
	WriteByte(MSG_ENTITY, ENT_PLAYER);
	//movements
	WriteCoord(MSG_ENTITY, self.origin_x);
	WriteCoord(MSG_ENTITY, self.blabla
	//frame
	WriteByte(MSG_ENTITY, self.frame);
	//
	WriteByte(MSG_ENTITY, self.shot);
	return TRUE;
}
and in CSQC_EntUpdate I add

Code: Select all

void CSQC_Ent_Update (float isnew)
{
	local float i = readbyte();
	if (i == ENT_PLAYER){
		//read here all send values from client.c in ssqc
		//movements
		self.origin_x = readcoord();
		self.blabla
		//frame
		self.frame = readbyte();
		//
		self.shot = readbyte();
		//all the remaining stuff
	}
}
Then in the client side animation

Code: Select all

void PlayerAnimFire()
{
	if(self.shot == 1){
		self.frame = animFireShotgun;
		self.frame1time += frametime;
	}
	else{
		self.frame = animFireShotgunIdle;
		self.frame1time += frametime;
	}
	skel_build(self.skeletonindex, self, self.modelindex, 0, bSpine2, bHolsterL, 1);
}
If I connect 2 clients, now I can see the other client in THE OTHER screen play fire animaion when I, in my own screen, press mouse button. Perfect, now IT WORKS.

This is exactly same issue I posted here. But, back then, I wasn't so sure of the mechanism.And, even back then, the solution was to use CSQC_EntUpdate instead of CSQC_ParseEvent. Now I could say I'm becoming more confident with CSQC so I now there's nothing I made wrong in the testing part. So, there are 2 possibilities:
  1. This is not the right method to parse an event for a specific client
  2. CSQC_ParseEvent is not made for sending client-specific data

    Please CSQC Gurus, help me! So I can update fteskel project soon! There are a lot of updates to bake! :D
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Do I need self.value in CSQC?

Post by Spike »

CSQC_Parse_Event events have no intrinsic relationship to any entity. you can send an entity index to the client, but the client possibly won't know what you're talking about (if the entity is not within that client's pvs at the time - there's always lag and resends that can give you problems like this). this is why there's a writeentity(), but only a readentitynum() that needs a separate lookup against entnum field, eg {entity e = find(world, entnum, readentitynum()); if (!e) panic();}
this might be fine if its a regular thing like an animation, but you're probably better off just transfering some field like .origin is transferred.
writing to a global when refering to the state of a single entity is dangerous - if your code uses the same global for every entity, that global will necissarily affect every entity that uses it. hence why it bugs out in that they're all affected.

you CAN use CSQC_Parse_Event for throwaway things like spawning particle effects in some weird crazy pattern, you can use it to update the client's hud, or update global state, but affecting a single entity is typically going to be unreliable.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Do I need self.value in CSQC?

Post by toneddu2000 »

Wow, thanks Spike for the super quick reply!!
Spike wrote:writing to a global when refering to the state of a single entity is dangerous - if your code uses the same global for every entity, that global will necissarily affect every entity that uses it. hence why it bugs out in that they're all affected.
Yeah, I tried also using a field but with no luck either.
Spike wrote:you CAN use CSQC_Parse_Event for throwaway things like spawning particle effects in some weird crazy pattern, you can use it to update the client's hud, or update global state, but affecting a single entity is typically going to be unreliable.
That's was exactly the answer I was waiting for! Thanks!

So, what should I use to keep track of entity fields in a reliable way? CSQC_EntUpdate()? Can you please explain self.SendEntity and self.SendFlags a little more? Because I only use them with player entity (self.SendEntity in the PutClientInServer() and self.SendFlags = FULLSEND; in PlayerPostThink(), otherwise player is blocked at middle air)but I really cannot say how I understood how it works and where it's possible to use it. I tried to send also non-player entities (like monsters) with this method but I always failed because I didn't know where to call self.SendEntity self.SendFlags.

For example I needed to add (following your leads of course, I didn't invent it :D )

Code: Select all

#define FULLSEND 0xffffff
to call, after

Code: Select all

self.SendFlags = FULLSEND;
Why that define it's not in the extensions? What does that statement mean?

Thanks a lot Spike for your big help!!
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Post Reply