about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/engine/client/client.cpp180
-rw-r--r--src/engine/client/client.h30
-rw-r--r--src/engine/server.h2
-rw-r--r--src/engine/server/server.cpp20
-rw-r--r--src/engine/server/server.h2
-rw-r--r--src/engine/shared/config_variables.h2
-rw-r--r--src/engine/shared/filecollection.cpp186
-rw-r--r--src/engine/shared/filecollection.h35
-rw-r--r--src/game/server/gamecontroller.cpp1
9 files changed, 249 insertions, 209 deletions
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index 37fda6c2..5029fe1e 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -32,6 +32,7 @@
 #include <engine/shared/protocol.h>
 #include <engine/shared/ringbuffer.h>
 #include <engine/shared/snapshot.h>
+#include <engine/shared/filecollection.h>
 
 #include <mastersrv/mastersrv.h>
 #include <versionsrv/versionsrv.h>
@@ -231,185 +232,6 @@ void CSmoothTime::Update(CGraph *pGraph, int64 Target, int TimeLeft, int AdjustD
 }
 
 
-bool CFileCollection::IsFilenameValid(const char *pFilename)
-{
-	if(str_length(pFilename) != m_FileDescLength+TIMESTAMP_LENGTH+m_FileExtLength ||
-		str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) ||
-		str_comp(pFilename+m_FileDescLength+TIMESTAMP_LENGTH, m_aFileExt))
-		return false;
-
-	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;
-}
-
-int64 CFileCollection::ExtractTimestamp(const char *pTimestring)
-{
-	int64 Timestamp = pTimestring[0]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[1]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[2]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[3]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[5]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[6]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[8]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[9]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[11]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[12]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[14]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[15]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[17]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[18]-'0';
-
-	return Timestamp;
-}
-
-void CFileCollection::BuildTimestring(int64 Timestamp, char *pTimestring)
-{
-	pTimestring[19] = 0;
-	pTimestring[18] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[17] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[16] = '-';
-	pTimestring[15] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[14] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[13] = '-';
-	pTimestring[12] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[11] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[10] = '_';
-	pTimestring[9] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[8] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[7] = '-';
-	pTimestring[6] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[5] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[4] = '-';
-	pTimestring[3] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[2] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[1] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[0] = (Timestamp&0xF)+'0';
-}
-
-void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries)
-{
-	mem_zero(m_aTimestamps, sizeof(m_aTimestamps));
-	m_NumTimestamps = 0;
-	m_MaxEntries = clamp(MaxEntries, 1, static_cast<int>(MAX_ENTRIES));
-	str_copy(m_aFileDesc, pFileDesc, sizeof(m_aFileDesc));
-	m_FileDescLength = str_length(m_aFileDesc);
-	str_copy(m_aFileExt, pFileExt, sizeof(m_aFileExt));
-	m_FileExtLength = str_length(m_aFileExt);
-	str_copy(m_aPath, pPath, sizeof(m_aPath));
-	m_pStorage = pStorage;
-
-	m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this);
-}
-
-void CFileCollection::AddEntry(int64 Timestamp)
-{
-	if(m_NumTimestamps == 0)
-	{
-		// empty list
-		m_aTimestamps[m_NumTimestamps++] = Timestamp;
-	}
-	else
-	{
-		// remove old file
-		if(m_NumTimestamps == m_MaxEntries)
-		{
-			char aBuf[512];
-			char aTimestring[TIMESTAMP_LENGTH];
-			BuildTimestring(m_aTimestamps[0], aTimestring);
-			str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt);
-			m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
-		}
-
-		// add entry to the sorted list
-		if(m_aTimestamps[0] > Timestamp)
-		{
-			// first entry
-			if(m_NumTimestamps < m_MaxEntries)
-			{
-				mem_move(m_aTimestamps+1, m_aTimestamps, m_NumTimestamps*sizeof(int64));
-				m_aTimestamps[0] = Timestamp;
-				++m_NumTimestamps;
-			}
-		}
-		else if(m_aTimestamps[m_NumTimestamps-1] <= Timestamp)
-		{
-			// last entry
-			if(m_NumTimestamps == m_MaxEntries)
-			{
-				mem_move(m_aTimestamps, m_aTimestamps+1, (m_NumTimestamps-1)*sizeof(int64));
-				m_aTimestamps[m_NumTimestamps-1] = Timestamp;
-			}
-			else
-				m_aTimestamps[m_NumTimestamps++] = Timestamp;
-		}
-		else
-		{
-			// middle entry
-			int Left = 0, Right = m_NumTimestamps-1;
-			while(Right-Left > 1)
-			{
-				int Mid = (Left+Right)/2;
-				if(m_aTimestamps[Mid] > Timestamp)
-					Right = Mid;
-				else
-					Left = Mid;
-			}
-
-			if(m_NumTimestamps == m_MaxEntries)
-			{
-				mem_move(m_aTimestamps, m_aTimestamps+1, (Right-1)*sizeof(int64));
-				m_aTimestamps[Right-1] = Timestamp;
-			}
-			else
-			{
-				mem_move(m_aTimestamps+Right+1, m_aTimestamps+Right, (m_NumTimestamps-Right)*sizeof(int64));
-				m_aTimestamps[Right] = Timestamp;
-				++m_NumTimestamps;
-			}
-		}
-	}
-}
-
-int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser)
-{
-	CFileCollection *pThis = static_cast<CFileCollection *>(pUser);
-
-	// check for valid file name format
-	if(IsDir || !pThis->IsFilenameValid(pFilename))
-		return 0;
-
-	// extract the timestamp
-	int64 Timestamp = pThis->ExtractTimestamp(pFilename+pThis->m_FileDescLength+1);
-
-	// add the entry
-	pThis->AddEntry(Timestamp);
-
-	return 0;
-}
-
-
 CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotDelta)
 {
 	m_pEditor = 0;
diff --git a/src/engine/client/client.h b/src/engine/client/client.h
index 3d81f073..1504a4e4 100644
--- a/src/engine/client/client.h
+++ b/src/engine/client/client.h
@@ -51,36 +51,6 @@ public:
 };
 
 
-class CFileCollection
-{
-	enum
-	{
-		MAX_ENTRIES=1000,
-		TIMESTAMP_LENGTH=20,	// _YYYY-MM-DD_HH-MM-SS
-	};
-
-	int64 m_aTimestamps[MAX_ENTRIES];
-	int m_NumTimestamps;
-	int m_MaxEntries;
-	char m_aFileDesc[128];
-	int m_FileDescLength;
-	char m_aFileExt[32];
-	int m_FileExtLength;
-	char m_aPath[512];
-	IStorage *m_pStorage;
-
-	bool IsFilenameValid(const char *pFilename);
-	int64 ExtractTimestamp(const char *pTimestring);
-	void BuildTimestring(int64 Timestamp, char *pTimestring);
-
-public:
-	void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries);
-	void AddEntry(int64 Timestamp);
-
-	static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
-};
-
-
 class CClient : public IClient, public CDemoPlayer::IListner
 {
 	// needed interfaces
diff --git a/src/engine/server.h b/src/engine/server.h
index 28a97ecc..31134ca9 100644
--- a/src/engine/server.h
+++ b/src/engine/server.h
@@ -56,6 +56,8 @@ public:
 
 	virtual bool IsAuthed(int ClientID) = 0;
 	virtual void Kick(int ClientID, const char *pReason) = 0;
+
+	virtual void DemoRecorder_HandleAutoStart() = 0;
 };
 
 class IGameServer : public IInterface
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index 46f87840..57be060b 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -22,6 +22,7 @@
 #include <engine/shared/packer.h>
 #include <engine/shared/protocol.h>
 #include <engine/shared/snapshot.h>
+#include <engine/shared/filecollection.h>
 
 #include <mastersrv/mastersrv.h>
 
@@ -1519,6 +1520,25 @@ void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
 	((CServer *)pUser)->m_RunServer = 0;
 }
 
+void CServer::DemoRecorder_HandleAutoStart()
+{
+	if(g_Config.m_SvAutoDemoRecord)
+	{
+		m_DemoRecorder.Stop();
+		char aFilename[128];
+		char aDate[20];
+		str_timestamp(aDate, sizeof(aDate));
+		str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", "auto/autorecord", aDate);
+		m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "server");
+		if(g_Config.m_SvAutoDemoMax)
+		{
+			// clean up auto recorded demos
+			CFileCollection AutoDemos;
+			AutoDemos.Init(Storage(), "demos/server", "autorecord", ".demo", g_Config.m_SvAutoDemoMax);
+		}
+	}
+}
+
 void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
 {
 	CServer* pServer = (CServer *)pUser;
diff --git a/src/engine/server/server.h b/src/engine/server/server.h
index 4e575055..d8fdd8fa 100644
--- a/src/engine/server/server.h
+++ b/src/engine/server/server.h
@@ -148,6 +148,8 @@ public:
 
 	void Kick(int ClientID, const char *pReason);
 
+	void DemoRecorder_HandleAutoStart();
+
 	//int Tick()
 	int64 TickStartTime(int Tick);
 	//int TickSpeed()
diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h
index cb8f5f15..0789476e 100644
--- a/src/engine/shared/config_variables.h
+++ b/src/engine/shared/config_variables.h
@@ -86,6 +86,8 @@ MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remo
 MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)")
 MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication")
 MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick")
+MACRO_CONFIG_INT(SvAutoDemoRecord, sv_auto_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos")
+MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, "Maximum number of automatically recorded demos (0 = no limit)")
 
 MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous")
 MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console")
diff --git a/src/engine/shared/filecollection.cpp b/src/engine/shared/filecollection.cpp
new file mode 100644
index 00000000..c7db92a6
--- /dev/null
+++ b/src/engine/shared/filecollection.cpp
@@ -0,0 +1,186 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+
+#include <base/math.h>
+
+#include <engine/storage.h>
+
+#include "filecollection.h"
+
+bool CFileCollection::IsFilenameValid(const char *pFilename)
+{
+	if(str_length(pFilename) != m_FileDescLength+TIMESTAMP_LENGTH+m_FileExtLength ||
+		str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) ||
+		str_comp(pFilename+m_FileDescLength+TIMESTAMP_LENGTH, m_aFileExt))
+		return false;
+
+	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;
+}
+
+int64 CFileCollection::ExtractTimestamp(const char *pTimestring)
+{
+	int64 Timestamp = pTimestring[0]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[1]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[2]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[3]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[5]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[6]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[8]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[9]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[11]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[12]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[14]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[15]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[17]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[18]-'0';
+
+	return Timestamp;
+}
+
+void CFileCollection::BuildTimestring(int64 Timestamp, char *pTimestring)
+{
+	pTimestring[19] = 0;
+	pTimestring[18] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[17] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[16] = '-';
+	pTimestring[15] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[14] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[13] = '-';
+	pTimestring[12] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[11] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[10] = '_';
+	pTimestring[9] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[8] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[7] = '-';
+	pTimestring[6] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[5] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[4] = '-';
+	pTimestring[3] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[2] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[1] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[0] = (Timestamp&0xF)+'0';
+}
+
+void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries)
+{
+	mem_zero(m_aTimestamps, sizeof(m_aTimestamps));
+	m_NumTimestamps = 0;
+	m_MaxEntries = clamp(MaxEntries, 1, static_cast<int>(MAX_ENTRIES));
+	str_copy(m_aFileDesc, pFileDesc, sizeof(m_aFileDesc));
+	m_FileDescLength = str_length(m_aFileDesc);
+	str_copy(m_aFileExt, pFileExt, sizeof(m_aFileExt));
+	m_FileExtLength = str_length(m_aFileExt);
+	str_copy(m_aPath, pPath, sizeof(m_aPath));
+	m_pStorage = pStorage;
+
+	m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this);
+}
+
+void CFileCollection::AddEntry(int64 Timestamp)
+{
+	if(m_NumTimestamps == 0)
+	{
+		// empty list
+		m_aTimestamps[m_NumTimestamps++] = Timestamp;
+	}
+	else
+	{
+		// remove old file
+		if(m_NumTimestamps == m_MaxEntries)
+		{
+			char aBuf[512];
+			char aTimestring[TIMESTAMP_LENGTH];
+			BuildTimestring(m_aTimestamps[0], aTimestring);
+			str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt);
+			m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
+		}
+
+		// add entry to the sorted list
+		if(m_aTimestamps[0] > Timestamp)
+		{
+			// first entry
+			if(m_NumTimestamps < m_MaxEntries)
+			{
+				mem_move(m_aTimestamps+1, m_aTimestamps, m_NumTimestamps*sizeof(int64));
+				m_aTimestamps[0] = Timestamp;
+				++m_NumTimestamps;
+			}
+		}
+		else if(m_aTimestamps[m_NumTimestamps-1] <= Timestamp)
+		{
+			// last entry
+			if(m_NumTimestamps == m_MaxEntries)
+			{
+				mem_move(m_aTimestamps, m_aTimestamps+1, (m_NumTimestamps-1)*sizeof(int64));
+				m_aTimestamps[m_NumTimestamps-1] = Timestamp;
+			}
+			else
+				m_aTimestamps[m_NumTimestamps++] = Timestamp;
+		}
+		else
+		{
+			// middle entry
+			int Left = 0, Right = m_NumTimestamps-1;
+			while(Right-Left > 1)
+			{
+				int Mid = (Left+Right)/2;
+				if(m_aTimestamps[Mid] > Timestamp)
+					Right = Mid;
+				else
+					Left = Mid;
+			}
+
+			if(m_NumTimestamps == m_MaxEntries)
+			{
+				mem_move(m_aTimestamps, m_aTimestamps+1, (Right-1)*sizeof(int64));
+				m_aTimestamps[Right-1] = Timestamp;
+			}
+			else
+			{
+				mem_move(m_aTimestamps+Right+1, m_aTimestamps+Right, (m_NumTimestamps-Right)*sizeof(int64));
+				m_aTimestamps[Right] = Timestamp;
+				++m_NumTimestamps;
+			}
+		}
+	}
+}
+
+int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser)
+{
+	CFileCollection *pThis = static_cast<CFileCollection *>(pUser);
+
+	// check for valid file name format
+	if(IsDir || !pThis->IsFilenameValid(pFilename))
+		return 0;
+
+	// extract the timestamp
+	int64 Timestamp = pThis->ExtractTimestamp(pFilename+pThis->m_FileDescLength+1);
+
+	// add the entry
+	pThis->AddEntry(Timestamp);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/src/engine/shared/filecollection.h b/src/engine/shared/filecollection.h
new file mode 100644
index 00000000..c7548a8b
--- /dev/null
+++ b/src/engine/shared/filecollection.h
@@ -0,0 +1,35 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#ifndef ENGINE_SHARED_FILECOLLECTION_H
+#define ENGINE_SHARED_FILECOLLECTION_H
+
+class CFileCollection
+{
+	enum
+	{
+		MAX_ENTRIES=1000,
+		TIMESTAMP_LENGTH=20,	// _YYYY-MM-DD_HH-MM-SS
+	};
+
+	int64 m_aTimestamps[MAX_ENTRIES];
+	int m_NumTimestamps;
+	int m_MaxEntries;
+	char m_aFileDesc[128];
+	int m_FileDescLength;
+	char m_aFileExt[32];
+	int m_FileExtLength;
+	char m_aPath[512];
+	IStorage *m_pStorage;
+
+	bool IsFilenameValid(const char *pFilename);
+	int64 ExtractTimestamp(const char *pTimestring);
+	void BuildTimestring(int64 Timestamp, char *pTimestring);
+
+public:
+	void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries);
+	void AddEntry(int64 Timestamp);
+
+	static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp
index fd574d85..f8d418c3 100644
--- a/src/game/server/gamecontroller.cpp
+++ b/src/game/server/gamecontroller.cpp
@@ -217,6 +217,7 @@ void IGameController::StartRound()
 	m_aTeamscore[TEAM_RED] = 0;
 	m_aTeamscore[TEAM_BLUE] = 0;
 	m_ForceBalanced = false;
+	Server()->DemoRecorder_HandleAutoStart();
 	char aBuf[256];
 	str_format(aBuf, sizeof(aBuf), "start round type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS);
 	GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);