I'm here to bother you again, CSQC mentors!
CASE:
simple mixture of SSQC + CSQC to spawn a player on a map. Nothing else. Let's start simple.
DP
on the client I create the SendEntity function
Code: Select all
float Player_SendEntityToCSQC()
{
WriteByte(MSG_ENTITY, ENT_CSPLAYER);
WriteByte(MSG_ENTITY, player.frame); //FIXME NEED COMPRESSION
WriteByte(MSG_ENTITY, player.modelindex);
WriteByte(MSG_ENTITY, player.PersID);
WriteShort(MSG_ENTITY, player.angles_x);
WriteShort(MSG_ENTITY, player.angles_y);
WriteShort(MSG_ENTITY, player.angles_z);
WriteCoord(MSG_ENTITY, player.origin_x);
WriteCoord(MSG_ENTITY, player.origin_y);
WriteCoord(MSG_ENTITY, player.origin_z);
WriteShort(MSG_ENTITY, player.velocity_x);
WriteShort(MSG_ENTITY, player.velocity_y);
WriteShort(MSG_ENTITY, player.velocity_z);
return TRUE;
}
void PutClientInServer()
{
local entity playerspwn;
playerspwn = Player_FindStartPoint();
player = self; //now use player as global player entity
player.classname = "player";
player.health = 100;
player.takedamage = DAMAGE_AIM;
player.solid = SOLID_SLIDEBOX;
player.movetype = MOVETYPE_WALK;
player.origin = playerspwn.origin;
player.angles = playerspwn.angles;
player.fixangle = TRUE; // turn this way immediately
precache_model(PLAYER_MODEL);
setmodel (player, PLAYER_MODEL);
setsize (player, VEC_HULL_MIN, VEC_HULL_MAX);
player.flags = FL_CLIENT;
player.SendEntity = Player_SendEntityToCSQC;//VITAL!
self.Version = self.Version + 1;//Is this needed?
}
Code: Select all
void Player_Startup(float newent)
{
if (newent)
{
player.classname = "player";
setmodelindex(self, player.modelindex);
self.drawmask = MASK_NORMAL; // makes the entity visible
}
}
void CSQC_Ent_Update (float isnew)
{
self.enttype = ReadByte();
switch(self.enttype)
{
//receiving Player
case ENT_CSPLAYER:
player = self;
//read here all send values from client.c in ssqc
player.animation = ReadByte();
player.modelindex = ReadByte();
player.PersID = ReadByte();
player.angles_x = ReadShort();
player.angles_y = ReadShort();
player.angles_z = ReadShort();
player.origin_x = ReadCoord();
player.origin_y = ReadCoord();
player.origin_z = ReadCoord();
player.velocity_x = ReadShort();
player.velocity_y = ReadShort();
player.velocity_z = ReadShort();
Player_Startup(isnew); // IT WILL HAPPEN JUST ONCE - in cs/player/startup.c
break;
}
}
I can see my shiny Quake3 map and that's it
FTE
...now here come the troubles!!
If you do something similar above, the map won't load: black screen, no errors, no warnings (and that's a bit annoying, I must say)
I want to clarify that I completely replaced CSQC DP defs with the command "pr_dumpplatform -FFTE -TCS -O csplat".
Then I replaced the CSQC part with cleancsqc.
This time map loads but only if I comment the SSQC and CSQC part of read/write values.
I studied A LOT csqctest and it uses a pretty obscure (at least for me) construction to send values from SSQC to SSQC.
Both SSQC AND CSQC share a classes.qc file
Code: Select all
#ifndef _CLASSES_QC_
#define _CLASSES_QC_
#define eclasses eclass(CLASS_ROCKET, ParseRocketClass) eclass(CLASS_GIB, ParseGibbing) eclass(CLASS_PLAYER, ParsePlayer) eclass(CLASS_EXPLOSION, ParseExplosion) eclass(CLASS_NAIL, ParseNailClass)
#ifdef CSQC
#define eclass(eid,func) void(float isnew) func;
eclasses
#undef eclass
#endif
enum {
#define eclass(eid,func) eid,
eclasses CLASS_MAX
#undef eclass
};
enum {
GIB_BAD,
GIB_PLAYER,
GIB_SOLDIER,
GIB_ZOMBIE,
GIB_DEMON,
GIB_OGRE,
GIB_DOG,
GIB_WIZARD,
GIB_SHAMBLER,
GIB_KNIGHT,
GIB_HELLKNIGHT,
GIB_FISH,
GIB_ENFORCER,
GIB_SHALRATH,
GIB_MAX
};
#else
#ifdef CSQC
nonstatic var void(float isnew) ParseEntityClass[ ] = {
#define eclass(eid,func) func ,
eclasses
#undef eclass
__NULL__
};
#endif
#endif
Now, my mind completely refuses to understand the #DEFINE directives, ok, but... what's the difference with the code I used?
CLASS_PLAYER is used in SSQC/client.qc
Code: Select all
WriteByte(MSG_ENTITY, CLASS_PLAYER);
Code: Select all
/*
this file handles the local player, and marshalling between the different sorts of player models.
RefreshPlayer: Called from the engine each time a player (ent with player.mdl) is about to be drawn
ParsePlayer: Called from CSQC_Ent_Parse for csqc protocol ents
*/
nonstatic void(float isnew) ParsePlayer =
{
local float f;
f = readbyte();
if (f != self.frame || isnew)
{
self.frame2 = self.frame;
self.lerptime = time;
self.frame = f;
}
self.angles_x = readbyte()*(360/256);
self.angles_y = readbyte()*(360/256);
self.origin_x = readcoord();
self.origin_y = readcoord();
self.origin_z = readcoord();
self.velocity_x = readshort();
self.velocity_y = readshort();
self.velocity_z = readshort();
self.colormap = self.entnum;
self.sveffects = readbyte();
RefreshPlayer(isnew);
};
Last funny thing: If I compile csqctest on svn FTE, quake(1)maps work great, instead my custom Quake 3 maps are not visible again!!
Here a little test I made with DP and FTE. Very basic pack: a map, an exe(only Win version, sorry), simple code and a bunch of silly assets!
In the FTE zip you find two code folders, one similar to DP's one (code_simple), with the only difference in FTE functions names and defs files, the other (code_cleancsqc) with the csqc part completely taken from cleancsqc
Please let me know if someone had same problems with FTE!
Thanks in advance