/
noire-dev
/
SourceTech
Обзор
Документация
Войти
/
noire-dev
/
SourceTech
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
sourcetech
code/server/sv_bot.c
453 строки
11 KB
noire-dev
Update: 2025-12-21 16:14 powersaving and clean
21 дек 2025, 07:14
21 дек 2025, 07:14
05bd062
Код
Авторство
О чём код?
/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Quake III Arena source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Quake III Arena source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // sv_bot.c #include "server.h" #include "../botlib/botlib.h" typedef struct bot_debugpoly_s { int inuse; int color; int numPoints; vec3_t points[128]; } bot_debugpoly_t; static bot_debugpoly_t *debugpolygons; static int bot_maxdebugpolys; extern botlib_export_t *botlib_export; int bot_enable; /* ================== SV_BotAllocateClient ================== */ int SV_BotAllocateClient( void ) { int i; client_t *cl; // find a client slot for ( i = 0, cl = svs.clients; i < sv.maxclients; i++, cl++ ) { if ( cl->state == CS_FREE ) { break; } } if ( i == sv.maxclients ) { return -1; } cl->gentity = SV_GentityNum( i ); cl->gentity->s.number = i; cl->state = CS_ACTIVE; cl->lastPacketTime = svs.time; cl->snapshotMsec = 1000 / sv_fps->integer; cl->netchan.remoteAddress.type = NA_BOT; cl->rate = 0; return i; } /* ================== SV_BotFreeClient ================== */ void SV_BotFreeClient( int clientNum ) { client_t *cl; if ( (unsigned) clientNum >= sv.maxclients ) { Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum ); } cl = &svs.clients[clientNum]; cl->state = CS_FREE; cl->name[0] = '\0'; if ( cl->gentity ) { cl->gentity->r.svFlags &= ~SVF_BOT; } } /* ================== BotImport_Print ================== */ static __attribute__ ((format (printf, 2, 3))) void QDECL BotImport_Print(int type, const char *fmt, ...) { char str[2048]; va_list ap; va_start(ap, fmt); Q_vsnprintf(str, sizeof(str), fmt, ap); va_end(ap); switch(type) { case PRT_MESSAGE: { Com_Printf("%s", str); break; } case PRT_WARNING: { Com_Printf(S_COLOR_YELLOW "Warning: %s", str); break; } case PRT_ERROR: { Com_Printf(S_COLOR_RED "Error: %s", str); break; } case PRT_FATAL: { Com_Printf(S_COLOR_RED "Fatal: %s", str); break; } case PRT_EXIT: { Com_Error(ERR_DROP, S_COLOR_RED "Exit: %s", str); break; } default: { Com_Printf("unknown print type\n"); break; } } } /* ================== BotImport_Trace ================== */ static void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) { trace_t trace; SV_Trace(&trace, start, mins, maxs, end, passent, contentmask); //copy the trace information bsptrace->allsolid = trace.allsolid; bsptrace->startsolid = trace.startsolid; bsptrace->fraction = trace.fraction; VectorCopy(trace.endpos, bsptrace->endpos); bsptrace->plane.dist = trace.plane.dist; VectorCopy(trace.plane.normal, bsptrace->plane.normal); bsptrace->plane.signbits = trace.plane.signbits; bsptrace->plane.type = trace.plane.type; bsptrace->surface.value = 0; bsptrace->surface.flags = trace.surfaceFlags; bsptrace->ent = trace.entityNum; bsptrace->exp_dist = 0; bsptrace->sidenum = 0; bsptrace->contents = 0; } /* ================== BotImport_EntityTrace ================== */ static void BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) { trace_t trace; SV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask); //copy the trace information bsptrace->allsolid = trace.allsolid; bsptrace->startsolid = trace.startsolid; bsptrace->fraction = trace.fraction; VectorCopy(trace.endpos, bsptrace->endpos); bsptrace->plane.dist = trace.plane.dist; VectorCopy(trace.plane.normal, bsptrace->plane.normal); bsptrace->plane.signbits = trace.plane.signbits; bsptrace->plane.type = trace.plane.type; bsptrace->surface.value = 0; bsptrace->surface.flags = trace.surfaceFlags; bsptrace->ent = trace.entityNum; bsptrace->exp_dist = 0; bsptrace->sidenum = 0; bsptrace->contents = 0; } /* ================== BotImport_PointContents ================== */ static int BotImport_PointContents(vec3_t point) { return SV_PointContents(point, -1); } /* ================== BotImport_inPVS ================== */ static int BotImport_inPVS(vec3_t p1, vec3_t p2) { return SV_inPVS (p1, p2); } /* ================== BotImport_BSPEntityData ================== */ static char *BotImport_BSPEntityData(void) { return CM_EntityString(); } /* ================== BotImport_BSPModelMinsMaxsOrigin ================== */ static void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) { clipHandle_t h; vec3_t mins, maxs; float max; int i; h = CM_InlineModel(modelnum); CM_ModelBounds(h, mins, maxs); //if the model is rotated if ((angles[0] || angles[1] || angles[2])) { // expand for rotation max = RadiusFromBounds(mins, maxs); for (i = 0; i < 3; i++) { mins[i] = -max; maxs[i] = max; } } if (outmins) VectorCopy(mins, outmins); if (outmaxs) VectorCopy(maxs, outmaxs); if (origin) VectorClear(origin); } /* ================== BotImport_GetMemory ================== */ static void *BotImport_GetMemory(int size) { void *ptr; ptr = Z_TagMalloc( size, TAG_BOTLIB ); return ptr; } /* ================== BotImport_FreeMemory ================== */ static void BotImport_FreeMemory(void *ptr) { Z_Free(ptr); } /* ================= BotImport_HunkAlloc ================= */ static void *BotImport_HunkAlloc( int size ) { return Hunk_Alloc( size ); } /* ================== SV_BotClientCommand ================== */ static void BotClientCommand( int client, const char *command ) { if ( (unsigned) client < sv.maxclients ) { SV_ExecuteClientCommand( &svs.clients[client], command ); } } /* ================== SV_BotFrame ================== */ void SV_BotFrame( int time ) { if (!bot_enable) return; if (!gvm) return; VM_Call( gvm, 1, BOTAI_START_FRAME, time ); } /* =============== SV_BotLibSetup =============== */ int SV_BotLibSetup( void ) { if (!bot_enable) return 0; if ( !botlib_export ) { Com_Printf( S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n" ); return -1; } return botlib_export->BotLibSetup(); } /* =============== SV_ShutdownBotLib Called when either the entire server is being killed, or it is changing to a different game directory. =============== */ int SV_BotLibShutdown( void ) { if ( !botlib_export ) { return -1; } return botlib_export->BotLibShutdown(); } /* ================== SV_BotInitCvars ================== */ void SV_BotInitCvars(void) { Cvar_Get("bot_enable", "1", 0); //enable the bot Cvar_Get("bot_developer", "0", CVAR_CHEAT); //bot developer mode Cvar_Get("bot_debug", "0", CVAR_CHEAT); //enable bot debugging Cvar_Get("bot_maxdebugpolys", "2", 0); //maximum number of debug polys Cvar_Get("bot_groundonly", "1", 0); //only show ground faces of areas Cvar_Get("bot_reachability", "0", 0); //show all reachabilities to other areas Cvar_Get("bot_visualizejumppads", "0", CVAR_CHEAT); //show jumppads Cvar_Get("bot_forceclustering", "0", 0); //force cluster calculations Cvar_Get("bot_forcereachability", "0", 0); //force reachability calculations Cvar_Get("bot_forcewrite", "0", 0); //force writing aas file Cvar_Get("bot_aasoptimize", "0", 0); //no aas file optimisation Cvar_Get("bot_saveroutingcache", "0", 0); //save routing cache Cvar_Get("bot_thinktime", "100", 0); //msec the bots thinks Cvar_Get("bot_reloadcharacters", "0", 0); //reload the bot characters each time Cvar_Get("bot_testichat", "0", 0); //test ichats Cvar_Get("bot_testrchat", "0", 0); //test rchats Cvar_Get("bot_testsolid", "0", CVAR_CHEAT); //test for solid areas Cvar_Get("bot_testclusters", "0", CVAR_CHEAT); //test the AAS clusters Cvar_Get("bot_fastchat", "0", 0); //fast chatting bots Cvar_Get("bot_nochat", "0", 0); //disable chats Cvar_Get("bot_pause", "0", CVAR_CHEAT); //pause the bots thinking Cvar_Get("bot_report", "0", CVAR_CHEAT); //get a full report in ctf Cvar_Get("bot_grapple", "0", 0); //enable grapple Cvar_Get("bot_rocketjump", "1", 0); //enable rocket jumping Cvar_Get("bot_challenge", "0", 0); //challenging bot } /* ================== SV_BotInitBotLib ================== */ void SV_BotInitBotLib(void) { botlib_import_t botlib_import; if (debugpolygons) Z_Free(debugpolygons); bot_maxdebugpolys = 2; debugpolygons = Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys); botlib_import.Print = BotImport_Print; botlib_import.Trace = BotImport_Trace; botlib_import.EntityTrace = BotImport_EntityTrace; botlib_import.PointContents = BotImport_PointContents; botlib_import.inPVS = BotImport_inPVS; botlib_import.BSPEntityData = BotImport_BSPEntityData; botlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin; botlib_import.BotClientCommand = BotClientCommand; //memory management botlib_import.GetMemory = BotImport_GetMemory; botlib_import.FreeMemory = BotImport_FreeMemory; botlib_import.AvailableMemory = Z_AvailableMemory; botlib_import.HunkAlloc = BotImport_HunkAlloc; // file system access botlib_import.FS_FOpenFile = FS_FOpenFileByMode; botlib_import.FS_Read = FS_Read; botlib_import.FS_Write = FS_Write; botlib_import.FS_FCloseFile = FS_FCloseFile; botlib_import.FS_Seek = FS_Seek; botlib_import.Sys_Milliseconds = Sys_Milliseconds; botlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import ); assert(botlib_export); // somehow we end up with a zero import. } // // * * * BOT AI CODE IS BELOW THIS POINT * * * // /* ================== SV_BotGetConsoleMessage ================== */ int SV_BotGetConsoleMessage( int client, char *buf, int size ) { if ( (unsigned) client < sv.maxclients ) { client_t* cl; int index; cl = &svs.clients[client]; cl->lastPacketTime = svs.time; if ( cl->reliableAcknowledge == cl->reliableSequence ) { return qfalse; } cl->reliableAcknowledge++; index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ); if ( !cl->reliableCommands[index][0] ) { return qfalse; } Q_strncpyz( buf, cl->reliableCommands[index], size ); return qtrue; } else { return qfalse; } } /* ================== SV_BotGetSnapshotEntity ================== */ int SV_BotGetSnapshotEntity( int client, int sequence ) { if ( (unsigned) client < sv.maxclients ) { const client_t* cl = &svs.clients[client]; const clientSnapshot_t* frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; if ( (unsigned) sequence >= frame->num_entities ) { return -1; } return frame->ents[sequence]->number; } else { return -1; } }