+static void CLVM_begin_increase_edicts(prvm_prog_t *prog)
+{
+ // links don't survive the transition, so unlink everything
+ World_UnlinkAll(&cl.world);
+}
+
+static void CLVM_end_increase_edicts(prvm_prog_t *prog)
+{
+ int i;
+ prvm_edict_t *ent;
+
+ // link every entity except world
+ for (i = 1, ent = prog->edicts;i < prog->num_edicts;i++, ent++)
+ if (!ent->priv.server->free && !VectorCompare(PRVM_clientedictvector(ent, absmin), PRVM_clientedictvector(ent, absmax)))
+ CL_LinkEdict(ent);
+}
+
+static void CLVM_init_edict(prvm_prog_t *prog, prvm_edict_t *e)
+{
+ int edictnum = PRVM_NUM_FOR_EDICT(e);
+ entity_render_t *entrender;
+ CL_ExpandCSQCRenderEntities(edictnum);
+ entrender = cl.csqcrenderentities + edictnum;
+ e->priv.server->move = false; // don't move on first frame
+ memset(entrender, 0, sizeof(*entrender));
+ entrender->shadertime = cl.time;
+}
+
+static void CLVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed)
+{
+ entity_render_t *entrender = cl.csqcrenderentities + PRVM_NUM_FOR_EDICT(ed);
+ R_DecalSystem_Reset(&entrender->decalsystem);
+ memset(entrender, 0, sizeof(*entrender));
+ World_UnlinkEdict(ed);
+ memset(ed->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
+ VM_RemoveEdictSkeleton(prog, ed);
+ World_Physics_RemoveFromEntity(&cl.world, ed);
+ World_Physics_RemoveJointFromEntity(&cl.world, ed);
+}
+
+static void CLVM_count_edicts(prvm_prog_t *prog)
+{
+ int i;
+ prvm_edict_t *ent;
+ int active = 0, models = 0, solid = 0;
+
+ for (i=0 ; i<prog->num_edicts ; i++)
+ {
+ ent = PRVM_EDICT_NUM(i);
+ if (ent->priv.server->free)
+ continue;
+ active++;
+ if (PRVM_clientedictfloat(ent, solid))
+ solid++;
+ if (PRVM_clientedictstring(ent, model))
+ models++;
+ }
+
+ Con_Printf("num_edicts:%3i\n", prog->num_edicts);
+ Con_Printf("active :%3i\n", active);
+ Con_Printf("view :%3i\n", models);
+ Con_Printf("touch :%3i\n", solid);
+}
+
+static qboolean CLVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent)
+{
+ return true;
+}
+
+// returns true if the packet is valid, false if end of file is reached
+// used for dumping the CSQC download into demo files
+qboolean MakeDownloadPacket(const char *filename, unsigned char *data, size_t len, int crc, int cnt, sizebuf_t *buf, int protocol)
+{
+ int packetsize = buf->maxsize - 7; // byte short long
+ int npackets = ((int)len + packetsize - 1) / (packetsize);
+ char vabuf[1024];
+
+ if(protocol == PROTOCOL_QUAKEWORLD)
+ return false; // CSQC can't run in QW anyway
+
+ SZ_Clear(buf);
+ if(cnt == 0)
+ {
+ MSG_WriteByte(buf, svc_stufftext);
+ MSG_WriteString(buf, va(vabuf, sizeof(vabuf), "\ncl_downloadbegin %lu %s\n", (unsigned long)len, filename));
+ return true;
+ }
+ else if(cnt >= 1 && cnt <= npackets)
+ {
+ unsigned long thispacketoffset = (cnt - 1) * packetsize;
+ int thispacketsize = (int)len - thispacketoffset;
+ if(thispacketsize > packetsize)
+ thispacketsize = packetsize;
+
+ MSG_WriteByte(buf, svc_downloaddata);
+ MSG_WriteLong(buf, thispacketoffset);
+ MSG_WriteShort(buf, thispacketsize);
+ SZ_Write(buf, data + thispacketoffset, thispacketsize);
+
+ return true;
+ }
+ else if(cnt == npackets + 1)
+ {
+ MSG_WriteByte(buf, svc_stufftext);
+ MSG_WriteString(buf, va(vabuf, sizeof(vabuf), "\ncl_downloadfinished %lu %d\n", (unsigned long)len, crc));
+ return true;
+ }
+ return false;
+}