/* =========== IN_Init =========== */ void IN_Init (void) { int MajorVersion = 0, MinorVersion = 0; qboolean DGA = false; Cvar_RegisterVariable (&m_filter, NULL); Cmd_AddCommand ("force_centerview", Force_CenterView_f); if (COM_CheckParm ("-nomouse")) mouse_available = false; else mouse_available = true; mouse_grab_active = false; dga_mouse_available = false; dga_mouse_active = false; /* if (COM_CheckParm ("-nokeyb")) keyboard_available = false; else */ keyboard_available = true; keyboard_grab_active = false; dga_keyboard_available = false; dga_keyboard_active = false; if (x_disp == NULL) Sys_Error ("IN_Init: x_disp not initialised before input..."); DGA = XF86DGAQueryVersion(x_disp, &MajorVersion, &MinorVersion); if(COM_CheckParm("-nodga")) { Con_Warning ("XFree86 DGA extension disabled at command line\n"); } else if (DGA) { Con_Printf ("XFree86 DGA extension version %d.%d found\n", MajorVersion, MinorVersion); if (COM_CheckParm("-nodgamouse")) Con_Warning ("XFree86 DGA Mouse disabled at command line\n"); else dga_mouse_available = true; if (COM_CheckParm("-nodgakeyb")) Con_Warning ("XFree86 DGA Keyboard disabled at command line\n"); else dga_keyboard_available = true; } else { Con_Warning ("XFree86 DGA extension not supported\n"); } IN_GrabMouse(); // grab mouse first! IN_GrabKeyboard(); }
void IN_StartupJoystick (void) { int i; int nummappings; char controllerdb[MAX_OSPATH]; SDL_GameController *gamecontroller; if (COM_CheckParm("-nojoy")) return; if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1 ) { Con_Warning("could not initialize SDL Game Controller\n"); return; } // Load additional SDL2 controller definitions from gamecontrollerdb.txt q_snprintf (controllerdb, sizeof(controllerdb), "%s/gamecontrollerdb.txt", com_basedir); nummappings = SDL_GameControllerAddMappingsFromFile(controllerdb); if (nummappings > 0) Con_Printf("%d mappings loaded from gamecontrollerdb.txt\n", nummappings); // Also try host_parms->userdir if (host_parms->userdir != host_parms->basedir) { q_snprintf (controllerdb, sizeof(controllerdb), "%s/gamecontrollerdb.txt", host_parms->userdir); nummappings = SDL_GameControllerAddMappingsFromFile(controllerdb); if (nummappings > 0) Con_Printf("%d mappings loaded from gamecontrollerdb.txt\n", nummappings); } for (i = 0; i < SDL_NumJoysticks(); i++) { const char *joyname = SDL_JoystickNameForIndex(i); if ( SDL_IsGameController(i) ) { const char *controllername = SDL_GameControllerNameForIndex(i); gamecontroller = SDL_GameControllerOpen(i); if (gamecontroller) { Con_Printf("detected controller: %s\n", controllername != NULL ? controllername : "NULL"); joy_active_instaceid = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller)); joy_active_controller = gamecontroller; break; } else { Con_Warning("failed to open controller: %s\n", controllername != NULL ? controllername : "NULL"); } } else { Con_Warning("joystick missing controller mappings: %s\n", joyname != NULL ? joyname : "NULL" ); } } }
void Sky_LoadCloudTexture(const char *cPath) { char cFileName[PLATFORM_MAX_PATH]; unsigned int iWidth,iHeight; uint8_t *bData; if(!cPath[0]) return; sprintf(cFileName, "%ssky/%scloud", g_state.cTexturePath, cPath); bData = Image_LoadImage(cFileName,&iWidth,&iHeight); if(bData) gCloudTexture = TexMgr_LoadImage( cl.worldmodel, cFileName, iWidth,iHeight, SRC_RGBA, bData, cFileName, 0, TEXPREF_ALPHA); else { Con_Warning("Failed to load %s!\n",cFileName); return; } }
void Window_UpdateVideo(void) { if (Video.msaa_samples != cv_video_msaasamples.iValue) { // TODO: Destroy window etc. Video.msaa_samples = cv_video_msaasamples.iValue; } SDL_SetWindowSize(sMainWindow, Video.iWidth, Video.iHeight); if (Video.vertical_sync != cv_video_verticlesync.bValue) { SDL_GL_SetSwapInterval(cv_video_verticlesync.iValue); Video.vertical_sync = cv_video_verticlesync.bValue; } if (Video.fullscreen != cv_video_fullscreen.bValue) { if (SDL_SetWindowFullscreen(sMainWindow, (SDL_bool)cv_video_fullscreen.bValue) == -1) { Con_Warning("Failed to set window mode!\n%s", SDL_GetError()); // Reset the variable to the current value. Cvar_SetValue(cv_video_fullscreen.name, Video.fullscreen); } else Video.fullscreen = cv_video_fullscreen.bValue; } if (!cv_video_fullscreen.value) // Center the window, to ensure it's not off screen. SDL_SetWindowPosition(sMainWindow, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); }
/* =========== IN_GrabMouse =========== */ void IN_GrabMouse (void) { if (mouse_available && !mouse_grab_active && x_win) { XWindowAttributes attribs_1; XSetWindowAttributes attribs_2; XGetWindowAttributes(x_disp, x_win, &attribs_1); attribs_2.event_mask = attribs_1.your_event_mask | KEY_MASK | MOUSE_MASK; XChangeWindowAttributes(x_disp, x_win, CWEventMask, &attribs_2); // hide cursor XDefineCursor(x_disp, x_win, CreateNullCursor()); // grab pointer XGrabPointer(x_disp, x_win, True, 0, GrabModeAsync, GrabModeAsync, x_win, None, CurrentTime); if (dga_mouse_available) { if (!vidmode_fullscreen && (vid.width < 640 || vid.height < 480)) Con_Warning ("Running low-res windowed mode, XFree86 DGA Mouse disabled\n"); else IN_ActivateDGAMouse(); } mouse_grab_active = true; } }
void _Material_AddSkin(Material_t *mCurrentMaterial, MaterialFunctionContext_t mftContext, char *cArg) { // Proceed to the next line. Script_GetToken(true); if (cToken[0] == '{') { while (true) { if (!Script_GetToken(true)) { Con_Warning("End of field without closing brace! (%s) (%i)\n", mCurrentMaterial->cPath, iScriptLine); break; } material_currentcontext = MATERIAL_FUNCTION_SKIN; if (cToken[0] == '}') { mCurrentMaterial->iSkins++; break; } // '$' declares that the following is a function. else if (cToken[0] == SCRIPT_SYMBOL_FUNCTION) Material_CheckFunctions(mCurrentMaterial); // '%' declares that the following is a variable. else if (cToken[0] == SCRIPT_SYMBOL_VARIABLE) { /* TODO: * Collect variable * Check it against internal solutions * Otherwise declare it, figure out where/how it's used */ } else { Con_Warning("Invalid field! (%s) (%i)\n", mCurrentMaterial->cPath, iScriptLine); break; } } } else Con_Warning("Invalid skin, no opening brace! (%s) (%i)\n", mCurrentMaterial->cPath, iScriptLine); }
bool Material_Precache(const char *ccPath) { Material_t *mNewMaterial; mNewMaterial = Material_Load(ccPath); if (!mNewMaterial) { Con_Warning("Failed to load material! (%s)\n", ccPath); return false; } return true; }
sfxcache_t *S_LoadSound (sfx_t *s) { char namebuffer[512]; wavinfo_t info; int len; float stepscale; sfxcache_t *sc; // see if still in memory sc = (sfxcache_t*)Cache_Check(&s->cache); if(sc) return sc; // load it in strncpy(namebuffer, g_state.cSoundPath, sizeof(namebuffer)); strcat(namebuffer, s->name); uint8_t *data = (uint8_t*)COM_LoadHeapFile(namebuffer); if (!data) { Con_Warning("Couldn't load %s\n", namebuffer); return NULL; } info = GetWavinfo (s->name, data, com_filesize); stepscale = (float)info.rate / shm->speed; len = info.samples / stepscale; len = len * info.width * info.channels; sc = (sfxcache_t*)Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name); if (!sc) { free(data); return NULL; } sc->length = info.samples; sc->loopstart = info.loopstart; sc->speed = info.rate; sc->width = info.width; sc->stereo = info.channels; ResampleSfx (s, sc->speed, sc->width, data + info.dataofs); free(data); return sc; }
void _Material_SetTextureEnvironmentMode(Material_t *Material, MaterialFunctionContext_t Context, char *cArg) { MaterialSkin_t *sCurrentSkin; sCurrentSkin = Material_GetSkin(Material, Material->iSkins); int i; for (i = 0; i < pARRAYELEMENTS(EnvironmentModes); i++) if (!strncmp(EnvironmentModes[i].ccVarName, cArg, strlen(EnvironmentModes[i].ccVarName))) { sCurrentSkin->mtTexture[sCurrentSkin->uiTextures].EnvironmentMode = EnvironmentModes[i].Mode; return; } Con_Warning("Invalid texture environment mode! (%s) (%s)\n", cArg, Material->cName); }
sfxcache_t *S_LoadSound (sfx_t *s) { char namebuffer[512]; byte *data; wavinfo_t info; int len; float stepscale; sfxcache_t *sc; byte stackbuf[1*1024]; // avoid dirtying the cache heap // see if still in memory sc = (sfxcache_t*)Cache_Check(&s->cache); if(sc) return sc; // load it in Q_strcpy(namebuffer,Global.cSoundPath); Q_strcat(namebuffer,s->name); data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf)); if (!data) { Con_Warning("Couldn't load %s\n", namebuffer); return NULL; } info = GetWavinfo (s->name, data, com_filesize); stepscale = (float)info.rate / shm->speed; len = info.samples / stepscale; len = len * info.width * info.channels; sc = (sfxcache_t*)Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name); if (!sc) return NULL; sc->length = info.samples; sc->loopstart = info.loopstart; sc->speed = info.rate; sc->width = info.width; sc->stereo = info.channels; ResampleSfx (s, sc->speed, sc->width, data + info.dataofs); return sc; }
void R_CheckEfrags (void) { efrag_t *ef; int count; if (cls.signon < 2) return; //don't spam when still parsing signon packet full of static ents for (count=MAX_EFRAGS, ef = cl.free_efrags; ef; count--, ef = ef->entnext) ; if (count > 640 && dev_peakstats.efrags <= 640) Con_Warning ("%i efrags exceeds standard limit of 640.\n", count); dev_stats.efrags = count; dev_peakstats.efrags = Math_Max(count,dev_peakstats.efrags); }
Material_t *Material_GetByPath(const char *ccPath) { int i; if(ccPath[0] == ' ') { Con_Warning("Attempted to find material, but recieved invalid path!\n"); return NULL; } for (i = 0; i < iMaterialCount; i++) if (mMaterials[i].cPath[0]) if (!strncmp(mMaterials[i].cPath, ccPath, sizeof(mMaterials[i].cPath))) return &mMaterials[i]; return NULL; }
/* Returns true on success. Unfinished */ Material_t *Material_GetByName(const char *ccMaterialName) { int i; if(ccMaterialName[0] == ' ') { Con_Warning("Attempted to find material, but recieved invalid material name!\n"); return NULL; } for (i = 0; i < iMaterialCount; i++) // If the material has no name, then it's not valid. if (mMaterials[i].cName[0]) if (!strncmp(mMaterials[i].cName, ccMaterialName, sizeof(mMaterials[i].cName))) return &mMaterials[i]; return NULL; }
/* =========== IN_GrabKeyboard =========== */ void IN_GrabKeyboard (void) { if (keyboard_available && !keyboard_grab_active && x_win) { // grab keyboard XGrabKeyboard(x_disp, x_win, False, GrabModeAsync, GrabModeAsync, CurrentTime); if (dga_keyboard_available) { if (!vidmode_fullscreen && (vid.width < 640 || vid.height < 480)) Con_Warning ("Running low-res windowed mode, XFree86 DGA Keyboard disabled\n"); else IN_ActivateDGAKeyboard(); } keyboard_grab_active = true; } }
void SV_CheckAllEnts (void) { int e; edict_t *check; // See if any solid entities are inside the final position check = NEXT_EDICT(sv.edicts); for(e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if( check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; if (SV_TestEntityPosition (check)) Con_Warning("Entity in invalid position!\n"); } }
/* Returns a material from the given ID. */ Material_t *Material_Get(int iMaterialID) { int i; // The identification would never be less than 0, and never more than our maximum. if (iMaterialID < 0 || iMaterialID > MATERIAL_MAX) { Con_Warning("Invalid material ID! (%i)\n",iMaterialID); return NULL; } for (i = 0; i < iMaterialCount; i++) if (mMaterials[i].iIdentification == iMaterialID) { mMaterials[i].bBind = true; return &mMaterials[i]; } return NULL; }
void _Material_SetType(Material_t *mCurrentMaterial, MaterialFunctionContext_t mftContext, char *cArg) { switch (mftContext) { case MATERIAL_FUNCTION_SKIN: { int iMaterialType = Q_atoi(cArg); // Ensure that the given type is valid. if ((iMaterialType < MATERIAL_TYPE_NONE) || (iMaterialType >= MATERIAL_TYPE_MAX)) Con_Warning("Invalid material type! (%i)\n", iMaterialType); mCurrentMaterial->msSkin[mCurrentMaterial->iSkins].uiType = iMaterialType; } break; case MATERIAL_FUNCTION_TEXTURE: _Material_SetTextureType(mCurrentMaterial, mftContext, cArg); break; default: Sys_Error("Invalid context!\n"); } }
void SCR_ScreenShot_f (void) { uint8_t *buffer; char tganame[32], checkname[PLATFORM_MAX_PATH]; int i; if (!plCreateDirectory(va("%s/%s", com_gamedir, g_state.cScreenshotPath))) Sys_Error("Failed to create directory!\n%s", plGetError()); // find a file name to save it to for (i = 0; i < 10000; i++) { sprintf(tganame, "%s%04i.tga", g_state.cScreenshotPath, i); sprintf(checkname,"%s/%s",com_gamedir,tganame); if(Sys_FileTime(checkname) == -1) break; // file doesn't exist } if(i >= 10000) { Con_Printf ("SCR_ScreenShot_f: Couldn't find an unused filename\n"); return; } //get data buffer = (uint8_t*)malloc(glwidth*glheight*3); glReadPixels(glx,gly,glwidth,glheight,GL_RGB,GL_UNSIGNED_BYTE,buffer); // now write the file if(Image_WriteTGA(tganame,buffer,glwidth,glheight,24,false)) Con_Printf("Wrote %s\n",tganame); else Con_Warning("Failed to write %s\n",tganame); free (buffer); }
/* Set flags for the material. */ void _Material_SetFlags(Material_t *mCurrentMaterial, MaterialFunctionContext_t mftContext, char *cArg) { int i; // Search through and copy each flag into the materials list of flags. for (i = 0; i < pARRAYELEMENTS(mfMaterialFlags); i++) { if (strstr(cArg, mfMaterialFlags[i].ccName)) { if (mfMaterialFlags[i].mftContext != mftContext) continue; switch (mftContext) { case MATERIAL_FUNCTION_MATERIAL: if (mfMaterialFlags[i].flags == MATERIAL_FLAG_ANIMATED) { mCurrentMaterial->iAnimationFrame = 0; mCurrentMaterial->dAnimationTime = 0; } mCurrentMaterial->iFlags |= mfMaterialFlags[i].flags; break; case MATERIAL_FUNCTION_SKIN: mCurrentMaterial->msSkin[mCurrentMaterial->iSkins].uiFlags |= mfMaterialFlags[i].flags; break; case MATERIAL_FUNCTION_TEXTURE: mCurrentMaterial->msSkin[mCurrentMaterial->iSkins].mtTexture [mCurrentMaterial->msSkin[mCurrentMaterial->iSkins].uiTextures].uiFlags |= mfMaterialFlags[i].flags; break; default: Con_Warning("Invalid context! (%s) (%s) (%i)\n", mCurrentMaterial->cName, mfMaterialFlags[i].ccName, mftContext); } } } }
void Material_CheckFunctions(Material_t *mNewMaterial) { MaterialKey_t *mKey; // Find the related function. for (mKey = MaterialFunctions; mKey->cKey; mKey++) // Remain case sensitive. if (!Q_strcasecmp(mKey->cKey, cToken + 1)) { /* todo account for texture slots etc */ if ((mKey->mftType != MATERIAL_FUNCTION_UNIVERSAL) && (material_currentcontext != mKey->mftType)) Sys_Error("Attempted to call a function within the wrong context! (%s) (%s) (%i)\n", cToken, mNewMaterial->cPath, iScriptLine); Script_GetToken(false); mKey->Function(mNewMaterial, material_currentcontext, cToken); return; } Con_Warning("Unknown function! (%s) (%s) (%i)\n", cToken, mNewMaterial->cPath, iScriptLine); }
static void GL_CheckExtensions (void) { int swap_control; // // multitexture // if (COM_CheckParm("-nomtex")) Con_Warning ("Mutitexture disabled at command line\n"); else if (GL_ParseExtensionList(gl_extensions, "GL_ARB_multitexture")) { GL_MTexCoord2fFunc = (PFNGLMULTITEXCOORD2FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord2fARB"); GL_SelectTextureFunc = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB"); if (GL_MTexCoord2fFunc && GL_SelectTextureFunc) { Con_Printf("FOUND: ARB_multitexture\n"); TEXTURE0 = GL_TEXTURE0_ARB; TEXTURE1 = GL_TEXTURE1_ARB; gl_mtexable = true; } else { Con_Warning ("Couldn't link to multitexture functions\n"); } } else if (GL_ParseExtensionList(gl_extensions, "GL_SGIS_multitexture")) { GL_MTexCoord2fFunc = (PFNGLMULTITEXCOORD2FARBPROC) SDL_GL_GetProcAddress("glMTexCoord2fSGIS"); GL_SelectTextureFunc = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glSelectTextureSGIS"); if (GL_MTexCoord2fFunc && GL_SelectTextureFunc) { Con_Printf("FOUND: SGIS_multitexture\n"); TEXTURE0 = TEXTURE0_SGIS; TEXTURE1 = TEXTURE1_SGIS; gl_mtexable = true; } else { Con_Warning ("Couldn't link to multitexture functions\n"); } } else { Con_Warning ("multitexture not supported (extension not found)\n"); } // // texture_env_combine // if (COM_CheckParm("-nocombine")) Con_Warning ("texture_env_combine disabled at command line\n"); else if (GL_ParseExtensionList(gl_extensions, "GL_ARB_texture_env_combine")) { Con_Printf("FOUND: ARB_texture_env_combine\n"); gl_texture_env_combine = true; } else if (GL_ParseExtensionList(gl_extensions, "GL_EXT_texture_env_combine")) { Con_Printf("FOUND: EXT_texture_env_combine\n"); gl_texture_env_combine = true; } else { Con_Warning ("texture_env_combine not supported\n"); } // // texture_env_add // if (COM_CheckParm("-noadd")) Con_Warning ("texture_env_add disabled at command line\n"); else if (GL_ParseExtensionList(gl_extensions, "GL_ARB_texture_env_add")) { Con_Printf("FOUND: ARB_texture_env_add\n"); gl_texture_env_add = true; } else if (GL_ParseExtensionList(gl_extensions, "GL_EXT_texture_env_add")) { Con_Printf("FOUND: EXT_texture_env_add\n"); gl_texture_env_add = true; } else { Con_Warning ("texture_env_add not supported\n"); } // // swap control (the "after SDL_SetVideoMode" part) // if (!gl_swap_control) { Con_Warning ("vertical sync not supported (SDL_GL_SetAttribute failed)\n"); } else if (SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &swap_control) == -1) { gl_swap_control = false; Con_Warning ("vertical sync not supported (SDL_GL_GetAttribute failed)\n"); } else if ((vid_vsync.value && swap_control != 1) || (!vid_vsync.value && swap_control != 0)) { gl_swap_control = false; Con_Warning ("vertical sync not supported (swap_control doesn't match vid_vsync)\n"); } else { Con_Printf("FOUND: SDL_GL_SWAP_CONTROL\n"); } // // anisotropic filtering // if (GL_ParseExtensionList(gl_extensions, "GL_EXT_texture_filter_anisotropic")) { float test1,test2; GLuint tex; // test to make sure we really have control over it // 1.0 and 2.0 should always be legal values glGenTextures(1, &tex); glBindTexture (GL_TEXTURE_2D, tex); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test1); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f); glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test2); glDeleteTextures(1, &tex); if (test1 == 1 && test2 == 2) { Con_Printf("FOUND: EXT_texture_filter_anisotropic\n"); gl_anisotropy_able = true; } else { Con_Warning ("anisotropic filtering locked by driver. Current driver setting is %f\n", test1); } //get max value either way, so the menu and stuff know it glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_anisotropy); if (gl_max_anisotropy < 2) { gl_anisotropy_able = false; gl_max_anisotropy = 1; Con_Warning ("anisotropic filtering broken: disabled\n"); } } else { gl_max_anisotropy = 1; Con_Warning ("texture_filter_anisotropic not supported\n"); } }
/* ================== SV_StartSound Each entity can have eight independant sound sources, like voice, weapon, feet, etc. Channel 0 is an auto-allocate channel, the others override anything already running on that entity/channel pair. An attenuation of 0 will play full volume everywhere in the level. Larger attenuations will drop off. (max 4 attenuation) ================== */ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, float attenuation) { int sound_num; int field_mask; int i; int ent; static float lastmsg = 0; if (volume < 0 || volume > 255) { Con_Warning ("SV_StartSound: volume = %d, max = %d\n", volume, 255); volume = CLAMP(0, volume, 255); } if (attenuation < 0 || attenuation > 4) { Con_Warning ("SV_StartSound: attenuation = %f, max = %d\n", attenuation, 4); attenuation = CLAMP(0, attenuation, 4); } if (channel < 0 || channel > 7) { Con_Warning ("SV_StartSound: channel = %i, max = %d\n", channel, 7); channel = CLAMP(0, channel, 7); } // drop silently if there is no room if (sv.datagram.cursize > ((sv.protocol == PROTOCOL_NETQUAKE) ? 1024 : MAX_DATAGRAM) - 16) return; // find precache number for sound for (sound_num=1 ; sound_num<MAX_SOUNDS && sv.sound_precache[sound_num] ; sound_num++) if (!strcmp(sample, sv.sound_precache[sound_num])) break; if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] ) { if (IsTimeout (&lastmsg, 2)) { // let's not upset and annoy the user Con_DPrintf ("SV_StartSound: %s not precacheed\n", sample); } return; } ent = NUM_FOR_EDICT(entity); field_mask = 0; if (volume != DEFAULT_SOUND_PACKET_VOLUME) field_mask |= SND_VOLUME; if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) field_mask |= SND_ATTENUATION; //johnfitz -- PROTOCOL_FITZQUAKE if (ent >= 8192) { if (sv.protocol == PROTOCOL_FITZQUAKE || sv.protocol == PROTOCOL_MARKV || sv.protocol == PROTOCOL_RMQ) field_mask |= SND_LARGEENTITY; else return; // don't send any info protocol can't support } if (sound_num >= 256 || channel >= 8) { if (sv.protocol == PROTOCOL_FITZQUAKE || sv.protocol == PROTOCOL_MARKV || sv.protocol == PROTOCOL_RMQ) field_mask |= SND_LARGESOUND; else return; // don't send any info protocol can't support } //johnfitz // directed messages go only to the entity the are targeted on MSG_WriteByte (&sv.datagram, svc_sound); MSG_WriteByte (&sv.datagram, field_mask); if (field_mask & SND_VOLUME) MSG_WriteByte (&sv.datagram, volume); if (field_mask & SND_ATTENUATION) MSG_WriteByte (&sv.datagram, attenuation*64); //johnfitz -- PROTOCOL_FITZQUAKE if (field_mask & SND_LARGEENTITY) { MSG_WriteShort (&sv.datagram, ent); MSG_WriteByte (&sv.datagram, channel); } else MSG_WriteShort (&sv.datagram, (ent<<3) | channel); if (field_mask & SND_LARGESOUND) MSG_WriteShort (&sv.datagram, sound_num); else MSG_WriteByte (&sv.datagram, sound_num); //johnfitz for (i=0 ; i<3 ; i++) MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]), sv.protocolflags); }
int Datagram_GetMessage (qsocket_t *sock) { unsigned int length; unsigned int flags; int ret = 0; struct qsockaddr readaddr; unsigned int sequence; unsigned int count; if (!sock->canSend) if ((net_time - sock->lastSendTime) > 1.0) ReSendMessage (sock); while(1) { length = sock->landriver->Read(sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr); /* // for testing packet loss effects if ((rand() & 255) > 220) continue; */ if (length == 0) break; if ((int)length == -1) { Con_Printf("Read error\n"); return -1; } // added !sock->net_wait (NAT fix) if (!sock->net_wait && sock->landriver->AddrCompare(&readaddr, &sock->addr) != 0) { #ifdef DEBUG Con_DPrintf("Forged packet received\n"); Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr)); Con_DPrintf("Received: %s\n", StrAddr (&readaddr)); #endif continue; } if (length < NET_HEADERSIZE) { shortPacketCount++; continue; } length = BigLong(packetBuffer.length); flags = length & (~NETFLAG_LENGTH_MASK); length &= NETFLAG_LENGTH_MASK; // ProQuake extra protection if (length > NET_DATAGRAMSIZE) { Con_Warning ("Datagram_GetMessage: excessive datagram length (%d, max = %d)\n", length, NET_DATAGRAMSIZE); return -1; } if (flags & NETFLAG_CTL) continue; sequence = BigLong(packetBuffer.sequence); packetsReceived++; // NAT fix if (sock->net_wait) { sock->addr = readaddr; strcpy(sock->address, sock->landriver->AddrToString(&readaddr)); sock->net_wait = false; } if (flags & NETFLAG_UNRELIABLE) { if (sequence < sock->unreliableReceiveSequence) { Con_DPrintf("Got a stale datagram\n"); ret = 0; break; } if (sequence != sock->unreliableReceiveSequence) { count = sequence - sock->unreliableReceiveSequence; droppedDatagrams += count; Con_DPrintf("Dropped %u datagram(s)\n", count); } sock->unreliableReceiveSequence = sequence + 1; length -= NET_HEADERSIZE; SZ_Clear (net_message->message); SZ_Write (net_message->message, packetBuffer.data, length); ret = 2; break; } if (flags & NETFLAG_ACK) { if (sequence != (sock->sendSequence - 1)) { Con_DPrintf("Stale ACK received\n"); continue; } if (sequence == sock->ackSequence) { sock->ackSequence++; if (sock->ackSequence != sock->sendSequence) Con_DPrintf("ack sequencing error\n"); } else { Con_DPrintf("Duplicate ACK received\n"); continue; } sock->sendMessageLength -= MAX_DATAGRAM; if (sock->sendMessageLength > 0) { // FIXME: was memcpy memmove(sock->sendMessage, sock->sendMessage + MAX_DATAGRAM, sock->sendMessageLength); sock->sendNext = true; } else { sock->sendMessageLength = 0; sock->canSend = true; } continue; } if (flags & NETFLAG_DATA) { packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK); packetBuffer.sequence = BigLong(sequence); sock->landriver->Write(sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr); if (sequence != sock->receiveSequence) { receivedDuplicateCount++; continue; } sock->receiveSequence++; length -= NET_HEADERSIZE; if (flags & NETFLAG_EOM) { SZ_Clear(net_message->message); SZ_Write(net_message->message, sock->receiveMessage, sock->receiveMessageLength); SZ_Write(net_message->message, packetBuffer.data, length); sock->receiveMessageLength = 0; ret = 1; break; } memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length); sock->receiveMessageLength += length; continue; } } if (sock->sendNext) SendMessageNext (sock); return ret; }
void Physics_ServerFrame(void) { int i; edict_t *eEntity; // Let the progs know that a new frame has started pr_global_struct.self = EDICT_TO_PROG(sv.edicts); pr_global_struct.eOther = sv.edicts; // TODO: should we pass the time to this? ~hogsy Game->Server_StartFrame(); // Treat each object in turn eEntity = sv.edicts; for(i = 0; i < sv.num_edicts; i++,eEntity = NEXT_EDICT(eEntity)) { if(eEntity->free) continue; if(pr_global_struct.force_retouch) SV_LinkEdict(eEntity,true); // Force retouch even for stationary // [11/7/2013] Cleaned this up and gave it its own function ~hogsy Game->Server_EntityFrame(eEntity); if(i > 0 && i <= svs.maxclients) SV_Physics_Client(eEntity,i); else { switch(eEntity->v.movetype) { case MOVETYPE_NONE: Server_RunThink(eEntity); break; case MOVETYPE_PUSH: SV_Physics_Pusher(eEntity); break; case MOVETYPE_NOCLIP: Physics_NoClip(eEntity); break; case MOVETYPE_WALK: case MOVETYPE_STEP: Game->Physics_CheckVelocity(eEntity); Game->Physics_SetGravity(eEntity); Physics_AddFriction(eEntity,eEntity->v.velocity,eEntity->v.origin); SV_WalkMove(eEntity); SV_LinkEdict(eEntity,true); Server_RunThink(eEntity); break; case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: case MOVETYPE_FLYBOUNCE: Physics_Toss(eEntity); break; default: Con_Warning("Bad movetype set for entity! (%s)",eEntity->v.cClassname); } } } if(pr_global_struct.force_retouch) pr_global_struct.force_retouch--; sv.time += host_frametime; }
void Sky_LoadSkyBox (char *name) { int i, mark; unsigned int width, height; char filename[PLATFORM_MAX_PATH]; bool bNoneFound = true; uint8_t *data; if(strcmp(cSkyBoxName, name) == 0) return; //no change // Purge old textures for(i = 0; i < 6; i++) { if(gSkyBoxTexture[i] && gSkyBoxTexture[i] != notexture) TexMgr_FreeTexture(gSkyBoxTexture[i]); gSkyBoxTexture[i] = NULL; } // Turn off skybox if sky is set to "" if(name[0] == 0) { cSkyBoxName[0] = 0; return; } // Load textures for (i=0; i<6; i++) { mark = Hunk_LowMark (); sprintf(filename, "%ssky/%s%s", g_state.cTexturePath, name, suf[i]); data = Image_LoadImage (filename, &width, &height); if (data) { gSkyBoxTexture[i] = TexMgr_LoadImage (cl.worldmodel, filename, width, height, SRC_RGBA, data, filename, 0, TEXPREF_NONE); bNoneFound = false; } else { Con_Warning("Couldn't load %s\n", filename); gSkyBoxTexture[i] = notexture; } Hunk_FreeToLowMark (mark); } if(bNoneFound) // go back to scrolling sky if skybox is totally missing { for(i = 0; i < 6; i++) { if(gSkyBoxTexture[i] && gSkyBoxTexture[i] != notexture) TexMgr_FreeTexture(gSkyBoxTexture[i]); gSkyBoxTexture[i] = NULL; } cSkyBoxName[0] = 0; return; } strcpy(cSkyBoxName, name); }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i; const char *str; //johnfitz int total, j, lastcmd; //johnfitz // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); lastcmd = 0; while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & U_SIGNAL) //johnfitz -- was 128, changed for clarity { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("Illegible server message, previous was %s\n", svc_strings[lastcmd]); //johnfitz -- added svc_strings[lastcmd] break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: CL_ParseClientdata (); //johnfitz -- removed bits parameter, we will read this inside CL_ParseClientdata() break; case svc_version: i = MSG_ReadLong (); //johnfitz -- support multiple protocols if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) Host_Error ("Server returned version %i, not %i or %i\n", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); cl.protocol = i; //johnfitz break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_stufftext: cls.stufftext_frame = host_framecount; // allow full frame update // in demo playback -- Pa3PyX Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); q_strlcpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING); cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); //johnfitz -- save extra info if (cl_lightstyle[i].length) { total = 0; cl_lightstyle[i].peak = 'a'; for (j=0; j<cl_lightstyle[i].length; j++) { total += cl_lightstyle[i].map[j] - 'a'; cl_lightstyle[i].peak = q_max(cl_lightstyle[i].peak, cl_lightstyle[i].map[j]); } cl_lightstyle[i].average = total / cl_lightstyle[i].length + 'a'; } else cl_lightstyle[i].average = cl_lightstyle[i].peak = 'm'; //johnfitz break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); q_strlcpy (cl.scores[i].name, MSG_ReadString(), MAX_SCOREBOARDNAME); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 1); // johnfitz -- added second parameter break; case svc_spawnstatic: CL_ParseStatic (1); //johnfitz -- added parameter break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); BGM_Pause (); } else { CDAudio_Resume (); BGM_Resume (); } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; //johnfitz -- if signonnum==2, signon packet has been fully parsed, so check for excessive static ents and efrags if (i == 2) { if (cl.num_statics > 128) Con_Warning ("%i static entities exceeds standard limit of 128.\n", cl.num_statics); R_CheckEfrags (); } //johnfitz CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (1); //johnfitz -- added parameter break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) BGM_PlayCDtrack ((byte)cls.forcetrack, true); else BGM_PlayCDtrack ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; //johnfitz -- new svc types case svc_skybox: Sky_LoadSkyBox (MSG_ReadString()); break; case svc_bf: Cmd_ExecuteString ("bf", src_command); break; case svc_fog: Fog_ParseServerMessage (); break; case svc_spawnbaseline2: //PROTOCOL_FITZQUAKE i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 2); break; case svc_spawnstatic2: //PROTOCOL_FITZQUAKE CL_ParseStatic (2); break; case svc_spawnstaticsound2: //PROTOCOL_FITZQUAKE CL_ParseStaticSound (2); break; //johnfitz } lastcmd = cmd; //johnfitz } }
/* Get gamma level. Based on the Darkplaces implementation. */ void Window_GetGamma(unsigned short *usRamp, int iRampSize) { if (!SDL_GetWindowGammaRamp(sMainWindow, usRamp, usRamp + iRampSize, usRamp + iRampSize * 2)) Con_Warning("Failed to get gamma level!\n%s", SDL_GetError()); }
void Window_InitializeVideo(void) { int iFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN; SDL_Surface *sIcon; // [28/7/2013] Moved check here and corrected, seems more secure ~hogsy if (SDL_VideoInit(NULL) < 0) Sys_Error("Failed to initialize video!\n%s\n", SDL_GetError()); SDL_DisableScreenSaver(); // Get display information. if (SDL_GetCurrentDisplayMode(0, &sDisplayMode) != 0) Sys_Error("Failed to get current display information!\n%s\n", SDL_GetError()); if (!Video.fullscreen) iFlags &= ~SDL_WINDOW_FULLSCREEN; #if 0 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); #endif SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 8); #if 0 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8); #endif SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); sMainWindow = SDL_CreateWindow( Game->Name, // [9/7/2013] Window name is based on the name given by Game ~hogsy SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Video.iWidth, Video.iHeight, iFlags); if (!sMainWindow) Sys_Error("Failed to create window!\n%s\n", SDL_GetError()); // Attempt to grab the window icon from the game directory. sIcon = SDL_LoadBMP(va("%s/icon.bmp", com_gamedir)); if (sIcon) { // [25/3/2014] Set the transparency key... ~hogsy SDL_SetColorKey(sIcon, true, SDL_MapRGB(sIcon->format, 0, 0, 0)); SDL_SetWindowIcon(sMainWindow, sIcon); SDL_FreeSurface(sIcon); } else // Give us a warning, but continue. Con_Warning("Failed to load window icon! (%s)\n", SDL_GetError()); sMainContext = SDL_GL_CreateContext(sMainWindow); if (!sMainContext) Sys_Error("Failed to create context!\n%s\n", SDL_GetError()); SDL_GL_SetSwapInterval(0); #ifdef _WIN32 if (SDL_GetWindowWMInfo(sMainWindow, &sSystemInfo)) g_mainwindow.instance = sSystemInfo.info.win.window; else Con_Warning("Failed to get WM information! (%s)\n", SDL_GetError()); #endif }
/* ================== CL_ParseServerInfo ================== */ void CL_ParseServerInfo (void) { const char *str; int i; int nummodels, numsounds; char model_precache[MAX_MODELS][MAX_QPATH]; char sound_precache[MAX_SOUNDS][MAX_QPATH]; Con_DPrintf ("Serverinfo packet received.\n"); // // wipe the client_state_t struct // CL_ClearState (); // parse protocol version number i = MSG_ReadLong (); //johnfitz -- support multiple protocols if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) { Con_Printf ("\n"); //becuase there's no newline after serverinfo print Host_Error ("Server returned version %i, not %i or %i\n", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); } cl.protocol = i; //johnfitz // parse maxclients cl.maxclients = MSG_ReadByte (); if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) { Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); return; } cl.scores = (scoreboard_t *) Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); // parse gametype cl.gametype = MSG_ReadByte (); // parse signon message str = MSG_ReadString (); q_strlcpy (cl.levelname, str, sizeof(cl.levelname)); // seperate the printfs so the server message can have a color Con_Printf ("\n%s\n", Con_Quakebar(40)); //johnfitz Con_Printf ("%c%s\n", 2, str); //johnfitz -- tell user which protocol this is Con_Printf ("Using protocol %i\n", i); // first we go through and touch all of the precache data that still // happens to be in the cache, so precaching something else doesn't // needlessly purge it // precache models memset (cl.model_precache, 0, sizeof(cl.model_precache)); for (nummodels = 1 ; ; nummodels++) { str = MSG_ReadString (); if (!str[0]) break; if (nummodels==MAX_MODELS) { Con_Printf ("Server sent too many model precaches\n"); return; } q_strlcpy (model_precache[nummodels], str, MAX_QPATH); Mod_TouchModel (str); } //johnfitz -- check for excessive models if (nummodels >= 256) Con_Warning ("%i models exceeds standard limit of 256.\n", nummodels); //johnfitz // precache sounds memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); for (numsounds = 1 ; ; numsounds++) { str = MSG_ReadString (); if (!str[0]) break; if (numsounds==MAX_SOUNDS) { Con_Printf ("Server sent too many sound precaches\n"); return; } q_strlcpy (sound_precache[numsounds], str, MAX_QPATH); S_TouchSound (str); } //johnfitz -- check for excessive sounds if (numsounds >= 256) Con_Warning ("%i sounds exceeds standard limit of 256.\n", numsounds); //johnfitz // // now we try to load everything else until a cache allocation fails // // copy the naked name of the map file to the cl structure -- O.S COM_StripExtension (COM_SkipPath(model_precache[1]), cl.mapname, sizeof(cl.mapname)); for (i = 1; i < nummodels; i++) { cl.model_precache[i] = Mod_ForName (model_precache[i], false); if (cl.model_precache[i] == NULL) { Con_Printf("Model %s not found\n", model_precache[i]); return; } CL_KeepaliveMessage (); } S_BeginPrecaching (); for (i = 1; i < numsounds; i++) { cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]); CL_KeepaliveMessage (); } S_EndPrecaching (); // local state cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; R_NewMap (); //johnfitz -- clear out string; we don't consider identical //messages to be duplicates if the map has changed in between con_lastcenterstring[0] = 0; //johnfitz Hunk_Check (); // make sure nothing is hurt noclip_anglehack = false; // noclip is turned off at start warn_about_nehahra_protocol = true; //johnfitz -- warn about nehahra protocol hack once per server connection //johnfitz -- reset developer stats memset(&dev_stats, 0, sizeof(dev_stats)); memset(&dev_peakstats, 0, sizeof(dev_peakstats)); memset(&dev_overflows, 0, sizeof(dev_overflows)); }
/* ================== CL_ParseUpdate Parse an entity update message from the server If an entities model or origin changes from frame to frame, it must be relinked. Other attributes can change without relinking. ================== */ void CL_ParseUpdate (int bits) { int i; qmodel_t *model; int modnum; qboolean forcelink; entity_t *ent; int num; int skin; if (cls.signon == SIGNONS - 1) { // first update is the final signon stage cls.signon = SIGNONS; CL_SignonReply (); } if (bits & U_MOREBITS) { i = MSG_ReadByte (); bits |= (i<<8); } //johnfitz -- PROTOCOL_FITZQUAKE if (cl.protocol == PROTOCOL_FITZQUAKE) { if (bits & U_EXTEND1) bits |= MSG_ReadByte() << 16; if (bits & U_EXTEND2) bits |= MSG_ReadByte() << 24; } //johnfitz if (bits & U_LONGENTITY) num = MSG_ReadShort (); else num = MSG_ReadByte (); ent = CL_EntityNum (num); if (ent->msgtime != cl.mtime[1]) forcelink = true; // no previous frame to lerp from else forcelink = false; //johnfitz -- lerping if (ent->msgtime + 0.2 < cl.mtime[0]) //more than 0.2 seconds since the last message (most entities think every 0.1 sec) ent->lerpflags |= LERP_RESETANIM; //if we missed a think, we'd be lerping from the wrong frame //johnfitz ent->msgtime = cl.mtime[0]; if (bits & U_MODEL) { modnum = MSG_ReadByte (); if (modnum >= MAX_MODELS) Host_Error ("CL_ParseModel: bad modnum"); } else modnum = ent->baseline.modelindex; if (bits & U_FRAME) ent->frame = MSG_ReadByte (); else ent->frame = ent->baseline.frame; if (bits & U_COLORMAP) i = MSG_ReadByte(); else i = ent->baseline.colormap; if (!i) ent->colormap = vid.colormap; else { if (i > cl.maxclients) Sys_Error ("i >= cl.maxclients"); ent->colormap = cl.scores[i-1].translations; } if (bits & U_SKIN) skin = MSG_ReadByte(); else skin = ent->baseline.skin; if (skin != ent->skinnum) { ent->skinnum = skin; if (num > 0 && num <= cl.maxclients) R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin } if (bits & U_EFFECTS) ent->effects = MSG_ReadByte(); else ent->effects = ent->baseline.effects; // shift the known values for interpolation VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); if (bits & U_ORIGIN1) ent->msg_origins[0][0] = MSG_ReadCoord (); else ent->msg_origins[0][0] = ent->baseline.origin[0]; if (bits & U_ANGLE1) ent->msg_angles[0][0] = MSG_ReadAngle(); else ent->msg_angles[0][0] = ent->baseline.angles[0]; if (bits & U_ORIGIN2) ent->msg_origins[0][1] = MSG_ReadCoord (); else ent->msg_origins[0][1] = ent->baseline.origin[1]; if (bits & U_ANGLE2) ent->msg_angles[0][1] = MSG_ReadAngle(); else ent->msg_angles[0][1] = ent->baseline.angles[1]; if (bits & U_ORIGIN3) ent->msg_origins[0][2] = MSG_ReadCoord (); else ent->msg_origins[0][2] = ent->baseline.origin[2]; if (bits & U_ANGLE3) ent->msg_angles[0][2] = MSG_ReadAngle(); else ent->msg_angles[0][2] = ent->baseline.angles[2]; //johnfitz -- lerping for movetype_step entities if (bits & U_STEP) { ent->lerpflags |= LERP_MOVESTEP; ent->forcelink = true; } else ent->lerpflags &= ~LERP_MOVESTEP; //johnfitz //johnfitz -- PROTOCOL_FITZQUAKE and PROTOCOL_NEHAHRA if (cl.protocol == PROTOCOL_FITZQUAKE) { if (bits & U_ALPHA) ent->alpha = MSG_ReadByte(); else ent->alpha = ent->baseline.alpha; if (bits & U_FRAME2) ent->frame = (ent->frame & 0x00FF) | (MSG_ReadByte() << 8); if (bits & U_MODEL2) modnum = (modnum & 0x00FF) | (MSG_ReadByte() << 8); if (bits & U_LERPFINISH) { ent->lerpfinish = ent->msgtime + ((float)(MSG_ReadByte()) / 255); ent->lerpflags |= LERP_FINISH; } else ent->lerpflags &= ~LERP_FINISH; } else if (cl.protocol == PROTOCOL_NETQUAKE) { //HACK: if this bit is set, assume this is PROTOCOL_NEHAHRA if (bits & U_TRANS) { float a, b; if (warn_about_nehahra_protocol) { Con_Warning ("nonstandard update bit, assuming Nehahra protocol\n"); warn_about_nehahra_protocol = false; } a = MSG_ReadFloat(); b = MSG_ReadFloat(); //alpha if (a == 2) MSG_ReadFloat(); //fullbright (not using this yet) ent->alpha = ENTALPHA_ENCODE(b); } else ent->alpha = ent->baseline.alpha; } //johnfitz //johnfitz -- moved here from above model = cl.model_precache[modnum]; if (model != ent->model) { ent->model = model; // automatic animation (torches, etc) can be either all together // or randomized if (model) { if (model->synctype == ST_RAND) ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; else ent->syncbase = 0.0; } else forcelink = true; // hack to make null model players work if (num > 0 && num <= cl.maxclients) R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin ent->lerpflags |= LERP_RESETANIM; //johnfitz -- don't lerp animation across model changes } //johnfitz if ( forcelink ) { // didn't have an update last message VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_origins[0], ent->origin); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); VectorCopy (ent->msg_angles[0], ent->angles); ent->forcelink = true; } }