#12
03 февраля 2012 в 20:40
Тестим и мапим под RtCW, камрад. Мы с Евгением работаем над одним проектом.
#13
04 февраля 2012 в 04:04
Обратите внимание, тема эта про лимиты в Ку2, потому камрад АТекс и указал на соответствующий порт.<br />Если хотите увеличить лимиты в idTech3, поглядите хотя бы как это сделано в q2bers.<br />Кармак тоже не дурак, если поставил лимит на кол-во моделей. Всё упирается в сетевой трафик, чем он меньше, тем меньше вероятность уткнуться в лимит полосы пропускания сети и получить лаги. Если лимит - 256, то наверно индекс модели передаётся в сетевом пакете как байт. Если тупо увеличить лимит, ясное дело, получим хаос. Поглядите как в q2bers сделано: если индекс модели не больше 255, то передаём как обычно - байт. Если больше, то выставляем некий бит-флаг в заголовке пакета и тогда передаём слово (2 байта). Т.о. и сетевой трафик экономим в 99% случаев, и лимит увеличен. Но, конечно же, ломаем сетевой протокол: клиенты, не знающие об этих изменениях будут вести себя непредсказуемо (зависит от того, как запрограммирована их реакция на нестандартные данные).
#14
04 февраля 2012 в 11:56
делаем только сингл...<br /><br />ладно, попробую раскопать где происходит "общение" протокола
#15
04 февраля 2012 в 12:26
[quote author=Eugeny link=topic=704.msg16526#msg16526 date=1328356563]<br />делаем только сингл...<br />[/quote]<br />То что это сингл ещё не значит что сетевой код не принимает участия в этом процессе ;D<br />Схема клиент-сервер работает всегда. Обе стороны всегда "разговаривают" на языке сетевых пакетов, даже если эти стороны части одного .exe<br />
#16
04 февраля 2012 в 12:27
ну так и сервер и клиент находятся на одном компьютере<br />[hr][size=1]Post Merge: [time]1328358616[/time][/size][hr]<br />это случайно не часть этого?<br />
<br />netField_t playerStateFields[] =<br />{<br /> { PSF( commandTime ), 32 },<br /> { PSF( pm_type ), 8 },<br /> { PSF( bobCycle ), 8 },<br /> { PSF( pm_flags ), 16 },<br /> { PSF( pm_time ), -16 },<br /> { PSF( origin[0] ), 0 },<br /> { PSF( origin[1] ), 0 },<br /> { PSF( origin[2] ), 0 },<br /> { PSF( velocity[0] ), 0 },<br /> { PSF( velocity[1] ), 0 },<br /> { PSF( velocity[2] ), 0 },<br /> { PSF( weaponTime ), -16 },<br /> { PSF( weaponDelay ), -16 },<br /> { PSF( grenadeTimeLeft ), -16 },<br /> { PSF( gravity ), 16 },<br /> { PSF( leanf ), 0 },<br /> { PSF( speed ), 16 },<br /> { PSF( delta_angles[0] ), 16 },<br /> { PSF( delta_angles[1] ), 16 },<br /> { PSF( delta_angles[2] ), 16 },<br /> { PSF( groundEntityNum ), GENTITYNUM_BITS },<br /> { PSF( legsTimer ), 16 },<br /> { PSF( torsoTimer ), 16 },<br /> { PSF( legsAnim ), ANIM_BITS },<br /> { PSF( torsoAnim ), ANIM_BITS },<br /> { PSF( movementDir ), 8 },<br /> { PSF( eFlags ), 16 },<br /> { PSF( eventSequence ), 8 },<br /> { PSF( events[0] ), 8 },<br /> { PSF( events[1] ), 8 },<br /> { PSF( events[2] ), 8 },<br /> { PSF( events[3] ), 8 },<br /> { PSF( eventParms[0] ), 8 },<br /> { PSF( eventParms[1] ), 8 },<br /> { PSF( eventParms[2] ), 8 },<br /> { PSF( eventParms[3] ), 8 },<br /> { PSF( clientNum ), 8 },<br /> { PSF( weapons[0] ), 32 },<br /> { PSF( weapons[1] ), 32 },<br /> { PSF( weapon ), 7 }, // (SA) yup, even more<br /> { PSF( weaponstate ), 4 },<br /> { PSF( viewangles[0] ), 0 },<br /> { PSF( viewangles[1] ), 0 },<br /> { PSF( viewangles[2] ), 0 },<br /> { PSF( viewheight ), -8 },<br /> { PSF( damageEvent ), 8 },<br /> { PSF( damageYaw ), 8 },<br /> { PSF( damagePitch ), 8 },<br /> { PSF( damageCount ), 8 },<br /> { PSF( mins[0] ), 0 },<br /> { PSF( mins[1] ), 0 },<br /> { PSF( mins[2] ), 0 },<br /> { PSF( maxs[0] ), 0 },<br /> { PSF( maxs[1] ), 0 },<br /> { PSF( maxs[2] ), 0 },<br /> { PSF( crouchMaxZ ), 0 },<br /> { PSF( crouchViewHeight ), 0 },<br /> { PSF( standViewHeight ), 0 },<br /> { PSF( deadViewHeight ), 0 },<br /> { PSF( runSpeedScale ), 0 },<br /> { PSF( sprintSpeedScale ), 0 },<br /> { PSF( crouchSpeedScale ), 0 },<br /> { PSF( friction ), 0 },<br /> { PSF( viewlocked ), 8 },<br /> { PSF( viewlocked_entNum ), 16 },<br /> { PSF( aiChar ), 8 },<br /> { PSF( teamNum ), 8 },<br /> { PSF( gunfx ), 8},<br /> { PSF( onFireStart ), 32},<br /> { PSF( curWeapHeat ), 8 },<br /> { PSF( sprintTime ), 16}, // FIXME: to be removed<br /> { PSF( aimSpreadScale ), 8},<br /> { PSF( aiState ), 2},<br /> { PSF( serverCursorHint ), 8}, //----(SA) added<br /> { PSF( serverCursorHintVal ), 8}, //----(SA) added<br />// RF not needed anymore<br />//{ PSF(classWeaponTime), 32}, // JPW NERVE<br /> { PSF( footstepCount ), 0},<br />};
<br />[hr][size=1]Post Merge: [time]1328358730[/time][/size][hr]<br />в таких функциях нужно будет менять цифру 8?<br />void MSG_WriteChar( msg_t *sb, int c ) {<br />#ifdef PARANOID<br /> if ( c < -128 || c > 127 ) {<br /> Com_Error( ERR_FATAL, "MSG_WriteChar: range error" );<br /> }<br />#endif<br /><br /> MSG_WriteBits( sb, c, 8 );<br />}<br />
#17
05 февраля 2012 в 16:38
#18
06 февраля 2012 в 21:23
Вот функция MSG_WriteDeltaEntity в RtCW<br /><br />GENTITYNUM_BITS 10<br />CHANGE_VECTOR_BYTES 10<br />SMALL_VECTOR_BITS 5 <br />MAX_GENTITIES ( 1 << GENTITYNUM_BITS ) = 1024<br />FLOAT_INT_BITS 13<br />FLOAT_INT_BIAS ( 1 << ( FLOAT_INT_BITS - 1 ) ) = 4096<br />[code]void MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entityState_s *to,<br /> qboolean force ) {<br /> int i, c;<br /> int numFields;<br /> netField_t *field;<br /> int trunc;<br /> float fullFloat;<br /> int *fromF, *toF;<br /> byte changeVector[CHANGE_VECTOR_BYTES];<br /> int compressedVector;<br /> qboolean changed;<br /> int print, endBit, startBit;<br /><br /> if ( msg->bit == 0 ) {<br /> startBit = msg->cursize * 8 - GENTITYNUM_BITS;<br /> } else {<br /> startBit = ( msg->cursize - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;<br /> }<br /><br /> numFields = sizeof( entityStateFields ) / sizeof( entityStateFields[0] );<br /><br /> // all fields should be 32 bits to avoid any compiler packing issues<br /> // the "number" field is not part of the field list<br /> // if this assert fails, someone added a field to the entityState_t<br /> // struct without updating the message fields<br /> assert( numFields + 1 == sizeof( *from ) / 4 );<br /><br /> c = msg->cursize;<br /><br /> // a NULL to is a delta remove message<br /> if ( to == NULL ) {<br /> if ( from == NULL ) {<br /> return;<br /> }<br /> if ( cl_shownet && ( cl_shownet->integer >= 2 || cl_shownet->integer == -1 ) ) {<br /> Com_Printf( "W|%3i: #%-3i remove\n", msg->cursize, from->number );<br /> }<br /> MSG_WriteBits( msg, from->number, GENTITYNUM_BITS );<br /> MSG_WriteBits( msg, 1, 1 );<br /> return;<br /> }<br /><br /> if ( to->number < 0 || to->number >= MAX_GENTITIES ) {<br /> Com_Error( ERR_FATAL, "MSG_WriteDeltaEntity: Bad entity number: %i", to->number );<br /> }<br /><br /> // build the change vector<br /> if ( numFields > 8 * CHANGE_VECTOR_BYTES ) {<br /> Com_Error( ERR_FATAL, "numFields > 8 * CHANGE_VECTOR_BYTES" );<br /> }<br /><br /> for ( i = 0 ; i < CHANGE_VECTOR_BYTES ; i++ ) {<br /> changeVector[i] = 0;<br /> }<br /> changed = qfalse;<br /> // build the change vector as bytes so it is endien independent<br /> for ( i = 0, field = entityStateFields ; i < numFields ; i++, field++ ) {<br /> fromF = ( int * )( (byte *)from + field->offset );<br /> toF = ( int * )( (byte *)to + field->offset );<br /> if ( *fromF != *toF ) {<br /> changeVector[ i >> 3 ] |= 1 << ( i & 7 );<br /> changed = qtrue;<br /> }<br /> }<br /><br /> if ( !changed ) {<br /> // nothing at all changed<br /> if ( !force ) {<br /> return; // nothing at all<br /> }<br /> // write two bits for no change<br /> MSG_WriteBits( msg, to->number, GENTITYNUM_BITS );<br /> MSG_WriteBits( msg, 0, 1 ); // not removed<br /> MSG_WriteBits( msg, 0, 1 ); // no delta<br /> return;<br /> }<br /><br /> // shownet 2/3 will interleave with other printed info, -1 will<br /> // just print the delta records`<br /> if ( cl_shownet && ( cl_shownet->integer >= 2 || cl_shownet->integer == -1 ) ) {<br /> print = 1;<br /> Com_Printf( "W|%3i: #%-3i ", msg->cursize, to->number );<br /> } else {<br /> print = 0;<br /> }<br /><br /> // check for a compressed change vector<br /> compressedVector = LookupChangeVector( changeVector );<br /><br /> MSG_WriteBits( msg, to->number, GENTITYNUM_BITS );<br /> MSG_WriteBits( msg, 0, 1 ); // not removed<br /> MSG_WriteBits( msg, 1, 1 ); // we have a delta<br /><br />// MSG_WriteBits( msg, compressedVector, SMALL_VECTOR_BITS );<br /> if ( compressedVector == -1 ) {<br /> oldsize += 4;<br /> MSG_WriteBits( msg, 1, 1 ); // complete change<br /> // we didn't find a fast match so we need to write the entire delta<br /> for ( i = 0 ; i + 8 <= numFields ; i += 8 ) {<br /> MSG_WriteByte( msg, changeVector[i >> 3] );<br /> }<br /> if ( numFields & 7 ) {<br /> MSG_WriteBits( msg, changeVector[i >> 3], numFields & 7 );<br /> }<br /> if ( print ) {<br /> Com_Printf( "<uc> " );<br /> }<br /> } else {<br /> MSG_WriteBits( msg, 0, 1 ); // compressed vector<br /> MSG_WriteBits( msg, compressedVector, SMALL_VECTOR_BITS );<br /> if ( print ) {<br /> Com_Printf( "<%2i> ", compressedVector );<br /> }<br /> }<br /><br /> for ( i = 0, field = entityStateFields ; i < numFields ; i++, field++ ) {<br /> fromF = ( int * )( (byte *)from + field->offset );<br /> toF = ( int * )( (byte *)to + field->offset );<br /><br /> if ( *fromF == *toF ) {<br /> continue;<br /> }<br /><br /> if ( field->bits == 0 ) {<br /> // float<br /> fullFloat = *(float *)toF;<br /> trunc = (int)fullFloat;<br /><br /> if ( fullFloat == 0.0f ) {<br /> MSG_WriteBits( msg, 0, 1 );<br /> oldsize += FLOAT_INT_BITS;<br /> } else {<br /> MSG_WriteBits( msg, 1, 1 );<br /> if ( trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 &&<br /> trunc + FLOAT_INT_BIAS < ( 1 << FLOAT_INT_BITS ) ) {<br /> // send as small integer<br /> MSG_WriteBits( msg, 0, 1 );<br /> MSG_WriteBits( msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS );<br /> if ( print ) {<br /> Com_Printf( "%s:%i ", field->name, trunc );<br /> }<br /> } else {<br /> // send as full floating point value<br /> MSG_WriteBits( msg, 1, 1 );<br /> MSG_WriteBits( msg, *toF, 32 );<br /> if ( print ) {<br /> Com_Printf( "%s:%f ", field->name, *(float *)toF );<br /> }<br /> }<br /> }<br /> } else {<br /> if ( *toF == 0 ) {<br /> MSG_WriteBits( msg, 0, 1 );<br /> } else {<br /> MSG_WriteBits( msg, 1, 1 );<br /> // integer<br /> MSG_WriteBits( msg, *toF, field->bits );<br /> if ( print ) {<br /> Com_Printf( "%s:%i ", field->name, *toF );<br /> }<br /> }<br /> }<br /> }<br /> c = msg->cursize - c;<br /><br /> if ( print ) {<br /> if ( msg->bit == 0 ) {<br /> endBit = msg->cursize * 8 - GENTITYNUM_BITS;<br /> } else {<br /> endBit = ( msg->cursize - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;<br /> }<br /> Com_Printf( " (%i bits)\n", endBit - startBit );<br /> }<br />}<br />[/code]<br />Тут как-то завязано на GENTITYNUM_BITS и MAX_GENTITIES
#19
17 мая 2012 в 05:09
а как узнать ограничения по Q1 вот щас карта там уже 412 монстров. довольно большая. где потолок?
#20
17 мая 2012 в 10:08
hzycanlg, точную цифру для оригианльного движка не помню, но что-то в районе 500-600 entities должно проглатывать. Но это не только монстры, но все прочее от источников света, до коробок с патронами.<br />В современных движках (Darkplaces, Fitzquake и иже с ними) ограничения вроде бы сдвинуты в большую сторону.