diff --git a/client/global/view.cpp b/client/global/view.cpp index dd937f8b..94e031d5 100644 --- a/client/global/view.cpp +++ b/client/global/view.cpp @@ -906,29 +906,38 @@ void V_CalcFirstPersonRefdef( ref_params_t *pparams ) V_DropPunchAngle( pparams->frametime, ev_punchangle ); static float oldz = 0; + float newz; - if( pparams->smoothing && pparams->onground && pparams->origin[2] - oldz > 0 ) + // stair smoothing + newz = pparams->vieworg[2]; + oldz -= newz; + oldz += (pparams->time - pparams->oldtime) * 100.0f; // speed of smooth + oldz = bound( -pparams->movevars->stepheight, oldz, 0 ); + pparams->vieworg[2] += oldz; + view->v.origin[2] += oldz; + oldz += newz; +/* + if( pparams->onground && pparams->vieworg[2] - oldz > 0 ) { float steptime; - ALERT( at_console, "smooth stair clibling\n" ); steptime = pparams->time - lasttime; if( steptime < 0 ) steptime = 0; oldz += steptime * 150; - if( oldz > pparams->origin[2]) - oldz = pparams->origin[2]; - if( pparams->origin[2] - oldz > pparams->movevars->stepheight ) - oldz = pparams->origin[2] - pparams->movevars->stepheight; - pparams->vieworg[2] += oldz - pparams->origin[2]; - view->v.origin[2] += oldz - pparams->origin[2]; + if( oldz > pparams->vieworg[2]) + oldz = pparams->vieworg[2]; + if( pparams->vieworg[2] - oldz > pparams->movevars->stepheight ) + oldz = pparams->vieworg[2] - pparams->movevars->stepheight; + pparams->vieworg[2] += oldz - pparams->vieworg[2]; + view->v.origin[2] += oldz - pparams->vieworg[2]; } - else oldz = pparams->origin[2]; - + else oldz = pparams->vieworg[2]; +*/ static Vector lastorg; Vector delta; - delta = pparams->origin - lastorg; + delta = pparams->vieworg - lastorg; if( delta.Length() != 0.0 ) { @@ -936,7 +945,7 @@ void V_CalcFirstPersonRefdef( ref_params_t *pparams ) ViewInterp.OriginTime[ViewInterp.CurrentOrigin & ORIGIN_MASK] = pparams->time; ViewInterp.CurrentOrigin++; - lastorg = pparams->origin; + lastorg = pparams->vieworg; } V_InterpolateOrigin( pparams ); // smooth moving in multiplayer diff --git a/common/ref_params.h b/common/ref_params.h index 42bfaff4..0fa33e70 100644 --- a/common/ref_params.h +++ b/common/ref_params.h @@ -47,7 +47,6 @@ typedef struct ref_params_s edict_t *onground; // pointer to onground entity byte *areabits; // come from server, contains visible areas list int waterlevel; - int smoothing; // input vec3_t velocity; diff --git a/common/studio.h b/common/studio.h new file mode 100644 index 00000000..231df040 --- /dev/null +++ b/common/studio.h @@ -0,0 +1,337 @@ +//======================================================================= +// Copyright XashXT Group 2008 © +// studio_ref.h - studio model reference +//======================================================================= +#ifndef STUDIO_REF_H +#define STUDIO_REF_H + +/* +============================================================================== + +STUDIO MODELS + +Studio models are position independent, so the cache manager can move them. +============================================================================== +*/ + +// header +#define STUDIO_VERSION 10 +#define IDSTUDIOHEADER (('T'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDST" +#define IDSEQGRPHEADER (('Q'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSQ" + +// studio limits +#define MAXSTUDIOTRIANGLES 32768 // max triangles per model +#define MAXSTUDIOVERTS 4096 // max vertices per submodel +#define MAXSTUDIOSEQUENCES 256 // total animation sequences +#define MAXSTUDIOSKINS 128 // total textures +#define MAXSTUDIOSRCBONES 512 // bones allowed at source movement +#define MAXSTUDIOBONES 128 // total bones actually used +#define MAXSTUDIOMODELS 32 // sub-models per model +#define MAXSTUDIOBODYPARTS 32 // body parts per submodel +#define MAXSTUDIOGROUPS 16 // sequence groups (e.g. barney01.mdl, barney02.mdl, e.t.c) +#define MAXSTUDIOANIMATIONS 512 // max frames per sequence +#define MAXSTUDIOMESHES 256 // max textures per model +#define MAXSTUDIOEVENTS 1024 // events per model +#define MAXSTUDIOPIVOTS 256 // pivot points +#define MAXSTUDIOBLENDS 16 // max anim blends +#define MAXSTUDIOCONTROLLERS 16 // max controllers per model +#define MAXSTUDIOATTACHMENTS 16 // max attachments per model + +// model global flags +#define STUDIO_STATIC 0x0001 // model without anims +#define STUDIO_RAGDOLL 0x0002 // ragdoll animation pose + +// lighting & rendermode options +#define STUDIO_NF_FLATSHADE 0x0001 +#define STUDIO_NF_CHROME 0x0002 +#define STUDIO_NF_FULLBRIGHT 0x0004 +#define STUDIO_NF_COLORMAP 0x0008 // can changed by colormap command +#define STUDIO_NF_BLENDED 0x0010 // rendering as semiblended +#define STUDIO_NF_ADDITIVE 0x0020 // rendering with additive mode +#define STUDIO_NF_TRANSPARENT 0x0040 // use texture with alpha channel + +// motion flags +#define STUDIO_X 0x0001 +#define STUDIO_Y 0x0002 +#define STUDIO_Z 0x0004 +#define STUDIO_XR 0x0008 +#define STUDIO_YR 0x0010 +#define STUDIO_ZR 0x0020 +#define STUDIO_LX 0x0040 +#define STUDIO_LY 0x0080 +#define STUDIO_LZ 0x0100 +#define STUDIO_AX 0x0200 +#define STUDIO_AY 0x0400 +#define STUDIO_AZ 0x0800 +#define STUDIO_AXR 0x1000 +#define STUDIO_AYR 0x2000 +#define STUDIO_AZR 0x4000 +#define STUDIO_TYPES 0x7FFF +#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance + +// bonecontroller types +#define STUDIO_MOUTH 4 + +// sequence flags +#define STUDIO_LOOPING 0x0001 + +// render flags +#define STUDIO_RENDER 0x0001 +#define STUDIO_EVENTS 0x0002 +#define STUDIO_MIRROR 0x0004 // a local player in mirror + +// bone flags +#define STUDIO_HAS_NORMALS 0x0001 +#define STUDIO_HAS_VERTICES 0x0002 +#define STUDIO_HAS_BBOX 0x0004 +#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them + +typedef struct +{ + int ident; + int version; + + char name[64]; + int length; + + vec3_t eyeposition; // ideal eye position + vec3_t min; // ideal movement hull size + vec3_t max; + + vec3_t bbmin; // clipping bounding box + vec3_t bbmax; + + int flags; + + int numbones; // bones + int boneindex; + + int numbonecontrollers; // bone controllers + int bonecontrollerindex; + + int numhitboxes; // complex bounding boxes + int hitboxindex; + + int numseq; // animation sequences + int seqindex; + + int numseqgroups; // demand loaded sequences + int seqgroupindex; + + int numtextures; // raw textures + int textureindex; + int texturedataindex; + + int numskinref; // replaceable textures + int numskinfamilies; + int skinindex; + + int numbodyparts; + int bodypartindex; + + int numattachments; // queryable attachable points + int attachmentindex; + + int soundtable; + int soundindex; + int soundgroups; + int soundgroupindex; + + int numtransitions; // animation node to animation node transition graph + int transitionindex; +} dstudiohdr_t; + +// header for demand loaded sequence group data +typedef struct +{ + int id; + int version; + + char name[64]; + int length; +} dstudioseqhdr_t; + +// bones +typedef struct +{ + char name[32]; // bone name for symbolic links + int parent; // parent bone + int flags; // ?? + int bonecontroller[6]; // bone controller index, -1 == none + float value[6]; // default DoF values + float scale[6]; // scale for delta DoF values +} dstudiobone_t; + +// bone controllers +typedef struct +{ + int bone; // -1 == 0 + int type; // X, Y, Z, XR, YR, ZR, M + float start; + float end; + int rest; // byte index value at rest + int index; // 0-3 user set controller, 4 mouth +} dstudiobonecontroller_t; + +// intersection boxes +typedef struct +{ + int bone; + int group; // intersection group + vec3_t bbmin; // bounding box + vec3_t bbmax; +} dstudiobbox_t; + +// demand loaded sequence groups +typedef struct +{ + char label[32]; // textual name + char name[64]; // file name + void *cache; // cache index pointer (only in memory) + int data; // hack for group 0 +} dstudioseqgroup_t; + +// sequence descriptions +typedef struct +{ + char label[32]; // sequence label (name) + + float fps; // frames per second + int flags; // looping/non-looping flags + + int activity; + int actweight; + + int numevents; + int eventindex; + + int numframes; // number of frames per sequence + + int numpivots; // number of foot pivots + int pivotindex; + + int motiontype; + int motionbone; + vec3_t linearmovement; + int automoveposindex; + int automoveangleindex; + + vec3_t bbmin; // per sequence bounding box + vec3_t bbmax; + + int numblends; + int animindex; // mstudioanim_t pointer relative to start of sequence group data + // [blend][bone][X, Y, Z, XR, YR, ZR] + + int blendtype[2]; // X, Y, Z, XR, YR, ZR + float blendstart[2]; // starting value + float blendend[2]; // ending value + int blendparent; + + int seqgroup; // sequence group for demand loading + + int entrynode; // transition node at entry + int exitnode; // transition node at exit + int nodeflags; // transition rules + + int nextseq; // auto advancing sequences +} dstudioseqdesc_t; + +// events +#include "studio_event.h" + +// pivots +typedef struct +{ + vec3_t org; // pivot point + int start; + int end; +} dstudiopivot_t; + +// attachment +typedef struct +{ + char name[32]; + int type; + int bone; + vec3_t org; // attachment point + vec3_t vectors[3]; +} dstudioattachment_t; + +typedef struct +{ + unsigned short offset[6]; +} dstudioanim_t; + +// animation frames +typedef union +{ + struct + { + byte valid; + byte total; + } num; + short value; +} dstudioanimvalue_t; + + +// body part index +typedef struct +{ + char name[64]; + int nummodels; + int base; + int modelindex; // index into models array +} dstudiobodyparts_t; + +// skin info +typedef struct +{ + char name[64]; + int flags; + int width; + int height; + + union + { + int index; // disk: offset at start of buffer + shader_t shader; // ref: shader number + }; +} dstudiotexture_t; + +// skin families +// short index[skinfamilies][skinref] // skingroup info + +// studio models +typedef struct +{ + char name[64]; + + int type; + float boundingradius; // software stuff + + int nummesh; + int meshindex; + + int numverts; // number of unique vertices + int vertinfoindex; // vertex bone info + int vertindex; // vertex vec3_t + int numnorms; // number of unique surface normals + int norminfoindex; // normal bone info + int normindex; // normal vec3_t + + int numgroups; // deformation groups + int groupindex; +} dstudiomodel_t; + +// meshes +typedef struct +{ + int numtris; + int triindex; + int skinref; + int numnorms; // per mesh normals + int normindex; // normal vec3_t +} dstudiomesh_t; + +#endif//STUDIO_REF_H \ No newline at end of file diff --git a/engine/client/cl_cmds.c b/engine/client/cl_cmds.c index 5978c7df..fc4c3c4d 100644 --- a/engine/client/cl_cmds.c +++ b/engine/client/cl_cmds.c @@ -226,13 +226,13 @@ timerefres [noflip] void SCR_TimeRefresh_f( void ) { int i; - int start, stop; - float time; + double start, stop; + double time; if ( cls.state != ca_active ) return; - start = Sys_Milliseconds(); + start = Sys_DoubleTime(); if( Cmd_Argc() == 2 ) { @@ -240,8 +240,8 @@ void SCR_TimeRefresh_f( void ) re->BeginFrame(); for( i = 0; i < 128; i++ ) { - cl.refdef.viewangles[1] = i/128.0 * 360.0f; - re->RenderFrame (&cl.refdef); + cl.refdef.viewangles[1] = i / 128.0 * 360.0f; + re->RenderFrame( &cl.refdef ); } re->EndFrame(); } @@ -249,7 +249,7 @@ void SCR_TimeRefresh_f( void ) { for( i = 0; i < 128; i++ ) { - cl.refdef.viewangles[1] = i/128.0 * 360.0f; + cl.refdef.viewangles[1] = i / 128.0 * 360.0f; re->BeginFrame(); re->RenderFrame(&cl.refdef); @@ -257,8 +257,8 @@ void SCR_TimeRefresh_f( void ) } } - stop = Sys_Milliseconds(); - time = (stop - start) / 1000.0f; + stop = Sys_DoubleTime (); + time = (stop - start); Msg( "%f seconds (%f fps)\n", time, 128 / time ); } @@ -271,5 +271,5 @@ viewpos */ void SCR_Viewpos_f( void ) { - Msg("(%g %g %g)\n", cl.refdef.vieworg[0], cl.refdef.vieworg[1], cl.refdef.vieworg[2] ); + Msg( "( %g %g %g )\n", cl.refdef.vieworg[0], cl.refdef.vieworg[1], cl.refdef.vieworg[2] ); } \ No newline at end of file diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index b7318c90..5e6a1d30 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -286,8 +286,6 @@ void CL_ParseFrame( sizebuf_t *msg ) frame_t *old; memset( &cl.frame, 0, sizeof( cl.frame )); - cl.mtime[1] = cl.mtime[0]; - cl.mtime[0] = MSG_ReadFloat( msg ); cl.frame.serverframe = MSG_ReadLong( msg ); cl.frame.deltaframe = MSG_ReadLong( msg ); cl.surpressCount = MSG_ReadByte( msg ); diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 689a84a8..81eda1a1 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -409,14 +409,10 @@ CL_FinishMove */ void CL_FinishMove( usercmd_t *cmd ) { - int i, ms; - - // send milliseconds of time to apply the move - // FIXME: return sv.time to let server calculate ping - ms = host.frametime * 1000; - if( ms > 250 ) ms = 100; // time was unreasonable - cmd->msec = ms; + int i; + // so server can get ping times + cmd->time = cl.mtime[0]; CL_ClampPitch(); for( i = 0; i < 3; i++ ) @@ -476,21 +472,19 @@ void CL_SendCmd( void ) usercmd_t *cmd, *oldcmd; usercmd_t nullcmd; int checksumIndex; - int curtime; // build a command even if not connected // save this command off for prediction i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1); cmd = &cl.cmds[i]; - curtime = Sys_Milliseconds(); *cmd = CL_CreateCmd (); - if(cls.state == ca_disconnected || cls.state == ca_connecting) + if( cls.state == ca_disconnected || cls.state == ca_connecting ) return; // ignore commands for demo mode - if(cls.state == ca_cinematic || cls.demoplayback) + if( cls.state == ca_cinematic || cls.demoplayback ) return; if( cls.state == ca_connected ) @@ -501,7 +495,7 @@ void CL_SendCmd( void ) } // send a userinfo update if needed - if (userinfo_modified) + if( userinfo_modified ) { userinfo_modified = false; MSG_WriteByte (&cls.netchan.message, clc_userinfo); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index ccedd2ed..5e92c76a 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -387,9 +387,9 @@ void CL_Disconnect( void ) cls.state = ca_disconnected; } -void CL_Disconnect_f (void) +void CL_Disconnect_f( void ) { - Host_Error("Disconnected from server\n"); + Host_Error( "Disconnected from server\n" ); } @@ -779,12 +779,12 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) Cmd_TokenizeString( s ); c = Cmd_Argv(0); - MsgDev(D_INFO, "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c ); + MsgDev( D_INFO, "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c ); // server connection - if(!com.strcmp( c, "client_connect")) + if( !com.strcmp( c, "client_connect" )) { - if (cls.state == ca_connected) + if( cls.state == ca_connected ) { Msg ("Dup connect received. Ignored.\n"); return; @@ -888,7 +888,7 @@ void CL_PacketEvent( netadr_t from, sizebuf_t *msg ) } // packet from server - if (!NET_CompareAdr( from, cls.netchan.remote_address)) + if (!NET_CompareAdr( from, cls.netchan.remote_address )) { MsgDev( D_WARN, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( from )); return; @@ -908,9 +908,19 @@ void CL_PacketEvent( netadr_t from, sizebuf_t *msg ) } } +void CL_ReadNetMessage( void ) +{ + while( NET_GetPacket( NS_CLIENT, &net_from, &net_message )) + { + CL_PacketEvent( net_from, &net_message ); + } +} + void CL_ReadPackets( void ) { - if( cls.demoplayback ) CL_ReadDemoMessage(); + if( cls.demoplayback ) + CL_ReadDemoMessage(); + else CL_ReadNetMessage(); if(NET_IsLocalAddress( cls.netchan.remote_address )) return; @@ -1251,10 +1261,12 @@ void CL_Init( void ) Con_Init(); VID_Init(); + if( !CL_LoadProgs( "client" )) - { Host_Error( "CL_InitGame: can't initialize client.dll\n" ); - } + + MSG_Init( &net_message, net_message_buffer, sizeof( net_message_buffer )); + UI_Init(); SCR_Init(); CL_InitLocal(); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 99435084..deb7d4c0 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -509,6 +509,10 @@ void CL_ParseServerMessage( sizebuf_t *msg ) case svc_print: Con_Print( va( "^6%s\n", MSG_ReadString( msg ))); break; + case svc_time: + cl.mtime[1] = cl.mtime[0]; + cl.mtime[0] = MSG_ReadFloat( msg ); + break; case svc_frame: CL_ParseFrame( msg ); break; diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index 9afb3070..5dfcca78 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -122,7 +122,6 @@ void V_SetupRefDef( void ) cl.refdef.paused = cl_paused->integer; cl.refdef.predicting = cl_predict->integer; cl.refdef.waterlevel = clent->v.waterlevel; - cl.refdef.smoothing = 1; // get rid of this cl.refdef.nextView = 0; // calculate the origin diff --git a/engine/common/input.c b/engine/common/input.c index 7a9558ea..022d40ef 100644 --- a/engine/common/input.c +++ b/engine/common/input.c @@ -20,7 +20,6 @@ int in_mouse_oldbuttonstate; int window_center_x, window_center_y; uint in_mouse_wheel; RECT window_rect; -POINT cur_pos; cvar_t *scr_xpos; // X coordinate of window position cvar_t *scr_ypos; // Y coordinate of window position diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 1d4bd9f4..33c40a03 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -59,33 +59,13 @@ such as during the connection stage while waiting for the client to load, then a packet only needs to be delivered if there is something in the unacknowledged reliable */ - -#define MAX_LOOPBACK 4 -#define MASK_LOOPBACK (MAX_LOOPBACK - 1) - cvar_t *net_showpackets; cvar_t *net_showdrop; cvar_t *net_qport; -static char *net_src[2] = -{ -"client", -"server" -}; - -typedef struct -{ - byte data[MAX_MSGLEN]; - int datalen; -} loopmsg_t; - -typedef struct -{ - loopmsg_t msgs[MAX_LOOPBACK]; - int get, send; -} loopback_t; - -loopback_t loopbacks[2]; +netadr_t net_from; +sizebuf_t net_message; +byte net_message_buffer[MAX_MSGLEN]; /* =============== @@ -113,7 +93,7 @@ called to open a channel to a remote system */ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) { - memset( chan, 0, sizeof(*chan)); + Mem_Set( chan, 0, sizeof( *chan )); chan->sock = sock; chan->remote_address = adr; @@ -122,6 +102,7 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) chan->incoming_sequence = 0; chan->outgoing_sequence = 1; chan->compress = true; + chan->rate = 1.0f / 2500; // inital value of rate MSG_Init( &chan->message, chan->message_buf, sizeof(chan->message_buf)); } @@ -167,6 +148,20 @@ void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, char *format, ... ) Netchan_OutOfBand( net_socket, adr, com.strlen( string ), string ); } +/* +=============== +Netchan_CanPacket + +Returns true if the bandwidth choke isn't active +================ +*/ +bool Netchan_CanPacket( netchan_t *chan ) +{ + if( chan->cleartime < host.realtime + MAX_BACKUP * chan->rate ) + return true; + return false; +} + /* =============== Netchan_CanReliable @@ -178,7 +173,7 @@ bool Netchan_CanReliable( netchan_t *chan ) { if( chan->reliable_length ) return false; // waiting for ack - return true; + return Netchan_CanPacket( chan ); } @@ -196,6 +191,14 @@ bool Netchan_NeedReliable( netchan_t *chan ) if( !chan->reliable_length && chan->message.cursize ) send_reliable = true; + if( !chan->reliable_length && chan->message.cursize ) + { + Mem_Copy( chan->reliable_buf, chan->message_buf, chan->message.cursize ); + chan->reliable_length = chan->message.cursize; + chan->message.cursize = 0; + chan->reliable_sequence ^= 1; + } + return send_reliable; } @@ -227,14 +230,6 @@ void Netchan_Transmit( netchan_t *chan, int length, byte *data ) send_reliable = Netchan_NeedReliable( chan ); - if( !chan->reliable_length && chan->message.cursize ) - { - Mem_Copy( chan->reliable_buf, chan->message_buf, chan->message.cursize ); - chan->reliable_length = chan->message.cursize; - chan->message.cursize = 0; - chan->reliable_sequence ^= 1; - } - // write the packet header MSG_Init( &send, send_buf, sizeof(send_buf)); @@ -269,13 +264,23 @@ void Netchan_Transmit( netchan_t *chan, int length, byte *data ) if( !overflow ) MsgDev( D_WARN, "Netchan_Transmit: unreliable msg overflow\n" ); overflow = true; } + if( chan->compress ) Huff_CompressPacket(&send, (chan->sock == NS_CLIENT) ? 10 : 8); + if( chan->cleartime < host.realtime ) + chan->cleartime = host.realtime + send.cursize * chan->rate; + else chan->cleartime += send.cursize * chan->rate; + // send the datagram NET_SendPacket( chan->sock, send.cursize, send.data, chan->remote_address ); if( net_showpackets->value ) + { + if( chan->sock == NS_CLIENT ) MsgDev( D_INFO, "CL " ); + else if( chan->sock == NS_SERVER ) MsgDev( D_INFO, "SV " ); + MsgDev( D_INFO, "Netchan_Transmit: %4i : %sreliable\n", send.cursize, send_reliable ? "" : "un" ); + } } /* @@ -308,7 +313,43 @@ bool Netchan_Process( netchan_t *chan, sizebuf_t *msg ) sequence_ack &= ~(1<<31); if( net_showpackets->value ) + { + if( chan->sock == NS_CLIENT ) MsgDev( D_INFO, "CL " ); + else if( chan->sock == NS_SERVER ) MsgDev( D_INFO, "SV " ); + MsgDev( D_INFO, "Netchan_Process: %4i : %sreliable\n", msg->cursize, recv_reliable ? "" : "un" ); + } + +#if 0 + // get a rate estimation + if( chan->outgoing_sequence - sequence_ack < MAX_LATENT ) + { + int i; + double time, rate; + + i = sequence_ack & (MAX_LATENT - 1); + time = Sys_DoubleTime() - chan->outgoing_time[i]; + time -= 0.1f; // subtract 100 ms + if( time <= 0 ) + { + // gotta be a digital link for <100 ms ping + if( chan->rate > 1.0f / 5000 ) + chan->rate = 1.0f / 5000; + } + else + { + if( chan->outgoing_size[i] < 512 ) + { + // only deal with small messages + rate = chan->outgoing_size[i] / time; + if( rate > 5000 ) rate = 5000; + rate = 1.0f / rate; + if( chan->rate > rate ) + chan->rate = rate; + } + } + } +#endif // discard stale or duplicated packets if( sequence <= chan->incoming_sequence ) @@ -338,186 +379,14 @@ bool Netchan_Process( netchan_t *chan, sizebuf_t *msg ) if( recv_reliable ) chan->incoming_reliable_sequence ^= 1; if( chan->compress ) Huff_DecompressPacket( msg, ( chan->sock == NS_SERVER) ? 10 : 8 ); + // the message can now be read from the current message pointer + // update statistics counters + chan->frame_latency = chan->frame_latency * OLD_AVG + (chan->outgoing_sequence - sequence_ack) * (1.0 - OLD_AVG); + chan->frame_rate = chan->frame_rate * OLD_AVG + (Sys_DoubleTime() - chan->last_received) * (1.0 - OLD_AVG); + chan->good_count += 1; + // the message can now be read from the current message pointer chan->last_received = Sys_DoubleTime (); - return true; -} - -/* -============================================================================= - - NET MISC HELPER FUNCTIONS - -============================================================================= -*/ -/* -=================== -NET_CompareBaseAdr - -Compares without the port -=================== -*/ -bool NET_CompareBaseAdr( netadr_t a, netadr_t b ) -{ - if( a.type != b.type ) return false; - if( a.type == NA_LOOPBACK ) return true; - - if( a.type == NA_IP ) - { - if(!memcmp(a.ip, b.ip, 4 )) - return true; - return false; - } - if (a.type == NA_IPX) - { - if((!memcmp( a.ipx, b.ipx, 10 ))) - return true; - return false; - } - MsgDev( D_ERROR, "NET_CompareBaseAdr: bad address type\n" ); - return false; -} - -bool NET_CompareAdr( netadr_t a, netadr_t b ) -{ - if( a.type != b.type ) - return false; - if( a.type == NA_LOOPBACK ) - return true; - - if( a.type == NA_IP ) - { - if((memcmp(a.ip, b.ip, 4 ) == 0) && a.port == b.port) - return true; - return false; - } - if( a.type == NA_IPX ) - { - if((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port) - return true; - return false; - } - MsgDev( D_ERROR, "NET_CompareAdr: bad address type\n" ); - return false; -} - -bool NET_IsLocalAddress( netadr_t adr ) -{ - return adr.type == NA_LOOPBACK; -} - -/* -============================================================================= - -LOOPBACK BUFFERS FOR LOCAL PLAYER - -============================================================================= -*/ -bool NET_GetLoopPacket( netsrc_t sock, netadr_t *from, sizebuf_t *msg ) -{ - int i; - loopback_t *loop; - - loop = &loopbacks[sock]; - - if( loop->send - loop->get > MAX_LOOPBACK ) - loop->get = loop->send - MAX_LOOPBACK; - - if( loop->get >= loop->send ) - return false; - i = loop->get & MASK_LOOPBACK; - loop->get++; - - Mem_Copy( msg->data, loop->msgs[i].data, loop->msgs[i].datalen ); - msg->cursize = loop->msgs[i].datalen; - memset( from, 0, sizeof(*from)); - from->type = NA_LOOPBACK; - return true; - -} - -void NET_SendLoopPacket( netsrc_t sock, int length, void *data, netadr_t to ) -{ - int i; - loopback_t *loop; - - loop = &loopbacks[sock^1]; - - i = loop->send & MASK_LOOPBACK; - loop->send++; - - Mem_Copy( loop->msgs[i].data, data, length ); - loop->msgs[i].datalen = length; -} - -/* -============================================================================= - - NETCHAN TRANSMIT\RECEIVED UTILS - -============================================================================= -*/ -void NET_SendPacket( netsrc_t sock, int length, void *data, netadr_t to ) -{ - // sequenced packets are shown in netchan, so just show oob - if( net_showpackets->integer && *(int *)data == -1 ) - MsgDev( D_INFO, "send packet %4i\n", length); - - if( to.type == NA_LOOPBACK ) - { - NET_SendLoopPacket( sock, length, data, to ); - return; - } - - if( to.type == NA_BAD ) return; - Sys_SendPacket( length, data, to ); -} - -/* -============= -NET_StringToAdr - -Traps "localhost" for loopback, passes everything else to system -============= -*/ -bool NET_StringToAdr( const char *s, netadr_t *a ) -{ - bool r; - char *port, base[MAX_SYSPATH]; - - if(!com.strcmp( s, "localhost" )) - { - memset( a, 0, sizeof(*a)); - a->type = NA_LOOPBACK; - return true; - } - - // look for a port number - com.strncpy( base, s, sizeof( base )); - port = com.strstr( base, ":" ); - if( port ) - { - *port = 0; - port++; - } - - r = Sys_StringToAdr( base, a ); - - if( !r ) - { - a->type = NA_BAD; - return false; - } - - // inet_addr returns this if out of range - if( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3] == 255 ) - { - a->type = NA_BAD; - return false; - } - - if( port ) a->port = BigShort((short)com.atoi( port )); - else a->port = BigShort( PORT_SERVER ); return true; } \ No newline at end of file diff --git a/engine/common/net_msg.c b/engine/common/net_msg.c index 7b735d03..58cd30d9 100644 --- a/engine/common/net_msg.c +++ b/engine/common/net_msg.c @@ -111,7 +111,7 @@ static net_field_t ent_fields[] = // probably usercmd_t never reached 32 field integer limit (in theory of course) static net_field_t cmd_fields[] = { -{ CM_FIELD(msec), NET_BYTE, true }, +{ CM_FIELD(time), NET_FLOAT, true }, { CM_FIELD(angles[0]), NET_ANGLE, false }, { CM_FIELD(angles[1]), NET_ANGLE, false }, { CM_FIELD(angles[2]), NET_ANGLE, false }, diff --git a/engine/common/net_msg.h b/engine/common/net_msg.h index 09de9d37..6a687b29 100644 --- a/engine/common/net_msg.h +++ b/engine/common/net_msg.h @@ -61,6 +61,7 @@ enum svc_ops_e svc_setangle, // [short short short] set the view angle to this absolute value svc_print, // [byte] id [string] null terminated string svc_crosshairangle, // [short][short][short] + svc_time, // [float] sv.time }; // client to server @@ -232,12 +233,11 @@ NET ============================================================== */ -bool NET_GetLoopPacket( netsrc_t sock, netadr_t *from, sizebuf_t *msg ); -void NET_SendPacket( netsrc_t sock, int length, void *data, netadr_t to ); -bool NET_StringToAdr( const char *s, netadr_t *a ); -bool NET_CompareBaseAdr( netadr_t a, netadr_t b ); -bool NET_CompareAdr( netadr_t a, netadr_t b ); -bool NET_IsLocalAddress( netadr_t adr ); + +#define OLD_AVG 0.99 // total = oldtotal * OLD_AVG + new * (1 - OLD_AVG) +#define MAX_LATENT 32 +#define MAX_BACKUP 200 + typedef struct netchan_s { @@ -250,9 +250,21 @@ typedef struct netchan_s double last_received; // for timeouts double last_sent; // for retransmits + // the statistics are cleared at each client begin, because + // the server connecting process gives a bogus picture of the data + float frame_latency; // rolling average + float frame_rate; + + int drop_count; // dropped packets, cleared each level + int good_count; // cleared each level + netadr_t remote_address; int qport; // qport value to write when transmitting + // bandwidth estimator + double cleartime; // if realtime > nc->cleartime, free to go + double rate; // seconds / byte + // sequencing variables int incoming_sequence; int incoming_acknowledged; @@ -272,8 +284,16 @@ typedef struct netchan_s int reliable_length; byte reliable_buf[MAX_MSGLEN-16]; // unacked reliable message + // time and size data to calculate bandwidth + int outgoing_size[MAX_LATENT]; + double outgoing_time[MAX_LATENT]; + } netchan_t; +extern netadr_t net_from; +extern sizebuf_t net_message; +extern byte net_message_buffer[MAX_MSGLEN]; + #define PROTOCOL_VERSION 36 #define PORT_MASTER 27900 #define PORT_CLIENT 27901 diff --git a/engine/engine.c b/engine/engine.c index 21cc7fbc..4fddfafc 100644 --- a/engine/engine.c +++ b/engine/engine.c @@ -21,7 +21,6 @@ launch_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, void *unused ) Host.Main = Host_Main; Host.Free = Host_Free; Host.CPrint = Host_Print; - Host.MSG_Init = MSG_Init; return &Host; } \ No newline at end of file diff --git a/engine/host.c b/engine/host.c index 557bcef2..c8536ff6 100644 --- a/engine/host.c +++ b/engine/host.c @@ -285,11 +285,6 @@ Returns last event time void Host_EventLoop( void ) { sys_event_t ev; - netadr_t ev_from; - byte bufData[MAX_MSGLEN]; - sizebuf_t buf; - - MSG_Init( &buf, bufData, sizeof( bufData )); while( 1 ) { @@ -297,15 +292,7 @@ void Host_EventLoop( void ) switch( ev.type ) { case SE_NONE: - // manually send packet events for the loopback channel - while( NET_GetLoopPacket( NS_CLIENT, &ev_from, &buf )) - { - CL_PacketEvent( ev_from, &buf ); - } - while( NET_GetLoopPacket( NS_SERVER, &ev_from, &buf )) - { - SV_PacketEvent( ev_from, &buf ); - } + // end of events return; case SE_KEY: Key_Event( ev.value[0], ev.value[1] ); @@ -317,24 +304,7 @@ void Host_EventLoop( void ) CL_MouseEvent( ev.value[0], ev.value[1] ); break; case SE_CONSOLE: - Cbuf_AddText(va( "%s\n", ev.data )); - break; - case SE_PACKET: - ev_from = *(netadr_t *)ev.data; - buf.cursize = ev.length - sizeof( ev_from ); - - // we must copy the contents of the message out, because - // the event buffers are only large enough to hold the - // exact payload, but channel messages need to be large - // enough to hold fragment reassembly - if((uint)buf.cursize > buf.maxsize ) - { - MsgDev( D_WARN, "Host_EventLoop: oversize packet\n"); - continue; - } - Mem_Copy( buf.data, (byte *)((netadr_t *)ev.data + 1), buf.cursize ); - if ( SV_Active()) SV_PacketEvent( ev_from, &buf ); - else CL_PacketEvent( ev_from, &buf ); + Cbuf_AddText( va( "%s\n", ev.data )); break; default: Host_Error( "Host_EventLoop: bad event type %i", ev.type ); @@ -418,10 +388,6 @@ void Host_Frame( double time ) Host_EventLoop (); // process all system events Cbuf_Execute (); // execure commands - // if running the server locally, make intentions now - if( cls.state == ca_connected && SV_Active()) - CL_SendCommand (); - SV_Frame (); // server frame CL_Frame (); // client frame VM_Frame (); // vprogs frame diff --git a/engine/server/server.h b/engine/server/server.h index 25b64653..8c88d516 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_MASTERS 8 // max recipients for heartbeat packets #define LATENCY_COUNTS 16 #define MAX_ENT_CLUSTERS 16 +#define CL_MAX_USERCMDS 16 // classic quake flags #define SPAWNFLAG_NOT_EASY 0x00000100 @@ -104,12 +105,14 @@ typedef struct sv_client_s char userinfo[MAX_INFO_STRING]; // name, etc int lastframe; // for delta compression - usercmd_t lastcmd; // for filling in big drops - usercmd_t cmd; // current user commands + usercmd_t cmds[CL_MAX_USERCMDS]; // current user commands + usercmd_t cmd; + int num_cmds; // number of received cmds int ping; int rate; int surpressCount; // number of messages rate supressed + double sendtime; // time before send next packet edict_t *edict; // EDICT_NUM(clientnum+1) char name[32]; // extracted from userinfo, color string allowed diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 472219d9..8f845dc0 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -199,6 +199,7 @@ gotnewcl: MSG_Init( &newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf)); newcl->state = cs_connected; + newcl->sendtime = host.realtime; newcl->lastmessage = host.realtime; newcl->lastconnect = host.realtime; @@ -467,17 +468,12 @@ void SV_RemoteCommand( netadr_t from, sizebuf_t *msg ) void SV_SetAngle( edict_t *ent, const float *rgflAngles ) { if( !ent || !ent->pvServerData || !ent->pvServerData->client ) return; -#if 0 - ent->pvServerData->s.delta_angles[0] = rgflAngles[0] - ent->pvServerData->client->lastcmd.angles[0]; - ent->pvServerData->s.delta_angles[1] = rgflAngles[1] - ent->pvServerData->client->lastcmd.angles[1]; - ent->pvServerData->s.delta_angles[2] = rgflAngles[2] - ent->pvServerData->client->lastcmd.angles[2]; -#else + MSG_Begin( svc_setangle ); MSG_WriteAngle32( &sv.multicast, rgflAngles[0] ); MSG_WriteAngle32( &sv.multicast, rgflAngles[1] ); MSG_WriteAngle32( &sv.multicast, rgflAngles[2] ); MSG_Send( MSG_ONE_R, vec3_origin, ent ); -#endif } /* @@ -557,7 +553,8 @@ void SV_New_f( sv_client_t *cl ) ent = EDICT_NUM( playernum + 1 ); ent->serialnumber = playernum + 1; cl->edict = ent; - Mem_Set( &cl->lastcmd, 0, sizeof(cl->lastcmd)); + cl->num_cmds = 0; + Mem_Set( &cl->cmd, 0, sizeof( cl->cmd )); // begin fetching configstrings MSG_WriteByte( &cl->netchan.message, svc_stufftext ); @@ -791,7 +788,7 @@ void SV_UserinfoChanged( sv_client_t *cl ) // if the client is on the same subnet as the server and we aren't running an // internet public server, assume they don't need a rate choke - if(NET_IsLANAddress( cl->netchan.remote_address )) + if(NET_IsLocalAddress( cl->netchan.remote_address )) { // lans should not rate limit cl->rate = 99999; @@ -1352,7 +1349,7 @@ void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd ) /* ================== -SV_UserMove +SV_ReadClientMove The message usually contains all the movement commands that were in the last three packets, so that the information @@ -1362,13 +1359,10 @@ On very fast clients, there may be multiple usercmd packed into each of the backup packets. ================== */ -static void SV_UserMove( sv_client_t *cl, sizebuf_t *msg ) +static void SV_ReadClientMove( sv_client_t *cl, sizebuf_t *msg ) { - usercmd_t nullcmd; - usercmd_t oldest, oldcmd, newcmd; - int checksumIndex, lastframe, net_drop; + int i, checksumIndex, lastframe; int checksum, calculatedChecksum; - double frametime[2]; double latency; checksumIndex = msg->readcount; @@ -1384,14 +1378,17 @@ static void SV_UserMove( sv_client_t *cl, sizebuf_t *msg ) } } - Mem_Set( &nullcmd, 0, sizeof( nullcmd )); - MSG_ReadDeltaUsercmd( msg, &nullcmd, &oldest); - MSG_ReadDeltaUsercmd( msg, &oldest, &oldcmd ); - MSG_ReadDeltaUsercmd( msg, &oldcmd, &newcmd ); + Mem_Set( &cl->cmds[0], 0, sizeof( usercmd_t )); + for( i = 0; i < 3; i++ ) + { + MSG_ReadDeltaUsercmd( msg, &cl->cmds[i], &cl->cmds[i+1] ); + cl->num_cmds++; + } if( cl->state != cs_spawned ) { cl->lastframe = -1; + cl->num_cmds = 0; return; } @@ -1400,32 +1397,47 @@ static void SV_UserMove( sv_client_t *cl, sizebuf_t *msg ) if( calculatedChecksum != checksum ) { MsgDev( D_ERROR, "SV_UserMove: failed command checksum for %s (%d != %d)\n", cl->name, calculatedChecksum, checksum ); - return; + cl->num_cmds = 0; } +} - if( !sv_paused->value ) +void SV_ExecuteClientMoves( sv_client_t *cl ) +{ + int moveindex; + float moveframetime; + double oldframetime; + double oldframetime2; + + if( cl->num_cmds < 1 ) return; + + // only start accepting input once the player is spawned + if( cl->state != cs_spawned ) return; + + for( moveindex = 0; moveindex < cl->num_cmds; moveindex++ ) { - frametime[0] = sv.frametime; - frametime[1] = svgame.globals->frametime; - sv.frametime = (newcmd.msec * 0.001); - svgame.globals->frametime = sv.frametime; - - net_drop = cl->netchan.dropped; - if( net_drop < 20 ) + usercmd_t *move = cl->cmds + moveindex; + + move->time = max( move->time, cl->cmd.time ); // prevent backstepping of time + moveframetime = bound( 0, move->time - cl->cmd.time, min( 0.1, sv.frametime * 4 )); + cl->cmd = *move; + + if( moveframetime <= 0 ) continue; + oldframetime = svgame.globals->frametime; + oldframetime2 = sv.frametime; + + // the server and qc frametime values must be changed temporarily + svgame.globals->frametime = sv.frametime = moveframetime; + // if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction) + if( sv.frametime > 0.05 ) { - while( net_drop > 2 ) - { - SV_Physics_ClientMove( cl, &cl->lastcmd ); - net_drop--; - } - if( net_drop > 1 ) SV_Physics_ClientMove( cl, &oldest ); - if( net_drop > 0 ) SV_Physics_ClientMove( cl, &oldcmd ); + svgame.globals->frametime = sv.frametime = moveframetime * 0.5f; + SV_Physics_ClientMove( cl, &cl->cmd ); } - SV_Physics_ClientMove( cl, &newcmd ); + + SV_Physics_ClientMove( cl, &cl->cmd ); + sv.frametime = oldframetime2; + svgame.globals->frametime = oldframetime; } - sv.frametime = frametime[0]; - svgame.globals->frametime = frametime[1]; - cl->lastcmd = newcmd; } /* @@ -1441,11 +1453,17 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg ) bool move_issued = false; char *s; + cl->num_cmds = 0; + // read optional clientCommand strings while( cl->state != cs_zombie ) { c = MSG_ReadByte( msg ); - if( c == -1 ) break; + if( c == -1 ) + { + SV_ExecuteClientMoves( cl ); + break; + } switch( c ) { @@ -1457,7 +1475,7 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg ) case clc_move: if( move_issued ) return; // someone is trying to cheat... move_issued = true; - SV_UserMove( cl, msg ); + SV_ReadClientMove( cl, msg ); break; case clc_stringcmd: s = MSG_ReadString( msg ); diff --git a/engine/server/sv_frame.c b/engine/server/sv_frame.c index 1691efe8..e3bacfce 100644 --- a/engine/server/sv_frame.c +++ b/engine/server/sv_frame.c @@ -330,8 +330,10 @@ void SV_WriteFrameToClient( sv_client_t *cl, sizebuf_t *msg ) } } + MSG_WriteByte( msg, svc_time ); + MSG_WriteFloat( msg, sv.time ); // send a servertime before each frame + MSG_WriteByte( msg, svc_frame ); - MSG_WriteFloat( msg, sv.time ); // send a servertime MSG_WriteLong( msg, sv.framenum ); MSG_WriteLong( msg, lastframe ); // what we are delta'ing from MSG_WriteByte( msg, cl->surpressCount ); // rate dropped packets @@ -443,6 +445,9 @@ bool SV_SendClientDatagram( sv_client_t *cl ) byte msg_buf[MAX_MSGLEN]; sizebuf_t msg; + if( cl->sendtime > host.realtime ) + return false; + SV_BuildClientFrame( cl ); MSG_Init( &msg, msg_buf, sizeof( msg_buf )); @@ -473,6 +478,7 @@ bool SV_SendClientDatagram( sv_client_t *cl ) // record information about the message cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].msg_size = msg.cursize; cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].msg_sent = host.realtime; + cl->sendtime = host.realtime + host_ticrate->value; // FIXME: this relationship is totally wrong return true; } @@ -493,9 +499,6 @@ bool SV_RateDrop( sv_client_t *cl ) if( NET_IsLocalAddress( cl->netchan.remote_address )) return false; - if( NET_IsLANAddress( cl->netchan.remote_address )) - return false; - for( i = 0; i < UPDATE_BACKUP; i++ ) total += cl->frames[i].msg_size; diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 9a2b09f5..fd1ad865 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -325,7 +325,8 @@ void SV_InitGame( void ) ent = EDICT_NUM( i + 1 ); ent->serialnumber = i + 1; svs.clients[i].edict = ent; - Mem_Set( &svs.clients[i].lastcmd, 0, sizeof( svs.clients[i].lastcmd )); + Mem_Set( &svs.clients[i].cmd, 0, sizeof( svs.clients[i].cmd )); + svs.clients[i].num_cmds = 0; } } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index fa1c438d..a3482963 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -124,6 +124,14 @@ void SV_PacketEvent( netadr_t from, sizebuf_t *msg ) if( i != Host_MaxClients()) return; } +void SV_ReadPackets( void ) +{ + while( NET_GetPacket( NS_SERVER, &net_from, &net_message )) + { + SV_PacketEvent( net_from, &net_message ); + } +} + /* ================== SV_CheckTimeouts @@ -235,6 +243,9 @@ void SV_Frame( void ) // check timeouts SV_CheckTimeouts (); + // read packets from clients + SV_ReadPackets (); + // update ping based on the last known frame from all clients SV_CalcPings (); @@ -376,6 +387,8 @@ void SV_Init( void ) // init game SV_LoadProgs( "server" ); + + MSG_Init( &net_message, net_message_buffer, sizeof( net_message_buffer )); } /* diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index 38388c0c..d02cdd3c 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -436,7 +436,7 @@ void SV_PlayerMove( edict_t *player ) usercmd_t *cmd; client = player->pvServerData->client; - cmd = &client->lastcmd; + cmd = &client->cmd; body = player->pvServerData->physbody; // member body ptr pe->PlayerMove( &player->pvServerData->s, cmd, body, false ); // server move diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 7625e0de..1aec4b18 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1428,20 +1428,12 @@ void SV_Physics_Step( edict_t *ent ) } else { - // freefall if not onground - int hitsound = ent->v.velocity[2] < sv_gravity->value * -0.1; - SV_AddGravity( ent ); SV_CheckVelocity( ent ); SV_FlyMove( ent, svgame.globals->frametime, NULL, SV_ContentsMask( ent )); SV_LinkEdict( ent ); // just hit ground - if( hitsound && ent->v.flags & FL_ONGROUND ) - { - Msg("Landing crash\n"); - //SV_StartSound(ent, 0, sv_sound_land.string, 255, 1); - } ent->pvServerData->forceupdate = true; } } diff --git a/history.log b/history.log index 424ce7c9..4057b051 100644 --- a/history.log +++ b/history.log @@ -1,5 +1,6 @@ Xash 0.56 alpha ++ implement renderMode system like in Half-Life + added glow sprites occlusion Xash 0.56 pre-alpha diff --git a/launch/filesystem.c b/launch/filesystem.c index c94becbf..1990ca69 100644 --- a/launch/filesystem.c +++ b/launch/filesystem.c @@ -1722,7 +1722,7 @@ FS_SysFileExists Look for a file in the filesystem only ================== */ -bool FS_SysFileExists (const char *path) +bool FS_SysFileExists( const char *path ) { int desc; diff --git a/launch/imagelib/img_wad.c b/launch/imagelib/img_wad.c index 2ba501b9..2d3755a2 100644 --- a/launch/imagelib/img_wad.c +++ b/launch/imagelib/img_wad.c @@ -337,7 +337,6 @@ bool Image_LoadLMP( const char *name, const byte *buffer, size_t filesize ) } if(!Image_ValidSize( name )) return false; - image.num_mips = 1; image.num_layers = 1; if( image.hint != IL_HINT_Q1 && filesize > (int)sizeof(lmp) + pixels ) diff --git a/launch/launch.h b/launch/launch.h index 0f16651e..dd6be62a 100644 --- a/launch/launch.h +++ b/launch/launch.h @@ -80,7 +80,6 @@ typedef struct system_s void ( *Main ) ( void ); // host frame void ( *Free ) ( void ); // close host void (*CPrint)( const char *msg ); // console print - void (*MSG_Init)( sizebuf_t *buf, byte *data, size_t length ); } system_t; typedef struct timer_s @@ -180,13 +179,15 @@ bool REG_SetValue( HKEY hKey, const char *SubKey, const char *Value, char *pBuff // void NET_Init( void ); void NET_Shutdown( void ); -void NET_ShowIP( void ); // just for debug void NET_Config( bool net_enable ); -char *NET_AdrToString( netadr_t a ); -bool NET_IsLANAddress( netadr_t adr ); -bool NET_StringToAdr( const char *s, netadr_t *a ); -bool NET_GetPacket( netadr_t *net_from, sizebuf_t *net_message ); -void NET_SendPacket( int length, const void *data, netadr_t to ); +bool NET_IsLocalAddress( netadr_t adr ); +char *NET_AdrToString( const netadr_t a ); +char *NET_BaseAdrToString( const netadr_t a ); +bool NET_StringToAdr( const char *string, netadr_t *adr ); +bool NET_CompareAdr( const netadr_t a, const netadr_t b ); +bool NET_CompareBaseAdr( const netadr_t a, const netadr_t b ); +bool NET_GetPacket( netsrc_t sock, netadr_t *from, sizebuf_t *msg ); +void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to ); // // stdlib.c diff --git a/launch/network.c b/launch/network.c index 34cc03ab..f502b946 100644 --- a/launch/network.c +++ b/launch/network.c @@ -8,15 +8,11 @@ #include "launch.h" #include "byteorder.h" -#define MAX_IPS 16 #define PORT_ANY -1 -#define PORT_SERVER 27960 -#define DO( src, dest ) \ - copy[0] = s[src]; \ - copy[1] = s[src + 1]; \ - sscanf( copy, "%x", &val ); \ - ((struct sockaddr_ipx *)sadr)->dest = val - +#define PORT_SERVER 27911 +#define MAX_LOOPBACK 4 +#define MASK_LOOPBACK (MAX_LOOPBACK - 1) + // wsock32.dll exports static int (_stdcall *pWSACleanup)( void ); static word (_stdcall *pNtohs)( word netshort ); @@ -24,6 +20,7 @@ static int (_stdcall *pWSAGetLastError)( void ); static int (_stdcall *pCloseSocket)( SOCKET s ); static word (_stdcall *pHtons)( word hostshort ); static dword (_stdcall *pInet_Addr)( const char* cp ); +static char* (_stdcall *pInet_Ntoa)( struct in_addr in ); static SOCKET (_stdcall *pSocket)( int af, int type, int protocol ); static struct hostent *(_stdcall *pGetHostByName)( const char* name ); static int (_stdcall *pIoctlSocket)( SOCKET s, long cmd, dword* argp ); @@ -53,6 +50,7 @@ static dllfunc_t winsock_funcs[] = {"connect", (void **) &pConnect }, {"recvfrom", (void **) &pRecvFrom }, {"inet_addr", (void **) &pInet_Addr }, + {"inet_ntoa", (void **) &pInet_Ntoa }, {"WSAStartup", (void **) &pWSAStartup }, {"WSACleanup", (void **) &pWSACleanup }, {"setsockopt", (void **) &pSetSockopt }, @@ -64,29 +62,38 @@ static dllfunc_t winsock_funcs[] = { NULL, NULL } }; -dll_info_t winsock_dll = { "wsock32.dll", winsock_funcs, NULL, NULL, NULL, true, 0 }; +dll_info_t winsock_dll = { "wsock32.dll", winsock_funcs, NULL, NULL, NULL, false, 0 }; + +typedef struct +{ + byte data[MAX_MSGLEN]; + int datalen; +} loopmsg_t; + +typedef struct +{ + loopmsg_t msgs[MAX_LOOPBACK]; + int get, send; +} loopback_t; + +loopback_t loopbacks[2]; static WSADATA winsockdata; static bool winsockInitialized = false; -static bool usingSocks = false; -static bool net_active = false; +static const char *net_src[2] = { "client", "server" }; +static cvar_t *net_ip; +static cvar_t *net_hostport; +static cvar_t *net_clientport; +static cvar_t *net_showpackets; +static int ip_sockets[2]; -static cvar_t *net_socks_enabled; -static cvar_t *net_socks_server; -static cvar_t *net_socks_port; -static cvar_t *net_socks_username; -static cvar_t *net_socks_password; -static struct sockaddr socksRelayAddr; -static SOCKET ip_socket; -static SOCKET socks_socket; -static SOCKET ipx_socket; -static char socksBuf[4096]; -static byte localIP[MAX_IPS][4]; -static int numIP; - -void NET_OpenWinSock( void ) +bool NET_OpenWinSock( void ) { - Sys_LoadLibrary( &winsock_dll ); + // initialize the Winsock function vectors (we do this instead of statically linking + // so we can run on Win 3.1, where there isn't necessarily Winsock) + if( Sys_LoadLibrary( &winsock_dll )) + return true; + return false; } void NET_FreeWinSock( void ) @@ -101,7 +108,7 @@ NET_ErrorString */ char *NET_ErrorString( void ) { - switch(pWSAGetLastError()) + switch(pWSAGetLastError( )) { case WSAEINTR: return "WSAEINTR"; case WSAEBADF: return "WSAEBADF"; @@ -151,9 +158,9 @@ char *NET_ErrorString( void ) } } -void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) +static void NET_NetadrToSockadr( netadr_t *a, struct sockaddr *s ) { - Mem_Set( s, 0, sizeof(*s)); + Mem_Set( s, 0, sizeof( *s )); if( a->type == NA_BROADCAST ) { @@ -167,24 +174,10 @@ void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip; ((struct sockaddr_in *)s)->sin_port = a->port; } - else if (a->type == NA_IPX) - { - ((struct sockaddr_ipx *)s)->sa_family = AF_IPX; - Mem_Copy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4); - Mem_Copy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6); - ((struct sockaddr_ipx *)s)->sa_socket = a->port; - } - else if (a->type == NA_BROADCAST_IPX) - { - ((struct sockaddr_ipx *)s)->sa_family = AF_IPX; - Mem_Set(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4); - Mem_Set(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6); - ((struct sockaddr_ipx *)s)->sa_socket = a->port; - } } -void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) +static void NET_SockadrToNetadr( struct sockaddr *s, netadr_t *a ) { if( s->sa_family == AF_INET ) { @@ -192,13 +185,6 @@ void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr; a->port = ((struct sockaddr_in *)s)->sin_port; } - else if (s->sa_family == AF_IPX) - { - a->type = NA_IPX; - Mem_Copy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4); - Mem_Copy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6); - a->port = ((struct sockaddr_ipx *)s)->sa_socket; - } } @@ -206,73 +192,111 @@ void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) ============= NET_StringToAdr +localhost idnewt +idnewt:28000 192.246.40.70 -12121212.121212121212 +192.246.40.70:28000 ============= */ -bool NET_StringToSockaddr( const char *s, struct sockaddr *sadr ) +static bool NET_StringToSockaddr( const char *s, struct sockaddr *sadr ) { struct hostent *h; - int val; + char *colon; char copy[MAX_SYSPATH]; Mem_Set( sadr, 0, sizeof( *sadr ) ); - // check for an IPX address - if(( com_strlen( s ) == 21 ) && ( s[8] == '.' )) + + ((struct sockaddr_in *)sadr)->sin_family = AF_INET; + ((struct sockaddr_in *)sadr)->sin_port = 0; + + com.strncpy( copy, s, sizeof( copy )); + + // strip off a trailing :port if present + for( colon = copy; *colon; colon++ ) { - ((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX; - ((struct sockaddr_ipx *)sadr)->sa_socket = 0; - copy[2] = 0; - DO(0, sa_netnum[0]); - DO(2, sa_netnum[1]); - DO(4, sa_netnum[2]); - DO(6, sa_netnum[3]); - DO(9, sa_nodenum[0]); - DO(11, sa_nodenum[1]); - DO(13, sa_nodenum[2]); - DO(15, sa_nodenum[3]); - DO(17, sa_nodenum[4]); - DO(19, sa_nodenum[5]); + if( *colon == ':' ) + { + *colon = 0; + ((struct sockaddr_in *)s)->sin_port = pHtons( (short)com.atoi( colon + 1 )); + } + } + + if( copy[0] >= '0' && copy[0] <= '9' ) + { + *(int *)&((struct sockaddr_in *)s)->sin_addr = pInet_Addr( copy ); } else { - ((struct sockaddr_in *)sadr)->sin_family = AF_INET; - ((struct sockaddr_in *)sadr)->sin_port = 0; - - if( s[0] >= '0' && s[0] <= '9' ) - { - *(int *)&((struct sockaddr_in *)sadr)->sin_addr = pInet_Addr(s); - } - else - { - if(( h = pGetHostByName(s)) == 0 ) - return 0; - *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0]; - } + if(!( h = pGetHostByName( copy ))) + return false; + *(int *)&((struct sockaddr_in *)s)->sin_addr = *(int *)h->h_addr_list[0]; } return true; } -char *NET_AdrToString( netadr_t a ) +char *NET_AdrToString( const netadr_t a ) { - static char s[64]; - if( a.type == NA_LOOPBACK ) - { - com_snprintf( s, sizeof(s), "loopback" ); - } + return "loopback"; else if( a.type == NA_IP ) + return va( "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], pNtohs( a.port )); + return ""; +} + +char *NET_BaseAdrToString( const netadr_t a ) +{ + if( a.type == NA_LOOPBACK ) + return "loopback"; + else if( a.type == NA_IP ) + return va( "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3] ); + return ""; +} + +/* +=================== +NET_CompareBaseAdr + +Compares without the port +=================== +*/ +bool NET_CompareBaseAdr( const netadr_t a, const netadr_t b ) +{ + if( a.type != b.type ) return false; + if( a.type == NA_LOOPBACK ) return true; + + if( a.type == NA_IP ) { - com_snprintf( s, sizeof(s), "%i.%i.%i.%i:%hu", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port)); + if(!memcmp( a.ip, b.ip, 4 )) + return true; + return false; } - else + + MsgDev( D_ERROR, "NET_CompareBaseAdr: bad address type\n" ); + return false; +} + +bool NET_CompareAdr( const netadr_t a, const netadr_t b ) +{ + if( a.type != b.type ) + return false; + if( a.type == NA_LOOPBACK ) + return true; + + if( a.type == NA_IP ) { - com_snprintf( s, sizeof(s), "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%hu", - a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], - BigShort(a.port)); + if((memcmp(a.ip, b.ip, 4 ) == 0) && a.port == b.port) + return true; + return false; } - return s; + + MsgDev( D_ERROR, "NET_CompareAdr: bad address type\n" ); + return false; +} + +bool NET_IsLocalAddress( netadr_t adr ) +{ + return adr.type == NA_LOOPBACK; } /* @@ -283,17 +307,79 @@ idnewt 192.246.40.70 ============= */ -bool NET_StringToAdr( const char *s, netadr_t *a ) +bool NET_StringToAdr( const char *string, netadr_t *adr ) { - struct sockaddr sadr; - - if( !NET_StringToSockaddr( s, &sadr )) + struct sockaddr s; + + if( !com.stricmp( string, "localhost" )) + { + Mem_Set( adr, 0, sizeof( netadr_t )); + adr->type = NA_LOOPBACK; + return true; + } + + if( !NET_StringToSockaddr( string, &s )) return false; - - SockadrToNetadr( &sadr, a ); + NET_SockadrToNetadr( &s, adr ); + return true; } +/* +============================================================================= + +LOOPBACK BUFFERS FOR LOCAL PLAYER + +============================================================================= +*/ +static bool NET_GetLoopPacket( netsrc_t sock, netadr_t *from, sizebuf_t *msg ) +{ + int i; + loopback_t *loop; + + loop = &loopbacks[sock]; + + if( loop->send - loop->get > MAX_LOOPBACK ) + loop->get = loop->send - MAX_LOOPBACK; + + if( loop->get >= loop->send ) + return false; + i = loop->get & MASK_LOOPBACK; + loop->get++; + + Mem_Copy( msg->data, loop->msgs[i].data, loop->msgs[i].datalen ); + msg->cursize = loop->msgs[i].datalen; + memset( from, 0, sizeof(*from)); + from->type = NA_LOOPBACK; + return true; + +} + +static bool NET_SendLoopPacket( netsrc_t sock, size_t length, const void *data, netadr_t to ) +{ + int i; + loopback_t *loop; + + if( to.type != NA_LOOPBACK ) + return false; + + loop = &loopbacks[sock^1]; + + i = loop->send & MASK_LOOPBACK; + loop->send++; + + Mem_Copy( loop->msgs[i].data, data, length ); + loop->msgs[i].datalen = length; + + return true; +} + +static void NET_ClearLoopback( void ) +{ + loopbacks[0].send = loopbacks[0].get = 0; + loopbacks[1].send = loopbacks[1].get = 0; +} + /* ================== NET_GetPacket @@ -301,64 +387,44 @@ NET_GetPacket Never called by the game logic, just the system event queing ================== */ -bool NET_GetPacket( netadr_t *net_from, sizebuf_t *net_message ) +bool NET_GetPacket( netsrc_t sock, netadr_t *from, sizebuf_t *msg ) { - int ret, err; - struct sockaddr from; - int fromlen; + uint ret; + struct sockaddr addr; + int err, addr_len; int net_socket; - int protocol; - for( protocol = 0; protocol < 2; protocol++ ) - { - if( protocol == 0 ) net_socket = ip_socket; - else net_socket = ipx_socket; - - if( !net_socket ) continue; - - fromlen = sizeof( from ); - ret = pRecvFrom( net_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen ); - if (ret == SOCKET_ERROR) - { - err = pWSAGetLastError(); - - if( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) - continue; - MsgDev( D_ERROR, "NET_GetPacket: %s\n", NET_ErrorString()); - continue; - } - if( net_socket == ip_socket ) - { - Mem_Set(((struct sockaddr_in *)&from)->sin_zero, 0, 8 ); - } - - if( usingSocks && net_socket == ip_socket && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) - { - if( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 ) - continue; - net_from->type = NA_IP; - net_from->ip[0] = net_message->data[4]; - net_from->ip[1] = net_message->data[5]; - net_from->ip[2] = net_message->data[6]; - net_from->ip[3] = net_message->data[7]; - net_from->port = *(short *)&net_message->data[8]; - net_message->readcount = 10; - } - else - { - SockadrToNetadr( &from, net_from ); - net_message->readcount = 0; - } - - if( ret == net_message->maxsize ) - { - MsgDev( D_WARN, "oversize packet from %s\n", NET_AdrToString (*net_from) ); - continue; - } - net_message->cursize = ret; + if( NET_GetLoopPacket( sock, from, msg )) return true; + + net_socket = ip_sockets[sock]; + if( !net_socket ) return false; + + addr_len = sizeof( addr ); + ret = pRecvFrom( net_socket, msg->data, msg->maxsize, 0, (struct sockaddr *)&addr, &addr_len ); + + NET_SockadrToNetadr( &addr, from ); + + if( ret == SOCKET_ERROR ) + { + err = pWSAGetLastError(); + + // WSAEWOULDBLOCK and WSAECONNRESET are silent + if( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) + return false; + + MsgDev( D_ERROR, "NET_GetPacket: %s from %s\n", NET_ErrorString(), NET_AdrToString( *from )); + return false; } - return false; + + if( ret == msg->maxsize ) + { + MsgDev( D_ERROR, "NET_GetPacket: oversize packet from %s\n", NET_AdrToString( *from )); + return false; + } + + msg->cursize = ret; + return true; } /* @@ -366,133 +432,42 @@ bool NET_GetPacket( netadr_t *net_from, sizebuf_t *net_message ) NET_SendPacket ================== */ -void NET_SendPacket( int length, const void *data, netadr_t to ) +void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to ) { - int ret; + int ret, err; struct sockaddr addr; SOCKET net_socket; - switch( to.type ) - { - case NA_IP: - case NA_BROADCAST: - net_socket = ip_socket; - break; - case NA_IPX: - case NA_BROADCAST_IPX: - net_socket = ipx_socket; - break; - default: - MsgDev( D_ERROR, "NET_SendPacket: bad address type\n"); + // sequenced packets are shown in netchan, so just show oob + if( net_showpackets->integer && *(int *)data == -1 ) + MsgDev( D_INFO, "send packet %4i\n", length ); + + if( NET_SendLoopPacket( sock, length, data, to )) return; - } + if( to.type != NA_BROADCAST && to.type != NA_IP ) + Sys_Error( "NET_SendPacket: bad address type\n" ); + + net_socket = ip_sockets[sock]; if( !net_socket ) return; - NetadrToSockadr( &to, &addr ); - if( usingSocks && to.type == NA_IP ) - { - socksBuf[0] = 0; // reserved - socksBuf[1] = 0; - socksBuf[2] = 0; // fragment (not fragmented) - socksBuf[3] = 1; // address type: IPV4 - *(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr; - *(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port; - Mem_Copy( &socksBuf[10], data, length ); - ret = pSendTo( net_socket, socksBuf, length+10, 0, &socksRelayAddr, sizeof(socksRelayAddr) ); - } - else ret = pSendTo( net_socket, data, length, 0, &addr, sizeof(addr) ); + NET_NetadrToSockadr( &to, &addr ); + + ret = pSendTo( net_socket, data, length, 0, &addr, sizeof( addr )); if( ret == SOCKET_ERROR ) { - int err = pWSAGetLastError(); + err = pWSAGetLastError(); - // wouldblock is silent + // WSAEWOULDBLOCK is silent if( err == WSAEWOULDBLOCK ) return; - // some PPP links do not allow broadcasts and return an error - if(( err == WSAEADDRNOTAVAIL ) && (( to.type == NA_BROADCAST ) || ( to.type == NA_BROADCAST_IPX ))) + // some PPP links don't allow broadcasts + if( err == WSAEADDRNOTAVAIL && to.type == NA_BROADCAST ) return; - MsgDev( D_ERROR, "NET_SendPacket: %s\n", NET_ErrorString() ); - } -} -/* -================== -NET_IsLANAddress - -LAN clients will have their rate var ignored -================== -*/ -bool NET_IsLANAddress( netadr_t adr ) -{ - int i; - - if( adr.type == NA_LOOPBACK ) - return true; - - if( adr.type == NA_IPX ) - return true; - - if( adr.type != NA_IP ) - return false; - - // choose which comparison to use based on the class of the address being tested - // any local adresses of a different class than the address being tested will fail based on the first byte - if( adr.ip[0] == 127 && adr.ip[1] == 0 && adr.ip[2] == 0 && adr.ip[3] == 1 ) - return true; - - // class A - if(( adr.ip[0] & 0x80) == 0x00 ) - { - for( i = 0; i < numIP; i++ ) - { - if( adr.ip[0] == localIP[i][0] ) - return true; - } - // the RFC1918 class a block will pass the above test - return false; - } - - // class B - if(( adr.ip[0] & 0xc0) == 0x80 ) - { - for( i = 0; i < numIP; i++ ) - { - if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) - return true; - // also check against the RFC1918 class b blocks - if( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 ) - return true; - } - return false; - } - - // class C - for( i = 0; i < numIP; i++ ) - { - if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) - return true; - // also check against the RFC1918 class c blocks - if( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) - return true; - } - return false; -} - -/* -================== -NET_ShowIP -================== -*/ -void NET_ShowIP( void ) -{ - int i; - - for( i = 0; i < numIP; i++ ) - { - Msg( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] ); + MsgDev( D_ERROR, "NET_SendPacket: %s to %s\n", NET_ErrorString(), NET_AdrToString( to )); } } @@ -501,488 +476,152 @@ void NET_ShowIP( void ) NET_IPSocket ==================== */ -int NET_IPSocket( char *net_interface, int port ) +static int NET_IPSocket( const char *netInterface, int port ) { - SOCKET newsocket; - struct sockaddr_in address; - bool _true = true; - int i = 1; - int err; + int err, net_socket; + struct sockaddr_in addr; + dword _true = 1; - if( net_interface ) MsgDev( D_INFO, "Opening IP socket: %s:%i\n", net_interface, port ); - else MsgDev( D_INFO, "Opening IP socket: localhost:%i\n", port ); - - if(( newsocket = pSocket( AF_INET, SOCK_DGRAM, IPPROTO_UDP )) == INVALID_SOCKET ) + MsgDev( D_INFO, "NET_UDPSocket( %s, %i )\n", netInterface, port ); + + if(( net_socket = pSocket( PF_INET, SOCK_DGRAM, IPPROTO_UDP )) == SOCKET_ERROR ) { err = pWSAGetLastError(); if( err != WSAEAFNOSUPPORT ) - MsgDev( D_WARN, "NET_IPSocket: socket: %s\n", NET_ErrorString()); + MsgDev( D_WARN, "NET_UDPSocket: socket = %s\n", NET_ErrorString( )); return 0; } - // make it non-blocking - if( pIoctlSocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) + if( pIoctlSocket( net_socket, FIONBIO, &_true ) == SOCKET_ERROR ) { - MsgDev( D_WARN, "NET_IPSocket: ioctl FIONBIO: %s\n", NET_ErrorString()); + MsgDev( D_WARN, "NET_UDPSocket: ioctlsocket FIONBIO = %s\n", NET_ErrorString( )); + pCloseSocket( net_socket ); return 0; } // make it broadcast capable - if( pSetSockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) + if( pSetSockopt( net_socket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof( _true )) == SOCKET_ERROR ) { - MsgDev( D_WARN, "NET_IPSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString()); + MsgDev( D_WARN, "NET_UDPSocket: setsockopt SO_BROADCAST = %s\n", NET_ErrorString( )); + pCloseSocket( net_socket ); return 0; } - if( !net_interface || !net_interface[0] || !com_stricmp( net_interface, "localhost")) - address.sin_addr.s_addr = INADDR_ANY; - else NET_StringToSockaddr( net_interface, (struct sockaddr *)&address ); + if( !netInterface[0] || !com.stricmp( netInterface, "localhost" )) + addr.sin_addr.s_addr = INADDR_ANY; + else NET_StringToSockaddr( netInterface, (struct sockaddr *)&addr ); - if( port == PORT_ANY ) address.sin_port = 0; - else address.sin_port = pHtons((short)port); - address.sin_family = AF_INET; + if( port == PORT_ANY ) addr.sin_port = 0; + else addr.sin_port = pHtons((short)port); - if( pBind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR ) + addr.sin_family = AF_INET; + + if( pBind( net_socket, (void *)&addr, sizeof( addr )) == SOCKET_ERROR ) { - MsgDev( D_WARN, "UDP_OpenSocket: bind: %s\n", NET_ErrorString()); - pCloseSocket( newsocket ); + MsgDev( D_WARN, "NET_UDPSocket: bind = %s\n", NET_ErrorString( )); + pCloseSocket( net_socket ); return 0; } - return newsocket; + + return net_socket; } -/* -==================== -NET_OpenSocks -==================== -*/ -void NET_OpenSocks( int port ) -{ - struct sockaddr_in address; - bool rfc1929 = false; - int err; - struct hostent *h; - int len; - byte buf[64]; - - usingSocks = false; - - MsgDev( D_INFO, "Opening connection to SOCKS server.\n" ); - - if(( socks_socket = pSocket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == INVALID_SOCKET ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: socket: %s\n", NET_ErrorString()); - return; - } - - h = pGetHostByName( net_socks_server->string ); - if( h == NULL ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString()); - return; - } - if( h->h_addrtype != AF_INET ) - { - MsgDev( D_WARN, "NET_OpenSocks: gethostbyname: address type was not AF_INET\n"); - return; - } - - address.sin_family = AF_INET; - address.sin_addr.s_addr = *(int *)h->h_addr_list[0]; - address.sin_port = pHtons( (short)net_socks_port->integer ); - - if( pConnect( socks_socket, (struct sockaddr *)&address, sizeof( address )) == SOCKET_ERROR ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: connect: %s\n", NET_ErrorString()); - return; - } - - // send socks authentication handshake - if( *net_socks_username->string || *net_socks_password->string ) - rfc1929 = true; - - buf[0] = 5; // SOCKS version - - // method count - if( rfc1929 ) - { - buf[1] = 2; - len = 4; - } - else - { - buf[1] = 1; - len = 3; - } - buf[2] = 0; // method #1 - method id #00: no authentication - if( rfc1929 ) buf[2] = 2; // method #2 - method id #02: username/password - - if( pSend( socks_socket, buf, len, 0 ) == SOCKET_ERROR ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: send: %s\n", NET_ErrorString()); - return; - } - - // get the response - len = pRecv( socks_socket, buf, 64, 0 ); - if( len == SOCKET_ERROR ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: recv: %s\n", NET_ErrorString()); - return; - } - if( len != 2 || buf[0] != 5 ) - { - MsgDev( D_WARN, "NET_OpenSocks: bad response\n" ); - return; - } - - switch( buf[1] ) - { - case 0: // no authentication - case 2: // username/password authentication - break; - default: - MsgDev( D_WARN, "NET_OpenSocks: request denied\n" ); - return; - } - - // do username/password authentication if needed - if( buf[1] == 2 ) - { - int ulen, plen; - - // build the request - ulen = com_strlen( net_socks_username->string ); - plen = com_strlen( net_socks_password->string ); - - buf[0] = 1; // username/password authentication version - buf[1] = ulen; - if( ulen ) Mem_Copy( &buf[2], net_socks_username->string, ulen ); - buf[2 + ulen] = plen; - if( plen ) Mem_Copy( &buf[3 + ulen], net_socks_password->string, plen ); - - // send it - if( pSend( socks_socket, buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: send: %s\n", NET_ErrorString()); - return; - } - - // get the response - len = pRecv( socks_socket, buf, 64, 0 ); - if( len == SOCKET_ERROR ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: recv: %s\n", NET_ErrorString()); - return; - } - if( len != 2 || buf[0] != 1 ) - { - MsgDev( D_WARN, "NET_OpenSocks: bad response\n" ); - return; - } - if( buf[1] != 0 ) - { - MsgDev( D_WARN, "NET_OpenSocks: authentication failed\n" ); - return; - } - } - - // send the UDP associate request - buf[0] = 5; // SOCKS version - buf[1] = 3; // command: UDP associate - buf[2] = 0; // reserved - buf[3] = 1; // address type: IPV4 - *(int *)&buf[4] = INADDR_ANY; - *(short *)&buf[8] = pHtons((short)port); // port - - if( pSend( socks_socket, buf, 10, 0 ) == SOCKET_ERROR ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: send: %s\n", NET_ErrorString()); - return; - } - - // get the response - len = pRecv( socks_socket, buf, 64, 0 ); - if( len == SOCKET_ERROR ) - { - err = pWSAGetLastError(); - MsgDev( D_WARN, "NET_OpenSocks: recv: %s\n", NET_ErrorString()); - return; - } - if( len < 2 || buf[0] != 5 ) - { - MsgDev( D_WARN, "NET_OpenSocks: bad response\n" ); - return; - } - // check completion code - if( buf[1] != 0 ) - { - MsgDev( D_WARN, "NET_OpenSocks: request denied: %i\n", buf[1] ); - return; - } - if( buf[3] != 1 ) - { - MsgDev( D_WARN, "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] ); - return; - } - ((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET; - ((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4]; - ((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8]; - Mem_Set(((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 ); - usingSocks = true; -} - -/* -==================== -NET_IPXSocket -==================== -*/ -int NET_IPXSocket( int port ) -{ - SOCKET newsocket; - struct sockaddr_ipx address; - int _true = 1; - int err; - - if(( newsocket = pSocket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX )) == INVALID_SOCKET ) - { - err = pWSAGetLastError(); - if( err != WSAEAFNOSUPPORT ) - MsgDev( D_WARN, "IPX_Socket: socket: %s\n", NET_ErrorString()); - return 0; - } - - // make it non-blocking - if( pIoctlSocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) - { - MsgDev( D_WARN, "IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString()); - return 0; - } - - // make it broadcast capable - if( pSetSockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof( _true ) ) == SOCKET_ERROR ) - { - MsgDev( D_WARN, "IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString()); - return 0; - } - - address.sa_family = AF_IPX; - Mem_Set( address.sa_netnum, 0, 4 ); - Mem_Set( address.sa_nodenum, 0, 6 ); - if( port == PORT_ANY ) address.sa_socket = 0; - else address.sa_socket = pHtons( (short)port ); - - if( pBind( newsocket, (void *)&address, sizeof(address)) == SOCKET_ERROR ) - { - MsgDev( D_WARN, "IPX_Socket: bind: %s\n", NET_ErrorString()); - pCloseSocket( newsocket ); - return 0; - } - return newsocket; -} - - -/* -==================== -NET_OpenIPX -==================== -*/ -void NET_OpenIPX( void ) -{ - int port; - - port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH, "network ip address" )->integer; - ipx_socket = NET_IPXSocket( port ); -} - - - -/* -===================== -NET_GetLocalAddress -===================== -*/ -void NET_GetLocalAddress( void ) -{ - string hostname; - int error, ip, i = 0; - struct hostent *hostInfo; - char *p; - - if( pGetHostName( hostname, MAX_STRING ) == SOCKET_ERROR ) - { - error = pWSAGetLastError(); - return; - } - - hostInfo = pGetHostByName( hostname ); - if( !hostInfo ) - { - error = pWSAGetLastError(); - return; - } - - MsgDev( D_INFO, "Hostname: %s\n", hostInfo->h_name ); - while(( p = hostInfo->h_aliases[i++] ) != NULL ) - MsgDev( D_INFO, "Alias: %s\n", p ); - - if( hostInfo->h_addrtype != AF_INET ) - return; - - numIP = 0; - while(( p = hostInfo->h_addr_list[numIP] ) != NULL && numIP < MAX_IPS ) - { - ip = pNtohl( *(int *)p); - localIP[numIP][0] = p[0]; - localIP[numIP][1] = p[1]; - localIP[numIP][2] = p[2]; - localIP[numIP][3] = p[3]; - MsgDev( D_INFO, "IP: %i.%i.%i.%i\n", (ip>>24) & 0xff, (ip>>16) & 0xff, (ip>>8) & 0xff, ip & 0xff ); - numIP++; - } -} - /* ==================== NET_OpenIP ==================== */ -void NET_OpenIP( void ) +static void NET_OpenIP( void ) { - cvar_t *ip; - int i, port; + int port; - ip = Cvar_Get( "net_ip", "localhost", CVAR_LATCH, "network ip address" ); - port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH, "network default port" )->integer; + net_ip = Cvar_Get( "ip", "localhost", CVAR_INIT, "network ip address" ); - // automatically scan for a valid port, so multiple - // dedicated servers can be started without requiring - // a different net_port for each one - for( i = 0; i < 10; i++ ) + if( !ip_sockets[NS_SERVER] ) { - ip_socket = NET_IPSocket( ip->string, port + i ); - if( ip_socket ) - { - Cvar_SetValue( "net_port", port + i ); - if( net_socks_enabled->integer ) - NET_OpenSocks( port + i ); - NET_GetLocalAddress(); - return; - } + port = Cvar_Get("ip_hostport", "0", CVAR_INIT, "network default port" )->integer; + if( !port ) port = Cvar_Get( "port", va( "%i", PORT_SERVER ), CVAR_INIT, "network default port" )->integer; + + ip_sockets[NS_SERVER] = NET_IPSocket( net_ip->string, port ); + if( !ip_sockets[NS_SERVER] && Sys.app_name == HOST_DEDICATED ) + Sys_Error( "couldn't allocate dedicated server IP port\n" ); } - MsgDev( D_WARN, "Couldn't allocate IP port\n" ); -} -/* -==================== -NET_GetCvars -==================== -*/ -static bool NET_GetCvars( void ) -{ - bool modified = false; + // dedicated servers don't need client ports + if( Sys.app_name == HOST_DEDICATED ) return; - if( net_socks_enabled && net_socks_enabled->modified ) - modified = true; - net_socks_enabled = Cvar_Get( "net_socksenabled", "0", CVAR_LATCH|CVAR_ARCHIVE, "network using socks" ); - - if( net_socks_server && net_socks_server->modified ) - modified = true; - net_socks_server = Cvar_Get( "net_socksserver", "", CVAR_LATCH|CVAR_ARCHIVE, "network server socket" ); - - if( net_socks_port && net_socks_port->modified ) - modified = true; - net_socks_port = Cvar_Get( "net_socksport", "1080", CVAR_LATCH|CVAR_ARCHIVE, "using socks port" ); - - if( net_socks_username && net_socks_username->modified ) - modified = true; - net_socks_username = Cvar_Get( "net_socksusername", "", CVAR_LATCH|CVAR_ARCHIVE, "autorization login" ); - - if( net_socks_password && net_socks_password->modified ) - modified = true; - net_socks_password = Cvar_Get( "net_sockspassword", "", CVAR_LATCH|CVAR_ARCHIVE, "autorization password" ); - - return modified; + if( !ip_sockets[NS_CLIENT] ) + { + port = Cvar_Get( "ip_clientport", "0", CVAR_INIT, "network client port" )->integer; + if( !port ) + { + port = Cvar_Get( "clientport", va( "%i", Com_RandomLong( 22950, 27950 )), CVAR_INIT, "network client port" )->integer; + if( !port ) port = PORT_ANY; + } + ip_sockets[NS_CLIENT] = NET_IPSocket( net_ip->string, port ); + if( !ip_sockets[NS_CLIENT] ) ip_sockets[NS_CLIENT] = NET_IPSocket( net_ip->string, PORT_ANY ); + } } /* ==================== NET_Config + +A single player game will only use the loopback code ==================== */ -void NET_Config( bool net_enable ) +void NET_Config( bool multiplayer ) { - bool modified, start, stop; + int i; + static bool old_config; - // get any latched changes to cvars - modified = NET_GetCvars(); - - // if enable state is the same and no cvars were modified, we have nothing to do - if( net_enable == net_active && !modified ) + if( old_config == multiplayer ) return; - if( net_enable == net_active ) - { - if( net_enable ) + old_config = multiplayer; + + if( !multiplayer ) + { + // shut down any existing sockets + for( i = 0; i < 2; i++ ) { - stop = true; - start = true; - } - else - { - stop = false; - start = false; + if( ip_sockets[i] ) + { + pCloseSocket( ip_sockets[i] ); + ip_sockets[i] = 0; + } } } else - { - if( net_enable ) - { - stop = false; - start = true; - } - else - { - stop = true; - start = false; - } - net_active = net_enable; + { // open sockets + NET_OpenIP (); } - if( stop ) - { - if( ip_socket && ip_socket != INVALID_SOCKET ) - { - pCloseSocket( ip_socket ); - ip_socket = 0; - } - - if( socks_socket && socks_socket != INVALID_SOCKET ) - { - pCloseSocket( socks_socket ); - socks_socket = 0; - } - if( ipx_socket && ipx_socket != INVALID_SOCKET ) - { - pCloseSocket( ipx_socket ); - ipx_socket = 0; - } - } - if( start ) - { - NET_OpenIP(); - NET_OpenIPX(); - } + NET_ClearLoopback (); } +// sleeps msec or until net socket is ready +void NET_Sleep( uint msec ) +{ + struct timeval timeout; + fd_set fdset; + int i = 0; + + if( Sys.app_name == HOST_NORMAL ) + return; // we're not a server, just run full speed + + FD_ZERO( &fdset ); + + if( ip_sockets[NS_SERVER] ) + { + FD_SET( ip_sockets[NS_SERVER], &fdset ); // network socket + i = ip_sockets[NS_SERVER]; + } + + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + pSelect( i+1, &fdset, NULL, NULL, &timeout ); +} /* ==================== @@ -993,18 +632,23 @@ void NET_Init( void ) { int r; - NET_OpenWinSock(); // loading wsock32.dll - r = pWSAStartup(MAKEWORD( 1, 1 ), &winsockdata ); + if( !NET_OpenWinSock()) // loading wsock32.dll + { + MsgDev( D_WARN, "NET_Init: wsock32.dll can't loaded\n" ); + return; + } + + r = pWSAStartup( MAKEWORD( 1, 1 ), &winsockdata ); if( r ) { MsgDev( D_WARN, "NET_Init: winsock initialization failed: %d\n", r ); return; } + net_showpackets = Cvar_Get ("net_showpackets", "0", CVAR_TEMP, "show network packets" ); + winsockInitialized = true; MsgDev( D_NOTE, "NET_Init()\n" ); - NET_GetCvars(); // register cvars - NET_Config( true ); // FIXME: testing! } diff --git a/launch/system.c b/launch/system.c index 0f228a73..5727704d 100644 --- a/launch/system.c +++ b/launch/system.c @@ -79,12 +79,17 @@ void Sys_GetStdAPI( void ) // network.c funcs com.NET_Init = NET_Init; com.NET_Shutdown = NET_Shutdown; - com.NET_ShowIP = NET_ShowIP; com.NET_Config = NET_Config; com.NET_AdrToString = NET_AdrToString; - com.NET_IsLANAddress = NET_IsLANAddress; com.NET_StringToAdr = NET_StringToAdr; com.NET_SendPacket = NET_SendPacket; + com.NET_IsLocalAddress = NET_IsLocalAddress; + com.NET_BaseAdrToString = NET_BaseAdrToString; + com.NET_StringToAdr = NET_StringToAdr; + com.NET_CompareAdr = NET_CompareAdr; + com.NET_CompareBaseAdr = NET_CompareBaseAdr; + com.NET_GetPacket = NET_GetPacket; + com.NET_SendPacket = NET_SendPacket; // common functions com.Com_InitRootDir = FS_InitRootDir; // init custom rootdir @@ -418,7 +423,6 @@ void Sys_CreateInstance( void ) Sys.Main = Host->Main; Sys.Free = Host->Free; Sys.CPrint = Host->CPrint; - Sys.MSG_Init = Host->MSG_Init; if( baserc_dll.link ) { CreateBaserc = (void *)baserc_dll.main; @@ -441,11 +445,11 @@ void Sys_CreateInstance( void ) { case HOST_NORMAL: Con_ShowConsole( false ); // hide console + Cbuf_AddText( "exec init.rc\n" ); // execute startup config and cmdline case HOST_DEDICATED: - Cbuf_AddText("exec init.rc\n"); // execute startup config and cmdline Cbuf_Execute(); // if stuffcmds wasn't run, then init.rc is probably missing, use default - if(!Sys.stuffcmdsrun) Cbuf_ExecuteText( EXEC_NOW, "stuffcmds\n" ); + if( !Sys.stuffcmdsrun ) Cbuf_ExecuteText( EXEC_NOW, "stuffcmds\n" ); break; case HOST_DPVENC: case HOST_BSPLIB: @@ -874,7 +878,6 @@ void Sys_Init( void ) Sys.hInstance = (HINSTANCE)GetModuleHandle( NULL ); Sys_GetStdAPI(); - Sys.MSG_Init = NULL; Sys.Init = NullInit; Sys.Main = NullFunc; Sys.Free = NullFunc; @@ -1242,9 +1245,6 @@ sys_event_t Sys_GetEvent( void ) MSG msg; sys_event_t ev; char *s; - sizebuf_t netmsg; - netadr_t adr; - static bool msg_init = false; // return if we have data if( event_head > event_tail ) @@ -1278,31 +1278,6 @@ sys_event_t Sys_GetEvent( void ) Sys_QueEvent( SE_CONSOLE, 0, 0, len, b ); } - // check for network packets - if( Sys.MSG_Init ) - { - msg_init = true; - Sys.MSG_Init( &netmsg, Sys.packet_received, sizeof( Sys.packet_received )); - if( NET_GetPacket( &adr, &netmsg )) - { - netadr_t *buf; - int len; - - // copy out to a seperate buffer for qeueing - // the readcount stepahead is for SOCKS support - len = sizeof(netadr_t) + netmsg.cursize - netmsg.readcount; - buf = Malloc( len ); - *buf = adr; - Mem_Copy( buf + 1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount ); - Sys_QueEvent( SE_PACKET, 0, 0, len, buf ); - } - } - else if( !msg_init ) - { - MsgDev( D_NOTE, "Sys_GetEvent: network support disabled\n" ); - msg_init = true; - } - // return if we have data if( event_head > event_tail ) { diff --git a/public/engine_api.h b/public/engine_api.h index 24a8fc42..81b024a7 100644 --- a/public/engine_api.h +++ b/public/engine_api.h @@ -24,7 +24,7 @@ // usercmd_t communication (a part of network protocol) typedef struct usercmd_s { - int msec; + float time; int angles[3]; int forwardmove; int sidemove; @@ -190,7 +190,6 @@ typedef struct launch_exp_s void ( *Main ) ( void ); // host frame void ( *Free ) ( void ); // close host void (*CPrint) ( const char *msg ); // host print - void (*MSG_Init)( sizebuf_t *buf, byte *data, size_t len ); // MSG init network buffer } launch_exp_t; #endif//ENGINE_API_H \ No newline at end of file diff --git a/public/launch_api.h b/public/launch_api.h index 72e719f1..4b67aadd 100644 --- a/public/launch_api.h +++ b/public/launch_api.h @@ -81,11 +81,11 @@ typedef struct script_s script_t; // script machine typedef struct { const char *name; void **func; } dllfunc_t; // Sys_LoadLibrary stuff typedef struct { int numfilenames; char **filenames; char *filenamesbuffer; } search_t; typedef struct { int ofs; int type; const char *name; } fields_t; // prvm custom fields -typedef void (*cmsave_t) (void* handle, const void* buffer, size_t size); -typedef void (*cmdraw_t)( int color, int numpoints, const float *points, const int *elements ); +typedef void ( *cmsave_t )( void* handle, const void* buffer, size_t size ); +typedef void ( *cmdraw_t )( int color, int numpoints, const float *points, const int *elements ); typedef void ( *setpair_t )( const char *key, const char *value, void *buffer, void *numpairs ); -typedef enum { NA_BAD, NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX } netadrtype_t; typedef enum { mod_bad, mod_world, mod_brush, mod_studio, mod_sprite } modtype_t; +typedef enum { NA_LOOPBACK, NA_BROADCAST, NA_IP } netadrtype_t; typedef enum { NS_CLIENT, NS_SERVER } netsrc_t; typedef void ( *xcommand_t )( void ); @@ -200,7 +200,6 @@ typedef enum SE_CHAR, // ev.value[0] is an ascii char SE_MOUSE, // ev.value[0] and ev.value[1] are reletive signed x / y moves SE_CONSOLE, // ev.data is a char* - SE_PACKET // ev.data is a netadr_t followed by data bytes to ev.length } ev_type_t; typedef struct @@ -438,12 +437,15 @@ typedef struct stdilib_api_s // network.c funcs void (*NET_Init)( void ); void (*NET_Shutdown)( void ); - void (*NET_ShowIP)( void ); void (*NET_Config)( bool net_enable ); char *(*NET_AdrToString)( netadr_t a ); - bool (*NET_IsLANAddress)( netadr_t adr ); + bool (*NET_IsLocalAddress)( netadr_t adr ); + char *(*NET_BaseAdrToString)( const netadr_t a ); bool (*NET_StringToAdr)( const char *s, netadr_t *a ); - void (*NET_SendPacket)( int length, const void *data, netadr_t to ); + bool (*NET_CompareAdr)( const netadr_t a, const netadr_t b ); + bool (*NET_CompareBaseAdr)( const netadr_t a, const netadr_t b ); + bool (*NET_GetPacket)( netsrc_t sock, netadr_t *from, sizebuf_t *msg ); + void (*NET_SendPacket)( netsrc_t sock, size_t length, const void *data, netadr_t to ); // common functions void (*Com_InitRootDir)( char *path ); // init custom rootdir @@ -738,12 +740,15 @@ network messages */ #define NET_Init com.NET_Init #define NET_Shutdown com.NET_Shutdown -#define NET_ShowIP com.NET_ShowIP #define NET_Config com.NET_Config #define NET_AdrToString com.NET_AdrToString -#define NET_IsLANAddress com.NET_IsLANAddress -#define Sys_StringToAdr com.NET_StringToAdr -#define Sys_SendPacket com.NET_SendPacket +#define NET_BaseAdrToString com.NET_BaseAdrToString +#define NET_IsLocalAddress com.NET_IsLocalAddress +#define NET_StringToAdr com.NET_StringToAdr +#define NET_SendPacket com.NET_SendPacket +#define NET_GetPacket com.NET_GetPacket +#define NET_CompareAdr com.NET_CompareAdr +#define NET_CompareBaseAdr com.NET_CompareBaseAdr /* =========================================== diff --git a/public/mathlib.h b/public/mathlib.h index 35ca87b0..f3be7d1a 100644 --- a/public/mathlib.h +++ b/public/mathlib.h @@ -37,11 +37,11 @@ #define VectorToServer(v) { v[0] = METER2INCH(v[0]), v[1] = METER2INCH(v[1]), v[2] = METER2INCH(v[2]); } #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) #define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) -#define Vector4Subtract(a,b,c){c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];c[3]=a[3]-b[3];} +#define Vector4Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) #define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) #define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) #define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) -#define Vector4Copy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];} +#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) #define VectorScale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale)) #define Vector4Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale),(out)[3] = (in)[3] * (scale)) #define VectorMultiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2]) diff --git a/release.bat b/release.bat index 048bd290..663a785d 100644 --- a/release.bat +++ b/release.bat @@ -71,5 +71,5 @@ if exist xtools\xtools.plg del /f /q xtools\xtools.plg echo Build succeeded! echo Please wait. Xash is now loading cd D:\Xash3D\ -xash.exe -dev 3 -log +map start +xash.exe -dev 3 -log +map dm_qstyle :done \ No newline at end of file diff --git a/render/gl_backend.c b/render/gl_backend.c index add937f0..ddcca2ba 100644 --- a/render/gl_backend.c +++ b/render/gl_backend.c @@ -1049,6 +1049,7 @@ void GL_SetDefaultState( void ) Matrix4x4_LoadIdentity( gl_state.matrix ); pglDisable( GL_TEXTURE_2D ); + gl_state.draw_rendermode = kRenderNormal; gl_state.draw_color[0] = 255; gl_state.draw_color[1] = 255; gl_state.draw_color[2] = 255; @@ -1082,8 +1083,9 @@ void GL_Setup3D( void ) pglLoadMatrixf( gl_projectionMatrix ); pglMatrixMode( GL_MODELVIEW ); - // Set state + // set state gl_state.orthogonal = false; + gl_state.draw_rendermode = kRenderNormal; GL_TexEnv( GL_MODULATE ); GL_Enable( GL_CULL_FACE ); @@ -1133,6 +1135,7 @@ void GL_Setup2D( void ) // Set state gl_state.orthogonal = true; + gl_state.draw_rendermode = kRenderNormal; GL_TexEnv( GL_MODULATE ); diff --git a/render/r_backend.h b/render/r_backend.h index 1381d800..d7f3ac33 100644 --- a/render/r_backend.h +++ b/render/r_backend.h @@ -55,7 +55,6 @@ typedef struct glstate_s word stateRamp[768]; // original gamma ramp uint screenTexture; - rgba_t draw_color; // current color int texNum[MAX_TEXTURE_UNITS]; int texEnv[MAX_TEXTURE_UNITS]; uint activeTMU; @@ -69,7 +68,7 @@ typedef struct glstate_s bool depth_test; bool blend; - // OpenGL current state + // OpenGL current state 3D matrix4x4 matrix; GLenum cullMode; GLfloat offsetFactor; @@ -81,6 +80,11 @@ typedef struct glstate_s GLenum depthFunc; GLboolean depthMask; GLfloat polygonoffset[2]; + + // additional params for orthogonal drawing + rgba_t draw_color; + kRenderMode_t draw_rendermode; // rendermode for drawing + int draw_frame; // will be reset after each drawing } glstate_t; // contains constant values that are always diff --git a/render/r_backend2.c b/render/r_backend2.c index e5d4bc1d..f5af4ee9 100644 --- a/render/r_backend2.c +++ b/render/r_backend2.c @@ -28,6 +28,7 @@ float m_fShaderTime; mesh_t *m_pRenderMesh; ref_shader_t *m_pCurrentShader; ref_entity_t *m_pCurrentEntity; +kRenderMode_t m_iRenderMode; static GLenum rb_drawMode; static GLboolean rb_CheckFlush; @@ -562,59 +563,220 @@ static void RB_DeformVertexes( void ) } } +/* +================= +RB_SetShaderRenderMode + +UNDONE: not all cases are filled +================= +*/ static shaderStage_t *RB_SetShaderRenderMode( shaderStage_t *stage ) { static shaderStage_t currentStage; + int mod_type = mod_bad; // mod_bad interpretate as orthogonal shader - if( !m_pCurrentEntity || !(m_pCurrentShader->flags & SHADER_RENDERMODE)) + if(!(stage->flags & SHADERSTAGE_RENDERMODE)) return stage; currentStage = *stage; - switch( m_pCurrentEntity->rendermode ) + if( m_pRenderModel && !gl_state.orthogonal ) + mod_type = m_pRenderModel->type; + + switch( m_iRenderMode ) { + case kRenderNormal: + switch( mod_type ) + { + case mod_bad: + currentStage.rgbGen.type = RGBGEN_IDENTITY; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_world: + case mod_brush: + // bsp surfaces uses lightmaps and ignore color values as well + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.flags |= (SHADERSTAGE_DEPTHFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_studio: + // UNDONE: wrote R_StudioLighting, change rgbGen to RGBGEN_VERTEX + // UNDONE: setup custom alpha channel for NF_ADDITIVE, change alphaGen to ALPHAGEN_VERTEX + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.rgbGen.type = RGBGEN_LIGHTINGAMBIENT; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_sprite: + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.rgbGen.type = RGBGEN_LIGHTINGAMBIENT; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + } + break; case kRenderTransColor: - currentStage.flags |= SHADERSTAGE_BLENDFUNC; - currentStage.flags |= SHADERSTAGE_ALPHAGEN; - currentStage.flags |= SHADERSTAGE_RGBGEN; - currentStage.blendFunc.src = GL_SRC_COLOR; - currentStage.blendFunc.dst = GL_ZERO; - currentStage.alphaGen.type = ALPHAGEN_ENTITY; - currentStage.rgbGen.type = RGBGEN_ENTITY; + switch( mod_type ) + { + case mod_bad: + currentStage.flags &= ~SHADERSTAGE_ALPHAFUNC; + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_VERTEX; + currentStage.alphaGen.type = ALPHAGEN_VERTEX; + currentStage.blendFunc.src = GL_ZERO; + currentStage.blendFunc.dst = GL_SRC_COLOR; + break; + case mod_world: + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.flags |= (SHADERSTAGE_DEPTHFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_brush: + case mod_studio: + case mod_sprite: + break; + } break; case kRenderTransTexture: - currentStage.flags |= (SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAGEN|SHADERSTAGE_RGBGEN); - currentStage.alphaGen.type = ALPHAGEN_ENTITY; - currentStage.blendFunc.src = GL_SRC_ALPHA; - currentStage.blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - currentStage.rgbGen.type = RGBGEN_VERTEX; + switch( mod_type ) + { + case mod_bad: + currentStage.flags &= ~SHADERSTAGE_ALPHAFUNC; + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_VERTEX; + currentStage.alphaGen.type = ALPHAGEN_VERTEX; + currentStage.blendFunc.src = GL_SRC_ALPHA; + currentStage.blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + break; + case mod_world: + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.flags |= (SHADERSTAGE_DEPTHFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_brush: + currentStage.flags &= ~(SHADERSTAGE_ALPHAFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_ENTITY; + currentStage.blendFunc.src = GL_SRC_ALPHA; + currentStage.blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + break; + case mod_studio: + case mod_sprite: + break; + } break; case kRenderGlow: - currentStage.flags |= SHADERSTAGE_BLENDFUNC; - currentStage.flags |= SHADERSTAGE_ALPHAGEN; - currentStage.flags |= SHADERSTAGE_RGBGEN; - currentStage.blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; - currentStage.blendFunc.dst = GL_ONE; - currentStage.flags &= ~SHADERSTAGE_DEPTHFUNC; - currentStage.depthFunc.func = 0; + switch( mod_type ) + { + case mod_bad: + currentStage.flags &= ~SHADERSTAGE_ALPHAFUNC; + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_VERTEX; + currentStage.alphaGen.type = ALPHAGEN_VERTEX; + currentStage.blendFunc.src = GL_SRC_ALPHA; + currentStage.blendFunc.dst = GL_ONE; + break; + case mod_world: + case mod_brush: + // completely ignore glow mode for world surfaces + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.flags |= (SHADERSTAGE_DEPTHFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_studio: + case mod_sprite: + currentStage.flags &= ~(SHADERSTAGE_ALPHAFUNC|SHADERSTAGE_DEPTHWRITE|SHADERSTAGE_DEPTHFUNC); + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_IDENTITY; // hl1 glow sprites ignores color + currentStage.alphaGen.type = ALPHAGEN_ENTITY; + currentStage.blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; + currentStage.blendFunc.dst = GL_ONE; + break; + } break; case kRenderTransAlpha: - currentStage.flags |= SHADERSTAGE_ALPHAFUNC; - currentStage.flags |= SHADERSTAGE_ALPHAGEN; - currentStage.flags |= SHADERSTAGE_RGBGEN; - currentStage.alphaFunc.func = GL_GREATER; - currentStage.alphaFunc.ref = 0.666; - currentStage.alphaGen.type = ALPHAGEN_ENTITY; - currentStage.rgbGen.type = RGBGEN_ENTITY; + switch( mod_type ) + { + case mod_bad: + currentStage.flags &= ~SHADERSTAGE_BLENDFUNC; + currentStage.flags |= SHADERSTAGE_ALPHAFUNC; + currentStage.rgbGen.type = RGBGEN_VERTEX; + currentStage.alphaGen.type = ALPHAGEN_VERTEX; + currentStage.alphaFunc.func = GL_GREATER; + currentStage.alphaFunc.ref = 0.666; + break; + case mod_world: + // always ignore transparent surfaces for world + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.flags |= (SHADERSTAGE_DEPTHFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_brush: + currentStage.flags &= ~SHADERSTAGE_BLENDFUNC; + currentStage.flags |= SHADERSTAGE_ALPHAFUNC; + currentStage.rgbGen.type = RGBGEN_IDENTITY; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + currentStage.alphaFunc.func = GL_GREATER; + currentStage.alphaFunc.ref = 0.666; + case mod_studio: + // UNDONE: wrote R_StudioLighting, change rgbGen to RGBGEN_VERTEX + // UNDONE: setup custom alpha channel for NF_ADDITIVE, change alphaGen to ALPHAGEN_VERTEX + currentStage.flags &= ~SHADERSTAGE_BLENDFUNC; + currentStage.flags |= SHADERSTAGE_ALPHAFUNC; + currentStage.rgbGen.type = RGBGEN_LIGHTINGAMBIENT; + currentStage.alphaGen.type = ALPHAGEN_ENTITY; + currentStage.alphaFunc.func = GL_GREATER; + currentStage.alphaFunc.ref = 0.666; + case mod_sprite: + currentStage.flags &= ~SHADERSTAGE_BLENDFUNC; + currentStage.flags |= SHADERSTAGE_ALPHAFUNC; + currentStage.rgbGen.type = RGBGEN_LIGHTINGAMBIENT; + currentStage.alphaGen.type = ALPHAGEN_ENTITY; + currentStage.alphaFunc.func = GL_GREATER; + currentStage.alphaFunc.ref = 0.666; + break; + } break; case kRenderTransAdd: - currentStage.flags |= (SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAGEN|SHADERSTAGE_RGBGEN); - currentStage.alphaGen.type = ALPHAGEN_ENTITY; - currentStage.rgbGen.type = RGBGEN_VERTEX; - currentStage.blendFunc.src = GL_SRC_ALPHA; - currentStage.blendFunc.dst = GL_ONE; + switch( mod_type ) + { + case mod_bad: + currentStage.flags &= ~SHADERSTAGE_ALPHAFUNC; + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_VERTEX; + currentStage.alphaGen.type = ALPHAGEN_VERTEX; + currentStage.blendFunc.src = GL_SRC_ALPHA; + currentStage.blendFunc.dst = GL_ONE; + break; + case mod_world: + currentStage.flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); + currentStage.flags |= (SHADERSTAGE_DEPTHFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_IDENTITY; + break; + case mod_brush: + currentStage.flags &= ~(SHADERSTAGE_ALPHAFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_ENTITY; + currentStage.blendFunc.src = GL_SRC_ALPHA; + currentStage.blendFunc.dst = GL_ONE; + break; + case mod_studio: + case mod_sprite: + currentStage.flags &= ~(SHADERSTAGE_ALPHAFUNC|SHADERSTAGE_DEPTHWRITE); + currentStage.flags |= SHADERSTAGE_BLENDFUNC; + currentStage.rgbGen.type = RGBGEN_IDENTITYLIGHTING; + currentStage.alphaGen.type = ALPHAGEN_ENTITY; + currentStage.blendFunc.src = GL_SRC_ALPHA; + currentStage.blendFunc.dst = GL_ONE; + break; + } break; - case kRenderNormal: default: return stage; } return ¤tStage; @@ -716,21 +878,21 @@ RB_CalcVertexColors */ static void RB_CalcVertexColors( shaderStage_t *stage ) { - rgbGen_t *rgbGen; - alphaGen_t *alphaGen; - shaderStage_t *newStage; + rgbGen_t *rgbGen = &stage->rgbGen; + alphaGen_t *alphaGen = &stage->alphaGen; + shaderStage_t *renderStage; vec3_t vec, dir; float *table; float now, f; byte r, g, b, a; int i; - newStage = RB_SetShaderRenderMode( stage ); - RB_SetShaderStageState( newStage ); - - rgbGen = &newStage->rgbGen; - alphaGen = &newStage->alphaGen; + renderStage = RB_SetShaderRenderMode( stage ); + RB_SetShaderStageState( renderStage ); + rgbGen = &renderStage->rgbGen; + alphaGen = &renderStage->alphaGen; + switch( rgbGen->type ) { case RGBGEN_IDENTITY: @@ -800,22 +962,11 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) } break; case RGBGEN_ENTITY: - switch( m_pCurrentEntity->rendermode ) + for( i = 0; i < ref.numVertex; i++ ) { - case kRenderNormal: - case kRenderTransAlpha: - case kRenderTransTexture: - break; - case kRenderGlow: - case kRenderTransAdd: - case kRenderTransColor: - for( i = 0; i < ref.numVertex; i++ ) - { - ref.colorArray[i][0] = m_pCurrentEntity->rendercolor[0]; - ref.colorArray[i][1] = m_pCurrentEntity->rendercolor[1]; - ref.colorArray[i][2] = m_pCurrentEntity->rendercolor[2]; - } - break; + ref.colorArray[i][0] = m_pCurrentEntity->rendercolor[0]; + ref.colorArray[i][1] = m_pCurrentEntity->rendercolor[1]; + ref.colorArray[i][2] = m_pCurrentEntity->rendercolor[2]; } break; case RGBGEN_ONEMINUSENTITY: @@ -827,7 +978,7 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) } break; case RGBGEN_LIGHTINGAMBIENT: - R_LightingAmbient(); + R_LightingAmbient( (int)(rgbGen->params[0]) ? true : false ); break; case RGBGEN_LIGHTINGDIFFUSE: R_LightingDiffuse(); @@ -881,21 +1032,8 @@ static void RB_CalcVertexColors( shaderStage_t *stage ) ref.colorArray[i][3] = 255 - ref.colorArray[i][3]; break; case ALPHAGEN_ENTITY: - switch( m_pCurrentEntity->rendermode ) - { - case kRenderNormal: - case kRenderTransColor: - for( i = 0; i < ref.numVertex; i++ ) - ref.colorArray[i][3] = 1.0f; - break; - case kRenderGlow: - case kRenderTransAdd: - case kRenderTransAlpha: - case kRenderTransTexture: - for( i = 0; i < ref.numVertex; i++ ) - ref.colorArray[i][3] = m_pCurrentEntity->renderamt; - break; - } + for( i = 0; i < ref.numVertex; i++ ) + ref.colorArray[i][3] = m_pCurrentEntity->renderamt; break; case ALPHAGEN_ONEMINUSENTITY: for( i = 0; i < ref.numVertex; i++ ) @@ -1289,6 +1427,7 @@ RB_SetupTextureUnit static void RB_SetupTextureUnit( stageBundle_t *bundle, uint unit ) { int angleframe; + int animframe = 0; GL_SelectTexture( unit ); @@ -1301,9 +1440,24 @@ static void RB_SetupTextureUnit( stageBundle_t *bundle, uint unit ) } else if( bundle->flags & STAGEBUNDLE_FRAMES ) { - // manually changed - bundle->currentFrame = bound( 0, bundle->currentFrame, bundle->numTextures - 1 ); - GL_BindTexture( bundle->textures[bundle->currentFrame] ); + if( m_pCurrentEntity ) + { + if( m_pCurrentEntity->model ) + { + switch( m_pCurrentEntity->model->type ) + { + case mod_brush: + case mod_world: + animframe = m_pCurrentEntity->frame; + break; + } + } + } + else if( gl_state.orthogonal ) + animframe = gl_state.draw_frame; + // manually changed frames + animframe = bound( 0, animframe, bundle->numTextures - 1 ); + GL_BindTexture( bundle->textures[animframe] ); } else if( bundle->flags & STAGEBUNDLE_ANIMFREQUENCY ) { @@ -1839,7 +1993,7 @@ void RB_RenderMeshes( mesh_t *meshes, int numMeshes ) sortKey = mesh->sortKey; // unpack sort key - shader = &r_shaders[(sortKey>>20) & (MAX_SHADERS - 1)]; + shader = &r_shaders[(sortKey>>18) & (MAX_SHADERS - 1)]; entity = &r_entities[(sortKey>>8) & MAX_ENTITIES-1]; infoKey = sortKey & 255; @@ -1881,6 +2035,7 @@ void RB_RenderMeshes( mesh_t *meshes, int numMeshes ) else GL_LoadMatrix( r_worldMatrix ); m_pCurrentEntity = entity; m_fShaderTime = r_refdef.time - entity->shaderTime; + m_iRenderMode = m_pCurrentEntity->rendermode; m_pRenderModel = m_pCurrentEntity->model; } } @@ -1943,6 +2098,9 @@ void RB_DrawStretchPic( float x, float y, float w, float h, float sl, float tl, // check if the arrays will overflow RB_CheckMeshOverflow( 6, 4 ); + m_iRenderMode = gl_state.draw_rendermode; + m_pRenderModel = NULL; + GL_Begin( GL_QUADS ); GL_Color4ubv( gl_state.draw_color ); GL_TexCoord2f( sl, tl ); @@ -1980,6 +2138,7 @@ void RB_InitBackend( void ) m_pRenderModel = NULL; m_fShaderTime = 0; m_pCurrentEntity = NULL; + m_iRenderMode = kRenderNormal; m_iInfoKey = -1; // Set default GL state diff --git a/render/r_draw.c b/render/r_draw.c index 27cae516..46cdc0e5 100644 --- a/render/r_draw.c +++ b/render/r_draw.c @@ -52,50 +52,16 @@ void R_DrawSetParms( shader_t handle, kRenderMode_t rendermode, int frame ) if( handle < 0 || handle > MAX_SHADERS || !(shader = &r_shaders[handle]) || !shader->numStages ) return; - // change rendermode if need - if( shader->flags & SHADER_RENDERMODE ) - { - switch( rendermode ) - { - case kRenderNormal: - shader->stages[0]->flags &= ~(SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAFUNC); - break; - case kRenderTransColor: - shader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - shader->stages[0]->blendFunc.src = GL_ZERO; - shader->stages[0]->blendFunc.dst = GL_SRC_COLOR; - break; - case kRenderTransTexture: - shader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - shader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - shader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - break; - case kRenderGlow: - shader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - shader->stages[0]->blendFunc.src = GL_ONE_MINUS_SRC_ALPHA; - shader->stages[0]->blendFunc.dst = GL_ONE; - break; - case kRenderTransAlpha: - shader->stages[0]->flags |= SHADERSTAGE_ALPHAFUNC; - shader->stages[0]->alphaFunc.func = GL_GREATER; - shader->stages[0]->alphaFunc.ref = 0.666; - break; - case kRenderTransAdd: - shader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC; - shader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - shader->stages[0]->blendFunc.dst = GL_ONE; - break; - } - } + gl_state.draw_rendermode = rendermode; if( !shader->stages[0]->numBundles || !shader->stages[0]->bundles[0]->numTextures ) return; // change frame if need - if( shader->stages[0]->bundles[0]->flags & STAGEBUNDLE_FRAMES && shader->stages[0]->bundles[0]->currentFrame != frame ) + if( shader->stages[0]->bundles[0]->flags & STAGEBUNDLE_FRAMES ) { // make sure what frame inbound - shader->stages[0]->bundles[0]->currentFrame = bound( 0, frame, shader->stages[0]->bundles[0]->numTextures - 1 ); + gl_state.draw_frame = bound( 0, frame, shader->stages[0]->bundles[0]->numTextures - 1 ); } } @@ -110,7 +76,7 @@ Call RB_RenderMesh to flush. void R_DrawStretchPic( float x, float y, float w, float h, float sl, float tl, float sh, float th, shader_t handle ) { ref_shader_t *shader = tr.defaultShader; - + if( handle >= 0 && handle < MAX_SHADERS ) shader = &r_shaders[handle]; RB_DrawStretchPic( x, y, w, h, sl, tl, sh, th, shader ); } diff --git a/render/r_light.c b/render/r_light.c index 9633b92f..2b5f19bd 100644 --- a/render/r_light.c +++ b/render/r_light.c @@ -370,14 +370,14 @@ void R_LightDir( const vec3_t origin, vec3_t lightDir ) R_LightingAmbient ================= */ -void R_LightingAmbient( void ) +void R_LightingAmbient( bool invLight ) { dlight_t *dl; vec3_t end, dir; float add, dist, radius; int i, l; vec4_t ambientLight; - rgba_t color; + rgba_t color, one; // Set to full bright if no light data if( r_refdef.onlyClientDraw || !r_worldModel->lightData || !m_pCurrentEntity ) @@ -394,6 +394,7 @@ void R_LightingAmbient( void ) // Get lighting at this point VectorSet( end, m_pCurrentEntity->origin[0], m_pCurrentEntity->origin[1], m_pCurrentEntity->origin[2] - WORLD_SIZE ); + Vector4Set( one, 255, 255, 255, 255 ); VectorSet( r_pointColor, 1, 1, 1 ); R_RecursiveLightPoint( r_worldModel->nodes, m_pCurrentEntity->origin, end ); @@ -434,7 +435,9 @@ void R_LightingAmbient( void ) for( i = 0; i < ref.numVertex; i++ ) { - Vector4Copy( ambientLight, ref.colorArray[i] ); + if( invLight ) + Vector4Subtract( one, ambientLight, ref.colorArray[i] ); + else Vector4Copy( ambientLight, ref.colorArray[i] ); } } @@ -892,7 +895,9 @@ R_UpdateSurfaceLightmap void R_UpdateSurfaceLightmap( surface_t *surf ) { if( surf->dlightFrame == r_frameCount ) + { GL_BindTexture( r_dlightTexture ); + } else { GL_BindTexture( r_lightmapTextures[surf->lmNum] ); diff --git a/render/r_local.h b/render/r_local.h index 3cc7129d..4f731552 100644 --- a/render/r_local.h +++ b/render/r_local.h @@ -27,7 +27,7 @@ typedef uint elem_t; #define MAX_TEXTURE_UNITS 8 #define MAX_LIGHTMAPS 128 #define MAX_PROGRAMS 512 -#define MAX_ENTITIES 4096 +#define MAX_ENTITIES 1024 #define MAX_VERTEX_BUFFERS 2048 #define MAX_POLYS 4096 #define MAX_POLY_VERTS 16384 @@ -702,7 +702,7 @@ typedef enum typedef struct { - qword sortKey; + uint sortKey; meshType_t meshType; void *mesh; } mesh_t; @@ -711,6 +711,7 @@ extern int m_iInfoKey; extern float m_fShaderTime; extern rmodel_t *m_pLoadModel; extern mesh_t *m_pRenderMesh; +extern kRenderMode_t m_iRenderMode; extern rmodel_t *m_pRenderModel; extern ref_shader_t *m_pCurrentShader; extern ref_entity_t *m_pCurrentEntity; @@ -801,7 +802,7 @@ mspriteframe_t *R_GetSpriteFrame( ref_entity_t *ent ); void R_MarkLights( void ); void R_LightDir( const vec3_t origin, vec3_t lightDir ); void R_LightForPoint( const vec3_t point, vec3_t ambientLight ); -void R_LightingAmbient( void ); +void R_LightingAmbient( bool invLight ); void R_LightingDiffuse( void ); void R_BeginBuildingLightmaps( void ); void R_EndBuildingLightmaps( void ); diff --git a/render/r_main.c b/render/r_main.c index adc87d54..3d627f3b 100644 --- a/render/r_main.c +++ b/render/r_main.c @@ -621,8 +621,8 @@ static void R_QSortMeshes( mesh_t *meshes, int numMeshes ) static mesh_t tmp; static int64 stack[4096]; int depth = 0; - int64 L, R, l, r, median; - qword pivot; + int L, R, l, r, median; + uint pivot; if( !numMeshes ) return; @@ -739,25 +739,20 @@ void R_AddMeshToList( meshType_t meshType, void *mesh, ref_shader_t *shader, ref { switch( entity->rendermode ) { + case kRenderTransTexture: + case kRenderGlow: + case kRenderTransAdd: + shader->sort = SORT_ADDITIVE; + break; case kRenderTransColor: shader->sort = SORT_DECAL; break; - case kRenderTransTexture: - shader->sort = SORT_BLEND; - break; - case kRenderGlow: - shader->sort = SORT_ADDITIVE; - break; case kRenderTransAlpha: shader->sort = SORT_SEETHROUGH; break; - case kRenderTransAdd: - shader->sort = SORT_ADDITIVE; - break; case kRenderNormal: - shader->sort = SORT_OPAQUE; + default: shader->sort = shader->realsort; // restore original break; - default: break; // leave unchanged } } @@ -774,7 +769,7 @@ void R_AddMeshToList( meshType_t meshType, void *mesh, ref_shader_t *shader, ref m = &r_transMeshes[r_numTransMeshes++]; } - m->sortKey = (shader->sort<<36) | (shader->shadernum<<20) | ((entity - r_entities)<<8) | (infoKey); + m->sortKey = (shader->sort << 28) | (shader->shadernum << 18) | ((entity - r_entities) << 8) | (infoKey); m->meshType = meshType; m->mesh = mesh; } @@ -1089,12 +1084,10 @@ static bool R_AddEntityToScene( edict_t *pRefEntity, int ed_type, float lerpfrac refent->rendermode = pRefEntity->v.rendermode; refent->body = pRefEntity->v.body; refent->scale = pRefEntity->v.scale; - refent->renderamt = pRefEntity->v.renderamt; refent->colormap = pRefEntity->v.colormap; refent->effects = pRefEntity->v.effects; - if( VectorIsNull( pRefEntity->v.rendercolor )) - VectorSet( refent->rendercolor, 255, 255, 255 ); - else VectorCopy( pRefEntity->v.rendercolor, refent->rendercolor ); + VectorCopy( pRefEntity->v.rendercolor, refent->rendercolor ); + refent->renderamt = pRefEntity->v.renderamt; refent->model = cl_models[pRefEntity->v.modelindex]; refent->movetype = pRefEntity->v.movetype; refent->framerate = pRefEntity->v.framerate; diff --git a/render/r_model.c b/render/r_model.c index ba793334..7b5a226c 100644 --- a/render/r_model.c +++ b/render/r_model.c @@ -1152,7 +1152,7 @@ rmodel_t *Mod_ForName( const char *name, bool crash ) file = FS_Open( mod->name, "rb" ); if( !file ) { - if( crash ) Host_Error( "Mod_NumForName: %s not found\n", mod->name ); + if( crash ) Host_Error( "Mod_ForName: %s not found\n", mod->name ); Mem_Set( mod->name, 0, sizeof( mod->name )); return NULL; } diff --git a/render/r_shader.c b/render/r_shader.c index c20869d0..4982abed 100644 --- a/render/r_shader.c +++ b/render/r_shader.c @@ -1283,11 +1283,9 @@ static bool R_ParseGeneralSort( ref_shader_t *shader, script_t *script ) else if( !com.stricmp( tok.string, "blend" )) shader->sort = SORT_BLEND; else if( !com.stricmp( tok.string, "blend2" )) shader->sort = SORT_BLEND2; else if( !com.stricmp( tok.string, "blend3" )) shader->sort = SORT_BLEND3; - else if( !com.stricmp( tok.string, "blend4" )) shader->sort = SORT_BLEND4; else if( !com.stricmp( tok.string, "outerBlend" )) shader->sort = SORT_OUTERBLEND; else if( !com.stricmp( tok.string, "additive" )) shader->sort = SORT_ADDITIVE; else if( !com.stricmp( tok.string, "nearest" )) shader->sort = SORT_NEAREST; - else if( !com.stricmp( tok.string, "postProcess" )) shader->sort = SORT_POST_PROCESS; else { shader->sort = com.atoi( tok.string ); @@ -1460,17 +1458,6 @@ static bool R_ParseGeneralEntityMergable( ref_shader_t *shader, script_t *script return true; } -/* -================= -R_ParseGeneralRenderMode -================= -*/ -static bool R_ParseGeneralRenderMode( ref_shader_t *shader, script_t *script ) -{ - shader->flags |= SHADER_RENDERMODE; - return true; -} - /* ================= R_ParseGeneralTessSize @@ -1601,6 +1588,18 @@ static bool R_ParseStageIf( ref_shader_t *shader, shaderStage_t *stage, script_t } return true; } + +/* +================= +R_ParseStageRenderMode +================= +*/ +static bool R_ParseStageRenderMode( ref_shader_t *shader, shaderStage_t *stage, script_t *script ) +{ + stage->flags |= SHADERSTAGE_RENDERMODE; + return true; +} + /* ================= R_ParseStageNoPicMip @@ -3297,7 +3296,14 @@ static bool R_ParseStageRgbGen( ref_shader_t *shader, shaderStage_t *stage, scri else if( !com.stricmp( tok.string, "oneMinusEntity" )) stage->rgbGen.type = RGBGEN_ONEMINUSENTITY; else if( !com.stricmp( tok.string, "lightingAmbient" )) + { stage->rgbGen.type = RGBGEN_LIGHTINGAMBIENT; + if( Com_ReadToken( script, false, &tok )) + { + if( !com.stricmp( tok.string, "invLight" )) + stage->rgbGen.params[0] = true; + } + } else if( !com.stricmp( tok.string, "lightingDiffuse" )) stage->rgbGen.type = RGBGEN_LIGHTINGDIFFUSE; else if( !com.stricmp( tok.string, "const" ) || !com.stricmp( tok.string, "constant" )) @@ -3521,17 +3527,16 @@ typedef struct static shaderGeneralCmd_t r_shaderGeneralCmds[] = { {"surfaceParm", R_ParseGeneralSurfaceParm }, -{ "noPicMip", R_ParseGeneralNoPicmip }, -{ "noCompress", R_ParseGeneralNoCompress }, -{ "highQuality", R_ParseGeneralHighQuality }, -{ "linear", R_ParseGeneralLinear }, -{ "nearest", R_ParseGeneralNearest }, -{ "clamp", R_ParseGeneralClamp }, -{ "zeroClamp", R_ParseGeneralZeroClamp }, -{ "alphaZeroClamp", R_ParseGeneralAlphaZeroClamp }, +{"noPicMip", R_ParseGeneralNoPicmip }, +{"noCompress", R_ParseGeneralNoCompress }, +{"highQuality", R_ParseGeneralHighQuality }, +{"linear", R_ParseGeneralLinear }, +{"nearest", R_ParseGeneralNearest }, +{"clamp", R_ParseGeneralClamp }, +{"zeroClamp", R_ParseGeneralZeroClamp }, +{"alphaZeroClamp", R_ParseGeneralAlphaZeroClamp }, {"noShadows", R_ParseGeneralNoShadows }, {"nomarks", R_ParseGeneralNoFragments }, -{"renderMode", R_ParseGeneralRenderMode, }, {"entityMergable", R_ParseGeneralEntityMergable }, {"polygonOffset", R_ParseGeneralPolygonOffset }, {"cull", R_ParseGeneralCull }, @@ -3546,6 +3551,7 @@ static shaderGeneralCmd_t r_shaderGeneralCmds[] = static shaderStageCmd_t r_shaderStageCmds[] = { {"if", R_ParseStageIf }, +{"renderMode", R_ParseStageRenderMode }, {"noPicMip", R_ParseStageNoPicMip }, {"noCompress", R_ParseStageNoCompress }, {"highQuality", R_ParseStageHighQuality }, @@ -3897,7 +3903,7 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui break; case SHADER_TEXTURE: shader->stages[0]->bundles[0]->flags |= STAGEBUNDLE_MAP; - shader->stages[0]->bundles[0]->textures[0] = R_FindTexture( shader->name, buffer, bufsize, 0, 0, 0 ); + shader->stages[0]->bundles[0]->textures[0] = R_FindTexture( va( "\"%s\"", shader->name ), buffer, bufsize, 0, 0, 0 ); if( !shader->stages[0]->bundles[0]->textures[0] ) { MsgDev( D_WARN, "couldn't find texture for shader '%s', using default...\n", shader->name ); @@ -3929,7 +3935,7 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui shader->surfaceParm |= SURF_NOLIGHTMAP; shader->sort = SORT_SEETHROUGH; } - else shader->flags |= SHADER_RENDERMODE; // never ovverrides custom surfaces + else shader->stages[0]->flags |= SHADERSTAGE_RENDERMODE; // never ovverrides custom surfaces if( shader->surfaceParm & SURF_WARP ) { shader->flags |= SHADER_TESSSIZE; @@ -3980,8 +3986,9 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui { shader->stages[0]->flags |= (SHADERSTAGE_BLENDFUNC|SHADERSTAGE_ALPHAGEN|SHADERSTAGE_RGBGEN); shader->stages[0]->rgbGen.type = RGBGEN_IDENTITYLIGHTING; - shader->stages[0]->alphaGen.type = ALPHAGEN_IDENTITY; - shader->stages[0]->blendFunc.src = GL_ONE; + shader->stages[0]->alphaGen.type = ALPHAGEN_CONST; + shader->stages[0]->alphaGen.params[0] = 0.5; + shader->stages[0]->blendFunc.src = GL_SRC_ALPHA; shader->stages[0]->blendFunc.dst = GL_ONE; shader->sort = SORT_ADDITIVE; } @@ -3994,7 +4001,7 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui shader->stages[0]->alphaFunc.ref = 0.666; shader->sort = SORT_SEETHROUGH; } - else shader->flags |= SHADER_RENDERMODE; + else shader->stages[0]->flags |= SHADERSTAGE_RENDERMODE; shader->stages[0]->bundles[0]->numTextures++; shader->stages[0]->numBundles++; shader->numStages++; @@ -4082,7 +4089,7 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui shader->stages[0]->alphaFunc.ref = 0.666; shader->sort = SORT_SEETHROUGH; } - shader->flags |= SHADER_RENDERMODE; // any sprite can overrided himself rendermode + shader->stages[0]->flags |= SHADERSTAGE_RENDERMODE; // any sprite can overrided himself rendermode shader->stages[0]->numBundles++; shader->numStages++; break; @@ -4095,10 +4102,10 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui MsgDev( D_WARN, "couldn't find texture for shader '%s', using default...\n", shader->name ); shader->stages[0]->bundles[0]->textures[0] = r_defaultConchars; } + shader->stages[0]->flags |= (SHADERSTAGE_BLENDFUNC|SHADERSTAGE_RGBGEN|SHADERSTAGE_ALPHAGEN); shader->stages[0]->rgbGen.type = RGBGEN_VERTEX; shader->stages[0]->alphaGen.type = ALPHAGEN_VERTEX; shader->stages[0]->bundles[0]->numTextures++; - shader->stages[0]->flags |= (SHADERSTAGE_BLENDFUNC|SHADERSTAGE_RGBGEN|SHADERSTAGE_ALPHAGEN); shader->stages[0]->blendFunc.src = GL_SRC_ALPHA; shader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; shader->stages[0]->numBundles++; @@ -4113,7 +4120,7 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui byte *buffer = FS_LoadInternal( shader->name + 1, &bufsize ); shader->stages[0]->bundles[0]->textures[0] = R_FindTexture( shader->name, buffer, bufsize, TF_NOPICMIP|TF_STATIC, TF_LINEAR, 0 ); } - else shader->stages[0]->bundles[0]->textures[0] = R_FindTexture( shader->name, buffer, bufsize, TF_NOPICMIP, TF_LINEAR, 0 ); + else shader->stages[0]->bundles[0]->textures[0] = R_FindTexture( va( "\"%s\"", shader->name ), buffer, bufsize, TF_NOPICMIP, TF_LINEAR, 0 ); if( !shader->stages[0]->bundles[0]->textures[0] ) { @@ -4124,12 +4131,7 @@ static ref_shader_t *R_CreateDefaultShader( const char *name, int shaderType, ui shader->stages[0]->bundles[0]->textures[0] = r_defaultTexture; } } - shader->flags |= SHADER_RENDERMODE; // client.dll uses rendermode - shader->stages[0]->rgbGen.type = RGBGEN_VERTEX; shader->stages[0]->bundles[0]->numTextures++; - shader->stages[0]->flags |= SHADERSTAGE_BLENDFUNC|SHADERSTAGE_RGBGEN; - shader->stages[0]->blendFunc.src = GL_SRC_ALPHA; - shader->stages[0]->blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; shader->stages[0]->numBundles++; shader->numStages++; break; @@ -4380,6 +4382,10 @@ static void R_FinishShader( ref_shader_t *shader ) stage->ignore = true; } + // for custom sorting + if( stage->flags & SHADERSTAGE_RENDERMODE ) + shader->flags |= SHADER_RENDERMODE; + // set rgbGen if unset if(!(stage->flags & SHADERSTAGE_RGBGEN)) { @@ -4391,18 +4397,19 @@ static void R_FinishShader( ref_shader_t *shader ) case SHADER_TEXTURE: if((stage->flags & SHADERSTAGE_BLENDFUNC) && (stage->bundles[0]->texType != TEX_LIGHTMAP)) stage->rgbGen.type = RGBGEN_IDENTITYLIGHTING; + else if( stage->flags & SHADERSTAGE_RENDERMODE ) + stage->rgbGen.type = RGBGEN_ENTITY; else stage->rgbGen.type = RGBGEN_IDENTITY; break; case SHADER_STUDIO: - if( shader->surfaceParm & (SURF_ADDITIVE|SURF_GLOW)) - stage->rgbGen.type = RGBGEN_IDENTITYLIGHTING; + if( stage->flags & SHADERSTAGE_RENDERMODE ) + stage->rgbGen.type = RGBGEN_ENTITY; else stage->rgbGen.type = RGBGEN_LIGHTINGAMBIENT; break; case SHADER_SPRITE: if( shader->surfaceParm & (SURF_ALPHA|SURF_BLEND)) stage->rgbGen.type = RGBGEN_LIGHTINGAMBIENT; - else if( shader->surfaceParm & (SURF_ADDITIVE|SURF_GLOW)) - stage->rgbGen.type = RGBGEN_ENTITY; + else stage->rgbGen.type = RGBGEN_ENTITY; break; case SHADER_NOMIP: case SHADER_GENERIC: @@ -4427,13 +4434,19 @@ static void R_FinishShader( ref_shader_t *shader ) stage->alphaGen.type = ALPHAGEN_VERTEX; else stage->alphaGen.type = ALPHAGEN_IDENTITY; } + else if( stage->flags & SHADERSTAGE_RENDERMODE ) + stage->alphaGen.type = ALPHAGEN_ENTITY; else stage->alphaGen.type = ALPHAGEN_IDENTITY; break; case SHADER_STUDIO: - stage->alphaGen.type = ALPHAGEN_ENTITY; + if( stage->flags & SHADERSTAGE_RENDERMODE ) + stage->alphaGen.type = ALPHAGEN_ENTITY; + else stage->alphaGen.type = ALPHAGEN_IDENTITY; break; case SHADER_SPRITE: - stage->alphaGen.type = ALPHAGEN_ENTITY; + if( stage->flags & SHADERSTAGE_RENDERMODE ) + stage->alphaGen.type = ALPHAGEN_ENTITY; + else stage->alphaGen.type = ALPHAGEN_IDENTITY; break; case SHADER_NOMIP: case SHADER_GENERIC: @@ -4534,6 +4547,9 @@ static void R_FinishShader( ref_shader_t *shader ) } } } + + // member real sort for restore when rendermode is reset + shader->realsort = shader->sort; } /* diff --git a/render/r_shader.h b/render/r_shader.h index 2d2cc189..455ca6bb 100644 --- a/render/r_shader.h +++ b/render/r_shader.h @@ -24,8 +24,8 @@ #define SHADER_STUDIO 5 // studio skins #define SHADER_SPRITE 6 // sprite frames -#define MAX_SHADERS 4096 -#define SHADERS_HASH_SIZE 1024 +#define MAX_SHADERS 1024 +#define SHADERS_HASH_SIZE 256 // MAX_SHADERS / 4 #define MAX_EXPRESSION_OPS 4096 #define MAX_EXPRESSION_REGISTERS 4096 #define MAX_PROGRAM_PARMS 16 @@ -56,7 +56,7 @@ typedef enum SHADER_TESSSIZE = BIT(14), SHADER_SKYPARMS = BIT(15), SHADER_DEFORMVERTEXES = BIT(16), - SHADER_RENDERMODE = BIT(17),// allow to change rendermode from code + SHADER_RENDERMODE = BIT(17), } shaderFlags_t; // shader stage flags @@ -71,7 +71,8 @@ typedef enum SHADERSTAGE_DEPTHWRITE = BIT(6), SHADERSTAGE_DETAIL = BIT(7), SHADERSTAGE_RGBGEN = BIT(8), - SHADERSTAGE_ALPHAGEN = BIT(10), + SHADERSTAGE_ALPHAGEN = BIT(9), + SHADERSTAGE_RENDERMODE = BIT(10), // allow to change rendermode from code } stageFlags_t; // stage bundle flags @@ -158,24 +159,21 @@ typedef enum typedef enum { - SORT_BAD = 0, - SORT_SKY, - SORT_SUBVIEW, - SORT_OPAQUE, - SORT_DECAL, - SORT_SEETHROUGH, - SORT_BANNER, - SORT_UNDERWATER, - SORT_WATER, - SORT_INNERBLEND, - SORT_BLEND, - SORT_BLEND2, - SORT_BLEND3, - SORT_BLEND4, - SORT_OUTERBLEND, - SORT_ADDITIVE, - SORT_NEAREST, - SORT_POST_PROCESS + SORT_SUBVIEW = 1, + SORT_SKY = 2, + SORT_OPAQUE = 3, + SORT_DECAL = 4, + SORT_SEETHROUGH = 5, + SORT_BANNER = 6, + SORT_UNDERWATER = 7, + SORT_WATER = 8, + SORT_INNERBLEND = 9, + SORT_BLEND = 10, + SORT_BLEND2 = 11, + SORT_BLEND3 = 12, + SORT_OUTERBLEND = 13, + SORT_ADDITIVE = 14, + SORT_NEAREST = 15 } sort_t; typedef enum @@ -374,7 +372,6 @@ typedef struct stageBundle_s texture_t *textures[SHADER_MAX_TEXTURES]; uint numTextures; - int currentFrame; float animFrequency; int cinematicHandle; @@ -419,6 +416,7 @@ typedef struct ref_shader_s cull_t cull; sort_t sort; + sort_t realsort; uint tessSize; skyParms_t skyParms; deform_t deform[SHADER_MAX_TRANSFORMS]; diff --git a/render/r_sprite.c b/render/r_sprite.c index 0380a6fc..25163366 100644 --- a/render/r_sprite.c +++ b/render/r_sprite.c @@ -372,6 +372,7 @@ void R_DrawSpriteModel( void ) e->scale = bound( 1.0, dist * 0.005f, 10.0f ); alpha = bound( 0, dist / 1000, 1.0f ); e->renderamt = 255 * alpha; + if( e->renderamt >= 255 ) return; // faded } else return; // occluded } diff --git a/render/r_studio.c b/render/r_studio.c index dc81dd8b..d043e61a 100644 --- a/render/r_studio.c +++ b/render/r_studio.c @@ -1758,7 +1758,7 @@ void R_StudioSetupRender( rmodel_t *model, bool weaponmodel ) m_pCurrentEntity->weaponmeshes = Mem_Alloc( r_temppool, sizeof( mstudiomesh_t ) * m_pRenderModel->nummeshes ); m_pCurrentEntity->weaponpoints = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numverts ); m_pCurrentEntity->weaponnormals = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numnorms ); - m_pCurrentEntity->weaponchrome = Mem_Alloc( r_temppool, sizeof( vec2_t ) * m_pRenderModel->numverts ); + m_pCurrentEntity->weaponchrome = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numverts ); // set intermediate vertex buffers m_pxmesh = m_pCurrentEntity->weaponmeshes; @@ -1771,7 +1771,7 @@ void R_StudioSetupRender( rmodel_t *model, bool weaponmodel ) m_pCurrentEntity->meshes = Mem_Alloc( r_temppool, sizeof( mstudiomesh_t ) * m_pRenderModel->nummeshes ); m_pCurrentEntity->points = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numverts ); m_pCurrentEntity->normals = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numnorms ); - m_pCurrentEntity->chrome = Mem_Alloc( r_temppool, sizeof( vec2_t ) * m_pRenderModel->numverts ); + m_pCurrentEntity->chrome = Mem_Alloc( r_temppool, sizeof( vec3_t ) * m_pRenderModel->numverts ); // set intermediate vertex buffers m_pxmesh = m_pCurrentEntity->meshes; diff --git a/server/ents/basefunc.cpp b/server/ents/basefunc.cpp index 421035bf..1df836c6 100644 --- a/server/ents/basefunc.cpp +++ b/server/ents/basefunc.cpp @@ -573,7 +573,7 @@ void CFuncMonitor::StartMessage( CBasePlayer *pPlayer ) { //send monitor index MESSAGE_BEGIN( MSG_ONE, gmsg.AddScreen, NULL, pPlayer->pev ); - WRITE_BYTE( entindex() ); + WRITE_SHORT( entindex() ); MESSAGE_END(); ChangeCamera( pev->target ); } @@ -671,7 +671,7 @@ void CFuncTeleport::StartMessage( CBasePlayer *pPlayer ) { //send portal index MESSAGE_BEGIN( MSG_ONE, gmsg.AddPortal, NULL, pPlayer->pev ); - WRITE_BYTE( entindex() ); + WRITE_SHORT( entindex() ); MESSAGE_END(); ChangeCamera( pev->target ); } @@ -1342,7 +1342,7 @@ void CPendulum :: Think( void ) } // FIXME: test - if( fabs(cos(wave)) < 0.05f ) + if( fabs(cos(wave)) < 0.01f ) { EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise3 ), m_flVolume, ATTN_IDLE, SND_CHANGE_VOL, PITCH_NORM ); } diff --git a/server/global/client.cpp b/server/global/client.cpp index bb5e3abc..2770b637 100644 --- a/server/global/client.cpp +++ b/server/global/client.cpp @@ -52,7 +52,7 @@ BOOL NewLevel = FALSE; float MsgDelay; user_messages_t gmsg; void LinkUserMessages( void ); -char text[128]; +char text[256]; extern int g_teamplay; //messages affect only player @@ -1141,22 +1141,24 @@ const char *GetGameDescription( void ) char szbuffer[128]; char *pfile = (char *)LOAD_FILE( "gameinfo.txt", NULL ); + memset( text, 0, sizeof( text )); + if( pfile ) { while( pfile ) { if( !stricmp( token, "title" )) { - pfile = COM_ParseFile(pfile, token); + pfile = COM_ParseFile( pfile, token ); sprintf( szbuffer, "%s ", token ); - strcat( text, szbuffer ); + strncat( text, szbuffer, sizeof( text )); } else if( !stricmp( token, "version" )) { - pfile = COM_ParseFile(pfile, token); - strcat( text, token ); + pfile = COM_ParseFile( pfile, token ); + strncat( text, token, sizeof( text )); } - pfile = COM_ParseFile(pfile, token); + pfile = COM_ParseFile( pfile, token ); } COM_FreeFile( pfile ); return text; @@ -1221,8 +1223,8 @@ void LinkUserMessages( void ) gmsg.CamData = REG_USER_MSG("CamData", -1); gmsg.Fsound = REG_USER_MSG("Fsound", -1); gmsg.RainData = REG_USER_MSG("RainData", 16); - gmsg.AddScreen = REG_USER_MSG( "AddScreen", 1); - gmsg.AddPortal = REG_USER_MSG( "AddPortal", 1); + gmsg.AddScreen = REG_USER_MSG( "AddScreen", 2); + gmsg.AddPortal = REG_USER_MSG( "AddPortal", 2); gmsg.HudText = REG_USER_MSG( "HudText", -1 ); gmsg.ShowGameTitle = REG_USER_MSG("GameTitle", 1); gmsg.TempEntity = REG_USER_MSG( "TempEntity", -1); diff --git a/todo.log b/todo.log index 001d103f..0f0432f1 100644 --- a/todo.log +++ b/todo.log @@ -79,9 +79,10 @@ Beta 13.12.08 48. building uimenu.dll 49. implement new timers OK 50. fixup network packets rate -51. fixup stair climbing -52. implement new user move system - +51. fixup stair climbing OK +52. implement new user move system OK +53. finish RenderMode for shaders OK +54. q1/hl1 bsp format ? Список доступных рендереров: Что в них интересного 0. Q3Fusion (Mirrors, Portals) diff --git a/xtools/ripper/conv_doom.c b/xtools/ripper/conv_doom.c index a7ca1969..d964857f 100644 --- a/xtools/ripper/conv_doom.c +++ b/xtools/ripper/conv_doom.c @@ -162,7 +162,7 @@ static void Conv_FreeTracks( struct track_s track[] ) for( i = 0; i < 16; i++ ) { - if(track[i].data) Mem_Free( track[i].data ) ; + if( track[i].data ) Mem_Free( track[i].data ) ; } } @@ -192,7 +192,7 @@ static void Conv_WriteByte( char MIDItrack, char byte, struct track_s track[] ) else { Conv_FreeTracks( track ); - Sys_Break("Not enough memory" ); + Sys_Break( "not enough memory\n" ); } track[MIDItrack].current++; } @@ -379,7 +379,7 @@ static bool Conv_Mus2Mid( const char *musicname, byte *buffer, int bufsize ) case 5: case 7: Conv_FreeTracks( track ); - MsgDev(D_ERROR, "Conv_Mus2Mid: bad event\n" ); + MsgDev( D_ERROR, "Conv_Mus2Mid: bad event\n" ); return false; default: break; @@ -402,7 +402,7 @@ static bool Conv_Mus2Mid( const char *musicname, byte *buffer, int bufsize ) } if( ouch ) MsgDev(D_WARN, "Conv_Mus2Mid: %s.mus - end of file probably corrupted\n", musicname ); - f = FS_Open(va("%s/%s.mid", gs_gamedir, musicname ), "wb" ); + f = FS_Open(va( "%s/%s.mid", gs_gamedir, musicname ), "wb" ); file_mid = VFS_Open( f, "w" ); Conv_WriteMIDheader( file_mid, TrackCnt + 1, division ); @@ -411,7 +411,7 @@ static bool Conv_Mus2Mid( const char *musicname, byte *buffer, int bufsize ) for( i = 0; i < (int)TrackCnt; i++ ) Conv_WriteTrack( file_mid, i, track ); Conv_FreeTracks( track ); - FS_Close(VFS_Close( file_mid )); + FS_Close( VFS_Close( file_mid )); VFS_Close( file_mus ); return true; @@ -573,7 +573,7 @@ void Skin_ProcessScript( const char *wad, const char *name ) { // start from scratch com.strncpy( flat.membername, name, 5 ); - flat.f = FS_Open( va("%s/%s/%s.qc", gs_gamedir, wad, flat.membername ), "w" ); + flat.f = FS_Open( va( "%s/%s/%s.qc", gs_gamedir, wad, flat.membername ), "w" ); flat.in_progress = true; flat.bounds[0] = flat.bounds[1] = 0; @@ -587,7 +587,7 @@ void Skin_ProcessScript( const char *wad, const char *name ) FS_Printf( flat.f, "\n$spritename\t%s.spr\n", flat.membername ); FS_Print( flat.f, "$type\t\tfacing_upright\n" ); // constant FS_Print( flat.f, "$texture\t\talphatest\n"); - FS_Print( flat.f, "$noresample\n" ); // comment this commad by taste + FS_Print( flat.f, "$noresample\n" ); // comment this command by taste } } @@ -648,7 +648,7 @@ bool ConvFLP( const char *name, byte *buffer, size_t filesize, const char *ext ) if( pic ) { FS_SaveImage(va("%s/%s.%s", gs_gamedir, name, ext ), pic ); - Msg("%s.flat\n", name ); // echo to console + Msg( "%s.flat\n", name ); // echo to console FS_FreeImage( pic ); return true; } @@ -679,7 +679,7 @@ bool ConvFLT( const char *name, byte *buffer, size_t filesize, const char *ext ) FS_SaveImage( va("%s/%s.%s", gs_gamedir, savedname, ext ), pic ); Conv_CreateShader( savedname, pic, "flt", NULL, 0, 0 ); - Msg("%s.flat\n", savedname ); // echo to console + Msg( "%s.flat\n", savedname ); // echo to console FS_FreeImage( pic ); return true; } @@ -695,7 +695,7 @@ bool ConvMID( const char *name, byte *buffer, size_t filesize, const char *ext ) { if(Conv_Mus2Mid( name, buffer, filesize )) { - Msg("%s.mus\n", name ); // echo to console + Msg( "%s.mus\n", name ); // echo to console return true; } return false; diff --git a/xtools/xtools.c b/xtools/xtools.c index 3529ce74..759926c2 100644 --- a/xtools/xtools.c +++ b/xtools/xtools.c @@ -233,7 +233,6 @@ launch_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, void *unused ) Com.Main = CommonMain; Com.Free = FreeCommon; Com.CPrint = BSP_PrintLog; - Com.MSG_Init = NULL; return &Com; } \ No newline at end of file