- /*
- ================================================================================
- Model Precache Monitor
- --------------------------------------------------------------------------
- Purpose:
- GoldSrc (Half-Life 1.6) has a hard engine limit of 512 precached models
- per map (MAX_MODELS). When a map + its plugins (e.g. BlockMaker) exceed
- this limit, clients get silently disconnected/crashed with NO error
- message anywhere, because the overflow happens in the client's network
- delta-decoding, not in server-side game logic.
- This plugin hooks the engine's model precache function, counts every
- model precached on map start, logs each one with its index, and warns
- loudly (server console + log file) if the count approaches or exceeds
- the 512 limit. This gives you hard evidence of which maps are at risk
- and by how much, so you know exactly how many models to cut.
- Requirements:
- - AMX Mod X 1.10.x
- - Fakemeta module (ships with AMXX by default)
- Author: (generated for user diagnostic use)
- ================================================================================
- */
- #include <amxmodx>
- #include <amxmisc>
- #include <fakemeta>
- #define PLUGIN_NAME "Model Precache Monitor"
- #define PLUGIN_VERSION "1.0"
- #define PLUGIN_AUTHOR "Diagnostic Tool"
- // Hard engine limit for GoldSrc. Do not change - this is fixed by the engine.
- #define MAX_MODELS_LIMIT 512
- // Threshold at which we start warning (models remaining gets tight).
- #define WARNING_THRESHOLD 480
- new g_modelCount;
- new g_logFile[128];
- new g_mapName[64];
- // Simple growable log of precached model names for this map load.
- new g_modelNames[MAX_MODELS_LIMIT + 64][64];
- public plugin_init()
- {
- register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);
- register_concmd("model_report", "cmd_model_report", ADMIN_RCON,
- "- prints the current map's precached model count/report to console");
- }
- public plugin_precache()
- {
- // Reset counters for the new map load. plugin_precache() runs before
- // other plugins' precache in load order, but since AMXX loads plugins
- // in the order listed in plugins.ini, place this plugin FIRST in
- // plugins.ini so it hooks before BlockMaker precaches its models.
- g_modelCount = 0;
- get_mapname(g_mapName, charsmax(g_mapName));
- new dataDir[64];
- formatex(dataDir, charsmax(dataDir), "addons/amxmodx/logs/model_precache");
- // Ensure log directory exists (AMXX will create logs/ itself; this is a subfolder)
- if (!dir_exists(dataDir))
- {
- mkdir(dataDir);
- }
- formatex(g_logFile, charsmax(g_logFile), "%s/%s.log", dataDir, g_mapName);
- // Start fresh log file for this map load
- new f = fopen(g_logFile, "wt");
- if (f)
- {
- fprintf(f, "=== Model Precache Report for map: %s ===^n", g_mapName);
- fprintf(f, "Engine hard limit: %d models^n^n", MAX_MODELS_LIMIT);
- fclose(f);
- }
- // Hook the engine precache_model calls from this point forward.
- // We use a forward on the engine function via fakemeta.
- register_forward(FM_PrecacheModel, "fw_PrecacheModel");
- }
- public fw_PrecacheModel(const model[])
- {
- if (g_modelCount >= (MAX_MODELS_LIMIT + 64))
- {
- // Safety bound on our own tracking array, should never realistically hit this.
- return FMRES_IGNORED;
- }
- // Avoid double-counting exact duplicate precache calls (engine also
- // de-duplicates internally, but we mirror that so our count matches reality).
- for (new i = 0; i < g_modelCount; i++)
- {
- if (equal(g_modelNames[i], model))
- {
- return FMRES_IGNORED; // already counted, not a new index
- }
- }
- copy(g_modelNames[g_modelCount], 63, model);
- g_modelCount++;
- new f = fopen(g_logFile, "a");
- if (f)
- {
- fprintf(f, "[%03d] %s^n", g_modelCount, model);
- fclose(f);
- }
- if (g_modelCount == WARNING_THRESHOLD)
- {
- log_amx("[Model Precache Monitor] WARNING: Map '%s' has reached %d/%d precached models. Getting close to the engine limit!",
- g_mapName, g_modelCount, MAX_MODELS_LIMIT);
- server_print("[Model Precache Monitor] WARNING: %d/%d models precached on map %s",
- g_modelCount, MAX_MODELS_LIMIT, g_mapName);
- }
- if (g_modelCount == MAX_MODELS_LIMIT)
- {
- log_amx("[Model Precache Monitor] CRITICAL: Map '%s' has HIT the %d model limit. Any further precache calls WILL cause client crashes/disconnects.",
- g_mapName, MAX_MODELS_LIMIT);
- server_print("[Model Precache Monitor] CRITICAL: model limit reached on map %s! Clients will start crashing.",
- g_mapName);
- }
- return FMRES_IGNORED;
- }
- public cmd_model_report(id, level, cid)
- {
- if (!cmd_access(id, level, cid, 1))
- return PLUGIN_HANDLED;
- console_print(id, "=== Model Precache Report ===");
- console_print(id, "Map: %s", g_mapName);
- console_print(id, "Total unique models precached: %d / %d", g_modelCount, MAX_MODELS_LIMIT);
- console_print(id, "Remaining headroom: %d", MAX_MODELS_LIMIT - g_modelCount);
- console_print(id, "Full log written to: %s", g_logFile);
- if (g_modelCount >= MAX_MODELS_LIMIT)
- {
- console_print(id, "STATUS: OVER LIMIT - this map WILL crash clients.");
- }
- else if (g_modelCount >= WARNING_THRESHOLD)
- {
- console_print(id, "STATUS: WARNING - close to limit, reduce models soon.");
- }
- else
- {
- console_print(id, "STATUS: OK");
- }
- return PLUGIN_HANDLED;
- }

Pobierz program!
