├── Lobby ├── API │ ├── Enums │ │ └── LobbyLocationType.cs │ └── LobbyLocationHandler.cs ├── packages.config ├── Patches │ └── StaminaUsageMultiplierPatch.cs ├── RestrictionsHandler.cs ├── Command │ ├── LobbyParentCommand.cs │ ├── DebugCommands │ │ ├── GetLocalDataCommand.cs │ │ ├── LocationListCommand.cs │ │ └── TpLocationCommand.cs │ └── ControlCommands │ │ ├── RemoveLocationCommand.cs │ │ └── AddLocationCommand.cs ├── Properties │ └── AssemblyInfo.cs ├── Lobby.cs ├── Lobby.csproj ├── Config.cs └── EventsHandler.cs ├── .gitignore ├── Lobby.sln └── README.md /Lobby/API/Enums/LobbyLocationType.cs: -------------------------------------------------------------------------------- 1 | namespace Lobby 2 | { 3 | public enum LobbyLocationType 4 | { 5 | Tower_1, 6 | Tower_2, 7 | Tower_3, 8 | Tower_4, 9 | Tower_5, 10 | Intercom, 11 | GR18, 12 | SCP173 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Lobby/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build results 2 | [Dd]ebug/ 3 | [Dd]ebugPublic/ 4 | [Rr]elease/ 5 | [Rr]eleases/ 6 | x64/ 7 | x86/ 8 | [Aa][Rr][Mm]/ 9 | [Aa][Rr][Mm]64/ 10 | bld/ 11 | [Bb]in/ 12 | [Oo]bj/ 13 | [Ll]og/ 14 | [Ll]ogs/ 15 | .vs 16 | 17 | # NuGet Packages 18 | *.nupkg 19 | 20 | # The packages folder can be ignored because of Package Restore 21 | **/[Pp]ackages/* 22 | 23 | # User-specific files 24 | *.rsuser 25 | *.suo 26 | *.user 27 | *.userosscache 28 | *.sln.docstates -------------------------------------------------------------------------------- /Lobby/Patches/StaminaUsageMultiplierPatch.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using InventorySystem; 3 | 4 | namespace Lobby.Patches 5 | { 6 | [HarmonyPatch(typeof(Inventory), nameof(Inventory.StaminaUsageMultiplier), MethodType.Getter)] 7 | public class StaminaUsageMultiplierPatch 8 | { 9 | private static void Postfix(Inventory __instance, ref float __result) 10 | { 11 | if (Lobby.Instance.Config.InfinityStamina && EventsHandler.IsLobby) 12 | __result = 0; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Lobby/RestrictionsHandler.cs: -------------------------------------------------------------------------------- 1 | using LabApi.Events.Arguments.PlayerEvents; 2 | 3 | namespace Lobby 4 | { 5 | public class RestrictionsHandler 6 | { 7 | private bool IsLobby => EventsHandler.IsLobby; 8 | 9 | public void OnPlayerInteractingDoor(PlayerInteractingDoorEventArgs ev) => ev.IsAllowed = !IsLobby; 10 | 11 | public void OnPlayerInteractingElevator(PlayerInteractingElevatorEventArgs ev) 12 | { 13 | if (IsLobby) ev.IsAllowed = false; 14 | } 15 | 16 | public void OnPlayerSearchingPickup(PlayerSearchingPickupEventArgs ev) => ev.IsAllowed = !IsLobby; 17 | 18 | public void OnPlayerDroppingItem(PlayerDroppingItemEventArgs ev) => ev.IsAllowed = !IsLobby; 19 | 20 | public void OnPlayerDroppingAmmo(PlayerDroppingAmmoEventArgs ev) => ev.IsAllowed = !IsLobby; 21 | 22 | public void OnPlayerThrowingItem(PlayerThrowingItemEventArgs ev) => ev.IsAllowed = !IsLobby; 23 | 24 | public void OnPlayerUsingIntercom(PlayerUsingIntercomEventArgs ev) => ev.IsAllowed = (IsLobby && !Lobby.Instance.Config.AllowIcom ? false : true); 25 | } 26 | } -------------------------------------------------------------------------------- /Lobby.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33103.184 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lobby", "Lobby\Lobby.csproj", "{F6FFBCFD-6FDB-4185-AB54-20AB167DCA57}" 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 | {F6FFBCFD-6FDB-4185-AB54-20AB167DCA57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {F6FFBCFD-6FDB-4185-AB54-20AB167DCA57}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {F6FFBCFD-6FDB-4185-AB54-20AB167DCA57}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {F6FFBCFD-6FDB-4185-AB54-20AB167DCA57}.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 = {E12F31A4-0BE3-4079-AB00-A9622456A49F} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Lobby/Command/LobbyParentCommand.cs: -------------------------------------------------------------------------------- 1 | using CommandSystem; 2 | using Lobby.Command.ControlCommands; 3 | using Lobby.Command.DebugCommands; 4 | using System; 5 | 6 | namespace Lobby.Command 7 | { 8 | [CommandHandler(typeof(RemoteAdminCommandHandler))] 9 | public class LobbyParentCommand : ParentCommand 10 | { 11 | public LobbyParentCommand() => LoadGeneratedCommands(); 12 | 13 | public override string Command => "lobby"; 14 | 15 | public override string[] Aliases { get; } = { "lb", "ly" }; 16 | 17 | public override string Description => "Lobby parent command."; 18 | 19 | public override void LoadGeneratedCommands() 20 | { 21 | RegisterCommand(new AddLocationCommand()); 22 | RegisterCommand(new RemoveLocationCommand()); 23 | RegisterCommand(new LocationListCommand()); 24 | RegisterCommand(new TpLocationCommand()); 25 | RegisterCommand(new GetLocalDataCommand()); 26 | } 27 | 28 | protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, out string response) 29 | { 30 | response = "Incorrect command, use: \nlobby addloc\nlobby removeloc\nlobby loclist\nlobby tploc\nlobby getlocaldata"; 31 | return false; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Lobby/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Lobby")] 8 | [assembly: AssemblyDescription("A plugin that adds a lobby when waiting for players.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("MrAfitol")] 11 | [assembly: AssemblyProduct("Lobby")] 12 | [assembly: AssemblyCopyright("Copyright © MrAfitol 2022")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("f6ffbcfd-6fdb-4185-ab54-20ab167dca57")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.6.2.0")] 35 | [assembly: AssemblyFileVersion("1.6.2.0")] 36 | -------------------------------------------------------------------------------- /Lobby/Lobby.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using LabApi.Events.Handlers; 3 | using LabApi.Features; 4 | using LabApi.Loader.Features.Plugins; 5 | using System; 6 | 7 | namespace Lobby 8 | { 9 | public class Lobby : Plugin 10 | { 11 | public static Lobby Instance { get; private set; } 12 | 13 | public override string Name { get; } = "Lobby"; 14 | 15 | public override string Description { get; } = "A plugin that adds a lobby when waiting for players."; 16 | 17 | public override string Author { get; } = "MrAfitol"; 18 | 19 | public override Version Version { get; } = new Version(1, 6, 2); 20 | 21 | public override Version RequiredApiVersion { get; } = new Version(LabApiProperties.CompiledVersion); 22 | 23 | public Harmony Harmony { get; private set; } 24 | 25 | public EventsHandler EventsHandler { get; private set; } 26 | public RestrictionsHandler RestrictionsHandler { get; private set; } 27 | 28 | public override void Enable() 29 | { 30 | Instance = this; 31 | Harmony = new Harmony("lobby.scp.sl"); 32 | EventsHandler = new EventsHandler(); 33 | RestrictionsHandler = new RestrictionsHandler(); 34 | ServerEvents.WaitingForPlayers += EventsHandler.OnWaitingForPlayers; 35 | ServerEvents.RoundStarted += EventsHandler.OnRoundStarted; 36 | } 37 | 38 | public override void Disable() 39 | { 40 | ServerEvents.WaitingForPlayers -= EventsHandler.OnWaitingForPlayers; 41 | ServerEvents.RoundStarted -= EventsHandler.OnRoundStarted; 42 | EventsHandler.UnregisterHandlers(); 43 | RestrictionsHandler = null; 44 | EventsHandler = null; 45 | Harmony = null; 46 | Instance = null; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Lobby/Command/DebugCommands/GetLocalDataCommand.cs: -------------------------------------------------------------------------------- 1 | using CommandSystem; 2 | using LabApi.Features.Permissions; 3 | using LabApi.Features.Wrappers; 4 | using System; 5 | using UnityEngine; 6 | 7 | namespace Lobby.Command.DebugCommands 8 | { 9 | public class GetLocalDataCommand : ICommand 10 | { 11 | public string Command => "getlocaldata"; 12 | 13 | public string[] Aliases { get; } = { "getlocdat", "getld", "gld" }; 14 | 15 | public string Description => "Shows the exact position and rotation in the room where the player is located."; 16 | 17 | public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) 18 | { 19 | Player playerSender = Player.Get(sender); 20 | 21 | if (!playerSender.HasAnyPermission("lobby.*", "lobby.debug.*", "lobby.debug.getld")) 22 | { 23 | response = $"You don't have permission to use this command!"; 24 | return false; 25 | } 26 | 27 | if (arguments.Count > 0) 28 | { 29 | response = "Incorrect command, use: \nlobby getlocalpos"; 30 | return false; 31 | } 32 | 33 | if (playerSender.Room == null) 34 | { 35 | response = "An error occurred when getting the room you are in."; 36 | return false; 37 | } 38 | 39 | GameObject Point = new GameObject("Point"); 40 | Point.transform.position = playerSender.Position; 41 | Point.transform.rotation = playerSender.Rotation; 42 | Point.transform.SetParent(playerSender.Room.Transform); 43 | 44 | response = $"Room name {playerSender.Room.GameObject.name}; Local position: {Point.transform.localPosition.ToString()}; Local Rotation: {Point.transform.localEulerAngles.ToString()}."; 45 | return true; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Lobby/Command/ControlCommands/RemoveLocationCommand.cs: -------------------------------------------------------------------------------- 1 | using CommandSystem; 2 | using LabApi.Features.Permissions; 3 | using LabApi.Features.Wrappers; 4 | using System; 5 | 6 | namespace Lobby.Command.ControlCommands 7 | { 8 | public class RemoveLocationCommand : ICommand 9 | { 10 | public string Command => "removeloc"; 11 | 12 | public string[] Aliases { get; } = { "remloc", "rloc", "rl" }; 13 | 14 | public string Description => "Remove a new lobby location."; 15 | 16 | public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) 17 | { 18 | Player playerSender = Player.Get(sender); 19 | 20 | if (!playerSender.HasAnyPermission("lobby.*", "lobby.control.*", "lobby.control.remove")) 21 | { 22 | response = $"You don't have permission to use this command!"; 23 | return false; 24 | } 25 | 26 | if (arguments.Count != 2) 27 | { 28 | response = "Incorrect command, use: \nlobby removeloc room (index)\nlobby removeloc static (index)"; 29 | return false; 30 | } 31 | 32 | if (!Int32.TryParse(arguments.At(1), out int index)) 33 | { 34 | response = "The index must be a number!"; 35 | return false; 36 | } 37 | 38 | switch (arguments.At(0)) 39 | { 40 | case "room": 41 | if (Lobby.Instance.Config.CustomRoomLocations == null || Lobby.Instance.Config.CustomRoomLocations?.Count - 1 < index) 42 | { 43 | response = $"Custom location at index {index} was not found."; 44 | return false; 45 | } 46 | 47 | Lobby.Instance.Config.CustomRoomLocations.RemoveAt(index); 48 | Lobby.Instance.SaveConfig(); 49 | 50 | response = $"Custom location at index {index} has been removed."; 51 | return true; 52 | case "static": 53 | if (Lobby.Instance.Config.CustomLocations == null || Lobby.Instance.Config.CustomLocations?.Count - 1 < index) 54 | { 55 | response = $"Custom location at index {index} was not found."; 56 | return false; 57 | } 58 | 59 | Lobby.Instance.Config.CustomLocations.RemoveAt(index); 60 | Lobby.Instance.SaveConfig(); 61 | 62 | response = $"Custom location at index {index} has been removed."; 63 | return true; 64 | default: 65 | response = "Incorrect command, use: \nlobby removeloc room (index)\nlobby removeloc static (index)"; 66 | return false; 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Lobby/Command/ControlCommands/AddLocationCommand.cs: -------------------------------------------------------------------------------- 1 | using CommandSystem; 2 | using LabApi.Features.Permissions; 3 | using LabApi.Features.Wrappers; 4 | using System; 5 | using UnityEngine; 6 | 7 | namespace Lobby.Command.ControlCommands 8 | { 9 | public class AddLocationCommand : ICommand 10 | { 11 | public string Command => "addloc"; 12 | 13 | public string[] Aliases { get; } = { "add", "ad" }; 14 | 15 | public string Description => "Add a new lobby location."; 16 | 17 | public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) 18 | { 19 | Player playerSender = Player.Get(sender); 20 | 21 | if (!playerSender.HasAnyPermission("lobby.*", "lobby.control.*", "lobby.control.add")) 22 | { 23 | response = $"You don't have permission to use this command!"; 24 | return false; 25 | } 26 | 27 | if (arguments.Count != 1) 28 | { 29 | response = "Incorrect command, use: \nlobby addloc room\nlobby addloc static"; 30 | return false; 31 | } 32 | 33 | switch (arguments.At(0)) 34 | { 35 | case "room": 36 | GameObject Point = new GameObject("Point"); 37 | Point.transform.position = playerSender.Position; 38 | Point.transform.rotation = playerSender.Rotation; 39 | Point.transform.SetParent(playerSender.Room.Transform); 40 | 41 | CustomRoomLocationData roomLocationData = new CustomRoomLocationData(); 42 | roomLocationData.RoomNameType = playerSender.Room.GameObject.name; 43 | roomLocationData.OffsetX = Point.transform.localPosition.x; roomLocationData.OffsetY = Point.transform.localPosition.y + 0.05f; roomLocationData.OffsetZ = Point.transform.localPosition.z; 44 | roomLocationData.RotationX = Point.transform.localEulerAngles.x; roomLocationData.RotationY = Point.transform.localEulerAngles.y; roomLocationData.RotationZ = Point.transform.localEulerAngles.z; 45 | 46 | Lobby.Instance.Config.CustomRoomLocations.Add(roomLocationData); 47 | Lobby.Instance.SaveConfig(); 48 | response = "New custom location added to the config."; 49 | return true; 50 | case "static": 51 | CustomLocationData locationData = new CustomLocationData(); 52 | locationData.PositionX = playerSender.Position.x; locationData.PositionY = playerSender.Position.y + 0.05f; locationData.PositionZ = playerSender.Position.z; 53 | locationData.RotationX = playerSender.Rotation.x; locationData.RotationY = playerSender.Rotation.y; locationData.RotationZ = playerSender.Rotation.z; 54 | 55 | Lobby.Instance.Config.CustomLocations.Add(locationData); 56 | Lobby.Instance.SaveConfig(); 57 | response = "New custom location added to the config."; 58 | return true; 59 | default: 60 | response = "Incorrect command, use: \nlobby addloc room\nlobby addloc static"; 61 | return false; 62 | } 63 | } 64 | 65 | 66 | } 67 | } -------------------------------------------------------------------------------- /Lobby/Command/DebugCommands/LocationListCommand.cs: -------------------------------------------------------------------------------- 1 | using CommandSystem; 2 | using LabApi.Features.Permissions; 3 | using LabApi.Features.Wrappers; 4 | using System; 5 | 6 | namespace Lobby.Command.DebugCommands 7 | { 8 | public class LocationListCommand : ICommand 9 | { 10 | public string Command => "loclist"; 11 | 12 | public string[] Aliases { get; } = { "llist", "ll" }; 13 | 14 | public string Description => "Display a list of custom locations in the console."; 15 | 16 | public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) 17 | { 18 | Player playerSender = Player.Get(sender); 19 | 20 | if (!playerSender.HasAnyPermission("lobby.*", "lobby.debug.*", "lobby.debug.loclist")) 21 | { 22 | response = $"You don't have permission to use this command!"; 23 | return false; 24 | } 25 | 26 | if (arguments.Count != 1) 27 | { 28 | response = "Incorrect command, use: \nlobby loclist all\nlobby loclist room\nlobby loclist static"; 29 | return false; 30 | } 31 | 32 | string resString = string.Empty; 33 | 34 | switch (arguments.At(0)) 35 | { 36 | case "all": 37 | resString += "Room locations:\n"; 38 | if (Lobby.Instance.Config.CustomRoomLocations?.Count > 0) 39 | { 40 | foreach (var item in Lobby.Instance.Config.CustomRoomLocations) 41 | resString += item.RoomNameType + " " + $"({item.OffsetX}, {item.OffsetY}, {item.OffsetZ})\n"; 42 | } 43 | 44 | resString += "\nStatic locations:\n"; 45 | if (Lobby.Instance.Config.CustomLocations?.Count > 0) 46 | { 47 | foreach (var item in Lobby.Instance.Config.CustomLocations) 48 | resString += $"({item.PositionX}, {item.PositionY}, {item.PositionZ})\n"; 49 | } 50 | 51 | response = resString; 52 | return true; 53 | case "room": 54 | resString += "Room locations:\n"; 55 | if (Lobby.Instance.Config.CustomRoomLocations?.Count > 0) 56 | { 57 | for (int i = 0; i < Lobby.Instance.Config.CustomRoomLocations.Count; i++) 58 | { 59 | CustomRoomLocationData data = Lobby.Instance.Config.CustomRoomLocations[i]; 60 | resString += $"({i}) " + data.RoomNameType + " " + $"({data.OffsetX}, {data.OffsetY}, {data.OffsetZ})\n"; 61 | } 62 | } 63 | 64 | response = resString; 65 | return true; 66 | case "static": 67 | resString += "Static locations:\n"; 68 | if (Lobby.Instance.Config.CustomLocations?.Count > 0) 69 | { 70 | for (int i = 0; i < Lobby.Instance.Config.CustomLocations.Count; i++) 71 | { 72 | CustomLocationData data = Lobby.Instance.Config.CustomLocations[i]; 73 | resString += $"({i}) " + $"({data.PositionX}, {data.PositionY}, {data.PositionZ})\n"; 74 | } 75 | } 76 | 77 | response = resString; 78 | return true; 79 | default: 80 | response = "Incorrect command, use: \nlobby loclist all\nlobby loclist room\nlobby loclist static"; 81 | return false; 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /Lobby/API/LobbyLocationHandler.cs: -------------------------------------------------------------------------------- 1 | using MapGeneration; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using UnityEngine; 6 | 7 | namespace Lobby.API 8 | { 9 | public static class LobbyLocationHandler 10 | { 11 | public static GameObject Point; 12 | 13 | public static Dictionary LocationDatas = new Dictionary() 14 | { 15 | { LobbyLocationType.Tower_1, new CustomRoomLocationData() { RoomNameType = RoomName.Outside.ToString(), OffsetX = 162.893f, OffsetY = 20f, OffsetZ = -13.430f, RotationX = 0, RotationY = 270, RotationZ = 0 } }, 16 | { LobbyLocationType.Tower_2, new CustomRoomLocationData() { RoomNameType = RoomName.Outside.ToString(), OffsetX = 108.03f, OffsetY = 15f, OffsetZ = -13.71f, RotationX = 0, RotationY = 90, RotationZ = 0 } }, 17 | { LobbyLocationType.Tower_3, new CustomRoomLocationData() { RoomNameType = RoomName.Outside.ToString(), OffsetX = 39.12f, OffsetY = 15f, OffsetZ = -32f, RotationX = 0, RotationY = 270, RotationZ = 0 } }, 18 | { LobbyLocationType.Tower_4, new CustomRoomLocationData() { RoomNameType = RoomName.Outside.ToString(), OffsetX = -15.854f, OffsetY = 15f, OffsetZ = -31.543f, RotationX = 0, RotationY = 90, RotationZ = 0 } }, 19 | { LobbyLocationType.Tower_5, new CustomRoomLocationData() { RoomNameType = RoomName.Outside.ToString(), OffsetX = 130.43f, OffsetY = -5.6f, OffsetZ = 21f, RotationX = 0, RotationY = 180, RotationZ = 0 } }, 20 | { LobbyLocationType.Intercom, new CustomRoomLocationData() { RoomNameType = RoomName.EzIntercom.ToString(), OffsetX = -4.16f, OffsetY = -3.860f, OffsetZ = -2.113f, RotationX = 0, RotationY = 180, RotationZ = 0 } }, 21 | { LobbyLocationType.GR18, new CustomRoomLocationData() { RoomNameType = RoomName.LczGlassroom.ToString(), OffsetX = 4.8f, OffsetY = 1f, OffsetZ = 2.3f, RotationX = 0, RotationY = 180, RotationZ = 0 } }, 22 | { LobbyLocationType.SCP173, new CustomRoomLocationData() { RoomNameType = RoomName.Lcz173.ToString(), OffsetX = 17f, OffsetY = 13f, OffsetZ = 8f, RotationX = 0, RotationY = -90, RotationZ = 0 } }, 23 | }; 24 | 25 | public static void SetLocation(LocationData locationData) 26 | { 27 | if (locationData is CustomRoomLocationData customRoomLocation) 28 | { 29 | RoomIdentifier Room; 30 | 31 | if (Enum.TryParse(customRoomLocation.RoomNameType, out RoomName roomName)) 32 | { 33 | Room = RoomIdentifier.AllRoomIdentifiers.First(x => x.Name == roomName); 34 | 35 | if (customRoomLocation.RoomNameType == RoomName.EzIntercom.ToString()) 36 | EventsHandler.IsIntercom = true; 37 | } 38 | else if (RoomIdentifier.AllRoomIdentifiers.Count(x => x.name.Contains(customRoomLocation.RoomNameType)) > 0) 39 | { 40 | Room = RoomIdentifier.AllRoomIdentifiers.First(x => x.name.Contains(customRoomLocation.RoomNameType)); 41 | } 42 | else 43 | { 44 | customRoomLocation = (CustomRoomLocationData)LocationDatas[LobbyLocationType.GR18]; 45 | Room = RoomIdentifier.AllRoomIdentifiers.First(x => x.Name == ParseEnum(customRoomLocation.RoomNameType)); 46 | } 47 | 48 | Point.transform.SetParent(Room.transform); 49 | Point.transform.localPosition = new Vector3(customRoomLocation.OffsetX, customRoomLocation.OffsetY, customRoomLocation.OffsetZ); 50 | Point.transform.localRotation = Quaternion.Euler(customRoomLocation.RotationX, customRoomLocation.RotationY, customRoomLocation.RotationZ); 51 | } 52 | else if (locationData is CustomLocationData customLocation) 53 | { 54 | Point.transform.localPosition = new Vector3(customLocation.PositionX, customLocation.PositionY, customLocation.PositionZ); 55 | Point.transform.localRotation = Quaternion.Euler(customLocation.RotationX, customLocation.RotationY, customLocation.RotationZ); 56 | } 57 | } 58 | 59 | public static T ParseEnum(string value) 60 | { 61 | return (T)Enum.Parse(typeof(T), value, true); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lobby 2 | [![Version](https://img.shields.io/github/v/release/MrAfitol/Lobby?sort=semver&style=flat-square&color=blue&label=Version)](https://github.com/MrAfitol/Lobby/releases) 3 | [![Downloads](https://img.shields.io/github/downloads/MrAfitol/Lobby/total?style=flat-square&color=yellow&label=Downloads)](https://github.com/MrAfitol/Lobby/releases) 4 | 5 | 6 | A plugin that adds a lobby when waiting for players. 7 | 8 | The idea was inspired from this [plugin](https://github.com/Michal78900/WaitAndChillReborn). 9 | ## How to download? 10 | - *1. Find the SCP SL server config folder* 11 | 12 | *("C:\Users\(user name)\AppData\Roaming\SCP Secret Laboratory\" for windows, "/home/(user name)/.config/SCP Secret Laboratory/" for Linux)* 13 | 14 | - *2. Find the "PluginAPI" folder there, it contains the "plugins" folder.* 15 | 16 | - *3. Select either the port of your server to install the same on that server or the "global" folder to install the plugin for all servers* 17 | 18 | ***Or*** 19 | 20 | - *Run the command in console `p install MrAfitol/Lobby`* 21 | 22 | ## View 23 | https://user-images.githubusercontent.com/76150070/208076431-7e7a98e3-d1b3-4365-a989-a09e7fa7f639.mp4 24 | 25 | 26 | ## Config 27 | ```yml 28 | # Main text ({seconds} - Either it shows how much is left until the start, or the server status is "Server is suspended", "Round starting", - Change the next text a rainbow color, - Close a rainbow color tag) 29 | title_text: Waiting for players, {seconds} 30 | # Text showing the number of players ({players} - Text with the number of players, - Change the next text a rainbow color, - Close a rainbow color tag) 31 | player_count_text: {players} 32 | # What will be written if the lobby is locked? 33 | server_pause_text: Server is suspended 34 | # What will be written when there is a second left? 35 | second_left_text: '{seconds} second left' 36 | # What will be written when there is more than a second left? 37 | seconds_left_text: '{seconds} seconds left' 38 | # What will be written when the round starts? 39 | round_start_text: Round starting 40 | # What will be written when there is only one player on the server? 41 | player_join_text: player joined 42 | # What will be written when there is more than one player on the server? 43 | players_join_text: players joined 44 | # Vertical text position. 45 | vertical_pos: 25 46 | # Top text size 47 | top_text_size: 50 48 | # Bottom text size 49 | bottom_text_size: 40 50 | # Top text size in intercom 51 | top_text_icom_size: 150 52 | # Bottom text size in intercom 53 | bottom_text_icom_size: 140 54 | # Enable the movement boost effect? 55 | enable_movement_boost: true 56 | # What is the movement boost intensity? (Max 255) 57 | movement_boost_intensity: 50 58 | # Will infinity stamina be enabled for people in the lobby? 59 | infinity_stamina: true 60 | # What role will people play in the lobby? 61 | lobby_player_role: Tutorial 62 | # Allow people to talk over the intercom? 63 | allow_icom: true 64 | # Display text on Intercom? (Works only when lobby Intercom type) 65 | display_in_icom: true 66 | # What size will the text be in the Intercom? (The larger the value, the smaller it will be) 67 | icom_text_size: 20 68 | # What items will be given when spawning a player in the lobby? (Leave blank to keep inventory empty) 69 | lobby_inventory: 70 | - Coin 71 | # In what locations can people spawn? (If this parameter is empty, one of the custom locations (or custom room locations) will be selected) 72 | lobby_location: 73 | - Tower_1 74 | - Tower_2 75 | - Tower_3 76 | - Tower_4 77 | - Tower_5 78 | - Intercom 79 | - GR18 80 | - SCP173 81 | # This option is for a custom lobby location 82 | custom_room_locations: 83 | - room_name_type: EzGateA 84 | offset_x: 0 85 | offset_y: 1 86 | offset_z: 0 87 | rotation_x: 0 88 | rotation_y: 0 89 | rotation_z: 0 90 | # This option is for a custom lobby location 91 | custom_locations: 92 | - position_x: 39.262001 93 | position_y: 1014.112 94 | position_z: -31.8439999 95 | rotation_x: 0 96 | rotation_y: 0 97 | rotation_z: 0 98 | # The name of the role that can use commands for Lobby. 99 | allowed_rank: 100 | - owner 101 | # User ID that can use commands for the Lobby. 102 | allowed_user_i_d: 103 | - SomeOtherSteamId64@steam 104 | ``` 105 | 106 | ## Wiki 107 | **Be sure to check out the [Wiki](https://github.com/MrAfitol/Lobby/wiki)** 108 | -------------------------------------------------------------------------------- /Lobby/Command/DebugCommands/TpLocationCommand.cs: -------------------------------------------------------------------------------- 1 | using CommandSystem; 2 | using LabApi.Features.Permissions; 3 | using LabApi.Features.Wrappers; 4 | using MapGeneration; 5 | using System; 6 | using System.Linq; 7 | using UnityEngine; 8 | 9 | namespace Lobby.Command.DebugCommands 10 | { 11 | public class TpLocationCommand : ICommand 12 | { 13 | public string Command => "tploc"; 14 | 15 | public string[] Aliases { get; } = { "tpl", "tl" }; 16 | 17 | public string Description => "Teleport to a custom location."; 18 | 19 | public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) 20 | { 21 | Player playerSender = Player.Get(sender); 22 | 23 | if (!playerSender.HasAnyPermission("lobby.*", "lobby.debug.*", "lobby.debug.tp")) 24 | { 25 | response = $"You don't have permission to use this command!"; 26 | return false; 27 | } 28 | 29 | if (arguments.Count != 2) 30 | { 31 | response = "Incorrect command, use: \nlobby tploc room (index)\nlobby tploc static (index)"; 32 | return false; 33 | } 34 | 35 | if (!Int32.TryParse(arguments.At(1), out int index)) 36 | { 37 | response = "The index must be a number"; 38 | return false; 39 | } 40 | 41 | GameObject Point = new GameObject("Point"); 42 | 43 | switch (arguments.At(0)) 44 | { 45 | case "room": 46 | if (Lobby.Instance.Config.CustomRoomLocations == null || Lobby.Instance.Config.CustomRoomLocations?.Count - 1 < index) 47 | { 48 | response = $"Custom location at index {index} was not found."; 49 | return false; 50 | } 51 | 52 | if (Enum.TryParse(Lobby.Instance.Config.CustomRoomLocations[index].RoomNameType, out RoomName roomName)) 53 | Point.transform.SetParent(RoomIdentifier.AllRoomIdentifiers.First(x => x.Name == roomName).transform); 54 | else if (RoomIdentifier.AllRoomIdentifiers.Count(x => x.name.Contains(Lobby.Instance.Config.CustomRoomLocations[index].RoomNameType)) > 0) 55 | Point.transform.SetParent(RoomIdentifier.AllRoomIdentifiers.First(x => x.name.Contains(Lobby.Instance.Config.CustomRoomLocations[index].RoomNameType)).transform); 56 | 57 | Point.transform.localPosition = new Vector3(Lobby.Instance.Config.CustomRoomLocations[index].OffsetX, Lobby.Instance.Config.CustomRoomLocations[index].OffsetY, Lobby.Instance.Config.CustomRoomLocations[index].OffsetZ); 58 | Point.transform.localEulerAngles = new Vector3(Lobby.Instance.Config.CustomRoomLocations[index].RotationX, Lobby.Instance.Config.CustomRoomLocations[index].RotationY, Lobby.Instance.Config.CustomRoomLocations[index].RotationZ); 59 | 60 | playerSender.Position = Point.transform.position; 61 | playerSender.Rotation = Point.transform.rotation; 62 | 63 | GameObject.Destroy(Point); 64 | 65 | response = $"You have successfully teleported to a custom location at index {index}."; 66 | return true; 67 | case "static": 68 | if (Lobby.Instance.Config.CustomLocations == null || Lobby.Instance.Config.CustomLocations?.Count - 1 < index) 69 | { 70 | response = $"Custom location at index {index} was not found."; 71 | return false; 72 | } 73 | 74 | playerSender.Position = new Vector3(Lobby.Instance.Config.CustomLocations[index].PositionX, Lobby.Instance.Config.CustomLocations[index].PositionY, Lobby.Instance.Config.CustomLocations[index].PositionZ); 75 | playerSender.Rotation = Quaternion.Euler(Lobby.Instance.Config.CustomLocations[index].RotationX, Lobby.Instance.Config.CustomLocations[index].RotationY, Lobby.Instance.Config.CustomLocations[index].RotationZ); 76 | 77 | response = $"You have successfully teleported to a custom location at index {index}."; 78 | return true; 79 | default: 80 | response = "Incorrect command, use: \nlobby tploc room (index)\nlobby tploc static (index)"; 81 | return false; 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /Lobby/Lobby.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F6FFBCFD-6FDB-4185-AB54-20AB167DCA57} 8 | Library 9 | Properties 10 | Lobby 11 | Lobby 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | true 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Lib.Harmony.2.3.3\lib\net48\0Harmony.dll 37 | 38 | 39 | False 40 | $(SCP_Dependencies)\Assembly-CSharp-firstpass.dll 41 | 42 | 43 | False 44 | $(SCP_Dependencies)\Assembly-CSharp-Publicized.dll 45 | 46 | 47 | False 48 | $(SCP_Dependencies)\CommandSystem.Core.dll 49 | 50 | 51 | ..\packages\Northwood.LabAPI.1.0.2\lib\net48\LabApi.dll 52 | 53 | 54 | False 55 | $(SCP_Dependencies)\Mirror.dll 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | False 66 | $(SCP_Dependencies)\UnityEngine.dll 67 | 68 | 69 | False 70 | $(SCP_Dependencies)\UnityEngine.CoreModule.dll 71 | 72 | 73 | $(SCP_Dependencies)\UnityEngine.PhysicsModule.dll 74 | 75 | 76 | ..\packages\YamlDotNet.11.0.1\lib\net45\YamlDotNet.dll 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Lobby/Config.cs: -------------------------------------------------------------------------------- 1 | using MapGeneration; 2 | using PlayerRoles; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | 6 | namespace Lobby 7 | { 8 | public class Config 9 | { 10 | [Description("Main text ({seconds} - Either it shows how much is left until the start, or the server status is \"Server is suspended\", \"Round starting\", - Change the next text a rainbow color, - Close a rainbow color tag)")] 11 | public string TitleText { get; set; } = "Waiting for players, {seconds}"; 12 | 13 | [Description("Text showing the number of players ({players} - Text with the number of players, - Change the next text a rainbow color, - Close a rainbow color tag)")] 14 | public string PlayerCountText { get; set; } = "{players}"; 15 | 16 | [Description("What will be written if the lobby is locked?")] 17 | public string ServerPauseText { get; set; } = "Server is suspended"; 18 | 19 | [Description("What will be written when there is a second left?")] 20 | public string SecondLeftText { get; set; } = "{seconds} second left"; 21 | 22 | [Description("What will be written when there is more than a second left?")] 23 | public string SecondsLeftText { get; set; } = "{seconds} seconds left"; 24 | 25 | [Description("What will be written when the round starts?")] 26 | public string RoundStartText { get; set; } = "Round starting"; 27 | 28 | [Description("What will be written when there is only one player on the server?")] 29 | public string PlayerJoinText { get; set; } = "player joined"; 30 | 31 | [Description("What will be written when there is more than one player on the server?")] 32 | public string PlayersJoinText { get; set; } = "players joined"; 33 | 34 | [Description("Vertical text position.")] 35 | public int VerticalPos { get; set; } = 25; 36 | 37 | [Description("Top text size")] 38 | public int TopTextSize { get; set; } = 50; 39 | 40 | [Description("Bottom text size")] 41 | public int BottomTextSize { get; set; } = 40; 42 | 43 | [Description("Top text size in intercom")] 44 | public int TopTextIcomSize { get; set; } = 150; 45 | 46 | [Description("Bottom text size in intercom")] 47 | public int BottomTextIcomSize { get; set; } = 140; 48 | 49 | [Description("Enable the movement boost effect?")] 50 | public bool EnableMovementBoost { get; set; } = true; 51 | 52 | [Description("What is the movement boost intensity? (Max 255)")] 53 | public byte MovementBoostIntensity { get; set; } = 50; 54 | 55 | [Description("Will infinity stamina be enabled for people in the lobby?")] 56 | public bool InfinityStamina { get; set; } = true; 57 | 58 | [Description("What role will people play in the lobby?")] 59 | public RoleTypeId LobbyPlayerRole { get; set; } = RoleTypeId.Tutorial; 60 | 61 | [Description("Allow people to talk over the intercom?")] 62 | public bool AllowIcom { get; set; } = true; 63 | 64 | [Description("Display text on Intercom? (Works only when lobby Intercom type)")] 65 | public bool DisplayInIcom { get; set; } = true; 66 | 67 | [Description("What size will the text be in the Intercom? (The larger the value, the smaller it will be)")] 68 | public int IcomTextSize { get; set; } = 20; 69 | 70 | [Description("What items will be given when spawning a player in the lobby? (Leave blank to keep inventory empty)")] 71 | public List LobbyInventory { get; set; } = new List() 72 | { 73 | ItemType.Coin 74 | }; 75 | 76 | [Description("In what locations can people spawn? (If this parameter is empty, one of the custom locations (or custom room locations) will be selected)")] 77 | public List LobbyLocation { get; set; } = new List() 78 | { 79 | LobbyLocationType.Tower_1, 80 | LobbyLocationType.Tower_2, 81 | LobbyLocationType.Tower_3, 82 | LobbyLocationType.Tower_4, 83 | LobbyLocationType.Tower_5, 84 | LobbyLocationType.Intercom, 85 | LobbyLocationType.GR18, 86 | LobbyLocationType.SCP173 87 | }; 88 | 89 | [Description("This option is for a custom lobby location")] 90 | public List CustomRoomLocations { get; set; } = new List() 91 | { 92 | new CustomRoomLocationData() 93 | { 94 | RoomNameType = RoomName.EzGateA.ToString(), 95 | OffsetX = 0, 96 | OffsetY = 1, 97 | OffsetZ = 0, 98 | RotationX = 0, 99 | RotationY = 0, 100 | RotationZ = 0, 101 | }, 102 | }; 103 | 104 | [Description("This option is for a custom lobby location")] 105 | public List CustomLocations { get; set; } = new List() 106 | { 107 | new CustomLocationData() 108 | { 109 | PositionX = 39.262f, 110 | PositionY = 315f, 111 | PositionZ = -31.844f, 112 | RotationX = 0, 113 | RotationY = 0, 114 | RotationZ = 0, 115 | }, 116 | }; 117 | } 118 | 119 | public class LocationData 120 | { 121 | } 122 | 123 | public class CustomRoomLocationData : LocationData 124 | { 125 | public string RoomNameType { get; set; } 126 | public float OffsetX { get; set; } 127 | public float OffsetY { get; set; } 128 | public float OffsetZ { get; set; } 129 | public float RotationX { get; set; } 130 | public float RotationY { get; set; } 131 | public float RotationZ { get; set; } 132 | } 133 | 134 | public class CustomLocationData : LocationData 135 | { 136 | public float PositionX { get; set; } 137 | public float PositionY { get; set; } 138 | public float PositionZ { get; set; } 139 | public float RotationX { get; set; } 140 | public float RotationY { get; set; } 141 | public float RotationZ { get; set; } 142 | } 143 | } -------------------------------------------------------------------------------- /Lobby/EventsHandler.cs: -------------------------------------------------------------------------------- 1 | using CentralAuth; 2 | using CustomPlayerEffects; 3 | using LabApi.Events.Arguments.PlayerEvents; 4 | using LabApi.Events.Handlers; 5 | using LabApi.Features.Wrappers; 6 | using Lobby.API; 7 | using MEC; 8 | using PlayerRoles; 9 | using PlayerRoles.Voice; 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Linq; 13 | using UnityEngine; 14 | using Logger = LabApi.Features.Console.Logger; 15 | using Random = UnityEngine.Random; 16 | 17 | namespace Lobby 18 | { 19 | public class EventsHandler 20 | { 21 | public static bool IsIntercom { get; set; } = false; 22 | public static bool IsLobby { get; set; } = true; 23 | 24 | private CoroutineHandle lobbyTimer, rainbowColor; 25 | private int r = 255, g = 0, b = 0; 26 | private string text; 27 | 28 | #region Events 29 | 30 | public void OnWaitingForPlayers() 31 | { 32 | try 33 | { 34 | LobbyLocationHandler.Point = new GameObject("LobbyPoint"); 35 | IsLobby = true; 36 | IsIntercom = false; 37 | Lobby.Instance.Harmony.PatchAll(); 38 | RegisterHandlers(); 39 | SpawnManager(); 40 | 41 | Timing.CallDelayed(0.1f, () => 42 | { 43 | GameObject.Find("StartRound").transform.localScale = Vector3.zero; 44 | 45 | if (lobbyTimer.IsRunning) 46 | Timing.KillCoroutines(lobbyTimer); 47 | if (rainbowColor.IsRunning) 48 | Timing.KillCoroutines(rainbowColor); 49 | 50 | if (Lobby.Instance.Config.TitleText.Contains("") || Lobby.Instance.Config.PlayerCountText.Contains("")) 51 | rainbowColor = Timing.RunCoroutine(RainbowColor()); 52 | 53 | lobbyTimer = Timing.RunCoroutine(LobbyTimer()); 54 | }); 55 | } 56 | catch (Exception e) 57 | { 58 | Logger.Error("[Event: OnWaitingForPlayers] " + e.ToString()); 59 | } 60 | } 61 | 62 | public void OnPlayerJoined(PlayerJoinedEventArgs ev) 63 | { 64 | try 65 | { 66 | if (IsLobby && (GameCore.RoundStart.singleton.NetworkTimer > 1 || GameCore.RoundStart.singleton.NetworkTimer == -2)) 67 | { 68 | Timing.CallDelayed(1f, () => 69 | { 70 | if (!ev.Player.IsOverwatchEnabled) 71 | { 72 | ev.Player.SetRole(Lobby.Instance.Config.LobbyPlayerRole); 73 | 74 | ev.Player.IsGodModeEnabled = true; 75 | 76 | if (Lobby.Instance.Config.LobbyInventory.Count > 0) 77 | { 78 | foreach (var item in Lobby.Instance.Config.LobbyInventory) 79 | { 80 | ev.Player.AddItem(item); 81 | } 82 | } 83 | 84 | Timing.CallDelayed(0.1f, () => 85 | { 86 | ev.Player.Position = LobbyLocationHandler.Point.transform.position; 87 | ev.Player.Rotation = LobbyLocationHandler.Point.transform.rotation; 88 | 89 | if (Lobby.Instance.Config.EnableMovementBoost) 90 | { 91 | ev.Player.EnableEffect(Lobby.Instance.Config.MovementBoostIntensity); 92 | } 93 | }); 94 | } 95 | }); 96 | } 97 | } 98 | catch (Exception e) 99 | { 100 | Logger.Error("[Event: OnPlayerJoined] " + e.ToString()); 101 | } 102 | } 103 | 104 | public void OnRoundStarted() 105 | { 106 | try 107 | { 108 | UnregisterHandlers(); 109 | IsLobby = false; 110 | 111 | if (!string.IsNullOrEmpty(IntercomDisplay._singleton.Network_overrideText)) IntercomDisplay._singleton.Network_overrideText = ""; 112 | 113 | foreach (var player in Player.List.Where(x => x.Role != RoleTypeId.Overwatch)) 114 | { 115 | player.SetRole(RoleTypeId.Spectator); 116 | 117 | Timing.CallDelayed(0.1f, () => 118 | { 119 | player.IsGodModeEnabled = false; 120 | if (Lobby.Instance.Config.EnableMovementBoost) player.DisableEffect(); 121 | }); 122 | } 123 | 124 | Timing.CallDelayed(1f, () => 125 | { 126 | if (lobbyTimer.IsRunning) 127 | Timing.KillCoroutines(lobbyTimer); 128 | if (rainbowColor.IsRunning) 129 | Timing.KillCoroutines(rainbowColor); 130 | }); 131 | 132 | Lobby.Instance.Harmony.UnpatchAll("lobby.scp.sl"); 133 | } 134 | catch (Exception e) 135 | { 136 | Logger.Error("[Event: OnRoundStarted] " + e.ToString()); 137 | } 138 | } 139 | 140 | #endregion 141 | 142 | #region Methods 143 | 144 | public void RegisterHandlers() 145 | { 146 | try 147 | { 148 | PlayerEvents.InteractingDoor += Lobby.Instance.RestrictionsHandler.OnPlayerInteractingDoor; 149 | PlayerEvents.InteractingElevator += Lobby.Instance.RestrictionsHandler.OnPlayerInteractingElevator; 150 | PlayerEvents.SearchingPickup += Lobby.Instance.RestrictionsHandler.OnPlayerSearchingPickup; 151 | PlayerEvents.DroppingItem += Lobby.Instance.RestrictionsHandler.OnPlayerDroppingItem; 152 | PlayerEvents.DroppingAmmo += Lobby.Instance.RestrictionsHandler.OnPlayerDroppingAmmo; 153 | PlayerEvents.ThrowingItem += Lobby.Instance.RestrictionsHandler.OnPlayerThrowingItem; 154 | PlayerEvents.UsingIntercom += Lobby.Instance.RestrictionsHandler.OnPlayerUsingIntercom; 155 | PlayerEvents.Joined += OnPlayerJoined; 156 | } 157 | catch (Exception e) 158 | { 159 | Logger.Error("[Lobby] [Method: RegisterHandlers] " + e.ToString()); 160 | } 161 | } 162 | 163 | public void UnregisterHandlers() 164 | { 165 | try 166 | { 167 | PlayerEvents.InteractingDoor -= Lobby.Instance.RestrictionsHandler.OnPlayerInteractingDoor; 168 | PlayerEvents.InteractingElevator -= Lobby.Instance.RestrictionsHandler.OnPlayerInteractingElevator; 169 | PlayerEvents.SearchingPickup -= Lobby.Instance.RestrictionsHandler.OnPlayerSearchingPickup; 170 | PlayerEvents.DroppingItem -= Lobby.Instance.RestrictionsHandler.OnPlayerDroppingItem; 171 | PlayerEvents.DroppingAmmo -= Lobby.Instance.RestrictionsHandler.OnPlayerDroppingAmmo; 172 | PlayerEvents.ThrowingItem -= Lobby.Instance.RestrictionsHandler.OnPlayerThrowingItem; 173 | PlayerEvents.UsingIntercom -= Lobby.Instance.RestrictionsHandler.OnPlayerUsingIntercom; 174 | PlayerEvents.Joined -= OnPlayerJoined; 175 | } 176 | catch (Exception e) 177 | { 178 | Logger.Error("[Lobby] [Method: UnregisterHandlers] " + e.ToString()); 179 | } 180 | } 181 | 182 | private void SpawnManager() 183 | { 184 | try 185 | { 186 | List locationList = new List(); 187 | 188 | if (Lobby.Instance.Config.LobbyLocation?.Count > 0) 189 | locationList.AddRange(Lobby.Instance.Config.LobbyLocation 190 | .Where(x => LobbyLocationHandler.LocationDatas.ContainsKey(x)) 191 | .Select(x => LobbyLocationHandler.LocationDatas[x])); 192 | 193 | if (Lobby.Instance.Config.CustomLocations?.Count > 0) 194 | locationList.AddRange(Lobby.Instance.Config.CustomLocations); 195 | 196 | if (Lobby.Instance.Config.CustomRoomLocations?.Count > 0) 197 | locationList.AddRange(Lobby.Instance.Config.CustomRoomLocations); 198 | 199 | if (locationList.Count <= 0) 200 | locationList.Add(LobbyLocationHandler.LocationDatas.ElementAt(Random.Range(0, LobbyLocationHandler.LocationDatas.Count - 1)).Value); 201 | LobbyLocationHandler.SetLocation(locationList.RandomItem()); 202 | } 203 | catch (Exception e) 204 | { 205 | Logger.Error("[Lobby] [Method: SpawnManager] " + e.ToString()); 206 | } 207 | } 208 | 209 | private IEnumerator RainbowColor() 210 | { 211 | r = 255; g = 0; b = 0; 212 | 213 | while (!Round.IsRoundStarted) 214 | { 215 | if (r > 0 && b == 0) 216 | { 217 | r -= 2; 218 | g += 2; 219 | } 220 | 221 | if (g > 0 && r == 0) 222 | { 223 | g -= 2; 224 | b += 2; 225 | } 226 | 227 | if (b > 0 && g == 0) 228 | { 229 | b -= 2; 230 | r += 2; 231 | } 232 | 233 | r = Mathf.Clamp(r, 0, 255); 234 | g = Mathf.Clamp(g, 0, 255); 235 | b = Mathf.Clamp(b, 0, 255); 236 | 237 | yield return Timing.WaitForSeconds(0.4f); 238 | } 239 | } 240 | 241 | private IEnumerator LobbyTimer() 242 | { 243 | while (!Round.IsRoundStarted) 244 | { 245 | text = string.Empty; 246 | 247 | if (Lobby.Instance.Config.VerticalPos < 0) 248 | for (int i = 0; i < ~Lobby.Instance.Config.VerticalPos; i++) 249 | text += "\n"; 250 | 251 | text += $"" + Lobby.Instance.Config.TitleText + ""; 252 | 253 | text += "\n" + $"" + Lobby.Instance.Config.PlayerCountText + ""; 254 | 255 | short NetworkTimer = GameCore.RoundStart.singleton.NetworkTimer; 256 | 257 | switch (NetworkTimer) 258 | { 259 | case -2: text = text.Replace("{seconds}", Lobby.Instance.Config.ServerPauseText); break; 260 | case -1: text = text.Replace("{seconds}", Lobby.Instance.Config.RoundStartText); break; 261 | case 1: text = text.Replace("{seconds}", Lobby.Instance.Config.SecondLeftText.Replace("{seconds}", NetworkTimer.ToString())); break; 262 | case 0: text = text.Replace("{seconds}", Lobby.Instance.Config.RoundStartText); break; 263 | default: text = text.Replace("{seconds}", Lobby.Instance.Config.SecondsLeftText.Replace("{seconds}", NetworkTimer.ToString())); break; 264 | } 265 | 266 | if (Player.Count == 1) 267 | text = text.Replace("{players}", $"{Player.Count} " + Lobby.Instance.Config.PlayerJoinText); 268 | else 269 | text = text.Replace("{players}", $"{Player.Count} " + Lobby.Instance.Config.PlayersJoinText); 270 | 271 | string hex = $"{r:X2}{g:X2}{b:X2}"; 272 | text = text.Replace("", $""); 273 | text = text.Replace("", ""); 274 | 275 | if (Lobby.Instance.Config.VerticalPos >= 0) 276 | for (int i = 0; i < Lobby.Instance.Config.VerticalPos; i++) 277 | text += "\n"; 278 | 279 | if (!IsIntercom || !Lobby.Instance.Config.DisplayInIcom) 280 | { 281 | foreach (Player ply in Player.List) 282 | if (ply.ReferenceHub.Mode != ClientInstanceMode.Unverified && ply.ReferenceHub.Mode != ClientInstanceMode.DedicatedServer && ply != null) 283 | ply.SendHint(text, 1.05f); 284 | } 285 | else IntercomDisplay._singleton.Network_overrideText = $"" + text + ""; 286 | 287 | yield return Timing.WaitForSeconds(1f); 288 | } 289 | } 290 | 291 | #endregion 292 | } 293 | } 294 | --------------------------------------------------------------------------------