]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_main.c
fix typo in cl_netinputpacketspersecond_qw cvar name which caused
[xonotic/darkplaces.git] / sv_main.c
index 17dbf2c38bc57d2f7d6a62fc97153e98ce7bb5e1..b2afd2637b4152126bac82dd6eebca8988932e96 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // sv_main.c -- server main program
 
 #include "quakedef.h"
+#include "sv_demo.h"
 #include "libcurl.h"
 
 static void SV_SaveEntFile_f(void);
@@ -58,7 +59,7 @@ cvar_t sv_checkforpacketsduringsleep = {0, "sv_checkforpacketsduringsleep", "0",
 cvar_t sv_clmovement_enable = {0, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"};
 cvar_t sv_clmovement_minping = {0, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"};
 cvar_t sv_clmovement_minping_disabletime = {0, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"};
-cvar_t sv_clmovement_waitforinput = {0, "sv_clmovement_waitforinput", "16", "when a client does not send input for this many frames, force them to move anyway (unlike QuakeWorld)"};
+cvar_t sv_clmovement_waitforinput = {0, "sv_clmovement_waitforinput", "4", "when a client does not send input for this many frames, force them to move anyway (unlike QuakeWorld)"};
 cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
 cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"};
 cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
@@ -147,6 +148,10 @@ cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singlepla
 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
 
+cvar_t sv_autodemo_perclient = {CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match)"};
+cvar_t sv_autodemo_perclient_nameformat = {CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the IP address + port number, and the client number, separated by underscores" };
+
+
 server_t sv;
 server_static_t svs;
 
@@ -417,6 +422,9 @@ void SV_Init (void)
        }
        Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
 
+       Cvar_RegisterVariable (&sv_autodemo_perclient);
+       Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat);
+
        // any special defaults for gamemodes go here
        if (gamemode == GAME_HIPNOTIC)
        {
@@ -586,7 +594,7 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v
        }
        else
                MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
-       if (field_mask & SND_LARGESOUND)
+       if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2)
                MSG_WriteShort (&sv.datagram, sound_num);
        else
                MSG_WriteByte (&sv.datagram, sound_num);
@@ -691,6 +699,9 @@ void SV_SendServerinfo (client_t *client)
        // LordHavoc: clear entityframe tracking
        client->latestframenum = 0;
 
+       // initialize the movetime, so a speedhack can't make use of the time before this client joined
+       client->cmd.time = sv.time;
+
        if (client->entitydatabase)
                EntityFrame_FreeDatabase(client->entitydatabase);
        if (client->entitydatabase4)
@@ -701,7 +712,7 @@ void SV_SendServerinfo (client_t *client)
        memset(client->stats, 0, sizeof(client->stats));
        memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
 
-       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
+       if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
        {
                if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
                        client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
@@ -797,6 +808,28 @@ void SV_SendServerinfo (client_t *client)
        client->num_pings = 0;
 #endif
        client->ping = 0;
+
+       SV_StopDemoRecording(client); // to split up demos into different files
+       if(sv_autodemo_perclient.integer && client->netconnection)
+       {
+               char demofile[MAX_OSPATH];
+               char levelname[MAX_QPATH];
+               char ipaddress[MAX_QPATH];
+               size_t i;
+
+               // start a new demo file
+               strlcpy(levelname, FS_FileWithoutPath(sv.worldmodel->name), sizeof(levelname));
+               if (strrchr(levelname, '.'))
+                       *(strrchr(levelname, '.')) = 0;
+
+               LHNETADDRESS_ToString(&(client->netconnection->peeraddress), ipaddress, sizeof(ipaddress), true);
+               for(i = 0; ipaddress[i]; ++i)
+                       if(!isalnum(ipaddress[i]))
+                               ipaddress[i] = '-';
+               dpsnprintf (demofile, sizeof(demofile), "%s_%s_%s_%d.dem", Sys_TimeString (sv_autodemo_perclient_nameformat.string), levelname, ipaddress, PRVM_NUM_FOR_EDICT(client->edict));
+
+               SV_StartDemoRecording(client, demofile, -1);
+       }
 }
 
 /*
@@ -1266,7 +1299,7 @@ static void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, size
        VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv.writeentitiestoclient_testeye);
        sv.writeentitiestoclient_pvsbytes = 0;
        if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
-               sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv.writeentitiestoclient_testeye, 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs));
+               sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv.writeentitiestoclient_testeye, 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), false);
 
        sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
 
@@ -1415,7 +1448,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        {
                if (ent->fields.server->punchangle[i])
                        bits |= (SU_PUNCH1<<i);
-               if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
+               if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
                        if (punchvector[i])
                                bits |= (SU_PUNCHVEC1<<i);
                if (ent->fields.server->velocity[i])
@@ -1467,7 +1500,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        statsf[STAT_FRAGLIMIT] = fraglimit.value;
        statsf[STAT_TIMELIMIT] = timelimit.value;
 
-       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
        {
                if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
                bits |= SU_ITEMS;
@@ -1503,7 +1536,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        {
                if (bits & (SU_PUNCH1<<i))
                {
-                       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+                       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
                                MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
                        else
                                MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
@@ -1517,7 +1550,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                }
                if (bits & (SU_VELOCITY1<<i))
                {
-                       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+                       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
                                MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
                        else
                                MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
@@ -1545,14 +1578,19 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                if (bits & SU_VIEWZOOM)
                        MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
        }
-       else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+       else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
        {
                if (bits & SU_WEAPONFRAME)
                        MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
                if (bits & SU_ARMOR)
                        MSG_WriteByte (msg, stats[STAT_ARMOR]);
                if (bits & SU_WEAPON)
-                       MSG_WriteByte (msg, stats[STAT_WEAPON]);
+               {
+                       if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+                               MSG_WriteShort (msg, stats[STAT_WEAPON]);
+                       else
+                               MSG_WriteByte (msg, stats[STAT_WEAPON]);
+               }
                MSG_WriteShort (msg, stats[STAT_HEALTH]);
                MSG_WriteByte (msg, stats[STAT_AMMO]);
                MSG_WriteByte (msg, stats[STAT_SHELLS]);
@@ -1659,7 +1697,7 @@ static void SV_SendClientDatagram (client_t *client)
                maxsize = sizeof(sv_sendclientdatagram_buf);
                maxsize2 = sizeof(sv_sendclientdatagram_buf);
        }
-       else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+       else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
        {
                // no packet size limit support on older protocols because DP1-4 kick
                // the client off if they overflow, and quake protocol shows less than
@@ -1755,6 +1793,12 @@ static void SV_SendClientDatagram (client_t *client)
                        SZ_Write (&msg, data, downloadsize);
        }
 
+       // reliable only if none is in progress
+       if(client->sendsignon != 2 && !client->netconnection->sendMessageLength)
+               SV_WriteDemoMessage(client, &(client->netconnection->message));
+       // unreliable
+       SV_WriteDemoMessage(client, &msg);
+
 // send the datagram
        NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->sendsignon == 2);
        if (client->sendsignon == 1 && !client->netconnection->message.cursize)
@@ -1797,6 +1841,7 @@ static void SV_UpdateToReliableMessages (void)
                        MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
                        MSG_WriteByte (&sv.reliable_datagram, i);
                        MSG_WriteString (&sv.reliable_datagram, host_client->name);
+                       SV_WriteNetnameIntoDemo(host_client);
                }
 
                // DP_SV_CLIENTCOLORS
@@ -2047,7 +2092,7 @@ SV_ModelIndex
 */
 int SV_ModelIndex(const char *s, int precachemode)
 {
-       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
+       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_MODELS);
        char filename[MAX_QPATH];
        if (!s || !*s)
                return 0;
@@ -2061,7 +2106,7 @@ int SV_ModelIndex(const char *s, int precachemode)
                {
                        if (precachemode)
                        {
-                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
+                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
                                {
                                        Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
                                        return 0;
@@ -2096,7 +2141,7 @@ SV_SoundIndex
 */
 int SV_SoundIndex(const char *s, int precachemode)
 {
-       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
+       int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_SOUNDS);
        char filename[MAX_QPATH];
        if (!s || !*s)
                return 0;
@@ -2110,7 +2155,7 @@ int SV_SoundIndex(const char *s, int precachemode)
                {
                        if (precachemode)
                        {
-                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
+                               if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
                                {
                                        Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
                                        return 0;
@@ -2166,7 +2211,7 @@ int SV_ParticleEffectIndex(const char *name)
                                argc = 0;
                                for (;;)
                                {
-                                       if (!COM_ParseToken_Simple(&text, true) || !strcmp(com_token, "\n"))
+                                       if (!COM_ParseToken_Simple(&text, true, false) || !strcmp(com_token, "\n"))
                                                break;
                                        if (argc < 16)
                                        {
@@ -2258,7 +2303,11 @@ static void SV_CreateBaseline (void)
 
                large = false;
                if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
+               {
                        large = true;
+                       if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+                               large = false;
+               }
 
                // add to the message
                if (large)
@@ -2272,6 +2321,11 @@ static void SV_CreateBaseline (void)
                        MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
                        MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
                }
+               else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+               {
+                       MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
+                       MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
+               }
                else
                {
                        MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
@@ -2534,7 +2588,7 @@ void SV_SpawnServer (const char *server)
        Mod_PurgeUnused();
 
 // create a baseline for more efficient communications
-       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
+       if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
                SV_CreateBaseline ();
 
 // send serverinfo to all connected clients, and set up botclients coming back from a level change
@@ -2727,6 +2781,8 @@ static void SV_VM_Setup(void)
                prog->limit_edicts = 2048; // guessing
        else if (sv.protocol == PROTOCOL_NEHAHRAMOVIE)
                prog->limit_edicts = 2048; // guessing!
+       else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+               prog->limit_edicts = 4096; // guessing!
        else
                prog->limit_edicts = MAX_EDICTS;
        prog->reserved_edicts = svs.maxclients;