Skip to content
Merged

Dev #152

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions EXILED/Exiled.API/Features/Items/Scp330.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ internal Scp330()
/// </summary>
public CandyKindID ExposedType { get; set; } = CandyKindID.None;

/// <summary>
/// Gets or sets the candy that will be added to the bag. Used for events.
/// </summary>
internal CandyKindID CandyToAdd { get; set; } = CandyKindID.None;

/// <summary>
/// Adds a specific candy to the bag.
/// </summary>
Expand Down
116 changes: 108 additions & 8 deletions EXILED/Exiled.API/Features/Npc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace Exiled.API.Features
using CentralAuth;
using CommandSystem;
using Exiled.API.Enums;
using Exiled.API.Extensions;
using Exiled.API.Features.Components;
using Exiled.API.Features.Roles;
using Footprinting;
Expand Down Expand Up @@ -142,6 +141,7 @@ public override Vector3 Position
/// <param name="userId">The userID of the NPC.</param>
/// <param name="position">The position to spawn the NPC.</param>
/// <returns>The <see cref="Npc"/> spawned.</returns>
[Obsolete("This metod is marked as obsolet due to a bug that make player have the same id. Use Npc.Spawn(string) instead")]
public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId = PlayerAuthenticationManager.DedicatedId, Vector3? position = null)
{
GameObject newObject = UnityEngine.Object.Instantiate(Mirror.NetworkManager.singleton.playerPrefab);
Expand Down Expand Up @@ -208,18 +208,118 @@ public static Npc Spawn(string name, RoleTypeId role, int id = 0, string userId
return npc;
}

/// <summary>
/// Spawns an NPC based on the given parameters.
/// </summary>
/// <param name="name">The name of the NPC.</param>
/// <param name="role">The RoleTypeId of the NPC, defaulting to None.</param>
/// <param name="ignored">Whether the NPC should be ignored by round ending checks.</param>
/// <param name="userId">The userID of the NPC for authentication. Defaults to the Dedicated ID.</param>
/// <param name="position">The position where the NPC should spawn. If null, the default spawn location is used.</param>
/// <returns>The <see cref="Npc"/> spawned.</returns>
public static Npc Spawn(string name, RoleTypeId role = RoleTypeId.None, bool ignored = false, string userId = PlayerAuthenticationManager.DedicatedId, Vector3? position = null)
{
GameObject newObject = UnityEngine.Object.Instantiate(Mirror.NetworkManager.singleton.playerPrefab);

Npc npc = new(newObject)
{
IsNPC = true,
};

FakeConnection fakeConnection = new(npc.Id);

try
{
if (userId == PlayerAuthenticationManager.DedicatedId)
{
npc.ReferenceHub.authManager.SyncedUserId = userId;
try
{
npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.DedicatedServer;
}
catch (Exception e)
{
Log.Debug($"Ignore: {e.Message}");
}
}
else
{
npc.ReferenceHub.authManager.InstanceMode = ClientInstanceMode.Unverified;
npc.ReferenceHub.authManager._privUserId = userId == string.Empty ? $"Dummy-{npc.Id}@localhost" : userId;
}
}
catch (Exception e)
{
Log.Debug($"Ignore: {e.Message}");
}

try
{
npc.ReferenceHub.roleManager.InitializeNewRole(RoleTypeId.None, RoleChangeReason.None);
}
catch (Exception e)
{
Log.Debug($"Ignore: {e.Message}");
}

NetworkServer.AddPlayerForConnection(fakeConnection, newObject);

npc.ReferenceHub.nicknameSync.Network_myNickSync = name;
Dictionary.Add(newObject, npc);

Timing.CallDelayed(0.5f, () =>
{
npc.Role.Set(role, SpawnReason.RoundStart, position is null ? RoleSpawnFlags.All : RoleSpawnFlags.AssignInventory);

if (position is not null)
npc.Position = position.Value;
});

if (ignored)
Round.IgnoredPlayers.Add(npc.ReferenceHub);

return npc;
}

/// <summary>
/// Destroys all NPCs currently spawned.
/// </summary>
public static void DestroyAll()
{
foreach (Npc npc in List)
npc.Destroy();
}

/// <summary>
/// Destroys the NPC.
/// </summary>
public void Destroy()
{
NetworkConnectionToClient conn = ReferenceHub.connectionToClient;
if (ReferenceHub._playerId.Value <= RecyclablePlayerId._autoIncrement)
ReferenceHub._playerId.Destroy();
ReferenceHub.OnDestroy();
CustomNetworkManager.TypedSingleton.OnServerDisconnect(conn);
Dictionary.Remove(GameObject);
Object.Destroy(GameObject);
try
{
Round.IgnoredPlayers.Remove(ReferenceHub);
NetworkConnectionToClient conn = ReferenceHub.connectionToClient;
ReferenceHub.OnDestroy();
CustomNetworkManager.TypedSingleton.OnServerDisconnect(conn);
Dictionary.Remove(GameObject);
Object.Destroy(GameObject);
}
catch (Exception e)
{
Log.Error($"Error while destroying a NPC: {e.Message}");
}
}

/// <summary>
/// Schedules the destruction of the NPC after a delay.
/// </summary>
/// <param name="time">The delay in seconds before the NPC is destroyed.</param>
public void LateDestroy(float time)
{
Timing.CallDelayed(time, () =>
{
this?.Destroy();
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,23 @@ public class InteractingScp330EventArgs : IPlayerEvent, IScp330Event, IDeniableE
public InteractingScp330EventArgs(Player player, int usage)
{
Player = player;
Scp330 = Scp330Bag.TryGetBag(player.ReferenceHub, out Scp330Bag scp330Bag) ? (Scp330)Item.Get(scp330Bag) : null;
Candy = Scp330Candies.GetRandom();
UsageCount = usage;
ShouldSever = usage >= 2;
ShouldPlaySound = true;
IsAllowed = Player.IsHuman;

if (Scp330Bag.TryGetBag(player.ReferenceHub, out Scp330Bag scp330Bag))
{
Scp330 = (Scp330)Item.Get(scp330Bag);
}
else
{
Scp330 = (Scp330)Item.Create(ItemType.SCP330, player);
Scp330.RemoveAllCandy();
player.AddItem(Scp330);
}

Scp330.CandyToAdd = Scp330Candies.GetRandom();
}

/// <summary>
Expand All @@ -47,7 +58,11 @@ public InteractingScp330EventArgs(Player player, int usage)
/// <summary>
/// Gets or sets a value indicating the type of candy that will be received from this interaction.
/// </summary>
public CandyKindID Candy { get; set; }
public CandyKindID Candy
{
get => Scp330.CandyToAdd;
set => Scp330.CandyToAdd = value;
}

/// <summary>
/// Gets or sets a value indicating whether the player's hands should get severed.
Expand All @@ -71,11 +86,9 @@ public InteractingScp330EventArgs(Player player, int usage)
public Player Player { get; }

/// <inheritdoc/>
/// <remarks>This value can be null.</remarks>
public Scp330 Scp330 { get; }

/// <inheritdoc/>
/// <remarks>This value can be null.</remarks>
public Item Item => Scp330;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
Label returnLabel = generator.DefineLabel();
Label continueLabel = generator.DefineLabel();
Label jmp = generator.DefineLabel();
Label skip = generator.DefineLabel();

LocalBuilder changingRoleEventArgs = generator.DeclareLocal(typeof(ChangingRoleEventArgs));
LocalBuilder player = generator.DeclareLocal(typeof(API.Features.Player));
Expand Down Expand Up @@ -155,8 +156,16 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
newInstructions.Count - 1,
new[]
{
// if (player.ReferenceHub == ReferenceHub.LocalHub)
// goto skip;
new(OpCodes.Ldloc_S, player.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(API.Features.Player), nameof(API.Features.Player.ReferenceHub))),
new(OpCodes.Callvirt, PropertyGetter(typeof(ReferenceHub), nameof(ReferenceHub.LocalHub))),
new(OpCodes.Call, Method(typeof(ReferenceHub), "op_Equality")),
new(OpCodes.Brtrue_S, skip),

// player
new CodeInstruction(OpCodes.Ldloc_S, player.LocalIndex),
new(OpCodes.Ldloc_S, player.LocalIndex),

// OldRole
new(OpCodes.Ldloc_0),
Expand All @@ -166,6 +175,8 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi

// Handlers.Player.OnSpawned(spawnedEventArgs)
new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnSpawned))),

new CodeInstruction(OpCodes.Nop).WithLabels(skip),
});

newInstructions[newInstructions.Count - 1].labels.Add(returnLabel);
Expand Down
27 changes: 22 additions & 5 deletions EXILED/Exiled.Events/Patches/Events/Scp330/InteractingScp330.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

namespace Exiled.Events.Patches.Events.Scp330
{
#pragma warning disable SA1402
#pragma warning disable SA1313
using System.Collections.Generic;
using System.Reflection.Emit;

using Exiled.API.Features;
using Exiled.API.Features.Items;
using Exiled.API.Features.Pools;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Scp330;
using Exiled.Events.Handlers;
using HarmonyLib;
using Interactables.Interobjects;
using InventorySystem.Items.Usables.Scp330;
Expand All @@ -26,9 +27,9 @@ namespace Exiled.Events.Patches.Events.Scp330

/// <summary>
/// Patches the <see cref="Scp330Interobject.ServerInteract(ReferenceHub, byte)" /> method to add the
/// <see cref="Scp330.InteractingScp330" /> event.
/// <see cref="Handlers.Scp330.InteractingScp330" /> event.
/// </summary>
[EventPatch(typeof(Scp330), nameof(Scp330.InteractingScp330))]
[EventPatch(typeof(Handlers.Scp330), nameof(Handlers.Scp330.InteractingScp330))]
[HarmonyPatch(typeof(Scp330Interobject), nameof(Scp330Interobject.ServerInteract))]
public static class InteractingScp330
{
Expand Down Expand Up @@ -66,7 +67,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
new(OpCodes.Stloc, ev.LocalIndex),

// Scp330.OnInteractingScp330(ev)
new(OpCodes.Call, Method(typeof(Scp330), nameof(Scp330.OnInteractingScp330))),
new(OpCodes.Call, Method(typeof(Handlers.Scp330), nameof(Handlers.Scp330.OnInteractingScp330))),

// if (!ev.IsAllowed)
// return;
Expand Down Expand Up @@ -135,4 +136,20 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
ListPool<CodeInstruction>.Pool.Return(newInstructions);
}
}

/// <summary>
/// Replaces <see cref="Scp330Candies.GetRandom"/> with <see cref="InteractingScp330EventArgs.Candy"/>.
/// </summary>
[EventPatch(typeof(Handlers.Scp330), nameof(Handlers.Scp330.InteractingScp330))]
[HarmonyPatch(typeof(Scp330Bag), nameof(Scp330Bag.TryAddSpecific))]
internal static class ReplaceCandy
{
private static void Prefix(Scp330Bag __instance, ref CandyKindID kind)
{
Scp330 scp330 = Item.Get<Scp330>(__instance);

if (scp330.CandyToAdd != CandyKindID.None)
kind = scp330.CandyToAdd;
}
}
}
2 changes: 1 addition & 1 deletion EXILED/Exiled.Events/Patches/Events/Server/Reporting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
new(OpCodes.Starg_S, 2),
});

offset = -2;
offset = -11;
index = newInstructions.FindLastIndex(
instruction => instruction.StoresField(Field(typeof(CheaterReport), nameof(CheaterReport._lastReport)))) + offset;

Expand Down
12 changes: 11 additions & 1 deletion EXILED/Exiled.Loader/Loader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,17 @@ public IEnumerator<float> Run(Assembly[] dependencies = null)
GameCore.Version.BackwardCompatibility,
GameCore.Version.BackwardRevision))
{
ServerConsole.AddLog($"Exiled is outdated, a new version will be installed automatically as soon as it's available.\nSCP:SL: {GameCore.Version.VersionString} Exiled Supported Version: {AutoUpdateFiles.RequiredSCPSLVersion}", ConsoleColor.DarkRed);
string messageText = new Version(
GameCore.Version.Major,
GameCore.Version.Minor,
GameCore.Version.Revision) < new Version(
AutoUpdateFiles.RequiredSCPSLVersion.Major,
AutoUpdateFiles.RequiredSCPSLVersion.Minor,
AutoUpdateFiles.RequiredSCPSLVersion.Revision)
? "SCP: SL is outdated. Update SCP: SL Dedicated Server to required version or downgrade Exiled."
: "Exiled is outdated, a new version will be installed automatically as soon as it's available.";

ServerConsole.AddLog($"{messageText}\nSCP:SL version: {GameCore.Version.VersionString} Exiled Supported Version: {AutoUpdateFiles.RequiredSCPSLVersion}", ConsoleColor.DarkRed);
yield break;
}

Expand Down