did a few things

This commit is contained in:
code002lover 2025-05-28 01:21:24 +02:00
parent 5b8dcb282f
commit c4ff84e8b6
10 changed files with 367 additions and 28 deletions

View File

@ -1,4 +1,5 @@
using LabApi.Events.Arguments.PlayerEvents;
using CustomPlayerEffects;
using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Handlers;
using LabApi.Features;
using LabApi.Features.Console;
@ -6,6 +7,8 @@ using LabApi.Features.Wrappers;
using LabApi.Loader.Features.Plugins;
using Mirror;
using PlayerRoles;
using PlayerRoles.PlayableScps.Scp3114;
using PlayerRoles.Ragdolls;
namespace CuffedFrenemies;
@ -30,7 +33,6 @@ public class CuffedFrenemies : Plugin
private static void OnCuff(PlayerCuffedEventArgs ev)
{
Logger.Debug($"Team: {ev.Target.Team}");
if (ev.Target.Team is Team.ClassD or Team.Scientists)
{
return;
@ -42,6 +44,28 @@ public class CuffedFrenemies : Plugin
return;
}
if (ev.Target.RoleBase is Scp3114Role scp3114)
{
var stolenRole = scp3114.CurIdentity.StolenRole;
var ragdoll = scp3114.CurIdentity.Ragdoll.Info;
switch (stolenRole)
{
case RoleTypeId.ChaosConscript or RoleTypeId.ChaosMarauder or RoleTypeId.ChaosRepressor
or RoleTypeId.ChaosRifleman:
scp3114.CurIdentity.Ragdoll.Info = new RagdollData(ragdoll.OwnerHub, ragdoll.Handler, RoleTypeId.NtfPrivate, ragdoll.StartPosition, ragdoll.StartRotation, ragdoll.Nickname, ragdoll.CreationTime);
return;
case RoleTypeId.NtfPrivate or RoleTypeId.NtfCaptain or RoleTypeId.NtfSergeant
or RoleTypeId.NtfSpecialist:
scp3114.CurIdentity.Ragdoll.Info = new RagdollData(ragdoll.OwnerHub, ragdoll.Handler, RoleTypeId.ChaosConscript, ragdoll.StartPosition, ragdoll.StartRotation, ragdoll.Nickname, ragdoll.CreationTime);
return;
}
}
if (ev.Target.Team is Team.SCPs or Team.Dead)
{
return;
}
var newRole = ev.Target.Team == Team.ChaosInsurgency ? RoleTypeId.NtfPrivate : RoleTypeId.ChaosConscript;
Logger.Debug($"Setting role to {newRole}");
var newItems = new List<Item>();

View File

@ -26,6 +26,9 @@
<Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
</Reference>
<Reference Include="Pooling">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Pooling.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>

View File

@ -0,0 +1,29 @@
using Interactables.Interobjects.DoorUtils;
using LabApi.Features.Console;
namespace KeycardButModern;
public enum DoorType
{
Normal,
Gate,
Checkpoint
}
public class DoorLockConfiguration
{
public Dictionary<DoorType, float> LockDurations { get; set; }= new()
{
{ DoorType.Normal, 5f },
{ DoorType.Gate, 8f },
{ DoorType.Checkpoint, 3f }
};
public static DoorType GetDoorType(DoorVariant door)
{
Logger.Debug("Door name: " + door.name);
if (door.name.Contains("Checkpoint"))
return DoorType.Checkpoint;
return door.name.Contains("Gate") ? DoorType.Gate : DoorType.Normal;
}
}

View File

@ -1,10 +1,14 @@
using System.Collections;
using Interactables.Interobjects;
using Interactables.Interobjects.DoorButtons;
using Interactables.Interobjects.DoorUtils;
using InventorySystem.Items.Keycards;
using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Handlers;
using LabApi.Features;
using LabApi.Features.Console;
using PlayerRoles;
using LabApi.Loader;
using UnityEngine;
using KeycardItem = InventorySystem.Items.Keycards.KeycardItem;
using Logger = LabApi.Features.Console.Logger;
namespace KeycardButModern
{
@ -16,6 +20,16 @@ namespace KeycardButModern
public override Version Version { get; } = new(1, 0, 0);
public override Version RequiredApiVersion { get; } = new (LabApiProperties.CompiledVersion);
public DoorLockConfiguration DoorLockConfiguration;
public static Plugin Singleton;
public override void LoadConfigs()
{
base.LoadConfigs();
DoorLockConfiguration = this.LoadConfig< DoorLockConfiguration > ("door_locks.yml");
}
private void OnInteractingDoor(PlayerInteractingDoorEventArgs ev)
{
if (ev.CanOpen)
@ -25,7 +39,6 @@ namespace KeycardButModern
if (ev.Door.IsLocked)
{
Logger.Debug("Door has active locks");
return;
}
@ -40,7 +53,6 @@ namespace KeycardButModern
if (!ev.Door.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Door.IsOpened = !ev.Door.IsOpened;
Logger.Debug("Door can be opened");
return;
}
@ -64,7 +76,6 @@ namespace KeycardButModern
if (ev.Generator.IsUnlocked)
{
Logger.Debug("Generator can be opened; Unlocked");
return;
}
@ -81,7 +92,6 @@ namespace KeycardButModern
if (!ev.Generator.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Generator.IsOpen = !ev.Generator.IsOpen;
ev.Generator.IsUnlocked = true;
Logger.Debug("Generator can be opened");
return;
}
@ -115,7 +125,6 @@ namespace KeycardButModern
if (!ev.Chamber.Base.CheckPermissions(keycardItem, out _)) continue;
ev.Chamber.IsOpen = !ev.Chamber.IsOpen;
Logger.Debug("Locker can be opened");
return;
}
@ -139,7 +148,42 @@ namespace KeycardButModern
if (!AlphaWarheadActivationPanel.Instance.CheckPermissions(keycardItem, out _)) continue;
ev.IsAllowed = true;
Logger.Debug("Nuke can be unlocked");
return;
}
}
private static void OnBulletHole(PlayerPlacedBulletHoleEventArgs ev)
{
var direction = (ev.HitPosition - ev.RaycastStart).normalized;
var distance = Vector3.Distance(ev.RaycastStart, ev.HitPosition);
var hits = Physics.RaycastAll(ev.RaycastStart, direction, distance);
foreach (var hit in hits)
{
ButtonVariant doorButton = hit.collider.GetComponent<LcdButton>();
if (!doorButton)
{
doorButton = hit.collider.GetComponent<CheckpointKeycardButton>();
}
if (!doorButton)
{
doorButton = hit.collider.GetComponent<KeycardButton>();
}
if (!doorButton)
{
doorButton = hit.collider.GetComponent<SimpleButton>();
}
if (!doorButton)
{
continue;
}
var doorVariant = DoorVariant.AllDoors.AsEnumerable()!.First(x => x.Buttons.Any(c=>c.GetInstanceID() == doorButton.GetInstanceID()));
doorVariant.ServerInteract(ev.Player.ReferenceHub, doorButton.ColliderId);
StartDoorLockCoroutine(doorVariant);
return;
}
}
@ -147,10 +191,30 @@ namespace KeycardButModern
public override void Enable()
{
Logger.Debug("starting...");
Singleton = this;
PlayerEvents.InteractingDoor += OnInteractingDoor;
PlayerEvents.InteractingGenerator += OnInteractingGenerator;
PlayerEvents.InteractingLocker += OnInteractingLocker;
PlayerEvents.UnlockingWarheadButton += OnUnlockingWarhead;
PlayerEvents.PlacedBulletHole += OnBulletHole;
}
private static void StartDoorLockCoroutine(DoorVariant door)
{
door.StartCoroutine(LockDoorCoroutine(door));
}
private static IEnumerator LockDoorCoroutine(DoorVariant door)
{
var doorType = DoorLockConfiguration.GetDoorType(door);
var lockDuration = Singleton.DoorLockConfiguration.LockDurations[doorType];
door.ServerChangeLock(DoorLockReason.SpecialDoorFeature, true);
yield return new WaitForSeconds(lockDuration);
door.ServerChangeLock(DoorLockReason.SpecialDoorFeature, false);
}
public override void Disable()
@ -159,7 +223,11 @@ namespace KeycardButModern
PlayerEvents.InteractingGenerator -= OnInteractingGenerator;
PlayerEvents.InteractingLocker -= OnInteractingLocker;
PlayerEvents.UnlockingWarheadButton -= OnUnlockingWarhead;
PlayerEvents.PlacedBulletHole -= OnBulletHole;
Logger.Debug("unloading...");
Singleton = null;
}
}
}

View File

@ -29,6 +29,9 @@
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>

41
ModTools/ModTools.csproj Normal file
View File

@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<LangVersion>latest</LangVersion>
<RootNamespace>ReportNotifier</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<Optimize>true</Optimize>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<Optimize>true</Optimize>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>
<Reference Include="Assembly-CSharp">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="CommandSystem.Core">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\CommandSystem.Core.dll</HintPath>
</Reference>
<Reference Include="Mirror">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\Mirror.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,70 @@
using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Handlers;
using LabApi.Features;
using LabApi.Features.Console;
using LabApi.Features.Permissions;
using LabApi.Features.Wrappers;
namespace ReportNotifier;
public class Plugin: LabApi.Loader.Features.Plugins.Plugin
{
public override string Name => "ModTools";
public override string Author => "Code002Lover";
public override Version Version { get; } = new(1, 0, 0);
public override string Description => "Various tools for moderation, including report notification and extra logs.";
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
public string LogFile { get; set; } = "ModTools.log";
private static FileStream _logFileHandler;
public override void Enable()
{
PlayerEvents.ReportedPlayer += OnReport;
PlayerEvents.Banned += OnBan;
PlayerEvents.Kicked += OnKick;
_logFileHandler = File.Open(LogFile, FileMode.Append);
}
public override void Disable()
{
PlayerEvents.ReportedPlayer -= OnReport;
PlayerEvents.Banned -= OnBan;
PlayerEvents.Kicked -= OnKick;
_logFileHandler = null;
}
private static void OnReport(PlayerReportedPlayerEventArgs ev)
{
Log($"Received Report from {ev.Player.Nickname} for {ev.Target.Nickname} with the reason: {ev.Reason}");
foreach (var player in Player.List)
{
Logger.Debug($"Player {player.Nickname} has permissions: {player.GetPermissions()}");
if (player.HasPermissions("AdminChat"))
{
player.SendBroadcast($"<color=#002DB3FF>{ev.Player.Nickname} reported {ev.Target.Nickname} for {ev.Reason}</color>", 3, Broadcast.BroadcastFlags.AdminChat, true);
}
}
}
private static void Log(string message)
{
Logger.Debug(message);
var now = DateTime.Now;
var bytes = System.Text.Encoding.UTF8.GetBytes($"[{now:dd.MM.yyyy : HH:mm:ss}] - {message}");
_logFileHandler.Write(bytes, 0, bytes.Length);
}
private static void OnBan(PlayerBannedEventArgs ev)
{
Log($"Player {ev.Player?.Nickname} ({ev.PlayerId}) got banned by {ev.Issuer.Nickname} ({ev.Issuer.PlayerId}) with reason: {ev.Reason}");
}
private static void OnKick(PlayerKickedEventArgs ev)
{
Log($"Player {ev.Player.Nickname} ({ev.Player.PlayerId}) got kicked by {ev.Issuer.Nickname} ({ev.Issuer.PlayerId}) with reason: {ev.Reason}");
}
}

View File

@ -27,6 +27,7 @@ public class IpRangeTests
[TestCase("192.168.1.0/24", "10.0.0.1", false)]
[TestCase("176.2.0.0/16", "176.2.73.23", true)]
[TestCase("176.2.0.0/16", "176.2.70.50", true)]
[TestCase("176.2.0.0/16", "176.2.72.1", true)]
public void IsInRange_WithCidrNotation_ReturnsExpectedResult(string range, string ip, bool expected)
{
Assert.That(RangeBan.IsInRange(range, ip), Is.EqualTo(expected));

View File

@ -18,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RangeBan.Tests", "RangeBan.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CuffedFrenemies", "CuffedFrenemies\CuffedFrenemies.csproj", "{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModTools", "ModTools\ModTools.csproj", "{F0AE1ABF-4FAF-4D20-AD71-C98804442D71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -60,5 +62,9 @@ Global
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Release|Any CPU.Build.0 = Release|Any CPU
{F0AE1ABF-4FAF-4D20-AD71-C98804442D71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0AE1ABF-4FAF-4D20-AD71-C98804442D71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0AE1ABF-4FAF-4D20-AD71-C98804442D71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0AE1ABF-4FAF-4D20-AD71-C98804442D71}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -1,4 +1,5 @@
using HintServiceMeow.Core.Enum;
using HintServiceMeow.Core.Models.HintContent;
using HintServiceMeow.Core.Models.Hints;
using HintServiceMeow.Core.Utilities;
using LabApi.Events.Arguments.PlayerEvents;
@ -8,6 +9,7 @@ using LabApi.Features.Console;
using LabApi.Features.Wrappers;
using LabApi.Loader.Features.Plugins;
using PlayerRoles;
using PlayerRoles.Spectating;
using Timer = System.Timers.Timer;
namespace VisibleSpectators
@ -20,6 +22,7 @@ namespace VisibleSpectators
public override string Description => "See your spectators";
public override Version RequiredApiVersion { get; } = new (LabApiProperties.CompiledVersion);
public int YCoordinate { get; set; } = 100;
private static Plugin _singleton;
private Timer _timer;
@ -60,12 +63,111 @@ namespace VisibleSpectators
}
}
private void AddPlayerHint(Player player)
{
if (player == null) return;
var hint = new Hint
{
Text = $"{Config!.HeaderMessage}\n{Config!.NoSpectatorsMessage}",
Alignment = HintAlignment.Right,
YCoordinate = YCoordinate,
Hide = true
};
var playerDisplay = PlayerDisplay.Get(player);
playerDisplay.AddHint(hint);
_spectatorHints[player] = hint;
}
private static readonly Dictionary<string, string> GetColorMap = new()
{
{ "DEFAULT", "FFFFFF" },
{ "PUMPKIN", "EE7600" },
{ "ARMY_GREEN", "4B5320" },
{ "MINT", "98FB98" },
{ "NICKEL", "727472" },
{ "CARMINE", "960018" },
{ "EMERALD", "50C878" },
{ "GREEN", "228B22" },
{ "LIME", "BFFF00" },
{ "POLICE_BLUE", "002DB3" },
{ "ORANGE", "FF9966" },
{ "SILVER_BLUE", "666699" },
{ "BLUE_GREEN", "4DFFB8" },
{ "MAGENTA", "FF0090" },
{ "YELLOW", "FAFF86" },
{ "TOMATO", "FF6448" },
{ "DEEP_PINK", "FF1493" },
{ "AQUA", "00FFFF" },
{ "CYAN", "00B7EB" },
{ "CRIMSON", "DC143C" },
{ "LIGHT_GREEN", "32CD32" },
{ "SILVER", "A0A0A0" },
{ "BROWN", "944710" },
{ "RED", "C50000" },
{ "PINK", "FF96DE" },
{ "LIGHT_RED", "FD8272" },
{ "PURPLE", "8137CE" },
{ "BLUE", "005EBC" },
{ "TEAL", "008080" },
{ "GOLD", "EFC01A" }
};
private static string PlayerToDisplay(Player player)
{
if (player == null) return "";
// Default color if GroupColor is null or not found in the map
const string defaultColor = "FFFFFF";
try
{
var groupColor = player.GroupColor;
if (string.IsNullOrEmpty(groupColor))
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
return GetColorMap.TryGetValue(groupColor.ToUpper(), out var color) ? $"<color=#{color}FF>{player.DisplayName}</color>" : $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
}
catch
{
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
}
}
private static bool IsNotOverwatch(Player player)
{
return player != null && player.Role != RoleTypeId.Overwatch;
}
private void UpdateSpectators(Player player)
{
var spectators = string.Join("\n",player.CurrentSpectators.Select(x => x.DisplayName));
if (player.Role == RoleTypeId.Spectator)
if (player == null)
{
spectators = string.Join("\n",player.CurrentlySpectating?.CurrentSpectators.Select(x => x.DisplayName) ?? Array.Empty<string>());
return;
}
// Safety check - if player doesn't have a hint, create one
if (!_spectatorHints.ContainsKey(player))
{
AddPlayerHint(player);
}
var spectators = Config!.NoSpectatorsMessage;
try
{
spectators = string.Join("\n",player.CurrentSpectators.Where(IsNotOverwatch).Select(PlayerToDisplay));
if (player.Role == RoleTypeId.Spectator)
spectators = player.CurrentlySpectating == null
? Config!.NoSpectatorsMessage
: string.Join("\n",
player.CurrentlySpectating?.CurrentSpectators.Where(IsNotOverwatch)
.Select(PlayerToDisplay) ?? Array.Empty<string>());
} catch (Exception e)
{
Logger.Error(e);
}
if (spectators.Length < 2)
@ -74,9 +176,11 @@ namespace VisibleSpectators
}
_spectatorHints[player].Text = $"{Config!.HeaderMessage}\n{spectators}\n{DateTime.UtcNow:HH:mm:ss}";
_spectatorHints[player].Text = $"{Config!.HeaderMessage}\n{spectators}";
_spectatorHints[player].Hide = player.Role is RoleTypeId.Overwatch or RoleTypeId.Destroyed or RoleTypeId.None;
_spectatorHints[player].Hide = player.Role is RoleTypeId.Destroyed or RoleTypeId.None;
_spectatorHints[player].YCoordinate = YCoordinate + player.CurrentSpectators.Count * 10;
}
private static Player[] GetPlayers()
@ -88,22 +192,12 @@ namespace VisibleSpectators
{
_singleton.UpdateSpectators(ev.OldTarget);
_singleton.UpdateSpectators(ev.NewTarget);
_singleton.UpdateSpectators(ev.Player);
}
private void OnJoin(PlayerJoinedEventArgs ev)
{
var hint = new Hint
{
Text = $"{Config!.HeaderMessage}\n{Config!.NoSpectatorsMessage}",
Alignment = HintAlignment.Right,
YCoordinate = 100,
Hide = true
};
var playerDisplay = PlayerDisplay.Get(ev.Player);
playerDisplay.AddHint(hint);
_spectatorHints[ev.Player] = hint;
AddPlayerHint(ev.Player);
}
}