&& !FS_FileExists(va("dlcache/%s.%i.%i", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer)))
{
Con_Printf("Downloading new CSQC code to dlcache/%s.%i.%i\n", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer);
- Cmd_ForwardStringToServer(va("download %s", csqc_progname.string));
+ if(cl_serverextension_download.integer >= 2 && FS_HasZlib())
+ Cmd_ForwardStringToServer(va("download %s deflate", csqc_progname.string));
+ else
+ Cmd_ForwardStringToServer(va("download %s", csqc_progname.string));
return;
}
}
size_t existingsize;
const char *extension;
- // finished file
- // save to disk only if we don't already have it
- // (this is mainly for playing back demos)
- existingcrc = FS_CRCFile(cls.qw_downloadname, &existingsize);
- if (existingsize || gamemode == GAME_NEXUIZ || !strcmp(cls.qw_downloadname, csqc_progname.string))
- // let csprogs ALWAYS go to dlcache, to prevent "viral csprogs"; also, never put files outside dlcache for Nexuiz
+ if(cls.qw_download_deflate)
+ {
+ unsigned char *out;
+ size_t inflated_size;
+ out = FS_Inflate(cls.qw_downloadmemory, cls.qw_downloadmemorycursize, &inflated_size, tempmempool);
+ Mem_Free(cls.qw_downloadmemory);
+ Con_Printf("Inflated download: new size: %u (%g%%)\n", (unsigned)inflated_size, 100.0 - 100.0*(cls.qw_downloadmemorycursize / (float)inflated_size));
+ cls.qw_downloadmemory = out;
+ cls.qw_downloadmemorycursize = inflated_size;
+ }
+
+ if(!cls.qw_downloadmemory)
{
- if ((int)existingsize != size || existingcrc != crc)
+ Con_Printf("Download \"%s\" is corrupt (see above!)\n", cls.qw_downloadname);
+ }
+ else
+ {
+ crc = CRC_Block(cls.qw_downloadmemory, cls.qw_downloadmemorycursize);
+ size = cls.qw_downloadmemorycursize;
+ // finished file
+ // save to disk only if we don't already have it
+ // (this is mainly for playing back demos)
+ existingcrc = FS_CRCFile(cls.qw_downloadname, &existingsize);
+ if (existingsize || gamemode == GAME_NEXUIZ || !strcmp(cls.qw_downloadname, csqc_progname.string))
+ // let csprogs ALWAYS go to dlcache, to prevent "viral csprogs"; also, never put files outside dlcache for Nexuiz
{
- // we have a mismatching file, pick another name for it
- char name[MAX_QPATH*2];
- dpsnprintf(name, sizeof(name), "dlcache/%s.%i.%i", cls.qw_downloadname, size, crc);
- if (!FS_FileExists(name))
+ if ((int)existingsize != size || existingcrc != crc)
{
- Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", name, size, crc);
- FS_WriteFile(name, cls.qw_downloadmemory, cls.qw_downloadmemorycursize);
+ // we have a mismatching file, pick another name for it
+ char name[MAX_QPATH*2];
+ dpsnprintf(name, sizeof(name), "dlcache/%s.%i.%i", cls.qw_downloadname, size, crc);
+ if (!FS_FileExists(name))
+ {
+ Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", name, size, crc);
+ FS_WriteFile(name, cls.qw_downloadmemory, cls.qw_downloadmemorycursize);
+ }
}
}
- }
- else
- {
- // we either don't have it or have a mismatching file...
- // so it's time to accept the file
- // but if we already have a mismatching file we need to rename
- // this new one, and if we already have this file in renamed form,
- // we do nothing
- Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", cls.qw_downloadname, size, crc);
- FS_WriteFile(cls.qw_downloadname, cls.qw_downloadmemory, cls.qw_downloadmemorycursize);
- extension = FS_FileExtension(cls.qw_downloadname);
- if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
- FS_Rescan();
+ else
+ {
+ // we either don't have it or have a mismatching file...
+ // so it's time to accept the file
+ // but if we already have a mismatching file we need to rename
+ // this new one, and if we already have this file in renamed form,
+ // we do nothing
+ Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", cls.qw_downloadname, size, crc);
+ FS_WriteFile(cls.qw_downloadname, cls.qw_downloadmemory, cls.qw_downloadmemorycursize);
+ extension = FS_FileExtension(cls.qw_downloadname);
+ if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
+ FS_Rescan();
+ }
}
}
else if (cls.qw_downloadmemory && size)
cls.qw_downloadmemory = Mem_Alloc(cls.permanentmempool, cls.qw_downloadmemorymaxsize);
cls.qw_downloadnumber++;
+ cls.qw_download_deflate = false;
+ if(Cmd_Argc() >= 4)
+ {
+ if(!strcmp(Cmd_Argv(3), "deflate"))
+ cls.qw_download_deflate = true;
+ // check further encodings here
+ }
+
Cmd_ForwardStringToServer("sv_startdownload");
}
double qw_downloadspeedtime;
int qw_downloadspeedcount;
int qw_downloadspeedrate;
+ qboolean qw_download_deflate;
// current file upload buffer (for uploading screenshots to server)
unsigned char *qw_uploaddata;
#define MAX_WBITS 15
#define Z_OK 0
#define Z_STREAM_END 1
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
#define ZLIB_VERSION "1.2.3"
+#define Z_BINARY 0
+#define Z_DEFLATED 8
+#define Z_MEMLEVEL_DEFAULT 8
+
+#define Z_NULL 0
+#define Z_DEFAULT_COMPRESSION (-1)
+#define Z_NO_FLUSH 0
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+
// Uncomment the following line if the zlib DLL you have still uses
// the 1.1.x series calling convention on Win32 (WINAPI)
//#define ZLIB_USES_WINAPI
#define QFILE_FLAG_PACKED (1 << 0)
// file is compressed using the deflate algorithm (PK3 only)
#define QFILE_FLAG_DEFLATED (1 << 1)
+// file is actually already loaded data
+#define QFILE_FLAG_DATA (1 << 2)
#define FILE_BUFF_SIZE 2048
typedef struct
// For zipped files
ztoolkit_t* ztk;
+
+ // for data files
+ const unsigned char *data;
};
static int (ZEXPORT *qz_inflateEnd) (z_stream* strm);
static int (ZEXPORT *qz_inflateInit2_) (z_stream* strm, int windowBits, const char *version, int stream_size);
static int (ZEXPORT *qz_inflateReset) (z_stream* strm);
+static int (ZEXPORT *qz_deflateInit2_) (z_stream* strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size);
+static int (ZEXPORT *qz_deflateEnd) (z_stream* strm);
+static int (ZEXPORT *qz_deflate) (z_stream* strm, int flush);
#define qz_inflateInit2(strm, windowBits) \
qz_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define qz_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ qz_deflateInit2_((strm), (level), (method), (windowBits), (memLevel), (strategy), ZLIB_VERSION, sizeof(z_stream))
+
+// qz_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
static dllfunction_t zlibfuncs[] =
{
{"inflateEnd", (void **) &qz_inflateEnd},
{"inflateInit2_", (void **) &qz_inflateInit2_},
{"inflateReset", (void **) &qz_inflateReset},
+ {"deflateInit2_", (void **) &qz_deflateInit2_},
+ {"deflateEnd", (void **) &qz_deflateEnd},
+ {"deflate", (void **) &qz_deflate},
{NULL, NULL}
};
return Sys_LoadLibrary (dllnames, &zlib_dll, zlibfuncs);
}
+/*
+====================
+FS_HasZlib
+
+See if zlib is available
+====================
+*/
+qboolean FS_HasZlib(void)
+{
+ PK3_OpenLibrary(); // to be safe
+ return (zlib_dll != 0);
+}
/*
====================
}
+/*
+====================
+FS_FileFromData
+
+Open a file. The syntax is the same as fopen
+====================
+*/
+qfile_t* FS_FileFromData (const unsigned char *data, const size_t size, qboolean quiet)
+{
+ qfile_t* file;
+ file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file));
+ memset (file, 0, sizeof (*file));
+ file->flags = QFILE_FLAG_DATA;
+ file->ungetc = EOF;
+ file->real_length = size;
+ file->data = data;
+ return file;
+}
+
/*
====================
FS_Close
*/
int FS_Close (qfile_t* file)
{
+ if(file->flags & QFILE_FLAG_DATA)
+ {
+ Mem_Free(file);
+ return 0;
+ }
+
if (close (file->handle))
return EOF;
else
done = 0;
+ if(file->flags & QFILE_FLAG_DATA)
+ {
+ size_t left = file->real_length - file->position;
+ if(buffersize > left)
+ buffersize = left;
+ memcpy(buffer, file->data + file->position, buffersize);
+ file->position += buffersize;
+ return buffersize;
+ }
+
// First, we copy as many bytes as we can from "buff"
if (file->buff_ind < file->buff_len)
{
if (offset < 0 || offset > file->real_length)
return -1;
+ if(file->flags & QFILE_FLAG_DATA)
+ {
+ file->position = offset;
+ return 0;
+ }
+
// If we have the data in our read buffer, we don't need to actually seek
if (file->position - file->buff_len <= offset && offset <= file->position)
{
return crc;
}
+unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool)
+{
+ z_stream strm;
+ unsigned char *out = NULL;
+ unsigned char *tmp;
+
+ memset(&strm, 0, sizeof(strm));
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ if(level < 0)
+ level = Z_DEFAULT_COMPRESSION;
+
+ if(qz_deflateInit2(&strm, level, Z_DEFLATED, -MAX_WBITS, Z_MEMLEVEL_DEFAULT, Z_BINARY) != Z_OK)
+ {
+ Con_Printf("FS_Deflate: deflate init error!\n");
+ return NULL;
+ }
+
+ strm.next_in = (unsigned char*)data;
+ strm.avail_in = size;
+
+ tmp = Mem_Alloc(tempmempool, size);
+ if(!tmp)
+ {
+ Con_Printf("FS_Deflate: not enough memory in tempmempool!\n");
+ qz_deflateEnd(&strm);
+ return NULL;
+ }
+
+ strm.next_out = tmp;
+ strm.avail_out = size;
+
+ if(qz_deflate(&strm, Z_FINISH) != Z_STREAM_END)
+ {
+ Con_Printf("FS_Deflate: deflate failed!\n");
+ qz_deflateEnd(&strm);
+ Mem_Free(tmp);
+ return NULL;
+ }
+
+ if(qz_deflateEnd(&strm) != Z_OK)
+ {
+ Con_Printf("FS_Deflate: deflateEnd failed\n");
+ Mem_Free(tmp);
+ return NULL;
+ }
+
+ if(strm.total_out >= size)
+ {
+ Con_Printf("FS_Deflate: deflate is useless on this data!\n");
+ Mem_Free(tmp);
+ return NULL;
+ }
+
+ out = Mem_Alloc(mempool, strm.total_out);
+ if(!out)
+ {
+ Con_Printf("FS_Deflate: not enough memory in target mempool!\n");
+ Mem_Free(tmp);
+ return NULL;
+ }
+
+ if(deflated_size)
+ *deflated_size = (size_t)strm.total_out;
+
+ memcpy(out, tmp, strm.total_out);
+ Mem_Free(tmp);
+
+ return out;
+}
+
+static void AssertBufsize(sizebuf_t *buf, int length)
+{
+ if(buf->cursize + length > buf->maxsize)
+ {
+ int oldsize = buf->maxsize;
+ unsigned char *olddata;
+ olddata = buf->data;
+ buf->maxsize += length;
+ buf->data = Mem_Alloc(tempmempool, buf->maxsize);
+ if(olddata)
+ {
+ memcpy(buf->data, olddata, oldsize);
+ Mem_Free(olddata);
+ }
+ }
+}
+
+unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflated_size, mempool_t *mempool)
+{
+ int ret;
+ z_stream strm;
+ unsigned char *out = NULL;
+ unsigned char tmp[2048];
+ unsigned int have;
+ sizebuf_t outbuf;
+
+ memset(&outbuf, 0, sizeof(outbuf));
+ outbuf.data = Mem_Alloc(tempmempool, sizeof(tmp));
+ outbuf.maxsize = sizeof(tmp);
+
+ memset(&strm, 0, sizeof(strm));
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ if(qz_inflateInit2(&strm, -MAX_WBITS) != Z_OK)
+ {
+ Con_Printf("FS_Inflate: inflate init error!\n");
+ Mem_Free(outbuf.data);
+ return NULL;
+ }
+
+ strm.next_in = (unsigned char*)data;
+ strm.avail_in = size;
+
+ do
+ {
+ strm.next_out = tmp;
+ strm.avail_out = sizeof(tmp);
+ ret = qz_inflate(&strm, Z_NO_FLUSH);
+ // it either returns Z_OK on progress, Z_STREAM_END on end
+ // or an error code
+ switch(ret)
+ {
+ case Z_STREAM_END:
+ case Z_OK:
+ break;
+
+ case Z_STREAM_ERROR:
+ Con_Print("FS_Inflate: stream error!\n");
+ break;
+ case Z_DATA_ERROR:
+ Con_Print("FS_Inflate: data error!\n");
+ break;
+ case Z_MEM_ERROR:
+ Con_Print("FS_Inflate: mem error!\n");
+ break;
+ case Z_BUF_ERROR:
+ Con_Print("FS_Inflate: buf error!\n");
+ break;
+ default:
+ Con_Print("FS_Inflate: unknown error!\n");
+ break;
+
+ }
+ if(ret != Z_OK && ret != Z_STREAM_END)
+ {
+ Con_Printf("Error after inflating %u bytes\n", (unsigned)strm.total_in);
+ Mem_Free(outbuf.data);
+ qz_inflateEnd(&strm);
+ return NULL;
+ }
+ have = sizeof(tmp) - strm.avail_out;
+ AssertBufsize(&outbuf, max(have, sizeof(tmp)));
+ SZ_Write(&outbuf, tmp, have);
+ } while(ret != Z_STREAM_END);
+
+ qz_inflateEnd(&strm);
+
+ out = Mem_Alloc(mempool, outbuf.cursize);
+ if(!out)
+ {
+ Con_Printf("FS_Inflate: not enough memory in target mempool!\n");
+ Mem_Free(outbuf.data);
+ return NULL;
+ }
+
+ memcpy(out, outbuf.data, outbuf.cursize);
+ Mem_Free(outbuf.data);
+
+ if(inflated_size)
+ *inflated_size = (size_t)outbuf.cursize;
+
+ return out;
+}
const char *FS_WhichPack(const char *filename);
qfile_t* FS_OpenRealFile (const char* filepath, const char* mode, qboolean quiet);
qfile_t* FS_OpenVirtualFile (const char* filepath, qboolean quiet);
+qfile_t* FS_FileFromData (const unsigned char *data, const size_t size, qboolean quiet);
int FS_Close (qfile_t* file);
fs_offset_t FS_Write (qfile_t* file, const void* data, size_t datasize);
fs_offset_t FS_Read (qfile_t* file, void* buffer, size_t buffersize);
void FS_mkdir (const char *path);
+unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool);
+unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflated_size, mempool_t *mempool);
+
+qboolean FS_HasZlib(void);
#endif
int csqc_progcrc; // -1 = no progs
int csqc_progsize; // -1 = no progs
char csqc_progname[MAX_QPATH]; // copied from csqc_progname at level start
+ unsigned char *csqc_progdata;
+ size_t csqc_progsize_deflated;
+ unsigned char *csqc_progdata_deflated;
// collision culling data
world_t world;
int download_expectedposition; // next position the client should ack
qboolean download_started;
char download_name[MAX_QPATH];
+ qboolean download_deflate;
// fixangle data
qboolean fixangle_angles_set;
if(client->sv_demo_file != NULL)
{
- void *csqcbuf;
- fs_offset_t csqclen;
- int csqccrc;
int i;
char buf[NET_MAXMESSAGE];
sizebuf_t sb;
- csqcbuf = FS_LoadFile(sv.csqc_progname, tempmempool, true, &csqclen);
- if(csqcbuf)
- {
- csqccrc = CRC_Block(csqcbuf, csqclen);
- sb.data = (void *) buf;
- sb.maxsize = sizeof(buf);
- i = 0;
- while(MakeDownloadPacket(sv.csqc_progname, csqcbuf, csqclen, csqccrc, i++, &sb, sv.protocol))
- SV_WriteDemoMessage(client, &sb, false);
- Mem_Free(csqcbuf);
- }
+ sb.data = (void *) buf;
+ sb.maxsize = sizeof(buf);
+ i = 0;
+ while(MakeDownloadPacket(sv.csqc_progname, sv.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, i++, &sb, sv.protocol))
+ SV_WriteDemoMessage(client, &sb, false);
}
//[515]: init stufftext string (it is sent before svc_serverinfo)
}
}
- if (sv_allowdownloads.integer)
+ //if (sv_allowdownloads.integer)
+ // always send the info that the server supports the protocol, even if downloads are forbidden
+ // only because of that, the CSQC exception can work
{
MSG_WriteByte (&client->netconnection->message, svc_stufftext);
- MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1\n");
+ MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 2\n");
}
// send at this time so it's guaranteed to get executed at the right time
host_client->download_started = true;
}
+static void Download_CheckExtensions(void)
+{
+ int i;
+ int argc = Cmd_Argc();
+
+ // first reset them all
+ host_client->download_deflate = false;
+
+ for(i = 2; i < argc; ++i)
+ {
+ if(!strcmp(Cmd_Argv(i), "deflate"))
+ {
+ host_client->download_deflate = true;
+ break;
+ }
+ }
+}
+
static void SV_Download_f(void)
{
const char *whichpack, *whichpack2, *extension;
+ qboolean is_csqc; // so we need to check only once
- if (Cmd_Argc() != 2)
+ if (Cmd_Argc() < 2)
{
- SV_ClientPrintf("usage: download <filename>\n");
+ SV_ClientPrintf("usage: download <filename> {<extensions>}*\n");
+ SV_ClientPrintf(" supported extensions: deflate\n");
return;
}
host_client->download_started = false;
}
- if (!sv_allowdownloads.integer)
+ is_csqc = (sv.csqc_progname[0] && strcmp(Cmd_Argv(1), sv.csqc_progname) == 0);
+
+ if (!sv_allowdownloads.integer && !is_csqc)
{
SV_ClientPrintf("Downloads are disabled on this server\n");
Host_ClientCommands("\nstopdownload\n");
return;
}
+ Download_CheckExtensions();
+
strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
extension = FS_FileExtension(host_client->download_name);
if (developer.integer >= 100)
Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
+ if(is_csqc)
+ {
+ char extensions[MAX_QPATH]; // make sure this can hold all extensions
+ extensions[0] = '\0';
+
+ if(host_client->download_deflate)
+ strlcat(extensions, " deflate", sizeof(extensions));
+
+ Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
+
+ if(host_client->download_deflate)
+ host_client->download_file = FS_FileFromData(sv.csqc_progdata_deflated, sv.csqc_progsize_deflated, true);
+ else
+ host_client->download_file = FS_FileFromData(sv.csqc_progdata, sv.csqc_progsize, true);
+
+ // no, no space is needed between %s and %s :P
+ Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions);
+
+ host_client->download_expectedposition = 0;
+ host_client->download_started = false;
+ host_client->sendsignon = true; // make sure this message is sent
+ return;
+ }
+
if (!FS_FileExists(host_client->download_name))
{
SV_ClientPrintf("Download rejected: server does not have the file \"%s\"\nYou may need to separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
+ /*
+ * we can only do this if we would actually deflate on the fly
+ * which we do not (yet)!
+ {
+ char extensions[MAX_QPATH]; // make sure this can hold all extensions
+ extensions[0] = '\0';
+
+ if(host_client->download_deflate)
+ strlcat(extensions, " deflate", sizeof(extensions));
+
+ // no, no space is needed between %s and %s :P
+ Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions);
+ }
+ */
Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
host_client->download_expectedposition = 0;
}
}
+/*
+================
+SV_Prepare_CSQC
+
+Load csprogs.dat and comperss it so it doesn't need to be
+reloaded on request.
+================
+*/
+void SV_Prepare_CSQC(void)
+{
+ fs_offset_t progsize;
+
+ if(sv.csqc_progdata)
+ {
+ Con_DPrintf("Unloading old CSQC data.\n");
+ Mem_Free(sv.csqc_progdata);
+ if(sv.csqc_progdata_deflated)
+ Mem_Free(sv.csqc_progdata_deflated);
+ }
+
+ sv.csqc_progdata = NULL;
+ sv.csqc_progdata_deflated = NULL;
+
+ Con_Print("Loading csprogs.dat\n");
+
+ sv.csqc_progname[0] = 0;
+ sv.csqc_progdata = FS_LoadFile(csqc_progname.string, sv_mempool, false, &progsize);
+
+ if(progsize > 0)
+ {
+ size_t deflated_size;
+
+ sv.csqc_progsize = (int)progsize;
+ sv.csqc_progcrc = CRC_Block(sv.csqc_progdata, progsize);
+ strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
+ Con_Printf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
+
+ Con_Print("Compressing csprogs.dat\n");
+ //unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool);
+ sv.csqc_progdata_deflated = FS_Deflate(sv.csqc_progdata, progsize, &deflated_size, -1, sv_mempool);
+ sv.csqc_progsize_deflated = (int)deflated_size;
+ Con_Printf("Deflated: %g%%\n", 100.0 - 100.0 * (deflated_size / (float)progsize));
+ Con_DPrintf("Uncompressed: %u\nCompressed: %u\n", (unsigned)sv.csqc_progsize, (unsigned)sv.csqc_progsize_deflated);
+ }
+}
/*
================
static void SV_VM_Setup(void)
{
extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat
- size_t csprogsdatasize;
PRVM_Begin;
PRVM_InitProg( PRVM_SERVERPROG );
PRVM_End;
- // see if there is a csprogs.dat installed, and if so, set the csqc_progcrc accordingly, this will be sent to connecting clients to tell them to only load a matching csprogs.dat file
- sv.csqc_progname[0] = 0;
- sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
- sv.csqc_progsize = csprogsdatasize;
- if (sv.csqc_progsize > 0)
- {
- strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
- Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
- }
+ SV_Prepare_CSQC();
}
void SV_VM_Begin(void)