42 changes: 37 additions & 5 deletions src/base/system.h
Expand Up @@ -303,6 +303,18 @@ int io_close(IOHANDLE io);
*/
int io_flush(IOHANDLE io);

/*
Function: io_sync
Synchronize file changes to disk.
Parameters:
io - Handle to the file.
Returns:
Returns 0 on success.
*/
int io_sync(IOHANDLE io);

/*
Function: io_error
Checks whether an error occurred during I/O with the file.
Expand Down Expand Up @@ -333,6 +345,12 @@ IOHANDLE io_stdout();
*/
IOHANDLE io_stderr();

/*
Function: io_current_exe
Returns an <IOHANDLE> to the current executable.
*/
IOHANDLE io_current_exe();

typedef struct ASYNCIO ASYNCIO;

/*
Expand Down Expand Up @@ -1873,14 +1891,14 @@ int str_utf8_to_skeleton(const char *str, int *buf, int buf_len);
Compares two strings for visual appearance.
Parameters:
a - String to compare.
b - String to compare.
str1 - String to compare.
str2 - String to compare.
Returns:
0 if the strings are confusable.
!=0 otherwise.
*/
int str_utf8_comp_confusable(const char *a, const char *b);
int str_utf8_comp_confusable(const char *str1, const char *str2);

/*
Function: str_utf8_tolower
Expand Down Expand Up @@ -1978,13 +1996,13 @@ const char *str_utf8_skip_whitespaces(const char *str);
the string in-place.
Parameters:
str - Pointer to the string.
param - Pointer to the string.
Remarks:
- The strings are treated as zero-terminated strings.
- The string is modified in-place.
*/
void str_utf8_trim_right(char *str);
void str_utf8_trim_right(char *param);

/*
Function: str_utf8_rewind
Expand Down Expand Up @@ -2326,6 +2344,20 @@ int secure_rand_below(int below);
*/
void set_console_msg_color(const void *rgbvoid);

/*
Function: os_version_str
Returns a human-readable version string of the operating system
Parameters:
version - Buffer to use for the output.
length - Length of the output buffer.
Returns:
0 - Success in getting the version.
1 - Failure in getting the version.
*/
int os_version_str(char *version, int length);

#if defined(__cplusplus)
}
#endif
Expand Down
17 changes: 15 additions & 2 deletions src/base/tl/threading.h
Expand Up @@ -2,17 +2,30 @@
#define BASE_TL_THREADING_H

#include "../system.h"
#include <atomic>

class CSemaphore
{
SEMAPHORE m_Sem;
// implement the counter seperatly, because the `sem_getvalue`-API is
// deprecated on macOS: https://stackoverflow.com/a/16655541
std::atomic_int m_Count{0};

public:
CSemaphore() { sphore_init(&m_Sem); }
~CSemaphore() { sphore_destroy(&m_Sem); }
CSemaphore(const CSemaphore &) = delete;
void Wait() { sphore_wait(&m_Sem); }
void Signal() { sphore_signal(&m_Sem); }
int GetApproximateValue() { return m_Count.load(); }
void Wait()
{
sphore_wait(&m_Sem);
m_Count.fetch_sub(1);
}
void Signal()
{
m_Count.fetch_add(1);
sphore_signal(&m_Sem);
}
};

class SCOPED_CAPABILITY CLock
Expand Down
38 changes: 24 additions & 14 deletions src/engine/client.h
Expand Up @@ -23,6 +23,7 @@ enum
};

typedef bool (*CLIENTFUNC_FILTER)(const void *pData, int DataSize, void *pUser);
struct CChecksumData;

class IClient : public IInterface
{
Expand Down Expand Up @@ -62,6 +63,14 @@ class IClient : public IInterface
int m_DataSize;
};

enum
{
CONN_MAIN = 0,
CONN_DUMMY,
CONN_CONTACT,
NUM_CONNS,
};

/* Constants: Client States
STATE_OFFLINE - The client is offline.
STATE_CONNECTING - The client is trying to connect to a server.
Expand All @@ -86,13 +95,13 @@ class IClient : public IInterface
inline int State() const { return m_State; }

// tick time access
inline int PrevGameTick(int Dummy) const { return m_PrevGameTick[Dummy]; }
inline int GameTick(int Dummy) const { return m_CurGameTick[Dummy]; }
inline int PredGameTick(int Dummy) const { return m_PredTick[Dummy]; }
inline float IntraGameTick(int Dummy) const { return m_GameIntraTick[Dummy]; }
inline float PredIntraGameTick(int Dummy) const { return m_PredIntraTick[Dummy]; }
inline float IntraGameTickSincePrev(int Dummy) const { return m_GameIntraTickSincePrev[Dummy]; }
inline float GameTickTime(int Dummy) const { return m_GameTickTime[Dummy]; }
inline int PrevGameTick(int Conn) const { return m_PrevGameTick[Conn]; }
inline int GameTick(int Conn) const { return m_CurGameTick[Conn]; }
inline int PredGameTick(int Conn) const { return m_PredTick[Conn]; }
inline float IntraGameTick(int Conn) const { return m_GameIntraTick[Conn]; }
inline float PredIntraGameTick(int Conn) const { return m_PredIntraTick[Conn]; }
inline float IntraGameTickSincePrev(int Conn) const { return m_GameIntraTickSincePrev[Conn]; }
inline float GameTickTime(int Conn) const { return m_GameTickTime[Conn]; }
inline int GameTickSpeed() const { return m_GameTickSpeed; }

// other time access
Expand Down Expand Up @@ -128,13 +137,13 @@ class IClient : public IInterface

// gfx
virtual void SwitchWindowScreen(int Index) = 0;
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0;
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing) = 0;
virtual void ToggleWindowVSync() = 0;
virtual void LoadFont() = 0;
virtual void Notify(const char *pTitle, const char *pMessage) = 0;

// networking
virtual void EnterGame() = 0;
virtual void EnterGame(int Conn) = 0;

//
virtual const char *MapDownloadName() const = 0;
Expand Down Expand Up @@ -173,16 +182,16 @@ class IClient : public IInterface

virtual void SnapSetStaticsize(int ItemType, int Size) = 0;

virtual int SendMsg(CMsgPacker *pMsg, int Flags) = 0;
virtual int SendMsgY(CMsgPacker *pMsg, int Flags, int NetClient = 1) = 0;
virtual int SendMsg(int Conn, CMsgPacker *pMsg, int Flags) = 0;
virtual int SendMsgActive(CMsgPacker *pMsg, int Flags) = 0;

template<class T>
int SendPackMsg(T *pMsg, int Flags)
int SendPackMsgActive(T *pMsg, int Flags)
{
CMsgPacker Packer(pMsg->MsgID(), false);
if(pMsg->Pack(&Packer))
return -1;
return SendMsg(&Packer, Flags);
return SendMsgActive(&Packer, Flags);
}

//
Expand Down Expand Up @@ -223,6 +232,7 @@ class IClient : public IInterface
virtual void GetSmoothTick(int *pSmoothTick, float *pSmoothIntraTick, float MixAmount) = 0;

virtual SWarning *GetCurWarning() = 0;
virtual CChecksumData *ChecksumData() = 0;
};

class IGameClient : public IInterface
Expand All @@ -243,7 +253,7 @@ class IGameClient : public IInterface
virtual void OnUpdate() = 0;
virtual void OnStateChange(int NewState, int OldState) = 0;
virtual void OnConnected() = 0;
virtual void OnMessage(int MsgID, CUnpacker *pUnpacker, bool IsDummy = 0) = 0;
virtual void OnMessage(int MsgID, CUnpacker *pUnpacker, int Conn, bool Dummy) = 0;
virtual void OnPredict() = 0;
virtual void OnActivateEditor() = 0;

Expand Down
9 changes: 1 addition & 8 deletions src/engine/client/backend/opengl/backend_opengl.cpp
Expand Up @@ -488,12 +488,7 @@ bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
pCommand->m_pCapabilities->m_TextBuffering = false;
pCommand->m_pCapabilities->m_QuadContainerBuffering = false;

if(GLEW_ARB_texture_non_power_of_two || pCommand->m_GlewMajor > 2)
pCommand->m_pCapabilities->m_NPOTTextures = true;
else
{
pCommand->m_pCapabilities->m_NPOTTextures = false;
}
pCommand->m_pCapabilities->m_NPOTTextures = GLEW_ARB_texture_non_power_of_two || pCommand->m_GlewMajor > 2;

if(!pCommand->m_pCapabilities->m_NPOTTextures || (!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures))
{
Expand Down Expand Up @@ -2329,9 +2324,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer
}
}

#ifdef BACKEND_GL_MODERN_API
#undef BACKEND_GL_MODERN_API
#endif

#endif

Expand Down
3 changes: 1 addition & 2 deletions src/engine/client/backend/opengl/backend_opengl.h
Expand Up @@ -72,7 +72,6 @@ class CCommandProcessorFragment_OpenGL : public CCommandProcessorFragment_OpenGL

bool m_IsOpenGLES;

protected:
bool IsTexturedState(const CCommandBuffer::SState &State);
static bool Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight);

Expand Down Expand Up @@ -209,7 +208,7 @@ class CCommandProcessorFragment_OpenGL2 : public CCommandProcessorFragment_OpenG

public:
CCommandProcessorFragment_OpenGL2() :
CCommandProcessorFragment_OpenGL(), m_UseMultipleTextureUnits(false) {}
m_UseMultipleTextureUnits(false) {}
};

class CCommandProcessorFragment_OpenGL3 : public CCommandProcessorFragment_OpenGL2
Expand Down
18 changes: 9 additions & 9 deletions src/engine/client/backend/opengl/opengl_sl_program.h
Expand Up @@ -35,9 +35,9 @@ class CGLSLProgram
//Support various types
void SetUniformVec2(int Loc, int Count, const float *pValue);
void SetUniformVec4(int Loc, int Count, const float *pValue);
void SetUniform(int Loc, const int Value);
void SetUniform(int Loc, const bool Value);
void SetUniform(int Loc, const float Value);
void SetUniform(int Loc, int Value);
void SetUniform(int Loc, bool Value);
void SetUniform(int Loc, float Value);
void SetUniform(int Loc, int Count, const float *pValues);

//for performance reason we do not use SetUniform with using strings... save the Locations of the variables instead
Expand Down Expand Up @@ -71,8 +71,8 @@ class CGLSLTWProgram : public CGLSLProgram
class CGLSLTextProgram : public CGLSLTWProgram
{
public:
CGLSLTextProgram() :
CGLSLTWProgram()
CGLSLTextProgram()

{
m_LastColor[0] = m_LastColor[1] = m_LastColor[2] = m_LastColor[3] = -1.f;
m_LastOutlineColor[0] = m_LastOutlineColor[1] = m_LastOutlineColor[2] = m_LastOutlineColor[3] = -1.f;
Expand Down Expand Up @@ -101,8 +101,8 @@ class CGLSLPrimitiveProgram : public CGLSLTWProgram
class CGLSLPrimitiveExProgram : public CGLSLTWProgram
{
public:
CGLSLPrimitiveExProgram() :
CGLSLTWProgram()
CGLSLPrimitiveExProgram()

{
m_LastRotation = 0.f;
m_LastCenter[0] = m_LastCenter[1] = 0.f;
Expand All @@ -121,8 +121,8 @@ class CGLSLPrimitiveExProgram : public CGLSLTWProgram
class CGLSLSpriteMultipleProgram : public CGLSLTWProgram
{
public:
CGLSLSpriteMultipleProgram() :
CGLSLTWProgram()
CGLSLSpriteMultipleProgram()

{
m_LastCenter[0] = m_LastCenter[1] = 0.f;
m_LastVertciesColor[0] = m_LastVertciesColor[1] = m_LastVertciesColor[2] = m_LastVertciesColor[3] = -1.f;
Expand Down
162 changes: 106 additions & 56 deletions src/engine/client/backend_sdl.cpp
Expand Up @@ -56,24 +56,25 @@ int putenv(const char *);

// ------------ CGraphicsBackend_Threaded

void CGraphicsBackend_Threaded::ThreadFunc()
void CGraphicsBackend_Threaded::ThreadFunc(void *pUser)
{
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
auto *pSelf = (CGraphicsBackend_Threaded *)pUser;
std::unique_lock<std::mutex> Lock(pSelf->m_BufferSwapMutex);
// notify, that the thread started
m_BufferDoneCond.notify_all();
while(!m_Shutdown)
pSelf->m_BufferDoneCond.notify_all();
while(!pSelf->m_Shutdown)
{
m_BufferSwapCond.wait(Lock);
if(m_pBuffer)
pSelf->m_BufferSwapCond.wait(Lock);
if(pSelf->m_pBuffer)
{
#ifdef CONF_PLATFORM_MACOS
CAutoreleasePool AutoreleasePool;
#endif
m_pProcessor->RunBuffer(m_pBuffer);
pSelf->m_pProcessor->RunBuffer(pSelf->m_pBuffer);

m_pBuffer = nullptr;
m_BufferInProcess.store(false, std::memory_order_relaxed);
m_BufferDoneCond.notify_all();
pSelf->m_pBuffer = nullptr;
pSelf->m_BufferInProcess.store(false, std::memory_order_relaxed);
pSelf->m_BufferDoneCond.notify_all();
}
#if defined(CONF_VIDEORECORDER)
if(IVideo::Current())
Expand All @@ -94,7 +95,7 @@ void CGraphicsBackend_Threaded::StartProcessor(ICommandProcessor *pProcessor)
m_Shutdown = false;
m_pProcessor = pProcessor;
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
m_Thread = std::thread([&]() { ThreadFunc(); });
m_Thread = thread_init(ThreadFunc, this, "Graphics thread");
// wait for the thread to start
m_BufferDoneCond.wait(Lock);
}
Expand All @@ -106,7 +107,7 @@ void CGraphicsBackend_Threaded::StopProcessor()
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
m_BufferSwapCond.notify_all();
}
m_Thread.join();
thread_wait(m_Thread);
}

void CGraphicsBackend_Threaded::RunBuffer(CCommandBuffer *pBuffer)
Expand Down Expand Up @@ -309,7 +310,7 @@ static bool BackendInitGlew(EBackendType BackendType, int &GlewMajor, int &GlewM
return true;
}
// Don't allow GL 3.3, if the driver doesn't support atleast OpenGL 4.5
#ifndef CONF_PLATFORM_WINDOWS
#ifndef CONF_FAMILY_WINDOWS
if(GLEW_VERSION_4_4)
{
GlewMajor = 4;
Expand Down Expand Up @@ -667,7 +668,7 @@ void CGraphicsBackend_SDL_OpenGL::GetVideoModes(CVideoMode *pModes, int MaxModes

// Only collect fullscreen modes when requested, that makes sure in windowed mode no refresh rates are shown that aren't supported without
// fullscreen anyway(except fullscreen desktop)
bool IsFullscreenDestkop = m_pWindow != NULL && ((SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP);
bool IsFullscreenDestkop = m_pWindow != NULL && (((SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) || g_Config.m_GfxFullscreen == 3);
bool CollectFullscreenModes = m_pWindow == NULL || ((SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN) != 0 && !IsFullscreenDestkop);

if(SDL_GetDesktopDisplayMode(Screen, &DesktopMode) < 0)
Expand Down Expand Up @@ -726,21 +727,37 @@ void CGraphicsBackend_SDL_OpenGL::GetVideoModes(CVideoMode *pModes, int MaxModes
void CGraphicsBackend_SDL_OpenGL::GetCurrentVideoMode(CVideoMode &CurMode, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen)
{
SDL_DisplayMode DPMode;
if(SDL_GetDesktopDisplayMode(Screen, &DPMode) < 0)
// if "real" fullscreen, obtain the video mode for that
if((SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN)
{
dbg_msg("gfx", "unable to get display mode: %s", SDL_GetError());
if(SDL_GetCurrentDisplayMode(Screen, &DPMode))
{
dbg_msg("gfx", "unable to get display mode: %s", SDL_GetError());
}
}
else
{
int Width = 0;
int Height = 0;
SDL_GL_GetDrawableSize(m_pWindow, &Width, &Height);
DPMode.w = Width;
DPMode.h = Height;
if(SDL_GetDesktopDisplayMode(Screen, &DPMode) < 0)
{
dbg_msg("gfx", "unable to get display mode: %s", SDL_GetError());
}
else
{
int Width = 0;
int Height = 0;
SDL_GL_GetDrawableSize(m_pWindow, &Width, &Height);
DPMode.w = Width;
DPMode.h = Height;
}
}
DisplayToVideoMode(&CurMode, &DPMode, HiDPIScale, DPMode.refresh_rate);
}

CGraphicsBackend_SDL_OpenGL::CGraphicsBackend_SDL_OpenGL()
{
mem_zero(m_aErrorString, sizeof(m_aErrorString) / sizeof(m_aErrorString[0]));
}

int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWidth, int *pHeight, int *pRefreshRate, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, IStorage *pStorage)
{
// print sdl version
Expand Down Expand Up @@ -851,7 +868,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
else if(Flags & (IGraphicsBackend::INITFLAG_DESKTOP_FULLSCREEN))
SdlFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;

bool IsFullscreen = (SdlFlags & SDL_WINDOW_FULLSCREEN) != 0;
bool IsFullscreen = (SdlFlags & SDL_WINDOW_FULLSCREEN) != 0 || g_Config.m_GfxFullscreen == 3;
// use desktop resolution as default resolution, clamp resolution if users's display is smaller than we remembered
// if the user starts in fullscreen, and the resolution was not found use the desktop one
if((IsFullscreen && !SupportedResolution) || *pWidth == 0 || *pHeight == 0 || (IsDesktopChanged && (*pWidth > *pDesktopWidth || *pHeight > *pDesktopHeight)))
Expand Down Expand Up @@ -953,8 +970,6 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
m_pProcessor = new CCommandProcessor_SDL_OpenGL(m_BackendType, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch);
StartProcessor(m_pProcessor);

mem_zero(m_aErrorString, sizeof(m_aErrorString) / sizeof(m_aErrorString[0]));

// issue init commands for OpenGL and SDL
CCommandBuffer CmdBuffer(1024, 512);
//run sdl first to have the context in the thread
Expand Down Expand Up @@ -1093,10 +1108,15 @@ void CGraphicsBackend_SDL_OpenGL::Maximize()
// TODO: SDL
}

void CGraphicsBackend_SDL_OpenGL::SetWindowParams(int FullscreenMode, bool IsBorderless)
void CGraphicsBackend_SDL_OpenGL::SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing)
{
if(FullscreenMode > 0)
{
bool IsDesktopFullscreen = FullscreenMode == 2;
#ifndef CONF_FAMILY_WINDOWS
// special mode for windows only
IsDesktopFullscreen |= FullscreenMode == 3;
#endif
if(FullscreenMode == 1)
{
#if defined(CONF_PLATFORM_MACOS) || defined(CONF_PLATFORM_HAIKU)
Expand All @@ -1105,16 +1125,35 @@ void CGraphicsBackend_SDL_OpenGL::SetWindowParams(int FullscreenMode, bool IsBor
#else
SDL_SetWindowFullscreen(m_pWindow, SDL_WINDOW_FULLSCREEN);
#endif
SDL_SetWindowResizable(m_pWindow, SDL_TRUE);
}
else if(FullscreenMode == 2)
else if(IsDesktopFullscreen)
{
SDL_SetWindowFullscreen(m_pWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_SetWindowResizable(m_pWindow, SDL_TRUE);
}
else
{
SDL_SetWindowFullscreen(m_pWindow, 0);
SDL_SetWindowBordered(m_pWindow, SDL_TRUE);
SDL_SetWindowResizable(m_pWindow, SDL_FALSE);
SDL_DisplayMode DPMode;
if(SDL_GetDesktopDisplayMode(g_Config.m_GfxScreen, &DPMode) < 0)
{
dbg_msg("gfx", "unable to get display mode: %s", SDL_GetError());
}
else
{
ResizeWindow(DPMode.w, DPMode.h, DPMode.refresh_rate);
SDL_SetWindowPosition(m_pWindow, SDL_WINDOWPOS_CENTERED_DISPLAY(g_Config.m_GfxScreen), SDL_WINDOWPOS_CENTERED_DISPLAY(g_Config.m_GfxScreen));
}
}
}
else
{
SDL_SetWindowFullscreen(m_pWindow, 0);
SDL_SetWindowBordered(m_pWindow, SDL_bool(!IsBorderless));
SDL_SetWindowResizable(m_pWindow, SDL_TRUE);
}
}

Expand Down Expand Up @@ -1149,7 +1188,6 @@ bool CGraphicsBackend_SDL_OpenGL::UpdateDisplayMode(int Index)

g_Config.m_GfxDesktopWidth = DisplayMode.w;
g_Config.m_GfxDesktopHeight = DisplayMode.h;
g_Config.m_GfxRefreshRate = DisplayMode.refresh_rate;

return true;
}
Expand All @@ -1161,52 +1199,55 @@ int CGraphicsBackend_SDL_OpenGL::GetWindowScreen()

int CGraphicsBackend_SDL_OpenGL::WindowActive()
{
return SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_INPUT_FOCUS;
return m_pWindow && SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_INPUT_FOCUS;
}

int CGraphicsBackend_SDL_OpenGL::WindowOpen()
{
return SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_SHOWN;
return m_pWindow && SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_SHOWN;
}

void CGraphicsBackend_SDL_OpenGL::SetWindowGrab(bool Grab)
{
SDL_SetWindowGrab(m_pWindow, Grab ? SDL_TRUE : SDL_FALSE);
}

void CGraphicsBackend_SDL_OpenGL::ResizeWindow(int w, int h, int RefreshRate)
bool CGraphicsBackend_SDL_OpenGL::ResizeWindow(int w, int h, int RefreshRate)
{
// don't call resize events when the window is at fullscreen desktop
if((SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP)
if(!m_pWindow || (SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
return false;

// if the window is at fullscreen use SDL_SetWindowDisplayMode instead, suggested by SDL
if(SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN)
{
// if the window is at fullscreen use SDL_SetWindowDisplayMode instead, suggested by SDL
if(SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN)
{
#ifdef CONF_PLATFORM_WINDOWS
// in windows make the window windowed mode first, this prevents strange window glitches (other games probably do something similar)
SetWindowParams(0, 1);
#ifdef CONF_FAMILY_WINDOWS
// in windows make the window windowed mode first, this prevents strange window glitches (other games probably do something similar)
SetWindowParams(0, 1, true);
#endif
SDL_DisplayMode SetMode = {};
SDL_DisplayMode ClosestMode = {};
SetMode.format = 0;
SetMode.w = w;
SetMode.h = h;
SetMode.refresh_rate = RefreshRate;
SDL_SetWindowDisplayMode(m_pWindow, SDL_GetClosestDisplayMode(g_Config.m_GfxScreen, &SetMode, &ClosestMode));
#ifdef CONF_PLATFORM_WINDOWS
// now change it back to fullscreen, this will restore the above set state, bcs SDL saves fullscreen modes appart from other video modes (as of SDL 2.0.16)
// see implementation of SDL_SetWindowDisplayMode
SetWindowParams(1, 0);
SDL_DisplayMode SetMode = {};
SDL_DisplayMode ClosestMode = {};
SetMode.format = 0;
SetMode.w = w;
SetMode.h = h;
SetMode.refresh_rate = RefreshRate;
SDL_SetWindowDisplayMode(m_pWindow, SDL_GetClosestDisplayMode(g_Config.m_GfxScreen, &SetMode, &ClosestMode));
#ifdef CONF_FAMILY_WINDOWS
// now change it back to fullscreen, this will restore the above set state, bcs SDL saves fullscreen modes appart from other video modes (as of SDL 2.0.16)
// see implementation of SDL_SetWindowDisplayMode
SetWindowParams(1, 0, true);
#endif
}
else
{
SDL_SetWindowSize(m_pWindow, w, h);
if(SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_MAXIMIZED)
// remove maximize flag
SDL_RestoreWindow(m_pWindow);
}
return true;
}
else
{
SDL_SetWindowSize(m_pWindow, w, h);
if(SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_MAXIMIZED)
// remove maximize flag
SDL_RestoreWindow(m_pWindow);
}

return false;
}

void CGraphicsBackend_SDL_OpenGL::GetViewportSize(int &w, int &h)
Expand All @@ -1225,4 +1266,13 @@ void CGraphicsBackend_SDL_OpenGL::NotifyWindow()
#endif
}

void CGraphicsBackend_SDL_OpenGL::WindowDestroyNtf(uint32_t WindowID)
{
}

void CGraphicsBackend_SDL_OpenGL::WindowCreateNtf(uint32_t WindowID)
{
m_pWindow = SDL_GetWindowFromID(WindowID);
}

IGraphicsBackend *CreateGraphicsBackend() { return new CGraphicsBackend_SDL_OpenGL; }
12 changes: 8 additions & 4 deletions src/engine/client/backend_sdl.h
Expand Up @@ -73,9 +73,9 @@ class CGraphicsBackend_Threaded : public IGraphicsBackend
CCommandBuffer *m_pBuffer;
std::atomic_bool m_Shutdown;
std::atomic_bool m_BufferInProcess;
std::thread m_Thread;
void *m_Thread;

void ThreadFunc();
static void ThreadFunc(void *pUser);
};

// takes care of implementation independent operations
Expand Down Expand Up @@ -241,6 +241,7 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
static void ClampDriverVersion(EBackendType BackendType);

public:
CGraphicsBackend_SDL_OpenGL();
virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int *pRefreshRate, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage);
virtual int Shutdown();

Expand All @@ -253,17 +254,20 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded

virtual void Minimize();
virtual void Maximize();
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless);
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing);
virtual bool SetWindowScreen(int Index);
virtual bool UpdateDisplayMode(int Index);
virtual int GetWindowScreen();
virtual int WindowActive();
virtual int WindowOpen();
virtual void SetWindowGrab(bool Grab);
virtual void ResizeWindow(int w, int h, int RefreshRate);
virtual bool ResizeWindow(int w, int h, int RefreshRate);
virtual void GetViewportSize(int &w, int &h);
virtual void NotifyWindow();

virtual void WindowDestroyNtf(uint32_t WindowID);
virtual void WindowCreateNtf(uint32_t WindowID);

virtual void GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch);
virtual bool IsConfigModernAPI() { return IsModernAPI(m_BackendType); }
virtual bool IsNewOpenGL() { return m_UseNewOpenGL; }
Expand Down
36 changes: 36 additions & 0 deletions src/engine/client/checksum.h
@@ -0,0 +1,36 @@
#ifndef ENGINE_CLIENT_CHECKSUM_H
#define ENGINE_CLIENT_CHECKSUM_H

#include <engine/shared/config.h>

struct CChecksumData
{
int m_SizeofData;
char m_aVersionStr[128];
int m_Version;
char m_aOsVersion[256];
int64_t m_Start;
int m_Random;
int m_SizeofClient;
int m_SizeofGameClient;
float m_Zoom;
int m_SizeofConfig;
CConfig m_Config;
int m_NumCommands;
int m_aCommandsChecksum[1024];
int m_NumComponents;
int m_aComponentsChecksum[64];
int m_NumFiles;
int m_NumExtra;
unsigned m_aFiles[1024];

void InitFiles();
};

union CChecksum
{
char m_aBytes[sizeof(CChecksumData)];
CChecksumData m_Data;
};

#endif // ENGINE_CLIENT_CHECKSUM_H
885 changes: 411 additions & 474 deletions src/engine/client/client.cpp

Large diffs are not rendered by default.

50 changes: 31 additions & 19 deletions src/engine/client/client.h
Expand Up @@ -8,6 +8,7 @@

#include <base/hash.h>
#include <engine/client.h>
#include <engine/client/checksum.h>
#include <engine/client/demoedit.h>
#include <engine/client/friends.h>
#include <engine/client/ghost.h>
Expand Down Expand Up @@ -61,6 +62,10 @@ class CSmoothTime
int64_t m_Current;
int64_t m_Target;

int64_t m_SnapMargin;
int64_t m_CurrentMargin;
int64_t m_TargetMargin;

CGraph m_Graph;

int m_SpikeCounter;
Expand All @@ -74,6 +79,9 @@ class CSmoothTime

void UpdateInt(int64_t Target);
void Update(CGraph *pGraph, int64_t Target, int TimeLeft, int AdjustDirection);

int64_t GetMargin(int64_t Now);
void UpdateMargin(int64_t TargetMargin);
};

class CServerCapabilities
Expand All @@ -83,6 +91,7 @@ class CServerCapabilities
bool m_AnyPlayerFlag;
bool m_PingEx;
bool m_AllowDummy;
bool m_SyncWeaponInput;
};

class CClient : public IClient, public CDemoPlayer::IListener
Expand All @@ -106,18 +115,9 @@ class CClient : public IClient, public CDemoPlayer::IListener
enum
{
NUM_SNAPSHOT_TYPES = 2,
PREDICTION_MARGIN = 1000 / 50 / 2, // magic network prediction value
};

enum
{
CLIENT_MAIN = 0,
CLIENT_DUMMY,
CLIENT_CONTACT,
NUM_CLIENTS,
};

class CNetClient m_NetClient[NUM_CLIENTS];
class CNetClient m_NetClient[NUM_CONNS];
class CDemoPlayer m_DemoPlayer;
class CDemoRecorder m_DemoRecorder[RECORDER_MAX];
class CDemoEditor m_DemoEditor;
Expand Down Expand Up @@ -210,6 +210,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
int m_aData[MAX_INPUT_SIZE]; // the input data
int m_Tick; // the tick that the input is for
int64_t m_PredictedTime; // prediction latency when we sent this input
int64_t m_PredictionMargin; // prediction margin when we sent this input
int64_t m_Time;
} m_aInputs[NUM_DUMMIES][200];

Expand Down Expand Up @@ -279,7 +280,13 @@ class CClient : public IClient, public CDemoPlayer::IListener
IOHANDLE m_BenchmarkFile;
int64_t m_BenchmarkStopTime;

CChecksum m_Checksum;
int m_OwnExecutableSize = 0;
IOHANDLE m_OwnExecutable;

void UpdateDemoIntraTimers();
int MaxLatencyTicks() const;
int PredictionMargin() const;

public:
IEngine *Engine() { return m_pEngine; }
Expand All @@ -297,11 +304,12 @@ class CClient : public IClient, public CDemoPlayer::IListener
CClient();

// ----- send functions -----
virtual int SendMsg(CMsgPacker *pMsg, int Flags);
virtual int SendMsgY(CMsgPacker *pMsg, int Flags, int NetClient = 1);
virtual int SendMsg(int Conn, CMsgPacker *pMsg, int Flags);
// Send via the currently active client (main/dummy)
virtual int SendMsgActive(CMsgPacker *pMsg, int Flags);

void SendInfo();
void SendEnterGame();
void SendEnterGame(int Conn);
void SendReady();
void SendMapRequest();

Expand Down Expand Up @@ -329,8 +337,8 @@ class CClient : public IClient, public CDemoPlayer::IListener
void SetState(int s);

// called when the map is loaded and we should init for a new round
void OnEnterGame();
virtual void EnterGame();
void OnEnterGame(bool Dummy);
virtual void EnterGame(int Conn);

virtual void Connect(const char *pAddress, const char *pPassword = NULL);
void DisconnectWithReason(const char *pReason);
Expand Down Expand Up @@ -374,8 +382,7 @@ class CClient : public IClient, public CDemoPlayer::IListener

void ProcessConnlessPacket(CNetChunk *pPacket);
void ProcessServerInfo(int Type, NETADDR *pFrom, const void *pData, int DataSize);
void ProcessServerPacket(CNetChunk *pPacket);
void ProcessServerPacketDummy(CNetChunk *pPacket);
void ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy);

void ResetMapDownload();
void FinishMapDownload();
Expand Down Expand Up @@ -417,6 +424,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
static void Con_Minimize(IConsole::IResult *pResult, void *pUserData);
static void Con_Ping(IConsole::IResult *pResult, void *pUserData);
static void Con_Screenshot(IConsole::IResult *pResult, void *pUserData);
static void Con_Reset(IConsole::IResult *pResult, void *pUserData);

#if defined(CONF_VIDEORECORDER)
static void StartVideo(IConsole::IResult *pResult, void *pUserData, const char *pVideName);
Expand Down Expand Up @@ -474,9 +482,12 @@ class CClient : public IClient, public CDemoPlayer::IListener
void HandleDemoPath(const char *pPath);
void HandleMapPath(const char *pPath);

virtual void InitChecksum();
virtual int HandleChecksum(int Conn, CUuid Uuid, CUnpacker *pUnpacker);

// gfx
virtual void SwitchWindowScreen(int Index);
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless);
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing);
virtual void ToggleWindowVSync();
virtual void LoadFont();
virtual void Notify(const char *pTitle, const char *pMessage);
Expand All @@ -501,7 +512,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
virtual void DemoSliceBegin();
virtual void DemoSliceEnd();
virtual void DemoSlice(const char *pDstPath, CLIENTFUNC_FILTER pfnFilter, void *pUser);
virtual void SaveReplay(const int Length);
virtual void SaveReplay(int Length);

virtual bool EditorHasUnsavedData() const { return m_pEditor->HasUnsavedData(); }

Expand All @@ -510,6 +521,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
virtual void GetSmoothTick(int *pSmoothTick, float *pSmoothIntraTick, float MixAmount);

virtual SWarning *GetCurWarning();
virtual CChecksumData *ChecksumData() { return &m_Checksum.m_Data; }
};

#endif
4 changes: 2 additions & 2 deletions src/engine/client/ghost.cpp
Expand Up @@ -361,7 +361,7 @@ void CGhostLoader::Close()
m_File = 0;
}

bool CGhostLoader::GetGhostInfo(const char *pFilename, CGhostInfo *pInfo, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc)
bool CGhostLoader::GetGhostInfo(const char *pFilename, CGhostInfo *pGhostInfo, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc)
{
CGhostHeader Header;
mem_zero(&Header, sizeof(Header));
Expand Down Expand Up @@ -395,7 +395,7 @@ bool CGhostLoader::GetGhostInfo(const char *pFilename, CGhostInfo *pInfo, const
return false;
}
}
*pInfo = Header.ToGhostInfo();
*pGhostInfo = Header.ToGhostInfo();

return true;
}
107 changes: 69 additions & 38 deletions src/engine/client/graphics_threaded.cpp
Expand Up @@ -1275,7 +1275,7 @@ void CGraphics_Threaded::QuadContainerUpload(int ContainerIndex)
if(IsQuadContainerBufferingEnabled())
{
SQuadContainer &Container = m_QuadContainers[ContainerIndex];
if(Container.m_Quads.size() > 0)
if(!Container.m_Quads.empty())
{
if(Container.m_QuadBufferObjectIndex == -1)
{
Expand Down Expand Up @@ -2075,14 +2075,24 @@ void CGraphics_Threaded::IndicesNumRequiredNotify(unsigned int RequiredIndicesCo

int CGraphics_Threaded::IssueInit()
{
int Flags = IGraphicsBackend::INITFLAG_RESIZABLE;
int Flags = 0;

bool IsPurlyWindowed = g_Config.m_GfxFullscreen == 0;
bool IsExclusiveFullscreen = g_Config.m_GfxFullscreen == 1;
bool IsDesktopFullscreen = g_Config.m_GfxFullscreen == 2;
#ifndef CONF_FAMILY_WINDOWS
// special mode for windows only
IsDesktopFullscreen |= g_Config.m_GfxFullscreen == 3;
#endif

if(g_Config.m_GfxBorderless)
Flags |= IGraphicsBackend::INITFLAG_BORDERLESS;
if(g_Config.m_GfxFullscreen == 1)
if(IsExclusiveFullscreen)
Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN;
else if(g_Config.m_GfxFullscreen == 2)
else if(IsDesktopFullscreen)
Flags |= IGraphicsBackend::INITFLAG_DESKTOP_FULLSCREEN;
if(IsPurlyWindowed || IsExclusiveFullscreen || IsDesktopFullscreen)
Flags |= IGraphicsBackend::INITFLAG_RESIZABLE;
if(g_Config.m_GfxVsync)
Flags |= IGraphicsBackend::INITFLAG_VSYNC;
if(g_Config.m_GfxHighdpi)
Expand Down Expand Up @@ -2310,12 +2320,12 @@ void CGraphics_Threaded::Maximize()
m_pBackend->Maximize();
}

void CGraphics_Threaded::SetWindowParams(int FullscreenMode, bool IsBorderless)
void CGraphics_Threaded::SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing)
{
m_pBackend->SetWindowParams(FullscreenMode, IsBorderless);
m_pBackend->SetWindowParams(FullscreenMode, IsBorderless, AllowResizing);
CVideoMode CurMode;
m_pBackend->GetCurrentVideoMode(CurMode, m_ScreenHiDPIScale, g_Config.m_GfxDesktopWidth, g_Config.m_GfxDesktopHeight, g_Config.m_GfxScreen);
Resize(CurMode.m_WindowWidth, CurMode.m_WindowHeight, CurMode.m_RefreshRate, false, true);
GotResized(CurMode.m_WindowWidth, CurMode.m_WindowHeight, CurMode.m_RefreshRate);
}

bool CGraphics_Threaded::SetWindowScreen(int Index)
Expand Down Expand Up @@ -2344,56 +2354,68 @@ void CGraphics_Threaded::Move(int x, int y)
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;
}

void CGraphics_Threaded::Resize(int w, int h, int RefreshRate, bool SetWindowSize, bool ForceResizeEvent)
void CGraphics_Threaded::Resize(int w, int h, int RefreshRate)
{
#if defined(CONF_VIDEORECORDER)
if(IVideo::Current() && IVideo::Current()->IsRecording())
return;
#endif

if(!ForceResizeEvent && WindowWidth() == w && WindowHeight() == h && (RefreshRate != -1 && RefreshRate == m_ScreenRefreshRate))
if(WindowWidth() == w && WindowHeight() == h && RefreshRate == m_ScreenRefreshRate)
return;

// if the size is changed manually, only set the window resize, a window size changed event is triggered anyway
if(SetWindowSize)
if(m_pBackend->ResizeWindow(w, h, RefreshRate))
{
m_pBackend->ResizeWindow(w, h, RefreshRate);
CVideoMode CurMode;
m_pBackend->GetCurrentVideoMode(CurMode, m_ScreenHiDPIScale, g_Config.m_GfxDesktopWidth, g_Config.m_GfxDesktopHeight, g_Config.m_GfxScreen);
GotResized(w, h, RefreshRate);
}
else
{
// if the size change event is triggered, set all parameters and change the viewport
m_pBackend->GetViewportSize(m_ScreenWidth, m_ScreenHeight);
}

// adjust the viewport to only allow certain aspect ratios
if(m_ScreenHeight > 4 * m_ScreenWidth / 5)
m_ScreenHeight = 4 * m_ScreenWidth / 5;
void CGraphics_Threaded::GotResized(int w, int h, int RefreshRate)
{
#if defined(CONF_VIDEORECORDER)
if(IVideo::Current() && IVideo::Current()->IsRecording())
return;
#endif

m_ScreenRefreshRate = RefreshRate == -1 ? m_ScreenRefreshRate : RefreshRate;
// if RefreshRate is -1 use the current config refresh rate
if(RefreshRate == -1)
RefreshRate = g_Config.m_GfxScreenRefreshRate;

g_Config.m_GfxScreenWidth = w;
g_Config.m_GfxScreenHeight = h;
g_Config.m_GfxScreenRefreshRate = m_ScreenRefreshRate;
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;
// if the size change event is triggered, set all parameters and change the viewport
m_pBackend->GetViewportSize(m_ScreenWidth, m_ScreenHeight);

CCommandBuffer::SCommand_Update_Viewport Cmd;
Cmd.m_X = 0;
Cmd.m_Y = 0;
Cmd.m_Width = m_ScreenWidth;
Cmd.m_Height = m_ScreenHeight;
// adjust the viewport to only allow certain aspect ratios
if(m_ScreenHeight > 4 * m_ScreenWidth / 5)
m_ScreenHeight = 4 * m_ScreenWidth / 5;

if(!AddCmd(
Cmd, [] { return true; }, "failed to add resize command"))
{
return;
}
m_ScreenRefreshRate = RefreshRate;

// kick the command buffer
KickCommandBuffer();
WaitForIdle();
g_Config.m_GfxScreenWidth = w;
g_Config.m_GfxScreenHeight = h;
g_Config.m_GfxScreenRefreshRate = m_ScreenRefreshRate;
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;

CCommandBuffer::SCommand_Update_Viewport Cmd;
Cmd.m_X = 0;
Cmd.m_Y = 0;
Cmd.m_Width = m_ScreenWidth;
Cmd.m_Height = m_ScreenHeight;

for(auto &ResizeListener : m_ResizeListeners)
ResizeListener.m_pFunc(ResizeListener.m_pUser);
if(!AddCmd(
Cmd, [] { return true; }, "failed to add resize command"))
{
return;
}

// kick the command buffer and wait
KickCommandBuffer();
WaitForIdle();

for(auto &ResizeListener : m_ResizeListeners)
ResizeListener.m_pFunc(ResizeListener.m_pUser);
}

void CGraphics_Threaded::AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser)
Expand All @@ -2408,6 +2430,8 @@ int CGraphics_Threaded::GetWindowScreen()

void CGraphics_Threaded::WindowDestroyNtf(uint32_t WindowID)
{
m_pBackend->WindowDestroyNtf(WindowID);

CCommandBuffer::SCommand_WindowDestroyNtf Cmd;
Cmd.m_WindowID = WindowID;

Expand All @@ -2420,6 +2444,8 @@ void CGraphics_Threaded::WindowDestroyNtf(uint32_t WindowID)

void CGraphics_Threaded::WindowCreateNtf(uint32_t WindowID)
{
m_pBackend->WindowCreateNtf(WindowID);

CCommandBuffer::SCommand_WindowCreateNtf Cmd;
Cmd.m_WindowID = WindowID;

Expand Down Expand Up @@ -2506,6 +2532,11 @@ void CGraphics_Threaded::Swap()

// kick the command buffer
KickCommandBuffer();
// TODO: Remove when https://github.com/libsdl-org/SDL/issues/5203 is fixed
#ifdef CONF_PLATFORM_MACOS
if(str_find(GetVersionString(), "Metal"))
WaitForIdle();
#endif
}

bool CGraphics_Threaded::SetVSync(bool State)
Expand Down
13 changes: 9 additions & 4 deletions src/engine/client/graphics_threaded.h
Expand Up @@ -669,17 +669,21 @@ class IGraphicsBackend

virtual void Minimize() = 0;
virtual void Maximize() = 0;
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0;
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing) = 0;
virtual bool SetWindowScreen(int Index) = 0;
virtual bool UpdateDisplayMode(int Index) = 0;
virtual int GetWindowScreen() = 0;
virtual int WindowActive() = 0;
virtual int WindowOpen() = 0;
virtual void SetWindowGrab(bool Grab) = 0;
virtual void ResizeWindow(int w, int h, int RefreshRate) = 0;
// returns true, if the video mode changed
virtual bool ResizeWindow(int w, int h, int RefreshRate) = 0;
virtual void GetViewportSize(int &w, int &h) = 0;
virtual void NotifyWindow() = 0;

virtual void WindowDestroyNtf(uint32_t WindowID) = 0;
virtual void WindowCreateNtf(uint32_t WindowID) = 0;

virtual void RunBuffer(CCommandBuffer *pBuffer) = 0;
virtual bool IsIdle() const = 0;
virtual void WaitForIdle() = 0;
Expand Down Expand Up @@ -1165,10 +1169,11 @@ class CGraphics_Threaded : public IEngineGraphics
int GetNumScreens() const override;
void Minimize() override;
void Maximize() override;
void SetWindowParams(int FullscreenMode, bool IsBorderless) override;
void SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing) override;
bool SetWindowScreen(int Index) override;
void Move(int x, int y) override;
void Resize(int w, int h, int RefreshRate, bool SetWindowSize = false, bool ForceResizeEvent = false) override;
void Resize(int w, int h, int RefreshRate) override;
void GotResized(int w, int h, int RefreshRate) override;
void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser) override;
int GetWindowScreen() override;

Expand Down
5 changes: 3 additions & 2 deletions src/engine/client/graphics_threaded_null.h
Expand Up @@ -147,10 +147,11 @@ class CGraphics_ThreadedNull : public IEngineGraphics
int GetNumScreens() const override { return 0; };
void Minimize() override{};
void Maximize() override{};
void SetWindowParams(int FullscreenMode, bool IsBorderless) override{};
void SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing) override{};
bool SetWindowScreen(int Index) override { return false; };
void Move(int x, int y) override{};
void Resize(int w, int h, int RefreshRate, bool SetWindowSize = false, bool ForceResizeEvent = false) override{};
void Resize(int w, int h, int RefreshRate) override{};
void GotResized(int w, int h, int RefreshRate) override{};
void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser) override{};
int GetWindowScreen() override { return 0; };

Expand Down
342 changes: 169 additions & 173 deletions src/engine/client/input.cpp

Large diffs are not rendered by default.

8 changes: 3 additions & 5 deletions src/engine/client/input.h
Expand Up @@ -19,10 +19,9 @@ class CInput : public IEngineInput
int m_InputGrabbed;
char *m_pClipboardText;

int64_t m_LastRelease;
int64_t m_ReleaseDelta;

bool m_MouseFocus;
bool m_MouseDoubleClick;

int m_VideoRestartNeeded;

void AddEvent(char *pText, int Key, int Flags);
Expand Down Expand Up @@ -58,12 +57,11 @@ class CInput : public IEngineInput
virtual void MouseModeRelative();
virtual void NativeMousePos(int *x, int *y) const;
virtual bool NativeMousePressed(int index);
virtual int MouseDoubleClick();
virtual bool MouseDoubleClick();
virtual const char *GetClipboardText();
virtual void SetClipboardText(const char *Text);

virtual int Update();
virtual void NextFrame();

virtual int VideoRestartNeeded();

Expand Down
5 changes: 1 addition & 4 deletions src/engine/client/serverbrowser.cpp
Expand Up @@ -206,7 +206,7 @@ bool CServerBrowser::SortCompareName(int Index1, int Index2) const
CServerEntry *b = m_ppServerlist[Index2];
// make sure empty entries are listed last
return (a->m_GotInfo && b->m_GotInfo) || (!a->m_GotInfo && !b->m_GotInfo) ? str_comp(a->m_Info.m_aName, b->m_Info.m_aName) < 0 :
a->m_GotInfo ? true : false;
a->m_GotInfo != 0;
}

bool CServerBrowser::SortCompareMap(int Index1, int Index2) const
Expand Down Expand Up @@ -282,8 +282,6 @@ void CServerBrowser::Filter()
Filtered = 1;
else if(g_Config.m_BrFilterPw && m_ppServerlist[i]->m_Info.m_Flags & SERVER_FLAG_PASSWORD)
Filtered = 1;
else if(g_Config.m_BrFilterCompatversion && str_comp_num(m_ppServerlist[i]->m_Info.m_aVersion, m_aNetVersion, 3) != 0)
Filtered = 1;
else if(g_Config.m_BrFilterServerAddress[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aAddress, g_Config.m_BrFilterServerAddress))
Filtered = 1;
else if(g_Config.m_BrFilterGametypeStrict && g_Config.m_BrFilterGametype[0] && str_comp_nocase(m_ppServerlist[i]->m_Info.m_aGameType, g_Config.m_BrFilterGametype))
Expand Down Expand Up @@ -397,7 +395,6 @@ int CServerBrowser::SortHash() const
i |= g_Config.m_BrFilterFriends << 7;
i |= g_Config.m_BrFilterPw << 8;
i |= g_Config.m_BrSortOrder << 9;
i |= g_Config.m_BrFilterCompatversion << 11;
i |= g_Config.m_BrFilterGametypeStrict << 12;
i |= g_Config.m_BrFilterUnfinishedMap << 13;
i |= g_Config.m_BrFilterCountry << 14;
Expand Down
2 changes: 1 addition & 1 deletion src/engine/client/serverbrowser.h
Expand Up @@ -229,7 +229,7 @@ class CServerBrowser : public IServerBrowser
static void Con_LeakIpAddress(IConsole::IResult *pResult, void *pUserData);

void SetInfo(CServerEntry *pEntry, const CServerInfo &Info);
void SetLatency(const NETADDR Addr, int Latency);
void SetLatency(NETADDR Addr, int Latency);

static void ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData);
};
Expand Down
6 changes: 1 addition & 5 deletions src/engine/client/serverbrowser_http.cpp
Expand Up @@ -344,11 +344,7 @@ bool ServerbrowserParseUrl(NETADDR *pOut, const char *pUrl)
}
}
str_truncate(aHost, sizeof(aHost), pRest + Start, End - Start);
if(net_addr_from_str(pOut, aHost))
{
return true;
}
return false;
return net_addr_from_str(pOut, aHost) != 0;
}
bool CServerBrowserHttp::Validate(json_value *pJson)
{
Expand Down
34 changes: 13 additions & 21 deletions src/engine/client/text.cpp
Expand Up @@ -977,7 +977,7 @@ class CTextRender : public IEngineTextRender

AppendTextContainer(pCursor, ContainerIndex, pText, Length);

if(TextContainer.m_StringInfo.m_CharacterQuads.size() == 0 && TextContainer.m_StringInfo.m_SelectionQuadContainerIndex == -1 && IsRendered)
if(TextContainer.m_StringInfo.m_CharacterQuads.empty() && TextContainer.m_StringInfo.m_SelectionQuadContainerIndex == -1 && IsRendered)
{
FreeTextContainer(ContainerIndex);
return -1;
Expand Down Expand Up @@ -1087,16 +1087,12 @@ class CTextRender : public IEngineTextRender
int SelectionEndChar = -1;

auto &&CheckInsideChar = [&](bool CheckOuter, int CursorX, int CursorY, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) -> bool {
if((LastCharX - LastCharWidth / 2 <= CursorX &&
CharX + CharWidth / 2 > CursorX &&
CharY - Size <= CursorY &&
CharY > CursorY) ||
(CheckOuter &&
CharY - Size > CursorY))
{
return true;
}
return false;
return (LastCharX - LastCharWidth / 2 <= CursorX &&
CharX + CharWidth / 2 > CursorX &&
CharY - Size <= CursorY &&
CharY > CursorY) ||
(CheckOuter &&
CharY - Size > CursorY);
};
auto &&CheckSelectionStart = [&](bool CheckOuter, int CursorX, int CursorY, int &SelectionChar, bool &SelectionUsedCase, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) {
if(!SelectionStarted && !SelectionUsedCase)
Expand All @@ -1110,15 +1106,11 @@ class CTextRender : public IEngineTextRender
}
};
auto &&CheckOutsideChar = [&](bool CheckOuter, int CursorX, int CursorY, float CharX, float CharWidth, float CharY) -> bool {
if((CharX + CharWidth / 2 > CursorX &&
CharY - Size <= CursorY &&
CharY > CursorY) ||
(CheckOuter &&
CharY <= CursorY))
{
return true;
}
return false;
return (CharX + CharWidth / 2 > CursorX &&
CharY - Size <= CursorY &&
CharY > CursorY) ||
(CheckOuter &&
CharY <= CursorY);
};
auto &&CheckSelectionEnd = [&](bool CheckOuter, int CursorX, int CursorY, int &SelectionChar, bool &SelectionUsedCase, float CharX, float CharWidth, float CharY) {
if(SelectionStarted && !SelectionUsedCase)
Expand Down Expand Up @@ -1402,7 +1394,7 @@ class CTextRender : public IEngineTextRender
GotNewLineLast = 0;
}

if(TextContainer.m_StringInfo.m_CharacterQuads.size() != 0 && IsRendered)
if(!TextContainer.m_StringInfo.m_CharacterQuads.empty() && IsRendered)
{
TextContainer.m_StringInfo.m_QuadNum = TextContainer.m_StringInfo.m_CharacterQuads.size();
// setup the buffers
Expand Down
4 changes: 2 additions & 2 deletions src/engine/client/updater.cpp
Expand Up @@ -93,8 +93,8 @@ CUpdater::CUpdater()
m_Percent = 0;
m_Lock = lock_create();

str_format(m_aClientExecTmp, sizeof(m_aClientExecTmp), CLIENT_EXEC ".%d.tmp", pid());
str_format(m_aServerExecTmp, sizeof(m_aServerExecTmp), SERVER_EXEC ".%d.tmp", pid());
IStorage::FormatTmpPath(m_aClientExecTmp, sizeof(m_aClientExecTmp), CLIENT_EXEC);
IStorage::FormatTmpPath(m_aServerExecTmp, sizeof(m_aServerExecTmp), SERVER_EXEC);
}

void CUpdater::Init()
Expand Down
2 changes: 1 addition & 1 deletion src/engine/client/video.cpp
Expand Up @@ -563,7 +563,7 @@ bool CVideo::OpenAudio()
}

/* Add an output stream. */
bool CVideo::AddStream(OutputStream *pStream, AVFormatContext *pOC, AVCodec **ppCodec, enum AVCodecID CodecId)
bool CVideo::AddStream(OutputStream *pStream, AVFormatContext *pOC, const AVCodec **ppCodec, enum AVCodecID CodecId)
{
AVCodecContext *c;

Expand Down
8 changes: 4 additions & 4 deletions src/engine/client/video.h
Expand Up @@ -75,7 +75,7 @@ class CVideo : public IVideo
void FinishFrames(OutputStream *pStream);
void CloseStream(OutputStream *pStream);

bool AddStream(OutputStream *pStream, AVFormatContext *pOC, AVCodec **ppCodec, enum AVCodecID CodecId);
bool AddStream(OutputStream *pStream, AVFormatContext *pOC, const AVCodec **ppCodec, enum AVCodecID CodecId);

class CGraphics_Threaded *m_pGraphics;
class IStorage *m_pStorage;
Expand Down Expand Up @@ -107,13 +107,13 @@ class CVideo : public IVideo
OutputStream m_VideoStream;
OutputStream m_AudioStream;

AVCodec *m_VideoCodec;
AVCodec *m_AudioCodec;
const AVCodec *m_VideoCodec;
const AVCodec *m_AudioCodec;

AVDictionary *m_pOptDict;

AVFormatContext *m_pFormatContext;
AVOutputFormat *m_pFormat;
const AVOutputFormat *m_pFormat;

uint8_t *m_pRGB;

Expand Down
1 change: 1 addition & 0 deletions src/engine/config.h
Expand Up @@ -13,6 +13,7 @@ class IConfigManager : public IInterface

virtual void Init() = 0;
virtual void Reset() = 0;
virtual void Reset(const char *pScriptName) = 0;
virtual bool Save() = 0;
virtual class CConfig *Values() = 0;

Expand Down
3 changes: 3 additions & 0 deletions src/engine/console.h
Expand Up @@ -9,6 +9,8 @@

static const ColorRGBA gs_ConsoleDefaultColor(1, 1, 1, 1);

struct CChecksumData;

class IConsole : public IInterface
{
MACRO_INTERFACE("console", 0)
Expand Down Expand Up @@ -107,6 +109,7 @@ class IConsole : public IInterface
virtual char *Format(char *pBuf, int Size, const char *pFrom, const char *pStr) = 0;
virtual void Print(int Level, const char *pFrom, const char *pStr, ColorRGBA PrintColor = gs_ConsoleDefaultColor) = 0;
virtual void SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCallback, void *pUser) = 0;
virtual void InitChecksum(CChecksumData *pData) const = 0;

virtual void SetAccessLevel(int AccessLevel) = 0;

Expand Down
5 changes: 3 additions & 2 deletions src/engine/graphics.h
Expand Up @@ -209,12 +209,13 @@ class IGraphics : public IInterface
int WindowWidth() const { return m_ScreenWidth / m_ScreenHiDPIScale; }
int WindowHeight() const { return m_ScreenHeight / m_ScreenHiDPIScale; }

virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0;
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing) = 0;
virtual bool SetWindowScreen(int Index) = 0;
virtual bool SetVSync(bool State) = 0;
virtual int GetWindowScreen() = 0;
virtual void Move(int x, int y) = 0;
virtual void Resize(int w, int h, int RefreshRate, bool SetWindowSize = false, bool ForceResizeEvent = false) = 0;
virtual void Resize(int w, int h, int RefreshRate) = 0;
virtual void GotResized(int w, int h, int RefreshRate) = 0;
virtual void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser) = 0;

virtual void WindowDestroyNtf(uint32_t WindowID) = 0;
Expand Down
3 changes: 1 addition & 2 deletions src/engine/input.h
Expand Up @@ -73,7 +73,7 @@ class IInput : public IInterface
virtual bool NativeMousePressed(int index) = 0;
virtual void MouseModeRelative() = 0;
virtual void MouseModeAbsolute() = 0;
virtual int MouseDoubleClick() = 0;
virtual bool MouseDoubleClick() = 0;
virtual const char *GetClipboardText() = 0;
virtual void SetClipboardText(const char *Text) = 0;

Expand All @@ -93,7 +93,6 @@ class IEngineInput : public IInput
public:
virtual void Init() = 0;
virtual int Update() = 0;
virtual void NextFrame() = 0;
virtual int VideoRestartNeeded() = 0;
};

Expand Down
42 changes: 37 additions & 5 deletions src/engine/server/databases/connection_pool.cpp
Expand Up @@ -54,7 +54,7 @@ CSqlExecData::CSqlExecData(
}

CDbConnectionPool::CDbConnectionPool() :
m_NumElem(),

FirstElem(0),
LastElem(0)
{
Expand Down Expand Up @@ -83,20 +83,20 @@ void CDbConnectionPool::RegisterDatabase(std::unique_ptr<IDbConnection> pDatabas

void CDbConnectionPool::Execute(
FRead pFunc,
std::unique_ptr<const ISqlData> pThreadData,
std::unique_ptr<const ISqlData> pSqlRequestData,
const char *pName)
{
m_aTasks[FirstElem++].reset(new CSqlExecData(pFunc, std::move(pThreadData), pName));
m_aTasks[FirstElem++].reset(new CSqlExecData(pFunc, std::move(pSqlRequestData), pName));
FirstElem %= sizeof(m_aTasks) / sizeof(m_aTasks[0]);
m_NumElem.Signal();
}

void CDbConnectionPool::ExecuteWrite(
FWrite pFunc,
std::unique_ptr<const ISqlData> pThreadData,
std::unique_ptr<const ISqlData> pSqlRequestData,
const char *pName)
{
m_aTasks[FirstElem++].reset(new CSqlExecData(pFunc, std::move(pThreadData), pName));
m_aTasks[FirstElem++].reset(new CSqlExecData(pFunc, std::move(pSqlRequestData), pName));
FirstElem %= sizeof(m_aTasks) / sizeof(m_aTasks[0]);
m_NumElem.Signal();
}
Expand Down Expand Up @@ -127,8 +127,15 @@ void CDbConnectionPool::Worker()
// remember last working server and try to connect to it first
int ReadServer = 0;
int WriteServer = 0;
// enter fail mode when a sql request fails, skip read request during it and
// write to the backup database until all requests are handled
bool FailMode = false;
while(1)
{
if(FailMode && m_NumElem.GetApproximateValue() == 0)
{
FailMode = false;
}
m_NumElem.Wait();
auto pThreadData = std::move(m_aTasks[LastElem++]);
// work through all database jobs after OnShutdown is called before exiting the thread
Expand All @@ -145,6 +152,16 @@ void CDbConnectionPool::Worker()
{
for(int i = 0; i < (int)m_aapDbConnections[Mode::READ].size(); i++)
{
if(m_Shutdown)
{
dbg_msg("sql", "%s dismissed read request during shutdown", pThreadData->m_pName);
break;
}
if(FailMode)
{
dbg_msg("sql", "%s dismissed read request during FailMode", pThreadData->m_pName);
break;
}
int CurServer = (ReadServer + i) % (int)m_aapDbConnections[Mode::READ].size();
if(ExecSqlFunc(m_aapDbConnections[Mode::READ][CurServer].get(), pThreadData.get(), false))
{
Expand All @@ -154,12 +171,26 @@ void CDbConnectionPool::Worker()
break;
}
}
if(!Success)
{
FailMode = true;
}
}
break;
case CSqlExecData::WRITE_ACCESS:
{
for(int i = 0; i < (int)m_aapDbConnections[Mode::WRITE].size(); i++)
{
if(m_Shutdown && !m_aapDbConnections[Mode::WRITE_BACKUP].empty())
{
dbg_msg("sql", "%s skipped to backup database during shutdown", pThreadData->m_pName);
break;
}
if(FailMode && !m_aapDbConnections[Mode::WRITE_BACKUP].empty())
{
dbg_msg("sql", "%s skipped to backup database during FailMode", pThreadData->m_pName);
break;
}
int CurServer = (WriteServer + i) % (int)m_aapDbConnections[Mode::WRITE].size();
if(ExecSqlFunc(m_aapDbConnections[Mode::WRITE][i].get(), pThreadData.get(), false))
{
Expand All @@ -171,6 +202,7 @@ void CDbConnectionPool::Worker()
}
if(!Success)
{
FailMode = true;
for(int i = 0; i < (int)m_aapDbConnections[Mode::WRITE_BACKUP].size(); i++)
{
if(ExecSqlFunc(m_aapDbConnections[Mode::WRITE_BACKUP][i].get(), pThreadData.get(), true))
Expand Down
2 changes: 1 addition & 1 deletion src/engine/server/databases/connection_pool.h
Expand Up @@ -75,7 +75,7 @@ class CDbConnectionPool
void Worker();
bool ExecSqlFunc(IDbConnection *pConnection, struct CSqlExecData *pData, bool Failure);

std::atomic_bool m_Shutdown;
std::atomic_bool m_Shutdown{false};
CSemaphore m_NumElem;
int FirstElem;
int LastElem;
Expand Down
8 changes: 2 additions & 6 deletions src/engine/server/databases/sqlite.cpp
Expand Up @@ -224,7 +224,7 @@ void CSqliteConnection::BindFloat(int Idx, float Value)

// TODO(2020-09-07): remove extern declaration, when all supported systems ship SQLite3 version 3.14 or above
#if defined(__GNUC__)
extern char *sqlite3_expanded_sql(sqlite3_stmt *pStmt) __attribute__((weak));
extern char *sqlite3_expanded_sql(sqlite3_stmt *pStmt) __attribute__((weak)); // NOLINT(readability-redundant-declaration)
#endif

void CSqliteConnection::Print()
Expand Down Expand Up @@ -377,11 +377,7 @@ bool CSqliteConnection::AddPoints(const char *pPlayer, int Points, char *pError,
BindInt(2, Points);
BindInt(3, Points);
bool End;
if(Step(&End, pError, ErrorSize))
{
return true;
}
return false;
return Step(&End, pError, ErrorSize);
}

std::unique_ptr<IDbConnection> CreateSqliteConnection(const char *pFilename, bool Setup)
Expand Down
62 changes: 54 additions & 8 deletions src/engine/server/server.cpp
Expand Up @@ -32,6 +32,8 @@

#include <mastersrv/mastersrv.h>

#include <game/version.h>

// DDRace
#include <engine/shared/linereader.h>
#include <vector>
Expand All @@ -46,6 +48,10 @@
#include <windows.h>
#endif

#include <signal.h>

volatile sig_atomic_t InterruptSignaled = 0;

CSnapIDPool::CSnapIDPool()
{
Reset();
Expand Down Expand Up @@ -93,9 +99,11 @@ int CSnapIDPool::NewID()
RemoveFirstTimeout();

int ID = m_FirstFree;
dbg_assert(ID != -1, "id error");
if(ID == -1)
{
dbg_msg("server", "invalid id");
return ID;
}
m_FirstFree = m_aIDs[m_FirstFree].m_Next;
m_aIDs[ID].m_State = 1;
m_Usage++;
Expand Down Expand Up @@ -298,14 +306,15 @@ CServer::CServer() :

m_aShutdownReason[0] = 0;

for(int i = 0; i < 2; i++)
for(int i = SIX; i <= SIXUP; i++)
{
m_apCurrentMapData[i] = 0;
m_aCurrentMapSize[i] = 0;
}

m_MapReload = false;
m_ReloadedWhenEmpty = false;
m_aCurrentMap[0] = '\0';

m_RconClientID = IServer::RCON_CID_SERV;
m_RconAuthLevel = AUTHED_ADMIN;
Expand Down Expand Up @@ -1151,7 +1160,7 @@ void CServer::SendCapabilities(int ClientID)
{
CMsgPacker Msg(NETMSG_CAPABILITIES, true);
Msg.AddInt(SERVERCAP_CURVERSION); // version
Msg.AddInt(SERVERCAPFLAG_DDNET | SERVERCAPFLAG_CHATTIMEOUTCODE | SERVERCAPFLAG_ANYPLAYERFLAG | SERVERCAPFLAG_PINGEX | SERVERCAPFLAG_ALLOWDUMMY); // flags
Msg.AddInt(SERVERCAPFLAG_DDNET | SERVERCAPFLAG_CHATTIMEOUTCODE | SERVERCAPFLAG_ANYPLAYERFLAG | SERVERCAPFLAG_PINGEX | SERVERCAPFLAG_ALLOWDUMMY | SERVERCAPFLAG_SYNCWEAPONINPUT); // flags
SendMsg(&Msg, MSGFLAG_VITAL, ClientID);
}

Expand Down Expand Up @@ -2298,7 +2307,7 @@ void CServer::ChangeMap(const char *pMap)

int CServer::LoadMap(const char *pMapName)
{
char aBuf[512];
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aBuf, sizeof(aBuf), "maps/%s.map", pMapName);
GameServer()->OnMapChange(aBuf, sizeof(aBuf));

Expand Down Expand Up @@ -2354,8 +2363,9 @@ int CServer::LoadMap(const char *pMapName)
if(!File)
{
Config()->m_SvSixup = 0;
dbg_msg("sixup", "couldn't load map %s", aBuf);
dbg_msg("sixup", "disabling 0.7 compatibility");
str_format(aBufMsg, sizeof(aBufMsg), "couldn't load map %s", aBuf);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "sixup", aBufMsg);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "sixup", "disabling 0.7 compatibility");
}
else
{
Expand All @@ -2372,6 +2382,11 @@ int CServer::LoadMap(const char *pMapName)
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "sixup", aBufMsg);
}
}
if(!Config()->m_SvSixup && m_apCurrentMapData[SIXUP])
{
free(m_apCurrentMapData[SIXUP]);
m_apCurrentMapData[SIXUP] = 0;
}

for(int i = 0; i < MAX_CLIENTS; i++)
m_aPrevStates[i] = m_aClients[i].m_State;
Expand Down Expand Up @@ -2475,8 +2490,13 @@ int CServer::Run()
{
m_RunServer = STOPPING;
}
str_format(aBuf, sizeof(aBuf), "version %s", GameServer()->NetVersion());
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "version " GAME_RELEASE_VERSION " on " CONF_PLATFORM_STRING " " CONF_ARCH_STRING);
if(GIT_SHORTREV_HASH)
{
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "git revision hash: %s", GIT_SHORTREV_HASH);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}

// process pending commands
m_pConsole->StoreCommands(false);
Expand Down Expand Up @@ -2698,6 +2718,11 @@ int CServer::Run()

PacketWaiting = x > 0 ? net_socket_read_wait(m_NetServer.Socket(), x) : true;
}
if(InterruptSignaled)
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "interrupted");
break;
}
}
}
const char *pDisconnectReason = "Server shutdown";
Expand Down Expand Up @@ -3461,6 +3486,14 @@ void CServer::ConchainMapUpdate(IConsole::IResult *pResult, void *pUserData, ICo
}
}

void CServer::ConchainSixupUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
CServer *pThis = static_cast<CServer *>(pUserData);
if(pResult->NumArguments() >= 1 && pThis->m_aCurrentMap[0] != '\0')
pThis->m_MapReload |= (pThis->m_apCurrentMapData[SIXUP] != 0) != (pResult->GetInteger(0) != 0);
}

#if defined(CONF_FAMILY_UNIX)
void CServer::ConchainConnLoggingServerChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
Expand Down Expand Up @@ -3534,6 +3567,7 @@ void CServer::RegisterCommands()
Console()->Chain("sv_rcon_mod_password", ConchainRconModPasswordChange, this);
Console()->Chain("sv_rcon_helper_password", ConchainRconHelperPasswordChange, this);
Console()->Chain("sv_map", ConchainMapUpdate, this);
Console()->Chain("sv_sixup", ConchainSixupUpdate, this);

#if defined(CONF_FAMILY_UNIX)
Console()->Chain("sv_conn_logging_server", ConchainConnLoggingServerChange, this);
Expand Down Expand Up @@ -3571,6 +3605,15 @@ void CServer::SnapSetStaticsize(int ItemType, int Size)

static CServer *CreateServer() { return new CServer(); }

void HandleSigIntTerm(int Param)
{
InterruptSignaled = 1;

// Exit the next time a signal is received
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
}

int main(int argc, const char **argv) // ignore_convention
{
cmdline_fix(&argc, &argv);
Expand Down Expand Up @@ -3599,6 +3642,9 @@ int main(int argc, const char **argv) // ignore_convention
return -1;
}

signal(SIGINT, HandleSigIntTerm);
signal(SIGTERM, HandleSigIntTerm);

CServer *pServer = CreateServer();
IKernel *pKernel = IKernel::Create();

Expand Down
1 change: 1 addition & 0 deletions src/engine/server/server.h
Expand Up @@ -412,6 +412,7 @@ class CServer : public IServer
static void ConchainRconModPasswordChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainRconHelperPasswordChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainMapUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainSixupUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);

#if defined(CONF_FAMILY_UNIX)
static void ConchainConnLoggingServerChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
Expand Down
6 changes: 6 additions & 0 deletions src/engine/server/sql_string_helpers.cpp
Expand Up @@ -42,6 +42,12 @@ int sqlstr::EscapeLike(char *pDst, const char *pSrc, int DstSize)

void sqlstr::AgoTimeToString(int AgoTime, char *pAgoString, int Size)
{
if(AgoTime <= 0)
{
str_copy(pAgoString, "moments", Size);
return;
}

char aBuf[20];
int aTimes[7] =
{
Expand Down
2 changes: 1 addition & 1 deletion src/engine/serverbrowser.h
Expand Up @@ -72,7 +72,7 @@ class CServerInfo
int m_MapSize;
char m_aVersion[32];
char m_aAddress[NETADDR_MAXSTRSIZE];
CClient m_aClients[MAX_CLIENTS];
CClient m_aClients[SERVERINFO_MAX_CLIENTS];
mutable int m_NumFilteredPlayers;

mutable CUIElement *m_pUIElement;
Expand Down
46 changes: 25 additions & 21 deletions src/engine/shared/compression.cpp
Expand Up @@ -8,17 +8,17 @@
unsigned char *CVariableInt::Pack(unsigned char *pDst, int i)
{
*pDst = (i >> 25) & 0x40; // set sign bit if i<0
i = i ^ (i >> 31); // if(i<0) i = ~i
i ^= i >> 31; // if(i<0) i = ~i

*pDst |= i & 0x3F; // pack 6bit into dst
i >>= 6; // discard 6 bits
if(i)
{
*pDst |= 0x80; // set extend bit
while(1)
while(true)
{
pDst++;
*pDst = i & (0x7F); // pack 7bit
*pDst = i & 0x7F; // pack 7bit
i >>= 7; // discard 7 bits
*pDst |= (i != 0) << 7; // set extend bit (may branch)
if(!i)
Expand All @@ -32,66 +32,70 @@ unsigned char *CVariableInt::Pack(unsigned char *pDst, int i)

const unsigned char *CVariableInt::Unpack(const unsigned char *pSrc, int *pInOut)
{
int Sign = (*pSrc >> 6) & 1;
const int Sign = (*pSrc >> 6) & 1;
*pInOut = *pSrc & 0x3F;

do
{
if(!(*pSrc & 0x80))
break;
pSrc++;
*pInOut |= (*pSrc & (0x7F)) << (6);
*pInOut |= (*pSrc & 0x7F) << 6;

if(!(*pSrc & 0x80))
break;
pSrc++;
*pInOut |= (*pSrc & (0x7F)) << (6 + 7);
*pInOut |= (*pSrc & 0x7F) << (6 + 7);

if(!(*pSrc & 0x80))
break;
pSrc++;
*pInOut |= (*pSrc & (0x7F)) << (6 + 7 + 7);
*pInOut |= (*pSrc & 0x7F) << (6 + 7 + 7);

if(!(*pSrc & 0x80))
break;
pSrc++;
*pInOut |= (*pSrc & (0x1F)) << (6 + 7 + 7 + 7);
} while(0);
*pInOut |= (*pSrc & 0x0F) << (6 + 7 + 7 + 7);
} while(false);

pSrc++;
*pInOut ^= -Sign; // if(sign) *i = ~(*i)
return pSrc;
}

long CVariableInt::Decompress(const void *pSrc_, int Size, void *pDst_, int DstSize)
long CVariableInt::Decompress(const void *pSrc_, int SrcSize, void *pDst_, int DstSize)
{
dbg_assert(DstSize % sizeof(int) == 0, "invalid bounds");

const unsigned char *pSrc = (unsigned char *)pSrc_;
const unsigned char *pEnd = pSrc + Size;
const unsigned char *pEnd = pSrc + SrcSize;
int *pDst = (int *)pDst_;
int *pDstEnd = pDst + DstSize / 4;
const int *pDstEnd = pDst + DstSize / sizeof(int);
while(pSrc < pEnd)
{
if(pDst >= pDstEnd)
return -1;
pSrc = CVariableInt::Unpack(pSrc, pDst);
pDst++;
}
return (unsigned char *)pDst - (unsigned char *)pDst_;
return (long)((unsigned char *)pDst - (unsigned char *)pDst_);
}

long CVariableInt::Compress(const void *pSrc_, int Size, void *pDst_, int DstSize)
long CVariableInt::Compress(const void *pSrc_, int SrcSize, void *pDst_, int DstSize)
{
int *pSrc = (int *)pSrc_;
dbg_assert(SrcSize % sizeof(int) == 0, "invalid bounds");

const int *pSrc = (int *)pSrc_;
unsigned char *pDst = (unsigned char *)pDst_;
unsigned char *pDstEnd = pDst + DstSize;
Size /= 4;
while(Size)
const unsigned char *pDstEnd = pDst + DstSize;
SrcSize /= sizeof(int);
while(SrcSize)
{
if(pDstEnd - pDst < 6)
if(pDstEnd - pDst <= MAX_BYTES_PACKED)
return -1;
pDst = CVariableInt::Pack(pDst, *pSrc);
Size--;
SrcSize--;
pSrc++;
}
return pDst - (unsigned char *)pDst_;
return (long)(pDst - (unsigned char *)pDst_);
}
12 changes: 10 additions & 2 deletions src/engine/shared/compression.h
Expand Up @@ -2,13 +2,21 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef ENGINE_SHARED_COMPRESSION_H
#define ENGINE_SHARED_COMPRESSION_H

// variable int packing
class CVariableInt
{
public:
enum
{
MAX_BYTES_PACKED = 5, // maximum number of bytes in a packed int
};

static unsigned char *Pack(unsigned char *pDst, int i);
static const unsigned char *Unpack(const unsigned char *pSrc, int *pInOut);
static long Compress(const void *pSrc, int Size, void *pDst, int DstSize);
static long Decompress(const void *pSrc, int Size, void *pDst, int DstSize);

static long Compress(const void *pSrc, int SrcSize, void *pDst, int DstSize);
static long Decompress(const void *pSrc, int SrcSize, void *pDst, int DstSize);
};

#endif
34 changes: 30 additions & 4 deletions src/engine/shared/config.cpp
Expand Up @@ -39,15 +39,36 @@ void CConfigManager::Reset()
#undef MACRO_CONFIG_STR
}

void CConfigManager::Reset(const char *pScriptName)
{
#define MACRO_CONFIG_INT(Name, ScriptName, def, min, max, flags, desc) \
if(str_comp(pScriptName, #ScriptName) == 0) \
{ \
g_Config.m_##Name = def; \
return; \
};
#define MACRO_CONFIG_COL(Name, ScriptName, def, flags, desc) MACRO_CONFIG_INT(Name, ScriptName, def, 0, 0, flags, desc)
#define MACRO_CONFIG_STR(Name, ScriptName, len, def, flags, desc) \
if(str_comp(pScriptName, #ScriptName) == 0) \
{ \
str_copy(g_Config.m_##Name, def, len); \
return; \
};

#include "config_variables.h"

#undef MACRO_CONFIG_INT
#undef MACRO_CONFIG_COL
#undef MACRO_CONFIG_STR
}

bool CConfigManager::Save()
{
if(!m_pStorage || !g_Config.m_ClSaveSettings)
return true;

char aConfigFileTmp[64];
str_format(aConfigFileTmp, sizeof(aConfigFileTmp), CONFIG_FILE ".%d.tmp", pid());

m_ConfigFile = m_pStorage->OpenFile(aConfigFileTmp, IOFLAG_WRITE, IStorage::TYPE_SAVE);
char aConfigFileTmp[IO_MAX_PATH_LENGTH];
m_ConfigFile = m_pStorage->OpenFile(IStorage::FormatTmpPath(aConfigFileTmp, sizeof(aConfigFileTmp), CONFIG_FILE), IOFLAG_WRITE, IStorage::TYPE_SAVE);

if(!m_ConfigFile)
{
Expand Down Expand Up @@ -89,6 +110,11 @@ bool CConfigManager::Save()
for(int i = 0; i < m_NumCallbacks; i++)
m_aCallbacks[i].m_pfnFunc(this, m_aCallbacks[i].m_pUserData);

if(io_sync(m_ConfigFile) != 0)
{
m_Failed = true;
}

if(io_close(m_ConfigFile) != 0)
m_Failed = true;

Expand Down
2 changes: 2 additions & 0 deletions src/engine/shared/config.h
Expand Up @@ -41,6 +41,7 @@ enum
CFGFLAG_NONTEEHISTORIC = 1 << 9,
CFGFLAG_COLLIGHT = 1 << 10,
CFGFLAG_COLALPHA = 1 << 11,
CFGFLAG_INSENSITIVE = 1 << 12,
};

class CConfigManager : public IConfigManager
Expand All @@ -67,6 +68,7 @@ class CConfigManager : public IConfigManager

virtual void Init();
virtual void Reset();
virtual void Reset(const char *pScriptName);
virtual bool Save();
virtual CConfig *Values() { return &g_Config; }

Expand Down
34 changes: 17 additions & 17 deletions src/engine/shared/config_variables.h
Expand Up @@ -6,9 +6,9 @@
// TODO: remove this
#include "././game/variables.h"

MACRO_CONFIG_STR(PlayerName, player_name, 16, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Name of the player")
MACRO_CONFIG_STR(PlayerClan, player_clan, 12, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Clan of the player")
MACRO_CONFIG_INT(PlayerCountry, player_country, -1, -1, 1000, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Country of the player")
MACRO_CONFIG_STR(PlayerName, player_name, 16, "", CFGFLAG_SAVE | CFGFLAG_CLIENT | CFGFLAG_INSENSITIVE, "Name of the player")
MACRO_CONFIG_STR(PlayerClan, player_clan, 12, "", CFGFLAG_SAVE | CFGFLAG_CLIENT | CFGFLAG_INSENSITIVE, "Clan of the player")
MACRO_CONFIG_INT(PlayerCountry, player_country, -1, -1, 1000, CFGFLAG_SAVE | CFGFLAG_CLIENT | CFGFLAG_INSENSITIVE, "Country of the player")
MACRO_CONFIG_STR(Password, password, 32, "", CFGFLAG_CLIENT | CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC, "Password to the server")
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")
Expand Down Expand Up @@ -56,7 +56,6 @@ MACRO_CONFIG_STR(BrFilterGametype, br_filter_gametype, 128, "", CFGFLAG_SAVE | C
MACRO_CONFIG_INT(BrFilterGametypeStrict, br_filter_gametype_strict, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Strict gametype filter")
MACRO_CONFIG_INT(BrFilterConnectingPlayers, br_filter_connecting_players, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter connecting players")
MACRO_CONFIG_STR(BrFilterServerAddress, br_filter_serveraddress, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Server address to filter")
MACRO_CONFIG_INT(BrFilterCompatversion, br_filter_compatversion, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter out non-compatible servers in browser")
MACRO_CONFIG_INT(BrFilterUnfinishedMap, br_filter_unfinished_map, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Show only servers with unfinished maps")

MACRO_CONFIG_STR(BrFilterExcludeCountries, br_filter_exclude_countries, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter out DDNet servers by country")
Expand All @@ -80,12 +79,12 @@ MACRO_CONFIG_INT(SndBufferSize, snd_buffer_size, 512, 128, 32768, CFGFLAG_SAVE |
MACRO_CONFIG_INT(SndRate, snd_rate, 48000, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sound mixing rate")
MACRO_CONFIG_INT(SndEnable, snd_enable, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sound enable")
MACRO_CONFIG_INT(SndMusic, snd_enable_music, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Play background music")
MACRO_CONFIG_INT(SndVolume, snd_volume, 100, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sound volume")
MACRO_CONFIG_INT(SndVolume, snd_volume, 30, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sound volume")
MACRO_CONFIG_INT(SndDevice, snd_device, -1, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "(deprecated) Sound device to use")
MACRO_CONFIG_INT(SndChatSoundVolume, snd_chat_volume, 100, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Chat sound volume")
MACRO_CONFIG_INT(SndGameSoundVolume, snd_game_volume, 100, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Game sound volume")
MACRO_CONFIG_INT(SndMapSoundVolume, snd_ambient_volume, 70, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Map Sound sound volume")
MACRO_CONFIG_INT(SndBackgroundMusicVolume, snd_background_music_volume, 50, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Background music sound volume")
MACRO_CONFIG_INT(SndChatSoundVolume, snd_chat_volume, 30, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Chat sound volume")
MACRO_CONFIG_INT(SndGameSoundVolume, snd_game_volume, 30, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Game sound volume")
MACRO_CONFIG_INT(SndMapSoundVolume, snd_ambient_volume, 30, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Map Sound sound volume")
MACRO_CONFIG_INT(SndBackgroundMusicVolume, snd_background_music_volume, 30, 0, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Background music sound volume")

MACRO_CONFIG_INT(SndNonactiveMute, snd_nonactive_mute, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(SndGame, snd_game, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enable game sounds")
Expand All @@ -105,10 +104,10 @@ MACRO_CONFIG_INT(GfxDesktopWidth, gfx_desktop_width, 0, 0, 0, CFGFLAG_SAVE | CFG
MACRO_CONFIG_INT(GfxDesktopHeight, gfx_desktop_height, 0, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Desktop resolution height for detecting display changes (not recommended to change manually)")
#if !defined(CONF_PLATFORM_MACOS)
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, 2, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Set fullscreen mode: 0=no fullscreen, 1=pure fullscreen, 2=desktop fullscreen")
MACRO_CONFIG_INT(GfxFullscreen, gfx_fullscreen, 1, 0, 3, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Set fullscreen mode: 0=no fullscreen, 1=pure fullscreen, 2=desktop fullscreen, 3=windowed fullscreen")
#else
MACRO_CONFIG_INT(GfxBorderless, gfx_borderless, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Borderless window (not to be used with fullscreen)")
MACRO_CONFIG_INT(GfxFullscreen, gfx_fullscreen, 0, 0, 2, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Set fullscreen mode: 0=no fullscreen, 1=pure fullscreen, 2=desktop fullscreen")
MACRO_CONFIG_INT(GfxFullscreen, gfx_fullscreen, 0, 0, 3, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Set fullscreen mode: 0=no fullscreen, 1=pure fullscreen, 2=desktop fullscreen, 3=windowed fullscreen")
#endif
MACRO_CONFIG_INT(GfxHighdpi, gfx_highdpi, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enable high-dpi")
MACRO_CONFIG_INT(GfxColorDepth, gfx_color_depth, 24, 16, 24, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Colors bits for framebuffer (fullscreen only)")
Expand All @@ -120,11 +119,7 @@ MACRO_CONFIG_INT(GfxRefreshRate, gfx_refresh_rate, 0, 0, 10000, CFGFLAG_SAVE | C
MACRO_CONFIG_INT(GfxFinish, gfx_finish, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(GfxBackgroundRender, gfx_backgroundrender, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Render graphics when window is in background")
MACRO_CONFIG_INT(GfxTextOverlay, gfx_text_overlay, 10, 1, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Stop rendering textoverlay in editor or with entities: high value = less details = more speed")
#if !defined(CONF_PLATFORM_MACOS)
MACRO_CONFIG_INT(GfxAsyncRenderOld, gfx_asyncrender_old, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Do rendering async from the the update")
#else
MACRO_CONFIG_INT(GfxAsyncRenderOld, gfx_asyncrender_old, 0, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Do rendering async from the the update")
#endif
MACRO_CONFIG_INT(GfxTuneOverlay, gfx_tune_overlay, 20, 1, 100, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Stop rendering text overlay in tuning zone in editor: high value = less details = more speed")
MACRO_CONFIG_INT(GfxQuadAsTriangle, gfx_quad_as_triangle, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Render quads as triangles (fixes quad coloring on some GPUs)")

Expand All @@ -133,6 +128,10 @@ MACRO_CONFIG_INT(InpMouseOld, inp_mouseold, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIE
MACRO_CONFIG_INT(InpTranslatedKeys, inp_translated_keys, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Translate keys before interpreting them, respects keyboard layouts")
MACRO_CONFIG_INT(InpIgnoredModifiers, inp_ignored_modifiers, 0, 0, 65536, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Ignored keyboard modifier mask")

MACRO_CONFIG_INT(ClPort, cl_port, 0, 0, 65535, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Port to use for client connections to server (0 to choose a random port, requires a restart)")
MACRO_CONFIG_INT(ClDummyPort, cl_dummy_port, 0, 0, 65535, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Port to use for dummy connections to server (0 to choose a random port, requires a restart)")
MACRO_CONFIG_INT(ClContactPort, cl_contact_port, 0, 0, 65535, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Port to use for serverinfo connections to server (0 to choose a random port, requires a restart)")

MACRO_CONFIG_STR(SvName, sv_name, 128, "unnamed server", CFGFLAG_SERVER, "Server name")
MACRO_CONFIG_STR(Bindaddr, bindaddr, 128, "", CFGFLAG_CLIENT | CFGFLAG_SERVER | CFGFLAG_MASTER, "Address to bind the client/server to")
MACRO_CONFIG_INT(SvIpv4Only, sv_ipv4only, 0, 0, 1, CFGFLAG_SERVER, "Whether to bind only to ipv4, otherwise bind to all available interfaces")
Expand Down Expand Up @@ -260,7 +259,8 @@ MACRO_CONFIG_STR(SvRulesLine9, sv_rules_line9, 128, "", CFGFLAG_SERVER, "Rules l
MACRO_CONFIG_STR(SvRulesLine10, sv_rules_line10, 128, "", CFGFLAG_SERVER, "Rules line 10")

MACRO_CONFIG_INT(SvTeam, sv_team, 1, 0, 3, CFGFLAG_SERVER | CFGFLAG_GAME, "Teams configuration (0 = off, 1 = on but optional, 2 = must play only with teams, 3 = forced random team only for you)")
MACRO_CONFIG_INT(SvTeamMaxSize, sv_max_team_size, MAX_CLIENTS, 1, MAX_CLIENTS, CFGFLAG_SERVER | CFGFLAG_GAME, "Maximum team size (from 2 to 64)")
MACRO_CONFIG_INT(SvMinTeamSize, sv_min_team_size, 2, 1, MAX_CLIENTS, CFGFLAG_SERVER | CFGFLAG_GAME, "Minimum team size (finishing in a team smaller than this size gives you no teamrank)")
MACRO_CONFIG_INT(SvMaxTeamSize, sv_max_team_size, MAX_CLIENTS, 1, MAX_CLIENTS, CFGFLAG_SERVER | CFGFLAG_GAME, "Maximum team size")
MACRO_CONFIG_INT(SvMapVote, sv_map_vote, 1, 0, 1, CFGFLAG_SERVER, "Whether to allow /map")

MACRO_CONFIG_STR(SvAnnouncementFileName, sv_announcement_filename, 24, "announcement.txt", CFGFLAG_SERVER, "file which will have the announcement, each one at a line")
Expand Down Expand Up @@ -311,7 +311,7 @@ MACRO_CONFIG_INT(ClZoomBackgroundLayers, cl_zoom_background_layers, 0, 0, 1, CFG
MACRO_CONFIG_COL(ClBackgroundColor, cl_background_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background color") //0 0 128
MACRO_CONFIG_COL(ClBackgroundEntitiesColor, cl_background_entities_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities) color") //0 0 128
MACRO_CONFIG_STR(ClBackgroundEntities, cl_background_entities, 100, "", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities)")
MACRO_CONFIG_STR(ClRunOnJoin, cl_run_on_join, 100, "", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Command to run when joining a server")
MACRO_CONFIG_STR(ClRunOnJoin, cl_run_on_join, 100, "", CFGFLAG_CLIENT | CFGFLAG_SAVE | CFGFLAG_INSENSITIVE, "Command to run when joining a server")

// menu background map
MACRO_CONFIG_STR(ClMenuMap, cl_menu_map, 100, "auto", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background map in the menu")
Expand Down
24 changes: 24 additions & 0 deletions src/engine/shared/console.cpp
Expand Up @@ -7,6 +7,7 @@
#include <base/system.h>
#include <base/vmath.h>

#include <engine/client/checksum.h>
#include <engine/shared/protocol.h>
#include <engine/storage.h>

Expand Down Expand Up @@ -342,6 +343,29 @@ void CConsole::SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCa
m_pTeeHistorianCommandUserdata = pUser;
}

void CConsole::InitChecksum(CChecksumData *pData) const
{
pData->m_NumCommands = 0;
for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
{
if(pData->m_NumCommands < (int)(sizeof(pData->m_aCommandsChecksum) / sizeof(pData->m_aCommandsChecksum[0])))
{
FCommandCallback pfnCallback = pCommand->m_pfnCallback;
void *pUserData = pCommand->m_pUserData;
while(pfnCallback == Con_Chain)
{
CChain *pChainInfo = static_cast<CChain *>(pUserData);
pfnCallback = pChainInfo->m_pfnCallback;
pUserData = pChainInfo->m_pCallbackUserData;
}
int CallbackBits = (uintptr_t)pfnCallback & 0xfff;
int *pTarget = &pData->m_aCommandsChecksum[pData->m_NumCommands];
*pTarget = ((uint8_t)pCommand->m_pName[0]) | ((uint8_t)pCommand->m_pName[1] << 8) | (CallbackBits << 16);
}
pData->m_NumCommands += 1;
}
}

bool CConsole::LineIsValid(const char *pStr)
{
if(!pStr || *pStr == 0)
Expand Down
5 changes: 3 additions & 2 deletions src/engine/shared/console.h
Expand Up @@ -89,8 +89,8 @@ class CConsole : public IConsole
const char *m_pCommand;
const char *m_apArgs[MAX_PARTS];

CResult() :
IResult()
CResult()

{
mem_zero(m_aStringStorage, sizeof(m_aStringStorage));
m_pArgsStart = 0;
Expand Down Expand Up @@ -222,6 +222,7 @@ class CConsole : public IConsole
virtual char *Format(char *pBuf, int Size, const char *pFrom, const char *pStr);
virtual void Print(int Level, const char *pFrom, const char *pStr, ColorRGBA PrintColor = gs_ConsoleDefaultColor);
virtual void SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCallback, void *pUser);
virtual void InitChecksum(CChecksumData *pData) const;

void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_USER)); }
void ResetServerGameSettings();
Expand Down
43 changes: 20 additions & 23 deletions src/engine/shared/filecollection.cpp
Expand Up @@ -29,29 +29,26 @@ bool CFileCollection::IsFilenameValid(const char *pFilename)
pFilename += m_FileDescLength;
}

if(pFilename[0] == '_' &&
pFilename[1] >= '0' && pFilename[1] <= '9' &&
pFilename[2] >= '0' && pFilename[2] <= '9' &&
pFilename[3] >= '0' && pFilename[3] <= '9' &&
pFilename[4] >= '0' && pFilename[4] <= '9' &&
pFilename[5] == '-' &&
pFilename[6] >= '0' && pFilename[6] <= '9' &&
pFilename[7] >= '0' && pFilename[7] <= '9' &&
pFilename[8] == '-' &&
pFilename[9] >= '0' && pFilename[9] <= '9' &&
pFilename[10] >= '0' && pFilename[10] <= '9' &&
pFilename[11] == '_' &&
pFilename[12] >= '0' && pFilename[12] <= '9' &&
pFilename[13] >= '0' && pFilename[13] <= '9' &&
pFilename[14] == '-' &&
pFilename[15] >= '0' && pFilename[15] <= '9' &&
pFilename[16] >= '0' && pFilename[16] <= '9' &&
pFilename[17] == '-' &&
pFilename[18] >= '0' && pFilename[18] <= '9' &&
pFilename[19] >= '0' && pFilename[19] <= '9')
return true;

return false;
return pFilename[0] == '_' &&
pFilename[1] >= '0' && pFilename[1] <= '9' &&
pFilename[2] >= '0' && pFilename[2] <= '9' &&
pFilename[3] >= '0' && pFilename[3] <= '9' &&
pFilename[4] >= '0' && pFilename[4] <= '9' &&
pFilename[5] == '-' &&
pFilename[6] >= '0' && pFilename[6] <= '9' &&
pFilename[7] >= '0' && pFilename[7] <= '9' &&
pFilename[8] == '-' &&
pFilename[9] >= '0' && pFilename[9] <= '9' &&
pFilename[10] >= '0' && pFilename[10] <= '9' &&
pFilename[11] == '_' &&
pFilename[12] >= '0' && pFilename[12] <= '9' &&
pFilename[13] >= '0' && pFilename[13] <= '9' &&
pFilename[14] == '-' &&
pFilename[15] >= '0' && pFilename[15] <= '9' &&
pFilename[16] >= '0' && pFilename[16] <= '9' &&
pFilename[17] == '-' &&
pFilename[18] >= '0' && pFilename[18] <= '9' &&
pFilename[19] >= '0' && pFilename[19] <= '9';
}

int64_t CFileCollection::ExtractTimestamp(const char *pTimestring)
Expand Down
2 changes: 1 addition & 1 deletion src/engine/shared/image_manipulation.h
Expand Up @@ -10,7 +10,7 @@ void DilateImage(unsigned char *pImageBuff, int w, int h, int BPP);
void DilateImageSub(unsigned char *pImageBuff, int w, int h, int BPP, int x, int y, int sw, int sh);

// returned pointer is allocated with malloc
uint8_t *ResizeImage(const uint8_t *pImgData, int Width, int Height, int NewWidth, int NewHeight, int BPP);
uint8_t *ResizeImage(const uint8_t *pImageData, int Width, int Height, int NewWidth, int NewHeight, int BPP);

int HighestBit(int OfVar);

Expand Down
2 changes: 1 addition & 1 deletion src/engine/shared/netban.h
Expand Up @@ -181,7 +181,7 @@ class CNetBan
int UnbanByRange(const CNetRange *pRange);
int UnbanByIndex(int Index);
void UnbanAll();
bool IsBanned(const NETADDR *pAddr, char *pBuf, unsigned BufferSize) const;
bool IsBanned(const NETADDR *pOrigAddr, char *pBuf, unsigned BufferSize) const;

static void ConBan(class IConsole::IResult *pResult, void *pUser);
static void ConBanRange(class IConsole::IResult *pResult, void *pUser);
Expand Down
2 changes: 1 addition & 1 deletion src/engine/shared/network.h
Expand Up @@ -455,7 +455,7 @@ class CNetClient
// error and state
int NetType() const { return m_Socket.type; }
int State();
int GotProblems() const;
int GotProblems(int64_t MaxLatency) const;
const char *ErrorString() const;

bool SecurityTokenUnknown() { return m_Connection.SecurityToken() == NET_SECURITY_TOKEN_UNKNOWN; }
Expand Down
4 changes: 2 additions & 2 deletions src/engine/shared/network_client.cpp
Expand Up @@ -143,9 +143,9 @@ int CNetClient::Flush()
return m_Connection.Flush();
}

int CNetClient::GotProblems() const
int CNetClient::GotProblems(int64_t MaxLatency) const
{
if(time_get() - m_Connection.LastRecvTime() > time_freq())
if(time_get() - m_Connection.LastRecvTime() > MaxLatency)
return 1;
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/engine/shared/packer.cpp
Expand Up @@ -19,7 +19,7 @@ void CPacker::AddInt(int i)
return;

// make sure that we have space enough
if(m_pEnd - m_pCurrent < 6)
if(m_pEnd - m_pCurrent <= CVariableInt::MAX_BYTES_PACKED)
{
dbg_break();
m_Error = 1;
Expand Down
1 change: 1 addition & 0 deletions src/engine/shared/protocol.h
Expand Up @@ -82,6 +82,7 @@ enum
SERVERINFO_LEVEL_MIN = 0,
SERVERINFO_LEVEL_MAX = 2,

SERVERINFO_MAX_CLIENTS = 128,
MAX_CLIENTS = 64,
VANILLA_MAX_CLIENTS = 16,

Expand Down
3 changes: 2 additions & 1 deletion src/engine/shared/protocol_ex.h
Expand Up @@ -20,12 +20,13 @@ enum
UNPACKMESSAGE_OK,
UNPACKMESSAGE_ANSWER,

SERVERCAP_CURVERSION = 4,
SERVERCAP_CURVERSION = 5,
SERVERCAPFLAG_DDNET = 1 << 0,
SERVERCAPFLAG_CHATTIMEOUTCODE = 1 << 1,
SERVERCAPFLAG_ANYPLAYERFLAG = 1 << 2,
SERVERCAPFLAG_PINGEX = 1 << 3,
SERVERCAPFLAG_ALLOWDUMMY = 1 << 4,
SERVERCAPFLAG_SYNCWEAPONINPUT = 1 << 5,
};

void RegisterUuids(class CUuidManager *pManager);
Expand Down
3 changes: 3 additions & 0 deletions src/engine/shared/protocol_ex_msgs.h
Expand Up @@ -29,3 +29,6 @@ UUID(NETMSG_CAPABILITIES, "capabilities@ddnet.tw")
UUID(NETMSG_CLIENTVER, "clientver@ddnet.tw")
UUID(NETMSG_PINGEX, "ping@ddnet.tw")
UUID(NETMSG_PONGEX, "pong@ddnet.tw")
UUID(NETMSG_CHECKSUM_REQUEST, "checksum-request@ddnet.tw")
UUID(NETMSG_CHECKSUM_RESPONSE, "checksum-response@ddnet.tw")
UUID(NETMSG_CHECKSUM_ERROR, "checksum-error@ddnet.tw")
6 changes: 3 additions & 3 deletions src/engine/shared/serverinfo.cpp
Expand Up @@ -108,7 +108,7 @@ bool CServerInfo2::FromJsonRaw(CServerInfo2 *pOut, const json_value *pJson)
{
return true;
}
if(i < MAX_CLIENTS)
if(i < SERVERINFO_MAX_CLIENTS)
{
CClient *pClient = &pOut->m_aClients[i];
str_copy(pClient->m_aName, Name, sizeof(pClient->m_aName));
Expand Down Expand Up @@ -173,7 +173,7 @@ CServerInfo2::operator CServerInfo() const
str_copy(Result.m_aMap, m_aMapName, sizeof(Result.m_aMap));
str_copy(Result.m_aVersion, m_aVersion, sizeof(Result.m_aVersion));

for(int i = 0; i < minimum(m_NumClients, (int)MAX_CLIENTS); i++)
for(int i = 0; i < minimum(m_NumClients, (int)SERVERINFO_MAX_CLIENTS); i++)
{
str_copy(Result.m_aClients[i].m_aName, m_aClients[i].m_aName, sizeof(Result.m_aClients[i].m_aName));
str_copy(Result.m_aClients[i].m_aClan, m_aClients[i].m_aClan, sizeof(Result.m_aClients[i].m_aClan));
Expand All @@ -182,7 +182,7 @@ CServerInfo2::operator CServerInfo() const
Result.m_aClients[i].m_Player = m_aClients[i].m_IsPlayer;
}

Result.m_NumReceivedClients = minimum(m_NumClients, (int)MAX_CLIENTS);
Result.m_NumReceivedClients = minimum(m_NumClients, (int)SERVERINFO_MAX_CLIENTS);
Result.m_Latency = -1;

return Result;
Expand Down
2 changes: 1 addition & 1 deletion src/engine/shared/serverinfo.h
Expand Up @@ -20,7 +20,7 @@ class CServerInfo2
bool m_IsPlayer;
};

CClient m_aClients[MAX_CLIENTS];
CClient m_aClients[SERVERINFO_MAX_CLIENTS];
int m_MaxClients;
int m_NumClients; // Indirectly serialized.
int m_MaxPlayers;
Expand Down
140 changes: 54 additions & 86 deletions src/engine/shared/snapshot.cpp
Expand Up @@ -175,19 +175,19 @@ int CSnapshotDelta::DiffItem(int *pPast, int *pCurrent, int *pOut, int Size)
return Needed;
}

void CSnapshotDelta::UndiffItem(int *pPast, int *pDiff, int *pOut, int Size)
void CSnapshotDelta::UndiffItem(int *pPast, int *pDiff, int *pOut, int Size, int *pDataRate)
{
while(Size)
{
*pOut = *pPast + *pDiff;

if(*pDiff == 0)
m_aSnapshotDataRate[m_SnapshotCurrent] += 1;
*pDataRate += 1;
else
{
unsigned char aBuf[16];
unsigned char aBuf[CVariableInt::MAX_BYTES_PACKED];
unsigned char *pEnd = CVariableInt::Pack(aBuf, *pDiff);
m_aSnapshotDataRate[m_SnapshotCurrent] += (int)(pEnd - (unsigned char *)aBuf) * 8;
*pDataRate += (int)(pEnd - (unsigned char *)aBuf) * 8;
}

pOut++;
Expand All @@ -202,7 +202,6 @@ CSnapshotDelta::CSnapshotDelta()
mem_zero(m_aItemSizes, sizeof(m_aItemSizes));
mem_zero(m_aSnapshotDataRate, sizeof(m_aSnapshotDataRate));
mem_zero(m_aSnapshotDataUpdates, sizeof(m_aSnapshotDataUpdates));
m_SnapshotCurrent = 0;
mem_zero(&m_Empty, sizeof(m_Empty));
}

Expand All @@ -211,8 +210,7 @@ CSnapshotDelta::CSnapshotDelta(const CSnapshotDelta &Old)
mem_copy(m_aItemSizes, Old.m_aItemSizes, sizeof(m_aItemSizes));
mem_copy(m_aSnapshotDataRate, Old.m_aSnapshotDataRate, sizeof(m_aSnapshotDataRate));
mem_copy(m_aSnapshotDataUpdates, Old.m_aSnapshotDataUpdates, sizeof(m_aSnapshotDataUpdates));
mem_copy(&m_SnapshotCurrent, &Old.m_SnapshotCurrent, sizeof(m_SnapshotCurrent));
mem_copy(&m_Empty, &Old.m_Empty, sizeof(m_Empty));
mem_zero(&m_Empty, sizeof(m_Empty));
}

void CSnapshotDelta::SetStaticsize(int ItemType, int Size)
Expand All @@ -222,7 +220,7 @@ void CSnapshotDelta::SetStaticsize(int ItemType, int Size)
m_aItemSizes[ItemType] = Size;
}

CSnapshotDelta::CData *CSnapshotDelta::EmptyDelta()
const CSnapshotDelta::CData *CSnapshotDelta::EmptyDelta() const
{
return &m_Empty;
}
Expand All @@ -232,11 +230,6 @@ int CSnapshotDelta::CreateDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pDstData
{
CData *pDelta = (CData *)pDstData;
int *pData = (int *)pDelta->m_aData;
int i, ItemSize, PastIndex;
CSnapshotItem *pFromItem;
CSnapshotItem *pCurItem;
CSnapshotItem *pPastItem;
int Count = 0;

pDelta->m_NumDeletedItems = 0;
pDelta->m_NumUpdateItems = 0;
Expand All @@ -246,9 +239,9 @@ int CSnapshotDelta::CreateDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pDstData
GenerateHash(aHashlist, pTo);

// pack deleted stuff
for(i = 0; i < pFrom->NumItems(); i++)
for(int i = 0; i < pFrom->NumItems(); i++)
{
pFromItem = pFrom->GetItem(i);
const CSnapshotItem *pFromItem = pFrom->GetItem(i);
if(GetItemIndexHashed(pFromItem->Key(), aHashlist) == -1)
{
// deleted
Expand All @@ -259,31 +252,30 @@ int CSnapshotDelta::CreateDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pDstData
}

GenerateHash(aHashlist, pFrom);
int aPastIndices[1024];

// fetch previous indices
// we do this as a separate pass because it helps the cache
int aPastIndices[CSnapshot::MAX_ITEMS];
const int NumItems = pTo->NumItems();
for(i = 0; i < NumItems; i++)
for(int i = 0; i < NumItems; i++)
{
pCurItem = pTo->GetItem(i); // O(1) .. O(n)
const CSnapshotItem *pCurItem = pTo->GetItem(i); // O(1) .. O(n)
aPastIndices[i] = GetItemIndexHashed(pCurItem->Key(), aHashlist); // O(n) .. O(n^n)
}

for(i = 0; i < NumItems; i++)
for(int i = 0; i < NumItems; i++)
{
// do delta
ItemSize = pTo->GetItemSize(i); // O(1) .. O(n)
pCurItem = pTo->GetItem(i); // O(1) .. O(n)
PastIndex = aPastIndices[i];

bool IncludeSize = pCurItem->Type() >= MAX_NETOBJSIZES || !m_aItemSizes[pCurItem->Type()];
const int ItemSize = pTo->GetItemSize(i); // O(1) .. O(n)
CSnapshotItem *pCurItem = pTo->GetItem(i); // O(1) .. O(n)
const int PastIndex = aPastIndices[i];
const bool IncludeSize = pCurItem->Type() >= MAX_NETOBJSIZES || !m_aItemSizes[pCurItem->Type()];

if(PastIndex != -1)
{
int *pItemDataDst = pData + 3;

pPastItem = pFrom->GetItem(PastIndex);
CSnapshotItem *pPastItem = pFrom->GetItem(PastIndex);

if(!IncludeSize)
pItemDataDst = pData + 2;
Expand All @@ -308,29 +300,9 @@ int CSnapshotDelta::CreateDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pDstData
mem_copy(pData, pCurItem->Data(), ItemSize);
pData += ItemSize / 4;
pDelta->m_NumUpdateItems++;
Count++;
}
}

if(0)
{
dbg_msg("snapshot", "%d %d %d",
pDelta->m_NumDeletedItems,
pDelta->m_NumUpdateItems,
pDelta->m_NumTempItems);
}

/*
// TODO: pack temp stuff

// finish
//mem_copy(pDelta->offsets, deleted, pDelta->num_deleted_items*sizeof(int));
//mem_copy(&(pDelta->offsets[pDelta->num_deleted_items]), update, pDelta->num_update_items*sizeof(int));
//mem_copy(&(pDelta->offsets[pDelta->num_deleted_items+pDelta->num_update_items]), temp, pDelta->num_temp_items*sizeof(int));
//mem_copy(pDelta->data_start(), data, data_size);
//pDelta->data_size = data_size;
* */

if(!pDelta->m_NumDeletedItems && !pDelta->m_NumUpdateItems && !pDelta->m_NumTempItems)
return 0;

Expand All @@ -344,40 +316,34 @@ static int RangeCheck(void *pEnd, void *pPtr, int Size)
return 0;
}

int CSnapshotDelta::UnpackDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pSrcData, int DataSize)
int CSnapshotDelta::UnpackDelta(CSnapshot *pFrom, CSnapshot *pTo, const void *pSrcData, int DataSize)
{
CSnapshotBuilder Builder;
CData *pDelta = (CData *)pSrcData;
int *pData = (int *)pDelta->m_aData;
int *pEnd = (int *)(((char *)pSrcData + DataSize));

CSnapshotItem *pFromItem;
int Keep, ItemSize;
int *pDeleted;
int ID, Type, Key;
int FromIndex;
int *pNewData;

CSnapshotBuilder Builder;
Builder.Init();

// unpack deleted stuff
pDeleted = pData;
int *pDeleted = pData;
if(pDelta->m_NumDeletedItems < 0)
return -1;
pData += pDelta->m_NumDeletedItems;
if(pData > pEnd)
return -1;

// copy all non deleted stuff
for(int i = 0; i < pFrom->NumItems(); i++)
{
// dbg_assert(0, "fail!");
pFromItem = pFrom->GetItem(i);
ItemSize = pFrom->GetItemSize(i);
Keep = 1;
CSnapshotItem *pFromItem = pFrom->GetItem(i);
const int ItemSize = pFrom->GetItemSize(i);
bool Keep = true;
for(int d = 0; d < pDelta->m_NumDeletedItems; d++)
{
if(pDeleted[d] == pFromItem->Key())
{
Keep = 0;
Keep = false;
break;
}
}
Expand All @@ -399,10 +365,15 @@ int CSnapshotDelta::UnpackDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pSrcData
if(pData + 2 > pEnd)
return -1;

Type = *pData++;
if(Type < 0)
return -1;
ID = *pData++;
const int Type = *pData++;
if(Type < 0 || Type > CSnapshot::MAX_TYPE)
return -3;

const int ID = *pData++;
if(ID < 0 || ID > CSnapshot::MAX_ID)
return -3;

int ItemSize;
if(Type < MAX_NETOBJSIZES && m_aItemSizes[Type])
ItemSize = m_aItemSizes[Type];
else
Expand All @@ -411,36 +382,32 @@ int CSnapshotDelta::UnpackDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pSrcData
return -2;
ItemSize = (*pData++) * 4;
}
m_SnapshotCurrent = Type;

if(m_SnapshotCurrent < 0 || m_SnapshotCurrent > 0xFFFF)
return -3;
if(RangeCheck(pEnd, pData, ItemSize) || ItemSize < 0)
if(ItemSize < 0 || RangeCheck(pEnd, pData, ItemSize))
return -3;

Key = (Type << 16) | ID;
const int Key = (Type << 16) | ID;

// create the item if needed
pNewData = Builder.GetItemData(Key);
int *pNewData = Builder.GetItemData(Key);
if(!pNewData)
pNewData = (int *)Builder.NewItem(Key >> 16, Key & 0xffff, ItemSize);
pNewData = (int *)Builder.NewItem(Type, ID, ItemSize);

if(!pNewData)
return -4;

FromIndex = pFrom->GetItemIndex(Key);
const int FromIndex = pFrom->GetItemIndex(Key);
if(FromIndex != -1)
{
// we got an update so we need pTo apply the diff
UndiffItem(pFrom->GetItem(FromIndex)->Data(), pData, pNewData, ItemSize / 4);
m_aSnapshotDataUpdates[m_SnapshotCurrent]++;
// we got an update so we need to apply the diff
UndiffItem(pFrom->GetItem(FromIndex)->Data(), pData, pNewData, ItemSize / 4, &m_aSnapshotDataRate[Type]);
}
else // no previous, just copy the pData
{
mem_copy(pNewData, pData, ItemSize);
m_aSnapshotDataRate[m_SnapshotCurrent] += ItemSize * 8;
m_aSnapshotDataUpdates[m_SnapshotCurrent]++;
m_aSnapshotDataRate[Type] += ItemSize * 8;
}
m_aSnapshotDataUpdates[Type]++;

pData += ItemSize / 4;
}
Expand All @@ -460,11 +427,10 @@ void CSnapshotStorage::Init()
void CSnapshotStorage::PurgeAll()
{
CHolder *pHolder = m_pFirst;
CHolder *pNext;

while(pHolder)
{
pNext = pHolder->m_pNext;
CHolder *pNext = pHolder->m_pNext;
free(pHolder);
pHolder = pNext;
}
Expand All @@ -477,11 +443,10 @@ void CSnapshotStorage::PurgeAll()
void CSnapshotStorage::PurgeUntil(int Tick)
{
CHolder *pHolder = m_pFirst;
CHolder *pNext;

while(pHolder)
{
pNext = pHolder->m_pNext;
CHolder *pNext = pHolder->m_pNext;
if(pHolder->m_Tick >= Tick)
return; // no more to remove
free(pHolder);
Expand Down Expand Up @@ -584,8 +549,7 @@ CSnapshotItem *CSnapshotBuilder::GetItem(int Index)

int *CSnapshotBuilder::GetItemData(int Key)
{
int i;
for(i = 0; i < m_NumItems; i++)
for(int i = 0; i < m_NumItems; i++)
{
if(GetItem(i)->Key() == Key)
return GetItem(i)->Data();
Expand All @@ -595,7 +559,6 @@ int *CSnapshotBuilder::GetItemData(int Key)

int CSnapshotBuilder::Finish(void *pSnapData)
{
//dbg_msg("snap", "---------------------------");
// flattern and make the snapshot
CSnapshot *pSnap = (CSnapshot *)pSnapData;
int OffsetSize = sizeof(int) * m_NumItems;
Expand Down Expand Up @@ -642,11 +605,16 @@ int CSnapshotBuilder::GetExtendedItemTypeIndex(int TypeID)

void *CSnapshotBuilder::NewItem(int Type, int ID, int Size)
{
if(ID == -1)
{
return 0;
}

if(m_DataSize + sizeof(CSnapshotItem) + Size >= CSnapshot::MAX_SIZE ||
m_NumItems + 1 >= MAX_ITEMS)
m_NumItems + 1 >= CSnapshot::MAX_ITEMS)
{
dbg_assert(m_DataSize < CSnapshot::MAX_SIZE, "too much data");
dbg_assert(m_NumItems < MAX_ITEMS, "too many items");
dbg_assert(m_NumItems < CSnapshot::MAX_ITEMS, "too many items");
return 0;
}

Expand Down
23 changes: 11 additions & 12 deletions src/engine/shared/snapshot.h
Expand Up @@ -32,6 +32,8 @@ class CSnapshot
{
OFFSET_UUID_TYPE = 0x4000,
MAX_TYPE = 0x7fff,
MAX_ID = 0xffff,
MAX_ITEMS = 1024,
MAX_PARTS = 64,
MAX_SIZE = MAX_PARTS * 1024
};
Expand All @@ -50,7 +52,6 @@ class CSnapshot

unsigned Crc();
void DebugDump();
static void RemoveExtraInfo(unsigned char *pData);
};

// CSnapshotDelta
Expand All @@ -73,23 +74,22 @@ class CSnapshotDelta
MAX_NETOBJSIZES = 64
};
short m_aItemSizes[MAX_NETOBJSIZES];
int m_aSnapshotDataRate[0xffff];
int m_aSnapshotDataUpdates[0xffff];
int m_SnapshotCurrent;
int m_aSnapshotDataRate[CSnapshot::MAX_TYPE + 1];
int m_aSnapshotDataUpdates[CSnapshot::MAX_TYPE + 1];
CData m_Empty;

void UndiffItem(int *pPast, int *pDiff, int *pOut, int Size);
static void UndiffItem(int *pPast, int *pDiff, int *pOut, int Size, int *pDataRate);

public:
static int DiffItem(int *pPast, int *pCurrent, int *pOut, int Size);
CSnapshotDelta();
CSnapshotDelta(const CSnapshotDelta &Old);
int GetDataRate(int Index) { return m_aSnapshotDataRate[Index]; }
int GetDataUpdates(int Index) { return m_aSnapshotDataUpdates[Index]; }
int GetDataRate(int Index) const { return m_aSnapshotDataRate[Index]; }
int GetDataUpdates(int Index) const { return m_aSnapshotDataUpdates[Index]; }
void SetStaticsize(int ItemType, int Size);
CData *EmptyDelta();
int CreateDelta(class CSnapshot *pFrom, class CSnapshot *pTo, void *pData);
int UnpackDelta(class CSnapshot *pFrom, class CSnapshot *pTo, void *pData, int DataSize);
const CData *EmptyDelta() const;
int CreateDelta(class CSnapshot *pFrom, class CSnapshot *pTo, void *pDstData);
int UnpackDelta(class CSnapshot *pFrom, class CSnapshot *pTo, const void *pSrcData, int DataSize);
};

// CSnapshotStorage
Expand Down Expand Up @@ -127,14 +127,13 @@ class CSnapshotBuilder
{
enum
{
MAX_ITEMS = 1024,
MAX_EXTENDED_ITEM_TYPES = 64,
};

char m_aData[CSnapshot::MAX_SIZE];
int m_DataSize;

int m_aOffsets[MAX_ITEMS];
int m_aOffsets[CSnapshot::MAX_ITEMS];
int m_NumItems;

int m_aExtendedItemTypes[MAX_EXTENDED_ITEM_TYPES];
Expand Down
6 changes: 6 additions & 0 deletions src/engine/shared/storage.cpp
Expand Up @@ -594,6 +594,12 @@ void IStorage::StripPathAndExtension(const char *pFilename, char *pBuffer, int B
str_copy(pBuffer, pExtractedName, Length);
}

const char *IStorage::FormatTmpPath(char *aBuf, unsigned BufSize, const char *pPath)
{
str_format(aBuf, BufSize, "%s.%d.tmp", pPath, pid());
return aBuf;
}

IStorage *CreateStorage(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments)
{
return CStorage::Create(pApplicationName, StorageType, NumArgs, ppArguments);
Expand Down
1 change: 1 addition & 0 deletions src/engine/storage.h
Expand Up @@ -39,6 +39,7 @@ class IStorage : public IInterface
virtual const char *GetBinaryPath(const char *pFilename, char *pBuffer, unsigned BufferSize) = 0;

static void StripPathAndExtension(const char *pFilename, char *pBuffer, int BufferSize);
static const char *FormatTmpPath(char *aBuf, unsigned BufSize, const char *pPath);
};

extern IStorage *CreateStorage(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments);
Expand Down
7 changes: 7 additions & 0 deletions src/engine/textrender.h
Expand Up @@ -15,6 +15,13 @@ enum
TEXTFLAG_STOP_AT_END = 4
};

enum ETextAlignment
{
TEXTALIGN_LEFT = 1 << 0,
TEXTALIGN_CENTER = 1 << 1,
TEXTALIGN_RIGHT = 1 << 2,
};

enum ETextRenderFlags
{
TEXT_RENDER_FLAG_NO_X_BEARING = 1 << 0,
Expand Down
2 changes: 1 addition & 1 deletion src/game/client/animstate.h
Expand Up @@ -18,7 +18,7 @@ class CAnimState
CAnimKeyframe *GetFrontFoot() { return &m_FrontFoot; };
CAnimKeyframe *GetAttach() { return &m_Attach; };
void Set(CAnimation *pAnim, float Time);
void Add(CAnimation *pAdded, float Time, float Amount);
void Add(CAnimation *pAnim, float Time, float Amount);

static CAnimState *GetIdle();
};
Expand Down
9 changes: 9 additions & 0 deletions src/game/client/component.h
Expand Up @@ -134,6 +134,10 @@ class CComponent
* The component virtual destructor.
*/
virtual ~CComponent() {}
/**
* Gets the size of the non-abstract component.
*/
virtual int Sizeof() const = 0;
/**
* Get a pointer to the game client.
*/
Expand All @@ -158,6 +162,11 @@ class CComponent
* Called to let the components run initialization code.
*/
virtual void OnInit(){};
/**
* Called to cleanup the component.
* This method is called when the client is closed.
*/
virtual void OnShutdown(){};
/**
* Called to reset the component.
* This method is usually called on your component constructor to avoid code duplication.
Expand Down
1 change: 0 additions & 1 deletion src/game/client/components/background.cpp
Expand Up @@ -78,7 +78,6 @@ void CBackground::LoadBackground()
else if(m_pMap->Load(aBuf))
{
m_pLayers->InitBackground(m_pMap);
RenderTools()->RenderTilemapGenerateSkip(m_pLayers);
NeedImageLoading = true;
m_Loaded = true;
}
Expand Down
7 changes: 4 additions & 3 deletions src/game/client/components/background.h
Expand Up @@ -32,10 +32,11 @@ class CBackground : public CMapLayers
public:
CBackground(int MapType = CMapLayers::TYPE_BACKGROUND_FORCE, bool OnlineOnly = true);
virtual ~CBackground();
virtual int Sizeof() const override { return sizeof(*this); }

virtual void OnInit();
virtual void OnMapLoad();
virtual void OnRender();
virtual void OnInit() override;
virtual void OnMapLoad() override;
virtual void OnRender() override;

void LoadBackground();
};
Expand Down
2 changes: 1 addition & 1 deletion src/game/client/components/binds.cpp
Expand Up @@ -11,7 +11,7 @@ bool CBinds::CBindsSpecial::OnInput(IInput::CEvent Event)
// only handle F and composed F binds
if((Event.m_Key >= KEY_F1 && Event.m_Key <= KEY_F12) || (Event.m_Key >= KEY_F13 && Event.m_Key <= KEY_F24))
{
int Mask = m_pBinds->GetModifierMask(Input());
int Mask = CBinds::GetModifierMask(Input());

// Look for a composed bind
bool ret = false;
Expand Down
8 changes: 5 additions & 3 deletions src/game/client/components/binds.h
Expand Up @@ -24,12 +24,14 @@ class CBinds : public CComponent
public:
CBinds();
~CBinds();
virtual int Sizeof() const override { return sizeof(*this); }

class CBindsSpecial : public CComponent
{
public:
CBinds *m_pBinds;
virtual bool OnInput(IInput::CEvent Event);
virtual int Sizeof() const override { return sizeof(*this); }
virtual bool OnInput(IInput::CEvent Event) override;
};

enum
Expand Down Expand Up @@ -57,8 +59,8 @@ class CBinds : public CComponent
static const char *GetModifierName(int Modifier);
static const char *GetKeyBindModifiersName(int Modifier);

virtual void OnConsoleInit();
virtual bool OnInput(IInput::CEvent Event);
virtual void OnConsoleInit() override;
virtual bool OnInput(IInput::CEvent Event) override;

// DDRace

Expand Down
7 changes: 4 additions & 3 deletions src/game/client/components/broadcast.h
Expand Up @@ -12,9 +12,10 @@ class CBroadcast : public CComponent
float m_BroadcastRenderOffset;

public:
virtual void OnReset();
virtual void OnRender();
virtual void OnMessage(int MsgType, void *pRawMsg);
virtual int Sizeof() const override { return sizeof(*this); }
virtual void OnReset() override;
virtual void OnRender() override;
virtual void OnMessage(int MsgType, void *pRawMsg) override;
};

#endif
2 changes: 1 addition & 1 deletion src/game/client/components/camera.cpp
Expand Up @@ -211,7 +211,7 @@ void CCamera::ConZoomMinus(IConsole::IResult *pResult, void *pUserData)
}
void CCamera::ConZoom(IConsole::IResult *pResult, void *pUserData)
{
float TargetLevel = pResult->NumArguments() ? clamp<float>(pResult->GetFloat(0), 0, 20) : g_Config.m_ClDefaultZoom;
float TargetLevel = pResult->NumArguments() ? pResult->GetFloat(0) : g_Config.m_ClDefaultZoom;
((CCamera *)pUserData)->ChangeZoom(pow(ZoomStep, TargetLevel - 10));
}
void CCamera::ConSetView(IConsole::IResult *pResult, void *pUserData)
Expand Down
7 changes: 4 additions & 3 deletions src/game/client/components/camera.h
Expand Up @@ -40,12 +40,13 @@ class CCamera : public CComponent
float m_ZoomSmoothingTarget;

CCamera();
virtual void OnRender();
virtual int Sizeof() const override { return sizeof(*this); }
virtual void OnRender() override;

// DDRace

virtual void OnConsoleInit();
virtual void OnReset();
virtual void OnConsoleInit() override;
virtual void OnReset() override;

private:
static void ConZoomPlus(IConsole::IResult *pResult, void *pUserData);
Expand Down