From 9ee7301d322ecda7c49cbe7f6aaa05d4956cda30 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 12 Feb 2012 05:18:31 +0000 Subject: [PATCH] my attempt at android multitouch (csqc can also distinguish separate mice in windows too). playing around with fragmentation and mtus. added net_mtu to negotiate some mtu size for smaller (or larger) network messages. setting a custom mtu allows for message fragmentation too. trying to add a reworked deltaing protocol, including all sorts of fun stuff like bbox sizes, and higher ent limits. added support for content override entities. set the skin field to some (negative) contents value, and you get movable water with prediction and waterwarp and everything, though you likely want a custom qbsp or a shader to get backface culling. removed some madness with model skins, fixing some weird q3 bugs. fixed forced-pause-on-start for q2 fixed q3 server to actually accept client packets again. fixed strftime builtin git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3979 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_ents.c | 713 ++++++++++++++++-- engine/client/cl_input.c | 23 +- engine/client/cl_main.c | 116 +-- engine/client/cl_parse.c | 128 +++- engine/client/cl_pred.c | 156 +++- engine/client/client.h | 17 +- engine/client/clq2_ents.c | 51 +- engine/client/image.c | 32 +- engine/client/in_win.c | 85 +-- engine/client/keys.c | 89 +-- engine/client/m_mp3.c | 3 +- engine/client/m_options.c | 2 +- engine/client/net_master.c | 9 +- engine/client/pr_csqc.c | 95 ++- engine/client/pr_menu.c | 28 +- engine/client/r_surf.c | 46 +- engine/client/render.h | 2 +- engine/client/renderer.c | 2 + engine/client/sbar.c | 4 +- engine/client/skin.c | 3 +- engine/client/sys_droid.c | 68 +- engine/client/sys_win.c | 238 +++++- engine/client/view.c | 17 +- engine/common/bothdefs.h | 61 +- engine/common/bspfile.h | 2 +- engine/common/com_mesh.c | 199 ++--- engine/common/com_mesh.h | 4 +- engine/common/common.c | 6 +- engine/common/common.h | 1 + engine/common/fs.c | 118 ++- engine/common/net.h | 3 + engine/common/net_chan.c | 223 +++++- engine/common/net_wins.c | 18 +- engine/common/pmove.c | 36 +- engine/common/pmove.h | 2 +- engine/common/pmovetst.c | 45 +- engine/common/pr_bgcmd.c | 3 +- engine/common/pr_common.h | 9 + engine/common/protocol.h | 116 ++- engine/common/q1bsp.c | 20 +- engine/common/world.h | 2 + engine/common/zone.c | 4 + engine/d3d/vid_d3d.c | 2 +- engine/dotnet2005/ftequake.sln | 1 - engine/dotnet2005/ftequake.vcproj | 1 + .../droid/src/com/fteqw/FTEDroidActivity.java | 154 ++-- .../droid/src/com/fteqw/FTEDroidEngine.java | 5 +- engine/gl/gl_alias.c | 119 ++- engine/gl/gl_backend.c | 9 +- engine/gl/gl_draw.c | 1 + engine/gl/gl_font.c | 3 +- engine/gl/gl_model.c | 1 + engine/gl/gl_model.h | 2 - engine/gl/gl_rmain.c | 9 +- engine/gl/gl_shader.c | 10 +- engine/gl/gl_shadow.c | 2 +- engine/gl/glmod_doom.c | 44 +- engine/gl/glquake.h | 1 + engine/gl/shader.h | 1 + engine/server/pr_cmds.c | 34 +- engine/server/progdefs.h | 2 +- engine/server/savegame.c | 44 +- engine/server/server.h | 40 +- engine/server/sv_ents.c | 554 +++++++++++++- engine/server/sv_init.c | 17 +- engine/server/sv_main.c | 255 +++---- engine/server/sv_mvd.c | 4 +- engine/server/sv_phys.c | 43 +- engine/server/sv_send.c | 59 +- engine/server/sv_user.c | 160 ++-- engine/server/svhl_game.c | 44 +- engine/server/svq2_ents.c | 4 +- engine/server/svq2_game.c | 3 + engine/server/svq3_game.c | 24 +- 74 files changed, 3175 insertions(+), 1276 deletions(-) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 72de0ab86..90bd9126e 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -37,11 +37,13 @@ extern cvar_t cl_nolerp; extern cvar_t cl_nolerp_netquake; extern cvar_t r_torch; extern cvar_t r_shadows; +extern cvar_t r_showbboxes; extern cvar_t cl_gibfilter, cl_deadbodyfilter; extern int cl_playerindex; -static struct predicted_player { +static struct predicted_player +{ int flags; qboolean active; vec3_t origin; // predicted origin @@ -54,6 +56,9 @@ static struct predicted_player { } predicted_players[MAX_CLIENTS]; static void CL_LerpNetFrameState(int fsanim, framestate_t *fs, lerpents_t *le); +qboolean CL_PredictPlayer(lerpents_t *le, entity_state_t *state, int sequence); +void CL_PlayerFrameUpdated(player_state_t *plstate, entity_state_t *state, int sequence); + extern int cl_playerindex, cl_h_playerindex, cl_rocketindex, cl_grenadeindex, cl_gib1index, cl_gib2index, cl_gib3index; @@ -86,9 +91,11 @@ qboolean CL_FilterModelindex(int modelindex, int frame) void CL_FreeDlights(void) { -#ifdef warningmsg -#pragma warningmsg("not freeing shadowmeshes") -#endif + int i; + for (i = 0; i < rtlights_max; i++) + if (cl_dlights[i].worldshadowmesh) + SH_FreeShadowMesh(cl_dlights[i].worldshadowmesh); + rtlights_max = cl_maxdlights = 0; BZ_Free(cl_dlights); cl_dlights = NULL; @@ -299,7 +306,7 @@ Can go from either a baseline or a previous packet_entity ================== */ //int bitcounts[32]; /// just for protocol profiling -void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean new) +void CLQW_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean new) { int i; #ifdef PROTOCOLEXTENSIONS @@ -330,13 +337,18 @@ void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean morebits |= MSG_ReadByte()<<8; #endif + if ((morebits & U_ENTITYDBL) && (cls.fteprotocolextensions & PEXT_ENTITYDBL)) + to->number += 512; + if ((morebits & U_ENTITYDBL2) && (cls.fteprotocolextensions & PEXT_ENTITYDBL2)) + to->number += 1024; + if (bits & U_MODEL) { to->modelindex = MSG_ReadByte (); - if (morebits & U_MODELDBL && cls.fteprotocolextensions & PEXT_MODELDBL) + if (morebits & U_MODELDBL && (cls.fteprotocolextensions & PEXT_MODELDBL)) to->modelindex += 256; } - else if (morebits & U_MODELDBL && cls.fteprotocolextensions & PEXT_MODELDBL) + else if (morebits & U_MODELDBL && (cls.fteprotocolextensions & PEXT_MODELDBL)) to->modelindex = MSG_ReadShort(); if (bits & U_FRAME) @@ -346,7 +358,11 @@ void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean to->colormap = MSG_ReadByte(); if (bits & U_SKIN) + { to->skinnum = MSG_ReadByte(); + if (to->skinnum >= 256-32) /*final 32 skins are taken as a content value instead*/ + to->skinnum = (char)to->skinnum; + } if (bits & U_EFFECTS) to->effects = (to->effects&0xff00)|MSG_ReadByte(); @@ -369,9 +385,10 @@ void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean if (bits & U_ANGLE3) to->angles[2] = MSG_ReadAngle (); + to->solid = ES_SOLID_BSP; if (bits & U_SOLID) { - // FIXME + //doesn't mean anything. solidity is infered instead. } #ifdef PEXT_SCALE @@ -399,11 +416,6 @@ void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean to->colormod[2] = MSG_ReadByte(); } - if ((morebits & U_ENTITYDBL) && (cls.fteprotocolextensions & PEXT_ENTITYDBL)) - to->number += 512; - if ((morebits & U_ENTITYDBL2) && (cls.fteprotocolextensions & PEXT_ENTITYDBL2)) - to->number += 1024; - if (morebits & U_DPFLAGS)// && cls.fteprotocolextensions & PEXT_DPFLAGS) { // these are bits for the 'flags' field of the entity_state_t @@ -466,10 +478,324 @@ void FlushEntityPacket (void) if (!word) break; // done - CL_ParseDelta (&olde, &newe, word, true); + CLQW_ParseDelta (&olde, &newe, word, true); } } +void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *olds, entity_state_t *baseline) +{ + unsigned int bits; + + bits = MSG_ReadByte(); + if (bits & UF_EXTEND1) + bits |= MSG_ReadByte()<<8; + if (bits & UF_EXTEND2) + bits |= MSG_ReadByte()<<16; + if (bits & UF_EXTEND3) + bits |= MSG_ReadByte()<<24; + + if (cl_shownet.ival >= 3) + Con_Printf("%3i: Update %4i 0x%x\n", msg_readcount, entnum, bits); + + if (bits & UF_RESET) + *news = *baseline; + else if (!olds) + { + Con_DPrintf("New entity without reset\n"); + *news = *baseline; + } + else + *news = *olds; + news->number = entnum; + + if (bits & UF_FRAME) + { + if (bits & UF_16BIT) + news->frame = MSG_ReadShort(); + else + news->frame = MSG_ReadByte(); + } + + if (bits & UF_ORIGINXY) + { + news->origin[0] = MSG_ReadCoord(); + news->origin[1] = MSG_ReadCoord(); + } + if (bits & UF_ORIGINZ) + news->origin[2] = MSG_ReadCoord(); + + if (bits & UF_PREDINFO) + { + /*predicted stuff gets more precise angles*/ + if (bits & UF_ANGLESXZ) + { + news->angles[0] = MSG_ReadAngle16(); + news->angles[2] = MSG_ReadAngle16(); + } + if (bits & UF_ANGLESY) + news->angles[1] = MSG_ReadAngle16(); + } + else + { + if (bits & UF_ANGLESXZ) + { + news->angles[0] = MSG_ReadAngle(); + news->angles[2] = MSG_ReadAngle(); + } + if (bits & UF_ANGLESY) + news->angles[1] = MSG_ReadAngle(); + } + + if ((bits & (UF_EFFECTS | UF_EFFECTS2)) == (UF_EFFECTS | UF_EFFECTS2)) + news->effects = MSG_ReadLong(); + else if (bits & UF_EFFECTS2) + news->effects = MSG_ReadShort(); + else if (bits & UF_EFFECTS) + news->effects = MSG_ReadByte(); + + news->u.q1.movement[0] = 0; + news->u.q1.movement[1] = 0; + news->u.q1.movement[2] = 0; + news->u.q1.velocity[0] = 0; + news->u.q1.velocity[1] = 0; + news->u.q1.velocity[2] = 0; + if (bits & UF_PREDINFO) + { + unsigned int predbits; + predbits = MSG_ReadByte(); + + if (predbits & UFP_FORWARD) + news->u.q1.movement[0] = MSG_ReadShort(); + else + news->u.q1.movement[0] = 0; + if (predbits & UFP_SIDE) + news->u.q1.movement[1] = MSG_ReadShort(); + else + news->u.q1.movement[1] = 0; + if (predbits & UFP_UP) + news->u.q1.movement[2] = MSG_ReadShort(); + else + news->u.q1.movement[2] = 0; + if (predbits & UFP_MOVETYPE) + news->u.q1.pmovetype = MSG_ReadByte(); + if (predbits & UFP_VELOCITYXY) + { + news->u.q1.velocity[0] = MSG_ReadShort(); + news->u.q1.velocity[1] = MSG_ReadShort(); + } + else + { + news->u.q1.velocity[0] = 0; + news->u.q1.velocity[1] = 0; + } + if (predbits & UFP_VELOCITYZ) + news->u.q1.velocity[2] = MSG_ReadShort(); + else + news->u.q1.velocity[2] = 0; + if (predbits & UFP_MSEC) + news->u.q1.msec = MSG_ReadByte(); + else + news->u.q1.msec = 0; + } + else + { + news->u.q1.pmovetype = 0; + news->u.q1.msec = 0; + } + + if (bits & UF_MODEL) + { + if (bits & UF_16BIT) + news->modelindex = MSG_ReadShort(); + else + news->modelindex = MSG_ReadByte(); + } + if (bits & UF_SKIN) + { + if (bits & UF_16BIT) + news->skinnum = MSG_ReadShort(); + else + news->skinnum = MSG_ReadByte(); + } + if (bits & UF_COLORMAP) + news->colormap = MSG_ReadByte(); + + if (bits & UF_SOLID) + news->solid = MSG_ReadShort(); + + if (bits & UF_FLAGS) + news->dpflags = MSG_ReadByte(); + + if (bits & UF_ALPHA) + news->trans = MSG_ReadByte(); + if (bits & UF_SCALE) + news->scale = MSG_ReadByte(); + if (bits & UF_ABSLIGHT) + news->abslight = MSG_ReadByte(); + if (bits & UF_DRAWFLAGS) + news->hexen2flags = MSG_ReadByte(); + if (bits & UF_TAGINFO) + { + news->tagentity = MSG_ReadShort(); + news->tagindex = MSG_ReadByte(); + } + if (bits & UF_LIGHT) + { + news->light[0] = MSG_ReadShort(); + news->light[1] = MSG_ReadShort(); + news->light[1] = MSG_ReadShort(); + news->light[1] = MSG_ReadShort(); + news->lightstyle = MSG_ReadByte(); + news->lightpflags = MSG_ReadByte(); + } + if (bits & UF_COLORMOD) + { + news->colormod[0] = MSG_ReadByte(); + news->colormod[1] = MSG_ReadByte(); + news->colormod[2] = MSG_ReadByte(); + } + if (bits & UF_GLOWMOD) + { + news->glowmod[0] = MSG_ReadByte(); + news->glowmod[1] = MSG_ReadByte(); + news->glowmod[2] = MSG_ReadByte(); + } + + if (bits & UF_FATNESS) + news->fatness = MSG_ReadByte(); + + + + /*update the prediction info if needed*/ + if ((bits & UF_PREDINFO) && (news->number-1) < cl.allocated_client_slots) + { + frame_t *fram; + fram = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; + CL_PlayerFrameUpdated(&fram->playerstate[news->number-1], news, cls.netchan.incoming_sequence); + } +} + +void CLFTE_ParseEntities(void) +{ + int oldpacket, newpacket; + packet_entities_t *oldp, *newp, nullp; + unsigned short newnum, oldnum; + int oldindex; + qboolean isvalid = false; + +// int i; +// for (i = cl.validsequence+1; i < cls.netchan.incoming_sequence; i++) +// { +// Con_Printf("CL: Dropped %i\n", i); +// } + + newpacket = cls.netchan.incoming_sequence&UPDATE_MASK; + oldpacket = cl.validsequence&UPDATE_MASK; + newp = &cl.frames[newpacket].packet_entities; + oldp = &cl.frames[oldpacket].packet_entities; + cl.frames[newpacket].invalid = true; + + + if (cls.netchan.incoming_sequence >= cl.validsequence + UPDATE_BACKUP) + { + oldp = &nullp; + oldp->num_entities = 0; + oldp->max_entities = 0; + } + else + isvalid = true; + + newp->servertime = MSG_ReadFloat(); + + cl.oldgametime = cl.gametime; + cl.oldgametimemark = cl.gametimemark; + cl.gametime = newp->servertime; + cl.gametimemark = realtime; + + /*clear all entities*/ + newp->num_entities = 0; + oldindex = 0; + while(1) + { + newnum = MSG_ReadShort(); + if (!newnum || msg_badread) + { + /*reached the end, don't forget old entities*/ + while(oldindex < oldp->num_entities) + { + if (newp->num_entities >= newp->max_entities) + { + newp->max_entities = newp->num_entities+1; + newp->entities = BZ_Realloc(newp->entities, sizeof(entity_state_t)*newp->max_entities); + } + newp->entities[newp->num_entities++] = oldp->entities[oldindex++]; + } + break; + } + if (newnum == 0x8000) + { + if (cl_shownet.ival >= 3) + Con_Printf("%3i: Reset all\n", msg_readcount); + newp->num_entities = 0; + isvalid = true; + continue; + } + + oldnum = oldindex >= oldp->num_entities ? 0xffff : oldp->entities[oldindex].number; + + /*if we skipped some, then they were unchanged*/ + while ((newnum&0x7fff) > oldnum) + { + if (newp->num_entities >= newp->max_entities) + { + newp->max_entities = newp->num_entities+1; + newp->entities = BZ_Realloc(newp->entities, sizeof(entity_state_t)*newp->max_entities); + } + newp->entities[newp->num_entities++] = oldp->entities[oldindex++]; + + oldnum = oldindex >= oldp->num_entities ? 0xffff : oldp->entities[oldindex].number; + } + + if (newnum & 0x8000) + { + if (cl_shownet.ival >= 3) + Con_Printf("%3i: Remove %i\n", msg_readcount, (newnum&32767)); + if (oldnum == (newnum&0x7fff)) + oldindex++; + continue; + } + else + { + if (!CL_CheckBaselines(newnum)) + Host_EndGame("CL_ParsePacketEntities: check baselines failed with size %i", newnum); + + if (newp->num_entities >= newp->max_entities) + { + newp->max_entities = newp->num_entities+1; + newp->entities = BZ_Realloc(newp->entities, sizeof(entity_state_t)*newp->max_entities); + } + + if (oldnum == newnum) + CLFTE_ReadDelta(newnum, &newp->entities[newp->num_entities++], &oldp->entities[oldindex++], cl_baselines + newnum); + else + CLFTE_ReadDelta(newnum, &newp->entities[newp->num_entities++], NULL, cl_baselines + newnum); + } + } + + if (isvalid) + { + cl.oldvalidsequence = cl.validsequence; + cl.validsequence = cls.netchan.incoming_sequence; + cl.ackedinputsequence = cl.validsequence; + cl.frames[newpacket].invalid = false; + } + else + cl.validsequence = 0; + + /*ackedinputsequence is updated when we have new player prediction info*/ + cl.ackedinputsequence = cls.netchan.incoming_sequence; +} + /* ================== CL_ParsePacketEntities @@ -657,7 +983,7 @@ void CL_ParsePacketEntities (qboolean delta) if (!CL_CheckBaselines(newnum)) Host_EndGame("CL_ParsePacketEntities: check baselines failed with size %i", newnum); - CL_ParseDelta (cl_baselines + newnum, &newp->entities[newindex], word, true); + CLQW_ParseDelta (cl_baselines + newnum, &newp->entities[newindex], word, true); newindex++; continue; } @@ -685,7 +1011,7 @@ void CL_ParsePacketEntities (qboolean delta) } //Con_Printf ("delta %i\n",newnum); - CL_ParseDelta (&oldp->entities[oldindex], &newp->entities[newindex], word, false); + CLQW_ParseDelta (&oldp->entities[oldindex], &newp->entities[newindex], word, false); newindex++; oldindex++; } @@ -745,9 +1071,10 @@ void DP5_ParseDelta(entity_state_t *s) s->trans = 255; s->scale = 16; s->number = num; - s->colormod[0] = 32; - s->colormod[1] = 32; - s->colormod[2] = 32; + s->colormod[0] = (256)/8; + s->colormod[1] = (256)/8; + s->colormod[2] = (256)/8; + s->solid = ES_SOLID_BSP; // s->active = true; } if (bits & E5_FLAGS) @@ -846,10 +1173,16 @@ void DP5_ParseDelta(entity_state_t *s) s->colormod[1] = MSG_ReadByte(); s->colormod[2] = MSG_ReadByte(); } + if (bits & E5_GLOWMOD) + { + s->glowmod[0] = MSG_ReadByte(); + s->glowmod[1] = MSG_ReadByte(); + s->glowmod[2] = MSG_ReadByte(); + } } int cl_latestframenum; -void CLNQ_ParseDarkPlaces5Entities(void) //the things I do.. :o( +void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o( { //the incoming entities do not come in in any order. :( //well, they come in in order of priorities, but that's not useful to us. @@ -987,7 +1320,7 @@ void CLNQ_ParseDarkPlaces5Entities(void) //the things I do.. :o( void CLNQ_ParseEntity(unsigned int bits) { int i; - int num, pnum; + int num; entity_state_t *state;//, *from; entity_state_t *base; static float lasttime; @@ -1045,6 +1378,7 @@ void CLNQ_ParseEntity(unsigned int bits) base = cl_baselines + num; state->number = num; + state->solid = ES_SOLID_BSP; state->dpflags = (bits & NQU_NOLERP)?RENDER_STEP:0; @@ -1426,6 +1760,194 @@ int V_AddLight (int entsource, vec3_t org, float quant, float r, float g, float return CL_NewDlightRGB (entsource, org, quant, -0.1, r, g, b) - cl_dlights; } +static void CLQ1_AddCube(shader_t *shader, vec3_t mins, vec3_t maxs, float r, float g, float b, float a) +{ + int v; + scenetris_t *t; + + if (!r && !g && !b) + return; + if (g && !b) + b = 0; + + /*reuse the previous trigroup if its the same shader*/ + if (cl_numstris && cl_stris[cl_numstris-1].shader == shader) + t = &cl_stris[cl_numstris-1]; + else + { + if (cl_numstris == cl_maxstris) + { + cl_maxstris += 8; + cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + } + t = &cl_stris[cl_numstris++]; + t->shader = shader; + t->numidx = 0; + t->numvert = 0; + t->firstidx = cl_numstrisidx; + t->firstvert = cl_numstrisvert; + } + + + if (cl_numstrisvert + 8 > cl_maxstrisvert) + { + cl_maxstrisvert = cl_numstrisvert + 8; + + cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert); + cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(vec2_t)*cl_maxstrisvert); + cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(vec4_t)*cl_maxstrisvert); + } + if (cl_maxstrisidx < cl_numstrisidx+6*6) + { + cl_maxstrisidx = cl_numstrisidx+6*6 + 64; + cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); + } + + + for (v = 0; v < 8; v++) + { + cl_strisvertv[cl_numstrisvert+v][0] = (v & 1)?mins[0]:maxs[0]; + cl_strisvertv[cl_numstrisvert+v][1] = (v & 2)?mins[1]:maxs[1]; + cl_strisvertv[cl_numstrisvert+v][2] = (v & 4)?mins[2]:maxs[2]; + + cl_strisvertt[cl_numstrisvert+v][0] = 0; + cl_strisvertt[cl_numstrisvert+v][1] = 0; + + cl_strisvertc[cl_numstrisvert+v][0] = r; + cl_strisvertc[cl_numstrisvert+v][1] = g; + cl_strisvertc[cl_numstrisvert+v][2] = b; + cl_strisvertc[cl_numstrisvert+v][3] = a; + } + + /*top*/ + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+3; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2; + + /*bottom*/ + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+4; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+5; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+6; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+6; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+5; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+7; + + /*'left'*/ + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+5; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+4; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+5; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0; + + /*right*/ + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+6; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+7; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+7; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+3; + + /*urm, the other way*/ + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+4; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+6; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+4; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0; + + /*and its oposite*/ + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+7; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+5; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+3; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+3; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+5; + + t->numvert += 8; + t->numidx = cl_numstrisidx - t->firstidx; + cl_numstrisvert += 8; +} +#include "pr_common.h" +void CLQ1_AddVisibleBBoxes(void) +{ + world_t *w; + wedict_t *e; + int i; + shader_t *s; + extern world_t csqc_world; + vec3_t min, max, size; + + switch(r_showbboxes.ival & 3) + { + default: + return; + + #ifndef CLIENTONLY + case 1: + w = &sv.world; + break; + #endif + #ifdef CSQC_DAT + case 2: + w = &csqc_world; + return; + #endif + } + + if (!w->progs) + return; + + s = R_RegisterShader("bboxshader", + "{\n" + "polygonoffset\n" + "{\n" + "map $whiteimage\n" + "blendfunc add\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "}\n" + "}\n"); + for (i = 1; i < w->num_edicts; i++) + { + e = WEDICT_NUM(w->progs, i); + if (e->isfree) + continue; + + if (r_showbboxes.ival & 4) + { + /*mins is easy*/ + VectorAdd(e->v->origin, e->v->mins, min); + + /*maxs is weeeeird*/ + VectorSubtract (e->v->maxs, e->v->mins, size); + if (size[0] < 3) + VectorCopy(min, max); + else if (size[0] <= 32) + { + max[0] = min[0] + 32; + max[1] = min[1] + 32; + max[2] = min[2] + 56; + } + else + { + max[0] = min[0] + 64; + max[1] = min[1] + 64; + max[2] = min[2] + 88; + } + } + else + { + VectorCopy(e->v->absmin, min); + VectorCopy(e->v->absmax, max); + } + CLQ1_AddCube(s, min, max, (e->v->solid || e->v->movetype)?0.1:0, (e->v->movetype == MOVETYPE_STEP || e->v->movetype == MOVETYPE_TOSS || e->v->movetype == MOVETYPE_BOUNCE)?0.1:0, ((int)e->v->flags & (FL_ONGROUND | ((e->v->movetype == MOVETYPE_STEP)?FL_FLY:0)))?0.1:0, 1); + } +} + void CLQ1_AddShadow(entity_t *ent) { float radius; @@ -1671,6 +2193,8 @@ void CL_LinkStaticEntities(void *pvs) ent->framestate.g[FS_REG].frametime[0] = cl.time; ent->framestate.g[FS_REG].frametime[1] = cl.time; + ent->shaderRGBAf[3] = 0.7; + // emit particles for statics (we don't need to cheat check statics) if (clmodel->particleeffect >= 0 && gl_part_flame.ival) { @@ -1696,7 +2220,7 @@ void R_FlameTrail(vec3_t start, vec3_t end, float seperation); /* Interpolates the two packets by the given time, writes its results into the lerpentities array. */ -static void CL_TransitionPacketEntities(packet_entities_t *newpack, packet_entities_t *oldpack, float servertime) +static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newpack, packet_entities_t *oldpack, float servertime) { lerpents_t *le; entity_state_t *snew, *sold; @@ -1757,7 +2281,17 @@ static void CL_TransitionPacketEntities(packet_entities_t *newpack, packet_entit VectorClear(move); } - if (sold == snew) + VectorCopy(le->origin, le->lastorigin); + if (snew->u.q1.pmovetype && CL_PredictPlayer(le, snew, newsequence)) + { + if (sold == snew) + { + /*keep trails correct*/ + le->isnew = true; + VectorCopy(le->origin, le->lastorigin); + } + } + else if (sold == snew) { //new this frame (or we noticed something changed significantly) VectorCopy(snew->origin, le->origin); @@ -1776,8 +2310,6 @@ static void CL_TransitionPacketEntities(packet_entities_t *newpack, packet_entit } else { - VectorCopy(le->origin, le->lastorigin); - if (snew->dpflags & RENDER_STEP) { float lfrac; @@ -1946,7 +2478,7 @@ void CL_TransitionEntities (void) packnew = &cl.frames[newf].packet_entities; packold = &cl.frames[oldf].packet_entities; - CL_TransitionPacketEntities(packnew, packold, servertime); + CL_TransitionPacketEntities(newff, packnew, packold, servertime); cl.currentpacktime = servertime; cl.currentpackentities = packnew; @@ -1973,7 +2505,9 @@ void CL_TransitionEntities (void) for (p = 0; p < cl.allocated_client_slots; p++, pnew++, pold++) { if (pnew->messagenum != newff) + { continue; + } le = &cl.lerpplayers[p]; VectorSubtract(pnew->predorigin, pold->predorigin, move); @@ -2205,10 +2739,11 @@ void CL_LinkPacketEntities (void) //set scale ent->scale = state->scale/16.0; #endif - ent->shaderRGBAf[0] = (state->colormod[0]*8.0f)/255; - ent->shaderRGBAf[1] = (state->colormod[1]*8.0f)/255; - ent->shaderRGBAf[2] = (state->colormod[2]*8.0f)/255; + ent->shaderRGBAf[0] = (state->colormod[0]*8.0f)/256; + ent->shaderRGBAf[1] = (state->colormod[1]*8.0f)/256; + ent->shaderRGBAf[2] = (state->colormod[2]*8.0f)/256; ent->shaderRGBAf[3] = state->trans/255.0f; + #ifdef PEXT_FATNESS //set trans ent->fatness = state->fatness/16.0; @@ -2238,6 +2773,7 @@ void CL_LinkPacketEntities (void) AngleVectors(angles, ent->axis[0], ent->axis[1], ent->axis[2]); VectorInverse(ent->axis[1]); + /*if this entity is in a player's slot...*/ if (ent->keynum <= cl.allocated_client_slots) { if (!cl.nolocalplayer[0]) @@ -2347,6 +2883,8 @@ void CL_LinkPacketEntities (void) #ifdef CSQC_DAT CSQC_DeltaEnd(); #endif + + CLQ1_AddVisibleBBoxes(); } /* @@ -2614,7 +3152,8 @@ void CL_ParsePlayerinfo (void) if (flags & DF_WEAPONFRAME) state->weaponframe = MSG_ReadByte (); - state->hullnum = 1; + VectorSet(state->szmins, -16, -16, -24); + VectorSet(state->szmaxs, 16, 16, 32); state->scale = 1; state->alpha = 255; state->fatness = 0; @@ -2729,10 +3268,8 @@ void CL_ParsePlayerinfo (void) else state->weaponframe = 0; - if (cl.worldmodel && cl.worldmodel->fromgame == fg_quake) - state->hullnum = 1; - else - state->hullnum = 56; + VectorSet(state->szmins, -16, -16, -24); + VectorSet(state->szmaxs, 16, 16, 32); state->scale = 1; state->alpha = 255; state->fatness = 0; @@ -2750,15 +3287,31 @@ void CL_ParsePlayerinfo (void) state->fatness = (float)MSG_ReadChar(); #endif #ifdef PEXT_HULLSIZE - if (cls.fteprotocolextensions & PEXT_HULLSIZE) + if ((cls.fteprotocolextensions & PEXT_HULLSIZE) && (flags & PF_HULLSIZE_Z)) { - if (flags & PF_HULLSIZE_Z) - state->hullnum = MSG_ReadByte(); + int num; + num = MSG_ReadByte(); + + if (cl.worldmodel->fromgame != fg_quake) + { + VectorScale(state->szmins, num/56.0f, state->szmins); + VectorScale(state->szmaxs, num/56.0f, state->szmaxs); + } + else + { + VectorCopy(cl.worldmodel->hulls[num&(MAX_MAP_HULLSM-1)].clip_mins, state->szmins); + VectorCopy(cl.worldmodel->hulls[num&(MAX_MAP_HULLSM-1)].clip_maxs, state->szmaxs); + } + if (num & 128) + { //this hack is for hexen2. + state->szmaxs[2] -= state->szmins[2]; + state->szmins[2] = 0; + } } //should be passed to player move func. #endif - if (cls.fteprotocolextensions & PEXT_COLOURMOD && flags & PF_COLOURMOD) + if (cls.fteprotocolextensions & PEXT_COLOURMOD && (flags & PF_COLOURMOD)) { state->colourmod[0] = MSG_ReadByte(); state->colourmod[1] = MSG_ReadByte(); @@ -2836,7 +3389,7 @@ guess_pm_type: state->command.msec = msec; CL_SetSolidEntities(); - CL_SetSolidPlayers (num); + CL_SetSolidPlayers(); CL_PredictUsercmd (0, state, &exact, &state->command); //uses player 0's maxspeed/grav... VectorCopy (exact.origin, state->predorigin); } @@ -3191,7 +3744,7 @@ void CL_LinkPlayers (void) //Con_DPrintf ("predict: %i\n", msec); oldphysent = pmove.numphysent; - CL_SetSolidPlayers (j); + CL_SetSolidPlayers (); CL_PredictUsercmd (0, state, &exact, &state->command); //uses player 0's maxspeed/grav... pmove.numphysent = oldphysent; VectorCopy (exact.origin, ent->origin); @@ -3363,6 +3916,7 @@ void CL_SetSolidEntities (void) frame_t *frame; packet_entities_t *pak; entity_state_t *state; + physent_t *pent; memset(&pmove.physents[0], 0, sizeof(physent_t)); pmove.physents[0].model = cl.worldmodel; @@ -3377,22 +3931,67 @@ void CL_SetSolidEntities (void) { state = &pak->entities[i]; - if (state->modelindex <= 0) + if (!state->solid && !state->skinnum) continue; - if (!cl.model_precache[state->modelindex]) - continue; - if (*cl.model_precache[state->modelindex]->name == '*' || cl.model_precache[state->modelindex]->numsubmodels) - if ( cl.model_precache[state->modelindex]->hulls[1].firstclipnode) + + if (state->solid == 31) + { /*bsp model size*/ + if (state->modelindex <= 0) + continue; + if (!cl.model_precache[state->modelindex]) + continue; + /*this makes non-inline bsp objects non-solid for prediction*/ + if ((*cl.model_precache[state->modelindex]->name == '*' || cl.model_precache[state->modelindex]->numsubmodels) && cl.model_precache[state->modelindex]->hulls[1].firstclipnode) + { + pent = &pmove.physents[pmove.numphysent]; + memset(pent, 0, sizeof(physent_t)); + pent->model = cl.model_precache[state->modelindex]; + VectorCopy (state->angles, pent->angles); + pent->angles[0]*=-1; + } + else + continue; + } + else { - memset(&pmove.physents[pmove.numphysent], 0, sizeof(physent_t)); - pmove.physents[pmove.numphysent].model = cl.model_precache[state->modelindex]; - VectorCopy (state->origin, pmove.physents[pmove.numphysent].origin); - VectorCopy (state->angles, pmove.physents[pmove.numphysent].angles); -// VectorCopy (cl.lerpents[state->number].origin, pmove.physents[pmove.numphysent].origin); -// VectorCopy (cl.lerpents[state->number].angles, pmove.physents[pmove.numphysent].angles); - pmove.physents[pmove.numphysent].angles[0]*=-1; - if (++pmove.numphysent == MAX_PHYSENTS) - break; + pent = &pmove.physents[pmove.numphysent]; + memset(pent, 0, sizeof(physent_t)); + pent->info = state->number; + /*don't bother with angles*/ + pent->maxs[0] = pent->maxs[1] = 8*(state->solid & 31); + pent->mins[0] = pent->mins[1] = -pent->maxs[0]; + pent->mins[2] = -8*((state->solid>>5) & 31); + pent->maxs[2] = 8*((state->solid>>10) & 63) - 32; + } + if (++pmove.numphysent == MAX_PHYSENTS) + break; + VectorCopy(state->origin, pent->origin); + pent->info = state->number; + + switch((int)state->skinnum) + { + case 0: + break; + case -16: + pent->nonsolid = true; + pent->forcecontentsmask = FTECONTENTS_LADDER; + break; + case Q1CONTENTS_SKY: + pent->nonsolid = true; + pent->forcecontentsmask = FTECONTENTS_SKY; + break; + case Q1CONTENTS_LAVA: + pent->nonsolid = true; + pent->forcecontentsmask = FTECONTENTS_LAVA; + break; + case Q1CONTENTS_SLIME: + pent->nonsolid = true; + pent->forcecontentsmask = FTECONTENTS_SLIME; + break; + case Q1CONTENTS_WATER: + pent->nonsolid = true; + pent->forcecontentsmask = FTECONTENTS_WATER; + break; } } @@ -3500,7 +4099,7 @@ pmove must be setup with world and solid entity hulls before calling (via CL_PredictMove) =============== */ -void CL_SetSolidPlayers (int playernum) +void CL_SetSolidPlayers (void) { int j; extern vec3_t player_mins; @@ -3521,10 +4120,6 @@ void CL_SetSolidPlayers (int playernum) if (!pplayer->active) continue; // not present this frame - // the player object never gets added - if (j == playernum) - continue; - if (pplayer->flags & PF_DEAD) continue; // dead players aren't solid diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 71073561a..088750f3e 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -48,7 +48,7 @@ usercmd_t independantphysics[MAX_SPLITS]; vec3_t mousemovements[MAX_SPLITS]; /*kinda a hack...*/ -int con_splitmodifier; +static int con_splitmodifier; cvar_t cl_forcesplitclient = CVAR("cl_forcesplitclient", "0"); extern cvar_t cl_splitscreen; int CL_TargettedSplit(qboolean nowrap) @@ -96,6 +96,22 @@ void CL_Split_f(void) } con_splitmodifier = tmp; } +void CL_SplitA_f(void) +{ + int tmp; + char *c, *args; + c = Cmd_Argv(0); + args = COM_Parse(Cmd_Args()); + while(*args == ' ' || *args == '\t') + args++; + tmp = con_splitmodifier; + con_splitmodifier = atoi(com_token); + if (*c == '+' || *c == '-') + Cmd_ExecuteString(va("%c%s", *c, args), Cmd_ExecLevel); + else + Cmd_ExecuteString(args, Cmd_ExecLevel); + con_splitmodifier = tmp; +} /* =============================================================================== @@ -1748,6 +1764,11 @@ void CL_InitInput (void) in_mlook.state[sp] = 1; #endif } + + /*then alternative arged ones*/ + Cmd_AddCommand ("p", CL_SplitA_f); + Cmd_AddCommand ("+p", CL_SplitA_f); + Cmd_AddCommand ("-p", CL_SplitA_f); Cmd_AddCommand ("+moveup", IN_UpDown); Cmd_AddCommand ("-moveup", IN_UpUp); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 0ebd4fb72..c4878d267 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -318,85 +318,8 @@ void CL_SupportedFTEExtensions(int *pext1, int *pext2) unsigned int fteprotextsupported = 0; unsigned int fteprotextsupported2 = 0; -#ifdef PEXT_SCALE //dmw - protocol extensions - fteprotextsupported |= PEXT_SCALE; -#endif -#ifdef PEXT_LIGHTSTYLECOL - fteprotextsupported |= PEXT_LIGHTSTYLECOL; -#endif -#ifdef PEXT_TRANS - fteprotextsupported |= PEXT_TRANS; -#endif -#ifdef PEXT_VIEW2 - fteprotextsupported |= PEXT_VIEW2; -#endif -#ifdef PEXT_ACCURATETIMINGS - fteprotextsupported |= PEXT_ACCURATETIMINGS; -#endif -#ifdef PEXT_ZLIBDL - fteprotextsupported |= PEXT_ZLIBDL; -#endif -#ifdef PEXT_FATNESS - fteprotextsupported |= PEXT_FATNESS; -#endif -#ifdef PEXT_HLBSP - fteprotextsupported |= PEXT_HLBSP; -#endif - -#ifdef PEXT_Q2BSP - fteprotextsupported |= PEXT_Q2BSP; -#endif -#ifdef PEXT_Q3BSP - fteprotextsupported |= PEXT_Q3BSP; -#endif - -#ifdef PEXT_TE_BULLET - fteprotextsupported |= PEXT_TE_BULLET; -#endif -#ifdef PEXT_HULLSIZE - fteprotextsupported |= PEXT_HULLSIZE; -#endif -#ifdef PEXT_SETVIEW - fteprotextsupported |= PEXT_SETVIEW; -#endif -#ifdef PEXT_MODELDBL - fteprotextsupported |= PEXT_MODELDBL; -#endif -#ifdef PEXT_SOUNDDBL - fteprotextsupported |= PEXT_SOUNDDBL; -#endif -#ifdef PEXT_VWEAP - fteprotextsupported |= PEXT_VWEAP; -#endif -#ifdef PEXT_FLOATCOORDS - fteprotextsupported |= PEXT_FLOATCOORDS; -#endif - fteprotextsupported |= PEXT_SPAWNSTATIC2; - fteprotextsupported |= PEXT_COLOURMOD; - fteprotextsupported |= PEXT_SPLITSCREEN; - fteprotextsupported |= PEXT_HEXEN2; - fteprotextsupported |= PEXT_CUSTOMTEMPEFFECTS; - fteprotextsupported |= PEXT_256PACKETENTITIES; - fteprotextsupported |= PEXT_ENTITYDBL; - fteprotextsupported |= PEXT_ENTITYDBL2; -// fteprotextsupported |= PEXT_64PLAYERS; - fteprotextsupported |= PEXT_SHOWPIC; - fteprotextsupported |= PEXT_SETATTACHMENT; -#ifdef PEXT_CHUNKEDDOWNLOADS - fteprotextsupported |= PEXT_CHUNKEDDOWNLOADS; -#endif -#ifdef PEXT_CSQC - fteprotextsupported |= PEXT_CSQC; -#endif -#ifdef PEXT_DPFLAGS - fteprotextsupported |= PEXT_DPFLAGS; -#endif - - fteprotextsupported2 |= PEXT2_PRYDONCURSOR; -#ifdef PEXT2_VOICECHAT - fteprotextsupported2 |= PEXT2_VOICECHAT; -#endif - fteprotextsupported2 |= PEXT2_SETANGLEDELTA; + fteprotextsupported = Net_PextMask(1); + fteprotextsupported2 = Net_PextMask(2); fteprotextsupported &= strtoul(cl_pext_mask.string, NULL, 16); // fteprotextsupported2 &= strtoul(cl_pext2_mask.string, NULL, 16); @@ -467,7 +390,7 @@ CL_SendConnectPacket called by CL_Connect_f and CL_CheckResend ====================== */ -void CL_SendConnectPacket ( +void CL_SendConnectPacket (int mtu, #ifdef PROTOCOL_VERSION_FTE int ftepext, int ftepext2, #endif @@ -608,6 +531,19 @@ void CL_SendConnectPacket ( Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_FTE2, fteprotextsupported2), sizeof(data)); #endif + if (mtu >= 0) + { + if (adr.type == NA_LOOPBACK) + mtu = 8192; + else if (net_mtu.ival > 64 && mtu > net_mtu.ival) + mtu = net_mtu.ival; + mtu &= ~7; + Q_strncatz(data, va("0x%x %i\n", PROTOCOL_VERSION_FRAGMENT, mtu), sizeof(data)); + cls.netchan.fragmentsize = mtu; + } + else + cls.netchan.fragmentsize = 0; + #ifdef HUFFNETWORK if (compressioncrc && Huff_CompressionCRC(compressioncrc)) { @@ -732,7 +668,7 @@ void CL_CheckForResend (void) CL_ConnectToDarkPlaces("", adr); } else - CL_SendConnectPacket (svs.fteprotocolextensions, svs.fteprotocolextensions2, false); + CL_SendConnectPacket (8192-16, Net_PextMask(1), Net_PextMask(2), false); return; } #endif @@ -1156,7 +1092,7 @@ void CL_ClearState (void) cl.fog_colour[1] = 0.3; cl.fog_colour[2] = 0.3; - cl.allocated_client_slots = MAX_CLIENTS; + cl.allocated_client_slots = QWMAX_CLIENTS; #ifndef CLIENTONLY if (sv.state) cl.allocated_client_slots = sv.allocated_client_slots; @@ -2299,7 +2235,7 @@ void CL_ConnectionlessPacket (void) { static unsigned int lasttime = 0xdeadbeef; unsigned int curtime = Sys_Milliseconds(); - unsigned long pext = 0, pext2 = 0, huffcrc=0; + unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0; Con_TPrintf (TLC_S2C_CHALLENGE); s = MSG_ReadString (); @@ -2317,7 +2253,7 @@ void CL_ConnectionlessPacket (void) cls.protocol = CP_QUAKE3; cls.challenge = atoi(s+17); - CL_SendConnectPacket (0, 0, 0/*, ...*/); + CL_SendConnectPacket (0, 0, 0, 0/*, ...*/); } else { @@ -2412,6 +2348,8 @@ void CL_ConnectionlessPacket (void) pext = MSG_ReadLong (); else if (c == PROTOCOL_VERSION_FTE2) pext2 = MSG_ReadLong (); + else if (c == PROTOCOL_VERSION_FRAGMENT) + mtu = MSG_ReadLong (); else if (c == PROTOCOL_VERSION_VARLENGTH) { int len = MSG_ReadLong(); @@ -2421,14 +2359,14 @@ void CL_ConnectionlessPacket (void) MSG_ReadSkip(len); /*payload*/ } #ifdef HUFFNETWORK - else if (c == (('H'<<0) + ('U'<<8) + ('F'<<16) + ('F' << 24))) + else if (c == PROTOCOL_VERSION_HUFFMAN) huffcrc = MSG_ReadLong (); #endif //else if (c == PROTOCOL_VERSION_...) else MSG_ReadLong (); } - CL_SendConnectPacket (pext, pext2, huffcrc/*, ...*/); + CL_SendConnectPacket (mtu, pext, pext2, huffcrc/*, ...*/); return; } #ifdef Q2CLIENT @@ -2523,6 +2461,7 @@ void CL_ConnectionlessPacket (void) if (c == S2C_CONNECTION) { int compress; + int mtu; #ifdef Q2CLIENT client_connect: //fixme: make function #endif @@ -2535,9 +2474,11 @@ client_connect: //fixme: make function return; } compress = cls.netchan.compress; + mtu = cls.netchan.fragmentsize; Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.qport); - CL_ParseEstablished(); + cls.netchan.fragmentsize = mtu; cls.netchan.compress = compress; + CL_ParseEstablished(); #ifdef Q3CLIENT if (cls.protocol != CP_QUAKE3) #endif @@ -2813,7 +2754,6 @@ void CL_ReadPackets (void) case CP_QUAKEWORLD: if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) { - player_state_t *n,*o; MSG_BeginReading(cls.netchan.netprim); cls.netchan.last_received = realtime; cls.netchan.outgoing_sequence = cls.netchan.incoming_sequence; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index bea6287e4..d31ba43e0 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "cl_ignore.h" void CL_GetNumberedEntityInfo (int num, float *org, float *ang); -void CLNQ_ParseDarkPlaces5Entities(void); +void CLDP_ParseDarkPlaces5Entities(void); void CL_SetStatInt (int pnum, int stat, int value); static qboolean CL_CheckModelResources (char *name); @@ -101,8 +101,8 @@ char *svc_strings[] = "svc_serverinfo", "svc_updatepl", "MVD svc_nails2", - "BAD svc_unused", - "FTE svc_view2", + "svcfte_soundextended", + "svcfte_soundlistshort", "FTE svc_lightstylecol", "FTE svc_bulletentext", // obsolete "FTE svc_lightnings", @@ -140,7 +140,7 @@ char *svc_strings[] = "svcfte_cgamepacket", "svcfte_voicechat", "svcfte_setangledelta", - "???", + "svcfte_updateentities", "???", "???", "???", @@ -280,7 +280,7 @@ int CL_CalcNet (void) else if (frame->invalid) packet_latency[i&NET_TIMINGSMASK] = 9998; // invalid delta else - packet_latency[i&NET_TIMINGSMASK] = (frame->receivedtime - frame->senttime)*20; + packet_latency[i&NET_TIMINGSMASK] = (frame->receivedtime - frame->senttime)*60; } lost = 0; @@ -322,6 +322,7 @@ int CL_CalcNet (void) //returns true if the download is going to be downloaded after the call. qboolean CL_EnqueDownload(char *filename, char *localname, unsigned int flags) { + char *ext; downloadlist_t *dl; qboolean webdl = false; if (localname && !strncmp(filename, "http://", 7)) @@ -336,8 +337,8 @@ qboolean CL_EnqueDownload(char *filename, char *localname, unsigned int flags) if (cls.demoplayback && cls.demoplayback != DPB_EZTV) return false; } - - if (strchr(localname, '\\') || strchr(localname, ':') || strstr(localname, "..")) + ext = COM_FileExtension(localname); + if (!stricmp(localname, "dll") || !stricmp(localname, "so") || strchr(localname, '\\') || strchr(localname, ':') || strstr(localname, "..")) { Con_Printf("Denying download of \"%s\"\n", filename); return false; @@ -658,7 +659,6 @@ Returns true if the file exists, returns false if it triggered a download. qboolean CL_CheckOrEnqueDownloadFile (char *filename, char *localname, unsigned int flags) { //returns false if we don't have the file yet. - if (flags & DLLF_NONGAME) { /*pak/pk3 downloads have an explicit leading package/ as an internal/network marker*/ @@ -1758,6 +1758,29 @@ void CL_ParseDownload (void) size = MSG_ReadShort (); percent = MSG_ReadByte (); + if (size == -2) + { + /*quakeforge*/ + MSG_ReadString(); + return; + } + if (size == -3) + { + char *localname; + Q_strncpyz(name, MSG_ReadString(), sizeof(name)); + localname = MSG_ReadString(); + /*quakeforge http download redirection*/ + if (cls.downloadqw) + { + Con_TPrintf (TL_CLS_DOWNLOAD_ISSET); + VFS_CLOSE (cls.downloadqw); + cls.downloadqw = NULL; + } + CL_DownloadFailed(cls.downloadremotename); + CL_CheckOrEnqueDownloadFile(name, localname, DLLF_IGNOREFAILED); + return; + } + if (cls.demoplayback && cls.demoplayback != DPB_EZTV) { if (size > 0) @@ -2244,6 +2267,7 @@ void CLQW_ParseServerData (void) // game directory str = MSG_ReadString (); + Con_DPrintf("Server is using gamedir \"%s\"\n", str); if (!*str) str = "qw"; @@ -2275,13 +2299,26 @@ void CLQW_ParseServerData (void) Wads_Flush(); } + /*mvds have different parsing*/ if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) { int i,j; - MSG_ReadFloat(); + + if (cls.fteprotocolextensions2 & PEXT2_MAXPLAYERS) + { + cl.allocated_client_slots = MSG_ReadByte(); + if (cl.allocated_client_slots > MAX_CLIENTS) + cl.allocated_client_slots = MAX_CLIENTS; + } + + cl.gametime = MSG_ReadFloat(); + cl.gametimemark = realtime; + cl.oldgametime = cl.gametime; + cl.oldgametimemark = realtime; + for (j = 0; j < MAX_SPLITS; j++) { - cl.playernum[j] = MAX_CLIENTS + j; + cl.playernum[j] = cl.allocated_client_slots + j; for (i = 0; i < UPDATE_BACKUP; i++) { cl.frames[i].playerstate[cl.playernum[j]].pm_type = PM_SPECTATOR; @@ -2292,7 +2329,32 @@ void CLQW_ParseServerData (void) cl.splitclients = 1; } - else + else if (cls.fteprotocolextensions2 & PEXT2_MAXPLAYERS) + { + cl.allocated_client_slots = MSG_ReadByte(); + if (cl.allocated_client_slots > MAX_CLIENTS) + { + cl.allocated_client_slots = MAX_CLIENTS; + Host_EndGame("Server sent us too many alternate clients\n"); + } + + /*parsing here is slightly different to allow us 255 max players instead of 127*/ + cl.splitclients = MSG_ReadByte(); + if (cl.splitclients & 128) + { + cl.spectator = true; + cl.splitclients &= ~128; + } + if (cl.splitclients > MAX_SPLITS) + Host_EndGame("Server sent us too many alternate clients\n"); + for (pnum = 0; pnum < cl.splitclients; pnum++) + { + cl.playernum[pnum] = MSG_ReadByte(); + if (cl.playernum[pnum] >= cl.allocated_client_slots) + Host_EndGame("unsupported local player slot\n"); + } + } + else { // parse player slot, high bit means spectator pnum = MSG_ReadByte (); @@ -2305,6 +2367,9 @@ void CLQW_ParseServerData (void) cl.playernum[clnum] &= ~128; } + if (cl.playernum[clnum] >= cl.allocated_client_slots) + Host_EndGame("unsupported local player slot\n"); + if (!(cls.fteprotocolextensions & PEXT_SPLITSCREEN)) break; @@ -2884,7 +2949,7 @@ void CLNQ_ParseClientdata (void) } else if (CPNQ_IS_DP) { - /*nothing*/ + /*nothing in dp6+*/ } else { @@ -2935,7 +3000,7 @@ void CLNQ_ParseClientdata (void) } } - if (CPNQ_IS_DP || cls.protocol_nq == CPNQ_DP5) + if (CPNQ_IS_DP) { if (bits & DPSU_VIEWZOOM) { @@ -3313,7 +3378,7 @@ void CL_ParseBaseline2 (void) { entity_state_t es; - CL_ParseDelta(&nullentitystate, &es, (unsigned short)MSG_ReadShort(), true); + CLQW_ParseDelta(&nullentitystate, &es, (unsigned short)MSG_ReadShort(), true); if (!CL_CheckBaselines(es.number)) Host_EndGame("CL_ParseBaseline2: check baselines failed with size %i", es.number); memcpy(cl_baselines + es.number, &es, sizeof(es)); @@ -3379,7 +3444,7 @@ void CL_ParseStatic (int version) } else { - CL_ParseDelta(&nullentitystate, &es, MSG_ReadShort(), true); + CLQW_ParseDelta(&nullentitystate, &es, MSG_ReadShort(), true); es.number+=MAX_EDICTS; for (i = 0; i < cl.num_statics; i++) @@ -3416,14 +3481,24 @@ void CL_ParseStatic (int version) #ifdef PEXT_SCALE ent->scale = es.scale/16.0; #endif - ent->shaderRGBAf[0] = (8.0f/255.0f)*es.colormod[0]; - ent->shaderRGBAf[1] = (8.0f/255.0f)*es.colormod[1]; - ent->shaderRGBAf[2] = (8.0f/255.0f)*es.colormod[2]; - ent->shaderRGBAf[3] = es.trans/255; + ent->shaderRGBAf[0] = (8.0f/256.0f)*es.colormod[0]; + ent->shaderRGBAf[1] = (8.0f/256.0f)*es.colormod[1]; + ent->shaderRGBAf[2] = (8.0f/256.0f)*es.colormod[2]; + ent->shaderRGBAf[3] = es.trans/255.0f; ent->fatness = es.fatness/16.0; ent->abslight = es.abslight; + ent->flags = es.flags; + if (es.effects & NQEF_ADDITIVE) + ent->flags |= Q2RF_ADDITIVE; + if (es.effects & EF_NODEPTHTEST) + ent->flags |= RF_NODEPTHTEST; + if (es.effects & DPEF_NOSHADOW) + ent->flags |= RF_NOSHADOW; + if (es.trans != 0xff) + ent->flags |= Q2RF_TRANSLUCENT; + VectorCopy (es.origin, ent->origin); VectorCopy (es.angles, ent->angles); es.angles[0]*=-1; @@ -4102,8 +4177,8 @@ void CL_MuzzleFlash (int destsplit) dl = CL_AllocDlight (-i); VectorCopy (pl->origin, dl->origin); //set it's origin - if (pl->hullnum & 0x80) /*hull is 0-based, so origin is bottom of model, move the light up slightly*/ - dl->origin[2] += 24; + if (pl->szmins[2] == 0) /*hull is 0-based, so origin is bottom of model, move the light up slightly*/ + dl->origin[2] += pl->szmaxs[2]/2; AngleVectors(pl->viewangles, dl->axis[0], dl->axis[1], dl->axis[2]); AngleVectors (pl->viewangles, fv, rv, uv); //shift it up a little @@ -4977,8 +5052,8 @@ void CL_DumpPacket(void) } } -#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); -#define SHOWNET2(x, y) if(cl_shownet.value==2)Con_Printf ("%3i:%3i:%s\n", msg_readcount-1, y, x); +#define SHOWNET(x) if(cl_shownet.value>=2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); +#define SHOWNET2(x, y) if(cl_shownet.value>=2)Con_Printf ("%3i:%3i:%s\n", msg_readcount-1, y, x); /* ===================== CL_ParseServerMessage @@ -5006,7 +5081,7 @@ void CLQW_ParseServerMessage (void) // if (cl_shownet.value == 1) Con_TPrintf (TL_INT_SPACE,net_message.cursize); - else if (cl_shownet.value == 2) + else if (cl_shownet.value >= 2) Con_TPrintf (TLC_LINEBREAK_MINUS); @@ -5421,6 +5496,9 @@ void CLQW_ParseServerMessage (void) CL_ParsePacketEntities (true); cl.ackedinputsequence = cl.validsequence; break; + case svcfte_updateentities: + CLFTE_ParseEntities(); + break; case svc_maxspeed: cl.maxspeed[destsplit] = MSG_ReadFloat(); @@ -6216,7 +6294,7 @@ void CLNQ_ParseServerMessage (void) CLNQ_SignonReply (); } //well, it's really any protocol, but we're only going to support version 5. - CLNQ_ParseDarkPlaces5Entities(); + CLDP_ParseDarkPlaces5Entities(); break; #ifdef PEXT_CSQC diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index f141633e7..6b2a2e996 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -26,14 +26,14 @@ cvar_t cl_pushlatency = SCVAR("pushlatency","-999"); extern frame_t *view_frame; -#define MAX_PARSE_ENTITIES 1024 -extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; - extern float pm_airaccelerate; extern usercmd_t independantphysics[MAX_SPLITS]; #ifdef Q2CLIENT +#define MAX_PARSE_ENTITIES 1024 +extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; + char *Get_Q2ConfigString(int i); #ifdef Q2BSPS @@ -121,7 +121,7 @@ void CLQ2_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t en if (ent->number == cl.playernum[0]+1) continue; - if (ent->solid == 31) + if (ent->solid == ES_SOLID_BSP) { // special value for bmodel cmodel = cl.model_precache[ent->modelindex]; if (!cmodel) @@ -395,35 +395,15 @@ void CL_PredictUsercmd (int pnum, player_state_t *from, player_state_t *to, user pmove.pm_type = from->pm_type; pmove.cmd = *u; + pmove.skipent = cl.playernum[pnum]+1; movevars.entgravity = cl.entgravity[pnum]; movevars.maxspeed = cl.maxspeed[pnum]; movevars.bunnyspeedcap = cl.bunnyspeedcap; pmove.onladder = false; - pmove.hullnum = from->hullnum; - if (cl.worldmodel->fromgame != fg_quake) - { - player_mins[0] = -16; - player_mins[1] = -16; - player_mins[2] = -24; - player_maxs[0] = 16; - player_maxs[1] = 16; - player_maxs[2] = 32; - - VectorScale(player_mins, pmove.hullnum/56.0f, player_mins); - VectorScale(player_maxs, pmove.hullnum/56.0f, player_maxs); - } - else - { - VectorCopy(cl.worldmodel->hulls[pmove.hullnum&(MAX_MAP_HULLSM-1)].clip_mins, player_mins); - VectorCopy(cl.worldmodel->hulls[pmove.hullnum&(MAX_MAP_HULLSM-1)].clip_maxs, player_maxs); - } - if (pmove.hullnum & 128) - { //this hack is for hexen2. - player_maxs[2] -= player_mins[2]; - player_mins[2] = 0; - } + VectorCopy(from->szmins, player_mins); + VectorCopy(from->szmaxs, player_maxs); PM_PlayerMove (cl.gamespeed); @@ -439,7 +419,9 @@ void CL_PredictUsercmd (int pnum, player_state_t *from, player_state_t *to, user to->weaponframe = from->weaponframe; to->pm_type = from->pm_type; - to->hullnum = from->hullnum; + + VectorCopy(player_mins, to->szmins); + VectorCopy(player_maxs, to->szmaxs); } @@ -750,6 +732,109 @@ void CL_CalcClientTime(void) } } +static void CL_DecodeStateSize(unsigned short solid, int modelindex, vec3_t mins, vec3_t maxs) +{ + if (solid == ES_SOLID_BSP) + { + if (modelindex < MAX_MODELS && cl.model_precache[modelindex] && !cl.model_precache[modelindex]->needload) + { + VectorCopy(cl.model_precache[modelindex]->mins, mins); + VectorCopy(cl.model_precache[modelindex]->maxs, maxs); + } + else + { + VectorClear(mins); + VectorClear(maxs); + } + } + else if (solid) + { + mins[0] = -8*(solid&31); + mins[1] = -8*(solid&31); + mins[2] = -8*((solid>>5)&31); + maxs[0] = 8*(solid&31); + maxs[1] = 8*(solid&31); + maxs[2] = 8*((solid>>10)&63) - 32; + } + else + { + VectorClear(mins); + VectorClear(maxs); + } +} + +/*called on packet reception*/ +void CL_PlayerFrameUpdated(player_state_t *plstate, entity_state_t *state, int sequence) +{ + /*update the prediction info*/ + int pmtype; + if (state->u.q1.pmovetype == MOVETYPE_NOCLIP) + { + if (cls.z_ext & Z_EXT_PM_TYPE_NEW) + pmtype = PM_SPECTATOR; + else + pmtype = PM_OLD_SPECTATOR; + } + else if (state->u.q1.pmovetype == MOVETYPE_FLY) + pmtype = PM_FLY; + else if (state->u.q1.pmovetype == MOVETYPE_NONE) + pmtype = PM_NONE; + else if (state->u.q1.pmovetype == MOVETYPE_BOUNCE || state->u.q1.pmovetype == MOVETYPE_TOSS) + pmtype = PM_DEAD; + else + pmtype = PM_NORMAL; + + plstate->pm_type = pmtype; + VectorCopy(state->origin, plstate->origin); + VectorScale(state->u.q1.velocity, 1/8.0, plstate->velocity); + plstate->messagenum = sequence; + + CL_DecodeStateSize(state->solid, state->modelindex, plstate->szmins, plstate->szmaxs); +} + +/*called once every rendered frame*/ +qboolean CL_PredictPlayer(lerpents_t *le, entity_state_t *state, int sequence) +{ + int msec, oldphysent; + usercmd_t cmd; + player_state_t start, exact; + int pnum; + + if (state->number-1 > cl.allocated_client_slots || cl.intermission) + return false; + + /*local players just interpolate for now. the prediction code will move it to the right place afterwards*/ + for (pnum = 0; pnum < cl.splitclients; pnum++) + { + if (state->number-1 == cl.playernum[pnum]) + return false; + } + + memset(&cmd, 0, sizeof(cmd)); + memset(&start, 0, sizeof(start)); + + CL_PlayerFrameUpdated(&start, state, sequence); + + msec = 500*(realtime - cls.latency + 0.02 - cl.frames[sequence & UPDATE_MASK].receivedtime); + cmd.msec = bound(0, msec, 255); + cmd.forwardmove = state->u.q1.movement[0]; + cmd.sidemove = state->u.q1.movement[1]; + cmd.upmove = state->u.q1.movement[2]; + + oldphysent = pmove.numphysent; + pmove.skipent = state->number-1; + CL_PredictUsercmd (0, &start, &exact, &cmd); //uses player 0's maxspeed/grav... + pmove.numphysent = oldphysent; + + /*need to update the entity's angles and origin so the linkentities function puts it in the correct predicted place*/ + le->angles[0] = state->angles[0]; + le->angles[1] = state->angles[1]; + le->angles[2] = state->angles[2]; + VectorCopy (exact.origin, le->origin); + + return true; +} + /* ============== CL_PredictMove @@ -769,7 +854,7 @@ void CL_PredictMovePNum (int pnum) float *org; float stepheight = 0; - cl.nolocalplayer[pnum] = false; + cl.nolocalplayer[pnum] = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS); #ifdef Q2CLIENT if (cls.protocol == CP_QUAKE2) @@ -874,7 +959,8 @@ fixedorg: // predict forward until cl.time <= to->senttime oldphysent = pmove.numphysent; - CL_SetSolidPlayers (cl.playernum[pnum]); + CL_SetSolidPlayers(); + pmove.skipent = cl.playernum[pnum]+1; to = &cl.frames[cl.ackedinputsequence & UPDATE_MASK]; @@ -940,8 +1026,6 @@ fixedorg: cls.netchan.outgoing_sequence; i++) { to = &cl.frames[(cl.ackedinputsequence+i) & UPDATE_MASK]; - if (cl.intermission) - to->playerstate->pm_type = PM_FLY; CL_PredictUsercmd (pnum, &from->playerstate[cl.playernum[pnum]] , &to->playerstate[cl.playernum[pnum]], &to->cmd[pnum]); @@ -965,6 +1049,14 @@ fixedorg: cl.onground[pnum] = pmove.onground; } stepheight = to->playerstate[cl.playernum[pnum]].origin[2] - from->playerstate[cl.playernum[pnum]].origin[2]; + + if (cl.nolocalplayer[pnum]) + { + //keep the entity tracking the prediction position, so mirrors don't go all weird + VectorCopy(to->playerstate[cl.playernum[pnum]].origin, cl.lerpents[cl.playernum[pnum]+1].origin); + VectorScale(to->cmd[pnum].angles, 360.0f / 0xffff, cl.lerpents[cl.playernum[pnum]+1].angles); + cl.lerpents[cl.playernum[pnum]+1].angles[0] *= -0.333; + } } pmove.numphysent = oldphysent; diff --git a/engine/client/client.h b/engine/client/client.h index 27481eb8a..cb3eee302 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -73,7 +73,7 @@ typedef struct qboolean onground; qboolean jump_held; int jump_msec; // hack for fixing bunny-hop flickering on non-ZQuake servers - int hullnum; + vec3_t szmins, szmaxs; float lerpstarttime; int oldframe; @@ -347,7 +347,7 @@ typedef struct { CPNQ_ID, CPNQ_PROQUAKE3_4, - CPNQ_FITZ666, + CPNQ_FITZ666, /*and rmqe999 protocol*/ CPNQ_DP5, CPNQ_DP6, CPNQ_DP7 @@ -462,6 +462,7 @@ typedef struct { //previous rendering frame (for trails) vec3_t lastorigin; qboolean isnew; + qboolean isplayer; //intermediate values for frame lerping float framelerpdeltatime; @@ -773,7 +774,7 @@ dlight_t *CL_NewDlightRGB (int key, const vec3_t origin, float radius, float tim dlight_t *CL_NewDlightCube (int key, const vec3_t origin, vec3_t angles, float radius, float time, vec3_t colours); void CL_DecayLights (void); -void CL_ParseDelta (struct entity_state_s *from, struct entity_state_s *to, int bits, qboolean); +void CLQW_ParseDelta (struct entity_state_s *from, struct entity_state_s *to, int bits, qboolean); void CL_Init (void); void Host_WriteConfiguration (void); @@ -1000,7 +1001,7 @@ void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, struct model_s *model, int sta // // cl_ents.c // -void CL_SetSolidPlayers (int playernum); +void CL_SetSolidPlayers (void); void CL_SetUpPlayerPrediction(qboolean dopred); void CL_LinkStaticEntities(void *pvs); void CL_TransitionEntities (void); /*call at the start of the frame*/ @@ -1008,6 +1009,7 @@ void CL_EmitEntities (void); void CL_ClearProjectiles (void); void CL_ParseProjectiles (int modelindex, qboolean nails2); void CL_ParsePacketEntities (qboolean delta); +void CLFTE_ParseEntities (void); void CL_SetSolidEntities (void); void CL_ParsePlayerinfo (void); void CL_ParseClientPersist(void); @@ -1057,9 +1059,10 @@ void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd); void CSQC_WorldLoaded(void); qboolean CSQC_ParseTempEntity(unsigned char firstbyte); qboolean CSQC_ConsoleCommand(char *cmd); -qboolean CSQC_KeyPress(int key, int unicode, qboolean down); -qboolean CSQC_MouseMove(float xdelta, float ydelta); -qboolean CSQC_MousePosition(float xabs, float yabs); +qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid); +qboolean CSQC_MouseMove(float xdelta, float ydelta, int devid); +qboolean CSQC_MousePosition(float xabs, float yabs, int devid); +qboolean CSQC_Accelerometer(float x, float y, float z); int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation); void CSQC_ParseEntities(void); qboolean CSQC_SettingListener(void); diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index f664f12ac..3f489cbbd 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -562,7 +562,7 @@ void CLQ2_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int // set everything to the state we are delta'ing from *to = *from; - VectorCopy (from->origin, to->old_origin); + VectorCopy (from->origin, to->u.q2.old_origin); to->number = number; if (bits & Q2U_MODEL) @@ -570,9 +570,9 @@ void CLQ2_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int if (bits & Q2U_MODEL2) to->modelindex2 = MSG_ReadByte (); if (bits & Q2U_MODEL3) - to->modelindex3 = MSG_ReadByte (); + to->u.q2.modelindex3 = MSG_ReadByte (); if (bits & Q2U_MODEL4) - to->modelindex4 = MSG_ReadByte (); + to->u.q2.modelindex4 = MSG_ReadByte (); if (bits & Q2U_FRAME8) to->frame = MSG_ReadByte (); @@ -594,11 +594,11 @@ void CLQ2_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int to->effects = MSG_ReadShort(); if ( (bits & (Q2U_RENDERFX8|Q2U_RENDERFX16)) == (Q2U_RENDERFX8|Q2U_RENDERFX16) ) - to->renderfx = MSG_ReadLong(); + to->u.q2.renderfx = MSG_ReadLong(); else if (bits & Q2U_RENDERFX8) - to->renderfx = MSG_ReadByte(); + to->u.q2.renderfx = MSG_ReadByte(); else if (bits & Q2U_RENDERFX16) - to->renderfx = MSG_ReadShort(); + to->u.q2.renderfx = MSG_ReadShort(); if (bits & Q2U_ORIGIN1) to->origin[0] = MSG_ReadCoord (); @@ -615,15 +615,15 @@ void CLQ2_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int to->angles[2] = MSG_ReadAngle(); if (bits & Q2U_OLDORIGIN) - MSG_ReadPos (to->old_origin); + MSG_ReadPos (to->u.q2.old_origin); if (bits & Q2U_SOUND) - to->sound = MSG_ReadByte (); + to->u.q2.sound = MSG_ReadByte (); if (bits & Q2U_EVENT) - to->event = MSG_ReadByte (); + to->u.q2.event = MSG_ReadByte (); else - to->event = 0; + to->u.q2.event = 0; if (bits & Q2U_SOLID) to->solid = MSG_ReadShort (); @@ -653,13 +653,13 @@ void CLQ2_DeltaEntity (q2frame_t *frame, int newnum, entity_state_t *old, int bi // some data changes will force no lerping if (state->modelindex != ent->current.modelindex || state->modelindex2 != ent->current.modelindex2 - || state->modelindex3 != ent->current.modelindex3 - || state->modelindex4 != ent->current.modelindex4 + || state->u.q2.modelindex3 != ent->current.u.q2.modelindex3 + || state->u.q2.modelindex4 != ent->current.u.q2.modelindex4 || abs(state->origin[0] - ent->current.origin[0]) > 512 || abs(state->origin[1] - ent->current.origin[1]) > 512 || abs(state->origin[2] - ent->current.origin[2]) > 512 - || state->event == Q2EV_PLAYER_TELEPORT - || state->event == Q2EV_OTHER_TELEPORT + || state->u.q2.event == Q2EV_PLAYER_TELEPORT + || state->u.q2.event == Q2EV_OTHER_TELEPORT ) { ent->serverframe = -99; @@ -672,15 +672,15 @@ void CLQ2_DeltaEntity (q2frame_t *frame, int newnum, entity_state_t *old, int bi // duplicate the current state so lerping doesn't hurt anything ent->prev = *state; - if (state->event == Q2EV_OTHER_TELEPORT) + if (state->u.q2.event == Q2EV_OTHER_TELEPORT) { VectorCopy (state->origin, ent->prev.origin); VectorCopy (state->origin, ent->lerp_origin); } else { - VectorCopy (state->old_origin, ent->prev.origin); - VectorCopy (state->old_origin, ent->lerp_origin); + VectorCopy (state->u.q2.old_origin, ent->prev.origin); + VectorCopy (state->u.q2.old_origin, ent->lerp_origin); } } else @@ -975,7 +975,7 @@ void CLQ2_FireEntityEvents (q2frame_t *frame) { num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1); s1 = &cl_parse_entities[num]; - if (s1->event) + if (s1->u.q2.event) CLQ2_EntityEvent (s1); // EF_TELEPORTER acts like an event, but is not cleared each frame @@ -1197,7 +1197,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) cent = &cl_entities[s1->number]; effects = s1->effects; - renderfx = s1->renderfx; + renderfx = s1->u.q2.renderfx; ent.rtype = RT_MODEL; ent.keynum = s1->number; @@ -1207,6 +1207,9 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) ent.shaderRGBAf[1] = 1; ent.shaderRGBAf[2] = 1; ent.shaderRGBAf[3] = 1; + ent.glowmod[0] = 1; + ent.glowmod[1] = 1; + ent.glowmod[2] = 1; ent.fatness = 0; ent.scoreboard = NULL; @@ -1260,7 +1263,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) { // step origin discretely, because the frames // do the animation properly VectorCopy (cent->current.origin, ent.origin); - VectorCopy (cent->current.old_origin, ent.oldorigin); + VectorCopy (cent->current.u.q2.old_origin, ent.oldorigin); } else { // interpolate origin @@ -1558,14 +1561,14 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) ent.shaderRGBAf[3] = 1; //PGM } - if (s1->modelindex3) + if (s1->u.q2.modelindex3) { - ent.model = cl.model_precache[s1->modelindex3]; + ent.model = cl.model_precache[s1->u.q2.modelindex3]; V_AddEntity (&ent); } - if (s1->modelindex4) + if (s1->u.q2.modelindex4) { - ent.model = cl.model_precache[s1->modelindex4]; + ent.model = cl.model_precache[s1->u.q2.modelindex4]; V_AddEntity (&ent); } diff --git a/engine/client/image.c b/engine/client/image.c index 4f7e2c1bd..1d26c251a 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -148,7 +148,7 @@ char *ReadGreyTargaFile (qbyte *data, int flen, tgaheader_t *tgahead, int asgrey } //remember to free it -qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, int asgrey) +qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, qboolean *hasalpha, int asgrey) { unsigned char *data; @@ -221,6 +221,8 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, int asgrey { if (tgaheader.bpp == 8) return NULL; + + *hasalpha = (tgaheader.bpp==32); } if (tgaheader.version == 11) { @@ -256,6 +258,7 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, int asgrey palette[row][2] = *data++; palette[row][3] = *data++; } + *hasalpha = true; break; } } @@ -502,6 +505,7 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, int asgrey return NULL; mul = tgaheader.bpp/8; + *hasalpha = mul==4; //flip +convert to 32 bit if (asgrey) outrow = &initbuf[(int)(0)*tgaheader.width]; @@ -887,7 +891,7 @@ int Image_WritePNG (char *filename, int compression, qbyte *pixels, int width, i if (!(png_ptr = qpng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) { fclose(fp); - return false; + return false; } if (!(info_ptr = qpng_create_info_struct(png_ptr))) @@ -899,6 +903,7 @@ int Image_WritePNG (char *filename, int compression, qbyte *pixels, int width, i if (setjmp(png_jmpbuf(png_ptr))) { +err: qpng_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return false; @@ -920,6 +925,8 @@ int Image_WritePNG (char *filename, int compression, qbyte *pixels, int width, i qpng_write_info(png_ptr, info_ptr); row_pointers = BZ_Malloc (sizeof(png_byte *) * height); + if (!row_pointers) + goto err; for (i = 0; i < height; i++) row_pointers[height - i - 1] = pixels + i * width * 3; qpng_write_image(png_ptr, row_pointers); @@ -2262,10 +2269,10 @@ texid_tf GL_LoadTextureDDS(char *iname, unsigned char *buffer, int filesize) #endif //returns r8g8b8a8 -qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, char *fname) +qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean *hasalpha, char *fname) { qbyte *data; - if ((data = ReadTargaFile(buf, len, width, height, false))) + if ((data = ReadTargaFile(buf, len, width, height, hasalpha, false))) { TRACE(("dbg: Read32BitImageFile: tga\n")); return data; @@ -2350,6 +2357,7 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) texid_t tex; // int h; char fname[MAX_QPATH], nicename[MAX_QPATH]; + qboolean hasalpha; int i, e; @@ -2411,12 +2419,12 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) if (buf) { - if ((data = Read32BitImageFile(buf, com_filesize, &image_width, &image_height, fname))) + hasalpha = false; + if ((data = Read32BitImageFile(buf, com_filesize, &image_width, &image_height, &hasalpha, fname))) { extern cvar_t vid_hardwaregamma; if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value) BoostGamma(data, image_width, image_height); - tex = R_LoadTexture32 (name, image_width, image_height, data, (flags | IF_REPLACE) + (i << IF_TEXTYPESHIFT)); BZ_Free(data); @@ -2484,13 +2492,16 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) return tex; } #endif - if ((data = Read32BitImageFile(buf, com_filesize, &image_width, &image_height, fname))) + hasalpha = false; + if ((data = Read32BitImageFile(buf, com_filesize, &image_width, &image_height, &hasalpha, fname))) { extern cvar_t vid_hardwaregamma; if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value) BoostGamma(data, image_width, image_height); - if (!(flags & IF_NOALPHA)) + if (hasalpha) + flags &= ~IF_NOALPHA; + else if (!(flags & IF_NOALPHA)) { unsigned int alpha_width, alpha_height, p; char aname[MAX_QPATH]; @@ -2502,7 +2513,7 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) snprintf(aname, sizeof(aname)-1, tex_path[i].path, nicename, va("_alpha%s", tex_extensions[e].name)); if ((alph = COM_LoadFile (aname, 5))) { - if ((alphadata = Read32BitImageFile(alph, com_filesize, &alpha_width, &alpha_height, aname))) + if ((alphadata = Read32BitImageFile(alph, com_filesize, &alpha_width, &alpha_height, &hasalpha, aname))) { if (alpha_width == image_width && alpha_height == image_height) { @@ -2589,6 +2600,7 @@ texid_t R_LoadBumpmapTexture(char *name, char *subpath) texid_t tex; // int h; char fname[MAX_QPATH], nicename[MAX_QPATH]; + qboolean hasalpha; static char *extensions[] = {//reverse order of preference - (match commas with optional file types) @@ -2635,7 +2647,7 @@ texid_t R_LoadBumpmapTexture(char *name, char *subpath) if ((buf = COM_LoadFile (fname, 5))) { - if ((data = ReadTargaFile(buf, com_filesize, &image_width, &image_height, 2))) //Only load a greyscale image. + if ((data = ReadTargaFile(buf, com_filesize, &image_width, &image_height, &hasalpha, 2))) //Only load a greyscale image. { TRACE(("dbg: Mod_LoadBumpmapTexture: tga %s loaded\n", name)); TEXASSIGNF(tex, R_LoadTexture8Bump(name, image_width, image_height, data, IF_NOALPHA|IF_NOGAMMA)); diff --git a/engine/client/in_win.c b/engine/client/in_win.c index a1b3741eb..098f396ff 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -68,7 +68,7 @@ typedef struct { HANDLE rawinputhandle; } handles; - int playerid; + int qdeviceid; } keyboard_t; typedef struct { @@ -77,7 +77,7 @@ typedef struct { } handles; int numbuttons; - int playerid; + int qdeviceid; /*the device id controls which player slot it controls, if splitscreen splits it that way*/ volatile int buttons; volatile int oldbuttons; @@ -976,7 +976,7 @@ void IN_RawInput_Init(void) rawmice[rawmicecount].handles.rawinputhandle = pRawInputDeviceList[i].hDevice; rawmice[rawmicecount].numbuttons = 10; rawmice[rawmicecount].pos[0] = RI_INVALID_POS; - rawmice[rawmicecount].playerid = rawmicecount; + rawmice[rawmicecount].qdeviceid = rawmicecount; rawmicecount++; break; case RIM_TYPEKEYBOARD: @@ -984,7 +984,7 @@ void IN_RawInput_Init(void) continue; rawkbd[rawkbdcount].handles.rawinputhandle = pRawInputDeviceList[i].hDevice; - rawkbd[rawkbdcount].playerid = rawmicecount; + rawkbd[rawkbdcount].qdeviceid = rawkbdcount; rawkbdcount++; break; default: @@ -1238,6 +1238,7 @@ static void ProcessMouse(mouse_t *mouse, float *movements, int pnum) int i; + /*each device will be processed when its player comes to be processed*/ int wpnum; wpnum = cl.splitclients; if (wpnum < 1) @@ -1245,7 +1246,7 @@ static void ProcessMouse(mouse_t *mouse, float *movements, int pnum) if (cl_forcesplitclient.ival) wpnum = (cl_forcesplitclient.ival-1) % wpnum; else - wpnum = mouse->playerid % wpnum; + wpnum = mouse->qdeviceid % wpnum; if (wpnum != pnum) return; @@ -1255,13 +1256,13 @@ static void ProcessMouse(mouse_t *mouse, float *movements, int pnum) if ( (mouse->buttons & (1<oldbuttons & (1<qdeviceid, K_MOUSE1 + i, 0, true); } if ( !(mouse->buttons & (1<oldbuttons & (1<qdeviceid, K_MOUSE1 + i, 0, false); } } mouse->oldbuttons = mouse->buttons; @@ -1273,15 +1274,15 @@ static void ProcessMouse(mouse_t *mouse, float *movements, int pnum) { while(mouse->wheeldelta <= -mfwt) { - Key_Event (pnum, K_MWHEELUP, 0, true); - Key_Event (pnum, K_MWHEELUP, 0, false); + Key_Event (mouse->qdeviceid, K_MWHEELUP, 0, true); + Key_Event (mouse->qdeviceid, K_MWHEELUP, 0, false); mouse->wheeldelta += mfwt; } while(mouse->wheeldelta >= mfwt) { - Key_Event (pnum, K_MWHEELDOWN, 0, true); - Key_Event (pnum, K_MWHEELDOWN, 0, false); + Key_Event (mouse->qdeviceid, K_MWHEELDOWN, 0, true); + Key_Event (mouse->qdeviceid, K_MWHEELDOWN, 0, false); mouse->wheeldelta -= mfwt; } } @@ -1319,7 +1320,7 @@ static void ProcessMouse(mouse_t *mouse, float *movements, int pnum) mx=my=0; #ifdef PEXT_CSQC - CSQC_MousePosition(mousecursor_x, mousecursor_y); + CSQC_MousePosition(mousecursor_x, mousecursor_y, mouse->qdeviceid); #endif } else @@ -1335,7 +1336,7 @@ static void ProcessMouse(mouse_t *mouse, float *movements, int pnum) #ifdef PEXT_CSQC if (mx || my) - if (CSQC_MouseMove(mx, my)) + if (CSQC_MouseMove(mx, my, mouse->qdeviceid)) { mx = 0; my = 0; @@ -1642,8 +1643,8 @@ void IN_Accumulate (void) #ifdef USINGRAWINPUT void IN_RawInput_MouseRead(void) { - int pnum; int i, tbuttons, j; + mouse_t *mouse; // find mouse in our mouse list for (i = 0; i < rawmicecount; i++) @@ -1654,14 +1655,7 @@ void IN_RawInput_MouseRead(void) if (i == rawmicecount) // we're not tracking this device return; - - pnum = cl.splitclients; - if (pnum < 1) - pnum = 1; - if (cl_forcesplitclient.ival) - pnum = (cl_forcesplitclient.ival-1) % pnum; - else - pnum = rawmice[i].playerid % pnum; + mouse = &rawmice[i]; // movement if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) @@ -1683,38 +1677,38 @@ void IN_RawInput_MouseRead(void) // buttons if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) - Key_Event(pnum, K_MOUSE1, 0, true); + Key_Event(mouse->qdeviceid, K_MOUSE1, 0, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) - Key_Event(pnum, K_MOUSE1, 0, false); + Key_Event(mouse->qdeviceid, K_MOUSE1, 0, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) - Key_Event(pnum, K_MOUSE2, 0, true); + Key_Event(mouse->qdeviceid, K_MOUSE2, 0, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) - Key_Event(pnum, K_MOUSE2, 0, false); + Key_Event(mouse->qdeviceid, K_MOUSE2, 0, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) - Key_Event(pnum, K_MOUSE3, 0, true); + Key_Event(mouse->qdeviceid, K_MOUSE3, 0, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) - Key_Event(pnum, K_MOUSE3, 0, false); + Key_Event(mouse->qdeviceid, K_MOUSE3, 0, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) - Key_Event(pnum, K_MOUSE4, 0, true); + Key_Event(mouse->qdeviceid, K_MOUSE4, 0, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) - Key_Event(pnum, K_MOUSE4, 0, false); + Key_Event(mouse->qdeviceid, K_MOUSE4, 0, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) - Key_Event(pnum, K_MOUSE5, 0, true); + Key_Event(mouse->qdeviceid, K_MOUSE5, 0, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) - Key_Event(pnum, K_MOUSE5, 0, false); + Key_Event(mouse->qdeviceid, K_MOUSE5, 0, false); // mouse wheel if (raw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) { // If the current message has a mouse_wheel message if ((SHORT)raw->data.mouse.usButtonData > 0) { - Key_Event(pnum, K_MWHEELUP, 0, true); - Key_Event(pnum, K_MWHEELUP, 0, false); + Key_Event(mouse->qdeviceid, K_MWHEELUP, 0, true); + Key_Event(mouse->qdeviceid, K_MWHEELUP, 0, false); } if ((SHORT)raw->data.mouse.usButtonData < 0) { - Key_Event(pnum, K_MWHEELDOWN, 0, true); - Key_Event(pnum, K_MWHEELDOWN, 0, false); + Key_Event(mouse->qdeviceid, K_MWHEELDOWN, 0, true); + Key_Event(mouse->qdeviceid, K_MWHEELDOWN, 0, false); } } @@ -1724,12 +1718,12 @@ void IN_RawInput_MouseRead(void) { if ( (tbuttons & (1<qdeviceid, K_MOUSE1 + j, 0, true); } if ( !(tbuttons & (1<qdeviceid, K_MOUSE1 + j, 0, false); } } @@ -1741,7 +1735,6 @@ void IN_RawInput_MouseRead(void) void IN_RawInput_KeyboardRead(void) { int i; - int pnum; qboolean down; WPARAM wParam; LPARAM lParam; @@ -1759,15 +1752,7 @@ void IN_RawInput_KeyboardRead(void) wParam = (-down) & 0xC0000000; lParam = MapVirtualKey(raw->data.keyboard.VKey, 0)<<16; - pnum = cl.splitclients; - if (pnum < 1) - pnum = 1; - if (cl_forcesplitclient.ival) - pnum = (cl_forcesplitclient.ival-1) % pnum; - else - pnum = rawkbd[i].playerid % pnum; - - IN_TranslateKeyEvent(wParam, lParam, down, pnum); + IN_TranslateKeyEvent(wParam, lParam, down, rawkbd[i].qdeviceid); } void IN_RawInput_Read(HANDLE in_device_handle) @@ -2397,7 +2382,7 @@ static int MapKey (int vkey) return scantokey[key]; } -void IN_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int pnum) +void IN_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdeviceid) { extern cvar_t in_builtinkeymap; int qcode; @@ -2419,5 +2404,5 @@ void IN_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int pnum) } } - Key_Event (pnum, qcode, unicode, down); + Key_Event (qdeviceid, qcode, unicode, down); } diff --git a/engine/client/keys.c b/engine/client/keys.c index 9569468b7..658fea195 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -1338,9 +1338,10 @@ Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ -void Key_Event (int pnum, int key, unsigned int unicode, qboolean down) +void Key_Event (int devid, int key, unsigned int unicode, qboolean down) { char *kb; + char p[16]; char cmd[1024]; int keystate, oldstate; @@ -1459,7 +1460,7 @@ void Key_Event (int pnum, int key, unsigned int unicode, qboolean down) if (key_dest == key_game) { #ifdef CSQC_DAT - if (CSQC_KeyPress(key, unicode, down)) //give csqc a chance to handle it. + if (CSQC_KeyPress(key, unicode, down, devid)) //give csqc a chance to handle it. return; #endif #ifdef VM_CG @@ -1555,40 +1556,24 @@ void Key_Event (int pnum, int key, unsigned int unicode, qboolean down) return; deltaused[key][keystate] = false; - kb = keybindings[key][keystate]; - if (pnum) - { - if (kb && kb[0] == '+') - { - Q_snprintfz (cmd, sizeof(cmd), "-p%i %s %i\n", pnum+1, kb+1, key+oldstate*256); - Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); - } - if (keyshift[key] != key) - { - kb = keybindings[keyshift[key]][keystate]; - if (kb && kb[0] == '+') - { - Q_snprintfz (cmd, sizeof(cmd), "-p%i %s %i\n", pnum+1, kb+1, key+oldstate*256); - Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); - } - } - } + if (devid) + Q_snprintfz (p, sizeof(p), "p %i ", devid+1); else + *p = 0; + kb = keybindings[key][keystate]; + if (kb && kb[0] == '+') { + Q_snprintfz (cmd, sizeof(cmd), "-%s%s %i\n", p, kb+1, key+oldstate*256); + Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); + } + if (keyshift[key] != key) + { + kb = keybindings[keyshift[key]][keystate]; if (kb && kb[0] == '+') { - Q_snprintfz (cmd, sizeof(cmd), "-%s %i\n", kb+1, key+oldstate*256); + Q_snprintfz (cmd, sizeof(cmd), "-%s%s %i\n", p, kb+1, key+oldstate*256); Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); } - if (keyshift[key] != key) - { - kb = keybindings[keyshift[key]][keystate]; - if (kb && kb[0] == '+') - { - Q_snprintfz (cmd, sizeof(cmd), "-%s %i\n", kb+1, key+oldstate*256); - Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); - } - } } return; } @@ -1623,37 +1608,25 @@ void Key_Event (int pnum, int key, unsigned int unicode, qboolean down) return; deltaused[key][keystate] = true; - kb = keybindings[key][keystate]; - if (pnum) - { - if (kb) - { - if (kb[0] == '+') - { // button commands add keynum as a parm - Q_snprintfz (cmd, sizeof(cmd), "+p%i %s %i\n", pnum+1, kb+1, key+oldstate*256); - Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); - } - else - { - Q_snprintfz (cmd, sizeof(cmd), "p%i %s\n", pnum+1, kb); - Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); - } - } - } + + if (devid) + Q_snprintfz (p, sizeof(p), "p %i ", devid+1); else + *p = 0; + + kb = keybindings[key][keystate]; + if (kb) { - if (kb) + if (kb[0] == '+') + { // button commands add keynum as a parm + Q_snprintfz (cmd, sizeof(cmd), "+%s%s %i\n", p, kb+1, key+oldstate*256); + Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); + } + else { - if (kb[0] == '+') - { // button commands add keynum as a parm - Q_snprintfz (cmd, sizeof(cmd), "%s %i\n", kb, key+oldstate*256); - Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); - } - else - { - Cbuf_AddText (kb, bindcmdlevel[key][keystate]); - Cbuf_AddText ("\n", bindcmdlevel[key][keystate]); - } + if (*p)Cbuf_AddText (p, bindcmdlevel[key][keystate]); + Cbuf_AddText (kb, bindcmdlevel[key][keystate]); + Cbuf_AddText ("\n", bindcmdlevel[key][keystate]); } } diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 83bd600da..41e6ee64d 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -1464,6 +1464,7 @@ cin_t *Media_Static_TryLoad(char *name) qbyte *staticfilmimage; int imagewidth; int imageheight; + qboolean hasalpha; int fsize; char fullname[MAX_QPATH]; @@ -1480,7 +1481,7 @@ cin_t *Media_Static_TryLoad(char *name) } if ((staticfilmimage = ReadPCXFile(file, fsize, &imagewidth, &imageheight)) || //convert to 32 rgba if not corrupt - (staticfilmimage = ReadTargaFile(file, fsize, &imagewidth, &imageheight, false)) || + (staticfilmimage = ReadTargaFile(file, fsize, &imagewidth, &imageheight, &hasalpha, false)) || #ifdef AVAIL_JPEGLIB (staticfilmimage = ReadJPEGFile(file, fsize, &imagewidth, &imageheight)) || #endif diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 770d2ced7..244d5b7ee 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -858,7 +858,7 @@ void M_Menu_Lighting_f (void) { "Disabled", "Enabled", - "Generated", + "Generate", NULL }; static const char *loadlitvalues[] = diff --git a/engine/client/net_master.c b/engine/client/net_master.c index ef97fb429..ef5f61de0 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -596,10 +596,7 @@ void Master_AddMaster (char *address, int type, char *description) return; } -#ifdef warningmsg -#pragma warningmsg("Master_AddMaster: add ipv6. don't care about tcp/irc.") -#endif - if (adr.type != NA_IP && adr.type != NA_IPX) + if (adr.type != NA_IP && adr.type != NA_IPV6 && adr.type != NA_IPX) { Con_Printf("Fixme: unable to poll address family for \"%s\"\n", address); return; @@ -806,10 +803,6 @@ void NET_SendPollPacket(int len, void *data, netadr_t to) int ret; struct sockaddr_qstorage addr; -#ifdef warningmsg -#pragma warningmsg("NET_SendPollPacket: no support for ipv6") -#endif - NetadrToSockadr (&to, &addr); #ifdef USEIPX if (((struct sockaddr*)&addr)->sa_family == AF_IPX) diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index d9bd89a2b..67c5117c3 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2138,7 +2138,6 @@ static void QCBUILTIN PF_cs_runplayerphysics (progfuncs_t *prinst, struct global VectorCopy(csqcg.pmove_maxs, player_maxs); VectorCopy(csqcg.pmove_mins, player_mins); } - pmove.hullnum = 1; CL_SetSolidEntities(); @@ -3515,9 +3514,8 @@ void CSQC_EntStateToCSQC(unsigned int flags, float lerptime, entity_state_t *src ent->xv->entnum = src->number; ent->v->modelindex = src->modelindex; -// ent->v->bitmask = src->bitmask; - ent->v->flags = src->flags; -// ent->v->effects = src->effects; +// ent->v->flags = src->flags; + ent->v->effects = src->effects; //we ignore the q2 state fields @@ -3527,22 +3525,46 @@ void CSQC_EntStateToCSQC(unsigned int flags, float lerptime, entity_state_t *src // ent->v->glowcolor = src->glowcolour; ent->xv->scale = src->scale/16.0f; ent->xv->fatness = src->fatness/16.0f; -// ent->v->hexen2flags = src->hexen2flags; -// ent->v->abslight = src->abslight; +// ent->xv->drawflags = src->hexen2flags; +// ent->xv->abslight = src->abslight; // ent->v->dpflags = src->dpflags; -// ent->v->colormod[0] = (src->colormod[0]/255.0f)*8; -// ent->v->colormod[1] = (src->colormod[1]/255.0f)*8; -// ent->v->colormod[2] = (src->colormod[2]/255.0f)*8; + ent->xv->colormod[0] = src->colormod[0]*(8/256.0f); + ent->xv->colormod[1] = src->colormod[1]*(8/256.0f); + ent->xv->colormod[2] = src->colormod[2]*(8/256.0f); ent->xv->alpha = src->trans/255.0f; -// ent->v->lightstyle = src->lightstyle; -// ent->v->lightpflags = src->lightpflags; +// ent->xv->style = src->lightstyle; +// ent->xv->pflags = src->lightpflags; // ent->v->solid = src->solid; -// ent->v->light[0] = src->light[0]; -// ent->v->light[1] = src->light[1]; -// ent->v->light[2] = src->light[2]; -// ent->v->light[3] = src->light[3]; -// ent->v->tagentity = src->tagentity; -// ent->v->tagindex = src->tagindex; +// ent->v->color[0] = src->light[0]; +// ent->v->color[1] = src->light[1]; +// ent->v->color[2] = src->light[2]; +// ent->v->light_lev = src->light[3]; +// ent->xv->tagentity = src->tagentity; +// ent->xv->tagindex = src->tagindex; + + if (src->solid == ES_SOLID_BSP) + { + ent->v->solid = SOLID_BSP; + VectorCopy(model->mins, ent->v->mins); + VectorCopy(model->maxs, ent->v->maxs); + } + else if (src->solid) + { + ent->v->solid = SOLID_BBOX; + ent->v->mins[0] = 8*(src->solid & 31); + ent->v->maxs[0] = ent->v->mins[0]; + ent->v->mins[1] = ent->v->mins[0]; + ent->v->maxs[1] = ent->v->mins[0]; + ent->v->mins[2] = 8*((src->solid>>5) & 31); + ent->v->maxs[2] = 8*((src->solid>>10) & 63) - 32; + } + else + ent->v->solid = SOLID_NOT; + + ent->v->movetype = src->u.q1.pmovetype; + ent->v->velocity[0] = src->u.q1.velocity[0]; + ent->v->velocity[1] = src->u.q1.velocity[1]; + ent->v->velocity[2] = src->u.q1.velocity[2]; if (model) { @@ -3581,9 +3603,9 @@ void CSQC_PlayerStateToCSQC(int pnum, player_state_t *srcp, csqcedict_t *ent) //ent->v->fatness = srcp->fatness; ent->xv->alpha = srcp->alpha/255.0f; -// ent->v->colormod[0] = (srcp->colormod[0]/255.0f)*8; -// ent->v->colormod[1] = (srcp->colormod[1]/255.0f)*8; -// ent->v->colormod[2] = (srcp->colormod[2]/255.0f)*8; +// ent->v->colormod[0] = srcp->colormod[0]*(8/256.0f); +// ent->v->colormod[1] = srcp->colormod[1]*(8/256.0f); +// ent->v->colormod[2] = srcp->colormod[2]*(8/256.0f); // ent->v->effects = srcp->effects; } @@ -4788,7 +4810,7 @@ qboolean CSQC_Init (qboolean anycsqc, unsigned int checksum) csprogs_checksum = checksum; csqc_usinglistener = false; - csqc_singlecheats = false; + csqc_singlecheats = cls.demoplayback; #ifndef CLIENTONLY if ((sv.state == ss_active && sv.allocated_client_slots == 1) || atoi(Info_ValueForKey(cl.serverinfo, "*cheats"))) csqc_singlecheats = true; @@ -4870,6 +4892,7 @@ qboolean CSQC_Init (qboolean anycsqc, unsigned int checksum) csqc_world.Event_Think = CSQC_Event_Think; csqc_world.Get_CModel = CSQC_World_ModelForIndex; csqc_world.Get_FrameState = CSQC_World_GetFrameState; + csqc_world.defaultgravityscale = 1; World_ClearWorld(&csqc_world); CSQC_InitFields(); //let the qclib know the field order that the engine needs. @@ -5259,7 +5282,7 @@ qboolean CSQC_DrawView(void) return true; } -qboolean CSQC_KeyPress(int key, int unicode, qboolean down) +qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid) { void *pr_globals; @@ -5267,15 +5290,16 @@ qboolean CSQC_KeyPress(int key, int unicode, qboolean down) return false; pr_globals = PR_globals(csqcprogs, PR_CURRENT); - G_FLOAT(OFS_PARM0) = !down; + G_FLOAT(OFS_PARM0) = down?CSIE_KEYDOWN:CSIE_KEYUP; G_FLOAT(OFS_PARM1) = MP_TranslateFTEtoDPCodes(key); G_FLOAT(OFS_PARM2) = unicode; + G_FLOAT(OFS_PARM3) = devid; PR_ExecuteProgram (csqcprogs, csqcg.input_event); return G_FLOAT(OFS_RETURN); } -qboolean CSQC_MousePosition(float xabs, float yabs) +qboolean CSQC_MousePosition(float xabs, float yabs, int devid) { void *pr_globals; @@ -5283,15 +5307,16 @@ qboolean CSQC_MousePosition(float xabs, float yabs) return false; pr_globals = PR_globals(csqcprogs, PR_CURRENT); - G_FLOAT(OFS_PARM0) = 3; + G_FLOAT(OFS_PARM0) = CSIE_MOUSEABS; G_FLOAT(OFS_PARM1) = xabs; G_FLOAT(OFS_PARM2) = yabs; + G_FLOAT(OFS_PARM3) = devid; PR_ExecuteProgram (csqcprogs, csqcg.input_event); return G_FLOAT(OFS_RETURN); } -qboolean CSQC_MouseMove(float xdelta, float ydelta) +qboolean CSQC_MouseMove(float xdelta, float ydelta, int devid) { void *pr_globals; @@ -5299,15 +5324,31 @@ qboolean CSQC_MouseMove(float xdelta, float ydelta) return false; pr_globals = PR_globals(csqcprogs, PR_CURRENT); - G_FLOAT(OFS_PARM0) = 2; + G_FLOAT(OFS_PARM0) = CSIE_MOUSEDELTA; G_FLOAT(OFS_PARM1) = xdelta; G_FLOAT(OFS_PARM2) = ydelta; + G_FLOAT(OFS_PARM3) = devid; PR_ExecuteProgram (csqcprogs, csqcg.input_event); return G_FLOAT(OFS_RETURN); } +qboolean CSQC_Accelerometer(float x, float y, float z) +{ + void *pr_globals; + if (!csqcprogs || !csqcg.input_event) + return false; + pr_globals = PR_globals(csqcprogs, PR_CURRENT); + + G_FLOAT(OFS_PARM0) = CSIE_ACCELEROMETER; + G_FLOAT(OFS_PARM1) = x; + G_FLOAT(OFS_PARM2) = y; + G_FLOAT(OFS_PARM3) = z; + PR_ExecuteProgram (csqcprogs, csqcg.input_event); + return G_FLOAT(OFS_RETURN); +} + qboolean CSQC_ConsoleCommand(char *cmd) { void *pr_globals; diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 8cf4c1f99..d00af91a8 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -105,13 +105,13 @@ int MP_TranslateFTEtoDPCodes(int code) case K_MOUSE1: return 512; case K_MOUSE2: return 513; case K_MOUSE3: return 514; - case K_MOUSE4: return 515; - case K_MOUSE5: return 516; -// case K_MOUSE6: return 517; -// case K_MOUSE7: return 518; -// case K_MOUSE8: return 519; -// case K_MOUSE9: return 520; -// case K_MOUSE10: return 521; + case K_MOUSE4: return 517; + case K_MOUSE5: return 518; + case K_MOUSE6: return 519; + case K_MOUSE7: return 520; + case K_MOUSE8: return 521; + case K_MOUSE9: return 522; + case K_MOUSE10: return 523; case K_MWHEELDOWN: return 515;//K_MOUSE4; case K_MWHEELUP: return 516;//K_MOUSE5; default: return code; @@ -208,13 +208,13 @@ int MP_TranslateDPtoFTECodes(int code) case 512: return K_MOUSE1; case 513: return K_MOUSE2; case 514: return K_MOUSE3; -// case 515: return K_MOUSE4; -// case 516: return K_MOUSE5; - case 517: return K_MOUSE6; - case 518: return K_MOUSE7; - case 519: return K_MOUSE8; -// case 520: return K_MOUSE9; -// case 521: return K_MOUSE10; + case 517: return K_MOUSE4; + case 518: return K_MOUSE5; + case 519: return K_MOUSE6; + case 520: return K_MOUSE7; + case 521: return K_MOUSE8; + case 522: return K_MOUSE9; + case 523: return K_MOUSE10; case 515: return K_MWHEELDOWN;//K_MOUSE4; case 516: return K_MWHEELUP;//K_MOUSE5; default: return code; diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index eb242c00e..108d9e19d 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -1734,6 +1734,7 @@ void Surf_SetupFrame(void) R_AnimateLight(); r_framecount++; + r_viewcontents = 0; if (r_refdef.flags & Q2RDF_NOWORLDMODEL) { } @@ -1778,6 +1779,8 @@ void Surf_SetupFrame(void) (leaf->cluster != r_viewcluster2) ) r_viewcluster2 = leaf->cluster; } + + r_viewcontents = leaf->contents; } #endif else if (cl.worldmodel && cl.worldmodel->fromgame == fg_doom3) @@ -1822,8 +1825,38 @@ void Surf_SetupFrame(void) r_viewleaf2 = NULL; if (r_viewleaf) - V_SetContentsColor (r_viewleaf->contents); + { + switch(r_viewleaf->contents) + { + case Q1CONTENTS_WATER: + r_viewcontents |= FTECONTENTS_WATER; + break; + case Q1CONTENTS_LAVA: + r_viewcontents |= FTECONTENTS_LAVA; + break; + case Q1CONTENTS_SLIME: + r_viewcontents |= FTECONTENTS_SLIME; + break; + case Q1CONTENTS_SKY: + r_viewcontents |= FTECONTENTS_SKY; + break; + } + } } + + /*pick up any extra water entities*/ + { + extern vec3_t player_maxs, player_mins; + vec3_t t1,t2; + VectorCopy(player_mins, t1); + VectorCopy(player_maxs, t2); + VectorClear(player_maxs); + VectorClear(player_mins); + r_viewcontents |= PM_ExtraBoxContents(r_origin); + VectorCopy(t1, player_mins); + VectorCopy(t2, player_maxs); + } + V_SetContentsColor (r_viewcontents); } @@ -2019,11 +2052,6 @@ void Surf_DrawWorld (void) currentmodel = cl.worldmodel; currententity = &r_worldentity; -#ifdef MAP_DOOM - if (currentmodel->fromgame == fg_doom) - GLR_DoomWorld(); - else -#endif { RSpeedRemark(); @@ -2067,6 +2095,12 @@ void Surf_DrawWorld (void) } else #endif + if (currentmodel->fromgame == fg_doom) + { + vis = NULL; + GLR_DoomWorld(); + } + else #ifdef TERRAIN if (currentmodel->type == mod_heightmap) { diff --git a/engine/client/render.h b/engine/client/render.h index c1850e1b3..2e688def5 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -384,7 +384,7 @@ void CLQ2_BlasterTrail2(vec3_t oldorg, vec3_t neworg); void WritePCXfile (const char *filename, qbyte *data, int width, int height, int rowbytes, qbyte *palette, qboolean upload); //data is 8bit. qbyte *ReadPCXFile(qbyte *buf, int length, int *width, int *height); -qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, int asgrey); +qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, qboolean *hasalpha, int asgrey); qbyte *ReadJPEGFile(qbyte *infile, int length, int *width, int *height); qbyte *ReadPNGFile(qbyte *buf, int length, int *width, int *height, const char *name); qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a1cc04993..b34eba044 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -305,6 +305,7 @@ cvar_t r_noaliasshadows = SCVARF ("r_noaliasshadows", "0", CVAR_ARCHIVE); cvar_t r_shadows = SCVARF ("r_shadows", "0", CVAR_ARCHIVE); +cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground."); cvar_t r_lightprepass = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "Experimental. Attempt to use a different lighting mechanism."); cvar_t r_shadow_bumpscale_basetexture = SCVAR ("r_shadow_bumpscale_basetexture", "4"); @@ -624,6 +625,7 @@ void Renderer_Init(void) Cvar_Register (&r_replacemodels, GRAPHICALNICETIES); + Cvar_Register (&r_showbboxes, GLRENDEREROPTIONS); Cvar_Register (&r_polygonoffset_submodel_factor, GLRENDEREROPTIONS); Cvar_Register (&r_polygonoffset_submodel_offset, GLRENDEREROPTIONS); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 89feba682..9af8a8ed2 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -2459,8 +2459,8 @@ void Sbar_Draw (void) { if (sb_showscores || sb_showteamscores || cl.stats[pnum][STAT_HEALTH] <= 0) Sbar_SoloScoreboard (); - else if (cls.gamemode != GAME_DEATHMATCH) - Sbar_CoopScoreboard (); +// else if (cls.gamemode != GAME_DEATHMATCH) +// Sbar_CoopScoreboard (); else Sbar_DrawNormal (pnum); diff --git a/engine/client/skin.c b/engine/client/skin.c index 9b003f794..549a99ac6 100644 --- a/engine/client/skin.c +++ b/engine/client/skin.c @@ -418,6 +418,7 @@ qbyte *Skin_Cache32 (skin_t *skin) qbyte *raw; qbyte *out, *pix; char *path; + qboolean hasalpha; if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but return NULL; // not download new ones. @@ -441,7 +442,7 @@ qbyte *Skin_Cache32 (skin_t *skin) raw = COM_LoadTempFile (name); if (raw) { - pix = ReadTargaFile(raw, com_filesize, &skin->width, &skin->height, false); + pix = ReadTargaFile(raw, com_filesize, &skin->width, &skin->height, &hasalpha, false); if (pix) { out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name); diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 21474d2bc..c59238e47 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -26,13 +26,22 @@ static qboolean sys_running = false; static void *sys_memheap; static unsigned int sys_lastframe; -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj, + jfloat ax, jfloat ay, jfloat az) { + static vec3_t oac; #ifdef SERVERONLY SV_Frame(); #else unsigned int now = Sys_Milliseconds(); double tdelta = (now - sys_lastframe) * 0.001; + if (oac[0] != ax || oac[1] != ay || oac[2] != az) + { + CSQC_Accelerometer(ax, ay, az); + oac[0] = ax; + oac[1] = ay; + oac[2] = az; + } Host_Frame(tdelta); sys_lastframe = now; #endif @@ -47,11 +56,11 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject o Cmd_ExecuteString("vid_restart\n", RESTRICT_LOCAL); else { - char *args [] = + const char *args [] = { "ftedroid", "-basepack", - (*env)->GetStringUTFChars(env, path, 0), + (*env)->GetStringUTFChars(env, path, NULL), "", "" //we should do this somewhere... (*env)->ReleaseStringUTFChars(env, path, parms.basedir); @@ -60,8 +69,8 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject o parms.basedir = "/sdcard/fte"; parms.argc = 3; parms.argv = args; - parms.memsize = sys_memheap = 8*1024*1024; - parms.membase = malloc(parms.memsize); + parms.memsize = 8*1024*1024; + parms.membase = sys_memheap = malloc(parms.memsize); if (!parms.membase) { Sys_Printf("Unable to alloc heap\n"); @@ -89,26 +98,36 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_keypress(JNIEnv *env, jobje int mousecursor_x, mousecursor_y; float mouse_x, mouse_y; -static float omouse_x, omouse_y; +static vec2_t omouse[8]; JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject obj, - jint act, jfloat x, jfloat y) + jint act, jint ptrid, jfloat x, jfloat y) { - static float totalmoved; - static qboolean down; - float dx, dy; + static float totalmoved[8]; + static qboolean down[8]; + float d[2]; - dx = x - omouse_x; - dy = y - omouse_y; - omouse_x = x; - omouse_y = y; + if (!act && CSQC_MousePosition(x, y, ptrid)) + return; + /*note that these events are not directly useful, so trigger mouse2 leaving mouse1 clean for tap events (and bypass any binds for it)*/ + if (act == 1 && CSQC_KeyPress(K_MOUSE2, 0, true, ptrid)) + return; + if (act == 2 && CSQC_KeyPress(K_MOUSE2, 0, false, ptrid)) + return; + + ptrid &= 7; + + d[0] = x - omouse[ptrid][0]; + d[1] = y - omouse[ptrid][1]; + omouse[ptrid][0] = x; + omouse[ptrid][1] = y; mousecursor_x = x; mousecursor_y = y; - if (down) + if (down[ptrid]) { - mouse_x += dx; - mouse_y += dy; - totalmoved += fabs(dx) + fabs(dy); + mouse_x += d[0]; + mouse_y += d[1]; + totalmoved[ptrid] += fabs(d[0]) + fabs(d[1]); } switch(act) @@ -116,13 +135,13 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject case 0: /*move*/ break; case 1: /*down*/ - totalmoved = 0; - down = true; + totalmoved[ptrid] = 0; + down[ptrid] = true; break; case 2: /*up*/ - down = false; + down[ptrid] = false; /*if it didn't move far, treat it as a regular click, if it did move a little then sorry if you just wanted a small turn!*/ - if (totalmoved < 3) + if (totalmoved[ptrid] < 3) { Key_Event(0, K_MOUSE1, 0, 1); Key_Event(0, K_MOUSE1, 0, 0); @@ -130,11 +149,6 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject break; } } -JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_accelerometer(JNIEnv *env, jobject obj, - jfloat x, jfloat y, jfloat z) -{ -// Con_Printf("Accelerometer: %f %f %f\n", x, y, z); -} static int secbase; double Sys_DoubleTime(void) diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index eaca37448..ba0ab1351 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -1376,19 +1376,142 @@ typedef struct IPropertyStore IPropertyStore * This); } *lpVtbl; } IPropertyStore; + #endif #endif static const IID IID_IPropertyStore = {0x886d8eeb, 0x8cf2, 0x4446, {0x8d, 0x02, 0xcd, 0xba, 0x1d, 0xbd, 0xcf, 0x99}}; + +#ifndef MINGW +#if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600 +#define IObjectArray IUnknown #endif +#endif +static const IID IID_IObjectArray = {0x92ca9dcd, 0x5622, 0x4bba, {0xa8,0x05,0x5e,0x9f,0x54,0x1b,0xd8,0xc9}}; + +#ifndef MINGW +#if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600 +typedef struct IObjectCollection +{ + struct IObjectCollectionVtbl + { + HRESULT ( __stdcall *QueryInterface )( + /* [in] IShellLink*/ void *This, + /* [in] */ const GUID * const riid, + /* [out] */ void **ppvObject); + + ULONG ( __stdcall *AddRef )( + /* [in] IShellLink*/ void *This); + + ULONG ( __stdcall *Release )( + /* [in] IShellLink*/ void *This); + + HRESULT ( __stdcall *GetCount )( + /* [in] IShellLink*/ void *This, + /* [out] */ UINT *pcObjects); + + HRESULT ( __stdcall *GetAt )( + /* [in] IShellLink*/ void *This, + /* [in] */ UINT uiIndex, + /* [in] */ const GUID * const riid, + /* [iid_is][out] */ void **ppv); + + HRESULT ( __stdcall *AddObject )( + /* [in] IShellLink*/ void *This, + /* [in] */ void *punk); + + HRESULT ( __stdcall *AddFromArray )( + /* [in] IShellLink*/ void *This, + /* [in] */ IObjectArray *poaSource); + + HRESULT ( __stdcall *RemoveObjectAt )( + /* [in] IShellLink*/ void *This, + /* [in] */ UINT uiIndex); + + HRESULT ( __stdcall *Clear )( + /* [in] IShellLink*/ void *This); + } *lpVtbl; +} IObjectCollection; +#endif +#endif +static const IID IID_IObjectCollection = {0x5632b1a4, 0xe38a, 0x400a, {0x92,0x8a,0xd4,0xcd,0x63,0x23,0x02,0x95}}; +static const CLSID CLSID_EnumerableObjectCollection = {0x2d3468c1, 0x36a7, 0x43b6, {0xac,0x24,0xd3,0xf0,0x2f,0xd9,0x60,0x7a}}; + + +#ifndef MINGW +#if !defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 7600 +typedef struct ICustomDestinationList +{ + struct ICustomDestinationListVtbl + { + HRESULT ( __stdcall *QueryInterface ) ( + /* [in] ICustomDestinationList*/ void *This, + /* [in] */ const GUID * const riid, + /* [out] */ void **ppvObject); + + ULONG ( __stdcall *AddRef )( + /* [in] ICustomDestinationList*/ void *This); + + ULONG ( __stdcall *Release )( + /* [in] ICustomDestinationList*/ void *This); + + HRESULT ( __stdcall *SetAppID )( + /* [in] ICustomDestinationList*/ void *This, + /* [string][in] */ LPCWSTR pszAppID); + + HRESULT ( __stdcall *BeginList )( + /* [in] ICustomDestinationList*/ void *This, + /* [out] */ UINT *pcMinSlots, + /* [in] */ const GUID * const riid, + /* [out] */ void **ppv); + + HRESULT ( __stdcall *AppendCategory )( + /* [in] ICustomDestinationList*/ void *This, + /* [string][in] */ LPCWSTR pszCategory, + /* [in] IObjectArray*/ void *poa); + + HRESULT ( __stdcall *AppendKnownCategory )( + /* [in] ICustomDestinationList*/ void *This, + /* [in] KNOWNDESTCATEGORY*/ int category); + + HRESULT ( __stdcall *AddUserTasks )( + /* [in] ICustomDestinationList*/ void *This, + /* [in] IObjectArray*/ void *poa); + + HRESULT ( __stdcall *CommitList )( + /* [in] ICustomDestinationList*/ void *This); + + HRESULT ( __stdcall *GetRemovedDestinations )( + /* [in] ICustomDestinationList*/ void *This, + /* [in] */ const IID * const riid, + /* [out] */ void **ppv); + + HRESULT ( __stdcall *DeleteList )( + /* [in] ICustomDestinationList*/ void *This, + /* [string][unique][in] */ LPCWSTR pszAppID); + + HRESULT ( __stdcall *AbortList )( + /* [in] ICustomDestinationList*/ void *This); + + } *lpVtbl; +} ICustomDestinationList; +#endif +#endif +static const IID IID_ICustomDestinationList = {0x6332debf, 0x87b5, 0x4670, {0x90,0xc0,0x5e,0x57,0xb4,0x08,0xa4,0x9e}}; +static const CLSID CLSID_DestinationList = {0x77f10cf0, 0x3db5, 0x4966, {0xb5,0x20,0xb7,0xc5,0x4f,0xd3,0x5e,0xd6}}; + + + +#endif + #if _MSC_VER > 1200 #define WIN7_APPNAME L"FTEQuake" -void Sys_RecentServer(char *command, char *target, char *title, char *desc) + +static IShellLinkW *CreateShellLink(char *command, char *target, char *title, char *desc) { HRESULT hr; IShellLinkW *link; IPropertyStore *prop_store; - SHARDAPPIDINFOLINK appinfo; WCHAR buf[1024]; char tmp[1024], *s; @@ -1396,9 +1519,12 @@ void Sys_RecentServer(char *command, char *target, char *title, char *desc) // Get a pointer to the IShellLink interface. hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, &link); if (FAILED(hr)) - return; - swprintf(buf, sizeof(buf), L"%S", exename); + return NULL; + + GetModuleFileNameW(NULL, buf, sizeof(buf)/sizeof(wchar_t)-1); + IShellLinkW_SetIconLocation(link, buf, 0); /*grab the first icon from our exe*/ IShellLinkW_SetPath(link, buf); /*program to run*/ + Q_strncpyz(tmp, com_quakedir, sizeof(tmp)); /*normalize the gamedir, so we don't end up with the same thing multiple times*/ for(s = tmp; *s; s++) @@ -1413,6 +1539,7 @@ void Sys_RecentServer(char *command, char *target, char *title, char *desc) swprintf(buf, sizeof(buf), L"%S", desc); IShellLinkW_SetDescription(link, buf); /*tooltip*/ + hr = IShellLinkW_QueryInterface(link, &IID_IPropertyStore, &prop_store); #ifndef MINGW @@ -1430,6 +1557,18 @@ void Sys_RecentServer(char *command, char *target, char *title, char *desc) } #endif + return link; +} + +void Sys_RecentServer(char *command, char *target, char *title, char *desc) +{ + SHARDAPPIDINFOLINK appinfo; + IShellLinkW *link; + + link = CreateShellLink(command, target, title, desc); + if (!link) + return; + appinfo.pszAppID=WIN7_APPNAME; appinfo.psl=link; SHAddToRecentDocs(SHARD_APPIDINFOLINK, &appinfo); @@ -1449,6 +1588,81 @@ void Win7_Init(void) pSetCurrentProcessExplicitAppUserModelID(WIN7_APPNAME); } } + +void Win7_TaskListInit(void) +{ + ICustomDestinationList *cdl; + IObjectCollection *col; + IObjectArray *arr; + IShellLinkW *link; + CoInitialize(NULL); + if (SUCCEEDED(CoCreateInstance(&CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, &IID_ICustomDestinationList, &cdl))) + { + UINT minslots; + IUnknown *removed; + cdl->lpVtbl->BeginList(cdl, &minslots, &IID_IObjectArray, &removed); + + if (SUCCEEDED(CoCreateInstance(&CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER, &IID_IObjectCollection, &col))) + { + + switch(M_GameType()) + { + case MGT_QUAKE1: + link = CreateShellLink("+menu_servers", "", "Server List", "Pick a multiplayer server to join"); + if (link) + { + col->lpVtbl->AddObject(col, link); + link->lpVtbl->Release(link); + } + link = CreateShellLink("+map start", "", "Start New Game (Quake)", "Begin a new single-player game"); + if (link) + { + col->lpVtbl->AddObject(col, link); + link->lpVtbl->Release(link); + } + break; + case MGT_QUAKE2: + link = CreateShellLink("+menu_servers", "", "Quake2 Server List", "Pick a multiplayer server to join"); + if (link) + { + col->lpVtbl->AddObject(col, link); + link->lpVtbl->Release(link); + } + link = CreateShellLink("+map unit1", "", "Start New Game (Quake2)", "Begin a new game"); + if (link) + { + col->lpVtbl->AddObject(col, link); + link->lpVtbl->Release(link); + } + break; + case MGT_HEXEN2: + link = CreateShellLink("+menu_servers", "", "Hexen2 Server List", "Pick a multiplayer server to join"); + if (link) + { + col->lpVtbl->AddObject(col, link); + link->lpVtbl->Release(link); + } + link = CreateShellLink("+map demo1", "", "Start New Game (Hexen2)", "Begin a new game"); + if (link) + { + col->lpVtbl->AddObject(col, link); + link->lpVtbl->Release(link); + } + break; + } + + if (SUCCEEDED(col->lpVtbl->QueryInterface(col, &IID_IObjectArray, &arr))) + { + cdl->lpVtbl->AddUserTasks(cdl, arr); + arr->lpVtbl->Release(arr); + } + col->lpVtbl->Release(col); + } + cdl->lpVtbl->AppendKnownCategory(cdl, 1); + cdl->lpVtbl->CommitList(cdl); + cdl->lpVtbl->Release(cdl); + } +} #endif @@ -1678,21 +1892,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin #ifndef MINGW #if _MSC_VER > 1200 - switch(M_GameType()) - { - case MGT_QUAKE1: - Sys_RecentServer("+menu_servers", "", "Server List", "Pick a server to play on"); - Sys_RecentServer("+map start", "", "Start New Game (Quake)", "Begin a new game"); - break; - case MGT_QUAKE2: - Sys_RecentServer("+menu_servers", "", "Server List", "Pick a server to play on"); - Sys_RecentServer("+map unit1", "", "Start New Game (Quake2)", "Begin a new game"); - break; - case MGT_HEXEN2: - Sys_RecentServer("+menu_servers", "", "Server List", "Pick a server to play on"); - Sys_RecentServer("+map demo1", "", "Start New Game (Hexen2)", "Begin a new game"); - break; - } + Win7_TaskListInit(); #endif #endif diff --git a/engine/client/view.c b/engine/client/view.c index fb68a38dd..04eb7ffb8 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -554,21 +554,14 @@ FIXME: Uses Q1 contents void V_SetContentsColor (int contents) { int i; - switch (contents) - { - case Q1CONTENTS_EMPTY: - cl.cshifts[CSHIFT_CONTENTS] = cshift_empty; - break; - case Q1CONTENTS_LAVA: + if (contents & FTECONTENTS_LAVA) cl.cshifts[CSHIFT_CONTENTS] = cshift_lava; - break; - case Q1CONTENTS_SOLID: - case Q1CONTENTS_SLIME: + else if (contents & (FTECONTENTS_SLIME | FTECONTENTS_SOLID)) cl.cshifts[CSHIFT_CONTENTS] = cshift_slime; - break; - default: + else if (contents & FTECONTENTS_WATER) cl.cshifts[CSHIFT_CONTENTS] = cshift_water; - } + else + cl.cshifts[CSHIFT_CONTENTS] = cshift_empty; cl.cshifts[CSHIFT_CONTENTS].percent *= v_contentblend.value; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index e586cd527..5a7d0f1a8 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -169,8 +169,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define INTERQUAKEMODELS #define HUFFNETWORK //huffman network compression - //#define DOOMWADS //doom wad/sprite support - //#define MAP_DOOM //doom map support + #define DOOMWADS //doom wad/sprite support + #define MAP_DOOM //doom map support #define MAP_PROC //doom3/quake4 map support //#define WOLF3DSUPPORT //wolfenstein3d map support (not started yet) #define Q2BSPS //quake 2 bsp support @@ -494,8 +494,7 @@ STAT_VIEW2 = 20, #endif STAT_VIEWZOOM = 21, // DP -//note that hexen2 stats are only used in hexen2 gamemodes, and can be read by csqc without further server changes. -//when running hexen2 mods, the server specifically sets up these stats for the csqc. +//these stats are used only when running a hexen2 mod/hud, and will never be used for a quake mod/hud/generic code. STAT_H2_LEVEL = 32, // changes stat bar STAT_H2_INTELLIGENCE, // changes stat bar STAT_H2_WISDOM, // changes stat bar @@ -553,25 +552,41 @@ STAT_H2_OBJECTIVE1, STAT_H2_OBJECTIVE2, - -STAT_MOVEVARS_WALLFRICTION = 237, // DP -STAT_MOVEVARS_FRICTION = 238, // DP -STAT_MOVEVARS_WATERFRICTION = 239, // DP -STAT_MOVEVARS_TICRATE = 240, // DP -STAT_MOVEVARS_TIMESCALE = 241, // DP -STAT_MOVEVARS_GRAVITY = 242, // DP -STAT_MOVEVARS_STOPSPEED = 243, // DP -STAT_MOVEVARS_MAXSPEED = 244, // DP -STAT_MOVEVARS_SPECTATORMAXSPEED = 245, // DP -STAT_MOVEVARS_ACCELERATE = 246, // DP -STAT_MOVEVARS_AIRACCELERATE = 247, // DP -STAT_MOVEVARS_WATERACCELERATE = 248, // DP -STAT_MOVEVARS_ENTGRAVITY = 249, // DP -STAT_MOVEVARS_JUMPVELOCITY = 250, // DP -STAT_MOVEVARS_EDGEFRICTION = 251, // DP -STAT_MOVEVARS_MAXAIRSPEED = 252, // DP -STAT_MOVEVARS_STEPHEIGHT = 253, // DP -STAT_MOVEVARS_AIRACCEL_QW = 254, // DP +STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR = 220, // DP +STAT_MOVEVARS_AIRCONTROL_PENALTY = 221, // DP +STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222, // DP +STAT_MOVEVARS_AIRSTRAFEACCEL_QW = 223, // DP +STAT_MOVEVARS_AIRCONTROL_POWER = 224, // DP +STAT_MOVEFLAGS = 225, // DP +STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL = 226, // DP +STAT_MOVEVARS_WARSOWBUNNY_ACCEL = 227, // DP +STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED = 228, // DP +STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL = 229, // DP +STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO = 230, // DP +STAT_MOVEVARS_AIRSTOPACCELERATE = 231, // DP +STAT_MOVEVARS_AIRSTRAFEACCELERATE = 232, // DP +STAT_MOVEVARS_MAXAIRSTRAFESPEED = 233, // DP +STAT_MOVEVARS_AIRCONTROL = 234, // DP +STAT_FRAGLIMIT = 235, // DP +STAT_TIMELIMIT = 236, // DP +STAT_MOVEVARS_WALLFRICTION = 237, // DP +STAT_MOVEVARS_FRICTION = 238, // DP +STAT_MOVEVARS_WATERFRICTION = 239, // DP +STAT_MOVEVARS_TICRATE = 240, // DP +STAT_MOVEVARS_TIMESCALE = 241, // DP +STAT_MOVEVARS_GRAVITY = 242, // DP +STAT_MOVEVARS_STOPSPEED = 243, // DP +STAT_MOVEVARS_MAXSPEED = 244, // DP +STAT_MOVEVARS_SPECTATORMAXSPEED = 245, // DP +STAT_MOVEVARS_ACCELERATE = 246, // DP +STAT_MOVEVARS_AIRACCELERATE = 247, // DP +STAT_MOVEVARS_WATERACCELERATE = 248, // DP +STAT_MOVEVARS_ENTGRAVITY = 249, // DP +STAT_MOVEVARS_JUMPVELOCITY = 250, // DP +STAT_MOVEVARS_EDGEFRICTION = 251, // DP +STAT_MOVEVARS_MAXAIRSPEED = 252, // DP +STAT_MOVEVARS_STEPHEIGHT = 253, // DP +STAT_MOVEVARS_AIRACCEL_QW = 254, // DP STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION = 255, // DP MAX_CL_STATS = 256 diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index 300faa8fc..9831654fc 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -504,7 +504,7 @@ typedef struct #define FTECONTENTS_LAVA 8 #define FTECONTENTS_SLIME 16 #define FTECONTENTS_WATER 32 -//#define FTECONTENTS_LADDER 32 +#define FTECONTENTS_LADDER 0x00004000 #define FTECONTENTS_FLUID (FTECONTENTS_WATER|FTECONTENTS_SLIME|FTECONTENTS_LAVA|FTECONTENTS_SKY) //sky is a fluid for q1 code. #define FTECONTENTS_PLAYERCLIP 0x00010000 #define FTECONTENTS_BODY 0x02000000 diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 0c313f100..30673d5e1 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -2161,18 +2161,21 @@ void Mod_ParseQ3SkinFile(char *out, char *surfname, char *modelname, int skinnum } #if defined(D3DQUAKE) || defined(GLQUAKE) -void Mod_LoadSkinFile(texnums_t *texnum, char *surfacename, int skinnumber, unsigned char *rawdata, int width, int height, unsigned char *palette) +shader_t *Mod_LoadSkinFile(shader_t **shaders, char *surfacename, int skinnumber, unsigned char *rawdata, int width, int height, unsigned char *palette) { + shader_t *shader; char shadername[MAX_QPATH]; Q_strncpyz(shadername, surfacename, sizeof(shadername)); Mod_ParseQ3SkinFile(shadername, surfacename, loadmodel->name, skinnumber, NULL); - texnum->shader = R_RegisterSkin(shadername, loadmodel->name); + shader = R_RegisterSkin(shadername, loadmodel->name); - R_BuildDefaultTexnums(texnum, texnum->shader); - if (texnum->shader->flags & SHADER_NOIMAGE) - Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", texnum->shader->name, loadmodel->name); + R_BuildDefaultTexnums(&shader->defaulttextures, shader); + if (shader->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", shader->name, loadmodel->name); + + return shader; } #endif @@ -2424,7 +2427,7 @@ static void *Q1_LoadSkins_SV (daliasskintype_t *pskintype, qboolean alpha) #if defined(GLQUAKE) || defined(D3DQUAKE) static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintranstype) { - texnums_t *texnums; + shader_t **shaders; char skinname[MAX_QPATH]; int i; int s, t; @@ -2485,8 +2488,8 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran if (!TEXVALID(texture) || (loadmodel->engineflags & MDLF_NOTREPLACEMENTS)) { //we're not using 24bits - texnums = Hunk_Alloc(sizeof(*texnums)+s); - saved = (qbyte*)(texnums+1); + shaders = Hunk_Alloc(sizeof(*shaders)+s); + saved = (qbyte*)(shaders+1); outskin->ofstexels = (qbyte *)(saved) - (qbyte *)outskin; memcpy(saved, pskintype+1, s); Mod_FloodFillSkin(saved, outskin->skinwidth, outskin->skinheight); @@ -2523,16 +2526,16 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran } } else - texnums = Hunk_Alloc(sizeof(*texnums)); - outskin->texnums=1; + shaders = Hunk_Alloc(sizeof(*shaders)); + outskin->numshaders=1; - outskin->ofstexnums = (char *)texnums - (char *)outskin; + outskin->ofsshaders = (char *)shaders - (char *)outskin; Q_snprintfz(skinname, sizeof(skinname), "%s_%i", loadname, i); if (skintranstype == 4) - texnums->shader = R_RegisterShader(skinname, + shaders[0] = R_RegisterShader(skinname, "{\n" "{\n" "map $diffuse\n" @@ -2543,7 +2546,7 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran "}\n" "}\n"); else if (skintranstype == 3) - texnums->shader = R_RegisterShader(skinname, + shaders[0] = R_RegisterShader(skinname, "{\n" "{\n" "map $diffuse\n" @@ -2553,7 +2556,7 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran "}\n" "}\n"); else if (skintranstype) - texnums->shader = R_RegisterShader(skinname, + shaders[0] = R_RegisterShader(skinname, "{\n" "{\n" "map $diffuse\n" @@ -2563,26 +2566,24 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran "}\n" "}\n"); else - texnums->shader = R_RegisterSkin(skinname, loadmodel->name); - R_BuildDefaultTexnums(texnums, texnums->shader); + shaders[0] = R_RegisterSkin(skinname, loadmodel->name); - texnums->loweroverlay = r_nulltex; - texnums->upperoverlay = r_nulltex; - - texnums->base = texture; - texnums->fullbright = fbtexture; - texnums->bump = bumptexture; + shaders[0]->defaulttextures.base = texture; + shaders[0]->defaulttextures.fullbright = fbtexture; + shaders[0]->defaulttextures.bump = bumptexture; //13/4/08 IMPLEMENTME if (r_skin_overlays.ival) { snprintf(skinname, sizeof(skinname), "%s_%i_pants", loadname, i); - texnums->loweroverlay = R_LoadReplacementTexture(skinname, "models", 0); + shaders[0]->defaulttextures.loweroverlay = R_LoadReplacementTexture(skinname, "models", 0); snprintf(skinname, sizeof(skinname), "%s_%i_shirt", loadname, i); - texnums->upperoverlay = R_LoadReplacementTexture(skinname, "models", 0); + shaders[0]->defaulttextures.upperoverlay = R_LoadReplacementTexture(skinname, "models", 0); } + R_BuildDefaultTexnums(&shaders[0]->defaulttextures, shaders[0]); + pskintype = (daliasskintype_t *)((char *)(pskintype+1)+s); break; @@ -2591,17 +2592,17 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran outskin->skinheight = pq1inmodel->skinheight; count = (daliasskingroup_t*)(pskintype+1); intervals = (daliasskininterval_t *)(count+1); - outskin->texnums = LittleLong(count->numskins); - data = (qbyte *)(intervals + outskin->texnums); - texnums = Hunk_Alloc(sizeof(*texnums)*outskin->texnums); - outskin->ofstexnums = (char *)texnums - (char *)outskin; + outskin->numshaders = LittleLong(count->numskins); + data = (qbyte *)(intervals + outskin->numshaders); + shaders = Hunk_Alloc(sizeof(*shaders)*outskin->numshaders); + outskin->ofsshaders = (char *)shaders - (char *)outskin; outskin->ofstexels = 0; sinter = LittleFloat(intervals[0].interval); if (sinter <= 0) sinter = 0.1; outskin->skinspeed = 1/sinter; - for (t = 0; t < outskin->texnums; t++,data+=s, texnums++) + for (t = 0; t < outskin->numshaders; t++,data+=s) { texture = r_nulltex; fbtexture = r_nulltex; @@ -2659,14 +2660,14 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran } Q_snprintfz(skinname, sizeof(skinname), "%s_%i_%i", loadname, i, t); - texnums->shader = R_RegisterSkin(skinname, loadmodel->name); + shaders[t] = R_RegisterSkin(skinname, loadmodel->name); - TEXASSIGN(texnums->base, texture); - TEXASSIGN(texnums->fullbright, fbtexture); - TEXASSIGN(texnums->loweroverlay, r_nulltex); - TEXASSIGN(texnums->upperoverlay, r_nulltex); + TEXASSIGN(shaders[t]->defaulttextures.base, texture); + TEXASSIGN(shaders[t]->defaulttextures.fullbright, fbtexture); + TEXASSIGN(shaders[t]->defaulttextures.loweroverlay, r_nulltex); + TEXASSIGN(shaders[t]->defaulttextures.upperoverlay, r_nulltex); - R_BuildDefaultTexnums(texnums, texnums->shader); + R_BuildDefaultTexnums(&shaders[t]->defaulttextures, shaders[t]); } pskintype = (daliasskintype_t *)data; break; @@ -3034,19 +3035,19 @@ static void Q2_LoadSkins(md2_t *pq2inmodel, char *skins) { #ifndef SERVERONLY int i; - texnums_t *texnums; + shader_t **shaders; galiasskin_t *outskin = (galiasskin_t *)((char *)galias + galias->ofsskins); for (i = 0; i < LittleLong(pq2inmodel->num_skins); i++, outskin++) { - texnums = Hunk_Alloc(sizeof(*texnums)); - outskin->ofstexnums = (char *)texnums - (char *)outskin; - outskin->texnums=1; + shaders = Hunk_Alloc(sizeof(*shaders)); + outskin->ofsshaders = (char *)shaders - (char *)outskin; + outskin->numshaders=1; COM_CleanUpPath(skins); //blooming tanks. - TEXASSIGN(texnums->base, R_LoadReplacementTexture(skins, "models", IF_NOALPHA)); - texnums->shader = R_RegisterSkin(skins, loadmodel->name); - R_BuildDefaultTexnums(texnums, texnums->shader); + shaders[0] = R_RegisterSkin(skins, loadmodel->name); + TEXASSIGN(shaders[0]->defaulttextures.base, R_LoadReplacementTexture(skins, "models", IF_NOALPHA)); + R_BuildDefaultTexnums(NULL, shaders[0]); outskin->skinwidth = 0; outskin->skinheight = 0; @@ -3057,20 +3058,19 @@ static void Q2_LoadSkins(md2_t *pq2inmodel, char *skins) #endif galias->numskins = LittleLong(pq2inmodel->num_skins); + /* #ifndef SERVERONLY outskin = (galiasskin_t *)((char *)galias + galias->ofsskins); outskin += galias->numskins - 1; if (galias->numskins) { - texnums = (texnums_t*)((char *)outskin +outskin->ofstexnums); - if (TEXVALID(texnums->base)) - return; - if (texnums->shader) + if (*(shader_t**)((char *)outskin + outskin->ofstexnums)) return; galias->numskins--; } #endif + */ } #define MD2_MAX_TRIANGLES 4096 @@ -3831,7 +3831,7 @@ qboolean Mod_LoadQ3Model(model_t *mod, void *buffer) { #ifndef SERVERONLY galiasskin_t *skin; - texnums_t *texnum; + shader_t **shaders; float lat, lng; md3St_t *inst; vec3_t *normals; @@ -3992,14 +3992,14 @@ qboolean Mod_LoadQ3Model(model_t *mod, void *buffer) //extern int gl_bumpmappingpossible; // unused variable char shadname[1024]; - skin = Hunk_Alloc((LittleLong(surf->numShaders)+externalskins)*((sizeof(galiasskin_t)+sizeof(texnums_t)))); + skin = Hunk_Alloc((LittleLong(surf->numShaders)+externalskins)*((sizeof(galiasskin_t)+sizeof(shader_t*)))); galias->ofsskins = (qbyte *)skin - (qbyte *)galias; - texnum = (texnums_t *)(skin + LittleLong(surf->numShaders)+externalskins); + shaders = (shader_t **)(skin + LittleLong(surf->numShaders)+externalskins); inshader = (md3Shader_t *)((qbyte *)surf + LittleLong(surf->ofsShaders)); for (i = 0; i < externalskins; i++) { - skin->texnums = 1; - skin->ofstexnums = (qbyte *)texnum - (qbyte *)skin; + skin->numshaders = 1; + skin->ofsshaders = (qbyte *)&shaders[i] - (qbyte *)skin; skin->ofstexels = 0; skin->skinwidth = 0; skin->skinheight = 0; @@ -4021,16 +4021,15 @@ qboolean Mod_LoadQ3Model(model_t *mod, void *buffer) if (qrenderer != QR_NONE) { - texnum->shader = R_RegisterSkin(shadname, mod->name); - R_BuildDefaultTexnums(texnum, texnum->shader); + shaders[i] = R_RegisterSkin(shadname, mod->name); + R_BuildDefaultTexnums(NULL, shaders[i]); - if (texnum->shader->flags & SHADER_NOIMAGE) - Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", texnum->shader->name, loadmodel->name); + if (shaders[i]->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", shaders[i]->name, loadmodel->name); } inshader++; skin++; - texnum++; } galias->numskins = i; } @@ -4181,7 +4180,7 @@ qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer) { #ifndef SERVERONLY galiasskin_t *skin; - texnums_t *texnum; + shader_t **shaders; int skinfiles; int j; #endif @@ -4366,14 +4365,14 @@ qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer) root[i].ofs_st_array = (char*)stcoords - (char*)&root[i]; root[i].numskins = skinfiles; - skin = Hunk_Alloc((sizeof(galiasskin_t)+sizeof(texnums_t))*skinfiles); - texnum = (texnums_t*)(skin+skinfiles); - for (j = 0; j < skinfiles; j++, texnum++) + skin = Hunk_Alloc((sizeof(galiasskin_t)+sizeof(shader_t*))*skinfiles); + shaders = (shader_t**)(skin+skinfiles); + for (j = 0; j < skinfiles; j++, shaders++) { - skin[j].texnums = 1; //non-sequenced skins. - skin[j].ofstexnums = (char *)texnum - (char *)&skin[j]; + skin[j].numshaders = 1; //non-sequenced skins. + skin[j].ofsshaders = (char *)shaders - (char *)&skin[j]; - Mod_LoadSkinFile(texnum, surfname, j, NULL, 0, 0, NULL); + Mod_LoadSkinFile(shaders, surfname, j, NULL, 0, 0, NULL); } root[i].ofsskins = (char *)skin - (char *)&root[i]; @@ -4566,7 +4565,7 @@ qboolean Mod_LoadPSKModel(model_t *mod, void *buffer) #ifndef SERVERONLY float *stcoord; galiasskin_t *skin; - texnums_t *gtexnums; + shader_t **gshaders; #endif galiasbone_t *bones; galiasgroup_t *group; @@ -5034,25 +5033,28 @@ qboolean Mod_LoadPSKModel(model_t *mod, void *buffer) group->isheirachical = false; } - for (i = 0; i < num_matt; i++) - { #ifndef SERVERONLY - skin = Hunk_Alloc(sizeof(galiasskin_t) + sizeof(texnums_t)); - gtexnums = (texnums_t*)(skin+1); - skin->ofstexnums = sizeof(*skin); - skin->texnums = 1; + skin = Hunk_Alloc(num_matt * (sizeof(galiasskin_t) + sizeof(shader_t*))); + gshaders = (shader_t**)(skin + num_matt); + for (i = 0; i < num_matt; i++, skin++) + { + skin->ofsshaders = (char*)&gshaders[i] - (char*)skin; + skin->numshaders = 1; skin->skinspeed = 10; Q_strncpyz(skin->name, matt[i].name, sizeof(skin->name)); - gtexnums->shader = R_RegisterSkin(matt[i].name, mod->name); - R_BuildDefaultTexnums(gtexnums, gtexnums->shader); - if (gtexnums->shader->flags & SHADER_NOIMAGE) - Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", gtexnums->shader->name, loadmodel->name); + gshaders[i] = R_RegisterSkin(matt[i].name, mod->name); + R_BuildDefaultTexnums(NULL, gshaders[i]); + if (gshaders[i]->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", gshaders[i]->name, loadmodel->name); gmdl[i].ofsskins = (char*)skin - (char*)&gmdl[i]; gmdl[i].numskins = 1; gmdl[i].ofs_st_array = (char*)stcoord - (char*)&gmdl[i]; gmdl[i].numverts = num_vtxw; +#else + for (i = 0; i < num_matt; i++, skin++, gshaders++) + { #endif gmdl[i].groupofs = (char*)group - (char*)&gmdl[i]; @@ -5223,7 +5225,7 @@ qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer) { #ifndef SERVERONLY galiasskin_t *skin; - texnums_t *texnum; + shader_t **shaders; int skinfiles; float *inst; float *outst; @@ -5440,14 +5442,14 @@ qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer) #else m->numskins = skinfiles; - skin = Hunk_Alloc((sizeof(galiasskin_t)+sizeof(texnums_t))*skinfiles); - texnum = (texnums_t*)(skin+skinfiles); - for (j = 0; j < skinfiles; j++, texnum++) + skin = Hunk_Alloc((sizeof(galiasskin_t)+sizeof(shader_t*))*skinfiles); + shaders = (shader_t**)(skin+skinfiles); + for (j = 0; j < skinfiles; j++, shaders++) { - skin[j].texnums = 1; //non-sequenced skins. - skin[j].ofstexnums = (char *)texnum - (char *)&skin[j]; + skin[j].numshaders = 1; //non-sequenced skins. + skin[j].ofsshaders = (char *)shaders - (char *)&skin[j]; - Mod_LoadSkinFile(texnum, mesh->shadername, j, NULL, 0, 0, NULL); + Mod_LoadSkinFile(shaders, mesh->shadername, j, NULL, 0, 0, NULL); } m->ofsskins = (char *)skin - (char *)m; @@ -5667,7 +5669,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) #endif galiasgroup_t *fgroup; galiasbone_t *bones; - texnums_t *texnum; + shader_t **shaders; index_t *idx; float basepose[12 * MAX_BONES]; qboolean baseposeonly; @@ -5736,7 +5738,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) /*allocate a nice big block of memory and figure out where stuff is*/ gai = Hunk_Alloc(sizeof(*gai)*h->num_meshes + #ifndef SERVERONLY - sizeof(*skin)*h->num_meshes + sizeof(*texnum)*h->num_meshes + + sizeof(*skin)*h->num_meshes + sizeof(*shaders)*h->num_meshes + #endif sizeof(*fgroup)*(baseposeonly?1:h->num_anims) + sizeof(float)*12*(baseposeonly?h->num_joints:(h->num_poses*h->num_frames)) + sizeof(*bones)*h->num_joints + (sizeof(*opos) + sizeof(*onorm) + sizeof(*otcoords) + (noweights?0:(sizeof(*oindex)+sizeof(*oweight)))) * h->num_vertexes); @@ -5759,7 +5761,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) opose = (float*)(fgroup + (baseposeonly?1:h->num_anims)); #ifndef SERVERONLY skin = (galiasskin_t*)(opose + 12*(baseposeonly?h->num_joints:h->num_poses*h->num_frames)); - texnum = (texnums_t*)(skin + h->num_meshes); + shaders = (shader_t**)(skin + h->num_meshes); #endif //no code to load animations or bones @@ -5900,12 +5902,12 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) skin[i].skinheight = 1; skin[i].ofstexels = 0; /*doesn't support 8bit colourmapping*/ skin[i].skinspeed = 10; /*something to avoid div by 0*/ - skin[i].texnums = 1; - skin[i].ofstexnums = (char*)&texnum[i] - (char*)&skin[i]; - texnum[i].shader = R_RegisterSkin(skin[i].name, mod->name); - R_BuildDefaultTexnums(&texnum[i], texnum[i].shader); - if (texnum[i].shader->flags & SHADER_NOIMAGE) - Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", texnum[i].shader->name, loadmodel->name); + skin[i].numshaders = 1; + skin[i].ofsshaders = (char*)&shaders[i] - (char*)&skin[i]; + shaders[i] = R_RegisterSkin(skin[i].name, mod->name); + R_BuildDefaultTexnums(NULL, shaders[i]); + if (shaders[i]->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", shaders[i]->name, loadmodel->name); gai[i].ofs_st_array = (char*)(otcoords+offset) - (char*)&gai[i]; #endif @@ -6229,7 +6231,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer, char *modname) float *posedata; #ifndef SERVERONLY galiasskin_t *skin; - texnums_t *texnum; + shader_t **shaders; #endif char *filestart = buffer; @@ -6389,12 +6391,12 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer, char *modname) #ifndef SERVERONLY skin = Hunk_Alloc(sizeof(*skin)); - texnum = Hunk_Alloc(sizeof(*texnum)); + shaders = Hunk_Alloc(sizeof(*shaders)); inf->numskins = 1; inf->ofsskins = (char*)skin - (char*)inf; - skin->texnums = 1; + skin->numshaders = 1; skin->skinspeed = 1; - skin->ofstexnums = (char*)texnum - (char*)skin; + skin->ofsshaders = (char*)shaders - (char*)skin; #endif EXPECT("{"); for(;;) @@ -6407,10 +6409,11 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer, char *modname) { buffer = COM_Parse(buffer); #ifndef SERVERONLY - texnum->shader = R_RegisterSkin(com_token, modname); - R_BuildDefaultTexnums(texnum, texnum->shader); - if (texnum->shader->flags & SHADER_NOIMAGE) - Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", texnum->shader->name, loadmodel->name); + //FIXME: we probably want to support multiple skins some time + shaders[0] = R_RegisterSkin(com_token, modname); + R_BuildDefaultTexnums(NULL, shaders[0]); + if (shaders[0]->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", shaders[0]->name, loadmodel->name); #endif } else if (!strcmp(com_token, "numverts")) diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index a140f3626..eb5859f3a 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -108,8 +108,8 @@ typedef struct { int skinheight; int ofstexels; //this is 8bit for frame 0 only. only valid in q1 models without replacement textures, used for colourising player skins. float skinspeed; - int texnums; - int ofstexnums; + int numshaders; + int ofsshaders; char name [MAX_QPATH]; } galiasskin_t; diff --git a/engine/common/common.c b/engine/common/common.c index be1872a4f..401c412d1 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1681,7 +1681,7 @@ char *COM_FileExtension (const char *in) { static char exten[8]; int i; - char *dot; + const char *dot; for (dot = in + strlen(in); dot >= in && *dot != '.'; dot--) ; @@ -3371,9 +3371,13 @@ void COM_Init (void) nullentitystate.colormod[0] = 32; nullentitystate.colormod[1] = 32; nullentitystate.colormod[2] = 32; + nullentitystate.glowmod[0] = 32; + nullentitystate.glowmod[1] = 32; + nullentitystate.glowmod[2] = 32; nullentitystate.trans = 255; nullentitystate.scale = 16; nullentitystate.abslight = 255; + nullentitystate.solid = 0;//ES_SOLID_BSP; } diff --git a/engine/common/common.h b/engine/common/common.h index 79291a2a4..ce4dbad7a 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -403,6 +403,7 @@ void COM_InitFilesystem (void); void FS_Shutdown(void); void COM_Gamedir (const char *dir); char *FS_GetGamedir(void); +void *FS_GetBasedir(void); qbyte *FS_LoadMallocFile (const char *path); int FS_LoadFile(char *name, void **file); diff --git a/engine/common/fs.c b/engine/common/fs.c index 811777a29..8476a5198 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1576,6 +1576,11 @@ char *FS_GetGamedir(void) { return gamedirfile; } +/*unsafe - provided only for gamecode compat, should not be used for internal features*/ +char *FS_GetBasedir(void) +{ + return com_quakedir; +} /* ================ COM_Gamedir @@ -1779,8 +1784,8 @@ const gamemode_info_t gamemode_info[] = { {"FTE-JK2", "jk2", "-jk2", {"base/assets0.pk3"}, NULL, {"base", "fte"}, "Jedi Knight II: Jedi Outcast"}, {"FTE-HalfLife", "hl", "-halflife", {"valve/liblist.gam"}, NULL, {"valve", "ftehl"}, "Half-Life"}, - {"FTE-Doom", "doom", "-doom", {"doom.wad"}, NULL, { "ftedoom"}, "Doom"}, - {"FTE-Doom2", "doom2", "-doom2", {"doom2.wad"}, NULL, { "ftedoom"}, "Doom2"}, + {"FTE-Doom", "doom", "-doom", {"doom.wad"}, NULL, {"*doom.wad", "ftedoom"}, "Doom"}, + {"FTE-Doom2", "doom2", "-doom2", {"doom2.wad"}, NULL, {"*doom2.wad", "ftedoom"}, "Doom2"}, {NULL} }; @@ -2023,24 +2028,6 @@ char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum) return buffer; } -#ifdef DOOMWADS -void FS_AddRootWads(void) -{ - vfsfile_t *vfs; - char *fname = "doom.wad"; - void *pak; - extern searchpathfuncs_t doomwadfilefuncs; - - vfs = FS_OpenVFS(fname, "rb", FS_ROOT); - - pak = doomwadfilefuncs.OpenNew(vfs, fname); - if (!pak) - return; - - FS_AddPathHandle(fname, fname, &doomwadfilefuncs, pak, true, false, true, (unsigned int)-1); -} -#endif - /* ================ FS_ReloadPackFiles @@ -2084,10 +2071,6 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) com_base_searchpaths = NULL; -#ifdef DOOMWADS - FS_AddRootWads(); -#endif - while(oldpaths) { next = oldpaths->nextpure; @@ -2390,9 +2373,47 @@ void FS_Shutdown(void) } +void FS_AddGamePack(const char *pakname) +{ + int j; + char *ext = COM_FileExtension(pakname); + vfsfile_t *vfs = VFSOS_Open(pakname, "rb"); + void *pak; + if (!vfs) + Con_Printf("Unable to open %s - missing?\n", pakname); + else + { + for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++) + { + if (!searchpathformats[j].extension || !searchpathformats[j].funcs || !searchpathformats[j].funcs->OpenNew) + continue; + if (!strcmp(ext, searchpathformats[j].extension)) + { + pak = searchpathformats[j].funcs->OpenNew(vfs, pakname); + if (pak) + { + FS_AddPathHandle("", pakname, searchpathformats[j].funcs, pak, true, false, true, (unsigned int)-1); + } + else + { + Con_Printf("Unable to open %s - corrupt?\n", pakname); + VFS_CLOSE(vfs); + } + vfs = NULL; + break; + } + } + if (vfs) + { + VFS_CLOSE(vfs); + Con_Printf("Unable to open %s - unsupported?\n", pakname); + } + } +} + void FS_StartupWithGame(int gamenum) { - int i, j; + int i; #ifdef AVAIL_ZLIB LibZ_Init(); @@ -2401,48 +2422,11 @@ void FS_StartupWithGame(int gamenum) Cvar_Set(&com_protocolname, gamemode_info[gamenum].protocolname); Cvar_ForceSet(&fs_gamename, gamemode_info[gamenum].poshname); -#ifdef DOOMWADS - FS_AddRootWads(); -#endif - i = COM_CheckParm ("-basepack"); while (i && i < com_argc-1) { // Con_Printf("found -basepack: %s\n", com_argv[i+1]); - - char *ext = COM_FileExtension(com_argv[i+1]); - vfsfile_t *vfs = VFSOS_Open(com_argv[i+1], "rb"); - void *pak; - if (!vfs) - Con_Printf("Unable to open %s - missing?\n", com_argv[i+1]); - else - { - for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++) - { - if (!searchpathformats[j].extension || !searchpathformats[j].funcs || !searchpathformats[j].funcs->OpenNew) - continue; - if (!strcmp(ext, searchpathformats[j].extension)) - { - pak = searchpathformats[j].funcs->OpenNew(vfs, com_argv[i+1]); - if (pak) - { - FS_AddPathHandle("", com_argv[i+1], searchpathformats[j].funcs, pak, true, false, true, (unsigned int)-1); - } - else - { - Con_Printf("Unable to open %s - corrupt?\n", com_argv[i+1]); - VFS_CLOSE(vfs); - } - vfs = NULL; - break; - } - } - if (vfs) - { - VFS_CLOSE(vfs); - Con_Printf("Unable to open %s - unsupported?\n", com_argv[i+1]); - } - } + FS_AddGamePack(com_argv[i+1]); i = COM_CheckNextParm ("-basepack", i); } @@ -2466,7 +2450,13 @@ void FS_StartupWithGame(int gamenum) { for (i = 0; i < sizeof(gamemode_info[gamenum].dir)/sizeof(gamemode_info[gamenum].dir[0]); i++) { - if (gamemode_info[gamenum].dir[i]) + if (gamemode_info[gamenum].dir[i] && *gamemode_info[gamenum].dir[i] == '*') + { + char buf[MAX_OSPATH]; + snprintf(buf, sizeof(buf), "%s%s", com_quakedir, gamemode_info[gamenum].dir[i]+1); + FS_AddGamePack(buf); + } + else if (gamemode_info[gamenum].dir[i]) { FS_AddGameDirectory (gamemode_info[gamenum].dir[i], va("%s%s", com_quakedir, gamemode_info[gamenum].dir[i]), ~0); if (*com_homedir) diff --git a/engine/common/net.h b/engine/common/net.h index 523313feb..8f8c98bee 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -120,6 +120,7 @@ typedef struct qboolean nqreliable_allowed; #endif struct netprim_s netprim; + int fragmentsize; float last_received; // for timeouts @@ -181,6 +182,8 @@ void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t adr, char *format, .. void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t adr, int language, translation_t text, ...); qboolean Netchan_Process (netchan_t *chan); void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport); +unsigned int Net_PextMask(int maskset); +extern cvar_t net_mtu; qboolean Netchan_CanPacket (netchan_t *chan, int rate); void Netchan_Block (netchan_t *chan, int bytes, int rate); diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 76c2c8c25..949d32629 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -36,7 +36,9 @@ packet header 1 does this message contain a reliable payload 31 acknowledge sequence 1 acknowledge receipt of even/odd message -16 qport +16 qport (only from client) +15 fragoffset (extension) +1 lastfrag (extension) The remote connection never knows if it missed a reliable message, the local side detects that it has been dropped by seeing a sequence acknowledge @@ -74,6 +76,7 @@ If the base part of the net address matches and the qport matches, then the channel matches even if the IP port differs. The IP port should be updated to the new value before sending out any replies. +fragmentation works like IP, offset and morefrags. offset is *8 (decode: (offset&~1)<<2 to avoid stomping on the morefrags flag, this allows really jumbo packets with 18 bits of length) */ @@ -81,6 +84,106 @@ int net_drop; cvar_t showpackets = SCVAR("showpackets", "0"); cvar_t showdrop = SCVAR("showdrop", "0"); cvar_t qport = SCVAR("qport", "0"); +cvar_t net_mtu = CVARD("mtu", "1450", "Specifies a maximum udp payload size, above which packets will be fragmented. If routers all worked properly this could be some massive value, and some massive value may work really nicely for lans. Use smaller values than the default if you're connecting through nested tunnels through routers that fail with IP fragmentation."); + +cvar_t pext_replacementdeltas = CVAR("debug_pext_replacementdeltas", "0"); /*rename once the extension is finalized*/ + +/*returns the bitmask of supported+enabled extensions*/ +unsigned int Net_PextMask(int maskset) +{ + unsigned int mask = 0; + if (maskset == 1) /*FTEX*/ + { + #ifdef PEXT_SCALE //dmw - protocol extensions + mask |= PEXT_SCALE; + #endif + #ifdef PEXT_LIGHTSTYLECOL + mask |= PEXT_LIGHTSTYLECOL; + #endif + #ifdef PEXT_TRANS + mask |= PEXT_TRANS; + #endif + #ifdef PEXT_VIEW2 + mask |= PEXT_VIEW2; + #endif + #ifdef PEXT_ACCURATETIMINGS + mask |= PEXT_ACCURATETIMINGS; + #endif + #ifdef PEXT_ZLIBDL + mask |= PEXT_ZLIBDL; + #endif + #ifdef PEXT_FATNESS + mask |= PEXT_FATNESS; + #endif + #ifdef PEXT_HLBSP + mask |= PEXT_HLBSP; + #endif + + #ifdef PEXT_Q2BSP + mask |= PEXT_Q2BSP; + #endif + #ifdef PEXT_Q3BSP + mask |= PEXT_Q3BSP; + #endif + + #ifdef PEXT_TE_BULLET + mask |= PEXT_TE_BULLET; + #endif + #ifdef PEXT_HULLSIZE + mask |= PEXT_HULLSIZE; + #endif + #ifdef PEXT_SETVIEW + mask |= PEXT_SETVIEW; + #endif + #ifdef PEXT_MODELDBL + mask |= PEXT_MODELDBL; + #endif + #ifdef PEXT_SOUNDDBL + mask |= PEXT_SOUNDDBL; + #endif + #ifdef PEXT_VWEAP + mask |= PEXT_VWEAP; + #endif + #ifdef PEXT_FLOATCOORDS + mask |= PEXT_FLOATCOORDS; + #endif + mask |= PEXT_SPAWNSTATIC2; + mask |= PEXT_COLOURMOD; + mask |= PEXT_SPLITSCREEN; + mask |= PEXT_HEXEN2; + mask |= PEXT_CUSTOMTEMPEFFECTS; + mask |= PEXT_256PACKETENTITIES; + mask |= PEXT_ENTITYDBL; + mask |= PEXT_ENTITYDBL2; + mask |= PEXT_SHOWPIC; + mask |= PEXT_SETATTACHMENT; + #ifdef PEXT_CHUNKEDDOWNLOADS + mask |= PEXT_CHUNKEDDOWNLOADS; + #endif + #ifdef PEXT_CSQC + mask |= PEXT_CSQC; + #endif + #ifdef PEXT_DPFLAGS + mask |= PEXT_DPFLAGS; + #endif + } + else if (maskset == 2) + { + mask |= PEXT2_PRYDONCURSOR; + #ifdef PEXT2_VOICECHAT + mask |= PEXT2_VOICECHAT; + #endif + mask |= PEXT2_SETANGLEDELTA; + + if (pext_replacementdeltas.ival) + mask |= PEXT2_REPLACEMENTDELTAS; + + if (MAX_CLIENTS != QWMAX_CLIENTS) + mask |= PEXT2_MAXPLAYERS; + } + + return mask; +} /* =============== @@ -92,6 +195,12 @@ void Netchan_Init (void) { int port; + Cvar_Register (&pext_replacementdeltas, "Protocol Extensions"); + Cvar_Register (&showpackets, "Networking"); + Cvar_Register (&showdrop, "Networking"); + Cvar_Register (&qport, "Networking"); + Cvar_Register (&net_mtu, "Networking"); + // pick a port value that should be nice and random #ifdef _WIN32 port = (time(NULL)) & 0xffff; @@ -99,10 +208,7 @@ void Netchan_Init (void) port = ((int)(getpid()+getuid()*1000) * time(NULL)) & 0xffff; #endif - Cvar_Register (&showpackets, "Networking"); - Cvar_Register (&showdrop, "Networking"); - Cvar_Register (&qport, "Networking"); - Cvar_SetValue(&qport, port); + Cvar_SetValue (&qport, port); } /* @@ -496,9 +602,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate) // write the packet header send.data = send_buf; - send.maxsize = MAX_QWMSGLEN + PACKET_HEADER; //dmw: wasn't quite true. - if (chan->sock == NS_CLIENT) - send.maxsize += 2; + send.maxsize = MAX_QWMSGLEN + PACKET_HEADER; send.cursize = 0; w1 = chan->outgoing_sequence | (send_reliable<<31); @@ -515,6 +619,13 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate) MSG_WriteShort (&send, cls.qport); #endif + if (chan->fragmentsize) + { + //allow the max size to be bigger + send.maxsize = MAX_OVERALLMSGLEN + PACKET_HEADER; + MSG_WriteShort(&send, 0); + } + // copy the reliable message to the packet first if (send_reliable) { @@ -535,7 +646,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate) if (chan->compress) { //int oldsize = send.cursize; - Huff_CompressPacket(&send, (chan->sock == NS_CLIENT)?10:8); + Huff_CompressPacket(&send, 8 + ((chan->sock == NS_CLIENT)?2:0) + (chan->fragmentsize?2:0)); // Con_Printf("%i becomes %i\n", oldsize, send.cursize); // Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8); } @@ -546,7 +657,45 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate) if (!cls.demoplayback) #endif { - NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address); + int hsz = 10 + ((chan->sock == NS_CLIENT)?2:0); /*header size, if fragmentation is in use*/ + + if (!chan->fragmentsize || send.cursize < chan->fragmentsize - hsz) + NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address); + else + { + int offset = chan->fragmentsize, no; + qboolean more; + /*switch on the 'more flags' bit, and send the first part*/ + send.data[hsz - 2] |= 0x1; + NET_SendPacket (chan->sock, offset, send.data, chan->remote_address); + + /*send the additional parts, adding new headers within the previous packet*/ + while(offset < send.cursize) + { + no = offset + chan->fragmentsize - hsz; + if (no < send.cursize) + { + more = true; + no &= 7; + if (no == offset) + break; + } + else + { + no = send.cursize; + more = false; + } + + *(int*)&send.data[(offset - hsz) + 0] = LittleLong(w1); + *(int*)&send.data[(offset - hsz) + 4] = LittleLong(w2); + if (chan->sock == NS_CLIENT) + *(short*)&send.data[offset - 4] = LittleShort(cls.qport); + *(short*)&send.data[offset - 2] = LittleShort(((offset-hsz)>>2) | (more?1:0)); + + NET_SendPacket (chan->sock, (no - offset) + hsz, send.data + offset - hsz, chan->remote_address); + offset = no; + } + } } Netchan_Block(chan, send.cursize, rate); @@ -562,7 +711,6 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate) , chan->incoming_sequence , chan->incoming_reliable_sequence , send.cursize); - return send.cursize; } @@ -583,6 +731,7 @@ qboolean Netchan_Process (netchan_t *chan) #ifndef CLIENTONLY int qport; #endif + int offset; if ( #ifndef SERVERONLY @@ -602,6 +751,11 @@ qboolean Netchan_Process (netchan_t *chan) qport = MSG_ReadShort (); #endif + if (chan->fragmentsize) + offset = (unsigned short)MSG_ReadShort(); + else + offset = 0; + reliable_message = sequence >> 31; reliable_ack = sequence_ack >> 31; @@ -659,6 +813,53 @@ qboolean Netchan_Process (netchan_t *chan) return false; } + if (offset) + { + int len = net_message.cursize - msg_readcount; + qboolean more = false; + if (offset & 1) + { + more = true; + offset &= ~1; + offset = offset << 2; + } + if (offset + len > sizeof(chan->in_fragment_buf)) /*stop the overflow*/ + { + if (showdrop.value) + Con_Printf("Dropping packet - too many fragments\n"); + return false; + } + if (chan->incoming_unreliable != sequence) + { + /*sequence doesn't match, forget the old*/ + chan->in_fragment_length = 0; + chan->incoming_unreliable = sequence; + } + if (offset != chan->in_fragment_length) + return false; /*dropped one*/ + + memcpy(chan->in_fragment_buf + offset, net_message.data + msg_readcount, len); + chan->in_fragment_length += net_message.cursize - msg_readcount; + + if (more) + { + /*nothing to process yet*/ + return false; + } + memcpy(net_message.data, chan->in_fragment_buf, chan->in_fragment_length); + msg_readcount = 0; + net_message.cursize = chan->in_fragment_length; + + chan->incoming_unreliable = 0; + chan->in_fragment_length = 0; + } + else + { + /*kill any pending reliable*/ + chan->incoming_unreliable = 0; + chan->in_fragment_length = 0; + } + // // dropped packets don't keep the message from being used // diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 5815cce7b..35c0b774b 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -75,6 +75,7 @@ extern cvar_t sv_port_tcp; extern cvar_t sv_port_tcp6; #endif cvar_t net_hybriddualstack = CVAR("net_hybriddualstack", "1"); +cvar_t net_fakeloss = CVARFD("net_fakeloss", "0", CVAR_CHEAT, "Simulates packetloss in both receiving and sending, on a scale from 0 to 1."); extern cvar_t sv_public, sv_listen_qw, sv_listen_nq, sv_listen_dp, sv_listen_q3; @@ -2890,15 +2891,23 @@ int NET_GetPacket (netsrc_t netsrc, int firstsock) if (!collection) return -1; - for (; firstsock < MAX_CONNECTIONS; firstsock+=1) + while (firstsock < MAX_CONNECTIONS) { if (!collection->conn[firstsock]) break; if (collection->conn[firstsock]->GetPacket(collection->conn[firstsock])) { + if (net_fakeloss.value) + { + if (frandom () < net_fakeloss.value) + continue; + } + net_from.connum = firstsock+1; return firstsock; } + + firstsock += 1; } return -1; @@ -2945,6 +2954,12 @@ void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t to) if (!collection) return; + if (net_fakeloss.value) + { + if (frandom () < net_fakeloss.value) + return; + } + if (to.connum) { if (collection->conn[to.connum-1]) @@ -3487,6 +3502,7 @@ void NET_Init (void) #endif Cvar_Register(&net_hybriddualstack, "networking"); + Cvar_Register(&net_fakeloss, "networking"); #ifndef CLIENTONLY Cmd_AddCommand("sv_addport", SVNET_AddPort_f); diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 391e7c0cf..076983f8f 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -516,7 +516,7 @@ void PM_WaterMove (void) for (i=0 ; i<3 ; i++) wishvel[i] = forward[i]*pmove.cmd.forwardmove + right[i]*pmove.cmd.sidemove; - if (pmove.pm_type != PM_FLY && !pmove.cmd.forwardmove && !pmove.cmd.sidemove && !pmove.cmd.upmove) + if (pmove.pm_type != PM_FLY && !pmove.cmd.forwardmove && !pmove.cmd.sidemove && !pmove.cmd.upmove && !pmove.onladder) wishvel[2] -= 60; // drift towards bottom else wishvel[2] += pmove.cmd.upmove; @@ -760,13 +760,11 @@ void PM_CategorizePosition (void) } } - if (cont & Q2CONTENTS_LADDER && pmove.physents[0].model->fromgame == fg_quake2) - pmove.onladder = true; - else - pmove.onladder = false; + //bsp objects marked as ladders mark regions to stand in to be classed as on a ladder. + cont = PM_ExtraBoxContents(pmove.origin); - //are we on a ladder? #ifdef Q2BSPS + //q3 has surfaceflag-based ladders if (pmove.physents[0].model->fromgame == fg_quake3) { trace_t t; @@ -786,7 +784,9 @@ void PM_CategorizePosition (void) pmove.onground = false; // too steep } } - if (cont & Q2CONTENTS_LADDER && pmove.physents[0].model->fromgame == fg_quake2) +#endif + //q2 has contents-based ladders + if ((cont & FTECONTENTS_LADDER) || ((cont & Q2CONTENTS_LADDER) && pmove.physents[0].model->fromgame == fg_quake2)) { trace_t t; vec3_t flatforward, fwd1; @@ -799,25 +799,13 @@ void PM_CategorizePosition (void) VectorMA (pmove.origin, 24, flatforward, fwd1); //if we hit a wall when going forwards and we are in a ladder region, then we are on a ladder. - if (pmove.physents[0].model->fromgame == fg_quake2) + t = PM_PlayerTrace(pmove.origin, fwd1); + if (t.fraction < 1) { - t = CM_BoxTrace(pmove.physents[0].model, pmove.origin, fwd1, player_mins, player_maxs, MASK_PLAYERSOLID); - if (t.fraction < 1) - { - pmove.onladder = true; - pmove.onground = false; // too steep - } + pmove.onladder = true; + pmove.onground = false; // too steep } } -#endif - - //bsp objects marked as ladders mark regions to stand in to be classed as on a ladder. - cont = PM_ExtraBoxContents(pmove.origin); - if ((cont & Q2CONTENTS_LADDER) && (pmove.physents[0].model->fromgame == fg_quake2 || pmove.physents[0].model->fromgame == fg_halflife)) - { - pmove.onladder = true; - pmove.onground = false; // too steep - } if (pmove.onground && pmove.pm_type != PM_FLY && pmove.waterlevel < 2) { @@ -956,7 +944,7 @@ void PM_NudgePosition (void) VectorCopy (pmove.origin, base); for (i=0 ; i<3 ; i++) - pmove.origin[i] = ((int)(pmove.origin[i]*8)) * 0.125; + base[i] = ((int)(base[i]*8)) * 0.125; for (z=0 ; z<=4 ; z++) { diff --git a/engine/common/pmove.h b/engine/common/pmove.h index 9cdacd2b5..99a2790bf 100644 --- a/engine/common/pmove.h +++ b/engine/common/pmove.h @@ -60,7 +60,6 @@ typedef struct int jump_msec; // msec since last jump float waterjumptime; int pm_type; - int hullnum; // world state int numphysent; @@ -72,6 +71,7 @@ typedef struct qboolean onladder; // results + int skipent; int numtouch; int touchindex[MAX_PHYSENTS]; vec3_t touchvel[MAX_PHYSENTS]; diff --git a/engine/common/pmovetst.c b/engine/common/pmovetst.c index fd1128dd6..bbe53db3e 100644 --- a/engine/common/pmovetst.c +++ b/engine/common/pmovetst.c @@ -125,26 +125,35 @@ int PM_PointContents (vec3_t p) for (num = 1; num < pmove.numphysent; num++) { pe = &pmove.physents[num]; + + if (pe->info == pmove.skipent) + continue; + pm = pe->model; if (pm) { - if (pe->forcecontentsmask) + if (p[0] >= pe->origin[0]+pm->mins[0] && p[0] <= pe->origin[0]+pm->maxs[0] && + p[1] >= pe->origin[1]+pm->mins[1] && p[1] <= pe->origin[1]+pm->maxs[1] && + p[2] >= pe->origin[2]+pm->mins[2] && p[2] <= pe->origin[2]+pm->maxs[2]) { - if (PM_TransformedModelPointContents(pm, p, pe->origin, pe->angles)) - pc |= pe->forcecontentsmask; - } - else - { - if (pe->nonsolid) - continue; - pc |= PM_TransformedModelPointContents(pm, p, pe->origin, pe->angles); + if (pe->forcecontentsmask) + { + if (PM_TransformedModelPointContents(pm, p, pe->origin, pe->angles)) + pc |= pe->forcecontentsmask; + } + else + { + if (pe->nonsolid) + continue; + pc |= PM_TransformedModelPointContents(pm, p, pe->origin, pe->angles); + } } } else if (pe->forcecontentsmask) { - if (p[0] >= pe->mins[0] && p[0] <= pe->maxs[0] && - p[1] >= pe->mins[1] && p[1] <= pe->maxs[1] && - p[2] >= pe->mins[2] && p[2] <= pe->maxs[2]) + if (p[0] >= pe->origin[0]+pe->mins[0] && p[0] <= pe->origin[0]+pe->maxs[0] && + p[1] >= pe->origin[1]+pe->mins[1] && p[1] <= pe->origin[1]+pe->maxs[1] && + p[2] >= pe->origin[2]+pe->mins[2] && p[2] <= pe->origin[2]+pe->maxs[2]) pc |= pe->forcecontentsmask; } } @@ -179,9 +188,9 @@ int PM_ExtraBoxContents (vec3_t p) } else if (pe->forcecontentsmask) { - if (p[0]+player_maxs[0] >= pe->mins[0] && p[0]+player_mins[0] <= pe->maxs[0] && - p[1]+player_maxs[1] >= pe->mins[1] && p[1]+player_mins[1] <= pe->maxs[1] && - p[2]+player_maxs[2] >= pe->mins[2] && p[2]+player_mins[2] <= pe->maxs[2]) + if (p[0]+player_maxs[0] >= pe->origin[0]+pe->mins[0] && p[0]+player_mins[0] <= pe->origin[0]+pe->maxs[0] && + p[1]+player_maxs[1] >= pe->origin[1]+pe->mins[1] && p[1]+player_mins[1] <= pe->origin[1]+pe->maxs[1] && + p[2]+player_maxs[2] >= pe->origin[2]+pe->mins[2] && p[2]+player_mins[2] <= pe->origin[2]+pe->maxs[2]) pc |= pe->forcecontentsmask; } } @@ -267,6 +276,9 @@ qboolean PM_TestPlayerPosition (vec3_t pos) { pe = &pmove.physents[i]; + if (pe->info == pmove.skipent) + continue; + if (pe->nonsolid) continue; @@ -316,6 +328,8 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end) if (pe->nonsolid) continue; + if (pe->info == pmove.skipent) + continue; if (!pe->model || pe->model->needload) { @@ -363,6 +377,5 @@ trace_t PM_TraceLine (vec3_t start, vec3_t end) { VectorClear(player_mins); VectorClear(player_maxs); - pmove.hullnum = 0; return PM_PlayerTrace(start, end); } diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index fb71fed1f..9c442f2bd 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -303,7 +303,7 @@ void QCBUILTIN PF_getsurfacenearpoint(progfuncs_t *prinst, struct globalvars_s * mvertex_t *v1, *v2; int edge; int e; - float bestdist = 10000000000000, dist; + float bestdist = 0x7fffffff, dist; int bestsurf = -1; world_t *w = prinst->parms->user; @@ -2094,7 +2094,6 @@ void QCBUILTIN PF_strftime (progfuncs_t *prinst, struct globalvars_s *pr_globals else tm = gmtime(&ctime); strftime(result, sizeof(result), in, tm); - Q_strncpyz(result, in, sizeof(result)); strtoupper(result); RETURN_TSTRING(result); diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index d5b59afb7..0d10abaf2 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -465,3 +465,12 @@ enum lightfield_e lfield_diffusescale=11, lfield_specularscale=12 }; +enum csqc_input_event +{ + /*devid is the player id (on android, its the multitouch id and is always present even in single player)*/ + CSIE_KEYDOWN = 0, /*syscode, unicode, devid*/ + CSIE_KEYUP = 1, /*syscode, unicode, devid*/ + CSIE_MOUSEDELTA = 2, /*x, y, devid*/ + CSIE_MOUSEABS = 3, /*x, y, devid*/ + CSIE_ACCELEROMETER = 4 /*x, y, z*/ +}; diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 8fcb233db..2ea758be7 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -52,10 +52,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PEXT_SPAWNSTATIC2 0x00400000 //Sends an entity delta instead of a baseline. #define PEXT_CUSTOMTEMPEFFECTS 0x00800000 //supports custom temp ents. #define PEXT_256PACKETENTITIES 0x01000000 //Client can recieve 256 packet entities. -//#define PEXT_NEVERUSED 0x02000000 //Client is able to cope with 64 players. Wow. +//#define PEXT_NEVERUSED 0x02000000 #define PEXT_SHOWPIC 0x04000000 #define PEXT_SETATTACHMENT 0x08000000 //md3 tags (needs networking, they need to lerp). -//#define PEXT_NEVERUSED 0x10000000 //retrieve a list of pk3s/pk3s/paks for downloading (with optional URL and crcs) +//#define PEXT_NEVERUSED 0x10000000 #define PEXT_CHUNKEDDOWNLOADS 0x20000000 //alternate file download method. Hopefully it'll give quadroupled download speed, especially on higher pings. #ifdef CSQC_DAT @@ -73,7 +73,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PEXT2_PRYDONCURSOR 0x00000001 #define PEXT2_VOICECHAT 0x00000002 #define PEXT2_SETANGLEDELTA 0x00000004 -//#define PEXT2_64PLAYERS 0x02000000 //Client is able to cope with 64 players. Wow. +#define PEXT2_REPLACEMENTDELTAS 0x00000008 +#define PEXT2_MAXPLAYERS 0x00000010 //Client is able to cope with more players than 32. abs max becomes 255, due to colormap issues. //#define PEXT2_PK3DOWNLOADS 0x10000000 //retrieve a list of pk3s/pk3s/paks for downloading (with optional URL and crcs) //ZQuake transparent protocol extensions. @@ -95,7 +96,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PROTOCOL_VERSION_FTE (('F'<<0) + ('T'<<8) + ('E'<<16) + ('X' << 24)) //fte extensions. #define PROTOCOL_VERSION_FTE2 (('F'<<0) + ('T'<<8) + ('E'<<16) + ('2' << 24)) //fte extensions. #define PROTOCOL_VERSION_HUFFMAN (('H'<<0) + ('U'<<8) + ('F'<<16) + ('F' << 24)) //packet compression -#define PROTOCOL_VERSION_VARLENGTH (('v'<<0) + ('l'<<8) + ('e'<<16) + ('n' << 24)) //packet compression +#define PROTOCOL_VERSION_VARLENGTH (('v'<<0) + ('l'<<8) + ('e'<<16) + ('n' << 24)) //variable length handshake +#define PROTOCOL_VERSION_FRAGMENT (('F'<<0) + ('R'<<8) + ('A'<<16) + ('G' << 24)) //supports fragmentation/packets larger than 1450 #define PROTOCOL_INFO_GUID (('G'<<0) + ('U'<<8) + ('I'<<16) + ('D' << 24)) //globally 'unique' client id info. @@ -276,6 +278,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svcfte_cgamepacket 83 #define svcfte_voicechat 84 #define svcfte_setangledelta 85 // [angle3] add this to the current viewangles +#define svcfte_updateentities 86 //fitz svcs @@ -513,6 +516,57 @@ enum clcq2_ops_e #endif +//first byte contains the stuff that's most likely to change constantly*/ +#define UF_FRAME (1u<<0) +#define UF_ORIGINXY (1u<<1) +#define UF_ORIGINZ (1u<<2) +#define UF_ANGLESXZ (1u<<4) +#define UF_ANGLESY (1u<<3) +#define UF_EFFECTS (1u<<5) +#define UF_PREDINFO (1u<<6) /*ent is predicted, probably a player*/ +#define UF_EXTEND1 (1u<<7) + +/*stuff which is common on ent spawning*/ +#define UF_RESET (1u<<8) +#define UF_16BIT (1u<<9) /*within this update, frame/skin/model is 16bit, not part of the deltaing itself*/ +#define UF_MODEL (1u<<10) +#define UF_SKIN (1u<<11) +#define UF_COLORMAP (1u<<12) +#define UF_SOLID (1u<<13) +#define UF_FLAGS (1u<<14) +#define UF_EXTEND2 (1u<<15) + +/*the rest is optional extensions*/ +#define UF_ALPHA (1u<<16) +#define UF_SCALE (1u<<17) +#define UF_ABSLIGHT (1u<<18) +#define UF_DRAWFLAGS (1u<<19) +#define UF_TAGINFO (1u<<20) +#define UF_LIGHT (1u<<21) +#define UF_EFFECTS2 (1u<<22) +#define UF_EXTEND3 (1u<<23) + +#define UF_COLORMOD (1u<<24) +#define UF_GLOWMOD (1u<<25) +#define UF_FATNESS (1u<<26) +#define UF_MODELINDEX2 (1u<<27) +#define UF_UNUSED4 (1u<<28) +#define UF_UNUSED3 (1u<<29) +#define UF_UNUSED2 (1u<<30) +#define UF_UNUSED1 (1u<<31) + +/*these flags are generally not deltaed as they're changing constantly*/ +#define UFP_FORWARD (1u<<0) +#define UFP_SIDE (1u<<1) +#define UFP_UP (1u<<2) +#define UFP_MOVETYPE (1u<<3) /*deltaed*/ +#define UFP_VELOCITYXY (1u<<4) +#define UFP_VELOCITYZ (1u<<5) +#define UFP_MSEC (1u<<6) + +#define UF_REMOVE UF_16BIT /*special flag, slightly more compact (we can reuse the 16bit flag as its not important)*/ + + #ifdef NQPROT @@ -716,7 +770,8 @@ enum { ========================================================== */ -#define MAX_CLIENTS 32 +#define MAX_CLIENTS 32 /*max 255, min 32*/ +#define QWMAX_CLIENTS 32 /*QW's standard max*/ #define UPDATE_BACKUP 64 // copies of entity_state_t to keep buffered // must be power of two @@ -738,7 +793,6 @@ typedef struct entity_state_s { unsigned short number; // edict index unsigned short modelindex; - unsigned int bitmask; // for dp ents, so lost state can be repeated in replacement packets. unsigned int flags; // nolerp, etc @@ -747,35 +801,51 @@ typedef struct entity_state_s vec3_t origin; vec3_t angles; #if defined(Q2CLIENT) || defined(Q2SERVER) - int renderfx; //q2 - vec3_t old_origin; //q2/q3 - qbyte modelindex3; //q2 - qbyte modelindex4; //q2 - qbyte sound; //q2 - qbyte event; //q2 - - unsigned short modelindex2; //q2 + union + { + struct + { + int renderfx; //q2 + vec3_t old_origin; //q2/q3 + qbyte modelindex3; //q2 + qbyte modelindex4; //q2 + qbyte sound; //q2 + qbyte event; //q2 + } q2; + struct + { + /*info to predict other players, so I don't get yelled at if fte were to stop supporting it*/ + qbyte pmovetype; + qbyte msec; + short movement[3]; + short velocity[3]; // 1/8th + } q1; + } u; #endif + unsigned short modelindex2; //q2/vweps unsigned short frame; + unsigned int skinnum; /*q2 needs 32 bits, which is quite impressive*/ + unsigned short colormap; - //pad 2 bytes qbyte glowsize; qbyte glowcolour; + qbyte scale; char fatness; - qbyte hexen2flags; qbyte abslight; - qbyte dpflags; - //pad + qbyte dpflags; qbyte colormod[3];//multiply this by 8 to read as 0 to 1... + + qbyte glowmod[3]; qbyte trans; qbyte lightstyle; qbyte lightpflags; unsigned short solid; +#define ES_SOLID_BSP 31 unsigned short light[4]; @@ -1278,10 +1348,8 @@ typedef struct q1usercmd_s #define RENDER_EXTERIORMODEL 8 #define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth #define RENDER_COLORMAPPED 32 -//#define RENDER_INDIRECT 64 -#define RENDER_SHADOW 65536 // cast shadow -#define RENDER_LIGHT 131072 // receive light -#define RENDER_TRANSPARENT 262144 // can't light during opaque stage +//#define RENDER_WORLDOBJECT 64 +//#define RENDER_COMPLEXANIMATION 128 //darkplaces protocols 5 to 7 use these // reset all entity fields (typically used if status changed) @@ -1347,7 +1415,7 @@ typedef struct q1usercmd_s #define E5_EXTEND3 (1<<23) // unused -#define E5_UNUSED24 (1<<24) +#define E5_GLOWMOD (1<<24) // unused #define E5_UNUSED25 (1<<25) // unused @@ -1363,7 +1431,7 @@ typedef struct q1usercmd_s // bits2 > 0 #define E5_EXTEND4 (1<<31) -#define E5_ALLUNUSED (E5_UNUSED24|E5_UNUSED25|E5_UNUSED26|E5_UNUSED27|E5_UNUSED28|E5_UNUSED29|E5_UNUSED30) +#define E5_ALLUNUSED (E5_UNUSED25|E5_UNUSED26|E5_UNUSED27|E5_UNUSED28|E5_UNUSED29|E5_UNUSED30) #define FITZB_LARGEMODEL (1<<0) // modelindex is short instead of byte #define FITZB_LARGEFRAME (1<<1) // frame is short instead of byte diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index db3b98121..bea074343 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -66,7 +66,7 @@ enum vec3_t rht_start, rht_end; static int Q1BSP_RecursiveHullTrace (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) { - dclipnode_t *node; + mclipnode_t *node; mplane_t *plane; float t1, t2; vec3_t mid; @@ -152,7 +152,6 @@ reenter: if (rht != rht_solid) return rht; - trace->fraction = midf; if (side) { /*we impacted the back of the node, so flip the plane*/ @@ -167,6 +166,13 @@ reenter: VectorCopy(plane->normal, trace->plane.normal); midf = (t1 - DIST_EPSILON) / (t1 - t2); } + + t1 = DotProduct (trace->plane.normal, rht_start) - trace->plane.dist; + t2 = DotProduct (trace->plane.normal, rht_end) - trace->plane.dist; + midf = (t1 - DIST_EPSILON) / (t1 - t2); + + + trace->fraction = midf; VectorCopy (mid, trace->endpos); VectorInterpolate(rht_start, midf, rht_end, trace->endpos); @@ -396,11 +402,11 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3] if (size[0] < 3) // Point hull = &model->hulls[0]; - else if (size[0] <= 8 && model->hulls[4].available) + else if (size[0] <= 8.1 && model->hulls[4].available) hull = &model->hulls[4]; //Pentacles - else if (size[0] <= 32 && size[2] <= 28) // Half Player + else if (size[0] <= 32.1 && size[2] <= 28.1) // Half Player hull = &model->hulls[3]; - else if (size[0] <= 32) // Full Player + else if (size[0] <= 32.1) // Full Player hull = &model->hulls[1]; else // Golumn hull = &model->hulls[5]; @@ -409,9 +415,9 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3] { if (size[0] < 3 || !model->hulls[1].available) hull = &model->hulls[0]; - else if (size[0] <= 32) + else if (size[0] <= 32.1) { - if (size[2] < 54 && model->hulls[3].available) + if (size[2] < 54.1 && model->hulls[3].available) hull = &model->hulls[3]; // 32x32x36 (half-life's crouch) else hull = &model->hulls[1]; diff --git a/engine/common/world.h b/engine/common/world.h index 2fc20428b..5e9b36d20 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -169,6 +169,8 @@ struct world_s int lastcheck; // used by PF_checkclient double lastchecktime; // for monster ai + float defaultgravityscale; //0 in QW, 1 for anything else (inc csqc) + /*antilag*/ float lagentsfrac; laggedentinfo_t *lagents; diff --git a/engine/common/zone.c b/engine/common/zone.c index 023be6842..a4209f585 100644 --- a/engine/common/zone.c +++ b/engine/common/zone.c @@ -1535,6 +1535,8 @@ void *Hunk_TempAllocMore (int size) #if TEMPDEBUG>0 hnktemps_t *nt; nt = (hnktemps_t*)malloc(size + sizeof(hnktemps_t) + TEMPDEBUG*2); + if (!nt) + return NULL; nt->next = hnktemps; nt->len = size; hnktemps = nt; @@ -1547,6 +1549,8 @@ void *Hunk_TempAllocMore (int size) #else hnktemps_t *nt; nt = (hnktemps_t*)malloc(size + sizeof(hnktemps_t)); + if (!nt) + return NULL; nt->next = hnktemps; hnktemps = nt; buf = (void *)(nt+1); diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index ecffefc18..e8a1f09f0 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1181,7 +1181,7 @@ static void D3D9_SetupViewPort(void) fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; - if (r_waterwarp.value<0 && r_viewleaf->contents <= Q1CONTENTS_WATER) + if (r_waterwarp.value<0 && r_viewcontents & FTECONTENTS_FLUID) { fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index 0b8da4524..c9f641a51 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -139,7 +139,6 @@ Global {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|x64.ActiveCfg = GLDebug|x64 {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|x64.Build.0 = GLDebug|x64 {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|Win32.Build.0 = GLDebug|Win32 {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|x64.ActiveCfg = GLDebug|x64 {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|x64.Build.0 = GLDebug|x64 {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLRelease|Win32.ActiveCfg = GLRelease|Win32 diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 0ed2a5950..32d11b7ed 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -699,6 +699,7 @@ GenerateDebugInformation="true" GenerateMapFile="true" SubSystem="2" + LargeAddressAware="2" TargetMachine="1" /> = 5) { - public void run() + /*Requires API level 5+ (android 2.0+)*/ + queueEvent(new Runnable() { - switch(act) + private void domove() { - case MotionEvent.ACTION_DOWN: - FTEDroidEngine.motion(1, x, y); - break; - case MotionEvent.ACTION_UP: - FTEDroidEngine.motion(2, x, y); - break; - case MotionEvent.ACTION_MOVE: - FTEDroidEngine.motion(0, x, y); - break; + final int pointerCount = event.getPointerCount(); + int i; + for (i = 0; i < pointerCount; i++) + FTEDroidEngine.motion(0, event.getPointerId(i), event.getX(i), event.getY(i)); } - } - }); + + public void run() + { + int id; + float x, y; + final int act = event.getAction(); + + domove(); + + switch(act & event.ACTION_MASK) + { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT); + x = event.getX(id); + y = event.getY(id); + id = event.getPointerId(id); + FTEDroidEngine.motion(1, id, x, y); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT); + x = event.getX(id); + y = event.getY(id); + id = event.getPointerId(id); + FTEDroidEngine.motion(2, id, x, y); + break; + case MotionEvent.ACTION_MOVE: + break; + } + } + }); + } + else + { + queueEvent(new Runnable() + { + public void run() + { + final int act = event.getAction(); + final float x = event.getX(); + final float y = event.getY(); + + FTEDroidEngine.motion(0, 0, x, y); + + switch(act) + { + case MotionEvent.ACTION_DOWN: + FTEDroidEngine.motion(1, 0, x, y); + break; + case MotionEvent.ACTION_UP: + FTEDroidEngine.motion(2, 0, x, y); + break; + case MotionEvent.ACTION_MOVE: + break; + } + } + }); + } return true; } /* @@ -237,6 +284,8 @@ public class FTEDroidActivity extends Activity return '\r'; case KeyEvent.KEYCODE_BACK: return 27; + case KeyEvent.KEYCODE_MENU: + return 241; case KeyEvent.KEYCODE_DEL: return 127; default: @@ -266,47 +315,44 @@ public class FTEDroidActivity extends Activity { } - private float gx,gy,gz; public void onSensorChanged(final SensorEvent event) { - // alpha is calculated as t / (t + dT) - // with t, the low-pass filter's time-constant - // and dT, the event delivery rate - - final float alpha = 0.8f; - - gx = alpha * gx + (1 - alpha) * event.values[0]; - gy = alpha * gy + (1 - alpha) * event.values[1]; - gz = alpha * gz + (1 - alpha) * event.values[2]; - - sendAccelerometer(event.values[0] - gx, event.values[1] - gy, event.values[2] - gz); - + acc_x = event.values[0]; + acc_y = event.values[1]; + acc_z = event.values[2]; } } @Override public void onCreate(Bundle savedInstanceState) { - //go full-screen + android.util.Log.i("FTEDroid", "onCreate"); + //go full-screen getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); - + + android.util.Log.i("FTEDroid", "create view"); view = new FTEView(this); setContentView(view); // setContentView(R.layout.main); + android.util.Log.i("FTEDroid", "init sensor manager"); sensorman = (SensorManager)getSystemService(SENSOR_SERVICE); - sensoracc = sensorman.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + android.util.Log.i("FTEDroid", "init accelerometer"); + if (sensorman != null) + sensoracc = sensorman.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + android.util.Log.i("FTEDroid", "done"); } @Override protected void onResume() { super.onResume(); - sensorman.registerListener((SensorEventListener)view, sensoracc, SensorManager.SENSOR_DELAY_GAME); + if (sensorman != null && sensoracc != null) + sensorman.registerListener((SensorEventListener)view, sensoracc, SensorManager.SENSOR_DELAY_GAME); view.resume(); } @@ -314,14 +360,16 @@ public class FTEDroidActivity extends Activity @Override protected void onStop() { - sensorman.unregisterListener(view); + if (sensorman != null && sensoracc != null) + sensorman.unregisterListener(view); super.onStop(); } @Override protected void onPause() { - sensorman.unregisterListener(view); + if (sensorman != null && sensoracc != null) + sensorman.unregisterListener(view); super.onPause(); } } diff --git a/engine/droid/src/com/fteqw/FTEDroidEngine.java b/engine/droid/src/com/fteqw/FTEDroidEngine.java index 9174c8885..a946c87a8 100644 --- a/engine/droid/src/com/fteqw/FTEDroidEngine.java +++ b/engine/droid/src/com/fteqw/FTEDroidEngine.java @@ -3,10 +3,9 @@ package com.fteqw; public class FTEDroidEngine { public static native void init(int w, int h, String basedir); /* init/reinit */ - public static native void frame(); + public static native void frame(float ax, float ay, float az); public static native void keypress(int down, int qkey, int unicode); - public static native void motion(int act, float x, float y); - public static native void accelerometer(float x, float y, float z); + public static native void motion(int act, int pointerid, float x, float y); public static native int paintaudio(byte[] stream, int len); static diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index f62faf8cb..8d3ea2089 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -170,10 +170,10 @@ void GL_GAliasFlushSkinCache(void) skincolourmapped.numbuckets = 0; } -static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, entity_t *e) +static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, entity_t *e, texnums_t **forcedtex) { galiasskin_t *skins; - texnums_t *texnums; + shader_t *shader; int frame; unsigned int subframe; extern int cl_playerindex; //so I don't have to strcmp @@ -181,14 +181,15 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, unsigned int tc, bc, pc; qboolean forced; + *forcedtex = NULL; + if (e->skinnum >= 100 && e->skinnum < 110) { shader_t *s; s = R_RegisterSkin(va("gfx/skin%d.lmp", e->skinnum), NULL); if (!TEXVALID(s->defaulttextures.base)) s->defaulttextures.base = R_LoadHiResTexture(va("gfx/skin%d.lmp", e->skinnum), NULL, 0); - s->defaulttextures.shader = s; - return &s->defaulttextures; + return s; } @@ -258,28 +259,30 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, if (!inf->numskins) { + /*model has no skins*/ skins = NULL; subframe = 0; - texnums = NULL; + shader = NULL; } else { skins = (galiasskin_t*)((char *)inf + inf->ofsskins); - if (!skins->texnums) + if (e->skinnum >= 0 && e->skinnum < inf->numskins) + skins += e->skinnum; + + if (!skins->numshaders) { + /*model has a skin, but has no framegroups*/ skins = NULL; subframe = 0; - texnums = NULL; + shader = NULL; } else { - if (e->skinnum >= 0 && e->skinnum < inf->numskins) - skins += e->skinnum; - subframe = cl.time*skins->skinspeed; - subframe = subframe%skins->texnums; + subframe = subframe%skins->numshaders; - texnums = (texnums_t*)((char *)skins + skins->ofstexnums + subframe*sizeof(texnums_t)); + shader = *(shader_t**)((char *)skins + skins->ofsshaders + subframe*sizeof(shader_t*)); } } @@ -287,12 +290,14 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, { if (cm->tcolour == tc && cm->bcolour == bc && cm->skinnum == e->skinnum && cm->subframe == subframe && cm->pclass == pc) { - return &cm->texnum; + *forcedtex = &cm->texnum; + return shader; } } //colourmap isn't present yet. cm = BZ_Malloc(sizeof(*cm)); + *forcedtex = &cm->texnum; Q_strncpyz(cm->name, skinname, sizeof(cm->name)); Hash_Add(&skincolourmapped, cm->name, cm, &cm->bucket); cm->tcolour = tc; @@ -304,10 +309,11 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, cm->texnum.base = r_nulltex; cm->texnum.loweroverlay = r_nulltex; cm->texnum.upperoverlay = r_nulltex; - cm->texnum.shader = texnums?texnums->shader:R_RegisterSkin(skinname, NULL); - if (!texnums) - { //load just the skin + if (!shader) + { //model has no shaders, so just the skin directly + shader = R_RegisterSkin(skinname, NULL); + if (e->scoreboard && e->scoreboard->skin) { if (cls.protocol == CP_QUAKE2) @@ -318,7 +324,7 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, inwidth = e->scoreboard->skin->width; inheight = e->scoreboard->skin->height; cm->texnum.base = R_LoadTexture32(e->scoreboard->skin->name, inwidth, inheight, (unsigned int*)original, IF_NOALPHA|IF_NOGAMMA); - return &cm->texnum; + return shader; } } else @@ -329,39 +335,38 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, inwidth = e->scoreboard->skin->width; inheight = e->scoreboard->skin->height; cm->texnum.base = R_LoadTexture8(e->scoreboard->skin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1); - return &cm->texnum; + return shader; } } if (TEXVALID(e->scoreboard->skin->tex_base)) { - texnums = &cm->texnum; - texnums->loweroverlay = e->scoreboard->skin->tex_lower; - texnums->upperoverlay = e->scoreboard->skin->tex_upper; - texnums->base = e->scoreboard->skin->tex_base; - return texnums; + cm->texnum.loweroverlay = e->scoreboard->skin->tex_lower; + cm->texnum.upperoverlay = e->scoreboard->skin->tex_upper; + cm->texnum.base = e->scoreboard->skin->tex_base; + return shader; } cm->texnum.base = R_LoadHiResTexture(e->scoreboard->skin->name, "skins", IF_NOALPHA); - return &cm->texnum; + return shader; } - return NULL; + return shader; } - cm->texnum.bump = texnums[cm->skinnum].bump; //can't colour bumpmapping - if (cls.protocol != CP_QUAKE2 && ((!texnums || (model==cl.model_precache[cl_playerindex] || model==cl.model_precache_vwep[0])) && e->scoreboard && e->scoreboard->skin)) + cm->texnum.bump = shader->defaulttextures.bump; //can't colour bumpmapping + if (cls.protocol != CP_QUAKE2 && ((model==cl.model_precache[cl_playerindex] || model==cl.model_precache_vwep[0]) && e->scoreboard && e->scoreboard->skin)) { + /*q1 only reskins the player model, not gibbed heads (which have the same colourmap)*/ original = Skin_Cache8(e->scoreboard->skin); inwidth = e->scoreboard->skin->width; inheight = e->scoreboard->skin->height; if (!original && TEXVALID(e->scoreboard->skin->tex_base)) { - texnums = &cm->texnum; - texnums->loweroverlay = e->scoreboard->skin->tex_lower; - texnums->upperoverlay = e->scoreboard->skin->tex_upper; - texnums->base = e->scoreboard->skin->tex_base; - return texnums; + cm->texnum.loweroverlay = e->scoreboard->skin->tex_lower; + cm->texnum.upperoverlay = e->scoreboard->skin->tex_upper; + cm->texnum.base = e->scoreboard->skin->tex_base; + return shader; } } else @@ -398,10 +403,8 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, unsigned scaled_width, scaled_height; qbyte *inrow; - texnums = &cm->texnum; - - texnums->base = r_nulltex; - texnums->fullbright = r_nulltex; + cm->texnum.base = r_nulltex; + cm->texnum.fullbright = r_nulltex; scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512; scaled_height = gl_max_size.value < 512 ? gl_max_size.value : 512; @@ -514,12 +517,12 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, } if (qrenderer == QR_OPENGL) { - texnums->base = R_AllocNewTexture(cm->name, scaled_width, scaled_height); - R_Upload(texnums->base, cm->name, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, NULL, scaled_width, scaled_height, IF_NOMIPMAP); + cm->texnum.base = R_AllocNewTexture(cm->name, scaled_width, scaled_height); + R_Upload(cm->texnum.base, cm->name, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, NULL, scaled_width, scaled_height, IF_NOMIPMAP); } else { - texnums->base = R_LoadTexture(cm->name, scaled_width, scaled_height, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, 0); + cm->texnum.base = R_LoadTexture(cm->name, scaled_width, scaled_height, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, 0); } if (!h2playertranslations) @@ -540,30 +543,21 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, } if (qrenderer == QR_OPENGL) { - texnums->fullbright = R_AllocNewTexture(cm->name, scaled_width, scaled_height); - R_Upload(texnums->fullbright, cm->name, TF_RGBA32, pixels, NULL, scaled_width, scaled_height, IF_NOMIPMAP); + cm->texnum.fullbright = R_AllocNewTexture(cm->name, scaled_width, scaled_height); + R_Upload(cm->texnum.fullbright, cm->name, TF_RGBA32, pixels, NULL, scaled_width, scaled_height, IF_NOMIPMAP); } else { - texnums->fullbright = R_LoadTexture(cm->name, scaled_width, scaled_height, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, 0); + cm->texnum.fullbright = R_LoadTexture(cm->name, scaled_width, scaled_height, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, 0); } } } else { - skins = (galiasskin_t*)((char *)inf + inf->ofsskins); - if (e->skinnum >= 0 && e->skinnum < inf->numskins) - skins += e->skinnum; - - if (!inf->numskins || !skins->texnums) - return NULL; - - frame = cl.time*skins->skinspeed; - frame = frame%skins->texnums; - texnums = (texnums_t*)((char *)skins + skins->ofstexnums + frame*sizeof(texnums_t)); - memcpy(&cm->texnum, texnums, sizeof(cm->texnum)); + /*model has no original skin info and thus cannot be reskinned, copy over the default textures so that the skincache doesn't break things when it gets reused*/ + cm->texnum = shader->defaulttextures; } - return &cm->texnum; + return shader; } } @@ -580,14 +574,12 @@ static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, return NULL; } - if (!skins->texnums) + if (!skins->numshaders) return NULL; frame = cl.time*skins->skinspeed; - frame = frame%skins->texnums; - texnums = (texnums_t*)((char *)skins + skins->ofstexnums + frame*sizeof(texnums_t)); - - return texnums; + frame = frame%skins->numshaders; + return *(shader_t**)((char *)skins + skins->ofsshaders + frame*sizeof(shader_t*)); } #if defined(RTLIGHTS) @@ -958,7 +950,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches) { galiasinfo_t *inf; model_t *clmodel; - shader_t *shader; + shader_t *shader, *regshader; batch_t *b; int surfnum; shadersort_t sort; @@ -1006,10 +998,11 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches) for(surfnum=0; inf; ((inf->nextsurf)?(inf = (galiasinfo_t*)((char *)inf + inf->nextsurf)):(inf=NULL)), surfnum++) { - skin = GL_ChooseSkin(inf, clmodel, surfnum, e); - if (!skin) + regshader = GL_ChooseSkin(inf, clmodel, surfnum, e, &skin); + if (!regshader) continue; - shader = e->forcedshader?e->forcedshader:skin->shader; + skin = skin?skin:®shader->defaulttextures; + shader = e->forcedshader?e->forcedshader:regshader; if (shader) { b = BE_GetTempBatch(); diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 9b459fbcc..709787e86 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -727,7 +727,10 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass, qboolea t = shaderstate.curdeluxmap; break; case T_GEN_DIFFUSE: - t = (shaderstate.curtexnums && TEXVALID(shaderstate.curtexnums->base))?shaderstate.curtexnums->base:missing_texture; + if (shaderstate.curtexnums && TEXVALID(shaderstate.curtexnums->base)) + t = shaderstate.curtexnums->base; + else + t = missing_texture; break; case T_GEN_NORMALMAP: t = shaderstate.curtexnums?shaderstate.curtexnums->bump:r_nulltex; /*FIXME: nulltex is not correct*/ @@ -3138,7 +3141,9 @@ void GLBE_SubmitBatch(batch_t *batch) if (lm < 0) { - shaderstate.curlightmap = r_nulltex; + extern texid_t r_whiteimage; + /*FIXME: this doesn't compensate for overbrighting*/ + shaderstate.curlightmap = r_whiteimage; shaderstate.curdeluxmap = r_nulltex; } else diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index bf6131909..f5f32582f 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -1150,6 +1150,7 @@ void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigne } } } + switch((flags & IF_TEXTYPE) >> IF_TEXTYPESHIFT) { case 0: diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 6d30b0e71..059e505a6 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -817,7 +817,8 @@ static texid_t Font_LoadFallbackConchars(void) int width, height; unsigned int i; qbyte *lump; - lump = ReadTargaFile(default_conchar, sizeof(default_conchar), &width, &height, false); + qboolean hasalpha; + lump = ReadTargaFile(default_conchar, sizeof(default_conchar), &width, &height, &hasalpha, false); if (!lump) Sys_Error("Corrupt internal drawchars"); /*convert greyscale to alpha*/ diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index c53ea70ef..a34fed7c5 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -3503,6 +3503,7 @@ void * RMod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum, Q_strncatz(name, va("_%i.tga", framenum), sizeof(name)); pspriteframe->shader = R_RegisterShader(name, "{\n" + "program defaultsprite\n" "{\n" "map $diffuse\n" "alphafunc ge128\n" diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 1af0aa264..d72da27cd 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -229,8 +229,6 @@ typedef struct texnums_s { texid_t loweroverlay; texid_t specular; texid_t fullbright; - - struct shader_s *shader; //fixme: remove... } texnums_t; typedef struct vboarray_s diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 370985d1d..f7e1c9bfc 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -63,6 +63,7 @@ vec3_t r_origin; // refdef_t r_refdef; +unsigned int r_viewcontents; mleaf_t *r_viewleaf, *r_oldviewleaf; mleaf_t *r_viewleaf2, *r_oldviewleaf2; int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; @@ -375,7 +376,7 @@ void R_SetupGL (void) fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; - if (r_waterwarp.value<0 && r_viewleaf && r_viewleaf->contents <= Q1CONTENTS_WATER) + if (r_waterwarp.value<0 && r_viewleaf && (r_viewcontents & FTECONTENTS_FLUID)) { fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); @@ -762,7 +763,7 @@ void R_Clear (void) #if 0 void GLR_SetupFog (void) { - if (r_viewleaf)// && r_viewleaf->contents != CONTENTS_EMPTY) + if (r_viewleaf)// && r_viewcontents != FTECONTENTS_EMPTY) { // static fogcolour; float fogcol[4]={0}; @@ -771,7 +772,7 @@ void GLR_SetupFog (void) fogperc=0; fogdist=512; - switch(r_viewleaf->contents) + switch(r_viewcontents) { case FTECONTENTS_WATER: fogcol[0] = 64/255.0; @@ -1150,7 +1151,7 @@ void GLR_RenderView (void) // SCENE POST PROCESSING // we check if we need to use any shaders - currently it's just waterwarp - if ((r_waterwarp.value>0 && r_viewleaf && r_viewleaf->contents <= Q1CONTENTS_WATER)) + if ((r_waterwarp.value>0 && r_viewleaf && (r_viewcontents & FTECONTENTS_WATER))) { if (scenepp_waterwarp) { diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 69c34ede2..c4d8d06c8 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -37,7 +37,7 @@ extern LPDIRECT3DDEVICE9 pD3DDev9; #endif extern texid_t missing_texture; -static texid_t r_whiteimage; +texid_t r_whiteimage; static qboolean shader_reload_needed; static qboolean shader_rescan_needed; @@ -1074,10 +1074,12 @@ struct sbuiltin_s "uniform sampler2D s_t0;\n" "in vec2 tc;\n" "varying vec4 vc;\n" + "uniform vec4 e_colourident;\n" "void main ()\n" "{\n" " gl_FragColor = fog4blend(texture2D(s_t0, tc) * vc);\n" + " gl_FragColor = gl_FragColor * e_colourident;\n" "}\n" "#endif\n" }, @@ -1102,10 +1104,12 @@ struct sbuiltin_s "uniform sampler2D s_t0;\n" "in vec2 tc;\n" "varying vec4 vc;\n" + "uniform vec4 e_colourident;\n" "void main ()\n" "{\n" " gl_FragColor = fog4additive(texture2D(s_t0, tc) * vc);\n" + " gl_FragColor = gl_FragColor * e_colourident;\n" "}\n" "#endif\n" }, @@ -1186,6 +1190,7 @@ struct sbuiltin_s "#endif\n" "varying vec2 tc, lm;\n" "uniform vec4 e_lmscale;\n" + "uniform vec4 e_colourident;\n" "#ifdef OFFSETMAPPING\n" "#include \"sys/offsetmapping.h\"\n" @@ -1204,6 +1209,7 @@ struct sbuiltin_s "#ifdef FOG\n" "gl_FragColor = fog4(gl_FragColor);\n" "#endif\n" + "gl_FragColor = gl_FragColor * e_colourident;\n" "}\n" "#endif\n" }, @@ -4696,6 +4702,8 @@ void Shader_UpdateRegistration (void) void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) { + if (!tn) + tn = &shader->defaulttextures; if (!TEXVALID(shader->defaulttextures.base)) { /*dlights/realtime lighting needs some stuff*/ diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 46685c6d9..8cfbcd4da 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -237,7 +237,7 @@ static void SHM_Shadow_Cache_Leaf(mleaf_t *leaf) sh_shmesh->litleaves[i>>3] |= 1<<(i&7); } -static void SH_FreeShadowMesh(shadowmesh_t *sm) +void SH_FreeShadowMesh(shadowmesh_t *sm) { unsigned int i; for (i = 0; i < sm->numsurftextures; i++) diff --git a/engine/gl/glmod_doom.c b/engine/gl/glmod_doom.c index cbbd0b5c2..6d20b5bcc 100644 --- a/engine/gl/glmod_doom.c +++ b/engine/gl/glmod_doom.c @@ -768,8 +768,8 @@ static void GLR_DrawWall(int texnum, int s, int t, float x1, float y1, float fro } if (mesh->numindexes+6 > tex->maxindicies) { - tex->maxindicies = mesh->numvertexes+6; - mesh->indexes = BZ_Realloc(mesh->colors4b_array, sizeof(*mesh->indexes) * tex->maxindicies); + tex->maxindicies = mesh->numindexes+6; + mesh->indexes = BZ_Realloc(mesh->indexes, sizeof(*mesh->indexes) * tex->maxindicies); } col = colour4b * 0x01010101; @@ -783,17 +783,17 @@ static void GLR_DrawWall(int texnum, int s, int t, float x1, float y1, float fro VectorSet(mesh->xyz_array[mesh->numvertexes+2], x2, y2, backfloor); VectorSet(mesh->xyz_array[mesh->numvertexes+3], x2, y2, frontfloor); Vector2Set(mesh->st_array[mesh->numvertexes+0], s1, t2); - Vector2Set(mesh->st_array[mesh->numvertexes+0], s1, t1); - Vector2Set(mesh->st_array[mesh->numvertexes+0], s2, t1); - Vector2Set(mesh->st_array[mesh->numvertexes+0], s2, t2); + Vector2Set(mesh->st_array[mesh->numvertexes+1], s1, t1); + Vector2Set(mesh->st_array[mesh->numvertexes+2], s2, t1); + Vector2Set(mesh->st_array[mesh->numvertexes+2], s2, t2); - mesh->indexes[mesh->numindexes+0] = mesh->numvertexes; - mesh->indexes[mesh->numindexes+1] = mesh->numvertexes; - mesh->indexes[mesh->numindexes+2] = mesh->numvertexes; + mesh->indexes[mesh->numindexes+0] = mesh->numvertexes+0; + mesh->indexes[mesh->numindexes+1] = mesh->numvertexes+1; + mesh->indexes[mesh->numindexes+2] = mesh->numvertexes+2; - mesh->indexes[mesh->numindexes+0] = mesh->numvertexes; - mesh->indexes[mesh->numindexes+2] = mesh->numvertexes; - mesh->indexes[mesh->numindexes+3] = mesh->numvertexes; + mesh->indexes[mesh->numindexes+3] = mesh->numvertexes+0; + mesh->indexes[mesh->numindexes+4] = mesh->numvertexes+2; + mesh->indexes[mesh->numindexes+5] = mesh->numvertexes+3; mesh->numvertexes += 4; mesh->numindexes += 6; @@ -1024,11 +1024,30 @@ static void GLR_RecursiveDoomNode(unsigned int node) void GLR_DoomWorld(void) { + int texnum; + gldoomtexture_t *t; if (!nodel || !nodec) return; //err... buggy + for (texnum = 0; texnum < numgldoomtextures; texnum++) //a hash table might be a good plan. + { + t = &gldoomtextures[texnum]; + t->mesh.numindexes = 0; + t->mesh.numvertexes = 0; + } r_visframecount++; GLR_RecursiveDoomNode(nodec-1); + + memset(cl.worldmodel->batches, 0, sizeof(cl.worldmodel->batches)); + for (texnum = 0; texnum < numgldoomtextures; texnum++) //a hash table might be a good plan. + { + t = &gldoomtextures[texnum]; + if (t->mesh.numindexes) + { + t->batch.next = cl.worldmodel->batches[t->shader->sort]; + cl.worldmodel->batches[t->shader->sort] = &t->batch; + } + } } @@ -1517,6 +1536,7 @@ static int Doom_LoadPatch(char *name) // texnum = numgldoomtextures; gldoomtextures = BZ_Realloc(gldoomtextures, sizeof(*gldoomtextures)*((numgldoomtextures+16)&~15)); + memset(gldoomtextures + numgldoomtextures, 0, sizeof(gldoomtextures[numgldoomtextures])); numgldoomtextures++; strncpy(gldoomtextures[texnum].name, name, 8); @@ -2037,6 +2057,8 @@ qboolean Mod_LoadDoomLevel(model_t *mod) mod->needload = false; mod->fromgame = fg_doom; + mod->type = mod_brush; + mod->nodes = (void*)0x1; CleanWalls(sidedefsl); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 57eb6731b..7de184fc0 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -257,6 +257,7 @@ extern vec3_t r_origin; // screen size info // extern refdef_t r_refdef; +extern unsigned int r_viewcontents; extern mleaf_t *r_viewleaf, *r_oldviewleaf; extern mleaf_t *r_viewleaf2, *r_oldviewleaf2; extern int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; //q2 diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 5b8c13e45..0f896d05a 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -515,6 +515,7 @@ void D3DBE_BaseEntTextures(void); void Sh_PreGenerateLights(void); //Draws lights, called from the backend void Sh_DrawLights(qbyte *vis, batch_t **mbatches); +void SH_FreeShadowMesh(struct shadowmesh_s *sm); void Sh_Shutdown(void); //Draws the depth of ents in the world near the current light void BE_BaseEntShadowDepth(void); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 8e4d6d127..d6eb973a4 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -1577,6 +1577,10 @@ void Q_InitProgs(void) sv.world.max_edicts = MAX_EDICTS; sv.world.edict_size = PR_InitEnts(svprogfuncs, sv.world.max_edicts); + if (progstype == PROG_QW) + sv.world.defaultgravityscale = 0; + else + sv.world.defaultgravityscale = 1; SV_RegisterH2CustomTents(); @@ -5607,18 +5611,7 @@ lh_extension_t *checkfteextensioncl(int mask, char *name) //true if the cient ex lh_extension_t *checkfteextensionsv(char *name) //true if the server supports an protocol extension. { - int i; - - for (i = 0; i < 32; i++) - { - if (svs.fteprotocolextensions & (1<v->velocity, pmove.velocity); VectorCopy(ent->v->maxs, player_maxs); VectorCopy(ent->v->mins, player_mins); - pmove.hullnum = SV_HullNumForPlayer(ent->xv->hull, ent->v->mins, ent->v->maxs); pmove.numphysent = 1; pmove.physents[0].model = sv.world.worldmodel; @@ -9262,7 +9254,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs //VM_SV_getextresponse, // #624 string getextresponse(void) - {"sprintf", PF_sprintf, 0, 0, 0, 627, "string(...)" STUB}, + {"sprintf", PF_sprintf, 0, 0, 0, 627, "string(...)"}, // {"getsurfacenumpoints",VM_getsurfacenumtriangles,0,0, 0, 628, "float(entity e, float s)" STUB}, // {"getsurfacepoint",VM_getsurfacenumtriangles,0,0, 0, 629, "vector(entity e, float s, float n)" STUB}, @@ -9369,10 +9361,10 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any if (pr_builtin[BuiltinList[i].ebfsnum] == PF_Fixme && builtincount[BuiltinList[i].ebfsnum] == (BuiltinList[i].obsolete?0:1)) { pr_builtin[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc; - Con_DPrintf("Enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum); +// Con_DPrintf("Enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum); } - else if (pr_builtin[i] != BuiltinList[i].bifunc) - Con_DPrintf("Not enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum); +// else if (pr_builtin[i] != BuiltinList[i].bifunc) +// Con_DPrintf("Not enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum); } } } @@ -9486,7 +9478,7 @@ void PR_SVExtensionList_f(void) if (i < 32) { - if (!(svs.fteprotocolextensions & (1<mapname, sv.name)) - break; + cache = svs.levcache; + while(cache) + { + if (!strcmp(cache->mapname, sv.name)) + break; - cache = cache->next; + cache = cache->next; + } + if (!cache) //not visited yet. Let us know that we went there. + { + cache = Z_Malloc(sizeof(levelcache_t)+strlen(sv.name)+1); + cache->mapname = (char *)(cache+1); + strcpy(cache->mapname, sv.name); + + cache->gametype = svs.gametype; + cache->next = svs.levcache; + svs.levcache = cache; + } } - if (!cache) //not visited yet. Let us know that we went there. - { - cache = Z_Malloc(sizeof(levelcache_t)+strlen(sv.name)+1); - cache->mapname = (char *)(cache+1); - strcpy(cache->mapname, sv.name); - - cache->gametype = svs.gametype; - cache->next = svs.levcache; - svs.levcache = cache; - } - if (savedir) - Q_snprintfz (name, sizeof(name), "saves/%s/%s", savedir, cache->mapname); + Q_snprintfz (name, sizeof(name), "saves/%s/%s", savedir, sv.name); else - Q_snprintfz (name, sizeof(name), "saves/%s", cache->mapname); + Q_snprintfz (name, sizeof(name), "saves/%s", sv.name); COM_DefaultExtension (name, ".lvc", sizeof(name)); FS_CreatePath(name, FS_GAMEONLY); @@ -859,7 +861,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame) VFS_PRINTF (f, "%s\n", comment); if (!dontharmgame) { - for (cl = svs.clients, clnum=0; clnum < MAX_CLIENTS; cl++,clnum++)//fake dropping + for (cl = svs.clients, clnum=0; clnum < sv.allocated_client_slots; cl++,clnum++)//fake dropping { if (cl->state < cs_spawned && !cl->istobeloaded) //don't drop if they are still connecting { diff --git a/engine/server/server.h b/engine/server/server.h index 32c602457..9ad681343 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -76,7 +76,7 @@ typedef struct laggedpacket_s double time; struct laggedpacket_s *next; int length; - unsigned char data[MAX_QWMSGLEN]; + unsigned char data[MAX_QWMSGLEN+10]; } laggedpacket_t; typedef struct @@ -284,14 +284,16 @@ typedef struct // received from client // reply - double senttime; - float ping_time; - int move_msecs; - int packetsizein; - int packetsizeout; - vec3_t playerpositions[MAX_CLIENTS]; - qboolean playerpresent[MAX_CLIENTS]; - packet_entities_t entities; //must come last (mvd states are bigger) + double senttime; //time we sent this frame to the client, for ping calcs + int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale + float ping_time; //how long it took for the client to ack it, may be negativ + int move_msecs; // + int packetsizein; //amount of data received for this frame + int packetsizeout; //amount of data that was sent in the frame + vec3_t playerpositions[MAX_CLIENTS]; //where each player was in this frame, for antilag + qboolean playerpresent[MAX_CLIENTS]; //whether the player was actually present + packet_entities_t entities; //package containing entity states that were sent in this frame, for deltaing + unsigned int *resendentbits; //the bits of each entity that were sent in this frame } client_frame_t; #ifdef Q2SERVER @@ -351,6 +353,7 @@ typedef struct client_s usercmd_t lastcmd; // for filling in big drops and partial predictions double localtime; // of last message qboolean jump_held; + qboolean lockangles; //mod is spamming angle changes, don't do relative changes float maxspeed; // localized maxspeed float entgravity; // localized ent gravity @@ -417,6 +420,8 @@ typedef struct client_s q3client_frame_t *q3frames; #endif } frameunion; + packet_entities_t sentents; + unsigned int *pendingentbits; char downloadfn[MAX_QPATH]; vfsfile_t *download; // file being downloaded @@ -469,7 +474,7 @@ typedef struct client_s netchan_t netchan; qboolean isindependant; - int lastsequence_acknoledged; + int lastsequence_acknowledged; #ifdef VOICECHAT unsigned int voice_read; /*place in ring*/ @@ -507,7 +512,7 @@ typedef struct client_s unsigned long fteprotocolextensions2; #endif unsigned long zquake_extensions; - unsigned int max_net_ents; + unsigned int max_net_ents; /*highest entity number the client can receive (limited by either protocol or client's buffer size)*/ unsigned int maxmodels; /*max models supported by whatever the protocol is*/ enum { @@ -760,10 +765,6 @@ typedef struct progsnum_t progsnum[MAX_PROGS]; int numprogs; -#ifdef PROTOCOLEXTENSIONS - unsigned long fteprotocolextensions; - unsigned long fteprotocolextensions2; -#endif struct netprim_s netprim; qboolean demoplayback; @@ -772,6 +773,7 @@ typedef struct int language; //the server operators language laggedpacket_t *free_lagged_packet; + packet_entities_t entstatebuffer; /*just a temp buffer*/ levelcache_t *levcache; } server_static_t; @@ -917,7 +919,7 @@ void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf); int SV_ModelIndex (char *name); void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg); -void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext); +void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext); void SV_SaveSpawnparms (qboolean); void SV_SaveLevelCache(char *savename, qboolean dontharmgame); @@ -955,8 +957,8 @@ qboolean SVQ2_InitGameProgs(void); void VARGS SVQ2_ShutdownGameProgs (void); //svq2_ents.c -void SV_BuildClientFrame (client_t *client); -void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg); +void SVQ2_BuildClientFrame (client_t *client); +void SVQ2_WriteFrameToClient (client_t *client, sizebuf_t *msg); #ifdef Q2SERVER void MSGQ2_WriteDeltaEntity (q2entity_state_t *from, q2entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity); void SVQ2_BuildBaselines(void); @@ -967,7 +969,7 @@ void SVQ2_BuildBaselines(void); void SVQ3_ShutdownGame(void); qboolean SVQ3_InitGame(void); qboolean SVQ3_ConsoleCommand(void); -void SVQ3_HandleClient(void); +qboolean SVQ3_HandleClient(void); void SVQ3_DirectConnect(void); void SVQ3_DropClient(client_t *cl); int SVQ3_AddBot(void); diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 82c8b1798..7a509589c 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -393,10 +393,33 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg) #endif } -#ifdef PEXT_CSQC void SV_CSQC_DroppedPacket(client_t *client, int sequence) { int i; + //skip it if we never generated that frame, to avoid pulling in stale data + if (client->frameunion.frames[sequence & UPDATE_MASK].sequence != sequence) + { + Con_Printf("SV: Stale %i\n", sequence); + return; + } + + if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + { + unsigned int *f = client->frameunion.frames[sequence & UPDATE_MASK].resendentbits; + Con_Printf("SV: Resend %i\n", sequence); + i = client->max_net_ents; + if (i > sv.world.num_edicts) + i = sv.world.num_edicts; + while (i > 0) + { + if (f[i]) + { + client->pendingentbits[i] |= f[i]; + f[i] = 0; + } + i--; + } + } if (!(client->csqcactive)) //we don't need this, but it might be a little faster. return; @@ -408,13 +431,19 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence) void SV_CSQC_DropAll(client_t *client) { int i; + + if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + { + Con_Printf("Reset all\n"); + client->pendingentbits[0] = UF_REMOVE; + } + if (!(client->csqcactive)) //we don't need this, but it might be a little faster. return; for (i = 0; i < sv.world.num_edicts; i++) client->csqcentversions[i]--; //do that update thang (but later). } -#endif //============================================================================= @@ -427,7 +456,7 @@ Writes part of a packetentities message. Can delta from either a baseline or a previous packet_entity ================== */ -void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext) +void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext) { #ifdef PROTOCOLEXTENSIONS int evenmorebits=0; @@ -554,8 +583,8 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb evenmorebits |= U_LIGHT; #endif - if (to->flags & U_SOLID) - bits |= U_SOLID; +// if (to->solid) +// bits |= U_SOLID; if (msg->cursize + 40 > msg->maxsize) { //not enough space in the buffer, don't send the entity this frame. (not sending means nothing changes, and it takes no bytes!!) @@ -684,15 +713,382 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb MSG_WriteByte (msg, (to->effects&0xff00)>>8); } +/*special flags which are slightly more compact. these are 'wasted' as part of the delta itself*/ +#define UF_REMOVE UF_16BIT /*special flag, slightly more compact (we can reuse the 16bit flag as its not important)*/ +#define UF_MOVETYPE UF_EFFECTS2 +//#define UF_WASTED3 UF_EXTEND1 +//#define UF_WASTED2 UF_EXTEND2 +//#define UF_WASTED1 UF_EXTEND3 + +static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *to) +{ + unsigned int bits = 0; + + if (to->u.q1.pmovetype) + { + bits |= UF_PREDINFO; + /*if we've got player movement then always resend this extra stuff to avoid any weird loss*/ + bits |= UF_ORIGINXY | UF_ORIGINZ | UF_ANGLESXZ | UF_ANGLESY; + if (from->u.q1.pmovetype != to->u.q1.pmovetype) + bits |= UF_MOVETYPE; + } + + if (to->origin[0] != from->origin[0]) + bits |= UF_ORIGINXY; + if (to->origin[1] != from->origin[1]) + bits |= UF_ORIGINXY; + if (to->origin[2] != from->origin[2]) + bits |= UF_ORIGINZ; + + if (to->angles[0] != from->angles[0]) + bits |= UF_ANGLESXZ; + if (to->angles[1] != from->angles[1]) + bits |= UF_ANGLESY; + if (to->angles[2] != from->angles[2]) + bits |= UF_ANGLESXZ; + + + if (to->modelindex != from->modelindex) + bits |= UF_MODEL; + if (to->frame != from->frame) + bits |= UF_FRAME; + if (to->skinnum != from->skinnum) + bits |= UF_SKIN; + if (to->colormap != from->colormap) + bits |= UF_COLORMAP; + if (to->effects != from->effects) + bits |= UF_EFFECTS; + if (to->dpflags != from->dpflags) + bits |= UF_FLAGS; + if (to->solid != from->solid) + bits |= UF_SOLID; + + if (to->scale != from->scale) + bits |= UF_SCALE; + if (to->trans != from->trans) + bits |= UF_ALPHA; + if (to->fatness != from->fatness) + bits |= UF_FATNESS; + + if (to->hexen2flags != from->hexen2flags) + bits |= UF_DRAWFLAGS; + if (to->abslight != from->abslight) + bits |= UF_ABSLIGHT; + + if (to->colormod[0]!=from->colormod[0]||to->colormod[1]!=from->colormod[1]||to->colormod[2]!=from->colormod[2]) + bits |= UF_COLORMOD; + + if (to->glowmod[0]!=from->glowmod[0]||to->glowmod[1]!=from->glowmod[1]||to->glowmod[2]!=from->glowmod[2]) + bits |= UF_GLOWMOD; + + if (to->tagentity != from->tagentity || to->tagindex != from->tagindex) + bits |= UF_TAGINFO; + + if (to->light[0] != from->light[0] || to->light[1] != from->light[1] || to->light[2] != from->light[2] || to->light[3] != from->light[3] || to->lightstyle != from->lightstyle || to->lightpflags != from->lightstyle) + bits |= UF_LIGHT; + + return bits; +} + +static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg) +{ + unsigned int predbits = 0; + if (bits & UF_MOVETYPE) + { + bits &= ~UF_MOVETYPE; + predbits |= UFP_MOVETYPE; + } + + /*check if we need more precision*/ + if ((bits & UF_MODEL) && state->modelindex > 255) + bits |= UF_16BIT; + if ((bits & UF_SKIN) && state->skinnum > 255) + bits |= UF_16BIT; + if ((bits & UF_FRAME) && state->frame > 255) + bits |= UF_16BIT; + + /*convert effects bits to higher lengths if needed*/ + if (bits & UF_EFFECTS) + { + if (state->effects & 0xffff0000) /*both*/ + bits |= UF_EFFECTS | UF_EFFECTS2; + else if (state->effects & 0x0000ff00) /*2 only*/ + bits = (bits & ~UF_EFFECTS) | UF_EFFECTS2; + } + if (bits & 0xff000000) + bits |= UF_EXTEND3; + if (bits & 0x00ff0000) + bits |= UF_EXTEND2; + if (bits & 0x0000ff00) + bits |= UF_EXTEND1; + + MSG_WriteByte(msg, bits>>0); + if (bits & UF_EXTEND1) + MSG_WriteByte(msg, bits>>8); + if (bits & UF_EXTEND2) + MSG_WriteByte(msg, bits>>16); + if (bits & UF_EXTEND3) + MSG_WriteByte(msg, bits>>24); + + if (bits & UF_FRAME) + { + if (bits & UF_16BIT) + MSG_WriteShort(msg, state->frame); + else + MSG_WriteByte(msg, state->frame); + } + if (bits & UF_ORIGINXY) + { + MSG_WriteCoord(msg, state->origin[0]); + MSG_WriteCoord(msg, state->origin[1]); + } + if (bits & UF_ORIGINZ) + MSG_WriteCoord(msg, state->origin[2]); + + if (bits & UF_PREDINFO) + { /*if we have pred info, use more precise angles*/ + if (bits & UF_ANGLESXZ) + { + MSG_WriteAngle16(msg, state->angles[0]); + MSG_WriteAngle16(msg, state->angles[2]); + } + if (bits & UF_ANGLESY) + MSG_WriteAngle16(msg, state->angles[1]); + } + else + { + if (bits & UF_ANGLESXZ) + { + MSG_WriteAngle(msg, state->angles[0]); + MSG_WriteAngle(msg, state->angles[2]); + } + if (bits & UF_ANGLESY) + MSG_WriteAngle(msg, state->angles[1]); + } + + if ((bits & (UF_EFFECTS|UF_EFFECTS2)) == (UF_EFFECTS|UF_EFFECTS2)) + MSG_WriteLong(msg, state->effects); + else if (bits & UF_EFFECTS2) + MSG_WriteShort(msg, state->effects); + else if (bits & UF_EFFECTS) + MSG_WriteByte(msg, state->effects); + + if (bits & UF_PREDINFO) + { + /*movetype is set above somewhere*/ + if (state->u.q1.movement[0]) + predbits |= UFP_FORWARD; + if (state->u.q1.movement[1]) + predbits |= UFP_SIDE; + if (state->u.q1.movement[2]) + predbits |= UFP_UP; + if (state->u.q1.velocity[0]) + predbits |= UFP_VELOCITYXY; + if (state->u.q1.velocity[1]) + predbits |= UFP_VELOCITYXY; + if (state->u.q1.velocity[2]) + predbits |= UFP_VELOCITYZ; + if (state->u.q1.msec) + predbits |= UFP_MSEC; + + MSG_WriteByte(msg, predbits); + if (predbits & UFP_FORWARD) + MSG_WriteShort(msg, state->u.q1.movement[0]); + if (predbits & UFP_SIDE) + MSG_WriteShort(msg, state->u.q1.movement[1]); + if (predbits & UFP_UP) + MSG_WriteShort(msg, state->u.q1.movement[2]); + if (predbits & UFP_MOVETYPE) + MSG_WriteByte(msg, state->u.q1.pmovetype); + if (predbits & UFP_VELOCITYXY) + { + MSG_WriteShort(msg, state->u.q1.velocity[0]); + MSG_WriteShort(msg, state->u.q1.velocity[1]); + } + if (predbits & UFP_VELOCITYZ) + MSG_WriteShort(msg, state->u.q1.velocity[2]); + if (predbits & UFP_MSEC) + MSG_WriteByte(msg, state->u.q1.msec); + } + + if (bits & UF_MODEL) + { + if (bits & UF_16BIT) + MSG_WriteShort(msg, state->modelindex); + else + MSG_WriteByte(msg, state->modelindex); + } + if (bits & UF_SKIN) + { + if (bits & UF_16BIT) + MSG_WriteShort(msg, state->skinnum); + else + MSG_WriteByte(msg, state->skinnum); + } + if (bits & UF_COLORMAP) + MSG_WriteByte(msg, state->colormap); + + if (bits & UF_SOLID) + MSG_WriteShort(msg, state->solid); + + if (bits & UF_FLAGS) + MSG_WriteByte(msg, state->dpflags); + + if (bits & UF_ALPHA) + MSG_WriteByte(msg, state->trans); + if (bits & UF_SCALE) + MSG_WriteByte(msg, state->scale); + if (bits & UF_ABSLIGHT) + MSG_WriteByte(msg, state->abslight); + if (bits & UF_DRAWFLAGS) + MSG_WriteByte(msg, state->hexen2flags); + if (bits & UF_TAGINFO) + { + MSG_WriteShort(msg, state->tagentity); + MSG_WriteByte(msg, state->tagindex); + } + if (bits & UF_LIGHT) + { + MSG_WriteShort (msg, state->light[0]); + MSG_WriteShort (msg, state->light[1]); + MSG_WriteShort (msg, state->light[2]); + MSG_WriteShort (msg, state->light[3]); + MSG_WriteByte (msg, state->lightstyle); + MSG_WriteByte (msg, state->lightpflags); + } + + if (bits & UF_COLORMOD) + { + MSG_WriteByte(msg, state->colormod[0]); + MSG_WriteByte(msg, state->colormod[1]); + MSG_WriteByte(msg, state->colormod[2]); + } + if (bits & UF_GLOWMOD) + { + MSG_WriteByte(msg, state->glowmod[0]); + MSG_WriteByte(msg, state->glowmod[1]); + MSG_WriteByte(msg, state->glowmod[2]); + } + if (bits & UF_FATNESS) + MSG_WriteByte(msg, state->fatness); +} + +/*SVFTE_EmitPacketEntities +Writes changed entities to the client. +Changed ent states will be tracked, even if they're not sent just yet, dropped packets will also re-flag dropped delta bits +Only what changed is tracked, via bitmask, its previous value is never tracked. +*/ +void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t *msg) +{ + entity_state_t *o, *n; + unsigned int i; + unsigned int j; + unsigned int *resend; + qboolean reset = (client->delta_sequence == -1) || (client->pendingentbits[0] & UF_REMOVE); + + if (reset) + { + for (j = 0; j < client->sentents.max_entities; j++) + { + client->sentents.entities[j].number = 0; + client->pendingentbits[j] = 0; + } + } + + j = 0; + if (to->num_entities) + { + j = to->entities[to->num_entities-1].number+1; + if (j > client->sentents.max_entities) + { + client->sentents.entities = BZ_Realloc(client->sentents.entities, sizeof(*client->sentents.entities) * j); + memset(&client->sentents.entities[client->sentents.max_entities], 0, sizeof(client->sentents.entities[0]) * (j - client->sentents.max_entities)); + client->sentents.max_entities = j; + } + } + + /*figure out the bits that changed*/ + for (i = 0, j = 0; i < to->num_entities; i++) + { + n = &to->entities[i]; + /*gaps are dead entities*/ + for (; j < n->number; j++) + { + o = &client->sentents.entities[j]; + if (o->number) + { + client->pendingentbits[j] = UF_REMOVE; + o->number = 0; /*dead*/ + } + } + + o = &client->sentents.entities[j]; + if (!o->number) + { + /*forget any remove bits*/ + client->pendingentbits[j] = UF_RESET | SVFTE_DeltaCalcBits(&EDICT_NUM(svprogfuncs, n->number)->baseline, n); + } + else + { + client->pendingentbits[j] |= SVFTE_DeltaCalcBits(o, n);; + } + *o = *n; + j++; + } + /*gaps are dead entities*/ + for (; j < client->sentents.max_entities; j++) + { + o = &client->sentents.entities[j]; + if (o->number) + { + client->pendingentbits[j] = UF_REMOVE; + o->number = 0; /*dead*/ + } + } + + resend = client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK].resendentbits; + + MSG_WriteByte (msg, svcfte_updateentities); + MSG_WriteFloat(msg, sv.world.physicstime); + if (reset) + MSG_WriteShort(msg, 0x8000); + + memset(resend, 0, client->sentents.max_entities*sizeof(*resend)); + + for(j = 0; j < client->sentents.max_entities; j++) + { + if (!client->pendingentbits[j]) + continue; + if (msg->cursize + 50 > msg->maxsize) + break; /*give up if it gets full*/ + + if (client->pendingentbits[j] & UF_REMOVE) + { + MSG_WriteShort(msg, j | 0x8000); + resend[j] = UF_REMOVE; + } + else + { + MSG_WriteShort(msg, j); + SVFTE_WriteUpdate(client->pendingentbits[j], &client->sentents.entities[j], msg); + resend[j] = client->pendingentbits[j]; + } + client->pendingentbits[j] = 0; + } + + MSG_WriteShort(msg, 0); +} + /* ============= -SV_EmitPacketEntities +SVQW_EmitPacketEntities Writes a delta update of a packet_entities_t to the message. +deltaing is performed from one set of entity states directly to the next ============= */ -void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg) +void SVQW_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg) { edict_t *ent; client_frame_t *fromframe; @@ -732,9 +1128,9 @@ void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t * { // delta update from old position //Con_Printf ("delta %i\n", newnum); #ifdef PROTOCOLEXTENSIONS - SV_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false, client->fteprotocolextensions); + SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false, client->fteprotocolextensions); #else - SV_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false); + SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false); #endif oldindex++; newindex++; @@ -749,9 +1145,9 @@ void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t * ent = NULL; //Con_Printf ("baseline %i\n", newnum); #ifdef PROTOCOLEXTENSIONS - SV_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true, client->fteprotocolextensions); + SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true, client->fteprotocolextensions); #else - SV_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true); + SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true); #endif newindex++; continue; @@ -1064,8 +1460,6 @@ void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t if (client->protocol == SCP_DARKPLACES7) MSG_WriteLong(msg, client->last_sequence); - for (newindex = 0; newindex < to->num_entities; newindex++) - to->entities[newindex].bitmask = 0; //add in the bitmasks of dropped packets. newindex = 0; @@ -2197,18 +2591,49 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli int i; -#ifdef Q2SERVER - state->modelindex2 = 0; - state->modelindex3 = 0; - state->modelindex4 = 0; - state->event = 0; - state->solid = 0; - state->sound = 0; - state->renderfx = 0; - state->old_origin[0] = 0; - state->old_origin[1] = 0; - state->old_origin[2] = 0; -#endif + state->number = NUM_FOR_EDICT(svprogfuncs, ent); + + state->u.q1.msec = 0; + state->u.q1.pmovetype = 0; + state->u.q1.movement[0] = 0; + state->u.q1.movement[1] = 0; + state->u.q1.movement[2] = 0; + state->u.q1.velocity[0] = 0; + state->u.q1.velocity[1] = 0; + state->u.q1.velocity[2] = 0; + if ((state->number-1) < (unsigned short)sv.allocated_client_slots && ent->v->movetype) + { + client_t *cl = &svs.clients[state->number-1]; + if (cl->isindependant) + { + state->u.q1.pmovetype = ent->v->movetype; + if (cl != client) + { /*only generate movement values if the client doesn't already know them...*/ + state->u.q1.movement[0] = ent->xv->movement[0]; + state->u.q1.movement[1] = ent->xv->movement[1]; + state->u.q1.movement[2] = ent->xv->movement[2]; + state->u.q1.msec = bound(0, 1000*(sv.time - cl->localtime), 255); + } + + state->u.q1.velocity[0] = ent->v->velocity[0] * 8; + state->u.q1.velocity[1] = ent->v->velocity[1] * 8; + state->u.q1.velocity[2] = ent->v->velocity[2] * 8; + } + } + + if (ent->v->solid == SOLID_BSP || (ent->v->skin < 0 && ent->v->modelindex)) + state->solid = ES_SOLID_BSP; + else if (ent->v->solid == SOLID_BBOX || ent->v->solid == SOLID_SLIDEBOX || ent->v->skin < 0) + { + i = bound(0, -ent->v->mins[0]/8, 31); + state->solid = i; + i = bound(0, -ent->v->mins[2]/8, 31); + state->solid |= i<<5; + i = bound(0, ((ent->v->maxs[2]+32)/8), 63); /*up can be negative*/ + state->solid |= i<<10; + } + else + state->solid = 0; state->dpflags = 0; if (ent->xv->viewmodelforclient) @@ -2216,6 +2641,8 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli //if ent->viewmodelforclient == client then: state->dpflags |= RENDER_VIEWMODEL; } + if (ent->v->colormap >= 1024) + state->dpflags |= RENDER_COLORMAPPED; if (ent->xv->exteriormodeltoclient && client) { if (ent->xv->exteriormodeltoclient == EDICT_TO_PROG(svprogfuncs, client->edict)) @@ -2226,11 +2653,11 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli if (ent->v->movetype == MOVETYPE_STEP) state->dpflags |= RENDER_STEP; - state->number = NUM_FOR_EDICT(svprogfuncs, ent); state->flags = 0; VectorCopy (ent->v->origin, state->origin); VectorCopy (ent->v->angles, state->angles); state->modelindex = ent->v->modelindex; + state->modelindex2 = ent->xv->vw_index; state->frame = ent->v->frame; state->colormap = ent->v->colormap; state->skinnum = ent->v->skin; @@ -2247,7 +2674,7 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli state->lightstyle = ent->xv->style; state->lightpflags = ent->xv->pflags; - if ((int)ent->v->flags & FL_CLASS_DEPENDENT && client->playerclass) //hexen2 wierdness. + if (((int)ent->v->flags & FL_CLASS_DEPENDENT) && client->playerclass) //hexen2 wierdness. { char modname[MAX_QPATH]; Q_strncpyz(modname, sv.strings.model_precache[state->modelindex], sizeof(modname)); @@ -2306,6 +2733,9 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli i = ent->xv->colormod[1]*(256/8); state->colormod[1] = bound(0, i, 255); i = ent->xv->colormod[2]*(256/8); state->colormod[2] = bound(0, i, 255); } + state->glowmod[0] = ent->xv->glowmod[0]*(256/8); + state->glowmod[1] = ent->xv->glowmod[1]*(256/8); + state->glowmod[2] = ent->xv->glowmod[2]*(256/8); state->glowsize = ent->xv->glow_size*0.25; state->glowcolour = ent->xv->glow_color; if (ent->xv->glow_trail) @@ -2338,6 +2768,8 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli #ifdef PEXT_FATNESS state->fatness = ent->xv->fatness; #endif + +#pragma warningmsg("TODO: Fix attachments for more vanilla clients") } void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, edict_t *clent, qboolean ignorepvs) @@ -2349,7 +2781,7 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, #define DEPTHOPTIMISE #ifdef DEPTHOPTIMISE vec3_t org; - float distances[MAX_EXTENDED_PACKET_ENTITIES]; + static float distances[32768]; float dist; #endif globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT); @@ -2401,12 +2833,13 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, } + /*legacy qw clients get their players separately*/ + if (ISQWCLIENT(client) && !(client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) + e = sv.allocated_client_slots+1; + else + e = 1; -#ifdef NQPROT - for (e=(ISQWCLIENT(client)?sv.allocated_client_slots+1:1) ; exv->SendEntity && (!ent->v->modelindex || !*PR_GetString(svprogfuncs, ent->v->model)) && !((int)ent->xv->pflags & PFLAGS_FULLDYNAMIC)) + if (!ent->xv->SendEntity && (!ent->v->modelindex || !*PR_GetString(svprogfuncs, ent->v->model)) && !((int)ent->xv->pflags & PFLAGS_FULLDYNAMIC) && ent->v->skin >= 0) continue; pvsflags = ent->xv->pvsflags; @@ -2698,13 +3131,20 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore } host_client = client; - pack = &frame->entities; + if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + { + pack = &svs.entstatebuffer; + if (pack->max_entities < client->max_net_ents) + { + pack->max_entities = client->max_net_ents; + pack->entities = BZ_Realloc(pack->entities, sizeof(*pack->entities) * pack->max_entities); + memset(pack->entities, 0, sizeof(entity_state_t) * pack->max_entities); + } + } + else + pack = &frame->entities; SV_Snapshot_Clear(pack); - // send over the players in the PVS - if (svs.gametype != GT_HALFLIFE) - SV_WritePlayersToClient (client, frame, clent, pvs, msg); - // put other visible entities into either a packet_entities or a nails message #ifdef SERVER_DEMO_PLAYBACK @@ -2749,7 +3189,41 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore // encode the packet entities as a delta from the // last packetentities acknowledged by the client - SV_EmitPacketEntities (client, pack, msg); + if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + { + SVFTE_EmitPacketEntities(client, pack, msg); + } + else + { + // Z_EXT_TIME protocol extension + // every now and then, send an update so that extrapolation + // on client side doesn't stray too far off + if (ISQWCLIENT(client)) + { + if (client->fteprotocolextensions & PEXT_ACCURATETIMINGS && sv.world.physicstime - client->nextservertimeupdate > 0) + { //the fte pext causes the server to send out accurate timings, allowing for perfect interpolation. + MSG_WriteByte (msg, svc_updatestatlong); + MSG_WriteByte (msg, STAT_TIME); + MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000)); + + client->nextservertimeupdate = sv.world.physicstime;//+10; + } + else if (client->zquake_extensions & Z_EXT_SERVERTIME && sv.world.physicstime - client->nextservertimeupdate > 0) + { //the zquake ext causes the server to send out peridoic timings, allowing for moderatly accurate game time. + MSG_WriteByte (msg, svc_updatestatlong); + MSG_WriteByte (msg, STAT_TIME); + MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000)); + + client->nextservertimeupdate = sv.world.physicstime+10; + } + } + + // send over the players in the PVS + if (svs.gametype != GT_HALFLIFE) + SV_WritePlayersToClient (client, frame, clent, pvs, msg); + + SVQW_EmitPacketEntities (client, pack, msg); + } SV_EmitCSQCUpdate(client, msg); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 39eda2099..b3126e4bc 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -256,6 +256,9 @@ void SV_EdictToEntState (int num, edict_t *ent, entity_state_t *state) if (/*progstype == PROG_H2 &&*/ ent->v->solid == SOLID_BSP) state->angles[0]*=-1; + if (ent->v->solid == SOLID_BSP) + state->solid = ES_SOLID_BSP; + if (state->effects & EF_FULLBRIGHT) { state->hexen2flags |= MLS_FULLBRIGHT; @@ -296,6 +299,7 @@ void SVNQ_CreateBaseline (void) { edict_t *svent; int entnum; + extern entity_state_t nullentitystate; int playermodel = SV_SafeModelIndex("progs/player.mdl"); @@ -303,16 +307,9 @@ void SVNQ_CreateBaseline (void) { svent = EDICT_NUM(svprogfuncs, entnum); - memset(&svent->baseline, 0, sizeof(entity_state_t)); + memcpy(&svent->baseline, &nullentitystate, sizeof(entity_state_t)); svent->baseline.number = entnum; -#ifdef PEXT_SCALE - svent->baseline.scale = 1*16; -#endif -#ifdef PEXT_TRANS - svent->baseline.trans = 255; -#endif - if (svent->isfree) continue; // create baselines for all player slots, @@ -616,6 +613,7 @@ void SV_UnspawnServer (void) //terminate the running server. *svs.clients[i].namebuf = '\0'; svs.clients[i].name = NULL; } + SV_FlushLevelCache(); NET_CloseServer (); } @@ -836,7 +834,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us Info_SetValueForStarKey(svs.info, "*gamespeed", "", MAX_SERVERINFO_STRING); } //reset the server time. - sv.time = 0.1; //some progs don't like time starting at 0. + sv.time = 0.01; //some progs don't like time starting at 0. //cos of spawn funcs like self.nextthink = time... //NQ uses 1, QW uses 0. Awkward. sv.starttime = Sys_DoubleTime(); @@ -1098,6 +1096,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us for (i=0 ; iframeunion.frames); drop->frameunion.frames = NULL; } + if (drop->sentents.entities) + { + Z_Free(drop->sentents.entities); + memset(&drop->sentents.entities, 0, sizeof(drop->sentents.entities)); + } if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) //gamecode should do it all for us. { @@ -1380,30 +1385,45 @@ void SVC_GetChallenge (void) if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) { #ifdef PROTOCOL_VERSION_FTE + unsigned int mask; //tell the client what fte extensions we support - if (svs.fteprotocolextensions) + mask = Net_PextMask(1); + if (mask) { lng = LittleLong(PROTOCOL_VERSION_FTE); memcpy(over, &lng, sizeof(lng)); over+=sizeof(lng); - lng = LittleLong(svs.fteprotocolextensions); + lng = LittleLong(mask); memcpy(over, &lng, sizeof(lng)); over+=sizeof(lng); } //tell the client what fte extensions we support - if (svs.fteprotocolextensions2) + mask = Net_PextMask(2); + if (mask) { lng = LittleLong(PROTOCOL_VERSION_FTE2); memcpy(over, &lng, sizeof(lng)); over+=sizeof(lng); - lng = LittleLong(svs.fteprotocolextensions2); + lng = LittleLong(mask); memcpy(over, &lng, sizeof(lng)); over+=sizeof(lng); } #endif + mask = net_mtu.ival&~7; + if (mask > 64) + { + lng = LittleLong(PROTOCOL_VERSION_FRAGMENT); + memcpy(over, &lng, sizeof(lng)); + over+=sizeof(lng); + + lng = LittleLong(mask); + memcpy(over, &lng, sizeof(lng)); + over+=sizeof(lng); + } + #ifdef HUFFNETWORK compressioncrc = Huff_PreferedCompressionCRC(); if (compressioncrc) @@ -1674,6 +1694,7 @@ client_t *SVC_DirectConnect(void) int version; int challenge; int huffcrc = 0; + int mtu = 0; char guid[128] = ""; char basic[80]; qboolean redirect = false; @@ -1823,33 +1844,48 @@ client_t *SVC_DirectConnect(void) Con_Printf ("* rejected connect from quakeworld\n"); return NULL; } + } - while(!msg_badread) + + while(!msg_badread) + { + Cmd_TokenizeString(MSG_ReadStringLine(), false, false); + switch(Q_atoi(Cmd_Argv(0))) { - Cmd_TokenizeString(MSG_ReadStringLine(), false, false); - switch(Q_atoi(Cmd_Argv(0))) + case PROTOCOL_VERSION_FTE: + if (protocol == SCP_QUAKEWORLD) { - case PROTOCOL_VERSION_FTE: protextsupported = Q_atoi(Cmd_Argv(1)); Con_DPrintf("Client supports 0x%x fte extensions\n", protextsupported); - break; - case PROTOCOL_VERSION_FTE2: + } + break; + case PROTOCOL_VERSION_FTE2: + if (protocol == SCP_QUAKEWORLD) + { protextsupported2 = Q_atoi(Cmd_Argv(1)); Con_DPrintf("Client supports 0x%x fte2 extensions\n", protextsupported2); - break; - case PROTOCOL_VERSION_HUFFMAN: - huffcrc = Q_atoi(Cmd_Argv(1)); - Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc); - break; - case PROTOCOL_INFO_GUID: - Q_strncpyz(guid, Cmd_Argv(1), sizeof(guid)); - Con_DPrintf("GUID %s\n", Cmd_Argv(1)); - break; } + break; + case PROTOCOL_VERSION_HUFFMAN: + huffcrc = Q_atoi(Cmd_Argv(1)); + Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc); + break; + case PROTOCOL_VERSION_FRAGMENT: + mtu = Q_atoi(Cmd_Argv(1)) & ~7; + if (mtu < 64) + mtu = 64; + Con_DPrintf("Client supports fragmentation. mtu %i.\n", mtu); + break; + case PROTOCOL_INFO_GUID: + Q_strncpyz(guid, Cmd_Argv(1), sizeof(guid)); + Con_DPrintf("GUID %s\n", Cmd_Argv(1)); + break; } - msg_badread=false; } + msg_badread=false; + + if (protextsupported & PEXT_256PACKETENTITIES) maxpacketentities = MAX_EXTENDED_PACKET_ENTITIES; @@ -2230,11 +2266,23 @@ client_t *SVC_DirectConnect(void) Z_Free(temp.frameunion.frames); } - temp.frameunion.frames = Z_Malloc((sizeof(client_frame_t)+sizeof(entity_state_t)*maxpacketentities)*UPDATE_BACKUP); - for (i = 0; i < UPDATE_BACKUP; i++) + if ((temp.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))// || ISDPCLIENT(&temp)) { - temp.frameunion.frames[i].entities.max_entities = maxpacketentities; - temp.frameunion.frames[i].entities.entities = (entity_state_t*)(temp.frameunion.frames+UPDATE_BACKUP) + i*temp.frameunion.frames[i].entities.max_entities; + temp.frameunion.frames = Z_Malloc(sizeof(client_frame_t)*UPDATE_BACKUP+sizeof(unsigned int)*temp.max_net_ents*UPDATE_BACKUP + sizeof(unsigned int)*temp.max_net_ents); + for (i = 0; i < UPDATE_BACKUP; i++) + { + temp.frameunion.frames[i].resendentbits = (unsigned int*)(temp.frameunion.frames+UPDATE_BACKUP) + i*temp.max_net_ents; + } + temp.pendingentbits = (unsigned int*)(temp.frameunion.frames+UPDATE_BACKUP) + UPDATE_BACKUP*temp.max_net_ents; + } + else + { + temp.frameunion.frames = Z_Malloc((sizeof(client_frame_t)+sizeof(entity_state_t)*maxpacketentities)*UPDATE_BACKUP); + for (i = 0; i < UPDATE_BACKUP; i++) + { + temp.frameunion.frames[i].entities.max_entities = maxpacketentities; + temp.frameunion.frames[i].entities.entities = (entity_state_t*)(temp.frameunion.frames+UPDATE_BACKUP) + i*temp.frameunion.frames[i].entities.max_entities; + } } break; } @@ -2263,6 +2311,8 @@ client_t *SVC_DirectConnect(void) newcl->netchan.compress = true; else newcl->netchan.compress = false; + if (mtu >= 0) + newcl->netchan.fragmentsize = mtu; newcl->protocol = protocol; #ifdef NQPROT @@ -3257,20 +3307,40 @@ qboolean SV_ReadPackets (float *delay) net_from = cl->netchan.remote_address; //not sure if anything depends on this, but lets not screw them up willynilly - if (Netchan_Process(&cl->netchan)) - { // this is a valid, sequenced packet, so process it - received++; - svs.stats.packets++; - if (cl->state > cs_zombie) - { //make sure they didn't already disconnect - cl->send_message = true; // reply at end of frame + if (ISNQCLIENT(cl)) + { + if (cl->state != cs_zombie) + { + if (NQNetChan_Process(&cl->netchan)) + { + received++; + svs.stats.packets++; + SVNQ_ExecuteClientMessage(cl); + } + } + break; + } + else + { + /*QW*/ + if (Netchan_Process(&cl->netchan)) + { // this is a valid, sequenced packet, so process it + received++; + svs.stats.packets++; + if (cl->state > cs_zombie) + { //make sure they didn't already disconnect + if (cl->send_message) + cl->chokecount++; + else + cl->send_message = true; // reply at end of frame - #ifdef Q2SERVER - if (cl->protocol == SCP_QUAKE2) - SVQ2_ExecuteClientMessage(cl); - else - #endif - SV_ExecuteClientMessage (cl); + #ifdef Q2SERVER + if (cl->protocol == SCP_QUAKE2) + SVQ2_ExecuteClientMessage(cl); + else + #endif + SV_ExecuteClientMessage (cl); + } } } } @@ -3328,6 +3398,9 @@ qboolean SV_ReadPackets (float *delay) { if (cl->state != cs_zombie) { + if (cl->delay > 0) + goto dominping; + if (NQNetChan_Process(&cl->netchan)) { received++; @@ -3341,17 +3414,7 @@ qboolean SV_ReadPackets (float *delay) #ifdef Q3SERVER if (ISQ3CLIENT(cl)) - { -#ifdef warningmsg -#pragma warningmsg("qwoverq3: fixme: this will block qw+q3 clients from the same ip") -#endif - if (cl->state != cs_zombie) - { - received++; - SVQ3_HandleClient(); - } - break; - } + continue; #endif if (cl->netchan.qport != qport) @@ -3364,6 +3427,7 @@ qboolean SV_ReadPackets (float *delay) if (cl->delay > 0) { +dominping: if (cl->state == cs_zombie) break; if (net_message.cursize > sizeof(svs.free_lagged_packet->data)) @@ -3414,6 +3478,14 @@ qboolean SV_ReadPackets (float *delay) if (i != MAX_CLIENTS) continue; +#ifdef Q3SERVER + if (sv_listen_q3.ival && SVQ3_HandleClient()) + { + received++; + continue; + } +#endif + #ifdef NQPROT SVNQ_ConnectionlessPacket(); #endif @@ -4077,88 +4149,6 @@ void SV_InitLocal (void) for (i=0 ; iv->velocity[2] -= scale * sv_gravity.value/*movevars.gravity*/ * host_frametime; + if (!scale) + scale = w->defaultgravityscale; + ent->v->velocity[2] -= scale * movevars.gravity * host_frametime; } /* @@ -537,7 +527,7 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec int i, e; wedict_t *check, *block; vec3_t mins, maxs; - float oldsolid; + //float oldsolid; pushed_t *p; vec3_t org, org2, move2, forward, right, up; @@ -577,14 +567,14 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec || check->v->movetype == MOVETYPE_NOCLIP || check->v->movetype == MOVETYPE_ANGLENOCLIP) continue; - +/* oldsolid = pusher->v->solid; pusher->v->solid = SOLID_NOT; block = World_TestEntityPosition (w, check); pusher->v->solid = oldsolid; if (block) continue; - +*/ // if the entity is standing on the pusher, it will definitely be moved if ( ! ( ((int)check->v->flags & FL_ONGROUND) && PROG_TO_WEDICT(w->progs, check->v->groundentity) == pusher) ) @@ -1103,15 +1093,16 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) && ent->v->movetype != MOVETYPE_FLYMISSILE && ent->v->movetype != MOVETYPE_BOUNCEMISSILE && ent->v->movetype != MOVETYPE_H2SWIM) - WPhys_AddGravity (ent, 1.0); + WPhys_AddGravity (w, ent, 1.0); // move angles VectorMA (ent->v->angles, host_frametime, ent->v->avelocity, ent->v->angles); // move origin VectorScale (ent->v->velocity, host_frametime, move); + if (!DotProduct(move, move)) + return; VectorCopy(ent->v->origin, temporg); - VectorCopy(temporg, ent->v->origin); fl = 0; #ifndef CLIENTONLY @@ -1123,7 +1114,14 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) trace = WPhys_PushEntity (w, ent, move, fl); if (trace.allsolid) + { trace.fraction = 0; + +#pragma warningmsg("These three lines might help boost framerates a lot in rmq, not sure if they violate expected behaviour in other mods though - check that they're safe.") + trace.plane.normal[0] = 0; + trace.plane.normal[1] = 0; + trace.plane.normal[2] = 1; + } if (trace.fraction == 1) return; if (ent->isfree) @@ -1206,7 +1204,7 @@ static void WPhys_Physics_Step (world_t *w, wedict_t *ent) { hitsound = ent->v->velocity[2] < movevars.gravity*-0.1; - WPhys_AddGravity (ent, 1.0); + WPhys_AddGravity (w, ent, 1.0); WPhys_CheckVelocity (w, ent); WPhys_FlyMove (w, ent, host_frametime, NULL); World_LinkEdict (w, ent, true); @@ -1897,7 +1895,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) if (!WPhys_RunThink (w, ent)) return; if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) - WPhys_AddGravity (ent, ent->xv->gravity); + WPhys_AddGravity (w, ent, ent->xv->gravity); WPhys_CheckStuck (w, ent); WPhys_WalkMove (w, ent); @@ -2093,6 +2091,8 @@ qboolean SV_Physics (void) qboolean moved = false; int maxtics; + //keep gravity tracking the cvar properly + movevars.gravity = sv_gravity.value; if (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM && svs.gametype != GT_HALFLIFE) //make tics multiples of sv_maxtic (defaults to 0.1) { @@ -2265,7 +2265,6 @@ qboolean SV_Physics (void) void SV_SetMoveVars(void) { - movevars.gravity = sv_gravity.value; movevars.stopspeed = sv_stopspeed.value; movevars.maxspeed = sv_maxspeed.value; movevars.spectatormaxspeed = sv_spectatormaxspeed.value; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 7d9a6830b..e39520d39 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1090,7 +1090,7 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) MSG_WriteByte(msg, svcfte_choosesplitclient); MSG_WriteByte(msg, pnum); } - if (client->fteprotocolextensions2 & PEXT2_SETANGLEDELTA && client->delta_sequence != -1) + if (!client->lockangles && (client->fteprotocolextensions2 & PEXT2_SETANGLEDELTA) && client->delta_sequence != -1) { MSG_WriteByte (msg, svcfte_setangledelta); for (i=0 ; i < 3 ; i++) @@ -1107,7 +1107,10 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) MSG_WriteAngle (msg, ent->v->angles[i]); } ent->v->fixangle = 0; + client->lockangles = true; } + else + client->lockangles = false; } /*sends the a centerprint string directly to the client*/ @@ -1160,13 +1163,6 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg) client_t *split; int pnum=0; - if (client->centerprintstring && ! client->num_backbuf) - { - SV_WriteCenterPrint(client, client->centerprintstring); - Z_Free(client->centerprintstring); - client->centerprintstring = NULL; - } - // send the chokecount for r_netgraph if (ISQWCLIENT(client)) if (client->chokecount) @@ -1177,34 +1173,21 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg) } for (split = client; split; split=split->controlled, pnum++) + { SV_WriteEntityDataToMessage(split, msg, pnum); + + if (split->centerprintstring && ! client->num_backbuf) + { + SV_WriteCenterPrint(split, split->centerprintstring); + Z_Free(split->centerprintstring); + split->centerprintstring = NULL; + } + } /* MSG_WriteByte (msg, svc_time); MSG_WriteFloat(msg, sv.physicstime); client->nextservertimeupdate = sv.physicstime; */ - // Z_EXT_TIME protocol extension - // every now and then, send an update so that extrapolation - // on client side doesn't stray too far off - if (ISQWCLIENT(client)) - { - if (client->fteprotocolextensions & PEXT_ACCURATETIMINGS && sv.world.physicstime - client->nextservertimeupdate > 0) - { //the fte pext causes the server to send out accurate timings, allowing for perfect interpolation. - MSG_WriteByte (msg, svc_updatestatlong); - MSG_WriteByte (msg, STAT_TIME); - MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000)); - - client->nextservertimeupdate = sv.world.physicstime;//+10; - } - else if (client->zquake_extensions & Z_EXT_SERVERTIME && sv.world.physicstime - client->nextservertimeupdate > 0) - { //the zquake ext causes the server to send out peridoic timings, allowing for moderatly accurate game time. - MSG_WriteByte (msg, svc_updatestatlong); - MSG_WriteByte (msg, STAT_TIME); - MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000)); - - client->nextservertimeupdate = sv.world.physicstime+10; - } - } #ifdef NQPROT if (ISQWCLIENT(client)) @@ -1548,9 +1531,9 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf statsf[STAT_CELLS] = ent->v->ammo_cells; if (!client->spectator) { - statsi[STAT_ACTIVEWEAPON] = ent->v->weapon; + statsf[STAT_ACTIVEWEAPON] = ent->v->weapon; if (client->csqcactive || client->protocol != SCP_QUAKEWORLD) - statsi[STAT_WEAPONFRAME] = ent->v->weaponframe; + statsf[STAT_WEAPONFRAME] = ent->v->weaponframe; } // stuff the sigil bits into the high bits of items for sbar @@ -1574,6 +1557,7 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf if (client->protocol == SCP_DARKPLACES7) { + /*note: statsf is truncated, which would mess things up*/ float *statsfi = (float*)statsi; // statsfi[STAT_MOVEVARS_WALLFRICTION] = sv_wall statsfi[STAT_MOVEVARS_FRICTION] = sv_friction.value; @@ -1789,7 +1773,7 @@ SV_SendClientDatagram */ qboolean SV_SendClientDatagram (client_t *client) { - qbyte buf[MAX_DATAGRAM]; + qbyte buf[MAX_OVERALLMSGLEN]; sizebuf_t msg; unsigned int sentbytes, fnum; @@ -1800,15 +1784,18 @@ qboolean SV_SendClientDatagram (client_t *client) msg.overflowed = false; msg.prim = client->datagram.prim; + if (!client->netchan.fragmentsize) + msg.maxsize = MAX_DATAGRAM; + if (sv.world.worldmodel && !client->controller) { if (ISQ2CLIENT(client)) { - SV_BuildClientFrame (client); + SVQ2_BuildClientFrame (client); // send over all the relevant entity_state_t // and the player_state_t - SV_WriteFrameToClient (client, &msg); + SVQ2_WriteFrameToClient (client, &msg); } else { @@ -2306,9 +2293,9 @@ void SV_SendClientMessages (void) SZ_Clear (&c->datagram); SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name); Con_Printf ("WARNING: reliable overflow for %s\n",c->name); - SV_DropClient (c); c->send_message = true; c->netchan.cleartime = 0; // don't choke this message + SV_DropClient (c); continue; } diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index c7c80b841..cc12e7da9 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -50,6 +50,7 @@ cvar_t sv_antilag_frac = CVARF("sv_antilag_frac", "1", CVAR_SERVERINFO); cvar_t sv_cheatpc = CVAR("sv_cheatpc", "125"); cvar_t sv_cheatspeedchecktime = CVAR("sv_cheatspeedchecktime", "30"); cvar_t sv_playermodelchecks = CVAR("sv_playermodelchecks", "0"); +cvar_t sv_ping_ignorepl = CVARD("sv_ping_ignorepl", "0", "If 1, ping times reported for players will ignore the effects of packetloss on ping times. 0 is slightly more honest, but less useful for connection diagnosis."); cvar_t sv_cmdlikercon = SCVAR("sv_cmdlikercon", "0"); //set to 1 to allow a password of username:password instead of the correct rcon password. cvar_t cmd_allowaccess = SCVAR("cmd_allowaccess", "0"); //set to 1 to allow cmd to execute console commands on the server. @@ -289,52 +290,77 @@ void SV_New_f (void) ClientReliableWrite_Byte (host_client, 0); ClientReliableWrite_String (host_client, gamedir); - splitnum = 0; - for (split = host_client; split; split = split->controlled) + if (host_client->fteprotocolextensions2 & PEXT2_MAXPLAYERS) { - switch(svs.gametype) + /*is this a sane way to do it? or should we split the spectator thing off entirely?*/ + ClientReliableWrite_Byte (host_client, sv.allocated_client_slots); + splitnum = 0; + for (split = host_client, splitnum = 0; split; split = split->controlled) + splitnum++; + ClientReliableWrite_Byte (host_client, (split->spectator?128:0) | splitnum); + for (split = host_client; split; split = split->controlled) { -#ifdef HLSERVER - case GT_HALFLIFE: - playernum = split - svs.clients; - break; -#endif -#ifdef Q2SERVER - case GT_QUAKE2: - playernum = Q2NUM_FOR_EDICT(split->q2edict)-1; - break; -#endif - default: playernum = NUM_FOR_EDICT(svprogfuncs, split->edict)-1; - } -#ifdef SERVER_DEMO_PLAYBACK - if (sv.demostate) - { - playernum = (MAX_CLIENTS-1-splitnum)|128; - } - else -#endif - if (split->spectator) - playernum |= 128; - - if (sv.state == ss_cinematic) - playernum = -1; - - if (ISQ2CLIENT(host_client)) - ClientReliableWrite_Short (host_client, playernum); - else + if (sv.state == ss_cinematic) + playernum = -1; ClientReliableWrite_Byte (host_client, playernum); - split->state = cs_connected; - split->connection_started = realtime; - #ifdef SVRANKING - split->stats_started = realtime; - #endif - splitnum++; + split->state = cs_connected; + split->connection_started = realtime; + #ifdef SVRANKING + split->stats_started = realtime; + splitnum++; + } } + else + { + splitnum = 0; + for (split = host_client; split; split = split->controlled) + { + switch(svs.gametype) + { + #ifdef HLSERVER + case GT_HALFLIFE: + playernum = split - svs.clients; + break; + #endif + #ifdef Q2SERVER + case GT_QUAKE2: + playernum = Q2NUM_FOR_EDICT(split->q2edict)-1; + break; + #endif + default: + playernum = NUM_FOR_EDICT(svprogfuncs, split->edict)-1; + } + #ifdef SERVER_DEMO_PLAYBACK + if (sv.demostate) + { + playernum = (MAX_CLIENTS-1-splitnum)|128; + } + else + #endif + if (split->spectator) + playernum |= 128; - if (host_client->fteprotocolextensions & PEXT_SPLITSCREEN) - ClientReliableWrite_Byte (host_client, 128); + if (sv.state == ss_cinematic) + playernum = -1; + + if (ISQ2CLIENT(host_client)) + ClientReliableWrite_Short (host_client, playernum); + else + ClientReliableWrite_Byte (host_client, playernum); + + split->state = cs_connected; + split->connection_started = realtime; + #ifdef SVRANKING + split->stats_started = realtime; + #endif + splitnum++; + } + + if (host_client->fteprotocolextensions & PEXT_SPLITSCREEN) + ClientReliableWrite_Byte (host_client, 128); + } // send full levelname #ifdef SERVER_DEMO_PLAYBACK @@ -1244,7 +1270,7 @@ void SVQW_PreSpawn_f (void) if (state->hexen2flags || state->trans || state->modelindex >= 256 || state->frame > 255 || state->scale || state->abslight) { MSG_WriteByte(&host_client->netchan.message, svc_spawnstatic2); - SV_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions); + SVQW_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions); continue; } } @@ -1305,7 +1331,7 @@ void SVQW_PreSpawn_f (void) else if (host_client->fteprotocolextensions & PEXT_SPAWNSTATIC2) { MSG_WriteByte(&host_client->netchan.message, svcfte_spawnbaseline2); - SV_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions); + SVQW_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions); } else if (state->modelindex < 256) { @@ -1601,6 +1627,7 @@ void SV_Begin_Core(client_t *split) ge->ClientBegin(split->q2edict); split->istobeloaded = false; + sv.spawned_client_slots++; } else #endif @@ -4751,10 +4778,10 @@ void SV_Pext_f(void) switch(strtoul(tag, NULL, 0)) { case PROTOCOL_VERSION_FTE: - host_client->fteprotocolextensions = strtoul(val, NULL, 0) & svs.fteprotocolextensions; + host_client->fteprotocolextensions = strtoul(val, NULL, 0) & Net_PextMask(1); break; case PROTOCOL_VERSION_FTE2: - host_client->fteprotocolextensions2 = strtoul(val, NULL, 0) & svs.fteprotocolextensions2; + host_client->fteprotocolextensions2 = strtoul(val, NULL, 0) & Net_PextMask(2); break; } } @@ -5231,14 +5258,14 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node ) if (check->v->owner == pl) continue; // player's own missile - if (check->v->solid == SOLID_BSP + if (check == player) + continue; + if ((check->v->solid == SOLID_TRIGGER && check->v->skin < 0) || check->v->solid == SOLID_BSP || check->v->solid == SOLID_BBOX || check->v->solid == SOLID_SLIDEBOX //|| (check->v->solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it ) { - if (check == player) - continue; for (i=0 ; i<3 ; i++) if (check->v->absmin[i] > pmove_maxs[i] @@ -5259,6 +5286,28 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node ) VectorCopy (check->v->origin, pe->origin); pe->info = NUM_FOR_EDICT(svprogfuncs, check); + pe->nonsolid = check->v->solid == SOLID_TRIGGER; + switch((int)check->v->skin) + { + case Q1CONTENTS_WATER: + pe->forcecontentsmask = FTECONTENTS_WATER; + break; + case Q1CONTENTS_LAVA: + pe->forcecontentsmask = FTECONTENTS_LAVA; + break; + case Q1CONTENTS_SLIME: + pe->forcecontentsmask = FTECONTENTS_SLIME; + break; + case Q1CONTENTS_SKY: + pe->forcecontentsmask = FTECONTENTS_SKY; + break; + case -16: + pe->forcecontentsmask = FTECONTENTS_LADDER; + break; + default: + pe->forcecontentsmask = 0; + break; + } if (check->v->solid == SOLID_BSP) { if(progstype != PROG_H2) @@ -5709,7 +5758,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) pmove.numphysent = 1; pmove.physents[0].model = sv.world.worldmodel; pmove.cmd = *ucmd; - pmove.hullnum = SV_HullNumForPlayer(sv_player->xv->hull, sv_player->v->mins, sv_player->v->maxs); + pmove.skipent = -1; movevars.entgravity = host_client->entgravity/movevars.gravity; movevars.maxspeed = host_client->maxspeed; @@ -6064,9 +6113,12 @@ void SV_ExecuteClientMessage (client_t *cl) { //split screen doesn't always have frames. frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK]; - if (cl->lastsequence_acknoledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged) + if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged) { - frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please + /*note that if there is packetloss, we can change a single frame's ping_time multiple times + this means that the 'ping' is more latency than ping times*/ + if (frame->ping_time == -1 || !sv_ping_ignorepl.ival) + frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please if (cl->spectator) cl->delay = 0; @@ -6087,15 +6139,18 @@ void SV_ExecuteClientMessage (client_t *cl) } } #ifdef PEXT_CSQC - if (cl->lastsequence_acknoledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged) + if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged) { - for (i = cl->lastsequence_acknoledged+1; i < cl->netchan.incoming_acknowledged; i++) + for (i = cl->lastsequence_acknowledged+1; i < cl->netchan.incoming_acknowledged; i++) SV_CSQC_DroppedPacket(cl, i); } else + { + /*too much loss, we don't know what was sent when, so reset the entire entity state*/ SV_CSQC_DropAll(cl); + } #endif - cl->lastsequence_acknoledged = cl->netchan.incoming_acknowledged; + cl->lastsequence_acknowledged = cl->netchan.incoming_acknowledged; if (sv_antilag.ival) { @@ -6137,6 +6192,7 @@ void SV_ExecuteClientMessage (client_t *cl) // save time for ping calculations if (cl->frameunion.frames) { //split screen doesn't always have frames. + cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].sequence = cl->netchan.outgoing_sequence; cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime; cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1; cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].move_msecs = -1; diff --git a/engine/server/svhl_game.c b/engine/server/svhl_game.c index 422320d8d..6844acfe7 100644 --- a/engine/server/svhl_game.c +++ b/engine/server/svhl_game.c @@ -1533,26 +1533,6 @@ extern vec3_t player_maxs; continue; pe = &pmove.physents[pmove.numphysent]; - if (other->v.modelindex) - { - pe->model = sv.models[other->v.modelindex]; - if (pe->model && pe->model->type != mod_brush) - pe->model = NULL; - } - else - pe->model = NULL; - pmove.numphysent++; - pe->info = other - SVHL_Edict; - VectorCopy(other->v.origin, pe->origin); - VectorCopy(other->v.mins, pe->mins); - VectorCopy(other->v.maxs, pe->maxs); - VectorCopy(other->v.angles, pe->angles); - - if (other->v.solid == SOLID_NOT || other->v.solid == SOLID_TRIGGER) - pe->nonsolid = true; - else - pe->nonsolid = false; - switch(other->v.skin) { case Q1CONTENTS_EMPTY: @@ -1580,6 +1560,30 @@ extern vec3_t player_maxs; pe->forcecontentsmask = 0; break; } + + if (other->v.solid == SOLID_NOT || other->v.solid == SOLID_TRIGGER) + { + if (!pe->forcecontentsmask) + continue; + pe->nonsolid = true; + } + else + pe->nonsolid = false; + + if (other->v.modelindex) + { + pe->model = sv.models[other->v.modelindex]; + if (pe->model && pe->model->type != mod_brush) + pe->model = NULL; + } + else + pe->model = NULL; + pmove.numphysent++; + pe->info = other - SVHL_Edict; + VectorCopy(other->v.origin, pe->origin); + VectorCopy(other->v.mins, pe->mins); + VectorCopy(other->v.maxs, pe->maxs); + VectorCopy(other->v.angles, pe->angles); } } diff --git a/engine/server/svq2_ents.c b/engine/server/svq2_ents.c index 412a6e53c..d45a3b9bb 100644 --- a/engine/server/svq2_ents.c +++ b/engine/server/svq2_ents.c @@ -541,7 +541,7 @@ void SVQ2_WritePlayerstateToClient (q2client_frame_t *from, q2client_frame_t *to SV_WriteFrameToClient ================== */ -void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg) +void SVQ2_WriteFrameToClient (client_t *client, sizebuf_t *msg) { q2client_frame_t *frame, *oldframe; int lastframe; @@ -602,7 +602,7 @@ copies off the playerstat and areabits. ============= */ void SVQ2_Ents_Init(void); -void SV_BuildClientFrame (client_t *client) +void SVQ2_BuildClientFrame (client_t *client) { int e, i; vec3_t org; diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index 55ab0dc39..b9ac8c933 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -736,6 +736,9 @@ qboolean SVQ2_InitGameProgs(void) */ } + Cvar_ForceSet(Cvar_Get("game", "", CVAR_LATCH, "Q2 compat"), FS_GetGamedir()); + Cvar_ForceSet(Cvar_Get("basedir", "", CVAR_LATCH, "Q2 compat"), FS_GetBasedir()); + ge = (game_export_t *)Sys_GetGameAPI ((game_import_t*)&import); if (!ge) diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index d67ccf47e..77cc51be2 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -1773,6 +1773,7 @@ void SVQ3_ClientCommand(client_t *cl) void SVQ3_ClientBegin(client_t *cl) { VM_Call(q3gamevm, GAME_CLIENT_BEGIN, (int)(cl-svs.clients)); + sv.spawned_client_slots++; } void SVQ3_ClientThink(client_t *cl) @@ -2360,7 +2361,7 @@ void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3) q3->apos.trBase[1] = 0; q3->pos.trDelta[2] = 0; q3->apos.trBase[0] = 0; - q3->event = q1->event; + q3->event = 0; q3->angles2[1] = 0; q3->eType = 0; q3->torsoAnim = q1->skinnum; @@ -2382,12 +2383,12 @@ void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3) q3->powerups = q1->effects; q3->modelindex = q1->modelindex; q3->otherEntityNum2 = 0; - q3->loopSound = q1->sound; + q3->loopSound = 0; q3->generic1 = q1->trans; - q3->origin2[2] = q1->old_origin[2]; - q3->origin2[0] = q1->old_origin[0]; - q3->origin2[1] = q1->old_origin[1]; - q3->modelindex2 = q1->modelindex2; + q3->origin2[2] = 0;//q1->old_origin[2]; + q3->origin2[0] = 0;//q1->old_origin[0]; + q3->origin2[1] = 0;//q1->old_origin[1]; + q3->modelindex2 = 0;//q1->modelindex2; q3->angles[0] = q1->angles[0]; q3->time = 0; q3->apos.trTime = 0; @@ -3068,13 +3069,13 @@ void SVQ3_ParseClientMessage(client_t *client) Con_Printf(CON_WARNING "WARNING: Junk at end of packet for client %s\n", client->name ); } }; -void SVQ3_HandleClient(void) +qboolean SVQ3_HandleClient(void) { int i; int qport; if (net_message.cursize<6) - return; //urm. :/ + return false; //urm. :/ MSG_BeginReading(msg_nullnetprim); MSG_ReadBits(32); @@ -3088,19 +3089,22 @@ void SVQ3_HandleClient(void) continue; if (!NET_CompareBaseAdr(svs.clients[i].netchan.remote_address, net_from)) continue; + if (!ISQ3CLIENT(&svs.clients[i])) + continue; //found them. break; } if (i == sv.allocated_client_slots) - return; //nope + return false; //nope if (!SVQ3_Netchan_Process(&svs.clients[i])) { - return; // wasn't accepted for some reason + return true; // wasn't accepted for some reason } SVQ3_ParseClientMessage(&svs.clients[i]); + return true; } void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and let the gamecode know of it.