Skip to content

Commit

Permalink
Bunch of bugfixes
Browse files Browse the repository at this point in the history
- Removed verbose logging in Actions.cs
- (Hopefully) fixed an issue where timings could cause players to be muffled indefinitely
- Fixed centipede not dropping for any player if the host is dead (and has the mod)
- (Hopefully) fixed little girl not un-targeting the host if they die
- Fixed teleporter teleporting the spectator ghost player if they have no body
- Disabled debug menu in Release builds
- Fixed some mods causing the teleporter timer to be below 0
- Changed a tiny bit of locomotion code, potentially fixing a slight but barely noticeable jitter when walking
- Fixed dynamic resolution not working
- Spectators will now see the time no matter if they're in the ship or not
  • Loading branch information
DaXcess committed Mar 2, 2024
1 parent 3876fed commit 48538b3
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 74 deletions.
4 changes: 3 additions & 1 deletion Source/Experiments/Experiments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ internal class Experiments
{
public static void RunExperiments()
{
ShowMeTheMoney(10000);
// ShowMeTheMoney(10000);
// SpawnShotgun();
// SpawnBuyableItem<JetpackItem>("Jetpack");
// SpawnBuyableItem<SprayPaintItem>("Spray paint");
Expand Down Expand Up @@ -87,6 +87,7 @@ private static T SpawnObject<T>(GameObject @object)
}
}

#if DEBUG
[LCVRPatch(LCVRPatchTarget.Universal)]
[HarmonyPatch]
internal static class ExperimentalPatches
Expand All @@ -103,3 +104,4 @@ private static bool DeveloperMode(ref bool __result)
return false;
}
}
#endif
8 changes: 0 additions & 8 deletions Source/Input/Actions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,11 @@ private bool DownloadControllerProfile(string profile, out InputActionAsset asse

private InputActionAsset GetProfile(string profile)
{
Logger.LogDebug(profile);
Logger.LogDebug(profiles);

Logger.LogDebug("A");

if (!profiles.TryGetValue(profile, out var inputAsset))
{
Logger.LogWarning($"Tried to load unknown controller profile: {profile}, falling back to default");
inputAsset = profiles["default"];
}
Logger.LogDebug("B");

// Download external profile if configured
var actions = string.IsNullOrEmpty(Plugin.Config.ControllerBindingsOverrideProfile.Value) switch
{
Expand All @@ -206,7 +199,6 @@ private InputActionAsset GetProfile(string profile)
false => inputAsset
}
};
Logger.LogDebug("C");

return actions;
}
Expand Down
66 changes: 35 additions & 31 deletions Source/Networking/DNet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.IO;
using System.Linq;
using UnityEngine;
using Object = UnityEngine.Object;

namespace LCVR.Networking;

Expand All @@ -23,7 +24,7 @@ public static class DNet
{
private const ushort PROTOCOL_VERSION = 3;

private static readonly NamedLogger Logger = new("Networking");
private static readonly NamedLogger logger = new("Networking");

private static DissonanceComms dissonance;
private static NfgoCommsNetwork network;
Expand All @@ -48,7 +49,7 @@ public static IEnumerator Initialize()
// Wait for voicechat connection
yield return new WaitUntil(() => LocalId.HasValue);

Logger.LogDebug("Connected to Dissonance server");
logger.LogDebug("Connected to Dissonance server");

dissonance.OnPlayerJoinedSession += OnPlayerJoinedSession;
dissonance.OnPlayerLeftSession += OnPlayerLeftSession;
Expand All @@ -73,6 +74,8 @@ public static void Shutdown()
players.Clear();
clients.Clear();
clientByName.Clear();

muffledPlayers.Clear();
}

public static void BroadcastRig(Rig rig)
Expand All @@ -99,15 +102,15 @@ private static void SendHandshakeResponse(ushort client)
{
if (!clients.TryGetValue(client, out var target))
{
Logger.LogError($"Cannot send handshake response to {client}: Client info is missing!");
logger.LogError($"Cannot send handshake response to {client}: Client info is missing!");
return;
}

SendPacket(MessageType.HandshakeResponse, [VRSession.InVR ? (byte)1 : (byte)0], target);
}

/// <summary>
/// Continously send handshake requests to clients that have not been negotiated with yet
/// Continuously send handshake requests to clients that have not been negotiated with yet
/// </summary>
private static IEnumerator SendHandshakeCoroutine()
{
Expand All @@ -127,17 +130,17 @@ private static IEnumerator SendHandshakeCoroutine()

private static void OnPlayerJoinedSession(VoicePlayerState player)
{
Logger.LogDebug("Player joined, trying to resolve client info");
logger.LogDebug("Player joined, trying to resolve client info");

if (!peers.TryGetClientInfoByName(player.Name, out var info))
{
Logger.LogError($"Failed to resolve client info for client '{player.Name}'");
logger.LogError($"Failed to resolve client info for client '{player.Name}'");
return;
}

Logger.LogDebug($"Resolved client info");
Logger.LogDebug($"Player Name = {player.Name}");
Logger.LogDebug($"Player Id = {info.PlayerId}");
logger.LogDebug($"Resolved client info");
logger.LogDebug($"Player Name = {player.Name}");
logger.LogDebug($"Player Id = {info.PlayerId}");

clients.Add(info.PlayerId, info);
clientByName.Add(player.Name, info.PlayerId);
Expand All @@ -149,15 +152,17 @@ private static void OnPlayerLeftSession(VoicePlayerState player)
return;

if (players.TryGetValue(id, out var networkPlayer))
GameObject.Destroy(networkPlayer);
Object.Destroy(networkPlayer);

subscribers.Remove(id);
players.Remove(id);
clients.Remove(id);
clientByName.Remove(player.Name);

Logger.LogDebug($"Player {player.Name} left the game");
Logger.LogDebug($"subscribers = {subscribers.Count}, players = {players.Count}, clients = {clients.Count} ({string.Join(", ", clients.Keys)}), clientByNames = {clientByName.Count} ({string.Join(", ", clientByName.Keys)})");
muffledPlayers.Remove(id);

logger.LogDebug($"Player {player.Name} left the game");
logger.LogDebug($"subscribers = {subscribers.Count}, players = {players.Count}, clients = {clients.Count} ({string.Join(", ", clients.Keys)}), clientByNames = {clientByName.Count} ({string.Join(", ", clientByName.Keys)})");
}

#endregion
Expand All @@ -166,7 +171,7 @@ private static void OnPlayerLeftSession(VoicePlayerState player)

private static void BroadcastPacket(MessageType type, byte[] payload)
{
var targets = subscribers.Where(key => clients.TryGetValue(key, out var value)).Select(value => clients[value]).ToList();
var targets = subscribers.Where(key => clients.TryGetValue(key, out _)).Select(value => clients[value]).ToList();

client.SendReliableP2P(targets, ConstructPacket(type, payload));
}
Expand Down Expand Up @@ -235,7 +240,7 @@ private static void HandleHandshakeRequest(ushort sender, ushort protocol)
if (protocol != PROTOCOL_VERSION)
return;

Logger.LogDebug($"Player {sender} has initiated a handshake");
logger.LogDebug($"Player {sender} has initiated a handshake");

SendHandshakeResponse(sender);
}
Expand All @@ -251,33 +256,34 @@ private static IEnumerator HandleHandshakeResponse(ushort sender, bool isInVR)
// Re-initialize player if already present
if (players.TryGetValue(sender, out var networkPlayer))
{
GameObject.Destroy(networkPlayer);
Object.Destroy(networkPlayer);
players.Remove(sender);
}

yield return new WaitUntil(() => peers.TryGetClientInfoById(sender, out var client));
// Wait until client is a part of the peers list
yield return new WaitUntil(() => peers.TryGetClientInfoById(sender, out _));

if (!peers.TryGetClientInfoById(sender, out var client))
{
Logger.LogError($"Failed to resolve client for Player Id {sender}. No VR movements will be synchronized.");
logger.LogError($"Failed to resolve client for Player Id {sender}. No VR movements will be synchronized.");

yield break;
}

var player = dissonance.FindPlayer(client.PlayerName);
if (player == null)
{
Logger.LogError($"Failed to resolve client for Player {player.Name}. No VR movements will be synchronized.");
logger.LogError($"Failed to resolve client for Player {client.PlayerName}. No VR movements will be synchronized.");
yield break;
}

yield return new WaitUntil(() => player.Tracker != null);

var playerObject = ((NfgoPlayer)player.Tracker).gameObject;
var playerObject = ((NfgoPlayer)player.Tracker!).gameObject;
var playerController = playerObject.GetComponent<PlayerControllerB>();
networkPlayer = playerObject.AddComponent<VRNetPlayer>();

Logger.LogInfo($"Found VR player {playerController.playerUsername}");
logger.LogInfo($"Found VR player {playerController.playerUsername}");

players.Add(sender, networkPlayer);

Expand Down Expand Up @@ -317,31 +323,31 @@ private static void HandleInteractWithLever(ushort sender, bool started)
lever.StopInteracting();
}

private static readonly List<VRNetPlayer> muffledPlayers = [];
private static readonly HashSet<ushort> muffledPlayers = [];

public static bool IsPlayerMuffled(int playerId)
{
return muffledPlayers.Any(player => (int)player.PlayerController.playerClientId == playerId);
return muffledPlayers.Any(player => player == playerId);
}

private static void HandleSetMuffled(ushort sender, bool muffled)
{
if (!players.TryGetValue(sender, out var player))
return;

Logger.Log($"{player.PlayerController.playerUsername} muffled: {muffled}");
logger.Log($"{player.PlayerController.playerUsername} muffled: {muffled}");

if (muffled)
{
var occlude = player.PlayerController.currentVoiceChatAudioSource.GetComponent<OccludeAudio>();
occlude.overridingLowPass = true;
occlude.lowPassOverride = 1000f;

muffledPlayers.Add(player);
muffledPlayers.Add(sender);
}
else
{
muffledPlayers.Remove(player);
muffledPlayers.Remove(sender);

StartOfRound.Instance.UpdatePlayerVoiceEffects();
}
Expand Down Expand Up @@ -420,10 +426,10 @@ public static Rig Deserialize(byte[] raw)
{
rightHandPosition = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()),
rightHandEulers = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()),
rightHandFingers = Fingers.Deserialize(br.ReadBytes(Fingers.ByteCount)),
rightHandFingers = Fingers.Deserialize(br.ReadBytes(Fingers.BYTE_COUNT)),
leftHandPosition = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()),
leftHandEulers = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()),
leftHandFingers = Fingers.Deserialize(br.ReadBytes(Fingers.ByteCount)),
leftHandFingers = Fingers.Deserialize(br.ReadBytes(Fingers.BYTE_COUNT)),
cameraEulers = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()),
cameraPosAccounted = new Vector3(br.ReadSingle(), 0, br.ReadSingle()),
modelOffset = new Vector3(br.ReadSingle(), 0, br.ReadSingle()),
Expand All @@ -445,7 +451,7 @@ public enum CrouchState : byte

public struct Fingers
{
public const int ByteCount = 5;
public const int BYTE_COUNT = 5;

public float thumb;
public float index;
Expand Down Expand Up @@ -508,7 +514,7 @@ private static void ProcessReceivedPacket(ref ArraySegment<byte> data)
{
try
{
using var stream = new MemoryStream(data.Array, data.Offset, data.Array.Length - data.Offset);
using var stream = new MemoryStream(data.Array!, data.Offset, data.Array!.Length - data.Offset);
using var reader = new BinaryReader(stream);

// Check magic
Expand All @@ -531,8 +537,6 @@ private static void ProcessReceivedPacket(ref ArraySegment<byte> data)
{
Logger.LogError(ex.Message);
Logger.LogError(ex.StackTrace);

return;
}
}
}
6 changes: 4 additions & 2 deletions Source/Physics/Interactions/TeleporterButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ private IEnumerator timerLoop()
{
while (true)
{
if (teleporter.cooldownTime > 0)
var cooldown = Mathf.Max(teleporter.cooldownTime, 0);

if (cooldown > 0)
timerText.color = new Color(1f, 0.1062f, 0f, 0.4314f);
else
timerText.color = new Color(0.1062f, 1f, 0f, 0.4314f);

timerText.text = $"{Mathf.Floor(teleporter.cooldownTime / 60f)}:{(int)teleporter.cooldownTime % 60:D2}";
timerText.text = $"{Mathf.Floor(cooldown / 60f)}:{(int)cooldown % 60:D2}";
yield return new WaitForSeconds(1);
}
}
Expand Down
29 changes: 28 additions & 1 deletion Source/Player/Spectating/EnemyPatches.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
using System.Collections.Generic;
using System.Reflection.Emit;
using GameNetcodeStuff;
using HarmonyLib;
using LCVR.Patches;
using Unity.Netcode;
using static HarmonyLib.AccessTools;

namespace LCVR.Player.Spectating;

Expand Down Expand Up @@ -35,12 +40,34 @@ private static bool TriggerCentipedeFall(CentipedeAI __instance)
{
var networkManager = __instance.NetworkManager;

if ((networkManager.IsClient || networkManager.IsHost) && StartOfRound.Instance.localPlayerController.isPlayerDead)
if ((int)__instance.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost) && StartOfRound.Instance.localPlayerController.isPlayerDead)
{
__instance.triggeredFall = false;
return false;
}

return true;
}

/// <summary>
/// Fix for the dress girl AI not swapping players if the host is dead and being haunted
/// </summary>
[HarmonyPatch(typeof(DressGirlAI), nameof(DressGirlAI.Update))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> DressGirlTargetDeadPlayerFix(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
return new CodeMatcher(instructions, generator)
.MatchForward(false, new CodeMatch(OpCodes.Call, PropertyGetter(typeof(NetworkBehaviour), nameof(NetworkBehaviour.IsServer))))
.Advance(6)
.CreateLabel(out var label)
.Advance(-1)
.SetInstructionAndAdvance(new(OpCodes.Brfalse, label))
.InsertAndAdvance([
new(OpCodes.Ldarg_0),
new(OpCodes.Ldfld, Field(typeof(DressGirlAI), nameof(DressGirlAI.hauntingPlayer))),
new(OpCodes.Ldfld, Field(typeof(PlayerControllerB), nameof(PlayerControllerB.isPlayerDead))),
])
.InsertBranch(OpCodes.Brfalse, 21)
.InstructionEnumeration();
}
}
20 changes: 19 additions & 1 deletion Source/Player/Spectating/EnvironmentPatches.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GameNetcodeStuff;
using System.Collections;
using GameNetcodeStuff;
using HarmonyLib;
using LCVR.Patches;
using System.Collections.Generic;
Expand Down Expand Up @@ -77,4 +78,21 @@ private static bool SilenceDoorTeleport(EntranceTeleport __instance, int playerO

return !networkCheck || !localPlayerCheck || !localDeadCheck;
}

/// <summary>
/// Prevent dead players from being teleported if they don't have a body to teleport
/// </summary>
[HarmonyPatch(typeof(ShipTeleporter), nameof(ShipTeleporter.beamUpPlayer))]
[HarmonyPrefix]
private static bool PreventTeleportDeadPlayer(ShipTeleporter __instance, ref IEnumerator __result)
{
var target = StartOfRound.Instance.mapScreen.targetedPlayer;
if (target != StartOfRound.Instance.localPlayerController || !target.isPlayerDead ||
target.deadBody is not null)
return true;

__instance.shipTeleporterAudio.PlayOneShot(__instance.teleporterSpinSFX);
__result = Utils.NopRoutine();
return false;
}
}

0 comments on commit 48538b3

Please sign in to comment.