Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
147 changes: 64 additions & 83 deletions SillySCP/Handlers/AntiSurface.cs
Original file line number Diff line number Diff line change
@@ -1,117 +1,98 @@
using System.Collections;
using System.Text.RegularExpressions;
using Exiled.API.Enums;
using Exiled.API.Enums;
using Exiled.API.Features;
using Exiled.API.Features.Doors;
using Exiled.Events.EventArgs.Map;
using Exiled.Events.EventArgs.Player;
using Exiled.API.Features.Waves;
using Exiled.Events.EventArgs.Server;
using Interactables.Interobjects;
using MEC;
using PlayerRoles;
using SillySCP.API.Interfaces;
using UnityEngine;

namespace SillySCP.Handlers;

public class AntiSurface : IRegisterable
{
public void Init()
{
Exiled.Events.Handlers.Map.ElevatorSequencesUpdated += OnElevatorSequencesUpdated;
Exiled.Events.Handlers.Server.RespawnedTeam += OnRespawned;
Exiled.Events.Handlers.Player.Died += OnPlayerDied;
Exiled.Events.Handlers.Server.RespawnedTeam += OnRespawnedTeam;
Exiled.Events.Handlers.Server.CompletingObjective += OnObjectiveComplete;
}

public void Unregister()
{
Exiled.Events.Handlers.Map.ElevatorSequencesUpdated -= OnElevatorSequencesUpdated;
Exiled.Events.Handlers.Server.RespawnedTeam -= OnRespawned;
Exiled.Events.Handlers.Player.Died -= OnPlayerDied;
Exiled.Events.Handlers.Server.RespawnedTeam -= OnRespawnedTeam;
Exiled.Events.Handlers.Server.CompletingObjective += OnObjectiveComplete;
}

private void OnPlayerDied(DiedEventArgs ev)
private void OnObjectiveComplete(CompletingObjectiveEventArgs ev)
{
if (Exiled.API.Features.Player.List.Count(p => p.IsAlive && !p.IsScp) > 3) return;
TryStartCoroutine();
_wave = GetWave();
}

private void OnElevatorSequencesUpdated(ElevatorSequencesUpdatedEventArgs ev)
private void OnRespawnedTeam(RespawnedTeamEventArgs ev)
{
if (ev.Sequence != ElevatorChamber.ElevatorSequence.DoorOpening) return;
if (ev.Lift.Type is not ElevatorType.GateA and not ElevatorType.GateB) return;
if (ev.Lift.CurrentLevel != 1) return;
TryStartCoroutine();
Timing.KillCoroutines(_handle);
_wave = GetWave();
_handle = Timing.RunCoroutine(SurfaceChecker());
}

private void OnRespawned(RespawnedTeamEventArgs ev)
private static TimedWave GetWave()
{
_handle = null;

Door ezA = Door.Get(DoorType.GateA);
Door ezB = Door.Get(DoorType.GateB);
ezA.Unlock();
ezB.Unlock();

TryStartCoroutine();
if (Respawn.NextKnownSpawnableFaction == SpawnableFaction.None) return null;
TimedWave wave = TimedWave.GetTimedWaves()
.FirstOrDefault(wave => wave.SpawnableFaction == Respawn.NextKnownSpawnableFaction && !wave.Timer.IsPaused);
return wave;
}

private CoroutineHandle? _handle;

private void TryStartCoroutine()
{
if (_handle != null) return;
_handle = Timing.RunCoroutine(SurfaceChecker());
}
private static TimedWave _wave;
private CoroutineHandle _handle;

private IEnumerator<float> SurfaceChecker()
private static IEnumerator<float> SurfaceChecker()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity why isn't this just like a coroutine you run per player?
that seems much simpler to me

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TPS go bwomp. Why would you do a coroutine for each player bruh?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplicity, it's really hard to follow rn imo.

Performance wise I'd imagine a per player coroutine;
which would only need to actually do stuff every few seconds, and can be spaced out naturally by adding it on join or when an event is triggered;
Thus making the performance concern negligible

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it hard to follow? Seems pretty simple to me, but that's because I built it. Running more co routines uses more of the CPU though which I would rather not do, especially when you're doing the same exact shit on all of them. This is the cleanest solution that makes sense. If you are confused by any parts of the code please do a proper review where you check the parts you're confused by and ask for clarification and I'll add a comment.

{
yield return Timing.WaitForSeconds(120);

if (Exiled.API.Features.Player.List.Count(player => player.IsAlive && !player.IsScp) > 3)
yield break;
HashSet<Exiled.API.Features.Player> lastKnownPlayers = new (GetSurfacePlayers());
DateTime firstCalled = DateTime.Now;
bool isFirstRun = true;

List<Exiled.API.Features.Player> surfacePlayers = Room.Get(RoomType.Surface).Players.ToList();

if (surfacePlayers.Count == 0 ||
surfacePlayers.Count(p => p.IsScp) > 1 ||
surfacePlayers.Select(p => p.Role.Team).Distinct().Count() > 1)
yield break;

Team team = surfacePlayers[0].Role.Team;
int playerCount = surfacePlayers.Count;

Door gateA = Door.Get(DoorType.ElevatorGateA);
Door gateB = Door.Get(DoorType.ElevatorGateB);
Door ezA = Door.Get(DoorType.GateA);
Door ezB = Door.Get(DoorType.GateB);

int closerToACount = surfacePlayers.Count(player =>
Vector3.Distance(player.Position, gateA.Position) <= Vector3.Distance(player.Position, gateB.Position));

ezA.IsOpen = ezB.IsOpen = true;
ezA.Lock(DoorLockType.Warhead);
ezB.Lock(DoorLockType.Warhead);

string message;
string translation;

if (playerCount != closerToACount)
{
message = $"{playerCount} {Spaceify(team.ToString())} personnel located on surface";
translation = $"{playerCount} {Spaceify(team.ToString())} personnel located on Surface";
}
else
foreach (int seconds in Seconds)
{
string nearGate = closerToACount > 0 ? "a" : "b";
string nearGateTranslation = closerToACount > 0 ? "A" : "B";
message = $"{playerCount} {Spaceify(team.ToString())} personnel located near gate {nearGate}";
translation = $"{playerCount} {Spaceify(team.ToString())} personnel located near Gate {nearGateTranslation}";
if (TotalSeconds(_wave) < seconds)
continue;

yield return Timing.WaitUntilTrue(() => TotalSeconds(_wave) <= seconds);

if (isFirstRun && (DateTime.Now - firstCalled).TotalSeconds < 29)
{
lastKnownPlayers = new (GetSurfacePlayers());
isFirstRun = false;
continue;
}

IEnumerable<Exiled.API.Features.Player> currentPlayers = GetSurfacePlayers();

foreach (Exiled.API.Features.Player player in currentPlayers)
{
if (lastKnownPlayers.Contains(player))
{
player.Kick("Holding up the round on surface.");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8.3.4. Every automated kick or ban (except ones issued by native game functions) must
be clearly described to the kicked/banned Player as an automated action not
related to native game function, unless it clearly does not look like an automated
action.

Suggested change
player.Kick("Holding up the round on surface.");
player.Kick("This is an automated kick performed by a plugin:\n Holding up the round on surface.");

}
}

lastKnownPlayers = new (currentPlayers);
}

Cassie.MessageTranslated(message, translation);
_handle = null;
}

private string Spaceify(string input) => Regex.Replace(input, "([A-Z])", " $1").Trim();
private static IEnumerable<Exiled.API.Features.Player> GetSurfacePlayers()
{
return Exiled.API.Features.Player.List.Where(player => player.Zone == ZoneType.Surface && player.IsHuman);
}

private static readonly int[] Seconds = new[]
{
180,
120,
60,
30
};

private static int TotalSeconds(TimedWave wave)
{
return Convert.ToInt32(wave.Timer.TimeLeft.TotalSeconds);
}
}
2 changes: 1 addition & 1 deletion SillySCP/SillySCP.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Costura.Fody" Version="6.0.0-beta0000" PrivateAssets="All" />
<PackageReference Include="ExMod.Exiled" Version="9.4.0" />
<PackageReference Include="ExMod.Exiled" Version="9.5.1" />
<PackageReference Include="Fody" Version="6.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Loading