Skip to content

Commit

Permalink
Replace the helper command with a FreezeBot function
Browse files Browse the repository at this point in the history
  • Loading branch information
lengran committed Mar 17, 2024
1 parent f20fbeb commit d73be97
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 106 deletions.
205 changes: 105 additions & 100 deletions OpenPrefirePrac.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ public class OpenPrefirePrac : BasePlugin
public override string ModuleName => "Open Prefire Prac";
public override string ModuleVersion => "0.0.15";
public override string ModuleAuthor => "Lengran";
public override string ModuleDescription => "A plugin for practicing prefire routes in CS:GO. https://github.com/lengran/OpenPrefirePrac";
public override string ModuleDescription => "A plugin for practicing prefire routes in CS2. https://github.com/lengran/OpenPrefirePrac";

private readonly Dictionary<CCSPlayerController, PlayerStatus> _playerStatuses = new();

private readonly Dictionary<CCSPlayerController, CCSPlayerController> _mastersOfBots = new();
private readonly Dictionary<CCSPlayerController, CCSPlayerController> _ownerOfBots = new(); // Map: bots -> owners.

private readonly Dictionary<string, int> _practiceNameToId = new();

Expand All @@ -38,7 +38,7 @@ public class OpenPrefirePrac : BasePlugin
public OpenPrefirePrac()
{
_playerCount = 0;
_translator = new Translator(Localizer, ModuleDirectory, CultureInfo.CurrentCulture.Name);
_translator = new Translator(Localizer, ModuleDirectory, CultureInfo.CurrentCulture.Name); // This doesn't work. The ModuleDirectory is not assigned now. Put it here to get rid of the warning of not initialized objects.
}

public override void Load(bool hotReload)
Expand All @@ -53,7 +53,7 @@ public override void Load(bool hotReload)
if (hotReload)
{
// Clear status registers
_mastersOfBots.Clear();
_ownerOfBots.Clear();
_practiceNameToId.Clear();
_practiceEnabled.Clear();
_practices.Clear();
Expand Down Expand Up @@ -141,7 +141,7 @@ public void OnMapStartHandler(string map)
for (var i = 0; i < mapDirectories.Count; i++)
{
var mapPath = mapDirectories[i].Substring(mapDirectories[i].LastIndexOf(Path.DirectorySeparatorChar) + 1);
Console.WriteLine($"[OpenPrefirePrac] Map folder for map {mapPath} found.");
// Console.WriteLine($"[OpenPrefirePrac] Map folder for map {mapPath} found.");
_availableMaps.Add(mapPath);

if (mapPath.Equals(_mapName))
Expand All @@ -166,64 +166,62 @@ public HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
{
var playerOrBot = @event.Userid;

// For bots, set them up.
if (!playerOrBot.IsValid || playerOrBot.IsHLTV)
{
return HookResult.Continue;
}

if (playerOrBot.IsBot)
if (playerOrBot.IsBot && _ownerOfBots.ContainsKey(playerOrBot))
{
// if there are more targets to place, move bot to next place
if (_mastersOfBots.ContainsKey(playerOrBot))
{
var master = _mastersOfBots[@event.Userid];
var targetNo = _playerStatuses[master].Progress;
var practiceIndex = _playerStatuses[master].PracticeIndex;
// For managed bots
var owner = _ownerOfBots[playerOrBot];
var targetNo = _playerStatuses[owner].Progress;
var practiceIndex = _playerStatuses[owner].PracticeIndex;

if (targetNo < _playerStatuses[master].EnabledTargets.Count)
{
_playerStatuses[master].Progress++;

MovePlayer(playerOrBot,
_practices[practiceIndex].Targets[_playerStatuses[master].EnabledTargets[targetNo]]
.IsCrouching,
_practices[practiceIndex].Targets[_playerStatuses[master].EnabledTargets[targetNo]].Position,
_practices[practiceIndex].Targets[_playerStatuses[master].EnabledTargets[targetNo]]
.Rotation);
Server.ExecuteCommand($"css_freeze_helper {playerOrBot.Slot}");
}
else
if (targetNo < _playerStatuses[owner].EnabledTargets.Count)
{
// If there are more targets to place, move bot to next place
_playerStatuses[owner].Progress++;

MovePlayer(playerOrBot,
_practices[practiceIndex].Targets[_playerStatuses[owner].EnabledTargets[targetNo]]
.IsCrouching,
_practices[practiceIndex].Targets[_playerStatuses[owner].EnabledTargets[targetNo]].Position,
_practices[practiceIndex].Targets[_playerStatuses[owner].EnabledTargets[targetNo]]
.Rotation);
// Server.ExecuteCommand($"css_freeze_helper {playerOrBot.Slot}");
Server.NextFrame(() => FreezeBot(playerOrBot));
}
else
{
// This code block is to patch the issue of extra bots.
// Explain:
// Bot B is died while Bot A is still spawning, so progress
// is not updated in time. This could cause Bot B not being
// kicked. So kick them here.
_ownerOfBots.Remove(playerOrBot);
_playerStatuses[owner].Bots.Remove(playerOrBot);
Server.ExecuteCommand($"bot_kick {playerOrBot.PlayerName}");

if (_playerStatuses[owner].Bots.Count == 0)
{
// This code block is to patch the issue of extra bots.
// Explain:
// Bot B is died while Bot A is still spawning, so progress
// is not updated in time. This could cause Bot B not being
// kicked. So kick them here.
_mastersOfBots.Remove(playerOrBot);
_playerStatuses[master].Bots.Remove(playerOrBot);
Server.ExecuteCommand($"bot_kick {playerOrBot.PlayerName}");

if (_playerStatuses[master].Bots.Count == 0)
{
// Practice finished.
master.PrintToChat(
$" {ChatColors.Green}[OpenPrefirePrac] {ChatColors.White}{_translator.Translate(master, "practice.finish")}");
ExitPrefireMode(master);
}
// Practice finished.
owner.PrintToChat(
$" {ChatColors.Green}[OpenPrefirePrac] {ChatColors.White}{_translator.Translate(owner, "practice.finish")}");
ExitPrefireMode(owner);
}
}
}
else
{
// Unmanaged player. This should not happen since hot_reload is now supported.
// For players: Set them up if they are practicing.
if (!_playerStatuses.ContainsKey(playerOrBot))
return HookResult.Continue;

if (_playerStatuses[playerOrBot].PracticeIndex < 0)
return HookResult.Continue;

SetupPrefireMode(@event.Userid);
SetupPrefireMode(playerOrBot);
}

return HookResult.Continue;
Expand All @@ -234,69 +232,63 @@ public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
{
var playerOrBot = @event.Userid;

// For bots, set them up.
if (!playerOrBot.IsValid || playerOrBot.IsHLTV)
{
return HookResult.Continue;
}

if (playerOrBot.IsBot)
if (playerOrBot.IsBot && _ownerOfBots.ContainsKey(playerOrBot))
{
if (_mastersOfBots.ContainsKey(playerOrBot))
{
var master = _mastersOfBots[playerOrBot];
var targetNo = _playerStatuses[master].Progress;
var practiceIndex = _playerStatuses[master].PracticeIndex;
// For managed bots
var owner = _ownerOfBots[playerOrBot];
var targetNo = _playerStatuses[owner].Progress;
var practiceIndex = _playerStatuses[owner].PracticeIndex;

if (targetNo >= _practices[practiceIndex].NumBots) // Bots will be killed after their first time getting spawned, so as to move them to target spots.
if (targetNo >= _practices[practiceIndex].NumBots) // Bots will be killed after their first time getting spawned, so as to move them to target spots.
{
// Award the player.
if (owner.PawnIsAlive && owner.Pawn.Value != null && _playerStatuses[owner].HealingMethod > 1)
{
// Award the player.
if (master.PawnIsAlive && master.Pawn.Value != null && _playerStatuses[master].HealingMethod > 1)
owner.GiveNamedItem("item_assaultsuit");

var currentHp = owner.Pawn.Value.Health;
switch (_playerStatuses[owner].HealingMethod)
{
master.GiveNamedItem("item_assaultsuit");

var currentHp = master.Pawn.Value.Health;
// if (healing_method_of_players[master_slot] == 2)
// current_hp = current_hp + 25;
// else
// current_hp = current_hp + 100;
switch (_playerStatuses[master].HealingMethod)
{
case 2:
currentHp = currentHp + 25;
break;
case 4:
currentHp = currentHp + 500;
break;
default:
currentHp = currentHp + 100;
break;
}
SetPlayerHealth(master, currentHp);
case 2:
currentHp = currentHp + 25;
break;
case 4:
currentHp = currentHp + 500;
break;
default:
currentHp = currentHp + 100;
break;
}
SetPlayerHealth(owner, currentHp);
}

// Print progress
master.PrintToCenter(_translator.Translate(master, "practice.progress", _playerStatuses[master].EnabledTargets.Count, _playerStatuses[master].EnabledTargets.Count - targetNo + _playerStatuses[master].Bots.Count - 1));
// Print progress
owner.PrintToCenter(_translator.Translate(owner, "practice.progress", _playerStatuses[owner].EnabledTargets.Count, _playerStatuses[owner].EnabledTargets.Count - targetNo + _playerStatuses[owner].Bots.Count - 1));
}

// Kick unnecessary bots
if (targetNo >= _playerStatuses[master].EnabledTargets.Count)
{
_mastersOfBots.Remove(playerOrBot);
_playerStatuses[master].Bots.Remove(playerOrBot);
Server.ExecuteCommand($"bot_kick {playerOrBot.PlayerName}");
// Kick unnecessary bots
if (targetNo >= _playerStatuses[owner].EnabledTargets.Count)
{
_ownerOfBots.Remove(playerOrBot);
_playerStatuses[owner].Bots.Remove(playerOrBot);
Server.ExecuteCommand($"bot_kick {playerOrBot.PlayerName}");

if (_playerStatuses[master].Bots.Count == 0)
{
// Practice finished.
master.PrintToChat($" {ChatColors.Green}[OpenPrefirePrac] {ChatColors.White}{_translator.Translate(master, "practice.finish")}");
ExitPrefireMode(master);
}
if (_playerStatuses[owner].Bots.Count == 0)
{
// Practice finished.
owner.PrintToChat($" {ChatColors.Green}[OpenPrefirePrac] {ChatColors.White}{_translator.Translate(owner, "practice.finish")}");
ExitPrefireMode(owner);
}
}
}
else
{
// For players: If some bots have already been kicked, add them back.
if (!_playerStatuses.ContainsKey(playerOrBot))
return HookResult.Continue;

Expand All @@ -306,7 +298,7 @@ public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
if (practiceIndex > -1 && numBots < _practices[practiceIndex].NumBots)
{
_playerStatuses[playerOrBot].Progress = 0;
AddBot(@event.Userid, _practices[practiceIndex].NumBots - numBots);
AddBot(playerOrBot, _practices[practiceIndex].NumBots - numBots);
}
}

Expand Down Expand Up @@ -671,7 +663,7 @@ private void RemoveBots(CCSPlayerController player)
{
Console.WriteLine($"[OpenPrefirePrac] Trying to kick an invalid bot.");
}
_mastersOfBots.Remove(bot);
_ownerOfBots.Remove(bot);
}
_playerStatuses[player].Bots.Clear();
_playerStatuses[player].Progress = 0;
Expand Down Expand Up @@ -705,7 +697,7 @@ private void AddBot(CCSPlayerController player, int numberOfBots)
if (!tempPlayer.UserId.HasValue) continue;
// Check if it belongs to someone, if so, do nothing
if (_mastersOfBots.ContainsKey(tempPlayer)) continue;
if (_ownerOfBots.ContainsKey(tempPlayer)) continue;
// If it's a newly added bot
if (numberBotToFind == 0)
Expand All @@ -717,7 +709,7 @@ private void AddBot(CCSPlayerController player, int numberOfBots)
}
_playerStatuses[player].Bots.Add(tempPlayer);
_mastersOfBots.Add(tempPlayer, player);
_ownerOfBots.Add(tempPlayer, player);
numberBotToFind--;
Expand All @@ -739,18 +731,31 @@ private void MovePlayer(CCSPlayerController player, bool crouch, Vector pos, QAn
player.PlayerPawn.Value!.Teleport(pos, ang, new Vector(0, 0, 0));
}

// FreezeBot doesn't work in Event environment, so make it a command.
[ConsoleCommand("css_freeze_helper", "Freeze a player")]
[CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)]
public void OnFreezeHelperCommand(CCSPlayerController? player, CommandInfo commandInfo)
{
var botSlot = int.Parse(commandInfo.ArgString);
var bot = new CCSPlayerController(NativeAPI.GetEntityFromIndex(botSlot + 1));
// // FreezeBot doesn't work in Event environment, so make it a command.
// [ConsoleCommand("css_freeze_helper", "Freeze a player")]
// [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)]
// public void OnFreezeHelperCommand(CCSPlayerController? player, CommandInfo commandInfo)
// {
// var botSlot = int.Parse(commandInfo.ArgString);
// var bot = new CCSPlayerController(NativeAPI.GetEntityFromIndex(botSlot + 1));

// if (
// bot is { IsValid: true, IsBot: true, IsHLTV: false, PawnIsAlive: true }
// && bot.Pawn.Value != null
// ) // && bot.Pawn.Value.LifeState == (byte)LifeState_t.LIFE_ALIVE)
// {
// bot.Pawn.Value.MoveType = MoveType_t.MOVETYPE_OBSOLETE;
// Schema.SetSchemaValue(bot.Pawn.Value.Handle, "CBaseEntity", "m_nActualMoveType", 1);
// Utilities.SetStateChanged(bot.Pawn.Value, "CBaseEntity", "m_MoveType");
// }
// }

private void FreezeBot(CCSPlayerController? bot)
{
if (
bot is { IsValid: true, IsBot: true, IsHLTV: false, PawnIsAlive: true }
&& bot.Pawn.Value != null
) // && bot.Pawn.Value.LifeState == (byte)LifeState_t.LIFE_ALIVE)
)
{
bot.Pawn.Value.MoveType = MoveType_t.MOVETYPE_OBSOLETE;
Schema.SetSchemaValue(bot.Pawn.Value.Handle, "CBaseEntity", "m_nActualMoveType", 1);
Expand Down
4 changes: 2 additions & 2 deletions PlayerStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class PlayerStatus
* 0: No healing
* 1: Init hp 500 with no healing
* 2: +25hp for each kill
* 3: +100hp for each kill
* 3: +100hp for each kill (default)
* 4: +500hp for each kill
*/
public int HealingMethod = 3;
Expand All @@ -25,7 +25,7 @@ public class PlayerStatus
public readonly Dictionary<string, int> LocalizedDifficultyNames = new();

/**
* 0: Random mode, 70% targets
* 0: Random mode, randomly spawn some targets(the spawn ratio is specified in the practice profile)
* 1: Full mode, all targets
*/
public int TrainingMode = 0;
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,9 @@ Finished practices:
TODO:

1. Create prefire profiles for all maps.
2. Draw guiding lines on the floor.
3. Improve bot logic.
4. Improve localization support (The supporting framework is done. Submitting translations is warmly welcomed.).
5. Reroute saperate logs into one gathered place for better debug experience.
2. Improve bot logic.
3. Improve localization support (The supporting framework is done. Submitting translations is warmly welcomed.).
4. Reroute saperate logs into one gathered place for better debug experience.

## Reference

Expand Down

0 comments on commit d73be97

Please sign in to comment.