initial commit
All checks were successful
CI / build (push) Successful in 32s
CI / release (push) Successful in 32s
CI / lint (push) Successful in 30s

This commit is contained in:
Kamal Tufekcic 2026-07-05 13:28:35 +03:00
commit d701598350
67 changed files with 9351 additions and 0 deletions

View file

@ -0,0 +1,72 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using Microsoft.Extensions.Logging;
using Outnumbered.Config;
namespace Outnumbered;
// Entry point. The plugin is a sealed partial class split by concern across files
// (Persistence.cs, Commands.cs, ...) — cookbook §0.
public sealed partial class OutnumberedPlugin : BasePlugin, IPluginConfig<OutnumberedConfig>
{
public override string ModuleName => "Outnumbered";
public override string ModuleVersion => "1.0.0-modes";
public override string ModuleAuthor => "snake";
public override string ModuleDescription => "Players-vs-bots RPG / perk mod.";
public OutnumberedConfig Config { get; set; } = new();
public void OnConfigParsed(OutnumberedConfig config) => Config = config; // MUST assign (cookbook §0)
// True between Load and Unload. Untracked one-shot AddTimer/NextFrame callbacks (SetupMap, the draft auto-pop, the
// changelevel) check this so a hot-reload/unload landing inside their delay window no-ops instead of firing against a
// torn-down instance. The REPEAT timers are killed explicitly in their Shutdown_*; this guards the deferred one-shots.
private bool _live;
public override void Load(bool hotReload)
{
Initialize_Database(hotReload);
Initialize_Driver();
Initialize_Handicap(); // structural guard: HandicapOverride mirrors HandicapConfig (fail-loud at load)
Initialize_Stats();
Initialize_Abilities();
Initialize_Effects(); // survival burn-DoT tick (no-op outside survival)
Initialize_Hud();
Initialize_Shop();
Initialize_Ranks();
Initialize_Feel();
Initialize_Api(); // the local UDS status/balance/top API — last: it reads the driver + effective handicap
RegisterListener<Listeners.OnTick>(OnTick_All); // ONE per-tick roster walk fanning out to the subsystems
RegisterSkillCommands(); // !s1..!sN direct skill-buy
RegisterAbilityCommands(); // !ability1..!abilityN bindable casts
_live = true;
Logger.LogInformation("Outnumbered loaded (mode driver: {Mode}) — persistence + stats + progression + handicap + abilities + HUD + shop.", _driver.Id);
}
// ONE per-tick roster walk shared by all per-tick subsystems: Utilities.GetPlayers() allocates a List, so materializing
// it once and fanning out (each subsystem keeps its own Enabled gate + throttle counter) avoids 3 extra full-roster
// scans + List allocs per tick.
private void OnTick_All()
{
var players = Utilities.GetPlayers();
OnTick_Abilities(players);
OnTick_Hud(players);
OnTick_Shop(players);
OnTick_Feel(players);
}
public override void Unload(bool hotReload)
{
_live = false; // make any in-flight one-shot timer/NextFrame callback a no-op
RemoveListener<Listeners.OnTick>(OnTick_All);
Shutdown_Api(); // reverse init order: stop serving (and unlink the socket) before the subsystems it reads tear down
Shutdown_Feel();
Shutdown_Ranks();
Shutdown_Shop();
Shutdown_Hud();
Shutdown_Abilities();
Shutdown_Effects();
Shutdown_Stats();
Shutdown_Driver();
Shutdown_Database();
}
}