Skip to content

Commit 91e9953

Browse files
committed
Add Files
0 parents  commit 91e9953

File tree

10 files changed

+453
-0
lines changed

10 files changed

+453
-0
lines changed

ScpProximityChat-LabAPI.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.13.35617.110 d17.13
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScpProximityChat-LabAPI", "ScpProximityChat-LabAPI\ScpProximityChat-LabAPI.csproj", "{181A12EA-BBFF-47C8-9A77-CF0C1D19F678}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{181A12EA-BBFF-47C8-9A77-CF0C1D19F678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{181A12EA-BBFF-47C8-9A77-CF0C1D19F678}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{181A12EA-BBFF-47C8-9A77-CF0C1D19F678}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{181A12EA-BBFF-47C8-9A77-CF0C1D19F678}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {9DB16192-77AC-4FB8-9845-7744360D6DC2}
24+
EndGlobalSection
25+
EndGlobal

ScpProximityChat-LabAPI/Config.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using LabApi.Loader.Features.Configuration;
2+
using PlayerRoles;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
namespace ScpProximityChat_LabAPI
10+
{
11+
public class Config : LabApiConfig
12+
{
13+
public bool Enabled { get; set; } = true;
14+
15+
public bool ToggleChat { get; set; } = true;
16+
17+
public string ProximityChatEnabledMessage { get; set; } = "<i><b>proximity chat <color=#42f57b>enabled</color></b></i>";
18+
public string ProximityChatDisabledMessage { get; set; } = "<i><b>proximity chat <color=red>disabled</color></b></i>";
19+
20+
public float MaxProximityDistance { get; set; } = 7f;
21+
22+
public HashSet<RoleTypeId> AllowedRoles { get; set; } =
23+
[
24+
RoleTypeId.Scp049,
25+
RoleTypeId.Scp096,
26+
RoleTypeId.Scp106,
27+
RoleTypeId.Scp173,
28+
RoleTypeId.Scp0492,
29+
RoleTypeId.Scp939
30+
];
31+
32+
public bool SendBroadcastOnRoleChange { get; set; } = false;
33+
public ushort BroadcastDuration { get; set; } = 5;
34+
public string BroadcastMessage { get; set; } = "<b>Proximity Chat can be toggled with the <color=#42f57b>[ALT]</color> key</b>.";
35+
}
36+
}

ScpProximityChat-LabAPI/Events.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using LabApi.Events.Arguments.PlayerEvents;
2+
using LabApi.Events.CustomHandlers;
3+
using LabApi.Features.Wrappers;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace ScpProximityChat_LabAPI
11+
{
12+
public class Events : CustomEventsHandler
13+
{
14+
public override void OnServerRoundRestarted()
15+
{
16+
Handler.ToggledPlayers.Clear();
17+
}
18+
19+
public override void OnPlayerChangedRole(PlayerChangedRoleEventArgs ev)
20+
{
21+
if (!ScpProximityChat.SharedConfig.SendBroadcastOnRoleChange)
22+
return;
23+
24+
if (!ScpProximityChat.SharedConfig.AllowedRoles.Contains(ev.NewRole.RoleTypeId))
25+
return;
26+
27+
ev.Player.SendBroadcast(ScpProximityChat.SharedConfig.BroadcastMessage, ScpProximityChat.SharedConfig.BroadcastDuration);
28+
}
29+
}
30+
}

ScpProximityChat-LabAPI/Handler.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Hints;
7+
using Mirror;
8+
using PlayerRoles.FirstPersonControl;
9+
using PlayerRoles.Spectating;
10+
using PlayerRoles.Voice;
11+
using UnityEngine;
12+
using VoiceChat;
13+
using VoiceChat.Networking;
14+
15+
namespace ScpProximityChat_LabAPI
16+
{
17+
public class Handler
18+
{
19+
public static readonly HashSet<ReferenceHub> ToggledPlayers = [];
20+
21+
public static bool OnPlayerTogglingNoClip(ReferenceHub player)
22+
{
23+
if (FpcNoclip.IsPermitted(player))
24+
return true;
25+
26+
if (!ScpProximityChat.SharedConfig.AllowedRoles.Contains(player.roleManager.CurrentRole.RoleTypeId))
27+
return true;
28+
29+
if (!ToggledPlayers.Add(player))
30+
{
31+
ToggledPlayers.Remove(player);
32+
player.hints.Show(new TextHint(ScpProximityChat.SharedConfig.ProximityChatDisabledMessage, [new StringHintParameter(string.Empty)], null, 4));
33+
return false;
34+
}
35+
36+
player.hints.Show(new TextHint(ScpProximityChat.SharedConfig.ProximityChatEnabledMessage, [new StringHintParameter(string.Empty)], null, 4));
37+
return false;
38+
}
39+
40+
public static bool OnPlayerUsingVoiceChat(NetworkConnection connection, VoiceMessage message)
41+
{
42+
if (message.Channel != VoiceChatChannel.ScpChat)
43+
return true;
44+
45+
if (!ReferenceHub.TryGetHubNetID(connection.identity.netId, out ReferenceHub player))
46+
return true;
47+
48+
if (!ScpProximityChat.SharedConfig.AllowedRoles.Contains(player.roleManager.CurrentRole.RoleTypeId) || (ScpProximityChat.SharedConfig.ToggleChat && !ToggledPlayers.Contains(player)))
49+
return true;
50+
51+
SendProximityMessage(message);
52+
return !ScpProximityChat.SharedConfig.ToggleChat;
53+
}
54+
55+
private static void SendProximityMessage(VoiceMessage msg)
56+
{
57+
foreach (ReferenceHub referenceHub in ReferenceHub.AllHubs)
58+
{
59+
if (referenceHub.roleManager.CurrentRole is SpectatorRole && !msg.Speaker.IsSpectatedBy(referenceHub))
60+
continue;
61+
62+
if (referenceHub.roleManager.CurrentRole is not IVoiceRole voiceRole2)
63+
continue;
64+
65+
if (Vector3.Distance(msg.Speaker.transform.position, referenceHub.transform.position) >= ScpProximityChat.SharedConfig.MaxProximityDistance)
66+
continue;
67+
68+
if (voiceRole2.VoiceModule.ValidateReceive(msg.Speaker, VoiceChatChannel.Proximity) is VoiceChatChannel.None)
69+
continue;
70+
71+
msg.Channel = VoiceChatChannel.Proximity;
72+
referenceHub.connectionToClient.Send(msg);
73+
}
74+
}
75+
}
76+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using HarmonyLib;
2+
using NorthwoodLib.Pools;
3+
using PlayerRoles.FirstPersonControl.NetworkMessages;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Reflection.Emit;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace ScpProximityChat_LabAPI.Patches;
12+
13+
[HarmonyPatch(typeof(FpcNoclipToggleMessage), nameof(FpcNoclipToggleMessage.ProcessMessage))]
14+
public class NoClipTogglePatch
15+
{
16+
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
17+
{
18+
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Shared.Rent(instructions);
19+
20+
Label ret = generator.DefineLabel();
21+
22+
newInstructions[newInstructions.Count - 1].labels.Add(ret);
23+
24+
int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Ret) + 1;
25+
26+
newInstructions.InsertRange(index, new CodeInstruction[]
27+
{
28+
new CodeInstruction(OpCodes.Ldloc_0).MoveLabelsFrom(newInstructions[index]),
29+
new (OpCodes.Call, AccessTools.Method(typeof(Handler), nameof(Handler.OnPlayerTogglingNoClip))),
30+
new (OpCodes.Brfalse, ret),
31+
});
32+
33+
foreach (CodeInstruction instruction in newInstructions)
34+
yield return instruction;
35+
36+
ListPool<CodeInstruction>.Shared.Return(newInstructions);
37+
}
38+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection.Emit;
5+
using System.Reflection;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using HarmonyLib;
9+
using Mirror;
10+
using NorthwoodLib.Pools;
11+
using VoiceChat.Networking;
12+
13+
14+
namespace ScpProximityChat_LabAPI.Patches;
15+
16+
[HarmonyPatch(typeof(VoiceTransceiver), "ServerReceiveMessage")]
17+
public class VoiceChatPatch
18+
{
19+
private static MethodInfo GetSendMethod()
20+
{
21+
foreach (MethodInfo method in typeof(NetworkConnection).GetMethods())
22+
{
23+
if (method.Name is nameof(NetworkConnection.Send) && method.GetGenericArguments().Length != 0)
24+
return method.MakeGenericMethod(typeof(VoiceMessage));
25+
}
26+
27+
return null;
28+
}
29+
30+
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
31+
{
32+
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Shared.Rent(instructions);
33+
34+
Label ret = generator.DefineLabel();
35+
36+
newInstructions[newInstructions.Count - 1].labels.Add(ret);
37+
38+
int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldloc_0);
39+
40+
newInstructions.InsertRange(index, new[]
41+
{
42+
new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]),
43+
new (OpCodes.Ldarg_1),
44+
new (OpCodes.Call, AccessTools.Method(typeof(Handler), nameof(Handler.OnPlayerUsingVoiceChat))),
45+
new (OpCodes.Brfalse_S, ret),
46+
});
47+
48+
foreach (CodeInstruction instruction in newInstructions)
49+
yield return instruction;
50+
51+
ListPool<CodeInstruction>.Shared.Return(newInstructions);
52+
}
53+
}

ScpProximityChat-LabAPI/Plugin.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using LabApi.Loader.Features.Plugins;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using LabApi.Events.CustomHandlers;
8+
using LabApi.Features;
9+
using LabApi.Features.Console;
10+
using LabApi.Loader.Features.Plugins.Enums;
11+
using HarmonyLib;
12+
13+
namespace ScpProximityChat_LabAPI
14+
{
15+
public class ScpProximityChat : Plugin<Config>
16+
{
17+
public static ScpProximityChat Instance { get; private set; }
18+
public Events Events { get; } = new Events();
19+
public override string Name { get; } = "ScpProximityChat";
20+
public override string Description { get; } = "Makes SCPs able to talk inside the proximity chat.";
21+
public override string Author { get; } = "FortNbreak";
22+
public override Version Version { get; } = new Version(1, 0, 0);
23+
public override Version RequiredApiVersion { get; } = new Version(LabApiProperties.CompiledVersion);
24+
public override string ConfigFileName { get; set; } = "scpproximitychat.yml";
25+
private static readonly Harmony HarmonyPatcher = new("scpproximitymodule.fortnbreak.com");
26+
public static Config SharedConfig { get; private set; }
27+
28+
public override void Enable()
29+
{
30+
if (!base.Config.Enabled)
31+
{
32+
Logger.Info("Plugin is set to not start, change the configuration file if this is a mistake");
33+
return;
34+
}
35+
36+
Logger.Info("Starting plugin...");
37+
38+
ScpProximityChat.Instance = this;
39+
40+
Logger.Info("Loading config.");
41+
42+
SharedConfig = base.Config;
43+
44+
Logger.Info("Registering events...");
45+
46+
CustomHandlersManager.RegisterEventsHandler<Events>(this.Events);
47+
48+
Logger.Info("Applying Harmony patches.");
49+
50+
HarmonyPatcher.PatchAll();
51+
52+
Logger.Info("Plugin has been enabled.");
53+
}
54+
55+
public override void Disable()
56+
{
57+
Logger.Info("Stopping plugin...");
58+
59+
ScpProximityChat.Instance = null;
60+
61+
Logger.Info("Loading config.");
62+
63+
SharedConfig = null;
64+
65+
Logger.Info("Unregistering events...");
66+
67+
CustomHandlersManager.UnregisterEventsHandler<Events>(this.Events);
68+
69+
Logger.Info("Unapplying Harmony patches.");
70+
71+
HarmonyPatcher.UnpatchAll();
72+
73+
Logger.Info("Plugin has been disabled.");
74+
}
75+
}
76+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("ScpProximityChat-LabAPI")]
9+
[assembly: AssemblyDescription("ScpProximityChat for LabAPI")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("FortNberak")]
12+
[assembly: AssemblyProduct("ScpProximityChat-LabAPI")]
13+
[assembly: AssemblyCopyright("Copyright © 2025")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("181a12ea-bbff-47c8-9a77-cf0c1d19f678")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
[assembly: AssemblyVersion("1.0.0.0")]
33+
[assembly: AssemblyFileVersion("1.0.0.0")]

0 commit comments

Comments
 (0)