Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update spawn management commands / functionality #32

Merged
merged 8 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Modules/Allocators/WeaponsAllocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@ public static void Allocate(CCSPlayerController player)
// player.GiveNamedItem(CsItem.USPS);
player.GiveNamedItem(CsItem.Deagle);
}

player.GiveNamedItem(CsItem.Knife);
}
}
14 changes: 1 addition & 13 deletions Modules/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,6 @@ public static void RemoveAllWeaponsAndEntities(CCSPlayerController player)
{
continue;
}

// Don't remove a players knife
if (
weapon.Value.DesignerName == CsItem.KnifeCT.ToString()
|| weapon.Value.DesignerName == CsItem.KnifeT.ToString()
)
{
continue;
}

player.PlayerPawn.Value.RemovePlayerItem(weapon.Value);
weapon.Value.Remove();
Expand Down Expand Up @@ -266,10 +257,7 @@ public static void TerminateRound(RoundEndReason roundEndReason)

public static bool IsInRange(float range, Vector v1, Vector v2)
{
var dx = v1.X - v2.X;
var dy = v1.Y - v2.Y;

return Math.Sqrt(Math.Pow(dx, 2) + Math.Pow(dy, 2)) <= range;
return GetDistanceBetweenVectors(v1, v2) <= range;
}

public static double GetDistanceBetweenVectors(Vector v1, Vector v2)
Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ If you appreciate the project then please take the time to star the repository
- [x] Improve bombsite announcement
- [x] Queue priority for VIPs
- [x] Add autoplant
- [ ] Add a command to view the spawns for the current map
- [x] Add a command to view the spawns for the current map
- [ ] Implement better spawn management system
- [ ] Add a release zip file without spawns too

## Installation
1. Download the zip file from the [latest release](https://github.com/B3none/cs2-retakes/releases), and extract the contents into your `counterstrikesharp/plugins` directory.
Expand All @@ -37,7 +38,7 @@ This package comes with a weapon allocation system, however I recommend using **
- Yoni's Allocator: https://github.com/yonilerner/cs2-retakes-allocator
- Ravid's Allocator: https://github.com/Ravid-A/cs2-retakes-weapon-allocator

## Plugin Configuration
## Configuration
When the plugin is first loaded it will create a `retakes_config.json` file in the plugin directory. This file contains all of the configuration options for the plugin:

| Config | Description | Default | Min | Max |
Expand All @@ -53,5 +54,13 @@ When the plugin is first loaded it will create a `retakes_config.json` file in t
| ShouldBreakBreakables | Whether to break all breakable props on round start | true | false | true |
| ShouldOpenDoors | Whether to open doors on round start | true | false | true |

## Commands
| Command | Arguments | Description | Permissions |
|-----------------|-----------|----------------------------------------------------------------------|-------------|
| !showspawns | <A / B> | Show the spawns for the specified bombsite. | @css/root |
| !addspawn | <CT / T> | Adds a retakes spawn point for the bombsite spawns currently shown. | @css/root |
| !removespawn | | Removes the nearest spawn point for the bombsite currently shown. | @css/root |
| css_debugqueues | | **SERVER ONLY** Shows the current queue state in the server console. | |

## Credits
This was inspired by the [CS:GO Retakes project](https://github.com/splewis/csgo-retakes) written by [splewis](https://github.com/splewis).
207 changes: 84 additions & 123 deletions RetakesPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace RetakesPlugin;
[MinimumApiVersion(147)]
public class RetakesPlugin : BasePlugin
{
private const string Version = "1.3.4";
private const string Version = "1.3.5";

#region Plugin info
public override string ModuleName => "Retakes Plugin";
Expand Down Expand Up @@ -72,41 +72,67 @@ public override void Load(bool hotReload)
}

#region Commands
[ConsoleCommand("css_addspawn", "Adds a spawn point for retakes to the map.")]
[CommandHelper(minArgs: 2, usage: "[T/CT] [A/B] [Y/N (can be planter / default = if you are stood in a bombsite)]", whoCanExecute: CommandUsage.CLIENT_ONLY)]
[ConsoleCommand("css_showspawns", "Show the spawns for the specified bombsite.")]
[CommandHelper(minArgs: 1, usage: "[A/B]", whoCanExecute: CommandUsage.CLIENT_ONLY)]
[RequiresPermissions("@css/root")]
public void OnCommandAddSpawn(CCSPlayerController? player, CommandInfo commandInfo)
public void OnCommandShowSpawns(CCSPlayerController? player, CommandInfo commandInfo)
{
if (!Helpers.DoesPlayerHavePawn(player))
if (!Helpers.IsValidPlayer(player))
{
commandInfo.ReplyToCommand($"{LogPrefix}You must be a player.");
return;
}

var team = commandInfo.GetArg(1).ToUpper();
if (team != "T" && team != "CT")
var bombsite = commandInfo.GetArg(1).ToUpper();
if (bombsite != "A" && bombsite != "B")
{
commandInfo.ReplyToCommand($"{LogPrefix}You must specify a team [T / CT] - [Value: {team}].");
commandInfo.ReplyToCommand($"{MessagePrefix}You must specify a bombsite [A / B].");
return;
}

var bombsite = commandInfo.GetArg(2).ToUpper();
if (bombsite != "A" && bombsite != "B")
if (_mapConfig == null)
{
commandInfo.ReplyToCommand($"{LogPrefix}You must specify a bombsite [A / B] - [Value: {bombsite}].");
commandInfo.ReplyToCommand($"{MessagePrefix}Map config not loaded for some reason...");
return;
}

var canBePlanter = commandInfo.GetArg(3).ToUpper();
if (canBePlanter != "" && canBePlanter != "Y" && canBePlanter != "N")

var spawns = _mapConfig.GetSpawnsClone().Where(spawn => spawn.Bombsite == (bombsite == "A" ? Bombsite.A : Bombsite.B)).ToList();

if (spawns.Count == 0)
{
commandInfo.ReplyToCommand($"{LogPrefix}Invalid value passed to can be a planter [Y / N] - [Value: {canBePlanter}].");
commandInfo.ReplyToCommand($"{MessagePrefix}No spawns found for bombsite {bombsite}.");
return;
}

foreach (var spawn in spawns)
{
Helpers.ShowSpawn(spawn);
}

if (team != "T" && canBePlanter == "Y")
_showingSpawnsForBombsite = bombsite == "A" ? Bombsite.A : Bombsite.B;
commandInfo.ReplyToCommand($"{MessagePrefix}Showing {spawns.Count} spawns for bombsite {bombsite}.");
}

[ConsoleCommand("css_addspawn", "Adds a retakes spawn point to the map for the bombsite currently shown.")]
[CommandHelper(minArgs: 1, usage: "[T/CT]", whoCanExecute: CommandUsage.CLIENT_ONLY)]
[RequiresPermissions("@css/root")]
public void OnCommandAddSpawn(CCSPlayerController? player, CommandInfo commandInfo)
{
if (!Helpers.DoesPlayerHavePawn(player))
{
commandInfo.ReplyToCommand($"{MessagePrefix}You must be a player.");
return;
}

if (_showingSpawnsForBombsite == null)
{
commandInfo.ReplyToCommand($"{MessagePrefix}You can't add a spawn if you're not showing the spawns.");
return;
}

var team = commandInfo.GetArg(1).ToUpper();
if (team != "T" && team != "CT")
{
commandInfo.ReplyToCommand($"{LogPrefix}It looks like you tried to place a bomb planter spawn for a CT? Is this correct?");
commandInfo.ReplyToCommand($"{MessagePrefix}You must specify a team [T / CT] - [Value: {team}].");
return;
}

Expand All @@ -116,101 +142,41 @@ public void OnCommandAddSpawn(CCSPlayerController? player, CommandInfo commandIn
)
{
Team = team == "T" ? CsTeam.Terrorist : CsTeam.CounterTerrorist,
CanBePlanter = team == "T" && (canBePlanter == "Y" || player.PlayerPawn.Value.InBombZone),
Bombsite = bombsite == "A" ? Bombsite.A : Bombsite.B
CanBePlanter = team == "T" && player.PlayerPawn.Value.InBombZone,
Bombsite = (Bombsite)_showingSpawnsForBombsite
};
Helpers.ShowSpawn(spawn);

if (_mapConfig == null)
{
commandInfo.ReplyToCommand($"{LogPrefix}Map config not loaded for some reason...");
commandInfo.ReplyToCommand($"{MessagePrefix}Map config not loaded for some reason...");
return;
}

var didAddSpawn = _mapConfig.AddSpawn(spawn);

commandInfo.ReplyToCommand($"{LogPrefix}{(didAddSpawn ? "Spawn added" : "Error adding spawn")}");
}

[ConsoleCommand("css_debugqueues", "Prints the state of the queues to the console.")]
[CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)]
[RequiresPermissions("@css/root")]
public void OnCommandDebugState(CCSPlayerController? player, CommandInfo commandInfo)
{
if (_gameManager == null)
{
Console.WriteLine($"{LogPrefix}Game manager not loaded.");
return;
}

_gameManager.QueueManager.DebugQueues(true);
commandInfo.ReplyToCommand($"{MessagePrefix}{(didAddSpawn ? "Spawn added" : "Error adding spawn")}");
}

[ConsoleCommand("css_showqangle", "This command shows the players current QAngle")]
[RequiresPermissions("@css/root")]
public void OnCommandShowQangle(CCSPlayerController? player, CommandInfo commandInfo)
{
if (!Helpers.IsValidPlayer(player))
{
return;
}

var playerPawn = player!.PlayerPawn.Value!;
var qAngle = playerPawn.AbsRotation;
var lookTargetPosition = playerPawn.LookTargetPosition;
var eyeAngles = playerPawn.EyeAngles;

Server.PrintToChatAll($"{MessagePrefix}lookTargetPosition: x({lookTargetPosition!.X}) y({lookTargetPosition!.Y}) z({lookTargetPosition!.Z})");
Server.PrintToChatAll($"{MessagePrefix}qAngle: x({qAngle!.X}) y({qAngle!.Y}) z({qAngle!.Z})");
Server.PrintToChatAll($"{MessagePrefix}eyeAngles: x({eyeAngles!.X}) y({eyeAngles!.Y}) z({eyeAngles!.Z})");
}

[ConsoleCommand("css_showspawns", "This command shows the spawns")]
[CommandHelper(minArgs: 1, usage: "[A/B]", whoCanExecute: CommandUsage.CLIENT_ONLY)]
[ConsoleCommand("css_removespawn", "Remove the closest visible spawn point.")]
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
[RequiresPermissions("@css/root")]
public void OnCommandShowSpawns(CCSPlayerController? player, CommandInfo commandInfo)
public void OnCommandRemoveSpawn(CCSPlayerController? player, CommandInfo commandInfo)
{
if (!Helpers.IsValidPlayer(player))
{
return;
}

var bombsite = commandInfo.GetArg(1).ToUpper();
if (bombsite != "A" && bombsite != "B")
{
commandInfo.ReplyToCommand($"{LogPrefix}You must specify a bombsite [A / B].");
return;
}

if (_mapConfig == null)
if (!Helpers.DoesPlayerHavePawn(player))
{
commandInfo.ReplyToCommand($"{LogPrefix}Map config not loaded for some reason...");
return;
}

var spawns = _mapConfig.GetSpawnsClone().Where(spawn => spawn.Bombsite == (bombsite == "A" ? Bombsite.A : Bombsite.B)).ToList();

if (spawns.Count == 0)
if (_showingSpawnsForBombsite == null)
{
commandInfo.ReplyToCommand($"{LogPrefix}No spawns found for bombsite {bombsite}.");
commandInfo.ReplyToCommand($"{MessagePrefix}You can't remove a spawn if you're not showing the spawns.");
return;
}

foreach (var spawn in spawns)
{
Helpers.ShowSpawn(spawn);
}

_showingSpawnsForBombsite = (bombsite == "A" ? Bombsite.A : Bombsite.B);
commandInfo.ReplyToCommand($"{LogPrefix}Showing {spawns.Count} spawns for bombsite {bombsite}.");
}

[ConsoleCommand("css_removespawn", "This command removes the spawn closest to you.")]
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
[RequiresPermissions("@css/root")]
public void OnCommandRemoveSpawn(CCSPlayerController? player, CommandInfo commandInfo)
{
if (!Helpers.DoesPlayerHavePawn(player) || _showingSpawnsForBombsite == null || _spawnManager == null)
if (_spawnManager == null)
{
commandInfo.ReplyToCommand($"{MessagePrefix}Spawn manager not loaded for some reason...");
return;
}

Expand All @@ -220,7 +186,6 @@ public void OnCommandRemoveSpawn(CCSPlayerController? player, CommandInfo comman
return;
}

// TODO: Figure out why we need to cast this.
var spawns = _spawnManager.GetSpawns((Bombsite)_showingSpawnsForBombsite);

if (spawns.Count == 0)
Expand All @@ -244,52 +209,48 @@ public void OnCommandRemoveSpawn(CCSPlayerController? player, CommandInfo comman
closestDistance = distance;
closestSpawn = spawn;
}

if (closestSpawn == null)
{
commandInfo.ReplyToCommand($"{MessagePrefix}No spawns found within 128 units.");
return;
}

// Remove the beam entity that is showing for the closest spawn.
var beamEntities = Utilities.FindAllEntitiesByDesignerName<CBeam>("beam");
foreach (var beamEntity in beamEntities)
{
if (beamEntity.AbsOrigin == null)
{
continue;
}

if (
beamEntity.AbsOrigin.Z - closestSpawn.Vector.Z == 0 &&
beamEntity.AbsOrigin.X - closestSpawn.Vector.X == 0 &&
beamEntity.AbsOrigin.Y - closestSpawn.Vector.Y == 0
)
{
beamEntity.Remove();
}
}

_mapConfig.RemoveSpawn(closestSpawn);
commandInfo.ReplyToCommand($"{MessagePrefix}Removed spawn.");
}

[ConsoleCommand("css_teleport", "This command teleports the player to the given coordinates")]

[ConsoleCommand("css_debugqueues", "Prints the state of the queues to the console.")]
[CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)]
[RequiresPermissions("@css/root")]
public void OnCommandTeleport(CCSPlayerController? player, CommandInfo commandInfo)
public void OnCommandDebugState(CCSPlayerController? player, CommandInfo commandInfo)
{
if (!Helpers.IsValidPlayer(player))
{
return;
}

if (!player!.PlayerPawn.IsValid)
if (_gameManager == null)
{
Console.WriteLine($"{LogPrefix}Game manager not loaded.");
return;
}

if (commandInfo.ArgCount != 4)
{
return;
}

if (!float.TryParse(commandInfo.ArgByIndex(1), out var positionX))
{
return;
}

if (!float.TryParse(commandInfo.ArgByIndex(2), out var positionY))
{
return;
}

if (!float.TryParse(commandInfo.ArgByIndex(3), out var positionZ))
{
return;
}

player.PlayerPawn.Value?.Teleport(new Vector(positionX, positionY, positionZ), new QAngle(0f,0f,0f), new Vector(0f, 0f, 0f));
_gameManager.QueueManager.DebugQueues(true);
}
#endregion

Expand Down