about summary refs log tree commit diff
path: root/src/engine
diff options
context:
space:
mode:
authorTeetime <TeetimeTW@yahoo.de>2013-03-24 04:19:57 +0100
committerTeetime <TeetimeTW@yahoo.de>2013-03-24 04:19:57 +0100
commit4affc155a906b6091aafc3f9635acc3b8b0aed8a (patch)
tree43e4dc20b9c36599571f3caf2e9108a4bb3f5401 /src/engine
parent6e73cd75bf24eb98781c68ae47d6527cc03262c8 (diff)
parent0914490bd994185caef6bfc3038f5cec737e31f3 (diff)
downloadzcatch-4affc155a906b6091aafc3f9635acc3b8b0aed8a.tar.gz
zcatch-4affc155a906b6091aafc3f9635acc3b8b0aed8a.zip
Merge branch 'master0.6' into zCatch
Conflicts:
	data/languages/index.txt
	src/game/server/entities/character.cpp
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/client/backend_sdl.cpp153
-rw-r--r--src/engine/client/backend_sdl.h94
-rw-r--r--src/engine/client/client.cpp36
-rw-r--r--src/engine/client/client.h2
-rw-r--r--src/engine/client/graphics.cpp49
-rw-r--r--src/engine/client/graphics.h2
-rw-r--r--src/engine/client/graphics_threaded.cpp136
-rw-r--r--src/engine/client/graphics_threaded.h35
-rw-r--r--src/engine/client/input.cpp13
-rw-r--r--src/engine/client/serverbrowser.cpp2
-rw-r--r--src/engine/client/text.cpp2
-rw-r--r--src/engine/demo.h4
-rw-r--r--src/engine/graphics.h2
-rw-r--r--src/engine/input.h7
-rw-r--r--src/engine/server/server.cpp101
-rw-r--r--src/engine/server/server.h6
-rw-r--r--src/engine/shared/config_variables.h11
-rw-r--r--src/engine/shared/console.cpp8
-rw-r--r--src/engine/shared/demo.cpp30
-rw-r--r--src/engine/shared/demo.h1
-rw-r--r--src/engine/shared/econ.cpp4
-rw-r--r--src/engine/shared/mapchecker.cpp1
-rw-r--r--src/engine/shared/netban.cpp2
-rw-r--r--src/engine/shared/netban.h4
-rw-r--r--src/engine/shared/network.h6
-rw-r--r--src/engine/shared/network_client.cpp2
-rw-r--r--src/engine/shared/network_conn.cpp19
-rw-r--r--src/engine/shared/network_server.cpp10
-rw-r--r--src/engine/shared/snapshot.cpp7
29 files changed, 489 insertions, 260 deletions
diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp
index e7975aca..37d1019a 100644
--- a/src/engine/client/backend_sdl.cpp
+++ b/src/engine/client/backend_sdl.cpp
@@ -11,6 +11,9 @@
 
 void CGraphicsBackend_Threaded::ThreadFunc(void *pUser)
 {
+	#ifdef CONF_PLATFORM_MACOSX
+		CAutoreleasePool AutoreleasePool;
+	#endif
 	CGraphicsBackend_Threaded *pThis = (CGraphicsBackend_Threaded *)pUser;
 
 	while(!pThis->m_Shutdown)
@@ -97,6 +100,41 @@ int CCommandProcessorFragment_OpenGL::TexFormatToOpenGLFormat(int TexFormat)
 	return GL_RGBA;
 }
 
+unsigned char CCommandProcessorFragment_OpenGL::Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp)
+{
+	int Value = 0;
+	for(int x = 0; x < ScaleW; x++)
+		for(int y = 0; y < ScaleH; y++)
+			Value += pData[((v+y)*w+(u+x))*Bpp+Offset];
+	return Value/(ScaleW*ScaleH);
+}
+
+void *CCommandProcessorFragment_OpenGL::Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData)
+{
+	unsigned char *pTmpData;
+	int ScaleW = Width/NewWidth;
+	int ScaleH = Height/NewHeight;
+
+	int Bpp = 3;
+	if(Format == CCommandBuffer::TEXFORMAT_RGBA)
+		Bpp = 4;
+
+	pTmpData = (unsigned char *)mem_alloc(NewWidth*NewHeight*Bpp, 1);
+
+	int c = 0;
+	for(int y = 0; y < NewHeight; y++)
+		for(int x = 0; x < NewWidth; x++, c++)
+		{
+			pTmpData[c*Bpp] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 0, ScaleW, ScaleH, Bpp);
+			pTmpData[c*Bpp+1] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 1, ScaleW, ScaleH, Bpp);
+			pTmpData[c*Bpp+2] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 2, ScaleW, ScaleH, Bpp);
+			if(Bpp == 4)
+				pTmpData[c*Bpp+3] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 3, ScaleW, ScaleH, Bpp);
+		}
+
+	return pTmpData;
+}
+
 void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State)
 {
 	// blend
@@ -130,7 +168,7 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
 	if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES)
 	{
 		glEnable(GL_TEXTURE_2D);
-		glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture]);
+		glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture].m_Tex);
 	}
 	else
 		glDisable(GL_TEXTURE_2D);
@@ -155,9 +193,14 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
 	glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, 1.0f, 10.f);
 }
 
+void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand)
+{
+	m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
+}
+
 void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
 {
-	glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot]);
+	glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot].m_Tex);
 	glTexSubImage2D(GL_TEXTURE_2D, 0, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height,
 		TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pCommand->m_pData);
 	mem_free(pCommand->m_pData);
@@ -165,31 +208,85 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::
 
 void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand)
 {
-	glDeleteTextures(1, &m_aTextures[pCommand->m_Slot]);
+	glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex);
+	*m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize;
 }
 
 void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
 {
+	int Width = pCommand->m_Width;
+	int Height = pCommand->m_Height;
+	void *pTexData = pCommand->m_pData;
+
+	// resample if needed
+	if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB)
+	{
+		int MaxTexSize;

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