/* ============================================================================= movevars_t communication ============================================================================= */ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to ) { delta_t *pField; delta_info_t *dt; int i, startBit; int numChanges = 0; dt = Delta_FindStruct( "movevars_t" ); ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); startBit = msg->iCurBit; // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); BF_WriteByte( msg, svc_deltamovevars ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { if( Delta_WriteField( msg, pField, from, to, 0.0f )) numChanges++; } // if we have no changes - kill the message if( !numChanges ) { BF_SeekToBit( msg, startBit ); return false; } return true; }
/* ================== MSG_WriteWeaponData Writes current client data only for local client Other clients can grab the client state from entity_state_t ================== */ void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, float timebase, int index ) { delta_t *pField; delta_info_t *dt; int i, startBit; int numChanges = 0; dt = Delta_FindStruct( "weapon_data_t" ); if( !dt || !dt->bInitialized ) { Host_Error( "MSG_WriteWeaponData: delta not initialized!\n" ); } pField = dt->pFields; ASSERT( pField ); // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); startBit = msg->iCurBit; BF_WriteOneBit( msg, 1 ); BF_WriteUBitLong( msg, index, MAX_WEAPON_BITS ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { if( Delta_WriteField( msg, pField, from, to, timebase )) numChanges++; } // if we have no changes - kill the message if( !numChanges ) BF_SeekToBit( msg, startBit ); }
void Delta_Init( void ) { delta_info_t *dt; // shutdown it first if( delta_init ) Delta_Shutdown (); Delta_InitFields (); // initialize fields delta_init = true; dt = Delta_FindStruct( "movevars_t" ); ASSERT( dt != NULL ); if( dt->bInitialized ) return; // "movevars_t" already specified by user // create movevars_t delta internal Delta_AddField( "movevars_t", "gravity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "stopspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "maxspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "spectatormaxspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "accelerate", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "airaccelerate", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "wateraccelerate", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "friction", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "edgefriction", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "waterfriction", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "bounce", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "stepsize", DT_FLOAT|DT_SIGNED, 16, 16.0f, 1.0f ); Delta_AddField( "movevars_t", "maxvelocity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); if( host.features & ENGINE_WRITE_LARGE_COORD ) Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 18, 1.0f, 1.0f ); // no fractional part else Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f ); // no fractional part Delta_AddField( "movevars_t", "waveHeight", DT_FLOAT|DT_SIGNED, 16, 16.0f, 8.0f ); Delta_AddField( "movevars_t", "skyName", DT_STRING, 1, 1.0f, 1.0f ); Delta_AddField( "movevars_t", "footsteps", DT_INTEGER, 1, 1.0f, 1.0f ); Delta_AddField( "movevars_t", "rollangle", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "rollspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "skycolor_r", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f ); // 0 - 264 Delta_AddField( "movevars_t", "skycolor_g", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f ); Delta_AddField( "movevars_t", "skycolor_b", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f ); Delta_AddField( "movevars_t", "skyvec_x", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); // 0 - 1 Delta_AddField( "movevars_t", "skyvec_y", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "skydir_x", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); // 0 - 1 Delta_AddField( "movevars_t", "skydir_y", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "skydir_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "skyangle", DT_ANGLE, 16, 1.0f, 1.0f ); // 0 - 360 Delta_AddField( "movevars_t", "wateralpha", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "fog_settings", DT_INTEGER, 32, 1.0f, 1.0f ); // now done dt->bInitialized = true; }
qboolean Delta_AddField( const char *pStructName, const char *pName, int flags, int bits, float mul, float post_mul ) { delta_info_t *dt; delta_field_t *pFieldInfo; delta_t *pField; int i; // get the delta struct dt = Delta_FindStruct( pStructName ); ASSERT( dt != NULL ); // check for coexisting field for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ ) { if( !Q_strcmp( pField->name, pName )) { MsgDev( D_NOTE, "Delta_Add: %s->%s already existing\n", pStructName, pName ); return false; // field already exist } } // find field description pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName ); if( !pFieldInfo ) { MsgDev( D_ERROR, "Delta_Add: couldn't find description for %s->%s\n", pStructName, pName ); return false; } if( dt->numFields + 1 > dt->maxFields ) { MsgDev( D_WARN, "Delta_Add: can't add %s->%s encoder list is full\n", pStructName, pName ); return false; // too many fields specified (duplicated ?) } // allocate a new one dt->pFields = Z_Realloc( dt->pFields, (dt->numFields + 1) * sizeof( delta_t )); for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ ); // copy info to new field pField->name = pFieldInfo->name; pField->offset = pFieldInfo->offset; pField->size = pFieldInfo->size; pField->flags = flags; pField->bits = bits; pField->multiplier = mul; pField->post_multiplier = post_mul; dt->numFields++; return true; }
void Delta_InitFields( void ) { char *afile, *pfile; string encodeDll, encodeFunc, token; delta_info_t *dt; afile = FS_LoadFile( DELTA_PATH, NULL, false ); if( !afile ) { static string errormsg; Q_snprintf( errormsg, sizeof( errormsg ), "DELTA_Load: couldn't load file %s\n", DELTA_PATH ); Sys_Error( errormsg ); } pfile = afile; while(( pfile = COM_ParseFile( pfile, token )) != NULL ) { dt = Delta_FindStruct( token ); if( dt == NULL ) { Sys_Error( "delta.lst: unknown struct %s\n", token ); } pfile = COM_ParseFile( pfile, encodeDll ); if( !Q_stricmp( encodeDll, "none" )) Q_strcpy( encodeFunc, "null" ); else pfile = COM_ParseFile( pfile, encodeFunc ); // jump to '{' pfile = COM_ParseFile( pfile, token ); if( token[0] != '{' ) { Sys_Error( "delta.lst: missing '{' in section %s\n", dt->pName ); } Delta_ParseTable( &pfile, dt, encodeDll, encodeFunc ); } Mem_Free( afile ); // adding some requrid fields fields that user may forget or don't know how to specified Delta_AddField( "event_t", "velocity[0]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f ); Delta_AddField( "event_t", "velocity[1]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f ); Delta_AddField( "event_t", "velocity[2]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f ); }
/* ================== MSG_ReadWeaponData Read the clientdata ================== */ void MSG_ReadWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, float timebase ) { delta_t *pField; delta_info_t *dt; int i; dt = Delta_FindStruct( "weapon_data_t" ); ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); *to = *from; // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_ReadField( msg, pField, from, to, timebase ); } }
void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to ) { delta_t *pField; delta_info_t *dt; int i; dt = Delta_FindStruct( "movevars_t" ); ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); *to = *from; // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_ReadField( msg, pField, from, to, 0.0f ); } }
/* ================== MSG_WriteClientData Writes current client data only for local client Other clients can grab the client state from entity_state_t ================== */ void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, float timebase ) { delta_t *pField; delta_info_t *dt; int i; dt = Delta_FindStruct( "clientdata_t" ); ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_WriteField( msg, pField, from, to, timebase ); } }
/* ===================== MSG_WriteDeltaEvent ===================== */ void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to ) { delta_t *pField; delta_info_t *dt; int i; dt = Delta_FindStruct( "event_t" ); ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_WriteField( msg, pField, from, to, 0.0f ); } }
/* ================== MSG_ReadClientData Read the clientdata ================== */ void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, float timebase ) { delta_t *pField; delta_info_t *dt; int i; dt = Delta_FindStruct( "clientdata_t" ); if( !dt || !dt->bInitialized ) { Host_Error( "MSG_ReadClientData: delta not initialized!\n" ); } pField = dt->pFields; ASSERT( pField ); *to = *from; // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_ReadField( msg, pField, from, to, timebase ); } }
/* ===================== MSG_ReadDeltaEvent ===================== */ void MSG_ReadDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to ) { delta_t *pField; delta_info_t *dt; int i; dt = Delta_FindStruct( "event_t" ); if( !dt || !dt->bInitialized ) { Host_Error( "MSG_ReadDeltaEvent: delta not initialized!\n" ); } pField = dt->pFields; ASSERT( pField ); *to = *from; // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_ReadField( msg, pField, from, to, 0.0f ); } }
/* ===================== MSG_WriteDeltaUsercmd ===================== */ void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to ) { delta_t *pField; delta_info_t *dt; int i; dt = Delta_FindStruct( "usercmd_t" ); if( !dt || !dt->bInitialized ) { Host_Error( "MSG_WriteDeltaUsercmd: delta not initialized!\n" ); } pField = dt->pFields; ASSERT( pField ); // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_WriteField( msg, pField, from, to, 0.0f ); } }
/* ================== MSG_ReadDeltaEntity The entity number has already been read from the message, which is how the from state is identified. If the delta removes the entity, entity_state_t->number will be set to MAX_EDICTS Can go from either a baseline or a previous packet_entity ================== */ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, qboolean player, float timebase ) { delta_info_t *dt = NULL; delta_t *pField; int i, fRemoveType; #ifndef XASH_DEDICATED if( number < 0 || number >= clgame.maxEntities ) { // broken packet, try to skip it MsgDev( D_ERROR, "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number ); return false; } *to = *from; to->number = number; fRemoveType = BF_ReadUBitLong( msg, 2 ); if( fRemoveType ) { // check for a remove Q_memset( to, 0, sizeof( *to )); if( fRemoveType & 1 ) { // removed from delta-message return false; } if( fRemoveType & 2 ) { // entity was removed from server to->number = -1; return false; } MsgDev( D_ERROR, "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType ); return false; } if( BF_ReadOneBit( msg )) to->entityType = BF_ReadUBitLong( msg, 2 ); if( to->entityType == ENTITY_BEAM ) { dt = Delta_FindStruct( "custom_entity_state_t" ); } else // ENTITY_NORMAL or other (try predict type) { /* Omit connection drop on wromg data from server. * I know that it is very dirty, * but i don't know how to do it better.*/ if( to->entityType != ENTITY_NORMAL ) MsgDev( D_NOTE, "MSG_ReadDeltaEntity: broken delta: entityType = %d\n", to->entityType ); if( player ) { dt = Delta_FindStruct( "entity_state_player_t" ); } else { dt = Delta_FindStruct( "entity_state_t" ); } } if( !(dt && dt->bInitialized) ) // Broken delta? { MsgDev( D_ERROR, "MSG_ReadDeltaEntity: broken delta\n"); return true; } pField = dt->pFields; ASSERT( pField ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_ReadField( msg, pField, from, to, timebase ); } #endif // message parsed return true; }
/* ================== MSG_WriteDeltaEntity Writes part of a packetentities message, including the entity number. Can delta from either a baseline or a previous packet_entity If to is NULL, a remove entity update will be sent If force is not set, then nothing at all will be generated if the entity is identical, under the assumption that the in-order delta code will catch it. ================== */ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean player, float timebase ) { delta_info_t *dt = NULL; delta_t *pField; int i, startBit; int numChanges = 0; if( to == NULL ) { int fRemoveType; if( from == NULL ) return; // a NULL to is a delta remove message BF_WriteWord( msg, from->number ); // fRemoveType: // 0 - keep alive, has delta-update // 1 - remove from delta message (but keep states) // 2 - completely remove from server if( force ) fRemoveType = 2; else fRemoveType = 1; BF_WriteUBitLong( msg, fRemoveType, 2 ); return; } startBit = msg->iCurBit; if( to->number < 0 || to->number >= GI->max_edicts ) { MsgDev( D_ERROR, "MSG_WriteDeltaEntity: Bad entity number: %i\n", to->number ); return; } BF_WriteWord( msg, to->number ); BF_WriteUBitLong( msg, 0, 2 ); // alive if( to->entityType != from->entityType ) { BF_WriteOneBit( msg, 1 ); BF_WriteUBitLong( msg, to->entityType, 2 ); } else BF_WriteOneBit( msg, 0 ); if( to->entityType == ENTITY_NORMAL ) { if( player ) { dt = Delta_FindStruct( "entity_state_player_t" ); } else { dt = Delta_FindStruct( "entity_state_t" ); } } else if( to->entityType == ENTITY_BEAM ) { dt = Delta_FindStruct( "custom_entity_state_t" ); } ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { if( Delta_WriteField( msg, pField, from, to, timebase )) numChanges++; } // if we have no changes - kill the message if( !numChanges && !force ) BF_SeekToBit( msg, startBit ); }
/* ================== MSG_ReadDeltaEntity The entity number has already been read from the message, which is how the from state is identified. If the delta removes the entity, entity_state_t->number will be set to MAX_EDICTS Can go from either a baseline or a previous packet_entity ================== */ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, qboolean player, float timebase ) { delta_info_t *dt = NULL; delta_t *pField; int i, fRemoveType; #ifndef _DEDICATED if( number < 0 || number >= clgame.maxEntities ) Host_Error( "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number ); #endif *to = *from; to->number = number; fRemoveType = BF_ReadUBitLong( msg, 2 ); if( fRemoveType ) { // check for a remove Q_memset( to, 0, sizeof( *to )); if( fRemoveType & 1 ) { // removed from delta-message return false; } if( fRemoveType & 2 ) { // entity was removed from server to->number = -1; return false; } Host_Error( "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType ); } if( BF_ReadOneBit( msg )) to->entityType = BF_ReadUBitLong( msg, 2 ); if( to->entityType == ENTITY_NORMAL ) { if( player ) { dt = Delta_FindStruct( "entity_state_player_t" ); } else { dt = Delta_FindStruct( "entity_state_t" ); } } else if( to->entityType == ENTITY_BEAM ) { dt = Delta_FindStruct( "custom_entity_state_t" ); } ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { Delta_ReadField( msg, pField, from, to, timebase ); } // message parsed return true; }