#include "server.h"
game_export_t *ge;
void PF_Unicast(edict_t *ent, bool reliable) {
int p;
client_t *client;
if(!ent)
return;
p = NUM_FOR_EDICT(ent);
if(p < 1 || p > maxclients->value)
return;
client = svs.clients + (p - 1);
if(reliable)
SZ_Write(&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
else
SZ_Write(&client->datagram, sv.multicast.data, sv.multicast.cursize);
SZ_Clear(&sv.multicast);
}
void PF_dprintf(char *fmt, ...) {
char msg[1024];
va_list argptr;
va_start(argptr, fmt);
vsprintf(msg, sizeof(msg), fmt, argptr);
va_end(argptr);
Com_Printf("%s", msg);
}
void PF_cprintf(edict_t *ent, int level, char *fmt, ...) {
char msg[1024];
va_list argptr;
int n;
if(ent) {
n = NUM_FOR_EDICT(ent);
if(n < 1 || n > maxclients->value)
Com_Error(ERR_DROP, "cprintf to a non-client");
}
va_start(argptr, fmt);
vsprintf(msg, sizeof(msg), fmt, argptr);
va_end(argptr);
if(ent)
SV_ClientPrintf(svs.clients + (n - 1), level, "%s", msg);
else
Com_Printf("%s", msg);
}
void PF_centerprintf(edict_t *ent, char *fmt, ...) {
char msg[1024];
va_list argptr;
int n;
n = NUM_FOR_EDICT(ent);
if(n < 1 || n > maxclients->value)
return;
va_start(argptr, fmt);
vsprintf(msg, sizeof(msg), fmt, argptr);
va_end(argptr);
MSG_WriteByte(&sv.multicast, svc_centerprint);
MSG_WriteString(&sv.multicast, msg);
PF_Unicast(ent, true);
}
void PF_error(char *fmt, ...) {
char msg[1024];
va_list argptr;
va_start(argptr, fmt);
vsprintf(msg, sizeof(msg), fmt, argptr);
va_end(argptr);
Com_Error(ERR_DROP, "Game Error: %s", msg);
}
void PF_setmodel(edict_t *ent, char *name) {
int i;
cmodel_t *mod;
if(!name)
Com_Error(ERR_DROP, "PF_setmodel: NULL");
int name_len = strlen(name);
if(name[0] == '*') {
ent->s.modelindex = ent->s.cmodel_index + 1;
ent->s.modelindex2 = atoi(name + 1);
mod = CM_InlineModel(ent->s.cmodel_index, name);
VectorCopy(mod->mins, ent->mins);
VectorCopy(mod->maxs, ent->maxs);
SV_LinkEdict(ent);
} else if(strncmp(name + name_len - 4, ".bsp", 4) == 0) {
unsigned int checksum;
sv.models[ent->s.cmodel_index][0] = CM_LoadMap(ent->s.cmodel_index, name, false, &checksum);
sprintf(sv.configstrings[CS_MODELS + ent->s.cmodel_index + 1], MAX_QPATH, "%s;%i", name, checksum);
for(int k = 1; k < CM_NumInlineModels(ent->s.cmodel_index); k++) {
char inline_name[6];
sprintf(inline_name, sizeof(inline_name), "*%i", k);
sv.models[ent->s.cmodel_index][k] = CM_InlineModel(ent->s.cmodel_index, inline_name);
}
ge->SpawnEntities(ent->s.cmodel_index, sv.name, CM_EntityString(ent->s.cmodel_index), NULL);
} else {
i = SV_ModelIndex(name);
ent->s.modelindex = i;
}
}
void PF_Configstring(int index, char *val) {
if(index < 0 || index >= MAX_CONFIGSTRINGS)
Com_Error(ERR_DROP, "configstring: bad index %i\n", index);
if(!val)
val = "";
strcpy(sv.configstrings[index], val);
if(sv.state != ss_loading) { SZ_Clear(&sv.multicast);
MSG_WriteChar(&sv.multicast, svc_configstring);
MSG_WriteShort(&sv.multicast, index);
MSG_WriteString(&sv.multicast, val);
SV_Multicast(CMODEL_A, vec3_origin, MULTICAST_ALL_R);
}
}
void PF_WriteChar(int c) { MSG_WriteChar(&sv.multicast, c); }
void PF_WriteByte(int c) { MSG_WriteByte(&sv.multicast, c); }
void PF_WriteShort(int c) { MSG_WriteShort(&sv.multicast, c); }
void PF_WriteLong(int c) { MSG_WriteLong(&sv.multicast, c); }
void PF_WriteFloat(float f) { MSG_WriteFloat(&sv.multicast, f); }
void PF_WriteString(char *s) { MSG_WriteString(&sv.multicast, s); }
void PF_WritePos(vec3_t pos) { MSG_WritePos(&sv.multicast, pos); }
void PF_WriteDir(vec3_t dir) { MSG_WriteDir(&sv.multicast, dir); }
void PF_WriteAngle(float f) { MSG_WriteAngle(&sv.multicast, f); }
bool PF_inPVS(int cmodel_index, vec3_t p1, vec3_t p2) {
int leafnum;
int cluster;
int area1, area2;
byte *mask;
leafnum = CM_PointLeafnum(cmodel_index, p1);
cluster = CM_LeafCluster(cmodel_index, leafnum);
area1 = CM_LeafArea(cmodel_index, leafnum);
mask = CM_ClusterPVS(cmodel_index, cluster);
leafnum = CM_PointLeafnum(cmodel_index, p2);
cluster = CM_LeafCluster(cmodel_index, leafnum);
area2 = CM_LeafArea(cmodel_index, leafnum);
if(mask && (!(mask[cluster >> 3] & (1 << (cluster & 7)))))
return false;
if(!CM_AreasConnected(cmodel_index, area1, area2))
return false; return true;
}
bool PF_inPHS(int cmodel_index, vec3_t p1, vec3_t p2) {
int leafnum;
int cluster;
int area1, area2;
byte *mask;
leafnum = CM_PointLeafnum(cmodel_index, p1);
cluster = CM_LeafCluster(cmodel_index, leafnum);
area1 = CM_LeafArea(cmodel_index, leafnum);
mask = CM_ClusterPHS(cmodel_index, cluster);
leafnum = CM_PointLeafnum(cmodel_index, p2);
cluster = CM_LeafCluster(cmodel_index, leafnum);
area2 = CM_LeafArea(cmodel_index, leafnum);
if(mask && (!(mask[cluster >> 3] & (1 << (cluster & 7)))))
return false; if(!CM_AreasConnected(cmodel_index, area1, area2))
return false;
return true;
}
void PF_StartSound(edict_t *entity, int channel, int sound_num, float volume, float attenuation, float timeofs) {
if(!entity)
return;
SV_StartSound(NULL, entity, channel, sound_num, volume, attenuation, timeofs);
}
void SV_ShutdownGameProgs(void) {
if(!ge)
return;
ge->Shutdown();
Sys_UnloadGame();
ge = NULL;
}
static void SV_SetAreaPortalState(int cmodel_index, int portal_num, bool open) {
CM_SetAreaPortalState(cmodel_index, portal_num, open);
}
static bool SV_AreasConnected(int cmodel_index, int area1, int area2) {
return CM_AreasConnected(cmodel_index, area1, area2);
}
void SCR_DebugGraph(float value, int color);
void SV_InitGameProgs(void) {
game_import_t import;
if(ge)
SV_ShutdownGameProgs();
import.multicast = SV_Multicast;
import.unicast = PF_Unicast;
import.bprintf = SV_BroadcastPrintf;
import.dprintf = PF_dprintf;
import.client_printf = PF_cprintf;
import.centerprintf = PF_centerprintf;
import.error = PF_error;
import.linkentity = SV_LinkEdict;
import.unlinkentity = SV_UnlinkEdict;
import.BoxEdicts = SV_AreaEdicts;
import.trace = SV_Trace;
import.pointcontents = SV_PointContents;
import.setmodel = PF_setmodel;
import.inPVS = PF_inPVS;
import.inPHS = PF_inPHS;
import.Pmove = Pmove;
import.modelindex = SV_ModelIndex;
import.soundindex = SV_SoundIndex;
import.imageindex = SV_ImageIndex;
import.configstring = PF_Configstring;
import.sound = PF_StartSound;
import.positioned_sound = SV_StartSound;
import.WriteChar = PF_WriteChar;
import.WriteByte = PF_WriteByte;
import.WriteShort = PF_WriteShort;
import.WriteLong = PF_WriteLong;
import.WriteFloat = PF_WriteFloat;
import.WriteString = PF_WriteString;
import.WritePosition = PF_WritePos;
import.WriteDir = PF_WriteDir;
import.WriteAngle = PF_WriteAngle;
import.TagMalloc = Z_TagMalloc;
import.TagFree = Z_Free;
import.FreeTags = Z_FreeTags;
import.cvar = Cvar_Get;
import.cvar_set = Cvar_Set;
import.cvar_forceset = Cvar_ForceSet;
import.argc = Cmd_Argc;
import.argv = Cmd_Argv;
import.args = Cmd_Args;
import.AddCommandString = Cbuf_AddText;
import.DebugGraph = SCR_DebugGraph;
import.SetAreaPortalState = SV_SetAreaPortalState;
import.AreasConnected = SV_AreasConnected;
ge = (game_export_t *)Sys_GetGameAPI(&import);
if(!ge)
Com_Error(ERR_DROP, "failed to load game DLL");
if(ge->apiversion != GAME_API_VERSION)
Com_Error(ERR_DROP, "game is version %i, not %i", ge->apiversion, GAME_API_VERSION);
ge->Init();
}