converting entities to csqc (player)

Discuss CSQC related programming.
Post Reply
ceriux
Posts: 2230
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

converting entities to csqc (player)

Post by ceriux »

Okay so iv finished the Scratch tutorial and for my next endeavor i'd like to convert the player and his animations over to csqc. iv chosen to use FTE because of network code and there seems to be more documentation that i could find for csqc on this engine.

currently im reading CSQC for dummies and plan to go through the stickied thread in this forum. currently im looking into the builtins i need to do what i want to achieve. i'll post any questions and problems i may have here. if anyone has any advice please feel free to post here ahead of time.

to start what are the builtins i need to start with?
gnounc
Posts: 428
Joined: Mon Apr 06, 2009 6:26 am

Re: converting entities to csqc (player)

Post by gnounc »

https://gitorious.org/clean_csqc/cleanc ... 879d7ca263:
thats pretty much what you'll want to start with.

as for suggestions, i suggest idling in irc. I saw you jumped in, but you jumped back out too.
You've gotta rack up that uptime son!
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: converting entities to csqc (player)

Post by Spike »

set a .SendEntity field on the entity. should be a function.
when the entity is changed, set the .SendFlags field to something.
inside your .SendEntity function, call WriteByte(MSG_ENTITY, foo); etc as required. return TRUE.
the 'flags' argument is a copy of the SendFlags bits that need to be resent.

in your csqc, write a CSQC_Ent_Update function that matches the exact Write* calls that your ssqc will have used. If you're sending multiple types of entity, your first byte will likely need to indicate which type of entity it is, and you can then branch into the right sort of entity after that.
when CSQC_Ent_Remove is called, remember to remove(self), or set up some think function to do it.

if you screw up and the ssqc+csqc's writes don't match, you'll trigger illegible server messages. set sv_csqcdebug 1 (in FTE) to try to get some usable debug info for it.

As this is the player entity that you're talking about, using SendEntity on it will result in some issues for the client. Firstly, the client will no longer know its own entity, and it will depend upon the csqc fully for it. This means that you will _NEED_ to set the VF_ORIGIN view property, or the view will be in the wrong place (0 0 0).
you can do that inside the player's .predraw function (set it up from CSQC_Ent_Update or so). Remember that you will need to provide interpolation or prediction yourself.

For prediction, you'll need to use getinputframe(frameid) from servercommandframe+1 (as determined by the latest entity state received) to clientcommandframe, and apply the player's pending input commands to the entity (the runstandardplayerphysics() function). For the player, you can do this instead of interpolation - the frame matching clientcommandframe will solve timing issues for you, providing smooth extrapolation. You'll likely still want to provide stair smoothing however.
Be warned that other players are a different beast entirely. You can't predict those, you'll need to write some interpolation code for them (check the entity's .entnum field against player_localentnum to see if its the local player's entity or not).


alternatively, you can leave the ssqc unmodified, use deltalisten("progs/player.mdl",someupdateplayerfunction,0) in csqc, and have the client do all of its normal prediction and stuff as normal, and feed that into your csqc player entity. the fields updated by deltalisten are engine/protocol dependant, but will always include smooth origin+angle info by default (you can disable interpolation if you still want to run prediction, but its easier to not do so).
this is more limited (you can't send custom fields), but it is meant to be much easier, and doesn't require ssqc changes.
ceriux
Posts: 2230
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Re: converting entities to csqc (player)

Post by ceriux »

alternatively, you can leave the ssqc unmodified, use deltalisten("progs/player.mdl",someupdateplayerfunction,0) in csqc
im probably wrong, but are you saying i dont have to redraw the model through csqc i can let ssqc do it and just have csqc update the player postion? what if i wanted every player model(s) to be differnt from one another and change randomly ingame?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: converting entities to csqc (player)

Post by Spike »

the deltalisten builtin is some cheaty builtin that has the client copy its lerped version of the entity into a csqc entity each frame, instead of automatically adding it with addentities, based upon its ssqc modelindex.
the callback allows you to tailor the entity on a per-frame basis. because the client only knows certain fields, you can use all sorts of custom fields to hold all sorts of custom things, like the current model, and override the lerped state with custom state.

for example, if you want some sort of visible weapon models on players, you can bung this code somewhere in your csqc:

Code: Select all

.float weapon; //.weapon is not a normal csqc field
float() playerpredraw = 
{
    //first add a copy of the player entity using the the player's weapon model
    switch(self.weapon)
    {
    case IT_SHOTGUN:
        setmodel(self, "progs/vw_shot.mdl");
        addentity(self);
        break;
    case IT_ROCKET_LAUNCHER:
        setmodel(self, "progs/vw_rock2.mdl");
        addentity(self);
        break;
    }
    //and now add the 'proper' copy of the player. this model should not contain a gun mesh.
    setmodel(self, "progs/vwplayer.mdl");
    return FALSE;//false means the engine will call addentity for us after.
};
void() playerlisten =
{
    //this example assumes the ssqc got tweaked to dupe self.weapon into self.skin, just for this example.
    //this is required because we don't have any custom fields. you could use colormod for instance, but that has precision issues.
    self.weapon = self.skin; //save it off
    self.skin = 0; //don't mess up normal player rendering.
    self.drawmask = 1; //delta/engine, I'm not gonna guess what your defs.qc-equivelent calls it
    self.predraw = playerpredraw; //so we can add both entities properly without needing to hack stuff too much
};
and in CSQC_Init:

Code: Select all

    deltalisten("progs/player.mdl", playerlisten, 0);
and at the end of ssqc's PlayerPostThink:

Code: Select all

    self.skin = self.weapon;  //deltalisten only sees renderable fields, so make sure it can see which weapon this player is using.
If you just want to know where the local player is, you can use DP_CSQC_QUERYRENDERENTITY. localplayerorigin = getentity(player_localentnum, GE_ORIGIN); for example. Remember you'll also need to deal with STAT_VIEWHEIGHT, or equivelent.
This can be used for other players, but the scanning is quite ugly, and may induce vomiting from people who favour clean code at the expense of brevity.

Anyway, make it up as you go. That's what I do!
Post Reply