Skip to content

Commit 1fb8c7d

Browse files
Merge pull request #226 from shobhit-pathak/dev
0.8.6
2 parents 87420fb + 9e663f0 commit 1fb8c7d

18 files changed

+337
-97
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
obj/*
2-
bin/*
2+
bin/*
3+
/.vs

Coach.cs

+105-50
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using CounterStrikeSharp.API.Core;
33
using CounterStrikeSharp.API.Modules.Utils;
44
using CounterStrikeSharp.API.Modules.Cvars;
5+
using System.Text.Json;
56

67
namespace MatchZy;
78

@@ -26,6 +27,11 @@ public void HandleCoachCommand(CCSPlayerController? player, string side)
2627
ReplyToUserCommand(player, "Coach command can only be used in match mode!");
2728
return;
2829
}
30+
if (IsWingmanMode())
31+
{
32+
ReplyToUserCommand(player, "Coach command cannot be used in wingman!");
33+
return;
34+
}
2935

3036
side = side.Trim().ToLower();
3137

@@ -73,13 +79,21 @@ public void HandleCoaches()
7379
coachKillTimer?.Kill();
7480
coachKillTimer = null;
7581
HashSet<CCSPlayerController> coaches = GetAllCoaches();
76-
if (coaches.Count == 0) return;
82+
if (IsWingmanMode() || coaches.Count == 0) return;
83+
if (spawnsData.Values.Any(list => list.Count == 0)) GetSpawns();
84+
if (coachSpawns.Count == 0 ||
85+
coachSpawns[(byte)CsTeam.CounterTerrorist].Count == 0 ||
86+
coachSpawns[(byte)CsTeam.Terrorist].Count == 0)
87+
{
88+
Log($"[HandleCoaches] No coach spawns found, player positions will not be swapped!");
89+
return;
90+
}
91+
7792
int freezeTime = ConVar.Find("mp_freezetime")!.GetPrimitiveValue<int>();
7893
freezeTime = freezeTime > 2 ? freezeTime: 2;
79-
coachKillTimer ??= AddTimer(freezeTime - 1.5f, KillCoaches);
80-
HashSet<CCSPlayerController> competitiveSpawnCoaches = new();
81-
if (spawnsData.Values.Any(list => list.Count == 0)) GetSpawns();
94+
coachKillTimer ??= AddTimer(freezeTime - 1f, KillCoaches);
8295

96+
Random random = new();
8397
foreach (CCSPlayerController coach in coaches)
8498
{
8599
if (!IsPlayerValid(coach)) continue;
@@ -94,64 +108,72 @@ public void HandleCoaches()
94108
coach.ActionTrackingServices!.MatchStats.Assists = 0;
95109
coach.ActionTrackingServices!.MatchStats.Damage = 0;
96110

97-
List<Position> teamPositions = spawnsData[coach.TeamNum];
111+
SetPlayerInvisible(player: coach, setWeaponsInvisible: false);
112+
// Stopping the coaches from moving, so that they don't block the players.
113+
coach.PlayerPawn.Value!.MoveType = MoveType_t.MOVETYPE_NONE;
114+
coach.PlayerPawn.Value!.ActualMoveType = MoveType_t.MOVETYPE_NONE;
115+
116+
List<Position> coachTeamSpawns = coachSpawns[coach.TeamNum];
98117
Position coachPosition = new(coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
99118

100-
foreach (Position position in teamPositions)
101-
{
102-
if (position.Equals(coachPosition))
103-
{
104-
competitiveSpawnCoaches.Add(coach);
105-
break;
106-
}
107-
}
108-
SetPlayerInvisible(player: coach, setWeaponsInvisible: false);
119+
// Picking a random position for the coach (from coachSpawns) to teleport them.
120+
Position newPosition = coachTeamSpawns[random.Next(0, coachTeamSpawns.Count)];
121+
109122
// Elevating coach before dropping the C4 to prevent it going inside the ground.
110123
AddTimer(0.05f, () =>
111124
{
112125
coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
113126
HandleCoachWeapons(coach);
114-
coach!.PlayerPawn.Value.Teleport(coachPosition.PlayerPosition, coachPosition.PlayerAngle, new Vector(0, 0, 0));
127+
coach!.PlayerPawn.Value.Teleport(newPosition.PlayerPosition, newPosition.PlayerAngle, new Vector(0, 0, 0));
115128
});
116-
129+
117130
}
118131

119-
var playerEntities = Utilities.FindAllEntitiesByDesignerName<CCSPlayerController>("cs_player_controller");
132+
List<CCSPlayerController> players = Utilities.GetPlayers();
133+
HashSet<Position> occupiedSpawns = new();
134+
HashSet<CCSPlayerController> incorrectSpawnedPlayers = new();
135+
136+
// We will loop on the players 2 times, first loop is to get all the players who are on a non-competitive spawn, and to get all the non-occupied competitive spawn.
137+
// In the next loop, we will teleport the non-competitive spawned players to an available competitive spawn.
120138

121-
// foreach (var key in playerData.Keys)
122-
// {
123-
foreach (var player in playerEntities)
139+
foreach (CCSPlayerController player in players)
124140
{
125-
if (!IsPlayerValid(player)) continue;
126-
// CCSPlayerController player = playerData[key];
141+
if (!IsPlayerValid(player) || coaches.Contains(player)) continue;
142+
127143
List<Position> teamPositions = spawnsData[player.TeamNum];
128144
Position playerPosition = new(player.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, player.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
129145
bool isCompetitiveSpawn = false;
130146
foreach (Position position in teamPositions)
131147
{
132148
if (position.Equals(playerPosition))
133149
{
150+
occupiedSpawns.Add(position);
134151
isCompetitiveSpawn = true;
135152
break;
136153
}
137154
}
138-
// Player is already on a competitive spawn, no need to swap.
139155
if (isCompetitiveSpawn) continue;
140156

141-
CCSPlayerController? coach = competitiveSpawnCoaches.FirstOrDefault((CCSPlayerController coach) => coach.Team == player.Team);
142-
if (coach is null) continue;
143-
competitiveSpawnCoaches.Remove(coach);
157+
// The player is not on a competitive spawn, we will put them on one in the next loop.
158+
incorrectSpawnedPlayers.Add(player);
159+
}
144160

145-
Position coachPosition = new(coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
146-
AddTimer(0.1f, () =>
147-
{
148-
coach!.PlayerPawn.Value!.Teleport(new Vector(playerPosition.PlayerPosition.X, playerPosition.PlayerPosition.Y, playerPosition.PlayerPosition.Z), playerPosition.PlayerAngle, new Vector(0, 0, 0));
149-
player!.PlayerPawn.Value.Teleport(coachPosition.PlayerPosition, coachPosition.PlayerAngle, new Vector(0, 0, 0));
150-
});
161+
foreach (CCSPlayerController player in incorrectSpawnedPlayers)
162+
{
163+
if (!IsPlayerValid(player) || coaches.Contains(player)) continue;
151164

152-
// Stopping the coaches from moving, so that they don't block the players.
153-
coach.PlayerPawn.Value!.MoveType = MoveType_t.MOVETYPE_NONE;
154-
coach.PlayerPawn.Value!.ActualMoveType = MoveType_t.MOVETYPE_NONE;
165+
List<Position> teamPositions = spawnsData[player.TeamNum];
166+
Position playerPosition = new(player.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, player.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
167+
foreach (Position position in teamPositions)
168+
{
169+
if (occupiedSpawns.Contains(position)) continue;
170+
occupiedSpawns.Add(position);
171+
AddTimer(0.1f, () =>
172+
{
173+
player!.PlayerPawn.Value.Teleport(position.PlayerPosition, position.PlayerAngle, new Vector(0, 0, 0));
174+
});
175+
break;
176+
}
155177
}
156178
}
157179

@@ -204,29 +226,62 @@ private void KillCoaches()
204226
{
205227
if (isPaused || IsTacticalTimeoutActive()) return;
206228
HashSet<CCSPlayerController> coaches = GetAllCoaches();
207-
if (coaches.Count == 0) return;
229+
if (IsWingmanMode() || coaches.Count == 0) return;
208230
string suicidePenalty = GetConvarStringValue(ConVar.Find("mp_suicide_penalty"));
209-
string deathDropGunEnabled = GetConvarStringValue(ConVar.Find("mp_death_drop_gun"));
210231
string specFreezeTime = GetConvarStringValue(ConVar.Find("spec_freeze_time"));
211232
string specFreezeTimeLock = GetConvarStringValue(ConVar.Find("spec_freeze_time_lock"));
212233
string specFreezeDeathanim = GetConvarStringValue(ConVar.Find("spec_freeze_deathanim_time"));
213234
Server.ExecuteCommand("mp_suicide_penalty 0;spec_freeze_time 0; spec_freeze_time_lock 0; spec_freeze_deathanim_time 0;");
214235

215-
// Adding timer to make sure above commands are executed successfully.
216-
AddTimer(0.5f, () =>
236+
foreach (var coach in coaches)
237+
{
238+
if (!IsPlayerValid(coach)) continue;
239+
if (isPaused || IsTacticalTimeoutActive()) continue;
240+
241+
Position coachPosition = new(coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
242+
coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
243+
// Dropping the C4 if it was picked up or passed to the coach.
244+
DropWeaponByDesignerName(coach, "weapon_c4");
245+
coach.PlayerPawn.Value!.CommitSuicide(explode: false, force: true);
246+
}
247+
Server.ExecuteCommand($"mp_suicide_penalty {suicidePenalty}; spec_freeze_time {specFreezeTime}; spec_freeze_time_lock {specFreezeTimeLock}; spec_freeze_deathanim_time {specFreezeDeathanim};");
248+
}
249+
250+
private void GetCoachSpawns()
251+
{
252+
coachSpawns = GetEmptySpawnsData();
253+
try
217254
{
218-
foreach (var coach in coaches)
255+
string spawnsConfigPath = Path.Combine(ModuleDirectory, "spawns", "coach", $"{Server.MapName}.json");
256+
string spawnsConfig = File.ReadAllText(spawnsConfigPath);
257+
258+
var jsonDictionary = JsonSerializer.Deserialize<Dictionary<string, List<Dictionary<string, string>>>>(spawnsConfig);
259+
if (jsonDictionary is null) return;
260+
foreach (var entry in jsonDictionary)
219261
{
220-
if (!IsPlayerValid(coach)) continue;
221-
if (isPaused || IsTacticalTimeoutActive()) continue;
262+
byte team = byte.Parse(entry.Key);
263+
List<Position> positionList = new();
222264

223-
Position coachPosition = new(coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
224-
coach!.PlayerPawn.Value!.Teleport(new Vector(coachPosition.PlayerPosition.X, coachPosition.PlayerPosition.Y, coachPosition.PlayerPosition.Z + 20.0f), coachPosition.PlayerAngle, new Vector(0, 0, 0));
225-
// Dropping the C4 if it was picked up or passed to the coach.
226-
DropWeaponByDesignerName(coach, "weapon_c4");
227-
coach.PlayerPawn.Value!.CommitSuicide(explode: false, force: true);
265+
foreach (var positionData in entry.Value)
266+
{
267+
string[] vectorArray = positionData["Vector"].Split(' ');
268+
string[] angleArray = positionData["QAngle"].Split(' ');
269+
270+
// Parse position and angle
271+
Vector vector = new(float.Parse(vectorArray[0]), float.Parse(vectorArray[1]), float.Parse(vectorArray[2]));
272+
QAngle qAngle = new(float.Parse(angleArray[0]), float.Parse(angleArray[1]), float.Parse(angleArray[2]));
273+
274+
Position position = new(vector, qAngle);
275+
276+
positionList.Add(position);
277+
}
278+
coachSpawns[team] = positionList;
228279
}
229-
Server.ExecuteCommand($"mp_suicide_penalty {suicidePenalty}; spec_freeze_time {specFreezeTime}; spec_freeze_time_lock {specFreezeTimeLock}; spec_freeze_deathanim_time {specFreezeDeathanim};");
230-
});
280+
Log($"[GetCoachSpawns] Loaded {coachSpawns.Count} coach spawns");
281+
}
282+
catch (Exception ex)
283+
{
284+
Log($"[GetCoachSpawns - FATAL] Error getting coach spawns. [ERROR]: {ex.Message}");
285+
}
231286
}
232-
}
287+
}

ConsoleCommands.cs

+1
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ public void OnEndMatchCommand(CCSPlayerController? player, CommandInfo? command)
441441
}
442442

443443
[ConsoleCommand("css_restart", "Restarts the match")]
444+
[ConsoleCommand("css_rr", "Restarts the match")]
444445
public void OnRestartMatchCommand(CCSPlayerController? player, CommandInfo? command)
445446
{
446447
if (IsPlayerAdmin(player, "css_restart", "@css/config"))

EventHandlers.cs

-4
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ public HookResult EventPlayerConnectFullHandler(EventPlayerConnectFull @event, G
3333
KickPlayer(player);
3434
return HookResult.Continue;
3535
}
36-
else
37-
{
38-
SwitchPlayerTeam(player, team);
39-
}
4036
}
4137
}
4238

MapVeto.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public void HandeMapBanCommand(CCSPlayerController player, string map)
199199
if (player.UserId != vetoCaptains[currentTeamToBan]) return;
200200

201201
if (!BanMap(map, playerTeam)) {
202-
player.PrintToChat($"{chatPrefix} {map} is not a valid map.");
202+
PrintToPlayerChat(player, $"{map} is not a valid map.");
203203
} else {
204204
HandleVetoStep();
205205
}
@@ -229,7 +229,7 @@ public void HandeMapPickCommand(CCSPlayerController player, string map)
229229
if (player.UserId != vetoCaptains[currentTeamToPick]) return;
230230

231231
if (!PickMap(map, playerTeam)) {
232-
player.PrintToChat($"{chatPrefix} {map} is not a valid map.");
232+
PrintToPlayerChat(player, $"{map} is not a valid map.");
233233
} else {
234234
HandleVetoStep();
235235
}

MatchZy.cs

+10-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public partial class MatchZy : BasePlugin
1313
{
1414

1515
public override string ModuleName => "MatchZy";
16-
public override string ModuleVersion => "0.8.5";
16+
public override string ModuleVersion => "0.8.6";
1717

1818
public override string ModuleAuthor => "WD- (https://github.com/shobhit-pathak/)";
1919

@@ -135,6 +135,7 @@ public override void Load(bool hotReload) {
135135
{ ".skipveto", OnSkipVetoCommand },
136136
{ ".sv", OnSkipVetoCommand },
137137
{ ".restart", OnRestartMatchCommand },
138+
{ ".rr", OnRestartMatchCommand },
138139
{ ".endmatch", OnEndMatchCommand },
139140
{ ".forceend", OnEndMatchCommand },
140141
{ ".reloadmap", OnMapReloadCommand },
@@ -144,6 +145,8 @@ public override void Load(bool hotReload) {
144145
{ ".reload_admins", OnReloadAdmins },
145146
{ ".tactics", OnPracCommand },
146147
{ ".prac", OnPracCommand },
148+
{ ".showspawns", OnShowSpawnsCommand },
149+
{ ".hidespawns", OnHideSpawnsCommand },
147150
{ ".dryrun", OnDryRunCommand },
148151
{ ".dry", OnDryRunCommand },
149152
{ ".noflash", OnNoFlashCommand },
@@ -212,7 +215,6 @@ public override void Load(bool hotReload) {
212215
// UpdatePlayersMap();
213216
});
214217
RegisterListener<Listeners.OnEntitySpawned>(OnEntitySpawnedHandler);
215-
216218
RegisterEventHandler<EventPlayerTeam>((@event, info) => {
217219
CCSPlayerController? player = @event.Userid;
218220
if (!IsPlayerValid(player)) return HookResult.Continue;
@@ -366,13 +368,13 @@ public override void Load(bool hotReload) {
366368
var originalMessage = @event.Text.Trim();
367369
var message = @event.Text.Trim().ToLower();
368370

369-
var parts = message.Split(' ');
371+
var parts = originalMessage.Split(' ');
370372
var messageCommand = parts.Length > 0 ? parts[0] : string.Empty;
371373
var messageCommandArg = parts.Length > 1 ? string.Join(' ', parts.Skip(1)) : string.Empty;
372374

373375
CCSPlayerController? player = null;
374-
if (playerData.ContainsKey(playerUserId)) {
375-
player = playerData[playerUserId];
376+
if (playerData.TryGetValue(playerUserId, out CCSPlayerController? value)) {
377+
player = value;
376378
}
377379

378380
if (player == null) {
@@ -454,15 +456,15 @@ public override void Load(bool hotReload) {
454456
{
455457
HandleSpawnCommand(player, messageCommandArg, (byte)CsTeam.Terrorist, "tspawn");
456458
}
457-
if (originalMessage.StartsWith(".team1"))
459+
if (message.StartsWith(".team1"))
458460
{
459461
HandleTeamNameChangeCommand(player, messageCommandArg, 1);
460462
}
461-
if (originalMessage.StartsWith(".team2"))
463+
if (message.StartsWith(".team2"))
462464
{
463465
HandleTeamNameChangeCommand(player, messageCommandArg, 2);
464466
}
465-
if (originalMessage.StartsWith(".rcon"))
467+
if (message.StartsWith(".rcon"))
466468
{
467469
if (IsPlayerAdmin(player, "css_rcon", "@css/rcon"))
468470
{

MatchZy.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.253">
10+
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.263">
1111
<PrivateAssets>none</PrivateAssets>
1212
<ExcludeAssets>runtime</ExcludeAssets>
1313
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -21,5 +21,6 @@
2121
</ItemGroup>
2222
<ItemGroup>
2323
<None Update="lang\**\*.*" CopyToOutputDirectory="PreserveNewest" />
24+
<None Update="spawns\**\*.*" CopyToOutputDirectory="PreserveNewest" />
2425
</ItemGroup>
2526
</Project>

0 commit comments

Comments
 (0)