Compare commits
7 Commits
c56e7c9dd6
...
01b41461c1
Author | SHA1 | Date | |
---|---|---|---|
01b41461c1 | |||
c4ff84e8b6 | |||
5b8dcb282f | |||
e099ee5071 | |||
a784ec1ff8 | |||
17f5e8c6c8 | |||
b0038a23d8 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ bin/
|
||||
obj/
|
||||
*.user
|
||||
*.dll
|
||||
fuchsbau/
|
||||
|
90
CuffedFrenemies/CuffedFrenemies.cs
Normal file
90
CuffedFrenemies/CuffedFrenemies.cs
Normal file
@ -0,0 +1,90 @@
|
||||
using CustomPlayerEffects;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Events.Handlers;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Console;
|
||||
using LabApi.Features.Wrappers;
|
||||
using LabApi.Loader.Features.Plugins;
|
||||
using Mirror;
|
||||
using PlayerRoles;
|
||||
using PlayerRoles.PlayableScps.Scp3114;
|
||||
using PlayerRoles.Ragdolls;
|
||||
|
||||
namespace CuffedFrenemies;
|
||||
|
||||
public class CuffedFrenemies : Plugin
|
||||
{
|
||||
public override string Name => "GamblingCoin";
|
||||
public override string Author => "Code002Lover";
|
||||
public override Version Version { get; } = new(1, 0, 0);
|
||||
public override string Description => "Gamble your life away";
|
||||
public override Version RequiredApiVersion { get; } = new (LabApiProperties.CompiledVersion);
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Debug("Loading");
|
||||
PlayerEvents.Cuffed += OnCuff;
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
PlayerEvents.Cuffed -= OnCuff;
|
||||
}
|
||||
|
||||
private static void OnCuff(PlayerCuffedEventArgs ev)
|
||||
{
|
||||
if (ev.Target.Team is Team.ClassD or Team.Scientists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.Target.Team == ev.Player.Team)
|
||||
{
|
||||
Logger.Debug("Same team, not changing role");
|
||||
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>();
|
||||
ev.Target.Items.CopyTo(newItems);
|
||||
newItems.Reverse();
|
||||
|
||||
var newPos = ev.Target.Position;
|
||||
|
||||
ev.Target.Inventory.UserInventory.Items.Clear();
|
||||
|
||||
ev.Target.SetRole(newRole);
|
||||
ev.Target.ClearItems();
|
||||
|
||||
foreach (var newItem in newItems)
|
||||
{
|
||||
ev.Target.Inventory.UserInventory.Items.Add(newItem.Serial,newItem.Base);
|
||||
}
|
||||
|
||||
ev.Target.Position = newPos;
|
||||
|
||||
}
|
||||
}
|
40
CuffedFrenemies/CuffedFrenemies.csproj
Normal file
40
CuffedFrenemies/CuffedFrenemies.csproj
Normal file
@ -0,0 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
</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="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>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -27,7 +27,7 @@ namespace GamblingCoin
|
||||
|
||||
public class GamblingCoinMessages
|
||||
{
|
||||
public String SpawnWaveMessage { get; set; } = "Did someone just enter the Site...?";
|
||||
public string SpawnWaveMessage { get; set; } = "Did someone just enter the Site...?";
|
||||
public string ItemSpawnMessage { get; set; } = "*plop*";
|
||||
public string UncommonItemSpawnMessage { get; set; } = "*bump*";
|
||||
public string RareItemSpawnMessage { get; set; } = "*badunk*";
|
||||
|
29
KeycardButModern/DoorLockConfiguration.cs
Normal file
29
KeycardButModern/DoorLockConfiguration.cs
Normal 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;
|
||||
}
|
||||
}
|
@ -1,8 +1,14 @@
|
||||
using InventorySystem.Items.Keycards;
|
||||
using System.Collections;
|
||||
using Interactables.Interobjects;
|
||||
using Interactables.Interobjects.DoorButtons;
|
||||
using Interactables.Interobjects.DoorUtils;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Events.Handlers;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Console;
|
||||
using LabApi.Loader;
|
||||
using UnityEngine;
|
||||
using KeycardItem = InventorySystem.Items.Keycards.KeycardItem;
|
||||
using Logger = LabApi.Features.Console.Logger;
|
||||
|
||||
namespace KeycardButModern
|
||||
{
|
||||
@ -14,21 +20,27 @@ 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)
|
||||
{
|
||||
Logger.Debug("Door can be opened, no need for implant check");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.Door.IsLocked)
|
||||
{
|
||||
Logger.Debug("Door has active locks");
|
||||
return;
|
||||
}
|
||||
|
||||
var permissions = ev.Door.Permissions;
|
||||
|
||||
foreach (var playerItem in ev.Player.Items)
|
||||
{
|
||||
@ -39,28 +51,183 @@ namespace KeycardButModern
|
||||
continue;
|
||||
}
|
||||
|
||||
var keycardPermissions = keycardItem.GetPermissions(ev.Door.Base);
|
||||
|
||||
Logger.Debug($"Item is a keycard: {keycardPermissions} vs {permissions} = {keycardPermissions & permissions}");
|
||||
|
||||
if ((keycardPermissions & permissions) != permissions) continue;
|
||||
ev.Door.IsOpened = true;
|
||||
Logger.Debug("Door can be opened");
|
||||
if (!ev.Door.Base.CheckPermissions(keycardItem, out _)) continue;
|
||||
ev.Door.IsOpened = !ev.Door.IsOpened;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInteractingGenerator(PlayerInteractingGeneratorEventArgs ev)
|
||||
{
|
||||
if (!ev.IsAllowed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Debug("starting...");
|
||||
PlayerEvents.InteractingDoor += OnInteractingDoor;
|
||||
if (ev.Player.CurrentItem?.Base is KeycardItem keycard)
|
||||
{
|
||||
if (ev.Generator.Base.CheckPermissions(keycard, out _))
|
||||
{
|
||||
ev.Generator.IsUnlocked = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev.Generator.IsUnlocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
foreach (var playerItem in ev.Player.Items)
|
||||
{
|
||||
//is keycard?
|
||||
if (playerItem.Type > ItemType.KeycardO5) continue;
|
||||
if (playerItem.Base is not KeycardItem keycardItem)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ev.Generator.Base.CheckPermissions(keycardItem, out _)) continue;
|
||||
ev.Generator.IsOpen = !ev.Generator.IsOpen;
|
||||
ev.Generator.IsUnlocked = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInteractingLocker(PlayerInteractingLockerEventArgs ev)
|
||||
{
|
||||
if (!ev.IsAllowed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.Chamber.Base.RequiredPermissions == DoorPermissionFlags.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.Player.CurrentItem?.Base is KeycardItem keycard)
|
||||
{
|
||||
if (ev.Chamber.Base.CheckPermissions(keycard, out _)) return;
|
||||
}
|
||||
|
||||
foreach (var playerItem in ev.Player.Items)
|
||||
{
|
||||
//is keycard?
|
||||
if (playerItem.Type > ItemType.KeycardO5) continue;
|
||||
if (playerItem.Base is not KeycardItem keycardItem)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ev.Chamber.Base.CheckPermissions(keycardItem, out _)) continue;
|
||||
ev.Chamber.IsOpen = !ev.Chamber.IsOpen;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnlockingWarhead(PlayerUnlockingWarheadButtonEventArgs ev)
|
||||
{
|
||||
if (ev.IsAllowed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var playerItem in ev.Player.Items)
|
||||
{
|
||||
//is keycard?
|
||||
if (playerItem.Type > ItemType.KeycardO5) continue;
|
||||
if (playerItem.Base is not KeycardItem keycardItem)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!AlphaWarheadActivationPanel.Instance.CheckPermissions(keycardItem, out _)) continue;
|
||||
ev.IsAllowed = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
PlayerEvents.InteractingDoor -= OnInteractingDoor;
|
||||
PlayerEvents.InteractingGenerator -= OnInteractingGenerator;
|
||||
PlayerEvents.InteractingLocker -= OnInteractingLocker;
|
||||
PlayerEvents.UnlockingWarheadButton -= OnUnlockingWarhead;
|
||||
|
||||
PlayerEvents.PlacedBulletHole -= OnBulletHole;
|
||||
Logger.Debug("unloading...");
|
||||
|
||||
Singleton = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
31
LogEvents/Class1.cs
Normal file
31
LogEvents/Class1.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using LabApi.Events.CustomHandlers;
|
||||
using LabApi.Features;
|
||||
using LabApi.Loader.Features.Plugins;
|
||||
|
||||
namespace LogEvents
|
||||
{
|
||||
internal class LogPlugin : Plugin
|
||||
{
|
||||
public override string Name { get; } = "LogPlugin";
|
||||
|
||||
public override string Description { get; } = "Example Plugin that logs (almost) all events.";
|
||||
|
||||
public override string Author { get; } = "Northwood";
|
||||
|
||||
public override Version Version { get; } = new Version(1, 0, 0, 0);
|
||||
|
||||
public override Version RequiredApiVersion { get; } = new Version(LabApiProperties.CompiledVersion);
|
||||
|
||||
public MyCustomEventsHandler Events { get; } = new();
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
CustomHandlersManager.RegisterEventsHandler(Events);
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
CustomHandlersManager.UnregisterEventsHandler(Events);
|
||||
}
|
||||
}
|
||||
}
|
1401
LogEvents/LogEvents.cs
Normal file
1401
LogEvents/LogEvents.cs
Normal file
File diff suppressed because it is too large
Load Diff
43
LogEvents/LogEvents.csproj
Normal file
43
LogEvents/LogEvents.csproj
Normal file
@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
</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="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>
|
||||
<Reference Include="UnityEngine.Physics2DModule">
|
||||
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.Physics2DModule.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>
|
||||
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
27
RangeBan.Tests/RangeBan.Tests.csproj
Normal file
27
RangeBan.Tests/RangeBan.Tests.csproj
Normal file
@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.3.2" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.4.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="NUnit.Framework"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RangeBan\RangeBan.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
62
RangeBan.Tests/UnitTest1.cs
Normal file
62
RangeBan.Tests/UnitTest1.cs
Normal file
@ -0,0 +1,62 @@
|
||||
namespace RangeBan.Tests;
|
||||
|
||||
[TestFixture]
|
||||
public class IpRangeTests
|
||||
{
|
||||
[Test]
|
||||
public void IsInRange_WithNullInput_ReturnsFalse()
|
||||
{
|
||||
Assert.That(RangeBan.IsInRange("192.168.1.0/24", null), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsInRange_WithEmptyInput_ReturnsFalse()
|
||||
{
|
||||
Assert.That(RangeBan.IsInRange("192.168.1.0/24", ""), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsInRange_WithInvalidRange_ReturnsFalse()
|
||||
{
|
||||
Assert.That(RangeBan.IsInRange("invalid-range", "192.168.1.1"), Is.False);
|
||||
}
|
||||
|
||||
[TestCase("192.168.1.0/24", "192.168.1.1", true)]
|
||||
[TestCase("192.168.1.0/24", "192.168.1.254", true)]
|
||||
[TestCase("192.168.1.0/24", "192.168.2.1", false)]
|
||||
[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));
|
||||
}
|
||||
|
||||
[TestCase("192.168.2.0/33")]
|
||||
[TestCase("192.168.1.0/invalid")]
|
||||
public void IsInRange_WithInvalidCidrNotation_ReturnsFalse(string range)
|
||||
{
|
||||
Assert.That(RangeBan.IsInRange(range, "192.168.1.1"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsInRange_WithInvalidIpAddress_ThrowsArgumentException()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => RangeBan.IsInRange("192.168.1.0/24", "invalid.ip.address"));
|
||||
}
|
||||
|
||||
[TestCase("192.168.1.0/24", "192.168.1")]
|
||||
[TestCase("192.168.1.0/24", "192.168.1.1.1")]
|
||||
[TestCase("192.168.1.0/24", "not.an.ip.address")]
|
||||
public void IsInRange_WithMalformedIpAddress_ThrowsArgumentException(string range, string ip)
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => RangeBan.IsInRange(range, ip));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsInRange_WithValidPublicIp_DoesNotThrow()
|
||||
{
|
||||
Assert.DoesNotThrow(() => RangeBan.IsInRange("192.168.1.0/24", "8.8.8.8"));
|
||||
}
|
||||
}
|
94
RangeBan/RangeBan.cs
Normal file
94
RangeBan/RangeBan.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System.Runtime.Serialization;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Events.Handlers;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Console;
|
||||
using LabApi.Loader.Features.Plugins;
|
||||
|
||||
namespace RangeBan;
|
||||
|
||||
public class RangeBan: Plugin<RangeBanConfig>
|
||||
{
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Debug("Loading...");
|
||||
PlayerEvents.PreAuthenticating += OnAuth;
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
Logger.Debug("Disabling...");
|
||||
PlayerEvents.PreAuthenticating -= OnAuth;
|
||||
}
|
||||
|
||||
private void OnAuth(PlayerPreAuthenticatingEventArgs ev)
|
||||
{
|
||||
Logger.Debug($"Ranges: {string.Join(" ; ", Config!.IpRanges)}");
|
||||
if (!Config!.IpRanges.Any(configIpRange => IsInRange(configIpRange, ev.IpAddress))) return;
|
||||
ev.RejectCustom("Your IP belongs to a banned player, please contact the server administrator for more information.");
|
||||
Logger.Warn($"Player with IP {ev.IpAddress} got kicked. UserId: {ev.UserId}");
|
||||
}
|
||||
|
||||
public override string Name => "RangeBan";
|
||||
public override string Author => "Code002Lover";
|
||||
public override Version Version { get; } = new(1, 0, 0);
|
||||
public override string Description => "Ban IP Ranges with ease";
|
||||
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||
|
||||
|
||||
public static bool IsInRange(string range, string ip)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ip) || string.IsNullOrEmpty(range))
|
||||
return false;
|
||||
|
||||
// Handle CIDR notation (e.g., "192.168.1.0/24")
|
||||
if (!range.Contains("/"))
|
||||
{
|
||||
//We only handle direct IPs and CIDR
|
||||
if (range.Split('.').Length != 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ip == range;
|
||||
};
|
||||
|
||||
var parts = range.Split('/');
|
||||
if (parts.Length != 2 || !int.TryParse(parts[1], out var cidrBits))
|
||||
return false;
|
||||
|
||||
if (cidrBits > 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var networkAddress = IPToUInt32(parts[0]);
|
||||
var mask = uint.MaxValue << (32 - cidrBits);
|
||||
var ipAddress = IPToUInt32(ip);
|
||||
|
||||
return (ipAddress & mask) == (networkAddress & mask);
|
||||
|
||||
}
|
||||
|
||||
private static uint IPToUInt32(string ipAddress)
|
||||
{
|
||||
var parts = ipAddress.Split('.');
|
||||
if (parts.Length != 4)
|
||||
throw new ArgumentException("Invalid IP address format");
|
||||
|
||||
uint result = 0;
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
if (!byte.TryParse(parts[i], out var part))
|
||||
throw new ArgumentException("Invalid IP address segment");
|
||||
result = (result << 8) | part;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class RangeBanConfig
|
||||
{
|
||||
public string[] IpRanges { get; set; } = {};
|
||||
}
|
37
RangeBan/RangeBan.csproj
Normal file
37
RangeBan/RangeBan.csproj
Normal file
@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
</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="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>
|
96
SCPTeamHint/SCPTeamHint.cs
Normal file
96
SCPTeamHint/SCPTeamHint.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using HintServiceMeow.Core.Enum;
|
||||
using HintServiceMeow.Core.Models.Hints;
|
||||
using HintServiceMeow.Core.Utilities;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Events.Handlers;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Console;
|
||||
using LabApi.Features.Wrappers;
|
||||
using PlayerRoles;
|
||||
using PlayerRoles.PlayableScps.Scp096;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace SCPTeamHint
|
||||
{
|
||||
public class Plugin : LabApi.Loader.Features.Plugins.Plugin
|
||||
{
|
||||
public override string Name => "SCPTeamHint";
|
||||
public override string Author => "HoherGeist, Code002Lover";
|
||||
public override Version Version { get; } = new(1, 0, 0);
|
||||
public override string Description => "Displays information about your SCP Teammates";
|
||||
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||
|
||||
private Timer _timer;
|
||||
private readonly Dictionary<Player,Hint> _spectatorHints = new();
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Debug("Apple juice");
|
||||
PlayerEvents.Joined += OnJoin;
|
||||
|
||||
_timer = new Timer(1000);
|
||||
_timer.Elapsed += (_,_) => UpdateHints();
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
PlayerEvents.Joined -= OnJoin;
|
||||
_timer.Stop();
|
||||
}
|
||||
|
||||
private void UpdateHints()
|
||||
{
|
||||
var hintTexts = new List<string>();
|
||||
|
||||
foreach (var player in Player.List)
|
||||
{
|
||||
if (!player.IsSCP) continue;
|
||||
|
||||
var text = $"{player.RoleBase.RoleName} | {player.HumeShield} | {player.Health} | {player.Zone}";
|
||||
|
||||
if (player.RoleBase is Scp096Role scp)
|
||||
{
|
||||
text += "\n";
|
||||
|
||||
scp.SubroutineModule.TryGetSubroutine(out Scp096TargetsTracker tracker);
|
||||
|
||||
text += $"Targets: {tracker.Targets.Count}";
|
||||
}
|
||||
|
||||
hintTexts.Add(text);
|
||||
}
|
||||
|
||||
foreach (var player in Player.List.Where(x=>!x.IsHost))
|
||||
{
|
||||
Logger.Debug($"Updating hint for {player.DisplayName}");
|
||||
UpdateHint(player, string.Join("\n", hintTexts));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateHint(Player player, string hintText)
|
||||
{
|
||||
var hint = _spectatorHints[player];
|
||||
|
||||
Logger.Debug($"Player {player.Nickname} is on team {player.RoleBase.Team} | hide: {player.RoleBase.Team != Team.SCPs}");
|
||||
hint.Hide = player.RoleBase.Team != Team.SCPs;
|
||||
|
||||
hint.Text = hintText;
|
||||
}
|
||||
|
||||
private void OnJoin(PlayerJoinedEventArgs ev)
|
||||
{
|
||||
|
||||
var hint = new Hint
|
||||
{
|
||||
Text = "Apfelsaft", Alignment = HintAlignment.Left, YCoordinate = 300, Hide = true
|
||||
};
|
||||
|
||||
var playerDisplay = PlayerDisplay.Get(ev.Player);
|
||||
playerDisplay.AddHint(hint);
|
||||
|
||||
_spectatorHints[ev.Player] = hint;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
46
SCPTeamHint/SCPTeamHint.csproj
Normal file
46
SCPTeamHint/SCPTeamHint.csproj
Normal file
@ -0,0 +1,46 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
</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="0Harmony">
|
||||
<HintPath>..\dependencies\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<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="HintServiceMeow">
|
||||
<HintPath>..\dependencies\HintServiceMeow-LabAPI.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="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>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -6,7 +6,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeycardButModern", "Keycard
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisibleSpectators", "VisibleSpectators\VisibleSpectators.csproj", "{F320856D-6340-4DD5-89F7-EE44611DF8E8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SCPList", "SCPList\SCPList.csproj", "{2EFB3C10-A917-4840-97CD-B36733D666DE}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SensitiveGrenades", "SensitiveGrenades\SensitiveGrenades.csproj", "{2EFB3C10-A917-4840-97CD-B36733D666DE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SCPTeamHint", "SCPTeamHint\SCPTeamHint.csproj", "{01A046C2-9083-4BDB-AC45-BA24966650D7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogEvents", "LogEvents\LogEvents.csproj", "{2C9FD537-231C-4486-8C1B-6359E5120D19}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RangeBan", "RangeBan\RangeBan.csproj", "{17798161-3317-4E64-880D-1CD7DE0EBE56}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RangeBan.Tests", "RangeBan.Tests\RangeBan.Tests.csproj", "{AA495D0E-0122-4C26-8D26-C728B65BFF12}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CuffedFrenemies", "CuffedFrenemies\CuffedFrenemies.csproj", "{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -30,5 +40,25 @@ Global
|
||||
{2EFB3C10-A917-4840-97CD-B36733D666DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2EFB3C10-A917-4840-97CD-B36733D666DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2EFB3C10-A917-4840-97CD-B36733D666DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{01A046C2-9083-4BDB-AC45-BA24966650D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{01A046C2-9083-4BDB-AC45-BA24966650D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{01A046C2-9083-4BDB-AC45-BA24966650D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{01A046C2-9083-4BDB-AC45-BA24966650D7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2C9FD537-231C-4486-8C1B-6359E5120D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2C9FD537-231C-4486-8C1B-6359E5120D19}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2C9FD537-231C-4486-8C1B-6359E5120D19}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2C9FD537-231C-4486-8C1B-6359E5120D19}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{17798161-3317-4E64-880D-1CD7DE0EBE56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{17798161-3317-4E64-880D-1CD7DE0EBE56}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{17798161-3317-4E64-880D-1CD7DE0EBE56}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{17798161-3317-4E64-880D-1CD7DE0EBE56}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AA495D0E-0122-4C26-8D26-C728B65BFF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AA495D0E-0122-4C26-8D26-C728B65BFF12}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AA495D0E-0122-4C26-8D26-C728B65BFF12}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA495D0E-0122-4C26-8D26-C728B65BFF12}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C3FEEC52-B7C0-4DB6-A0CA-54BE175072D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{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
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
53
SensitiveGrenades/SensitiveGrenades.cs
Normal file
53
SensitiveGrenades/SensitiveGrenades.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using InventorySystem.Items.Pickups;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Events.Handlers;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Wrappers;
|
||||
using LabApi.Loader.Features.Plugins;
|
||||
using UnityEngine;
|
||||
using Logger = LabApi.Features.Console.Logger;
|
||||
using TimedGrenadePickup = InventorySystem.Items.ThrowableProjectiles.TimedGrenadePickup;
|
||||
|
||||
namespace SensitiveGrenades
|
||||
{
|
||||
public class SensitiveGrenades : Plugin
|
||||
{
|
||||
public override string Name => "SensitiveGrenades";
|
||||
public override string Author => "Code002Lover";
|
||||
public override Version Version { get; } = new(1, 0, 0);
|
||||
public override string Description => "Shoot grenades to blow them up!";
|
||||
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Debug("starting...");
|
||||
|
||||
PlayerEvents.PlacedBulletHole += ShotWeapon;
|
||||
}
|
||||
|
||||
private static void ShotWeapon(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)
|
||||
{
|
||||
var itemPickup = hit.collider.GetComponent<ItemPickupBase>();
|
||||
|
||||
var grenade = itemPickup as TimedGrenadePickup;
|
||||
|
||||
if (!grenade) continue;
|
||||
|
||||
itemPickup.DestroySelf();
|
||||
TimedGrenadeProjectile.SpawnActive(itemPickup.Position, itemPickup.Info.ItemId, ev.Player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
Logger.Debug("unloading...");
|
||||
}
|
||||
}
|
||||
}
|
44
SensitiveGrenades/SensitiveGrenades.csproj
Normal file
44
SensitiveGrenades/SensitiveGrenades.csproj
Normal file
@ -0,0 +1,44 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
<RootNamespace>SensitiveGrenades</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="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>
|
||||
<Reference Include="UnityEngine.Physics2DModule">
|
||||
<HintPath>..\..\.local\share\Steam\steamapps\common\SCP Secret Laboratory Dedicated Server\SCPSL_Data\Managed\UnityEngine.Physics2DModule.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>
|
||||
<PackageReference Include="Northwood.LabAPI" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user