Forum

Q1 - problem with Stats and demos

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

Q1 - problem with Stats and demos

Postby ChOwW » Sat Dec 03, 2011 2:28 pm

Hello everyone :>

I'm trying to make an engine based on NetQuake, cross-compilable for PC, PSP, and Wii, just for some educationnal purposes.

To begin with, I only started from an older PSP engine of Quake, and adapted-it from the original NQ source, to finish using some old sources of QuakeWii... I needed to know how to adapt X or Y thing...
I've implanted some features from QuakeWorld and a very few from ProQuake (exactly the client recording ingame and a more precise aiming angle fix), but I'm also trying to implant new elements, and trying to remake the QuakeC source to be more "mod"-flexible.

But I have a problem about one feature.

I've implanted an Alt. Ammo System on the HUD, like on HL1 with the mp5.

So I've added STAT_ALTAMMO to the stats on Quakedef.h , as well as adding from Client_state_t altammo_items .

I also added to protocol.h a new SU_ bit

Code: Select all
#define SU_ALTITEMS (1<<15)


I've linked from sv_main to cl_parse the Msg_ReadLong message, and the status bar seems to read it. It seems it works well.

Image

However, when I'm trying to record ingame, and playdemo it, the only message I get is

Code: Select all
HOST_ERROR: CL_ParseServerMessage: Bad server message


I'm quite sure I forgot to adapt something in particular... But yet, I don't know exactly what.
I also modified a bit the QuakeC source, but it's not the source of the problem, since I have recorded and playdemo'd it well.

Here's what I modified in cl_parse.c
Code: Select all
/*
==================
CL_ParseClientdata

Server information pertaining to this client only
==================
*/
void CL_ParseClientdata (int bits)
{
   int      i, j;
   
   if (bits & SU_VIEWHEIGHT)
      cl.viewheight = MSG_ReadChar ();
   else
      cl.viewheight = DEFAULT_VIEWHEIGHT;

   if (bits & SU_IDEALPITCH)
      cl.idealpitch = MSG_ReadChar ();
   else
      cl.idealpitch = 0;
   
   VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
   for (i=0 ; i<3 ; i++)
   {
      if (bits & (SU_PUNCH1<<i) )
         cl.punchangle[i] = MSG_ReadChar();
      else
         cl.punchangle[i] = 0;
      if (bits & (SU_VELOCITY1<<i) )
         cl.mvelocity[0][i] = MSG_ReadChar()*16;
      else
         cl.mvelocity[0][i] = 0;
   }

// [always sent]   if (bits & SU_ITEMS)
      i = MSG_ReadLong ();

   if (cl.items != i)
   {   // set flash times
      Sbar_Changed ();
      for (j=0 ; j<32 ; j++)
         if ( (i & (1<<j)) && !(cl.items & (1<<j)))
            cl.item_gettime[j] = cl.time;
      cl.items = i;
   }
   
//*CH0WW : PLEASE FIX AMMO ONLY !!! */
   i = MSG_ReadLong ();
   if (cl.altammo_items != i)
   {   // set flash times
      Sbar_Changed ();
      cl.altammo_items = i;
   }

   cl.onground = (bits & SU_ONGROUND) != 0;
   cl.inwater = (bits & SU_INWATER) != 0;

   if (bits & SU_WEAPONFRAME)
      cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte ();
   else
      cl.stats[STAT_WEAPONFRAME] = 0;

   if (bits & SU_ARMOR)
      i = MSG_ReadByte ();
   else
      i = 0;
   if (cl.stats[STAT_ARMOR] != i)
   {
      cl.stats[STAT_ARMOR] = i;
      Sbar_Changed ();
   }

   if (bits & SU_WEAPON)
      i = MSG_ReadByte ();
   else
      i = 0;
   if (cl.stats[STAT_WEAPON] != i)
   {
      cl.stats[STAT_WEAPON] = i;
      Sbar_Changed ();
   }
   
   i = MSG_ReadShort ();
   if (cl.stats[STAT_HEALTH] != i)
   {
      cl.stats[STAT_HEALTH] = i;
      Sbar_Changed ();
   }

   i = MSG_ReadByte ();         // Read ammo byte
   if (cl.stats[STAT_AMMO] != i)   // if it changed...
   {
      cl.stats[STAT_AMMO] = i; // Update it!
      Sbar_Changed ();
   }

//----- Ch0wW : Addition of AltAmmo HUD -- MSG_WriteByte (msg, ent->v.currentammo_sec);
   i = MSG_ReadByte ();
   if (cl.stats[STAT_ALTAMMO] != i)
   {
      cl.stats[STAT_ALTAMMO] = i;
      Sbar_Changed ();
   }

   for (i=0 ; i<4 ; i++)             // Shat_shells -> stat_cells = 0/1/2/3 = 4 - TODO : Remake it for dynamically linking with QuakeC
   {
      j = MSG_ReadByte ();
      if (cl.stats[STAT_SHELLS+i] != j)// On part de Stat_SHELLS - TODO : Remake it for linking with QuakeC
      {
         cl.stats[STAT_SHELLS+i] = j;
         Sbar_Changed ();
      }
   }

   i = MSG_ReadByte ();

   if (standard_quake)
   {
      if (cl.stats[STAT_ACTIVEWEAPON] != i)
      {
         cl.stats[STAT_ACTIVEWEAPON] = i;
         Sbar_Changed ();
      }
   }
   else
   {
      if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i))
      {
         cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
         Sbar_Changed ();
      }
   }
}


and in Sv_main.c ...

Code: Select all
void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
{
   int      bits;
   int      i;
   edict_t   *other;
   int      items, altitems;
#ifndef QUAKE2
   eval_t   *val;
#endif

//
// send a damage message
//
   if (ent->v.dmg_take || ent->v.dmg_save)
   {
      other = PROG_TO_EDICT(ent->v.dmg_inflictor);
      MSG_WriteByte (msg, svc_damage);
      MSG_WriteByte (msg, ent->v.dmg_save);
      MSG_WriteByte (msg, ent->v.dmg_take);
      for (i=0 ; i<3 ; i++)
         MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));
   
      ent->v.dmg_take = 0;
      ent->v.dmg_save = 0;
   }

//
// send the current viewpos offset from the view entity
//
   SV_SetIdealPitch ();      // how much to look up / down ideally

// a fixangle might get lost in a dropped packet.  Oh well.
   if ( ent->v.fixangle )
   {
      MSG_WriteByte (msg, svc_setangle);
      for (i=0 ; i < 3 ; i++)
         MSG_WriteAngle (msg, ent->v.angles[i] );
      ent->v.fixangle = 0;
   }

   bits = 0;
   
   if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)
      bits |= SU_VIEWHEIGHT;
      
   if (ent->v.idealpitch)
      bits |= SU_IDEALPITCH;

// stuff the sigil bits into the high bits of items for sbar, or else
// mix in items2
#ifdef QUAKE2
   items = (int)ent->v.items | ((int)ent->v.items2 << 23);
#else
   /*val = GetEdictFieldValue(ent, "items2");

   if (val)
      items = (int)ent->v.items | ((int)val->_float << 23);
   else*/
      items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
      
#endif

   bits |= SU_ITEMS | SU_ALTITEMS;


   altitems = (int)ent->v.altammo_items | ((int)pr_global_struct->serverflags << 28);   // Ch0wW 02/12/11 -- Alt Ammo Addition (HUD) -- Dirty hack :/

   if ( (int)ent->v.flags & FL_ONGROUND)
      bits |= SU_ONGROUND;
   
   if ( ent->v.waterlevel >= 2)
      bits |= SU_INWATER;
   
   for (i=0 ; i<3 ; i++)
   {
      if (ent->v.punchangle[i])
         bits |= (SU_PUNCH1<<i);
      if (ent->v.velocity[i])
         bits |= (SU_VELOCITY1<<i);
   }
   
   if (ent->v.weaponframe)
      bits |= SU_WEAPONFRAME;

   if (ent->v.armorvalue)
      bits |= SU_ARMOR;

//   if (ent->v.weapon)
      bits |= SU_WEAPON;

// send the data

   MSG_WriteByte (msg, svc_clientdata);
   MSG_WriteShort (msg, bits);

   if (bits & SU_VIEWHEIGHT)
      MSG_WriteChar (msg, ent->v.view_ofs[2]);

   if (bits & SU_IDEALPITCH)
      MSG_WriteChar (msg, ent->v.idealpitch);

   for (i=0 ; i<3 ; i++)
   {
      if (bits & (SU_PUNCH1<<i))
         MSG_WriteChar (msg, ent->v.punchangle[i]);
      if (bits & (SU_VELOCITY1<<i))
         MSG_WriteChar (msg, ent->v.velocity[i]/16);
   }

// [always sent]   if (bits & SU_ITEMS)
   MSG_WriteLong (msg, items);                     //  ITEMS
   MSG_WriteLong (msg, altitems);                  // Ch0wW 02/12/11 -- Alt Ammo Addition (HUD)
   
   if (bits & SU_WEAPONFRAME)
      MSG_WriteByte (msg, ent->v.weaponframe);
   if (bits & SU_ARMOR)
      MSG_WriteByte (msg, ent->v.armorvalue);
   if (bits & SU_WEAPON)
      MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel));
   
   MSG_WriteShort (msg, ent->v.health);
   MSG_WriteByte (msg, ent->v.currentammo);
   MSG_WriteByte (msg, ent->v.currentammo_sec); // Ch0wW 06/11/11 -- Secondary Ammo Type Addition
//   MSG_WriteByte (msg, ent->v.maxammo);
   MSG_WriteByte (msg, ent->v.ammo_shells);
   MSG_WriteByte (msg, ent->v.ammo_nails);
   MSG_WriteByte (msg, ent->v.ammo_rockets);
   MSG_WriteByte (msg, ent->v.ammo_cells);

   if (standard_quake)
   {
      MSG_WriteByte (msg, ent->v.weapon);
   }
   else
   {
      for(i=0;i<32;i++)
      {
         if ( ((int)ent->v.weapon) & (1<<i) )
         {
            MSG_WriteByte (msg, i);
            break;
         }
      }
   }
}


Thanks in advance.
ChOwW
 
Posts: 21
Joined: Sat Dec 03, 2011 1:20 pm

Re: Q1 - problem with Stats and demos

Postby Spike » Sat Dec 03, 2011 6:51 pm

if its just demos that fail, your problem is not due to svc_clientdata.
check what changes you've made in cl_demo.c. make sure that whatever enables your higher precision aiming angles is also enabled for playing back those demos. considering you're not aiming for quake compatibility, and not even with the id demos, you should perhaps consider unconditionally sending/reading shorts for your angles in the clc_move commands, which would permit you to forgo any protocol toggles/detection.
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: Q1 - problem with Stats and demos

Postby Eluan » Sun Dec 04, 2011 4:51 am

If you need help with the Wii, feel free to ask me, I'm the author of the Wii port. (A port of the gamecube port with my own GX renderer)
Eluan
 
Posts: 10
Joined: Sun Jun 15, 2008 9:03 am
Location: Florianópolis, Brazil

Re: Q1 - problem with Stats and demos

Postby ChOwW » Sun Dec 04, 2011 11:32 am

Thanks Eluan, but I prefer to understand it by myself... That'll help me too discovering more of the wii's devkit abilities.

Spike : Actually, I haven't done any modification to cl_demo.c taken from ProQuake 3.50 ; I saw what to modify in view.c , but that's all I did.
It recorded well before implanting that Alt-Ammo system on the HUD. (except the fact I couldn't continue the demo if I changelevel'd, but I think that was an issue in the past)

Anyway, I've found what was my problem.

In PQ's cl_demo.c file, in CL_GetMessage, I commented by mistake that part (easily found):

Code: Select all
      demo_head_size[cls.signon] = net_message.cursize;

      if (!cls.signon)
      {
         char *ch;
         int len;

         len = strlen(demo_head[0]);
      //   ch = strstr(demo_head[0] + len + 1, "ProQuake Server Version");
         //if (ch)
      //      memcpy(ch, va("ProQuake \217Demo\217 Version %4.2f", PROQUAKE_VERSION), 28);
      //   else
      //   {
            ch = demo_head[0] + demo_head_size[0];
            *ch++ = svc_print;
      
<---- MY MISTAKE - 0
   /*   ch += 1 + sprintf(ch, "\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"
                              "\n   \01\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\03");
   */
>---- MY MISTAKE - 1

                                demo_head_size[0] = ch - (char *) demo_head[0];
      //   }
      }


I think it corrupted the messagedata written to the demo, hence that Cl_ParseServerMessage error...

Anyway, thanks a lot helping me.
ChOwW
 
Posts: 21
Joined: Sat Dec 03, 2011 1:20 pm


Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 1 guest