diff options
Diffstat (limited to 'src/engine')
29 files changed, 489 insertions, 260 deletions
diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index e7975aca..37d1019a 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -11,6 +11,9 @@ void CGraphicsBackend_Threaded::ThreadFunc(void *pUser) { + #ifdef CONF_PLATFORM_MACOSX + CAutoreleasePool AutoreleasePool; + #endif CGraphicsBackend_Threaded *pThis = (CGraphicsBackend_Threaded *)pUser; while(!pThis->m_Shutdown) @@ -97,6 +100,41 @@ int CCommandProcessorFragment_OpenGL::TexFormatToOpenGLFormat(int TexFormat) return GL_RGBA; } +unsigned char CCommandProcessorFragment_OpenGL::Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp) +{ + int Value = 0; + for(int x = 0; x < ScaleW; x++) + for(int y = 0; y < ScaleH; y++) + Value += pData[((v+y)*w+(u+x))*Bpp+Offset]; + return Value/(ScaleW*ScaleH); +} + +void *CCommandProcessorFragment_OpenGL::Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData) +{ + unsigned char *pTmpData; + int ScaleW = Width/NewWidth; + int ScaleH = Height/NewHeight; + + int Bpp = 3; + if(Format == CCommandBuffer::TEXFORMAT_RGBA) + Bpp = 4; + + pTmpData = (unsigned char *)mem_alloc(NewWidth*NewHeight*Bpp, 1); + + int c = 0; + for(int y = 0; y < NewHeight; y++) + for(int x = 0; x < NewWidth; x++, c++) + { + pTmpData[c*Bpp] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 0, ScaleW, ScaleH, Bpp); + pTmpData[c*Bpp+1] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 1, ScaleW, ScaleH, Bpp); + pTmpData[c*Bpp+2] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 2, ScaleW, ScaleH, Bpp); + if(Bpp == 4) + pTmpData[c*Bpp+3] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 3, ScaleW, ScaleH, Bpp); + } + + return pTmpData; +} + void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State) { // blend @@ -130,7 +168,7 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) { glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture]); + glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture].m_Tex); } else glDisable(GL_TEXTURE_2D); @@ -155,9 +193,14 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, 1.0f, 10.f); } +void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand) +{ + m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage; +} + void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) { - glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); + glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot].m_Tex); glTexSubImage2D(GL_TEXTURE_2D, 0, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pCommand->m_pData); mem_free(pCommand->m_pData); @@ -165,31 +208,85 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer:: void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) { - glDeleteTextures(1, &m_aTextures[pCommand->m_Slot]); + glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex); + *m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize; } void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) { + int Width = pCommand->m_Width; + int Height = pCommand->m_Height; + void *pTexData = pCommand->m_pData; + + // resample if needed + if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB) + { + int MaxTexSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTexSize); + if(Width > MaxTexSize || Height > MaxTexSize) + { + do + { + Width>>=1; + Height>>=1; + } + while(Width > MaxTexSize || Height > MaxTexSize); + + void *pTmpData = Rescale(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast<const unsigned char *>(pCommand->m_pData)); + mem_free(pTexData); + pTexData = pTmpData; + } + else if(Width > 16 && Height > 16 && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0) + { + Width>>=1; + Height>>=1; + + void *pTmpData = Rescale(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast<const unsigned char *>(pCommand->m_pData)); + mem_free(pTexData); + pTexData = pTmpData; + } + } + int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); - glGenTextures(1, &m_aTextures[pCommand->m_Slot]); - glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]); + if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_COMPRESSED) + { + switch(StoreOglformat) + { + case GL_RGB: StoreOglformat = GL_COMPRESSED_RGB_ARB; break; + case GL_ALPHA: StoreOglformat = GL_COMPRESSED_ALPHA_ARB; break; + case GL_RGBA: StoreOglformat = GL_COMPRESSED_RGBA_ARB; break; + default: StoreOglformat = GL_COMPRESSED_RGBA_ARB; + } + } + glGenTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex); + glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot].m_Tex); if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_NOMIPMAPS) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, pCommand->m_Width, pCommand->m_Height, 0, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, pCommand->m_Width, pCommand->m_Height, Oglformat, GL_UNSIGNED_BYTE, pCommand->m_pData); + gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); } - mem_free(pCommand->m_pData); + // calculate memory usage + m_aTextures[pCommand->m_Slot].m_MemSize = Width*Height*pCommand->m_PixelSize; + while(Width > 2 && Height > 2) + { + Width>>=1; + Height>>=1; + m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize; + } + *m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize; + + mem_free(pTexData); } void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) @@ -260,12 +357,14 @@ void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCom CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL() { mem_zero(m_aTextures, sizeof(m_aTextures)); + m_pTextureMemoryUsage = 0; } bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand * pBaseCommand) { switch(pBaseCommand->m_Cmd) { + case CMD_INIT: Cmd_Init(static_cast<const SCommand_Init *>(pBaseCommand)); break; case CCommandBuffer::CMD_TEXTURE_CREATE: Cmd_Texture_Create(static_cast<const CCommandBuffer::SCommand_Texture_Create *>(pBaseCommand)); break; case CCommandBuffer::CMD_TEXTURE_DESTROY: Cmd_Texture_Destroy(static_cast<const CCommandBuffer::SCommand_Texture_Destroy *>(pBaseCommand)); break; case CCommandBuffer::CMD_TEXTURE_UPDATE: Cmd_Texture_Update(static_cast<const CCommandBuffer::SCommand_Texture_Update *>(pBaseCommand)); break; @@ -388,7 +487,7 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer) // ------------ CGraphicsBackend_SDL_OpenGL -int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags) +int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Width, int *Height, int FsaaSamples, int Flags) { if(!SDL_WasInit(SDL_INIT_VIDEO)) { @@ -400,13 +499,20 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, #ifdef CONF_FAMILY_WINDOWS if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention - putenv("SDL_VIDEO_WINDOW_POS=8,27"); // ignore_convention + putenv("SDL_VIDEO_WINDOW_POS=center"); // ignore_convention #endif } const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // prevent stuck mouse cursor sdl-bug when loosing fullscreen focus in windows + // use current resolution as default + if(*Width == 0 || *Height == 0) + { + *Width = pInfo->current_w; + *Height = pInfo->current_h; + } + // set flags int SdlFlags = SDL_OPENGL; if(Flags&IGraphicsBackend::INITFLAG_RESIZABLE) @@ -420,6 +526,13 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, if(pInfo->blit_hw) // ignore_convention SdlFlags |= SDL_HWACCEL; + dbg_assert(!(Flags&IGraphicsBackend::INITFLAG_BORDERLESS) + || !(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN), + "only one of borderless and fullscreen may be activated at the same time"); + + if(Flags&IGraphicsBackend::INITFLAG_BORDERLESS) + SdlFlags |= SDL_NOFRAME; + if(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN) SdlFlags |= SDL_FULLSCREEN; @@ -436,13 +549,13 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, Flags&CCommandBuffer::INITFLAG_VSYNC ? 1 : 0); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, Flags&IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0); // set caption SDL_WM_SetCaption(pName, pName); // create window - m_pScreenSurface = SDL_SetVideoMode(Width, Height, 0, SdlFlags); + m_pScreenSurface = SDL_SetVideoMode(*Width, *Height, 0, SdlFlags); if(!m_pScreenSurface) { dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); @@ -460,11 +573,14 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, m_pProcessor = new CCommandProcessor_SDL_OpenGL; StartProcessor(m_pProcessor); - // issue a init command + // issue init commands for OpenGL and SDL CCommandBuffer CmdBuffer(1024, 512); - CCommandProcessorFragment_SDL::SCommand_Init Cmd; - Cmd.m_Context = m_GLContext; - CmdBuffer.AddCommand(Cmd); + CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL; + CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage; + CmdBuffer.AddCommand(CmdOpenGL); + CCommandProcessorFragment_SDL::SCommand_Init CmdSDL; + CmdSDL.m_Context = m_GLContext; + CmdBuffer.AddCommand(CmdSDL); RunBuffer(&CmdBuffer); WaitForIdle(); @@ -490,6 +606,11 @@ int CGraphicsBackend_SDL_OpenGL::Shutdown() return 0; } +int CGraphicsBackend_SDL_OpenGL::MemoryUsage() const +{ + return m_TextureMemoryUsage; +} + void CGraphicsBackend_SDL_OpenGL::Minimize() { SDL_WM_IconifyWindow(); diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index c6c2255a..e90f9455 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -28,24 +28,72 @@ static void GL_SwapBuffers(const SGLContext &Context) { SwapBuffers(Context.m_hDC); } #elif defined(CONF_PLATFORM_MACOSX) - #include <AGL/agl.h> + #include <objc/objc-runtime.h> + + class semaphore + { + SDL_sem *sem; + public: + semaphore() { sem = SDL_CreateSemaphore(0); } + ~semaphore() { SDL_DestroySemaphore(sem); } + void wait() { SDL_SemWait(sem); } + void signal() { SDL_SemPost(sem); } + }; struct SGLContext { - AGLContext m_Context; + id m_Context; }; static SGLContext GL_GetCurrentContext() { SGLContext Context; - Context.m_Context = aglGetCurrentContext(); + Class NSOpenGLContextClass = (Class) objc_getClass("NSOpenGLContext"); + SEL selector = sel_registerName("currentContext"); + Context.m_Context = objc_msgSend((objc_object*) NSOpenGLContextClass, selector); return Context; } - static void GL_MakeCurrent(const SGLContext &Context) { aglSetCurrentContext(Context.m_Context); } - static void GL_ReleaseContext(const SGLContext &Context) { aglSetCurrentContext(NULL); } - static void GL_SwapBuffers(const SGLContext &Context) { aglSwapBuffers(Context.m_Context); } - + static void GL_MakeCurrent(const SGLContext &Context) + { + SEL selector = sel_registerName("makeCurrentContext"); + objc_msgSend(Context.m_Context, selector); + } + + static void GL_ReleaseContext(const SGLContext &Context) + { + Class NSOpenGLContextClass = (Class) objc_getClass("NSOpenGLContext"); + SEL selector = sel_registerName("clearCurrentContext"); + objc_msgSend((objc_object*) NSOpenGLContextClass, selector); + } + + static void GL_SwapBuffers(const SGLContext &Context) + { + SEL selector = sel_registerName("flushBuffer"); + objc_msgSend(Context.m_Context, selector); + } + + class CAutoreleasePool + { + private: + id m_Pool; + + public: + CAutoreleasePool() + { + Class NSAutoreleasePoolClass = (Class) objc_getClass("NSAutoreleasePool"); + m_Pool = class_createInstance(NSAutoreleasePoolClass, 0); + SEL selector = sel_registerName("init"); + objc_msgSend(m_Pool, selector); + } + + ~CAutoreleasePool() + { + SEL selector = sel_registerName("drain"); + objc_msgSend(m_Pool, selector); + } + }; + #elif defined(CONF_FAMILY_UNIX) #include <GL/glx.h> @@ -119,11 +167,34 @@ public: // takes care of opengl related rendering class CCommandProcessorFragment_OpenGL { - GLuint m_aTextures[CCommandBuffer::MAX_TEXTURES]; + struct CTexture + { + GLuint m_Tex; + int m_MemSize; + }; + CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES]; + volatile int *m_pTextureMemoryUsage; + +public: + enum + { + CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_OPENGL, + }; + + struct SCommand_Init : public CCommandBuffer::SCommand + { + SCommand_Init() : SCommand(CMD_INIT) {} + volatile int *m_pTextureMemoryUsage; + }; + +private: static int TexFormatToOpenGLFormat(int TexFormat); + static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); + static void *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); void SetState(const CCommandBuffer::SState &State); + void Cmd_Init(const SCommand_Init *pCommand); void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand); void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand); void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand); @@ -145,7 +216,7 @@ class CCommandProcessorFragment_SDL public: enum { - CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM, + CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_SDL, CMD_SHUTDOWN, }; @@ -187,10 +258,13 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded SDL_Surface *m_pScreenSurface; ICommandProcessor *m_pProcessor; SGLContext m_GLContext; + volatile int m_TextureMemoryUsage; public: - virtual int Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags); + virtual int Init(const char *pName, int *Width, int *Height, int FsaaSamples, int Flags); virtual int Shutdown(); + virtual int MemoryUsage() const; + virtual void Minimize(); virtual void Maximize(); virtual int WindowActive(); diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index d5da647b..30f92eb0 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -137,14 +137,16 @@ void CGraph::Render(IGraphics *pGraphics, int Font, float x, float y, float w, f pGraphics->LinesEnd(); pGraphics->TextureSet(Font); - pGraphics->QuadsText(x+2, y+h-16, 16, 1,1,1,1, pDescription); + pGraphics->QuadsBegin(); + pGraphics->QuadsText(x+2, y+h-16, 16, pDescription); char aBuf[32]; str_format(aBuf, sizeof(aBuf), "%.2f", m_Max); - pGraphics->QuadsText(x+w-8*str_length(aBuf)-8, y+2, 16, 1,1,1,1, aBuf); + pGraphics->QuadsText(x+w-8*str_length(aBuf)-8, y+2, 16, aBuf); str_format(aBuf, sizeof(aBuf), "%.2f", m_Min); - pGraphics->QuadsText(x+w-8*str_length(aBuf)-8, y+h-16, 16, 1,1,1,1, aBuf); + pGraphics->QuadsText(x+w-8*str_length(aBuf)-8, y+h-16, 16, aBuf); + pGraphics->QuadsEnd(); } @@ -678,6 +680,7 @@ void CClient::DebugRender() //m_pGraphics->BlendNormal(); Graphics()->TextureSet(m_DebugFont); Graphics()->MapScreen(0,0,Graphics()->ScreenWidth(),Graphics()->ScreenHeight()); + Graphics()->QuadsBegin(); if(time_get()-LastSnap > time_freq()) { @@ -699,7 +702,7 @@ void CClient::DebugRender() mem_stats()->total_allocations, Graphics()->MemoryUsage()/1024, (int)(1.0f/FrameTimeAvg + 0.5f)); - Graphics()->QuadsText(2, 2, 16, 1,1,1,1, aBuffer); + Graphics()->QuadsText(2, 2, 16, aBuffer); { @@ -715,7 +718,7 @@ void CClient::DebugRender() str_format(aBuffer, sizeof(aBuffer), "send: %3d %5d+%4d=%5d (%3d kbps) avg: %5d\nrecv: %3d %5d+%4d=%5d (%3d kbps) avg: %5d", SendPackets, SendBytes, SendPackets*42, SendTotal, (SendTotal*8)/1024, SendBytes/SendPackets, RecvPackets, RecvBytes, RecvPackets*42, RecvTotal, (RecvTotal*8)/1024, RecvBytes/RecvPackets); - Graphics()->QuadsText(2, 14, 16, 1,1,1,1, aBuffer); + Graphics()->QuadsText(2, 14, 16, aBuffer); } // render rates @@ -728,7 +731,7 @@ void CClient::DebugRender() { str_format(aBuffer, sizeof(aBuffer), "%4d %20s: %8d %8d %8d", i, GameClient()->GetItemName(i), m_SnapshotDelta.GetDataRate(i)/8, m_SnapshotDelta.GetDataUpdates(i), (m_SnapshotDelta.GetDataRate(i)/m_SnapshotDelta.GetDataUpdates(i))/8); - Graphics()->QuadsText(2, 100+y*12, 16, 1,1,1,1, aBuffer); + Graphics()->QuadsText(2, 100+y*12, 16, aBuffer); y++; } } @@ -736,7 +739,8 @@ void CClient::DebugRender() str_format(aBuffer, sizeof(aBuffer), "pred: %d ms", (int)((m_PredictedTime.Get(Now)-m_GameTime.Get(Now))*1000/(float)time_freq())); - Graphics()->QuadsText(2, 70, 16, 1,1,1,1, aBuffer); + Graphics()->QuadsText(2, 70, 16, aBuffer); + Graphics()->QuadsEnd(); // render graphs if(g_Config.m_DbgGraphs) @@ -1310,7 +1314,6 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) } // unpack delta - PurgeTick = DeltaTick; SnapSize = m_SnapshotDelta.UnpackDelta(pDeltaShot, pTmpBuffer3, pDeltaData, DeltaSize); if(SnapSize < 0) { @@ -1349,7 +1352,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) if(m_aSnapshots[SNAP_PREV] && m_aSnapshots[SNAP_PREV]->m_Tick < PurgeTick) PurgeTick = m_aSnapshots[SNAP_PREV]->m_Tick; if(m_aSnapshots[SNAP_CURRENT] && m_aSnapshots[SNAP_CURRENT]->m_Tick < PurgeTick) - PurgeTick = m_aSnapshots[SNAP_PREV]->m_Tick; + PurgeTick = m_aSnapshots[SNAP_CURRENT]->m_Tick; m_SnapshotStorage.PurgeUntil(PurgeTick); // add new @@ -1746,14 +1749,19 @@ void CClient::Run() // open socket { NETADDR BindAddr; - if(g_Config.m_Bindaddr[0] == 0 || net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) != 0) + if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0) + { + // got bindaddr + BindAddr.type = NETTYPE_ALL; + } + else { mem_zero(&BindAddr, sizeof(BindAddr)); BindAddr.type = NETTYPE_ALL; } if(!m_NetClient.Open(BindAddr, 0)) { - dbg_msg("client", "couldn't start network"); + dbg_msg("client", "couldn't open socket"); return; } } @@ -1937,10 +1945,10 @@ void CClient::Run() break; // beNice - if(g_Config.m_DbgStress) + if(g_Config.m_ClCpuThrottle) + thread_sleep(g_Config.m_ClCpuThrottle); + else if(g_Config.m_DbgStress || !m_pGraphics->WindowActive()) thread_sleep(5); - else if(g_Config.m_ClCpuThrottle || !m_pGraphics->WindowActive()) - thread_sleep(1); if(g_Config.m_DbgHitch) { diff --git a/src/engine/client/client.h b/src/engine/client/client.h index d958b49a..87e2bc70 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -175,8 +175,6 @@ class CClient : public IClient, public CDemoPlayer::IListner class CHostLookup m_VersionServeraddr; } m_VersionInfo; - semaphore m_GfxRenderSemaphore; - semaphore m_GfxStateSemaphore; volatile int m_GfxState; static void GraphicsThreadProxy(void *pThis) { ((CClient*)pThis)->GraphicsThread(); } void GraphicsThread(); diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 2111703e..2e8a855d 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -22,6 +22,20 @@ #include "graphics.h" +#if defined(CONF_PLATFORM_MACOSX) + + class semaphore + { + SDL_sem *sem; + public: + semaphore() { sem = SDL_CreateSemaphore(0); } + ~semaphore() { SDL_DestroySemaphore(sem); } + void wait() { SDL_SemWait(sem); } + void signal() { SDL_SemPost(sem); } + }; +#endif + + static CVideoMode g_aFakeModes[] = { {320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8}, {720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8}, @@ -686,13 +700,10 @@ void CGraphics_OpenGL::QuadsDrawFreeform(const CFreeformItem *pArray, int Num) AddVertices(4*Num); } -void CGraphics_OpenGL::QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText) +void CGraphics_OpenGL::QuadsText(float x, float y, float Size, const char *pText) { float StartX = x; - QuadsBegin(); - SetColor(r,g,b,a); - while(*pText) { char c = *pText; @@ -716,8 +727,6 @@ void CGraphics_OpenGL::QuadsText(float x, float y, float Size, float r, float g, x += Size/2; } } - - QuadsEnd(); } int CGraphics_OpenGL::Init() @@ -761,12 +770,19 @@ int CGraphics_OpenGL::Init() int CGraphics_SDL::TryInit() { - m_ScreenWidth = g_Config.m_GfxScreenWidth; - m_ScreenHeight = g_Config.m_GfxScreenHeight; - const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // prevent stuck mouse cursor sdl-bug when loosing fullscreen focus in windows + // use current resolution as default + if(g_Config.m_GfxScreenWidth == 0 || g_Config.m_GfxScreenHeight == 0) + { + g_Config.m_GfxScreenWidth = pInfo->current_w; + g_Config.m_GfxScreenHeight = pInfo->current_h; + } + + m_ScreenWidth = g_Config.m_GfxScreenWidth; + m_ScreenHeight = g_Config.m_GfxScreenHeight; + // set flags int Flags = SDL_OPENGL; if(g_Config.m_DbgResizable) @@ -780,7 +796,15 @@ int CGraphics_SDL::TryInit() if(pInfo->blit_hw) // ignore_convention Flags |= SDL_HWACCEL; - if(g_Config.m_GfxFullscreen) + if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen) + { + dbg_msg("gfx", "both borderless and fullscreen activated, disabling borderless"); + g_Config.m_GfxBorderless = 0; + } + + if(g_Config.m_GfxBorderless) + Flags |= SDL_NOFRAME; + else if(g_Config.m_GfxFullscreen) Flags |= SDL_FULLSCREEN; // set gl attributes @@ -876,7 +900,7 @@ int CGraphics_SDL::Init() #ifdef CONF_FAMILY_WINDOWS if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention - putenv("SDL_VIDEO_WINDOW_POS=8,27"); // ignore_convention + putenv("SDL_VIDEO_WINDOW_POS=center"); // ignore_convention #endif if(InitWindow() != 0) @@ -929,7 +953,8 @@ void CGraphics_SDL::Swap() { if(m_DoScreenshot) { - ScreenshotDirect(m_aScreenshotName); + if(WindowActive()) + ScreenshotDirect(m_aScreenshotName); m_DoScreenshot = false; } diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index fdd83aa7..670c22b4 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -119,7 +119,7 @@ public: virtual void QuadsDraw(CQuadItem *pArray, int Num); virtual void QuadsDrawTL(const CQuadItem *pArray, int Num); virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num); - virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText); + virtual void QuadsText(float x, float y, float Size, const char *pText); virtual int Init(); }; diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index b19e8a83..e34b7259 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -80,8 +80,27 @@ void CGraphics_Threaded::FlushVertices() } } + // check if we have enough free memory in the commandbuffer + if(!m_pCommandBuffer->AddCommand(Cmd)) + { + // kick command buffer and try again + KickCommandBuffer(); + + Cmd.m_pVertices = (CCommandBuffer::SVertex *)m_pCommandBuffer->AllocData(sizeof(CCommandBuffer::SVertex)*NumVerts); + if(Cmd.m_pVertices == 0x0) + { + dbg_msg("graphics", "failed to allocate data for vertices"); + return; + } + + if(!m_pCommandBuffer->AddCommand(Cmd)) + { + dbg_msg("graphics", "failed to allocate memory for render command"); + return; + } + } + mem_copy(Cmd.m_pVertices, m_aVertices, sizeof(CCommandBuffer::SVertex)*NumVerts); - m_pCommandBuffer->AddCommand(Cmd); } void CGraphics_Threaded::AddVertices(int Count) @@ -107,41 +126,6 @@ void CGraphics_Threaded::Rotate4(const CCommandBuffer::SPoint &rCenter, CCommand } } -unsigned char CGraphics_Threaded::Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp) -{ - int Value = 0; - for(int x = 0; x < ScaleW; x++) - for(int y = 0; y < ScaleH; y++) - Value += pData[((v+y)*w+(u+x))*Bpp+Offset]; - return Value/(ScaleW*ScaleH); -} - -unsigned char *CGraphics_Threaded::Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData) -{ - unsigned char *pTmpData; - int ScaleW = Width/NewWidth; - int ScaleH = Height/NewHeight; - - int Bpp = 3; - if(Format == CImageInfo::FORMAT_RGBA) - Bpp = 4; - - pTmpData = (unsigned char *)mem_alloc(NewWidth*NewHeight*Bpp, 1); - - int c = 0; - for(int y = 0; y < NewHeight; y++) - for(int x = 0; x < NewWidth; x++, c++) - { - pTmpData[c*Bpp] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 0, ScaleW, ScaleH, Bpp); - pTmpData[c*Bpp+1] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 1, ScaleW, ScaleH, Bpp); - pTmpData[c*Bpp+2] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 2, ScaleW, ScaleH, Bpp); - if(Bpp == 4) - pTmpData[c*Bpp+3] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 3, ScaleW, ScaleH, Bpp); - } - - return pTmpData; -} - CGraphics_Threaded::CGraphics_Threaded() { m_State.m_ScreenTL.x = 0; @@ -228,7 +212,7 @@ void CGraphics_Threaded::WrapClamp() int CGraphics_Threaded::MemoryUsage() const { - return m_TextureMemoryUsage; + return m_pBackend->MemoryUsage(); } void CGraphics_Threaded::MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) @@ -293,8 +277,7 @@ int CGraphics_Threaded::UnloadTexture(int Index) Cmd.m_Slot = Index; m_pCommandBuffer->AddCommand(Cmd); - m_aTextures[Index].m_Next = m_FirstFreeTexture; - m_TextureMemoryUsage -= m_aTextures[Index].m_MemSize; + m_aTextureIndices[Index] = m_FirstFreeTexture; m_FirstFreeTexture = Index; return 0; } @@ -307,6 +290,16 @@ static int ImageFormatToTexFormat(int Format) return CCommandBuffer::TEXFORMAT_RGBA; } +static int ImageFormatToPixelSize(int Format) +{ + switch(Format) + { + case CImageInfo::FORMAT_RGB: return 3; + case CImageInfo::FORMAT_ALPHA: return 1; + default: return 4; + } +} + int CGraphics_Threaded::LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData) { @@ -319,13 +312,7 @@ int CGraphics_Threaded::LoadTextureRawSub(int TextureID, int x, int y, int Width Cmd.m_Format = ImageFormatToTexFormat(Format); // calculate memory usage - int PixelSize = 4; - if(Format == CImageInfo::FORMAT_RGB) - PixelSize = 3; - else if(Format == CImageInfo::FORMAT_ALPHA) - PixelSize = 1; - - int MemSize = Width*Height*PixelSize; + int MemSize = Width*Height*ImageFormatToPixelSize(Format); // copy texture data void *pTmpData = mem_alloc(MemSize, sizeof(void*)); @@ -345,13 +332,14 @@ int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const // grab texture int Tex = m_FirstFreeTexture; - m_FirstFreeTexture = m_aTextures[Tex].m_Next; - m_aTextures[Tex].m_Next = -1; + m_FirstFreeTexture = m_aTextureIndices[Tex]; + m_aTextureIndices[Tex] = -1; CCommandBuffer::SCommand_Texture_Create Cmd; Cmd.m_Slot = Tex; Cmd.m_Width = Width; Cmd.m_Height = Height; + Cmd.m_PixelSize = ImageFormatToPixelSize(Format); Cmd.m_Format = ImageFormatToTexFormat(Format); Cmd.m_StoreFormat = ImageFormatToTexFormat(StoreFormat); @@ -359,17 +347,13 @@ int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const Cmd.m_Flags = 0; if(Flags&IGraphics::TEXLOAD_NOMIPMAPS) Cmd.m_Flags |= CCommandBuffer::TEXFLAG_NOMIPMAPS; - - // calculate memory usage - int PixelSize = 4; - if(Format == CImageInfo::FORMAT_RGB) - PixelSize = 3; - else if(Format == CImageInfo::FORMAT_ALPHA) - PixelSize = 1; - - int MemSize = Width*Height*PixelSize; + if(g_Config.m_GfxTextureCompression) + Cmd.m_Flags |= CCommandBuffer::TEXFLAG_COMPRESSED; + if(g_Config.m_GfxTextureQuality || Flags&TEXLOAD_NORESAMPLE) + Cmd.m_Flags |= CCommandBuffer::TEXFLAG_QUALITY; // copy texture data + int MemSize = Width*Height*Cmd.m_PixelSize; void *pTmpData = mem_alloc(MemSize, sizeof(void*)); mem_copy(pTmpData, pData, MemSize); Cmd.m_pData = pTmpData; @@ -377,17 +361,6 @@ int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const // m_pCommandBuffer->AddCommand(Cmd); - // calculate memory usage - int MemUsage = MemSize; - while(Width > 2 && Height > 2) - { - Width>>=1; - Height>>=1; - MemUsage += Width*Height*PixelSize; - } - - m_TextureMemoryUsage += MemUsage; - //mem_free(pTmpData); return Tex; } @@ -675,13 +648,10 @@ void CGraphics_Threaded::QuadsDrawFreeform(const CFreeformItem *pArray, int Num) AddVertices(4*Num); } -void CGraphics_Threaded::QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText) +void CGraphics_Threaded::QuadsText(float x, float y, float Size, const char *pText) { float StartX = x; - QuadsBegin(); - SetColor(r,g,b,a); - while(*pText) { char c = *pText; @@ -705,18 +675,23 @@ void CGraphics_Threaded::QuadsText(float x, float y, float Size, float r, float x += Size/2; } } - - QuadsEnd(); } int CGraphics_Threaded::IssueInit() { int Flags = 0; - if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN; + if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen) + { + dbg_msg("gfx", "both borderless and fullscreen activated, disabling borderless"); + g_Config.m_GfxBorderless = 0; + } + + if(g_Config.m_GfxBorderless) Flags |= IGraphicsBackend::INITFLAG_BORDERLESS; + else if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN; if(g_Config.m_GfxVsync) Flags |= IGraphicsBackend::INITFLAG_VSYNC; if(g_Config.m_DbgResizable) Flags |= IGraphicsBackend::INITFLAG_RESIZABLE; - return m_pBackend->Init("Teeworlds", g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags); + return m_pBackend->Init("Teeworlds", &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags); } int CGraphics_Threaded::InitWindow() @@ -766,9 +741,9 @@ int CGraphics_Threaded::Init() // init textures m_FirstFreeTexture = 0; - for(int i = 0; i < MAX_TEXTURES; i++) - m_aTextures[i].m_Next = i+1; - m_aTextures[MAX_TEXTURES-1].m_Next = -1; + for(int i = 0; i < MAX_TEXTURES-1; i++) + m_aTextureIndices[i] = i+1; + m_aTextureIndices[MAX_TEXTURES-1] = -1; m_pBackend = CreateGraphicsBackend(); if(InitWindow() != 0) @@ -843,7 +818,8 @@ void CGraphics_Threaded::Swap() // TODO: screenshot support if(m_DoScreenshot) { - ScreenshotDirect(m_aScreenshotName); + if(WindowActive()) + ScreenshotDirect(m_aScreenshotName); m_DoScreenshot = false; } diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index f90f818d..ff03c6bb 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -57,7 +57,8 @@ public: { // commadn groups CMDGROUP_CORE = 0, // commands that everyone has to implement - CMDGROUP_PLATFORM = 10000, // commands specific to a platform + CMDGROUP_PLATFORM_OPENGL = 10000, // commands specific to a platform + CMDGROUP_PLATFORM_SDL = 20000, // CMD_NOP = CMDGROUP_CORE, @@ -94,13 +95,8 @@ public: TEXFORMAT_ALPHA, TEXFLAG_NOMIPMAPS = 1, - }; - - enum - { - INITFLAG_FULLSCREEN = 1, - INITFLAG_VSYNC = 2, - INITFLAG_RESIZABLE = 4, + TEXFLAG_COMPRESSED = 2, + TEXFLAG_QUALITY = 4, }; enum @@ -217,6 +213,7 @@ public: int m_Width; int m_Height; + int m_PixelSize; int m_Format; int m_StoreFormat; int m_Flags; @@ -300,11 +297,16 @@ public: INITFLAG_FULLSCREEN = 1, INITFLAG_VSYNC = 2, INITFLAG_RESIZABLE = 4, + INITFLAG_BORDERLESS = 8, }; - virtual int Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags) = 0; + virtual ~IGraphicsBackend() {} + + virtual int Init(const char *pName, int *Width, int *Height, int FsaaSamples, int Flags) = 0; virtual int Shutdown() = 0; + virtual int MemoryUsage() const = 0; + virtual void Minimize() = 0; virtual void Maximize() = 0; virtual int WindowActive() = 0; @@ -354,15 +356,7 @@ class CGraphics_Threaded : public IEngineGraphics int m_InvalidTexture; - struct CTexture - { - int m_State; - int m_MemSize; - int m_Flags; - int m_Next; - }; - - CTexture m_aTextures[MAX_TEXTURES]; + int m_aTextureIndices[MAX_TEXTURES]; int m_FirstFreeTexture; int m_TextureMemoryUsage; @@ -370,9 +364,6 @@ class CGraphics_Threaded : public IEngineGraphics void AddVertices(int Count); void Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints); - static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); - static unsigned char *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); - void KickCommandBuffer(); int IssueInit(); @@ -428,7 +419,7 @@ public: virtual void QuadsDraw(CQuadItem *pArray, int Num); virtual void QuadsDrawTL(const CQuadItem *pArray, int Num); virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num); - virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText); + virtual void QuadsText(float x, float y, float Size, const char *pText); virtual void Minimize(); virtual void Maximize(); diff --git a/src/engine/client/input.cpp b/src/engine/client/input.cpp index 0b4a44a4..7ff8d6fe 100644 --- a/src/engine/client/input.cpp +++ b/src/engine/client/input.cpp @@ -35,6 +35,7 @@ CInput::CInput() m_InputCurrent = 0; m_InputGrabbed = 0; + m_InputDispatched = false; m_LastRelease = 0; m_ReleaseDelta = -1; @@ -116,10 +117,14 @@ int CInput::Update() /*if(!input_grabbed && Graphics()->WindowActive()) Input()->MouseModeRelative();*/ - // clear and begin count on the other one - m_InputCurrent^=1; - mem_zero(&m_aInputCount[m_InputCurrent], sizeof(m_aInputCount[m_InputCurrent])); - mem_zero(&m_aInputState[m_InputCurrent], sizeof(m_aInputState[m_InputCurrent])); + if(m_InputDispatched) + { + // clear and begin count on the other one + m_InputCurrent^=1; + mem_zero(&m_aInputCount[m_InputCurrent], sizeof(m_aInputCount[m_InputCurrent])); + mem_zero(&m_aInputState[m_InputCurrent], sizeof(m_aInputState[m_InputCurrent])); + m_InputDispatched = false; + } { int i; diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 4dda9da9..588194ea 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -495,7 +495,7 @@ void CServerBrowser::Refresh(int Type) /* do the broadcast version */ Packet.m_ClientID = -1; mem_zero(&Packet, sizeof(Packet)); - Packet.m_Address.type = NETTYPE_ALL|NETTYPE_LINK_BROADCAST; + Packet.m_Address.type = m_pNetClient->NetType()|NETTYPE_LINK_BROADCAST; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(Buffer); Packet.m_pData = Buffer; diff --git a/src/engine/client/text.cpp b/src/engine/client/text.cpp index af06fc11..d838ef29 100644 --- a/src/engine/client/text.cpp +++ b/src/engine/client/text.cpp @@ -639,7 +639,7 @@ public: Compare.m_Y = DrawY; Compare.m_Flags &= ~TEXTFLAG_RENDER; Compare.m_LineWidth = -1; - TextEx(&Compare, pText, Wlen); + TextEx(&Compare, pCurrent, Wlen); if(Compare.m_X-DrawX > pCursor->m_LineWidth) { diff --git a/src/engine/demo.h b/src/engine/demo.h index 7b7365c7..bd4a307a 100644 --- a/src/engine/demo.h +++ b/src/engine/demo.h @@ -21,6 +21,10 @@ struct CDemoHeader char m_aType[8]; char m_aLength[4]; char m_aTimestamp[20]; +}; + +struct CTimelineMarkers +{ char m_aNumTimelineMarkers[4]; char m_aTimelineMarkers[MAX_TIMELINE_MARKERS][4]; }; diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 7f272497..a2fe4741 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -120,7 +120,7 @@ public: : m_X0(x0), m_Y0(y0), m_X1(x1), m_Y1(y1), m_X2(x2), m_Y2(y2), m_X3(x3), m_Y3(y3) {} }; virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num) = 0; - virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText) = 0; + virtual void QuadsText(float x, float y, float Size, const char *pText) = 0; struct CColorVertex { diff --git a/src/engine/input.h b/src/engine/input.h index 7d28be10..93ceccd2 100644 --- a/src/engine/input.h +++ b/src/engine/input.h @@ -38,6 +38,7 @@ protected: unsigned char m_aInputState[2][1024]; int m_InputCurrent; + bool m_InputDispatched; int KeyWasPressed(int Key) { return m_aInputState[m_InputCurrent^1][Key]; } @@ -51,7 +52,11 @@ public: // events int NumEvents() const { return m_NumEvents; } - void ClearEvents() { m_NumEvents = 0; } + void ClearEvents() + { + m_NumEvents = 0; + m_InputDispatched = true; + } CEvent GetEvent(int Index) const { if(Index < 0 || Index >= m_NumEvents) diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 577c040f..4fa872eb 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -36,45 +36,23 @@ #include <windows.h> #endif -static const char *StrUTF8Ltrim(const char *pStr) +static const char *StrLtrim(const char *pStr) { - while(*pStr) - { - const char *pStrOld = pStr; - int Code = str_utf8_decode(&pStr); - - // check if unicode is not empty - if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) && - (Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) && - Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC)) - { - return pStrOld; - } - } + while(*pStr && *pStr >= 0 && *pStr <= 32) + pStr++; return pStr; } -static void StrUTF8Rtrim(char *pStr) +static void StrRtrim(char *pStr) { - const char *p = pStr; - const char *pEnd = 0; - while(*p) + int i = str_length(pStr); + while(i >= 0) { - const char *pStrOld = p; - int Code = str_utf8_decode(&p); - - // check if unicode is not empty - if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) && - (Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) && - Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC)) - { - pEnd = 0; - } - else if(pEnd == 0) - pEnd = pStrOld; + if(pStr[i] < 0 || pStr[i] > 32) + break; + pStr[i] = 0; + i--; } - if(pEnd != 0) - *(const_cast<char *>(pEnd)) = 0; } @@ -167,7 +145,7 @@ void CSnapIDPool::FreeID(int ID) } -void CServerBan::Init(IConsole *pConsole, IStorage *pStorage, CServer* pServer) +void CServerBan::InitServerBan(IConsole *pConsole, IStorage *pStorage, CServer* pServer) { CNetBan::Init(pConsole, pStorage); @@ -331,8 +309,12 @@ int CServer::TrySetClientName(int ClientID, const char *pName) char aTrimmedName[64]; // trim the name - str_copy(aTrimmedName, StrUTF8Ltrim(pName), sizeof(aTrimmedName)); - StrUTF8Rtrim(aTrimmedName); + str_copy(aTrimmedName, StrLtrim(pName), sizeof(aTrimmedName)); + StrRtrim(aTrimmedName); + + // check for empty names + if(!aTrimmedName[0]) + return -1; // check if new and old name are the same if(m_aClients[ClientID].m_aName[0] && str_comp(m_aClients[ClientID].m_aName, aTrimmedName) == 0) @@ -343,11 +325,6 @@ int CServer::TrySetClientName(int ClientID, const char *pName) Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); pName = aTrimmedName; - - // check for empty names - if(!pName[0]) - return -1; - // make sure that two clients doesn't have the same name for(int i = 0; i < MAX_CLIENTS; i++) if(i != ClientID && m_aClients[i].m_State >= CClient::STATE_READY) @@ -371,14 +348,23 @@ void CServer::SetClientName(int ClientID, const char *pName) if(!pName) return; - char aNameTry[MAX_NAME_LENGTH]; - str_copy(aNameTry, pName, MAX_NAME_LENGTH); - if(TrySetClientName(ClientID, aNameTry)) + char aCleanName[MAX_NAME_LENGTH]; + str_copy(aCleanName, pName, sizeof(aCleanName)); + + // clear name + for(char *p = aCleanName; *p; ++p) + { + if(*p < 32) + *p = ' '; + } + + if(TrySetClientName(ClientID, aCleanName)) { // auto rename for(int i = 1;; i++) { - str_format(aNameTry, MAX_NAME_LENGTH, "(%d)%s", i, pName); + char aNameTry[MAX_NAME_LENGTH]; + str_format(aNameTry, sizeof(aCleanName), "(%d)%s", i, aCleanName); if(TrySetClientName(ClientID, aNameTry) == 0) break; } @@ -870,6 +856,9 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) } else if(Msg == NETMSG_REQUEST_MAP_DATA) { + if(m_aClients[ClientID].m_State < CClient::STATE_CONNECTING) + return; + int Chunk = Unpacker.GetInt(); int ChunkSize = 1024-128; int Offset = Chunk * ChunkSize; @@ -1270,10 +1259,6 @@ void CServer::InitRegister(CNetServer *pNetServer, IEngineMasterServer *pMasterS int CServer::Run() { - m_pGameServer = Kernel()->RequestInterface<IGameServer>(); - m_pMap = Kernel()->RequestInterface<IEngineMap>(); - m_pStorage = Kernel()->RequestInterface<IStorage>(); - // m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this); @@ -1289,6 +1274,7 @@ int CServer::Run() if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0) { // sweet! + BindAddr.type = NETTYPE_ALL; BindAddr.port = g_Config.m_SvPort; } else @@ -1306,7 +1292,6 @@ int CServer::Run() m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this); - m_ServerBan.Init(Console(), Storage(), this); m_Econ.Init(Console(), &m_ServerBan); char aBuf[256]; @@ -1482,8 +1467,12 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser) { net_addr_str(pThis->m_NetServer.ClientAddr(i), aAddrStr, sizeof(aAddrStr), true); if(pThis->m_aClients[i].m_State == CClient::STATE_INGAME) - str_format(aBuf, sizeof(aBuf), "id=%d addr=%s name='%s' score=%d", i, aAddrStr, - pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_Score); + { + const char *pAuthStr = pThis->m_aClients[i].m_Authed == CServer::AUTHED_ADMIN ? "(Admin)" : + pThis->m_aClients[i].m_Authed == CServer::AUTHED_MOD ? "(Mod)" : ""; + str_format(aBuf, sizeof(aBuf), "id=%d addr=%s name='%s' score=%d %s", i, aAddrStr, + pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_Score, pAuthStr); + } else str_format(aBuf, sizeof(aBuf), "id=%d addr=%s connecting", i, aAddrStr); pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); @@ -1564,6 +1553,7 @@ void CServer::ConLogout(IConsole::IResult *pResult, void *pUser) pServer->SendMsgEx(&Msg, MSGFLAG_VITAL, pServer->m_RconClientID, true); pServer->m_aClients[pServer->m_RconClientID].m_Authed = AUTHED_NO; + pServer->m_aClients[pServer->m_RconClientID].m_AuthTries = 0; pServer->m_aClients[pServer->m_RconClientID].m_pRconCmdToSend = 0; pServer->SendRconLine(pServer->m_RconClientID, "Logout successful."); char aBuf[32]; @@ -1628,7 +1618,11 @@ void CServer::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void void CServer::RegisterCommands() { m_pConsole = Kernel()->RequestInterface<IConsole>(); + m_pGameServer = Kernel()->RequestInterface<IGameServer>(); + m_pMap = Kernel()->RequestInterface<IEngineMap>(); + m_pStorage = Kernel()->RequestInterface<IStorage>(); + // register console commands Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "Kick player with specified id for any reason"); Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "List players"); Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "Shut down"); @@ -1645,6 +1639,10 @@ void CServer::RegisterCommands() Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this); Console()->Chain("mod_command", ConchainModCommandUpdate, this); Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this); + + // register console commands in sub parts + m_ServerBan.InitServerBan(Console(), Storage(), this); + m_pGameServer->OnConsoleInit(); } @@ -1725,7 +1723,6 @@ int main(int argc, const char **argv) // ignore_convention // register all console commands pServer->RegisterCommands(); - pGameServer->OnConsoleInit(); /* This banmaster is added into the source of the server that i'm able to ban players even if no banmaster.cfg is used. * Often serverhoster doesn't add this file because they don't know what it is for and remove it, not diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 27991746..4a1f7344 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -50,10 +50,10 @@ class CServerBan : public CNetBan public: class CServer *Server() const { return m_pServer; } - void Init(class IConsole *pConsole, class IStorage *pStorage, class CServer* pServer); + void InitServerBan(class IConsole *pConsole, class IStorage *pStorage, class CServer* pServer); - int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason); - int BanRange(const CNetRange *pRange, int Seconds, const char *pReason); + virtual int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason); + virtual int BanRange(const CNetRange *pRange, int Seconds, const char *pReason); static void ConBanExt(class IConsole::IResult *pResult, void *pUser); }; diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 76e4ccd3..c588be5c 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -15,7 +15,7 @@ MACRO_CONFIG_STR(Password, password, 32, "", CFGFLAG_CLIENT|CFGFLAG_SERVER, "Pas MACRO_CONFIG_STR(Logfile, logfile, 128, "", CFGFLAG_SAVE|CFGFLAG_CLIENT|CFGFLAG_SERVER, "Filename to log all output to") MACRO_CONFIG_INT(ConsoleOutputLevel, console_output_level, 0, 0, 2, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Adjusts the amount of information in the console") -MACRO_CONFIG_INT(ClCpuThrottle, cl_cpu_throttle, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") +MACRO_CONFIG_INT(ClCpuThrottle, cl_cpu_throttle, 0, 0, 100, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") MACRO_CONFIG_INT(ClEditor, cl_editor, 0, 0, 1, CFGFLAG_CLIENT, "") MACRO_CONFIG_INT(ClLoadCountryFlags, cl_load_country_flags, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Load and show country flags") @@ -57,8 +57,9 @@ MACRO_CONFIG_INT(SndDevice, snd_device, -1, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, " MACRO_CONFIG_INT(SndNonactiveMute, snd_nonactive_mute, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") -MACRO_CONFIG_INT(GfxScreenWidth, gfx_screen_width, 800, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution width") -MACRO_CONFIG_INT(GfxScreenHeight, gfx_screen_height, 600, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution height") +MACRO_CONFIG_INT(GfxScreenWidth, gfx_screen_width, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution width") +MACRO_CONFIG_INT(GfxScreenHeight, gfx_screen_height, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution height") +MACRO_CONFIG_INT(GfxBorderless, gfx_borderless, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Borderless window (not to be used with fullscreen)") MACRO_CONFIG_INT(GfxFullscreen, gfx_fullscreen, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Fullscreen") MACRO_CONFIG_INT(GfxAlphabits, gfx_alphabits, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Alpha bits for framebuffer (fullscreen only)") MACRO_CONFIG_INT(GfxColorDepth, gfx_color_depth, 24, 16, 24, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Colors bits for framebuffer (fullscreen only)") @@ -71,9 +72,9 @@ MACRO_CONFIG_INT(GfxTextureQuality, gfx_texture_quality, 1, 0, 1, CFGFLAG_SAVE|C MACRO_CONFIG_INT(GfxFsaaSamples, gfx_fsaa_samples, 0, 0, 16, CFGFLAG_SAVE|CFGFLAG_CLIENT, "FSAA Samples") MACRO_CONFIG_INT(GfxRefreshRate, gfx_refresh_rate, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen refresh rate") MACRO_CONFIG_INT(GfxFinish, gfx_finish, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") -MACRO_CONFIG_INT(GfxAsyncRender, gfx_asyncrender, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Do rendering async from the the update") +MACRO_CONFIG_INT(GfxAsyncRender, gfx_asyncrender, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Do rendering async from the the update") -MACRO_CONFIG_INT(GfxThreaded, gfx_threaded, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Use the threaded graphics backend") +MACRO_CONFIG_INT(GfxThreaded, gfx_threaded, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Use the threaded graphics backend") MACRO_CONFIG_INT(InpMousesens, inp_mousesens, 100, 5, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity") diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 443c5904..399f5323 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -16,21 +16,21 @@ const char *CConsole::CResult::GetString(unsigned Index) { - if (Index < 0 || Index >= m_NumArgs) + if (Index >= m_NumArgs) return ""; return m_apArgs[Index]; } int CConsole::CResult::GetInteger(unsigned Index) { - if (Index < 0 || Index >= m_NumArgs) + if (Index >= m_NumArgs) return 0; return str_toint(m_apArgs[Index]); } float CConsole::CResult::GetFloat(unsigned Index) { - if (Index < 0 || Index >= m_NumArgs) + if (Index >= m_NumArgs) return 0.0f; return str_tofloat(m_apArgs[Index]); } @@ -68,7 +68,7 @@ int CConsole::ParseStart(CResult *pResult, const char *pString, int Length) if(Length < Len) Len = Length; - str_copy(pResult->m_aStringStorage, pString, Length); + str_copy(pResult->m_aStringStorage, pString, Len); pStr = pResult->m_aStringStorage; // get command diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index 37c82cce..953d8b56 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -14,6 +14,7 @@ static const unsigned char gs_aHeaderMarker[7] = {'T', 'W', 'D', 'E', 'M', 'O', 0}; static const unsigned char gs_ActVersion = 4; +static const unsigned char gs_OldVersion = 3; static const int gs_LengthOffset = 152; static const int gs_NumMarkersOffset = 176; @@ -29,6 +30,7 @@ CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta) int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetVersion, const char *pMap, unsigned Crc, const char *pType) { CDemoHeader Header; + CTimelineMarkers TimelineMarkers; if(m_File) return -1; @@ -90,9 +92,8 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con str_copy(Header.m_aType, pType, sizeof(Header.m_aType)); // Header.m_Length - add this on stop str_timestamp(Header.m_aTimestamp, sizeof(Header.m_aTimestamp)); - // Header.m_aNumTimelineMarkers - add this on stop - // Header.m_aTimelineMarkers - add this on stop io_write(DemoFile, &Header, sizeof(Header)); + io_write(DemoFile, &TimelineMarkers, sizeof(TimelineMarkers)); // fill this on stop // write map data while(1) @@ -615,7 +616,7 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const return -1; } - if(m_Info.m_Header.m_Version < gs_ActVersion) + if(m_Info.m_Header.m_Version < gs_OldVersion) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "demo version %d is not supported", m_Info.m_Header.m_Version); @@ -624,6 +625,8 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const m_File = 0; return -1; } + else if(m_Info.m_Header.m_Version > gs_OldVersion) + io_read(m_File, &m_Info.m_TimelineMarkers, sizeof(m_Info.m_TimelineMarkers)); // get demo type if(!str_comp(m_Info.m_Header.m_aType, "client")) @@ -663,15 +666,18 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const mem_free(pMapData); } - // get timeline markers - int Num = ((m_Info.m_Header.m_aNumTimelineMarkers[0]<<24)&0xFF000000) | ((m_Info.m_Header.m_aNumTimelineMarkers[1]<<16)&0xFF0000) | - ((m_Info.m_Header.m_aNumTimelineMarkers[2]<<8)&0xFF00) | (m_Info.m_Header.m_aNumTimelineMarkers[3]&0xFF); - m_Info.m_Info.m_NumTimelineMarkers = Num; - for(int i = 0; i < Num && i < MAX_TIMELINE_MARKERS; i++) + if(m_Info.m_Header.m_Version > gs_OldVersion) { - char *pTimelineMarker = m_Info.m_Header.m_aTimelineMarkers[i]; - m_Info.m_Info.m_aTimelineMarkers[i] = ((pTimelineMarker[0]<<24)&0xFF000000) | ((pTimelineMarker[1]<<16)&0xFF0000) | - ((pTimelineMarker[2]<<8)&0xFF00) | (pTimelineMarker[3]&0xFF); + // get timeline markers + int Num = ((m_Info.m_TimelineMarkers.m_aNumTimelineMarkers[0]<<24)&0xFF000000) | ((m_Info.m_TimelineMarkers.m_aNumTimelineMarkers[1]<<16)&0xFF0000) | + ((m_Info.m_TimelineMarkers.m_aNumTimelineMarkers[2]<<8)&0xFF00) | (m_Info.m_TimelineMarkers.m_aNumTimelineMarkers[3]&0xFF); + m_Info.m_Info.m_NumTimelineMarkers = Num; + for(int i = 0; i < Num && i < MAX_TIMELINE_MARKERS; i++) + { + char *pTimelineMarker = m_Info.m_TimelineMarkers.m_aTimelineMarkers[i]; + m_Info.m_Info.m_aTimelineMarkers[i] = ((pTimelineMarker[0]<<24)&0xFF000000) | ((pTimelineMarker[1]<<16)&0xFF0000) | + ((pTimelineMarker[2]<<8)&0xFF00) | (pTimelineMarker[3]&0xFF); + } } // scan the file for interessting points @@ -843,7 +849,7 @@ bool CDemoPlayer::GetDemoInfo(class IStorage *pStorage, const char *pFilename, i return false; io_read(File, pDemoHeader, sizeof(CDemoHeader)); - if(mem_comp(pDemoHeader->m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) || pDemoHeader->m_Version < gs_ActVersion) + if(mem_comp(pDemoHeader->m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) || pDemoHeader->m_Version < gs_OldVersion) { io_close(File); return false; diff --git a/src/engine/shared/demo.h b/src/engine/shared/demo.h index 760e7256..d27f4ab6 100644 --- a/src/engine/shared/demo.h +++ b/src/engine/shared/demo.h @@ -51,6 +51,7 @@ public: struct CPlaybackInfo { CDemoHeader m_Header; + CTimelineMarkers m_TimelineMarkers; IDemoPlayer::CInfo m_Info; diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp index eb7df872..e0df8635 100644 --- a/src/engine/shared/econ.cpp +++ b/src/engine/shared/econ.cpp @@ -75,7 +75,11 @@ void CEcon::Init(IConsole *pConsole, CNetBan *pNetBan) NETADDR BindAddr; if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0) + { + // got bindaddr + BindAddr.type = NETTYPE_ALL; BindAddr.port = g_Config.m_EcPort; + } else { mem_zero(&BindAddr, sizeof(BindAddr)); diff --git a/src/engine/shared/mapchecker.cpp b/src/engine/shared/mapchecker.cpp index f8ba30ae..5a7d062f 100644 --- a/src/engine/shared/mapchecker.cpp +++ b/src/engine/shared/mapchecker.cpp @@ -6,6 +6,7 @@ #include <engine/storage.h> #include <versionsrv/versionsrv.h> +#include <versionsrv/mapversions.h> #include "datafile.h" #include "memheap.h" diff --git a/src/engine/shared/netban.cpp b/src/engine/shared/netban.cpp index d26d64d4..707b709b 100644 --- a/src/engine/shared/netban.cpp +++ b/src/engine/shared/netban.cpp @@ -243,7 +243,7 @@ typename CNetBan::CBan<T> *CNetBan::CBanPool<T, HashCount>::Get(int Index) const template<class T> void CNetBan::MakeBanInfo(const CBan<T> *pBan, char *pBuf, unsigned BuffSize, int Type) const { - if(pBan == 0) + if(pBan == 0 || pBuf == 0) { if(BuffSize > 0) pBuf[0] = 0; diff --git a/src/engine/shared/netban.h b/src/engine/shared/netban.h index 447a838d..70164832 100644 --- a/src/engine/shared/netban.h +++ b/src/engine/shared/netban.h @@ -34,7 +34,7 @@ protected: bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr, int Start, int Length) const { - return pRange->m_LB.type == pAddr->type && + return pRange->m_LB.type == pAddr->type && (Start == 0 || mem_comp(&pRange->m_LB.ip[0], &pAddr->ip[0], Start) == 0) && mem_comp(&pRange->m_LB.ip[Start], &pAddr->ip[Start], Length-Start) <= 0 && mem_comp(&pRange->m_UB.ip[Start], &pAddr->ip[Start], Length-Start) >= 0; } @@ -170,7 +170,7 @@ public: class IStorage *Storage() const { return m_pStorage; } virtual ~CNetBan() {} - virtual void Init(class IConsole *pConsole, class IStorage *pStorage); + void Init(class IConsole *pConsole, class IStorage *pStorage); void Update(); virtual int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason); diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index dd43389e..259d600f 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -140,6 +140,7 @@ private: int m_Token; int m_RemoteClosed; + bool m_BlockCloseMsg; TStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> m_Buffer; @@ -167,7 +168,7 @@ private: void Resend(); public: - void Init(NETSOCKET Socket); + void Init(NETSOCKET Socket, bool BlockCloseMsg); int Connect(NETADDR *pAddr); void Disconnect(const char *pReason); @@ -187,6 +188,7 @@ public: // Needed for GotProblems in NetClient int64 LastRecvTime() const { return m_LastRecvTime; } + int64 ConnectTime() const { return m_LastUpdateTime; } int AckSequence() const { return m_Ack; } }; @@ -353,7 +355,7 @@ public: int ResetErrorString(); // error and state - int NetType() { return m_Socket.type; } + int NetType() const { return m_Socket.type; } int State(); int GotProblems(); const char *ErrorString(); diff --git a/src/engine/shared/network_client.cpp b/src/engine/shared/network_client.cpp index 2c035606..8e0e2910 100644 --- a/src/engine/shared/network_client.cpp +++ b/src/engine/shared/network_client.cpp @@ -16,7 +16,7 @@ bool CNetClient::Open(NETADDR BindAddr, int Flags) // init m_Socket = Socket; - m_Connection.Init(m_Socket); + m_Connection.Init(m_Socket, false); return true; } diff --git a/src/engine/shared/network_conn.cpp b/src/engine/shared/network_conn.cpp index 6531f5aa..cd2df048 100644 --- a/src/engine/shared/network_conn.cpp +++ b/src/engine/shared/network_conn.cpp @@ -37,12 +37,13 @@ void CNetConnection::SetError(const char *pString) str_copy(m_ErrorString, pString, sizeof(m_ErrorString)); } -void CNetConnection::Init(NETSOCKET Socket) +void CNetConnection::Init(NETSOCKET Socket, bool BlockCloseMsg) { Reset(); ResetStats(); m_Socket = Socket; + m_BlockCloseMsg = BlockCloseMsg; mem_zero(m_ErrorString, sizeof(m_ErrorString)); } @@ -213,24 +214,25 @@ int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr) m_State = NET_CONNSTATE_ERROR; m_RemoteClosed = 1; - if(pPacket->m_DataSize) + char Str[128] = {0}; + if(pPacket->m_DataSize > 1) { // make sure to sanitize the error string form the other party - char Str[128]; if(pPacket->m_DataSize < 128) - str_copy(Str, (char *)pPacket->m_aChunkData, pPacket->m_DataSize); + str_copy(Str, (char *)&pPacket->m_aChunkData[1], pPacket->m_DataSize); else - str_copy(Str, (char *)pPacket->m_aChunkData, sizeof(Str)); + str_copy(Str, (char *)&pPacket->m_aChunkData[1], sizeof(Str)); str_sanitize_strong(Str); + } + if(!m_BlockCloseMsg) + { // set the error string SetError(Str); } - else - SetError("No reason given"); if(g_Config.m_Debug) - dbg_msg("conn", "closed reason='%s'", ErrorString()); + dbg_msg("conn", "closed reason='%s'", Str); } return 0; } @@ -244,6 +246,7 @@ int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr) Reset(); m_State = NET_CONNSTATE_PENDING; m_PeerAddr = *pAddr; + mem_zero(m_ErrorString, sizeof(m_ErrorString)); m_LastSendTime = Now; m_LastRecvTime = Now; m_LastUpdateTime = Now; diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index b693b667..e97a8eba 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -30,7 +30,7 @@ bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int Ma m_MaxClientsPerIP = MaxClientsPerIP; for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aSlots[i].m_Connection.Init(m_Socket); + m_aSlots[i].m_Connection.Init(m_Socket, true); return true; } @@ -69,11 +69,17 @@ int CNetServer::Drop(int ClientID, const char *pReason) int CNetServer::Update() { + int64 Now = time_get(); for(int i = 0; i < MaxClients(); i++) { m_aSlots[i].m_Connection.Update(); if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR) - Drop(i, m_aSlots[i].m_Connection.ErrorString()); + { + if(Now - m_aSlots[i].m_Connection.ConnectTime() < time_freq()/2 && NetBan()) + NetBan()->BanAddr(ClientAddr(i), 60, "Stressing network"); + else + Drop(i, m_aSlots[i].m_Connection.ErrorString()); + } } return 0; diff --git a/src/engine/shared/snapshot.cpp b/src/engine/shared/snapshot.cpp index 9ef8fdc3..1514278b 100644 --- a/src/engine/shared/snapshot.cpp +++ b/src/engine/shared/snapshot.cpp @@ -195,13 +195,14 @@ int CSnapshotDelta::CreateDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pDstData // fetch previous indices // we do this as a separate pass because it helps the cache - for(i = 0; i < pTo->NumItems(); i++) + const int NumItems = pTo->NumItems(); + for(i = 0; i < NumItems; i++) { pCurItem = pTo->GetItem(i); // O(1) .. O(n) aPastIndecies[i] = GetItemIndexHashed(pCurItem->Key(), Hashlist); // O(n) .. O(n^n) } - for(i = 0; i < pTo->NumItems(); i++) + for(i = 0; i < NumItems; i++) { // do delta ItemSize = pTo->GetItemSize(i); // O(1) .. O(n) @@ -474,7 +475,7 @@ int CSnapshotStorage::Get(int Tick, int64 *pTagtime, CSnapshot **ppData, CSnapsh if(ppData) *ppData = pHolder->m_pSnap; if(ppAltData) - *ppData = pHolder->m_pAltSnap; + *ppAltData = pHolder->m_pAltSnap; return pHolder->m_SnapSize; } |