Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ public IEnumerator AttachPing(INitroxPlayer player)
// we also take a dependency on the lack of signalping later to differentiate remote player pings from others.
Object.DestroyImmediate(signalBase.GetComponent<SignalPing>());

// Disable the SphereCollider on the signal to prevent it from triggering proximity events
// (e.g., precursor pedestals, doors) when the remote player approaches
if (signalBase.TryGetComponent(out SphereCollider sphereCollider))
Comment thread
misterbubb marked this conversation as resolved.
{
sphereCollider.enabled = false;
}

SetInGamePingColor(player, ping);
}

Expand Down
1 change: 1 addition & 0 deletions NitroxClient/GameLogic/RemotePlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ private void SetupBody()

Collider.center = Vector3.zero;
Collider.radius = refCollider.radius;
Collider.height = refCollider.height;
Collider.direction = refCollider.direction;
Collider.contactOffset = refCollider.contactOffset;
Collider.isTrigger = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Reflection;
using NitroxClient.GameLogic.PlayerLogic;
using UnityEngine;

namespace NitroxPatcher.Patches.Dynamic;

/// <summary>
/// Makes ion cube pedestals (the ones with ion cubes on top that rise up) react to remote players.
/// </summary>
public sealed partial class PrecursorActivatedPillar_OnTriggerEnter_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((PrecursorActivatedPillar t) => t.OnTriggerEnter(default));

public static bool Prefix(PrecursorActivatedPillar __instance, Collider col, bool ___active, ref bool ___extended, ref bool ___isFullyExtended, FMODAsset ___openSound, FMOD_CustomLoopingEmitter ___openedLoopingSound)
{
if (!___active)
{
return false;
}

GameObject entityRoot = UWE.Utils.GetEntityRoot(col.gameObject);
if (!entityRoot)
{
entityRoot = col.gameObject;
}

bool isLocalPlayer = entityRoot.GetComponentInChildren<Player>() != null;
bool isRemotePlayer = entityRoot.GetComponentInChildren<RemotePlayerIdentifier>() != null;

if (!isLocalPlayer && !isRemotePlayer)
{
return false;
}

// Track player count for proper exit handling
PrecursorActivatedPillar_OnTriggerExit_Patch.IncrementPlayerCount(__instance);

// Only play sounds and animate if not already extended
if (!___extended)
{
if (___openSound)
{
Utils.PlayFMODAsset(___openSound, __instance.transform, 20f);
}
if (___openedLoopingSound)
{
___openedLoopingSound.Play();
}
___extended = true;
___isFullyExtended = false;
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Reflection;
using FMOD.Studio;
using NitroxClient.GameLogic.PlayerLogic;
using UnityEngine;

namespace NitroxPatcher.Patches.Dynamic;

/// <summary>
/// Prevents ion cube pedestals from retracting when a player leaves if other players are still nearby.
/// </summary>
public sealed partial class PrecursorActivatedPillar_OnTriggerExit_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((PrecursorActivatedPillar t) => t.OnTriggerExit(default));

/// <summary>
/// Tracks the number of players currently in each pillar's trigger zone.
/// </summary>
private static readonly Dictionary<int, int> playerCountByPillar = [];

public static void IncrementPlayerCount(PrecursorActivatedPillar pillar)
{
int id = pillar.GetInstanceID();
playerCountByPillar.TryGetValue(id, out int count);
playerCountByPillar[id] = count + 1;
}

public static bool Prefix(PrecursorActivatedPillar __instance, Collider col, ref bool ___extended, ref bool ___isFullyExtended, FMODAsset ___closeSound, FMOD_CustomLoopingEmitter ___openedLoopingSound)
{
GameObject entityRoot = UWE.Utils.GetEntityRoot(col.gameObject);
if (!entityRoot)
{
entityRoot = col.gameObject;
}

bool isLocalPlayer = entityRoot.GetComponentInChildren<Player>() != null;
bool isRemotePlayer = entityRoot.GetComponentInChildren<RemotePlayerIdentifier>() != null;

if (!isLocalPlayer && !isRemotePlayer)
{
return false;
}

// Decrement player count (only if we have a count for this pillar)
int id = __instance.GetInstanceID();
int newCount = 0;
if (playerCountByPillar.TryGetValue(id, out int count) && count > 0)
{
newCount = count - 1;
playerCountByPillar[id] = newCount;
}

// Only retract if no players remain
if (newCount <= 0)
{
if (___closeSound)
{
Utils.PlayFMODAsset(___closeSound, __instance.transform, 20f);
}
if (___openedLoopingSound)
{
___openedLoopingSound.Stop(STOP_MODE.ALLOWFADEOUT);
}
___extended = false;
___isFullyExtended = true;
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Reflection;
using NitroxClient.GameLogic.PlayerLogic;
using UnityEngine;

namespace NitroxPatcher.Patches.Dynamic;

/// <summary>
/// Makes the gun disable terminal open when remote players approach.
/// </summary>
public sealed partial class PrecursorDisableGunTerminalArea_OnTriggerEnter_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((PrecursorDisableGunTerminalArea t) => t.OnTriggerEnter(default));

public static bool Prefix(PrecursorDisableGunTerminalArea __instance, Collider other)
{
if (!PrecursorDisableGunTerminalArea_OnTriggerExit_Patch.IsPlayerCollider(other, out GameObject entityRoot))
{
return false;
}

// Track player count for proper exit handling
PrecursorDisableGunTerminalArea_OnTriggerExit_Patch.IncrementPlayerCount(__instance);

// Only open if this is the first player entering
if (PrecursorDisableGunTerminalArea_OnTriggerExit_Patch.GetPlayerCount(__instance) == 1)
{
__instance.terminal.OnTerminalAreaEnter();
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System.Collections.Generic;
using System.Reflection;
using NitroxClient.GameLogic.PlayerLogic;
using UnityEngine;

namespace NitroxPatcher.Patches.Dynamic;

/// <summary>
/// Prevents the gun disable terminal from closing when a player leaves if other players are still nearby.
/// </summary>
public sealed partial class PrecursorDisableGunTerminalArea_OnTriggerExit_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((PrecursorDisableGunTerminalArea t) => t.OnTriggerExit(default));

/// <summary>
/// Tracks the number of players currently in each trigger zone.
/// </summary>
private static readonly Dictionary<int, int> playerCountByTrigger = [];

/// <summary>
/// Checks if the collider belongs to a player (local or remote) and returns the entity root.
/// </summary>
/// <param name="other">The collider to check</param>
/// <param name="entityRoot">The entity root GameObject if it's a player, null otherwise</param>
/// <returns>True if the collider belongs to a player, false otherwise</returns>
public static bool IsPlayerCollider(Collider other, out GameObject entityRoot)
{
entityRoot = UWE.Utils.GetEntityRoot(other.gameObject);
if (entityRoot == null)
{
entityRoot = other.gameObject;
}

bool isLocalPlayer = entityRoot.GetComponent<Player>() != null;
bool isRemotePlayer = entityRoot.GetComponent<RemotePlayerIdentifier>() != null;

return isLocalPlayer || isRemotePlayer;
}

public static void IncrementPlayerCount(PrecursorDisableGunTerminalArea trigger)
{
int id = trigger.GetInstanceID();
playerCountByTrigger.TryGetValue(id, out int count);
playerCountByTrigger[id] = count + 1;
}

public static int GetPlayerCount(PrecursorDisableGunTerminalArea trigger)
{
int id = trigger.GetInstanceID();
playerCountByTrigger.TryGetValue(id, out int count);
return count;
}

public static bool Prefix(PrecursorDisableGunTerminalArea __instance, Collider other)
{
if (!IsPlayerCollider(other, out GameObject entityRoot))
{
return false;
}
Comment thread
misterbubb marked this conversation as resolved.

// Decrement player count (only if we have a count for this trigger)
int id = __instance.GetInstanceID();
int newCount = 0;
if (playerCountByTrigger.TryGetValue(id, out int count) && count > 0)
{
newCount = count - 1;
playerCountByTrigger[id] = newCount;
}

// Only close if no players remain
if (newCount <= 0)
{
__instance.terminal.OnTerminalAreaExit();
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Reflection;
using NitroxClient.GameLogic.PlayerLogic;
using UnityEngine;

namespace NitroxPatcher.Patches.Dynamic;

/// <summary>
/// Makes precursor key terminal pedestals (tablet pedestals) react to remote players.
/// </summary>
public sealed partial class PrecursorKeyTerminalTrigger_OnTriggerEnter_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((PrecursorKeyTerminalTrigger t) => t.OnTriggerEnter(default));

public static bool Prefix(PrecursorKeyTerminalTrigger __instance, Collider col)
{
bool isLocalPlayer = col.gameObject.Equals(Player.main.gameObject);
bool isRemotePlayer = col.GetComponentInParent<RemotePlayerIdentifier>() != null;

if (!isLocalPlayer && !isRemotePlayer)
{
return false;
}

// Track player count for proper exit handling
PrecursorKeyTerminalTrigger_OnTriggerExit_Patch.IncrementPlayerCount(__instance);

// Only send OpenDeck if this is the first player entering
if (PrecursorKeyTerminalTrigger_OnTriggerExit_Patch.GetPlayerCount(__instance) == 1)
{
__instance.SendMessageUpwards("OpenDeck");
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Collections.Generic;
using System.Reflection;
using NitroxClient.GameLogic.PlayerLogic;
using UnityEngine;

namespace NitroxPatcher.Patches.Dynamic;

/// <summary>
/// Prevents precursor key terminal pedestals from closing when a player leaves if other players are still nearby.
/// </summary>
public sealed partial class PrecursorKeyTerminalTrigger_OnTriggerExit_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((PrecursorKeyTerminalTrigger t) => t.OnTriggerExit(default));

/// <summary>
/// Tracks the number of players currently in each trigger zone.
/// </summary>
private static readonly Dictionary<int, int> playerCountByTrigger = [];

public static void IncrementPlayerCount(PrecursorKeyTerminalTrigger trigger)
{
int id = trigger.GetInstanceID();
playerCountByTrigger.TryGetValue(id, out int count);
playerCountByTrigger[id] = count + 1;
}

public static int GetPlayerCount(PrecursorKeyTerminalTrigger trigger)
{
int id = trigger.GetInstanceID();
playerCountByTrigger.TryGetValue(id, out int count);
return count;
}

public static bool Prefix(PrecursorKeyTerminalTrigger __instance, Collider col)
{
bool isLocalPlayer = col.gameObject.Equals(Player.main.gameObject);
bool isRemotePlayer = col.GetComponentInParent<RemotePlayerIdentifier>() != null;

if (!isLocalPlayer && !isRemotePlayer)
{
return false;
}

// Decrement player count (only if we have a count for this trigger)
int id = __instance.GetInstanceID();
int newCount = 0;
if (playerCountByTrigger.TryGetValue(id, out int count) && count > 0)
{
newCount = count - 1;
playerCountByTrigger[id] = newCount;
}

// Only close if no players remain
if (newCount <= 0)
{
__instance.SendMessageUpwards("CloseDeck");
Comment thread
misterbubb marked this conversation as resolved.
}

return false;
}
}
Loading