Merge pull request #300 from misternebula/respawn-overhaul

Respawn overhaul
This commit is contained in:
_nebula 2021-08-09 11:57:20 +01:00 committed by GitHub
commit 9c7a09d0da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
144 changed files with 4476 additions and 1911 deletions

1
.gitignore vendored
View File

@ -361,6 +361,7 @@ QSB.csproj.user
GameAssets/
Chert/
Riebeck/
IgnoreInGithub/
OWML.Config.json
WeavedFiles/QSB.dll
WeavedFiles/QSB.dll.mdb

View File

@ -3,7 +3,7 @@ CRC: 2815158869
Hashes:
AssetFileHash:
serializedVersion: 2
Hash: 81bbcd8775249928cc67d7ff90ff9047
Hash: 5677b7876f2afae05c0920067ef29e8a
TypeTreeHash:
serializedVersion: 2
Hash: 4d6a73cb377370ba69c96eb5da1b5028

Binary file not shown.

View File

@ -1,9 +1,9 @@
ManifestFileVersion: 0
CRC: 1574640978
CRC: 3621554448
Hashes:
AssetFileHash:
serializedVersion: 2
Hash: 7f0a5acd2c87eeadfd051836171b2256
Hash: c9002a0b83220186e94179a065236b5c
TypeTreeHash:
serializedVersion: 2
Hash: 8b6abf066340f652e25eed06e6b72102
@ -22,10 +22,8 @@ ClassTypes:
- Class: 115
Script: {instanceID: 0}
Assets:
- Assets/NetworkStickPivot.prefab
- Assets/NetworkPlayer.prefab
- Assets/NetworkCameraRoot.prefab
- Assets/NetworkProbe.prefab
- Assets/NETWORK_Player_Body.prefab
- Assets/NetworkOrb.prefab
- Assets/NetworkShip.prefab
Dependencies: []

View File

@ -53,7 +53,7 @@ namespace QSB.Animation.NPC.Patches
{
if (playerId == uint.MaxValue)
{
DebugLog.DebugWrite($"Error - {__instance.name} is in conversation with a null player! Defaulting to active camera.", MessageType.Error);
DebugLog.ToConsole($"Error - {__instance.name} is in conversation with a null player! Defaulting to active camera.", MessageType.Error);
playerToUse = QSBPlayerManager.LocalPlayer;
}
else

View File

@ -1,4 +1,5 @@
using QSB.WorldSync;
using QSB.Utility;
using QSB.WorldSync;
using UnityEngine;
namespace QSB.Animation.NPC.WorldObjects
@ -15,10 +16,10 @@ namespace QSB.Animation.NPC.WorldObjects
public abstract CharacterDialogueTree GetDialogueTree();
public virtual void StartConversation()
=> QSBWorldSync.RaiseEvent(GetDialogueTree(), "OnStartConversation");
=> GetDialogueTree().RaiseEvent("OnStartConversation");
public virtual void EndConversation()
=> QSBWorldSync.RaiseEvent(GetDialogueTree(), "OnEndConversation");
=> GetDialogueTree().RaiseEvent("OnEndConversation");
public abstract bool InConversation();
}

View File

@ -49,7 +49,7 @@ namespace QSB.Animation.Player
QSBSceneManager.OnUniverseSceneLoaded -= OnUniverseSceneLoaded;
}
private void OnUniverseSceneLoaded(OWScene obj) => LoadControllers();
private void OnUniverseSceneLoaded(OWScene oldScene, OWScene newScene) => LoadControllers();
private void LoadControllers()
{

View File

@ -1,7 +1,7 @@
using QSB.Events;
using QSB.Patches;
using QSB.Player;
using QSB.WorldSync;
using QSB.Utility;
using UnityEngine;
namespace QSB.Animation.Patches
@ -91,24 +91,24 @@ namespace QSB.Animation.Patches
if (!____leftFootGrounded && leftFootLift < 0.333f)
{
____leftFootGrounded = true;
QSBWorldSync.RaiseEvent(__instance, "OnLeftFootGrounded");
__instance.RaiseEvent("OnLeftFootGrounded");
}
else if (____leftFootGrounded && leftFootLift > 0.666f)
{
____leftFootGrounded = false;
QSBWorldSync.RaiseEvent(__instance, "OnLeftFootLift");
__instance.RaiseEvent("OnLeftFootLift");
}
var rightFootLift = ____animator.GetFloat("RightFootLift");
if (!____rightFootGrounded && rightFootLift < 0.333f)
{
____rightFootGrounded = true;
QSBWorldSync.RaiseEvent(__instance, "OnRightFootGrounded");
__instance.RaiseEvent("OnRightFootGrounded");
}
else if (____rightFootGrounded && rightFootLift > 0.666f)
{
____rightFootGrounded = false;
QSBWorldSync.RaiseEvent(__instance, "OnRightFootLift");
__instance.RaiseEvent("OnRightFootLift");
}
}

View File

@ -19,10 +19,9 @@ namespace QSB.Animation.Player.Thrusters
CreateThrusterFlameController(newVfx, player);
newVfx.transform.parent = player.Body.transform;
// Body isnt the actualy player body... it's the model... ;(
newVfx.transform.localPosition = new Vector3(0, 10.24412f, 2.268939f);
newVfx.transform.rotation = Quaternion.Euler(1.5f, 0, 0);
newVfx.transform.localScale = new Vector3(10, 10, 10);
newVfx.transform.localPosition = Vector3.zero;
newVfx.transform.rotation = Quaternion.Euler(0, 0, 0);
newVfx.transform.localScale = new Vector3(1, 1, 1);
// Deleted objects take 1 update to actually be deleted
QSBCore.UnityEvents.FireOnNextUpdate(() => newVfx.SetActive(true));

View File

@ -0,0 +1,13 @@
namespace QSB.ClientServerStateSync
{
public enum ClientState
{
NotLoaded,
InTitleScreen,
AliveInSolarSystem,
DeadInSolarSystem,
AliveInEye,
WaitingForOthersToDieInSolarSystem,
WaitingForOthersToReadyInSolarSystem
}
}

View File

@ -0,0 +1,125 @@
using QSB.Events;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.Utility;
using UnityEngine;
namespace QSB.ClientServerStateSync
{
internal class ClientStateManager : MonoBehaviour
{
public static ClientStateManager Instance { get; private set; }
public event ChangeStateEvent OnChangeState;
public delegate void ChangeStateEvent(ClientState newState);
private void Awake()
=> Instance = this;
private void Start()
{
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
QSBCore.UnityEvents.RunWhen(() => PlayerTransformSync.LocalInstance != null, () => QSBEventManager.FireEvent(EventNames.QSBClientState, ForceGetCurrentState()));
}
public void ChangeClientState(ClientState newState)
{
if (QSBPlayerManager.LocalPlayer.State == newState)
{
return;
}
DebugLog.DebugWrite($"CHANGE CLIENT STATE FROM {QSBPlayerManager.LocalPlayer.State} to {newState}");
QSBPlayerManager.LocalPlayer.State = newState;
OnChangeState?.Invoke(newState);
}
private void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool inUniverse)
{
var serverState = ServerStateManager.Instance.GetServerState();
if (QSBCore.IsHost)
{
if (newScene == OWScene.SolarSystem && oldScene != OWScene.SolarSystem)
{
DebugLog.DebugWrite($"Server is loading SolarSystem just after creating server.");
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.AliveInSolarSystem);
}
if (newScene == OWScene.SolarSystem && oldScene == OWScene.SolarSystem)
{
DebugLog.DebugWrite($"Server is reloading SolarSystem");
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.WaitingForOthersToReadyInSolarSystem);
}
if (newScene == OWScene.TitleScreen)
{
DebugLog.DebugWrite($"Server has gone back to title screen");
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.InTitleScreen);
}
}
else
{
if (newScene == OWScene.SolarSystem && oldScene != OWScene.SolarSystem && serverState != ServerState.AwaitingPlayConfirmation)
{
DebugLog.DebugWrite($"Client is loading SolarSystem just after connecting.");
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.AliveInSolarSystem);
}
if (newScene == OWScene.SolarSystem && oldScene == OWScene.SolarSystem)
{
DebugLog.DebugWrite($"Client is reloading SolarSystem");
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.WaitingForOthersToReadyInSolarSystem);
}
if (serverState == ServerState.WaitingForDeath)
{
DebugLog.DebugWrite($"Client loaded new scene while server is waiting for all players to die");
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.WaitingForOthersToReadyInSolarSystem);
}
}
}
public void OnDeath()
{
var currentScene = QSBSceneManager.CurrentScene;
if (currentScene == OWScene.SolarSystem)
{
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.DeadInSolarSystem);
}
else if (currentScene == OWScene.EyeOfTheUniverse)
{
DebugLog.ToConsole($"Error - You died in the Eye? HOW DID YOU DO THAT?!", OWML.Common.MessageType.Error);
}
else
{
// whaaaaaaaaa
DebugLog.ToConsole($"Error - You died... in a menu? In the credits? In any case, you should never see this. :P", OWML.Common.MessageType.Error);
}
}
private ClientState ForceGetCurrentState()
{
var currentScene = LoadManager.GetCurrentScene();
var lastScene = LoadManager.GetPreviousScene();
if (currentScene == OWScene.TitleScreen || currentScene == OWScene.Credits_Fast || currentScene == OWScene.Credits_Final)
{
return ClientState.InTitleScreen;
}
// cant join while dead...
if (currentScene == OWScene.SolarSystem)
{
return ClientState.AliveInSolarSystem;
}
if (currentScene == OWScene.EyeOfTheUniverse)
{
return ClientState.AliveInEye;
}
return ClientState.NotLoaded;
}
}
}

View File

@ -0,0 +1,41 @@
using QSB.Events;
using QSB.Messaging;
using QSB.Player;
using QSB.Utility;
namespace QSB.ClientServerStateSync.Events
{
internal class ClientStateEvent : QSBEvent<EnumMessage<ClientState>>
{
public override EventType Type => EventType.ClientState;
public override void SetupListener()
=> GlobalMessenger<ClientState>.AddListener(EventNames.QSBClientState, Handler);
public override void CloseListener()
=> GlobalMessenger<ClientState>.RemoveListener(EventNames.QSBClientState, Handler);
private void Handler(ClientState state) => SendEvent(CreateMessage(state));
private EnumMessage<ClientState> CreateMessage(ClientState state) => new EnumMessage<ClientState>
{
AboutId = LocalPlayerId,
EnumValue = state
};
public override void OnReceiveLocal(bool server, EnumMessage<ClientState> message)
=> ClientStateManager.Instance.ChangeClientState(message.EnumValue);
public override void OnReceiveRemote(bool server, EnumMessage<ClientState> message)
{
DebugLog.DebugWrite($"Remote receive id:{message.AboutId} state:{message.EnumValue}");
if (message.AboutId == uint.MaxValue)
{
DebugLog.DebugWrite($"Error - ID is uint.MaxValue!", OWML.Common.MessageType.Error);
return;
}
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.State = message.EnumValue;
}
}
}

View File

@ -0,0 +1,30 @@
using QSB.Events;
using QSB.Messaging;
namespace QSB.ClientServerStateSync.Events
{
internal class ServerStateEvent : QSBEvent<EnumMessage<ServerState>>
{
public override EventType Type => EventType.ServerState;
public override void SetupListener()
=> GlobalMessenger<ServerState>.AddListener(EventNames.QSBServerState, Handler);
public override void CloseListener()
=> GlobalMessenger<ServerState>.RemoveListener(EventNames.QSBServerState, Handler);
private void Handler(ServerState state) => SendEvent(CreateMessage(state));
private EnumMessage<ServerState> CreateMessage(ServerState state) => new EnumMessage<ServerState>
{
AboutId = LocalPlayerId,
EnumValue = state
};
public override void OnReceiveLocal(bool server, EnumMessage<ServerState> message)
=> OnReceiveRemote(server, message);
public override void OnReceiveRemote(bool server, EnumMessage<ServerState> message)
=> ServerStateManager.Instance.ChangeServerState(message.EnumValue);
}
}

View File

@ -0,0 +1,26 @@
namespace QSB.ClientServerStateSync
{
public enum ServerState
{
// When in menus
NotLoaded,
// When in any credits
Credits,
// For normal play in SolarSystem
InSolarSystem,
// For normal play in EyeOfTheUniverse
InEye,
// At end of loop, waiting for everyone to be ready to reload the scene
WaitingForDeath,
// At start of loop, waiting for everybody to be ready to start playing
AwaitingPlayConfirmation,
// When the statue has been activated
InStatueCutscene
}
}

View File

@ -0,0 +1,126 @@
using QSB.Events;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.Utility;
using System.Linq;
using UnityEngine;
namespace QSB.ClientServerStateSync
{
internal class ServerStateManager : MonoBehaviour
{
public static ServerStateManager Instance { get; private set; }
public event ChangeStateEvent OnChangeState;
public delegate void ChangeStateEvent(ServerState newState);
private ServerState _currentState;
private void Awake()
=> Instance = this;
private void Start()
{
if (!QSBCore.IsHost)
{
return;
}
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
GlobalMessenger.AddListener("TriggerSupernova", OnTriggerSupernova);
QSBCore.UnityEvents.RunWhen(() => PlayerTransformSync.LocalInstance != null, () => QSBEventManager.FireEvent(EventNames.QSBServerState, ForceGetCurrentState()));
}
public void ChangeServerState(ServerState newState)
{
if (_currentState == newState)
{
return;
}
DebugLog.DebugWrite($"CHANGE SERVER STATE FROM {_currentState} to {newState}");
_currentState = newState;
OnChangeState?.Invoke(newState);
}
public ServerState GetServerState()
=> _currentState;
private void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool inUniverse)
{
switch (newScene)
{
case OWScene.Credits_Fast:
case OWScene.Credits_Final:
case OWScene.PostCreditsScene:
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.Credits);
break;
case OWScene.TitleScreen:
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.NotLoaded);
break;
case OWScene.SolarSystem:
if (oldScene == OWScene.SolarSystem)
{
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.AwaitingPlayConfirmation);
}
else
{
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.InSolarSystem);
}
break;
case OWScene.EyeOfTheUniverse:
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.AwaitingPlayConfirmation);
break;
case OWScene.None:
case OWScene.Undefined:
default:
DebugLog.ToConsole($"Warning - newScene is {newScene}!", OWML.Common.MessageType.Warning);
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.NotLoaded);
break;
}
}
private void OnTriggerSupernova()
{
DebugLog.DebugWrite($"TriggerSupernova");
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.WaitingForDeath);
}
private ServerState ForceGetCurrentState()
{
var currentScene = LoadManager.GetCurrentScene();
var lastScene = LoadManager.GetPreviousScene();
switch (currentScene)
{
case OWScene.SolarSystem:
return ServerState.InSolarSystem;
case OWScene.EyeOfTheUniverse:
return ServerState.InEye;
default:
return ServerState.NotLoaded;
}
}
private void Update()
{
if (!QSBCore.IsHost)
{
return;
}
if (_currentState == ServerState.AwaitingPlayConfirmation)
{
if (QSBPlayerManager.PlayerList.All(x => x.State == ClientState.WaitingForOthersToReadyInSolarSystem))
{
DebugLog.DebugWrite($"All ready!!");
QSBEventManager.FireEvent(EventNames.QSBStartLoop);
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.InSolarSystem);
}
}
}
}
}

View File

@ -0,0 +1,7 @@
namespace QSB.DeathSync
{
public enum EndLoopReason
{
AllPlayersDead = 0
}
}

View File

@ -0,0 +1,41 @@
using QSB.ClientServerStateSync;
using QSB.Events;
using QSB.Messaging;
using QSB.Utility;
namespace QSB.DeathSync.Events
{
internal class EndLoopEvent : QSBEvent<EnumMessage<EndLoopReason>>
{
public override EventType Type => EventType.EndLoop;
public override void SetupListener() => GlobalMessenger<EndLoopReason>.AddListener(EventNames.QSBEndLoop, Handler);
public override void CloseListener() => GlobalMessenger<EndLoopReason>.RemoveListener(EventNames.QSBEndLoop, Handler);
private void Handler(EndLoopReason type) => SendEvent(CreateMessage(type));
private EnumMessage<EndLoopReason> CreateMessage(EndLoopReason type) => new EnumMessage<EndLoopReason>
{
AboutId = LocalPlayerId,
EnumValue = type
};
public override void OnReceiveLocal(bool server, EnumMessage<EndLoopReason> message)
=> OnReceiveRemote(server, message);
public override void OnReceiveRemote(bool server, EnumMessage<EndLoopReason> message)
{
switch (message.EnumValue)
{
case EndLoopReason.AllPlayersDead:
DebugLog.DebugWrite($"all players dead");
Locator.GetDeathManager().KillPlayer(DeathType.TimeLoop);
if (QSBCore.IsHost)
{
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.WaitingForDeath);
}
break;
}
}
}
}

View File

@ -1,4 +1,5 @@
using QSB.Events;
using QSB.ClientServerStateSync;
using QSB.Events;
using QSB.Player;
using QSB.Utility;
@ -20,11 +21,23 @@ namespace QSB.DeathSync.Events
NecronomiconIndex = Necronomicon.GetRandomIndex(type)
};
public override void OnReceiveLocal(bool server, PlayerDeathMessage message)
{
DebugLog.DebugWrite($"RECEIVE LOCAL PLAYER DEATH");
var player = QSBPlayerManager.GetPlayer(message.AboutId);
RespawnManager.Instance.OnPlayerDeath(player);
ClientStateManager.Instance.OnDeath();
}
public override void OnReceiveRemote(bool server, PlayerDeathMessage message)
{
var playerName = QSBPlayerManager.GetPlayer(message.AboutId).Name;
DebugLog.DebugWrite($"RECEIVE REMOTE PLAYER DEATH");
var player = QSBPlayerManager.GetPlayer(message.AboutId);
var playerName = player.Name;
var deathMessage = Necronomicon.GetPhrase(message.EnumValue, message.NecronomiconIndex);
DebugLog.ToAll(string.Format(deathMessage, playerName));
RespawnManager.Instance.OnPlayerDeath(player);
}
}
}

View File

@ -0,0 +1,37 @@
using QSB.Events;
using QSB.Messaging;
using QSB.Player;
namespace QSB.DeathSync.Events
{
internal class PlayerRespawnEvent : QSBEvent<PlayerMessage>
{
public override EventType Type => EventType.PlayerRespawn;
public override void SetupListener()
=> GlobalMessenger<uint>.AddListener(EventNames.QSBPlayerRespawn, Handler);
public override void CloseListener()
=> GlobalMessenger<uint>.RemoveListener(EventNames.QSBPlayerRespawn, Handler);
private void Handler(uint playerId) => SendEvent(CreateMessage(playerId));
private PlayerMessage CreateMessage(uint playerId) => new PlayerMessage
{
AboutId = playerId
};
public override void OnReceiveLocal(bool server, PlayerMessage message)
=> OnReceiveRemote(server, message);
public override void OnReceiveRemote(bool server, PlayerMessage message)
{
if (message.AboutId == LocalPlayerId)
{
RespawnManager.Instance.Respawn();
}
RespawnManager.Instance.OnPlayerRespawn(QSBPlayerManager.GetPlayer(message.AboutId));
}
}
}

View File

@ -0,0 +1,31 @@
using QSB.ClientServerStateSync;
using QSB.Events;
using QSB.Messaging;
using QSB.Utility;
namespace QSB.DeathSync.Events
{
internal class StartLoopEvent : QSBEvent<PlayerMessage>
{
public override EventType Type => EventType.StartLoop;
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBStartLoop, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBStartLoop, Handler);
private void Handler() => SendEvent(CreateMessage());
private PlayerMessage CreateMessage() => new PlayerMessage
{
AboutId = LocalPlayerId
};
public override void OnReceiveLocal(bool server, PlayerMessage message)
=> OnReceiveRemote(server, message);
public override void OnReceiveRemote(bool server, PlayerMessage message)
{
DebugLog.DebugWrite($" ~~~ LOOP START ~~~");
QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.AliveInSolarSystem);
}
}
}

View File

@ -1,8 +1,10 @@
using Harmony;
using QSB.Events;
using QSB.Patches;
using QSB.Player;
using QSB.ShipSync;
using QSB.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
@ -186,6 +188,7 @@ namespace QSB.DeathSync.Patches
public static bool DeathManager_KillPlayer_Prefix(DeathType deathType)
{
DebugLog.DebugWrite($"KILL PLAYER PREFIX stacetrace : \r\n {Environment.StackTrace}");
if (RespawnOnDeath.Instance == null)
{
return true;
@ -196,31 +199,26 @@ namespace QSB.DeathSync.Patches
return true;
}
if (!ShipManager.Instance.HasAuthority)
{
RespawnOnDeath.Instance.ResetPlayer();
return false;
}
QSBPlayerManager.LocalPlayer.IsDead = true;
RespawnOnDeath.Instance.ResetShip();
RespawnOnDeath.Instance.ResetPlayer();
return false;
}
public static void DeathManager_KillPlayer_Postfix(DeathType deathType)
=> QSBEventManager.FireEvent(EventNames.QSBPlayerDeath, deathType);
{
DebugLog.DebugWrite($"KILL PLAYER POSTFIX");
QSBEventManager.FireEvent(EventNames.QSBPlayerDeath, deathType);
}
public static void ShipDamageController_Awake(ref bool ____exploded)
=> ____exploded = true;
public static IEnumerable<CodeInstruction> ReturnNull(IEnumerable<CodeInstruction> instructions)
{
return new List<CodeInstruction>
public static IEnumerable<CodeInstruction> ReturnNull(IEnumerable<CodeInstruction> instructions) => new List<CodeInstruction>
{
new CodeInstruction(OpCodes.Ldnull),
new CodeInstruction(OpCodes.Ret)
};
}
public static bool DestructionVolume_VanishShip(DeathType ____deathType)
{
@ -238,9 +236,8 @@ namespace QSB.DeathSync.Patches
{
Locator.GetDeathManager().KillPlayer(____deathType);
}
// Ship is being destroyed, but player isn't in it.
RespawnOnDeath.Instance.ResetShip();
return false;
return true;
}
}
}

View File

@ -0,0 +1,248 @@
using QSB.Patches;
using UnityEngine;
namespace QSB.DeathSync.Patches
{
internal class MapPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.RespawnTime;
public override void DoPatches()
{
Prefix(nameof(MapController_LateUpdate));
Prefix(nameof(MapController_EnterMapView));
}
public static bool MapController_EnterMapView(
MapController __instance,
ref bool ____isMapMode,
OWAudioSource ____audioSource,
MapMarkerManager ____mapMarkerManager,
OWCamera ____mapCamera,
OWCamera ____activeCam,
MeshRenderer ____gridRenderer,
ref Transform ____targetTransform,
ref bool ____lockedToTargetTransform,
ref Vector3 ____position,
ref float ____yaw,
ref float ____pitch,
ref float ____zoom,
ref float ____targetZoom,
ref bool ____interpPosition,
ref bool ____interpPitch,
ref bool ____interpZoom,
ref bool ____framingPlayer,
ref float ____lockTimer,
float ____defaultYawAngle,
float ____initialPitchAngle,
float ____initialZoomDist,
float ____defaultZoomDist,
float ____lockOnMoveLength,
ref float ____gridOverrideSize,
ref bool ____gridOverride,
ref float ____gridTimer,
ref float ____revealLength,
ReferenceFrame ____currentRFrame,
float ____gridLockOnLength,
ref float ____revealTimer
)
{
if (____isMapMode)
{
return false;
}
____mapMarkerManager.SetVisible(true);
GlobalMessenger.FireEvent("EnterMapView");
GlobalMessenger<OWCamera>.FireEvent("SwitchActiveCamera", ____mapCamera);
if (____audioSource.isPlaying)
{
____audioSource.Stop();
____audioSource.SetLocalVolume(1f);
____audioSource.Play();
}
else
{
____audioSource.SetLocalVolume(1f);
____audioSource.Play();
}
Locator.GetAudioMixer().MixMap();
____activeCam.enabled = false;
____mapCamera.enabled = true;
____gridRenderer.enabled = false;
____targetTransform = null;
____lockedToTargetTransform = false;
____position = RespawnOnDeath.Instance.DeathPositionWorld - Locator.GetCenterOfTheUniverse().GetStaticReferenceFrame().GetPosition();
____position.y = 0f;
____yaw = ____defaultYawAngle;
____pitch = ____initialPitchAngle;
____zoom = ____initialZoomDist;
____targetZoom = ____defaultZoomDist;
__instance.transform.rotation = Quaternion.LookRotation(-RespawnOnDeath.Instance.DeathPlayerUpVector, RespawnOnDeath.Instance.DeathPlayerForwardVector);
__instance.transform.position = RespawnOnDeath.Instance.DeathPositionWorld;
____interpPosition = true;
____interpPitch = true;
____interpZoom = true;
____framingPlayer = ____lockedToTargetTransform;
____lockTimer = ____lockOnMoveLength;
____gridOverrideSize = (____currentRFrame == null) ? 0f : ____currentRFrame.GetAutopilotArrivalDistance();
____gridOverride = ____gridOverrideSize > 0f;
____gridTimer = (!____gridOverride) ? 0f : ____gridLockOnLength;
____revealLength = 20f;
____revealTimer = 0f;
____isMapMode = true;
return false;
}
public static bool MapController_LateUpdate(
MapController __instance,
ref float ____observatoryRevealTwist,
ref float ____defaultPitchAngle,
ref float ____initialPitchAngle,
OWCamera ____mapCamera,
ref float ____lockTimer,
ref float ____revealTimer,
float ____lockOnMoveLength,
float ____revealLength,
ref bool ____screenPromptsVisible,
bool ____isPaused,
ScreenPrompt ____closePrompt,
ScreenPrompt ____panPrompt,
ScreenPrompt ____rotatePrompt,
ScreenPrompt ____zoomPrompt,
ref bool ____lockedToTargetTransform,
ref bool ____interpPosition,
ref bool ____interpPitch,
ref bool ____interpZoom,
OWCamera ____activeCam,
ref Vector3 ____position,
float ____panSpeed,
ref float ____zoom,
float ____maxPanDistance,
float ____yawSpeed,
ref float ____yaw,
float ____pitchSpeed,
ref float ____pitch,
float ____minPitchAngle,
float ____maxPitchAngle,
ref float ____targetZoom,
float ____minZoomDistance,
float ____maxZoomDistance,
float ____initialZoomDist,
float ____zoomSpeed,
float ____observatoryRevealDist
)
{
____lockTimer = Mathf.Min(____lockTimer + Time.deltaTime, ____lockOnMoveLength);
____revealTimer = Mathf.Min(____revealTimer + Time.deltaTime, ____revealLength);
var revealFraction = Mathf.Clamp01(____revealTimer / ____revealLength);
var smoothedRevealFraction = Mathf.SmoothStep(0f, 1f, revealFraction);
var canInteractWith = ____revealTimer > 18f;
if (____screenPromptsVisible && ____isPaused)
{
____closePrompt.SetVisibility(false);
____panPrompt.SetVisibility(false);
____rotatePrompt.SetVisibility(false);
____zoomPrompt.SetVisibility(false);
____screenPromptsVisible = false;
}
else if (!____screenPromptsVisible && canInteractWith && !____isPaused)
{
____closePrompt.SetVisibility(false);
____panPrompt.SetVisibility(true);
____rotatePrompt.SetVisibility(true);
____zoomPrompt.SetVisibility(true);
____screenPromptsVisible = true;
}
var XZinput = Vector2.zero;
var lookInput = Vector2.zero;
var zoomInput = 0f;
if (canInteractWith)
{
XZinput = OWInput.GetValue(InputLibrary.moveXZ, InputMode.All);
lookInput = InputLibrary.look.GetValue(false);
zoomInput = OWInput.GetValue(InputLibrary.mapZoom, InputMode.All);
lookInput.y *= -1f;
zoomInput *= -1f;
}
____lockedToTargetTransform &= XZinput.sqrMagnitude < 0.01f;
____interpPosition &= XZinput.sqrMagnitude < 0.01f;
____interpPitch &= Mathf.Abs(lookInput.y) < 0.1f;
____interpZoom &= Mathf.Abs(zoomInput) < 0.1f;
if (____interpPosition)
{
var a = ____activeCam.transform.position - Locator.GetCenterOfTheUniverse().GetOffsetPosition();
var b = Vector3.zero;
____position = Vector3.Lerp(a, b, smoothedRevealFraction);
}
else
{
var normalized = Vector3.Scale(__instance.transform.forward + __instance.transform.up, new Vector3(1f, 0f, 1f)).normalized;
var a2 = (__instance.transform.right * XZinput.x) + (normalized * XZinput.y);
____position += a2 * ____panSpeed * ____zoom * Time.deltaTime;
____position.y = 0f;
if (____position.sqrMagnitude > ____maxPanDistance * ____maxPanDistance)
{
____position = ____position.normalized * ____maxPanDistance;
}
}
____yaw += lookInput.x * ____yawSpeed * Time.deltaTime;
____yaw = OWMath.WrapAngle(____yaw);
if (____interpPitch)
{
____pitch = Mathf.Lerp(____initialPitchAngle, ____defaultPitchAngle, smoothedRevealFraction);
}
else
{
____pitch += lookInput.y * ____pitchSpeed * Time.deltaTime;
____pitch = Mathf.Clamp(____pitch, ____minPitchAngle, ____maxPitchAngle);
}
if (____interpZoom)
{
____zoom = Mathf.Lerp(____initialZoomDist, ____targetZoom, smoothedRevealFraction);
}
else
{
____zoom += zoomInput * ____zoomSpeed * Time.deltaTime;
____zoom = Mathf.Clamp(____zoom, ____minZoomDistance, ____maxZoomDistance);
}
____mapCamera.nearClipPlane = Mathf.Lerp(0.1f, 1f, smoothedRevealFraction);
var finalRotation = Quaternion.Euler(____pitch, ____yaw, 0f);
var num4 = revealFraction * (2f - revealFraction);
var num5 = Mathf.SmoothStep(0f, 1f, num4);
// Create rotation that's looking down at the player from above
var lookingDownAtPlayer = Quaternion.LookRotation(-RespawnOnDeath.Instance.DeathPlayerUpVector, Vector3.up);
// Get starting position - distance above player
var startingPosition = RespawnOnDeath.Instance.DeathPositionWorld;
startingPosition += RespawnOnDeath.Instance.DeathPlayerUpVector * num5 * ____observatoryRevealDist;
// Lerp to final rotation
__instance.transform.rotation = Quaternion.Lerp(lookingDownAtPlayer, finalRotation, num5);
// Lerp reveal twist
__instance.transform.rotation *= Quaternion.AngleAxis(Mathf.Lerp(____observatoryRevealTwist, 0f, num4), Vector3.forward);
var endPosition = ____position + (-__instance.transform.forward * ____zoom) + Locator.GetCenterOfTheUniverse().GetStaticReferenceFrame().GetPosition();
// Lerp to final position
__instance.transform.position = Vector3.Lerp(startingPosition, endPosition, num5);
return false;
}
}
}

View File

@ -0,0 +1,166 @@
using OWML.Utils;
using QSB.Patches;
namespace QSB.DeathSync.Patches
{
internal class RespawnPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public override void DoPatches()
{
Prefix(nameof(PlayerRecoveryPoint_OnGainFocus));
Prefix(nameof(PlayerRecoveryPoint_OnPressInteract));
}
public static bool PlayerRecoveryPoint_OnGainFocus(
PlayerResources ____playerResources,
bool ____refuelsPlayer,
bool ____healsPlayer,
SingleInteractionVolume ____interactVolume
)
{
if (____playerResources == null)
{
____playerResources = Locator.GetPlayerTransform().GetComponent<PlayerResources>();
}
var isAtFullHealth = ____playerResources.GetHealthFraction() == 1f;
var isAtFullFuel = ____playerResources.GetFuelFraction() == 1f;
var canBeRefueled = false;
var canBeHealed = false;
if (!isAtFullFuel && ____refuelsPlayer)
{
canBeRefueled = true;
}
if (!isAtFullHealth && ____healsPlayer)
{
canBeHealed = true;
}
var showRespawnPrompt = false;
var uitextType = UITextType.None;
if (canBeHealed && canBeRefueled)
{
// Heal and refuel
uitextType = UITextType.RefillPrompt_0;
____interactVolume.SetKeyCommandVisible(true);
}
else if (canBeHealed)
{
// Heal
uitextType = UITextType.RefillPrompt_2;
____interactVolume.SetKeyCommandVisible(true);
}
else if (canBeRefueled)
{
// Refuel
uitextType = UITextType.RefillPrompt_4;
____interactVolume.SetKeyCommandVisible(true);
}
else if (RespawnManager.Instance.RespawnNeeded)
{
showRespawnPrompt = true;
}
else if (____refuelsPlayer && ____healsPlayer)
{
// Fuel and health full
uitextType = UITextType.RefillPrompt_7;
____interactVolume.SetKeyCommandVisible(false);
}
else if (____refuelsPlayer)
{
// Fuel full
uitextType = UITextType.RefillPrompt_8;
____interactVolume.SetKeyCommandVisible(false);
}
else if (____healsPlayer)
{
// Health full
uitextType = UITextType.RefillPrompt_9;
____interactVolume.SetKeyCommandVisible(false);
}
if (showRespawnPrompt)
{
____interactVolume.GetValue<ScreenPrompt>("_screenPrompt").SetText($"<CMD> Respawn Player");
____interactVolume.GetValue<ScreenPrompt>("_noCommandIconPrompt").SetText("Respawn Player");
}
if (uitextType != UITextType.None)
{
____interactVolume.ChangePrompt(uitextType);
}
return false;
}
public static bool PlayerRecoveryPoint_OnPressInteract(
PlayerRecoveryPoint __instance,
PlayerResources ____playerResources,
ref bool ____recovering,
bool ____refuelsPlayer,
bool ____healsPlayer,
PlayerAudioController ____playerAudioController,
SingleInteractionVolume ____interactVolume
)
{
var playerNeedsRefueling = ____playerResources.GetFuelFraction() != 1f;
var playerNeedsHealing = ____playerResources.GetHealthFraction() != 1f;
var canBeInteractedWith = false;
if (playerNeedsRefueling && ____refuelsPlayer)
{
canBeInteractedWith = true;
}
if (playerNeedsHealing && ____healsPlayer)
{
canBeInteractedWith = true;
}
if (RespawnManager.Instance.RespawnNeeded)
{
canBeInteractedWith = true;
}
if (canBeInteractedWith)
{
if (RespawnManager.Instance.RespawnNeeded && !playerNeedsRefueling && !playerNeedsHealing)
{
RespawnManager.Instance.RespawnSomePlayer();
return false;
}
____playerResources.StartRefillResources(____refuelsPlayer, ____healsPlayer);
if (____playerAudioController != null)
{
if (playerNeedsRefueling && ____refuelsPlayer)
{
____playerAudioController.PlayRefuel();
}
if (playerNeedsHealing && ____healsPlayer)
{
____playerAudioController.PlayMedkit();
}
}
____recovering = true;
__instance.enabled = true;
}
else
{
____interactVolume.ResetInteraction();
}
return false;
}
}
}

View File

@ -0,0 +1,109 @@
using OWML.Utils;
using QSB.Events;
using QSB.Patches;
using QSB.Player;
using QSB.Utility;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.DeathSync
{
internal class RespawnManager : MonoBehaviour
{
public static RespawnManager Instance;
public bool RespawnNeeded => _playersPendingRespawn.Count != 0;
private List<PlayerInfo> _playersPendingRespawn = new List<PlayerInfo>();
private NotificationData _previousNotification;
private void Start()
{
Instance = this;
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool inUniverse)
{
QSBPlayerManager.PlayerList.ForEach(x => x.IsDead = false);
_playersPendingRespawn.Clear();
}
public void TriggerRespawnMap()
{
DebugLog.DebugWrite($"TRIGGER RESPAWN MAP");
QSBPatchManager.DoPatchType(QSBPatchTypes.RespawnTime);
QSBCore.UnityEvents.FireOnNextUpdate(() => GlobalMessenger.FireEvent("TriggerObservatoryMap"));
}
public void Respawn()
{
var mapController = FindObjectOfType<MapController>();
QSBPatchManager.DoUnpatchType(QSBPatchTypes.RespawnTime);
var playerSpawner = FindObjectOfType<PlayerSpawner>();
playerSpawner.DebugWarp(playerSpawner.GetSpawnPoint(SpawnLocation.Ship));
mapController.GetType().GetAnyMethod("ExitMapView").Invoke(mapController, null);
var cameraEffectController = Locator.GetPlayerCamera().GetComponent<PlayerCameraEffectController>();
cameraEffectController.OpenEyes(1f, false);
}
public void OnPlayerDeath(PlayerInfo player)
{
DebugLog.DebugWrite($"ON PLAYER DEATH");
if (_playersPendingRespawn.Contains(player))
{
DebugLog.ToConsole($"Warning - Received death message for player who is already in _playersPendingRespawn!", OWML.Common.MessageType.Warning);
return;
}
DebugLog.DebugWrite($"set player to be dead");
player.IsDead = true;
_playersPendingRespawn.Add(player);
UpdateRespawnNotification();
QSBPlayerManager.ChangePlayerVisibility(player.PlayerId, false);
}
public void OnPlayerRespawn(PlayerInfo player)
{
if (!_playersPendingRespawn.Contains(player))
{
DebugLog.ToConsole($"Warning - Received respawn message for player who is not in _playersPendingRespawn!", OWML.Common.MessageType.Warning);
return;
}
player.IsDead = false;
_playersPendingRespawn.Remove(player);
UpdateRespawnNotification();
QSBPlayerManager.ChangePlayerVisibility(player.PlayerId, true);
}
public void RespawnSomePlayer()
{
var playerToRespawn = _playersPendingRespawn.First();
QSBEventManager.FireEvent(EventNames.QSBPlayerRespawn, playerToRespawn.PlayerId);
}
private void UpdateRespawnNotification()
{
NotificationManager.SharedInstance.UnpinNotification(_previousNotification);
if (_playersPendingRespawn.Count == 0)
{
return;
}
var data = new NotificationData(NotificationTarget.Player, $"[{_playersPendingRespawn.Count}] PLAYER(S) AWAITING RESPAWN");
NotificationManager.SharedInstance.PostNotification(data, true);
_previousNotification = data;
}
}
}

View File

@ -1,6 +1,8 @@
using OWML.Common;
using OWML.Utils;
using QSB.ShipSync.TransformSync;
using QSB.Events;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.Utility;
using System.Linq;
using UnityEngine;
@ -17,21 +19,21 @@ namespace QSB.DeathSync
DeathType.TimeLoop
};
private readonly Vector3 ShipContainerOffset = new Vector3(-16.45f, -52.67f, 227.39f);
private readonly Quaternion ShipContainerRotation = Quaternion.Euler(-76.937f, 1.062f, -185.066f);
private SpawnPoint _shipSpawnPoint;
private SpawnPoint _playerSpawnPoint;
private OWRigidbody _shipBody;
private PlayerSpawner _playerSpawner;
private FluidDetector _fluidDetector;
private PlayerResources _playerResources;
private ShipComponent[] _shipComponents;
private HatchController _hatchController;
private ShipCockpitController _cockpitController;
private PlayerSpacesuit _spaceSuit;
private ShipTractorBeamSwitch _shipTractorBeam;
private SuitPickupVolume[] _suitPickupVolumes;
private Vector3 _deathPositionRelative;
public Transform DeathClosestAstroObject { get; private set; }
public Vector3 DeathPositionWorld
=> DeathClosestAstroObject == null
? Vector3.zero
: DeathClosestAstroObject.TransformPoint(_deathPositionRelative);
public Vector3 DeathPlayerUpVector { get; private set; }
public Vector3 DeathPlayerForwardVector { get; private set; }
public void Awake() => Instance = this;
@ -41,49 +43,48 @@ namespace QSB.DeathSync
_playerResources = playerTransform.GetComponent<PlayerResources>();
_spaceSuit = Locator.GetPlayerSuit();
_playerSpawner = FindObjectOfType<PlayerSpawner>();
_shipTractorBeam = FindObjectOfType<ShipTractorBeamSwitch>();
_suitPickupVolumes = FindObjectsOfType<SuitPickupVolume>();
_fluidDetector = Locator.GetPlayerCamera().GetComponentInChildren<FluidDetector>();
_playerSpawnPoint = GetSpawnPoint();
_shipSpawnPoint = GetSpawnPoint(true);
var shipTransform = Locator.GetShipTransform();
if (shipTransform == null)
{
DebugLog.ToConsole($"Warning - Init() ran when ship was null?", MessageType.Warning);
return;
}
_shipComponents = shipTransform.GetComponentsInChildren<ShipComponent>();
_hatchController = shipTransform.GetComponentInChildren<HatchController>();
_cockpitController = shipTransform.GetComponentInChildren<ShipCockpitController>();
_shipBody = Locator.GetShipBody();
if (_shipSpawnPoint == null)
{
DebugLog.ToConsole("Warning - _shipSpawnPoint is null in Init()!", MessageType.Warning);
return;
}
// Move debug spawn point to initial ship position (so ship doesnt spawn in space!)
var timberHearth = Locator.GetAstroObject(AstroObject.Name.TimberHearth).transform;
_shipSpawnPoint.transform.SetParent(timberHearth);
_shipSpawnPoint.transform.localPosition = ShipContainerOffset;
_shipSpawnPoint.transform.localRotation = ShipContainerRotation;
}
public void ResetPlayer()
{
DebugLog.DebugWrite($"Trying to reset player.");
DebugLog.DebugWrite($"RESET PLAYER");
if (_playerSpawnPoint == null)
{
DebugLog.ToConsole("Warning - _playerSpawnPoint is null!", MessageType.Warning);
Init();
}
// Cant use _playerSpawner.DebugWarp because that will warp the ship if the player is in it
var deadPlayersCount = QSBPlayerManager.PlayerList.Count(x => x.IsDead);
if (deadPlayersCount == QSBPlayerManager.PlayerList.Count)
{
QSBEventManager.FireEvent(EventNames.QSBEndLoop, EndLoopReason.AllPlayersDead);
return;
}
RespawnManager.Instance.TriggerRespawnMap();
var inSpace = PlayerTransformSync.LocalInstance.SectorSync.SectorList.Count == 0;
if (inSpace)
{
DeathClosestAstroObject = Locator.GetAstroObject(AstroObject.Name.Sun).transform;
}
else
{
var allAstroobjects = Resources.FindObjectsOfTypeAll<AstroObject>().Where(x => x.GetAstroObjectName() != AstroObject.Name.None && x.GetAstroObjectType() != AstroObject.Type.Satellite);
var ordered = allAstroobjects.OrderBy(x => Vector3.SqrMagnitude(x.transform.position));
DeathClosestAstroObject = ordered.First().transform;
}
var deathPosition = Locator.GetPlayerTransform().position;
_deathPositionRelative = DeathClosestAstroObject.InverseTransformPoint(deathPosition);
DeathPlayerUpVector = Locator.GetPlayerTransform().up;
DeathPlayerForwardVector = Locator.GetPlayerTransform().forward;
var playerBody = Locator.GetPlayerBody();
playerBody.WarpToPositionRotation(_playerSpawnPoint.transform.position, _playerSpawnPoint.transform.rotation);
playerBody.SetVelocity(_playerSpawnPoint.GetPointVelocity());
@ -123,49 +124,7 @@ namespace QSB.DeathSync
}
}
public void ResetShip()
{
DebugLog.DebugWrite($"Trying to reset ship.");
if (!ShipTransformSync.LocalInstance.HasAuthority)
{
DebugLog.ToConsole($"Warning - Tried to reset ship when not in control!", MessageType.Warning);
return;
}
if (_shipSpawnPoint == null)
{
DebugLog.ToConsole("Warning - _shipSpawnPoint is null!", MessageType.Warning);
Init();
}
if (_shipBody == null)
{
DebugLog.ToConsole($"Warning - Tried to reset ship, but the ship is null!", MessageType.Warning);
return;
}
_shipBody.SetVelocity(_shipSpawnPoint.GetPointVelocity());
_shipBody.WarpToPositionRotation(_shipSpawnPoint.transform.position, _shipSpawnPoint.transform.rotation);
foreach (var shipComponent in _shipComponents)
{
shipComponent.SetDamaged(false);
}
Invoke(nameof(ExitShip), 0.01f);
}
private void ExitShip()
{
DebugLog.DebugWrite($"Exit ship.");
_cockpitController.Invoke("ExitFlightConsole");
_cockpitController.Invoke("CompleteExitFlightConsole");
_hatchController.SetValue("_isPlayerInShip", false);
_hatchController.Invoke("OpenHatch");
_shipTractorBeam.ActivateTractorBeam();
}
private SpawnPoint GetSpawnPoint(bool isShip = false)
private SpawnPoint GetSpawnPoint()
{
var spawnList = _playerSpawner.GetValue<SpawnPoint[]>("_spawnList");
if (spawnList == null)
@ -176,7 +135,7 @@ namespace QSB.DeathSync
return spawnList.FirstOrDefault(spawnPoint =>
spawnPoint.GetSpawnLocation() == SpawnLocation.TimberHearth
&& spawnPoint.IsShipSpawn() == isShip);
&& spawnPoint.IsShipSpawn() == false);
}
}
}

View File

@ -5,8 +5,6 @@
// Built into Outer Wilds -- don't change unless they change in-game!
public static string TurnOnFlashlight = "TurnOnFlashlight";
public static string TurnOffFlashlight = "TurnOffFlashlight";
public static string LaunchProbe = "LaunchProbe";
public static string RetrieveProbe = "RetrieveProbe";
public static string ProbeLauncherEquipped = "ProbeLauncherEquipped";
public static string ProbeLauncherUnequipped = "ProbeLauncherUnequipped";
public static string EquipSignalscope = "EquipSignalscope";
@ -32,7 +30,7 @@
public static string QSBPlayerDeath = "QSBPlayerDeath";
public static string QSBPlayerJoin = "QSBPlayerJoin";
public static string QSBPlayerReady = "QSBPlayerReady";
public static string QSBPlayerStatesRequest = "QSBPlayerStatesRequest";
public static string QSBRequestStateResync = "QSBPlayerStatesRequest";
public static string QSBServerTime = "QSBServerTime";
public static string QSBStartLift = "QSBStartLift";
public static string QSBGeyserState = "QSBGeyserState";
@ -41,7 +39,7 @@
public static string QSBConversation = "QSBConversation";
public static string QSBConversationStartEnd = "QSBConversationStartEnd";
public static string QSBChangeAnimType = "QSBPlayInstrument";
public static string QSBServerSendPlayerStates = "QSBServerSendPlayerStates";
public static string QSBPlayerInformation = "QSBServerSendPlayerStates";
public static string QSBRevealFact = "QSBRevealFact";
public static string QSBSocketStateChange = "QSBSocketStateChange";
public static string QSBMultiStateChange = "QSBMultiStateChange";
@ -77,5 +75,16 @@
public static string QSBComponentDamaged = "QSBComponentDamaged";
public static string QSBComponentRepaired = "QSBComponentRepaired";
public static string QSBComponentRepairTick = "QSBComponentRepairTick";
public static string QSBPlayerRespawn = "QSBPlayerRespawn";
public static string QSBProbeEvent = "QSBProbeEvent";
public static string QSBProbeStartRetrieve = "QSBProbeStartRetrieve";
public static string QSBRetrieveProbe = "QSBRetrieveProbe";
public static string QSBPlayerRetrieveProbe = "QSBPlayerRetrieveProbe";
public static string QSBLaunchProbe = "QSBLaunchProbe";
public static string QSBPlayerLaunchProbe = "QSBPlayerLaunchProbe";
public static string QSBEndLoop = "QSBEndLoop";
public static string QSBStartLoop = "QSBStartLoop";
public static string QSBServerState = "QSBServerState";
public static string QSBClientState = "QSBClientState";
}
}

View File

@ -2,57 +2,130 @@
{
public enum EventType
{
/*
* SERVER EVENTS
*/
ServerTime,
PlayerState,
PlayerStatesRequest,
FlashlightActiveChange,
SignalscopeActiveChange,
TranslatorActiveChange,
ProbeLauncherActiveChange,
SuitActiveChange,
StartStatue,
EndLoop,
StartLoop,
ServerState,
ClientState,
/*
* PLAYER EVENTS
*/
PlayerInformation,
RequestStateResync,
PlayerJoin,
PlayerDeath,
PlayerReady,
ProbeActiveChange,
Elevator,
Geyser,
OrbSlot,
OrbUser,
PlayerKick,
PlayerRespawn,
EnterLeave,
/*
* DIALOGUE
*/
Conversation,
ConversationStartEnd,
PlayInstrument,
DialogueCondition,
RevealFact,
/*
* ANIMATION
*/
PlayInstrument,
AnimTrigger,
NpcAnimEvent,
SuitActiveChange,
/*
* ORBS
*/
OrbSlot,
OrbUser,
/*
* CAMPFIRES
*/
CampfireState,
Roasting,
MarshmallowEvent,
/*
* WORLD OBJECTS
*/
Geyser,
Elevator,
/*
* ITEMS
*/
DropItem,
SocketItem,
MoveToCarry,
/*
* QUANTUM OBJECTS
*/
SocketStateChange,
MultiStateChange,
QuantumShuffle,
QuantumAuthority,
MoonStateChange,
IdentifyFrequency,
IdentifySignal,
TextTranslated,
EnterLeave,
PlayerEntangle,
DropItem,
SocketItem,
MoveToCarry,
StartStatue,
PlayerKick,
CampfireState,
Roasting,
MarshmallowEvent,
AnimTrigger,
NpcAnimEvent,
FlyShip,
OpenHatch,
EnableFunnel,
/*
* SHIP
*/
ComponentDamaged,
ComponentRepaired,
ComponentRepairTick,
HullImpact,
HullDamaged,
HullChangeIntegrity,
HullRepaired,
HullRepairTick,
ComponentDamaged,
ComponentRepaired,
ComponentRepairTick
FlyShip,
OpenHatch,
EnableFunnel,
/*
* TOOLS
*/
// Flashlight
FlashlightActiveChange,
// Translator
TranslatorActiveChange,
TextTranslated,
// Signalscope
SignalscopeActiveChange,
IdentifyFrequency,
IdentifySignal,
// Probe
ProbeStartRetrieve,
ProbeEvent,
// Probe Launcher
ProbeLauncherActiveChange,
RetrieveProbe,
PlayerRetrieveProbe,
LaunchProbe,
PlayerLaunchProbe
}
}

View File

@ -3,7 +3,6 @@ using QSB.Messaging;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.Utility;
using QuantumUNET;
using QuantumUNET.Components;
namespace QSB.Events
@ -30,8 +29,8 @@ namespace QSB.Events
public abstract void SetupListener();
public abstract void CloseListener();
public virtual void OnReceiveRemote(bool server, T message) { }
public virtual void OnReceiveLocal(bool server, T message) { }
public virtual void OnReceiveRemote(bool isHost, T message) { }
public virtual void OnReceiveLocal(bool isHost, T message) { }
public void SendEvent(T message)
{
@ -53,7 +52,7 @@ namespace QSB.Events
* if <isServer> is true, this message has been received on the server *server*.
* Therefore, we don't want to do any event handling code - that should be dealt
* with on the server *client* and any other client. So just forward the message
* onto all clients. This way, the server *server* just acts as the ditribution
* onto all clients. This way, the server *server* just acts as the distribution
* hub for all events.
*/
@ -68,7 +67,7 @@ namespace QSB.Events
return;
}
if (message.OnlySendToServer && !QNetworkServer.active)
if (message.OnlySendToHost && !QSBCore.IsHost)
{
return;
}
@ -82,11 +81,11 @@ namespace QSB.Events
if (message.FromId == QSBPlayerManager.LocalPlayerId ||
QSBPlayerManager.IsBelongingToLocalPlayer(message.FromId))
{
OnReceiveLocal(QNetworkServer.active, message);
OnReceiveLocal(QSBCore.IsHost, message);
return;
}
OnReceiveRemote(QNetworkServer.active, message);
OnReceiveRemote(QSBCore.IsHost, message);
}
}
}

View File

@ -2,6 +2,7 @@
using QSB.Animation.NPC.Events;
using QSB.Animation.Player.Events;
using QSB.CampfireSync.Events;
using QSB.ClientServerStateSync.Events;
using QSB.ConversationSync.Events;
using QSB.DeathSync.Events;
using QSB.ElevatorSync.Events;
@ -20,6 +21,7 @@ using QSB.ShipSync.Events.Hull;
using QSB.StatueSync.Events;
using QSB.TimeSync.Events;
using QSB.Tools.Events;
using QSB.Tools.ProbeLauncherTool.Events;
using QSB.TranslationSync.Events;
using QSB.Utility;
using System.Collections.Generic;
@ -43,11 +45,11 @@ namespace QSB.Events
new PlayerFlashlightEvent(),
new PlayerSignalscopeEvent(),
new PlayerTranslatorEvent(),
new PlayerProbeLauncherEvent(),
new EquipProbeLauncherEvent(),
new PlayerProbeEvent(),
new PlayerDeathEvent(),
new PlayerStatesRequestEvent(),
new ServerSendPlayerStatesEvent(),
new RequestStateResyncEvent(),
new PlayerInformationEvent(),
new ChangeAnimTypeEvent(),
new ServerTimeEvent(),
new PlayerEntangledEvent(),
@ -55,6 +57,16 @@ namespace QSB.Events
new EnterExitRoastingEvent(),
new MarshmallowEventEvent(),
new AnimationTriggerEvent(),
new PlayerRespawnEvent(),
new ProbeStartRetrieveEvent(),
new RetrieveProbeEvent(),
new LaunchProbeEvent(),
new PlayerRetrieveProbeEvent(),
new PlayerLaunchProbeEvent(),
new EndLoopEvent(),
new StartLoopEvent(),
new ServerStateEvent(),
new ClientStateEvent(),
// World Objects
new ElevatorEvent(),
new GeyserEvent(),

View File

@ -21,7 +21,7 @@ namespace QSB.GeyserSync.Events
State = state
};
public override void OnReceiveRemote(bool server, BoolWorldObjectMessage message)
public override void OnReceiveRemote(bool isHost, BoolWorldObjectMessage message)
{
if (!QSBCore.WorldObjectsReady)
{

View File

@ -2,7 +2,7 @@
namespace QSB.Inputs.Patches
{
class InputPatches : QSBPatch
internal class InputPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;

View File

@ -5,22 +5,34 @@ namespace QSB.Messaging
{
public class PlayerMessage : QMessageBase
{
/// <summary>
/// The Player ID that is sending this message
/// </summary>
public uint FromId { get; set; }
/// <summary>
/// The Player ID that this message is about
/// </summary>
public uint AboutId { get; set; }
public bool OnlySendToServer { get; set; }
/// <summary>
/// If true, only send this message to the host of the current session
/// (OnReceiveLocal/Remote is not called on any other client)
/// </summary>
public bool OnlySendToHost { get; set; }
public override void Deserialize(QNetworkReader reader)
{
FromId = reader.ReadUInt32();
AboutId = reader.ReadUInt32();
OnlySendToServer = reader.ReadBoolean();
OnlySendToHost = reader.ReadBoolean();
}
public override void Serialize(QNetworkWriter writer)
{
writer.Write(FromId);
writer.Write(AboutId);
writer.Write(OnlySendToServer);
writer.Write(OnlySendToHost);
}
}
}

View File

@ -70,7 +70,7 @@ namespace QSB.OrbSync.Events
}
var orbSync = NomaiOrbTransformSync.OrbTransformSyncs
.FirstOrDefault(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].gameObject);
.FirstOrDefault(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].transform);
if (orbSync == null)
{
DebugLog.ToConsole($"Error - No orb found for user event. (ID {message.ObjectId})", MessageType.Error);
@ -107,14 +107,14 @@ namespace QSB.OrbSync.Events
return;
}
if (!NomaiOrbTransformSync.OrbTransformSyncs.Any(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].gameObject))
if (!NomaiOrbTransformSync.OrbTransformSyncs.Any(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].transform))
{
DebugLog.ToConsole($"Error - No NomaiOrbTransformSync has AttachedOrb with objectId {message.ObjectId}!");
return;
}
var orb = NomaiOrbTransformSync.OrbTransformSyncs
.First(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].gameObject);
.First(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].transform);
orb.enabled = true;
}
}

View File

@ -22,7 +22,7 @@ namespace QSB.OrbSync
{
QSBWorldSync.OldOrbList.Clear();
QSBWorldSync.OldOrbList = Resources.FindObjectsOfTypeAll<NomaiInterfaceOrb>().ToList();
if (QSBCore.IsServer)
if (QSBCore.IsHost)
{
NomaiOrbTransformSync.OrbTransformSyncs.ForEach(x => QNetworkServer.Destroy(x.gameObject));
NomaiOrbTransformSync.OrbTransformSyncs.Clear();

View File

@ -1,5 +1,6 @@
using QSB.Events;
using QSB.Patches;
using QSB.Utility;
using QSB.WorldSync;
using UnityEngine;
@ -34,7 +35,7 @@ namespace QSB.OrbSync.Patches
if (Time.timeSinceLevelLoad > 1f)
{
QSBWorldSync.HandleSlotStateChange(__instance, orb, true);
QSBWorldSync.RaiseEvent(__instance, "OnSlotActivated", __instance);
__instance.RaiseEvent("OnSlotActivated", __instance);
}
__result = true;
@ -51,7 +52,7 @@ namespace QSB.OrbSync.Patches
{
QSBWorldSync.HandleSlotStateChange(__instance, orb, false);
____occupyingOrb = null;
QSBWorldSync.RaiseEvent(__instance, "OnSlotDeactivated", __instance);
__instance.RaiseEvent("OnSlotDeactivated", __instance);
__result = false;
return false;
}

View File

@ -23,10 +23,17 @@ namespace QSB.OrbSync.TransformSync
protected override void Init()
{
base.Init();
SetReferenceTransform(AttachedObject.GetAttachedOWRigidbody().GetOrigParent());
var originalParent = AttachedObject.GetAttachedOWRigidbody().GetOrigParent();
if (originalParent == Locator.GetRootTransform())
{
DebugLog.DebugWrite($"{_logName} with AttachedObject {AttachedObject.name} had it's original parent as SolarSystemRoot - Destroying...");
Destroy(this);
}
SetReferenceTransform(originalParent);
}
private GameObject GetTransform()
private Transform GetTransform()
{
if (_index == -1)
{
@ -46,11 +53,11 @@ namespace QSB.OrbSync.TransformSync
return null;
}
return QSBWorldSync.OldOrbList[_index].gameObject;
return QSBWorldSync.OldOrbList[_index].transform;
}
protected override GameObject InitLocalTransform() => GetTransform();
protected override GameObject InitRemoteTransform() => GetTransform();
protected override Component InitLocalTransform() => GetTransform();
protected override Component InitRemoteTransform() => GetTransform();
public override bool IsReady => QSBCore.WorldObjectsReady;
public override bool UseInterpolation => false;

View File

@ -1,5 +1,6 @@
using OWML.Utils;
using QSB.Events;
using QSB.Utility;
using QSB.WorldSync;
namespace QSB.OrbSync.WorldObjects
@ -37,7 +38,7 @@ namespace QSB.OrbSync.WorldObjects
var occOrb = state ? QSBWorldSync.OldOrbList[orbId] : null;
AttachedObject.SetValue("_occupyingOrb", occOrb);
var ev = state ? "OnSlotActivated" : "OnSlotDeactivated";
QSBWorldSync.RaiseEvent(AttachedObject, ev, AttachedObject);
AttachedObject.RaiseEvent(ev, AttachedObject);
Activated = state;
}
}

View File

@ -18,7 +18,7 @@ namespace QSB.Patches
{
foreach (var item in _patchedMethods)
{
DebugLog.DebugWrite($"[Unpatch] {item.DeclaringType}.{item.Name}", MessageType.Info);
//DebugLog.DebugWrite($"[Unpatch] {item.DeclaringType}.{item.Name}", MessageType.Info);
Unpatch(item);
}
@ -29,9 +29,10 @@ namespace QSB.Patches
public void Empty(string patchName)
{
DebugLog.DebugWrite($"[Empty] {patchName}", MessageType.Success);
//DebugLog.DebugWrite($"[Empty] {patchName}", MessageType.Success);
var method = GetMethodInfo(patchName);
QSBCore.Helper.HarmonyHelper.EmptyMethod(method);
_patchedMethods.Add(method);
}
public void Prefix(string patchName)
@ -58,7 +59,7 @@ namespace QSB.Patches
_patchedMethods.Add(method);
}
DebugLog.DebugWrite($"{(isPrefix ? "[Prefix]" : "[Postfix]")} {patchName}", method == null ? MessageType.Error : MessageType.Success);
//DebugLog.DebugWrite($"{(isPrefix ? "[Prefix]" : "[Postfix]")} {patchName}", method == null ? MessageType.Error : MessageType.Success);
}
private MethodInfo GetMethodInfo(string patchName)
@ -103,7 +104,7 @@ namespace QSB.Patches
{
var dictionary = typeof(HarmonySharedState).Invoke<Dictionary<MethodBase, byte[]>>("GetState", new object[0]);
var methodBase = dictionary.Keys.First(m =>
m.DeclaringType == method.DeclaringType
m.DeclaringType == method.DeclaringType
&& m.Name == method.Name);
var patchInfo = PatchInfoSerialization.Deserialize(dictionary.GetValueSafe(methodBase));

View File

@ -18,6 +18,7 @@ using QSB.RoastingSync.Patches;
using QSB.ShipSync.Patches;
using QSB.StatueSync.Patches;
using QSB.TimeSync.Patches;
using QSB.Tools.ProbeLauncherTool.Patches;
using QSB.TranslationSync.Patches;
using QSB.Utility;
using System;
@ -59,7 +60,10 @@ namespace QSB.Patches
new CharacterAnimationPatches(),
new ShipPatches(),
new InputPatches(),
new TimePatches()
new TimePatches(),
new MapPatches(),
new RespawnPatches(),
new LauncherPatches()
};
DebugLog.DebugWrite("Patch Manager ready.", MessageType.Success);
@ -68,10 +72,10 @@ namespace QSB.Patches
public static void DoPatchType(QSBPatchTypes type)
{
OnPatchType?.SafeInvoke(type);
DebugLog.DebugWrite($"Patch block {Enum.GetName(typeof(QSBPatchTypes), type)}", MessageType.Info);
//DebugLog.DebugWrite($"Patch block {Enum.GetName(typeof(QSBPatchTypes), type)}", MessageType.Info);
foreach (var patch in _patchList.Where(x => x.Type == type))
{
DebugLog.DebugWrite($" - Patching in {patch.GetType().Name}", MessageType.Info);
//DebugLog.DebugWrite($" - Patching in {patch.GetType().Name}", MessageType.Info);
patch.DoPatches();
}
}
@ -79,10 +83,10 @@ namespace QSB.Patches
public static void DoUnpatchType(QSBPatchTypes type)
{
OnUnpatchType?.SafeInvoke(type);
DebugLog.DebugWrite($"Unpatch block {Enum.GetName(typeof(QSBPatchTypes), type)}", MessageType.Info);
//DebugLog.DebugWrite($"Unpatch block {Enum.GetName(typeof(QSBPatchTypes), type)}", MessageType.Info);
foreach (var patch in _patchList.Where(x => x.Type == type))
{
DebugLog.DebugWrite($" - Unpatching in {patch.GetType().Name}", MessageType.Info);
//DebugLog.DebugWrite($" - Unpatching in {patch.GetType().Name}", MessageType.Info);
patch.DoUnpatches();
}
}

View File

@ -4,6 +4,7 @@
{
OnClientConnect = 0,
OnNonServerClientConnect = 1,
OnServerClientConnect = 2
OnServerClientConnect = 2,
RespawnTime = 3
}
}

View File

@ -0,0 +1,37 @@
using OWML.Common;
using QSB.Events;
using QSB.Utility;
namespace QSB.Player.Events
{
public class PlayerInformationEvent : QSBEvent<PlayerInformationMessage>
{
public override EventType Type => EventType.PlayerInformation;
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBPlayerInformation, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBPlayerInformation, Handler);
private void Handler() => SendEvent(CreateMessage(QSBPlayerManager.LocalPlayer));
private PlayerInformationMessage CreateMessage(PlayerInfo player) => new PlayerInformationMessage
{
AboutId = player.PlayerId,
PlayerName = player.Name,
PlayerState = player.PlayerStates,
ClientState = player.State
};
public override void OnReceiveRemote(bool server, PlayerInformationMessage message)
{
DebugLog.DebugWrite($"Received playerstate of player ID {message.AboutId}", MessageType.Info);
if (QSBPlayerManager.PlayerExists(message.AboutId))
{
QSBPlayerManager.HandleFullStateMessage(message);
}
else
{
DebugLog.ToConsole($"Warning - got player information message about player that doesnt exist!", MessageType.Warning);
}
}
}
}

View File

@ -1,12 +1,14 @@
using QSB.Messaging;
using QSB.ClientServerStateSync;
using QSB.Messaging;
using QuantumUNET.Transport;
namespace QSB.Player.Events
{
public class PlayerStateMessage : PlayerMessage
public class PlayerInformationMessage : PlayerMessage
{
public string PlayerName { get; set; }
public PlayerState PlayerState { get; set; }
public ClientState ClientState { get; set; }
public override void Deserialize(QNetworkReader reader)
{
@ -22,6 +24,7 @@ namespace QSB.Player.Events
TranslatorEquipped = reader.ReadBoolean(),
ProbeActive = reader.ReadBoolean()
};
ClientState = (ClientState)reader.ReadInt32();
}
public override void Serialize(QNetworkWriter writer)
@ -35,6 +38,7 @@ namespace QSB.Player.Events
writer.Write(PlayerState.SignalscopeEquipped);
writer.Write(PlayerState.TranslatorEquipped);
writer.Write(PlayerState.ProbeActive);
writer.Write((int)ClientState);
}
}
}
}

View File

@ -41,6 +41,12 @@ namespace QSB.Player.Events
player.Name = message.PlayerName;
var text = $"Connected to server as {player.Name}.";
DebugLog.ToAll(text, MessageType.Info);
if (QSBSceneManager.IsInUniverse)
{
QSBPlayerManager.LocalPlayer.PlayerStates.IsReady = true;
QSBEventManager.FireEvent(EventNames.QSBPlayerReady, true);
}
}
}
}

View File

@ -34,14 +34,14 @@ namespace QSB.Player.Events
private static void HandleServer(ToggleMessage message)
{
DebugLog.DebugWrite($"Get ready event from {message.FromId}", MessageType.Success);
DebugLog.DebugWrite($"[SERVER] Get ready event from {message.FromId}", MessageType.Success);
QSBPlayerManager.GetPlayer(message.AboutId).PlayerStates.IsReady = message.ToggleValue;
QSBEventManager.FireEvent(EventNames.QSBServerSendPlayerStates);
QSBEventManager.FireEvent(EventNames.QSBPlayerInformation);
}
private void HandleClient(ToggleMessage message)
{
DebugLog.DebugWrite($"Get ready event from {message.FromId}", MessageType.Success);
DebugLog.DebugWrite($"[CLIENT] Get ready event from {message.FromId}", MessageType.Success);
if (!QSBPlayerManager.PlayerExists(message.FromId))
{
DebugLog.ToConsole(

View File

@ -1,87 +0,0 @@
using OWML.Utils;
using QSB.CampfireSync.WorldObjects;
using QSB.Events;
using QSB.Messaging;
using QSB.QuantumSync;
using QSB.TranslationSync;
using QSB.TranslationSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
namespace QSB.Player.Events
{
public class PlayerStatesRequestEvent : QSBEvent<PlayerMessage>
{
public override EventType Type => EventType.PlayerStatesRequest;
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBPlayerStatesRequest, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBPlayerStatesRequest, Handler);
private void Handler() => SendEvent(CreateMessage());
private PlayerMessage CreateMessage() => new PlayerMessage
{
AboutId = LocalPlayerId,
OnlySendToServer = true
};
public override void OnReceiveRemote(bool server, PlayerMessage message)
{
DebugLog.DebugWrite($"Get state request from {message.FromId} - isServer?{server}");
QSBEventManager.FireEvent(EventNames.QSBServerSendPlayerStates);
if (!server)
{
return;
}
// TODO : CLEAN. THIS. SHIT.
foreach (var condition in QSBWorldSync.DialogueConditions)
{
QSBEventManager.FireEvent(EventNames.DialogueCondition, condition.Key, condition.Value);
}
foreach (var fact in QSBWorldSync.ShipLogFacts)
{
QSBEventManager.FireEvent(EventNames.QSBRevealFact, fact.Id, fact.SaveGame, false);
}
foreach (var wallText in QSBWorldSync.GetWorldObjects<QSBWallText>().Where(x => x.AttachedObject.GetValue<bool>("_initialized") && x.AttachedObject.GetNumTextBlocks() > 0))
{
foreach (var id in wallText.GetTranslatedIds())
{
QSBEventManager.FireEvent(EventNames.QSBTextTranslated, NomaiTextType.WallText, wallText.ObjectId, id);
}
}
foreach (var computer in QSBWorldSync.GetWorldObjects<QSBComputer>().Where(x => x.AttachedObject.GetValue<bool>("_initialized") && x.AttachedObject.GetNumTextBlocks() > 0))
{
foreach (var id in computer.GetTranslatedIds())
{
QSBEventManager.FireEvent(EventNames.QSBTextTranslated, NomaiTextType.Computer, computer.ObjectId, id);
}
}
foreach (var vesselComputer in QSBWorldSync.GetWorldObjects<QSBVesselComputer>().Where(x => x.AttachedObject.GetValue<bool>("_initialized") && x.AttachedObject.GetNumTextBlocks() > 0))
{
foreach (var id in vesselComputer.GetTranslatedIds())
{
QSBEventManager.FireEvent(EventNames.QSBTextTranslated, NomaiTextType.VesselComputer, vesselComputer.ObjectId, id);
}
}
var list = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>().ToList();
for (var i = 0; i < list.Count; i++)
{
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, i, list[i].ControllingPlayer);
}
foreach (var campfire in QSBWorldSync.GetWorldObjects<QSBCampfire>())
{
QSBEventManager.FireEvent(EventNames.QSBCampfireState, campfire.ObjectId, campfire.GetState());
}
}
}
}

View File

@ -0,0 +1,97 @@
using OWML.Utils;
using QSB.CampfireSync.WorldObjects;
using QSB.ClientServerStateSync;
using QSB.Events;
using QSB.Messaging;
using QSB.QuantumSync;
using QSB.TranslationSync;
using QSB.TranslationSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
namespace QSB.Player.Events
{
// Can be sent by any client (including host) to signal they want latest worldobject, player, and server infomation
public class RequestStateResyncEvent : QSBEvent<PlayerMessage>
{
public override EventType Type => EventType.RequestStateResync;
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBRequestStateResync, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBRequestStateResync, Handler);
private void Handler()
{
DebugLog.DebugWrite($"Sending QSBRequestStateResync");
SendEvent(CreateMessage());
}
private PlayerMessage CreateMessage() => new PlayerMessage
{
AboutId = LocalPlayerId
};
public override void OnReceiveRemote(bool isHost, PlayerMessage message)
{
DebugLog.DebugWrite($"OnReceiveRemote RequestStateResyncEvent");
// if host, send worldobject and server states
if (isHost)
{
DebugLog.DebugWrite($"SENDING SERVER STATE");
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerStateManager.Instance.GetServerState());
DebugLog.DebugWrite($"SENDING PLAYER INFORMATION");
QSBEventManager.FireEvent(EventNames.QSBPlayerInformation);
SendWorldObjectInfo();
return;
}
// if client, send player and client states
DebugLog.DebugWrite($"SENDING PLAYER INFORMATION");
QSBEventManager.FireEvent(EventNames.QSBPlayerInformation);
}
private void SendWorldObjectInfo()
{
DebugLog.DebugWrite($"SENDING WORLDOBJECT INFORMATION");
QSBWorldSync.DialogueConditions.ForEach(condition
=> QSBEventManager.FireEvent(EventNames.DialogueCondition, condition.Key, condition.Value));
QSBWorldSync.ShipLogFacts.ForEach(fact
=> QSBEventManager.FireEvent(EventNames.QSBRevealFact, fact.Id, fact.SaveGame, false));
foreach (var wallText in QSBWorldSync.GetWorldObjects<QSBWallText>().Where(x => x.AttachedObject.GetValue<bool>("_initialized") && x.AttachedObject.GetNumTextBlocks() > 0))
{
wallText.GetTranslatedIds().ForEach(id
=> QSBEventManager.FireEvent(EventNames.QSBTextTranslated, NomaiTextType.WallText, wallText.ObjectId, id));
}
foreach (var computer in QSBWorldSync.GetWorldObjects<QSBComputer>().Where(x => x.AttachedObject.GetValue<bool>("_initialized") && x.AttachedObject.GetNumTextBlocks() > 0))
{
computer.GetTranslatedIds().ForEach(id
=> QSBEventManager.FireEvent(EventNames.QSBTextTranslated, NomaiTextType.Computer, computer.ObjectId, id));
}
foreach (var vesselComputer in QSBWorldSync.GetWorldObjects<QSBVesselComputer>().Where(x => x.AttachedObject.GetValue<bool>("_initialized") && x.AttachedObject.GetNumTextBlocks() > 0))
{
vesselComputer.GetTranslatedIds().ForEach(id
=> QSBEventManager.FireEvent(EventNames.QSBTextTranslated, NomaiTextType.VesselComputer, vesselComputer.ObjectId, id));
}
var list = QSBWorldSync.GetWorldObjects<IQSBQuantumObject>().ToList();
for (var i = 0; i < list.Count; i++)
{
QSBEventManager.FireEvent(EventNames.QSBQuantumAuthority, i, list[i].ControllingPlayer);
}
QSBWorldSync.GetWorldObjects<QSBCampfire>().ForEach(campfire
=> QSBEventManager.FireEvent(EventNames.QSBCampfireState, campfire.ObjectId, campfire.GetState()));
}
}
}

View File

@ -1,39 +0,0 @@
using OWML.Common;
using QSB.Events;
using QSB.Utility;
namespace QSB.Player.Events
{
public class ServerSendPlayerStatesEvent : QSBEvent<PlayerStateMessage>
{
public override EventType Type => EventType.PlayerState;
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBServerSendPlayerStates, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBServerSendPlayerStates, Handler);
private void Handler()
{
foreach (var player in QSBPlayerManager.PlayerList)
{
DebugLog.DebugWrite($" - Sending playerstate of player ID {player.PlayerId}", MessageType.Info);
SendEvent(CreateMessage(player));
}
}
private PlayerStateMessage CreateMessage(PlayerInfo player) => new PlayerStateMessage
{
AboutId = player.PlayerId,
PlayerName = player.Name,
PlayerState = player.PlayerStates
};
public override void OnReceiveRemote(bool server, PlayerStateMessage message)
{
DebugLog.DebugWrite($"Received playerstate of player ID {message.AboutId}", MessageType.Info);
if (QSBPlayerManager.PlayerExists(message.AboutId))
{
QSBPlayerManager.HandleFullStateMessage(message);
}
}
}
}

View File

@ -1,10 +1,12 @@
using UnityEngine;
using QSB.Utility;
using UnityEngine;
namespace QSB.Player
{
public class PlayerHUDMarker : HUDDistanceMarker
{
private PlayerInfo _player;
private bool _needsInitializing;
private bool _isReady;
protected override void InitCanvasMarker()
@ -19,34 +21,57 @@ namespace QSB.Player
public void Init(PlayerInfo player)
{
DebugLog.DebugWrite($"Init {player.PlayerId} name:{player.Name}");
_player = player;
_player.HudMarker = this;
_isReady = true;
}
protected override void RefreshOwnVisibility()
{
if (_canvasMarker != null)
{
_canvasMarker.SetVisibility(true);
}
_needsInitializing = true;
}
private void Update()
{
if (_needsInitializing)
{
Initialize();
}
if (!_isReady || !_player.PlayerStates.IsReady)
{
return;
}
if (_canvasMarker != null)
{
var isVisible = _canvasMarker.IsVisible();
if (_player.Visible != isVisible)
{
_canvasMarker.SetVisibility(_player.Visible);
}
}
else
{
DebugLog.DebugWrite($"Warning - _canvasMarker for {_player.PlayerId} is null!", OWML.Common.MessageType.Warning);
}
}
private void Initialize()
{
if (_player.Name == null)
{
DebugLog.ToConsole($"Error - {_player.PlayerId} has a null name!", OWML.Common.MessageType.Error);
_player.Name = "NULL";
}
_markerLabel = _player.Name.ToUpper();
_isReady = false;
_needsInitializing = false;
_isReady = true;
base.InitCanvasMarker();
}
public void Remove()
{
_isReady = false;
// do N O T destroy the parent - it completely breaks the ENTIRE GAME
if (_canvasMarker != null)
{

View File

@ -1,11 +1,14 @@
using QSB.Animation.Player;
using QSB.Animation.Player.Thrusters;
using QSB.CampfireSync.WorldObjects;
using QSB.ClientServerStateSync;
using QSB.Player.TransformSync;
using QSB.ProbeSync;
using QSB.QuantumSync;
using QSB.RoastingSync;
using QSB.Tools;
using QSB.Tools.ProbeLauncherTool;
using QSB.Utility;
using System.Linq;
using UnityEngine;
@ -24,19 +27,31 @@ namespace QSB.Player
public GameObject CameraBody { get; set; }
public GameObject Body { get; set; }
public GameObject RoastingStick { get; set; }
public bool Visible { get; set; } = true;
// Tools
public GameObject ProbeBody { get; set; }
public QSBProbe Probe { get; set; }
public QSBFlashlight FlashLight => CameraBody?.GetComponentInChildren<QSBFlashlight>();
public QSBFlashlight FlashLight
{
get
{
if (CameraBody == null)
{
return null;
}
return CameraBody.GetComponentInChildren<QSBFlashlight>();
}
}
public QSBTool Signalscope => GetToolByType(ToolType.Signalscope);
public QSBTool Translator => GetToolByType(ToolType.Translator);
public QSBTool ProbeLauncher => GetToolByType(ToolType.ProbeLauncher);
public Transform ItemSocket => CameraBody.transform.Find("ItemSocket");
public Transform ScrollSocket => CameraBody.transform.Find("ScrollSocket");
public Transform SharedStoneSocket => CameraBody.transform.Find("SharedStoneSocket");
public Transform WarpCoreSocket => CameraBody.transform.Find("WarpCoreSocket");
public Transform VesselCoreSocket => CameraBody.transform.Find("VesselCoreSocket");
public QSBProbeLauncherTool ProbeLauncher => (QSBProbeLauncherTool)GetToolByType(ToolType.ProbeLauncher);
public Transform ItemSocket => CameraBody.transform.Find("REMOTE_ItemSocket");
public Transform ScrollSocket => CameraBody.transform.Find("REMOTE_ScrollSocket");
public Transform SharedStoneSocket => CameraBody.transform.Find("REMOTE_SharedStoneSocket");
public Transform WarpCoreSocket => CameraBody.transform.Find("REMOTE_WarpCoreSocket");
public Transform VesselCoreSocket => CameraBody.transform.Find("REMOTE_VesselCoreSocket");
public QSBMarshmallow Marshmallow { get; set; }
public QSBCampfire Campfire { get; set; }
@ -54,6 +69,66 @@ namespace QSB.Player
public bool IsInMoon; // TODO : move into PlayerStates?
public bool IsInShrine; // TODO : move into PlayerStates?
public IQSBQuantumObject EntangledObject;
public bool IsDead { get; set; }
public ClientState State { get; set; }
// Local only
public PlayerProbeLauncher LocalProbeLauncher
{
get
{
if (QSBPlayerManager.LocalPlayer != this)
{
DebugLog.ToConsole($"Warning - Tried to access local-only property LocalProbeLauncher in PlayerInfo for non local player!", OWML.Common.MessageType.Warning);
return null;
}
return CameraBody.transform.Find("ProbeLauncher").GetComponent<PlayerProbeLauncher>();
}
}
public Flashlight LocalFlashlight
{
get
{
if (QSBPlayerManager.LocalPlayer != this)
{
DebugLog.ToConsole($"Warning - Tried to access local-only property LocalFlashlight in PlayerInfo for non local player!", OWML.Common.MessageType.Warning);
return null;
}
return Locator.GetFlashlight();
}
}
public Signalscope LocalSignalscope
{
get
{
if (QSBPlayerManager.LocalPlayer != this)
{
DebugLog.ToConsole($"Warning - Tried to access local-only property LocalSignalscope in PlayerInfo for non local player!", OWML.Common.MessageType.Warning);
return null;
}
return CameraBody.transform.Find("Signalscope").GetComponent<Signalscope>();
}
}
public NomaiTranslator LocalTranslator
{
get
{
if (QSBPlayerManager.LocalPlayer != this)
{
DebugLog.ToConsole($"Warning - Tried to access local-only property LocalTranslator in PlayerInfo for non local player!", OWML.Common.MessageType.Warning);
return null;
}
return CameraBody.transform.Find("NomaiTranslatorProp").GetComponent<NomaiTranslator>();
}
}
public PlayerInfo(uint id)
{
@ -76,10 +151,7 @@ namespace QSB.Player
() => QSBPlayerManager.GetSyncObject<AnimationSync>(PlayerId).SetSuitState(PlayerStates.SuitedUp));
}
private QSBTool GetToolByType(ToolType type)
{
return CameraBody?.GetComponentsInChildren<QSBTool>()
private QSBTool GetToolByType(ToolType type) => CameraBody?.GetComponentsInChildren<QSBTool>()
.FirstOrDefault(x => x.Type == type);
}
}
}

View File

@ -5,7 +5,6 @@ using QSB.Tools;
using QSB.Utility;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEngine;
@ -20,9 +19,8 @@ namespace QSB.Player
var localInstance = PlayerTransformSync.LocalInstance;
if (localInstance == null)
{
var method = new StackTrace().GetFrame(1).GetMethod();
DebugLog.ToConsole($"Error - Trying to get LocalPlayerId when the local PlayerTransformSync instance is null." +
$"{Environment.NewLine} Called from {method.DeclaringType.Name}.{method.Name} ", MessageType.Error);
$"{Environment.NewLine} Stacktrace : {Environment.StackTrace} ", MessageType.Error);
return uint.MaxValue;
}
@ -47,9 +45,8 @@ namespace QSB.Player
{
if (!QSBNetworkManager.Instance.IsReady)
{
var method = new StackTrace().GetFrame(1).GetMethod();
DebugLog.ToConsole($"Warning - GetPlayer() (id<{id}>) called when Network Manager not ready! Is a Player Sync Object still active? " +
$"{Environment.NewLine} Called from {method.DeclaringType.Name}.{method.Name}", MessageType.Warning);
$"{Environment.NewLine} Stacktrace :\r\n{Environment.StackTrace}", MessageType.Warning);
}
if (id == uint.MaxValue || id == 0U)
@ -63,8 +60,13 @@ namespace QSB.Player
return player;
}
var trace = new StackTrace().GetFrame(1).GetMethod();
DebugLog.DebugWrite($"Create Player : id<{id}> (Called from {trace.DeclaringType.Name}.{trace.Name})", MessageType.Info);
if (!QSBCore.IsInMultiplayer)
{
DebugLog.ToConsole($"Error - Tried to create player id:{id} when not in multiplayer! Stacktrace : {Environment.StackTrace}", MessageType.Error);
return default;
}
DebugLog.DebugWrite($"Create Player : id<{id}> Stacktrace :\r\n{Environment.StackTrace}", MessageType.Info);
player = new PlayerInfo(id);
PlayerList.Add(player);
return player;
@ -72,16 +74,16 @@ namespace QSB.Player
public static void RemovePlayer(uint id)
{
var trace = new StackTrace().GetFrame(1).GetMethod();
DebugLog.DebugWrite($"Remove Player : id<{id}> (Called from {trace.DeclaringType.Name}.{trace.Name})", MessageType.Info);
DebugLog.DebugWrite($"Remove Player : id<{id}> Stacktrace :\r\n{Environment.StackTrace}", MessageType.Info);
PlayerList.RemoveAll(x => x.PlayerId == id);
}
public static bool PlayerExists(uint id) =>
id != uint.MaxValue && PlayerList.Any(x => x.PlayerId == id);
public static void HandleFullStateMessage(PlayerStateMessage message)
public static void HandleFullStateMessage(PlayerInformationMessage message)
{
DebugLog.DebugWrite($"Handle full state message of {message.AboutId}");
var player = GetPlayer(message.AboutId);
player.Name = message.PlayerName;
player.PlayerStates = message.PlayerState;
@ -89,6 +91,7 @@ namespace QSB.Player
{
player.UpdateStateObjects();
}
player.State = message.ClientState;
}
public static IEnumerable<T> GetSyncObjects<T>() where T : PlayerSyncObject =>
@ -101,11 +104,8 @@ namespace QSB.Player
public static void RemoveSyncObject(PlayerSyncObject obj) => PlayerSyncObjects.Remove(obj);
public static bool IsBelongingToLocalPlayer(uint id)
{
return id == LocalPlayerId ||
public static bool IsBelongingToLocalPlayer(uint id) => id == LocalPlayerId ||
PlayerSyncObjects.Any(x => x != null && x.AttachedNetId == id && x.IsLocalPlayer);
}
public static List<PlayerInfo> GetPlayersWithCameras(bool includeLocalCamera = true)
{
@ -142,20 +142,19 @@ namespace QSB.Player
{
renderer.enabled = visible;
}
player.Visible = visible;
}
public static PlayerInfo GetClosestPlayerToWorldPoint(Vector3 worldPoint, bool includeLocalPlayer)
{
return includeLocalPlayer
public static PlayerInfo GetClosestPlayerToWorldPoint(Vector3 worldPoint, bool includeLocalPlayer) => includeLocalPlayer
? GetClosestPlayerToWorldPoint(PlayerList, worldPoint)
: GetClosestPlayerToWorldPoint(PlayerList.Where(x => x != LocalPlayer).ToList(), worldPoint);
}
public static PlayerInfo GetClosestPlayerToWorldPoint(List<PlayerInfo> playerList, Vector3 worldPoint)
{
if (playerList.Count == 0)
{
DebugLog.DebugWrite($"Error - Cannot get closest player from empty player list.", MessageType.Error);
DebugLog.ToConsole($"Error - Cannot get closest player from empty player list.", MessageType.Error);
return null;
}

View File

@ -1,56 +0,0 @@
using QSB.Events;
using QSB.SectorSync;
using QSB.Syncs.TransformSync;
using QSB.Tools;
using QSB.Utility;
using UnityEngine;
namespace QSB.Player.TransformSync
{
public class PlayerCameraSync : SectoredTransformSync
{
protected override Transform InitLocalTransform()
{
SectorSync.Init(Locator.GetPlayerSectorDetector(), this);
var body = Locator.GetPlayerCamera().gameObject.transform;
Player.Camera = Locator.GetPlayerCamera();
Player.CameraBody = body.gameObject;
Player.PlayerStates.IsReady = true;
QSBEventManager.FireEvent(EventNames.QSBPlayerReady, true);
DebugLog.DebugWrite("PlayerCameraSync init done - Request state!");
QSBEventManager.FireEvent(EventNames.QSBPlayerStatesRequest);
return body;
}
protected override Transform InitRemoteTransform()
{
var body = new GameObject("RemotePlayerCamera");
PlayerToolsManager.Init(body.transform);
var camera = body.AddComponent<Camera>();
camera.enabled = false;
var owcamera = body.AddComponent<OWCamera>();
owcamera.fieldOfView = 70;
owcamera.nearClipPlane = 0.1f;
owcamera.farClipPlane = 50000f;
Player.Camera = owcamera;
Player.CameraBody = body;
return body.transform;
}
public override bool IsReady => Locator.GetPlayerTransform() != null
&& Player != null
&& QSBPlayerManager.PlayerExists(Player.PlayerId)
&& NetId.Value != uint.MaxValue
&& NetId.Value != 0U;
public override bool UseInterpolation => true;
public override TargetType Type => TargetType.PlayerCamera;
}
}

View File

@ -1,7 +1,14 @@
using QSB.Animation.Player;
using OWML.Utils;
using QSB.Animation.Player;
using QSB.Events;
using QSB.Instruments;
using QSB.RoastingSync;
using QSB.SectorSync;
using QSB.Syncs.TransformSync;
using QSB.Tools;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
using UnityEngine;
namespace QSB.Player.TransformSync
@ -10,6 +17,31 @@ namespace QSB.Player.TransformSync
{
static PlayerTransformSync() => AnimControllerPatch.Init();
private Transform _visibleCameraRoot;
private Transform _networkCameraRoot => gameObject.transform.GetChild(0);
private Transform _visibleRoastingSystem;
private Transform _networkRoastingSystem => gameObject.transform.GetChild(1);
private Transform _networkStickRoot => _networkRoastingSystem.GetChild(0);
private Transform _visibleStickPivot;
private Transform _networkStickPivot => _networkStickRoot.GetChild(0);
private Transform _visibleStickTip;
private Transform _networkStickTip => _networkStickPivot.GetChild(0);
protected Vector3 _cameraPositionVelocity;
protected Quaternion _cameraRotationVelocity;
protected Vector3 _pivotPositionVelocity;
protected Quaternion _pivotRotationVelocity;
protected Vector3 _tipPositionVelocity;
protected Quaternion _tipRotationVelocity;
protected Vector3 _roastingPositionVelocity;
protected Quaternion _roastingRotationVelocity;
private Transform GetStickPivot()
=> Resources.FindObjectsOfTypeAll<RoastingStickController>().First().transform.Find("Stick_Root/Stick_Pivot");
public override void OnStartLocalPlayer()
=> LocalInstance = this;
@ -19,8 +51,30 @@ namespace QSB.Player.TransformSync
Player.TransformSync = this;
}
protected override void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool isInUniverse)
{
if (!HasAuthority)
{
base.OnSceneLoaded(oldScene, newScene, isInUniverse);
}
if (isInUniverse)
{
Player.PlayerStates.IsReady = true;
QSBEventManager.FireEvent(EventNames.QSBPlayerReady, true);
}
else
{
Player.PlayerStates.IsReady = false;
QSBEventManager.FireEvent(EventNames.QSBPlayerReady, false);
}
base.OnSceneLoaded(oldScene, newScene, isInUniverse);
}
protected override void OnDestroy()
{
// TODO : Maybe move this to a leave event...? Would ensure everything could finish up before removing the player
QSBPlayerManager.OnRemovePlayer?.Invoke(PlayerId);
base.OnDestroy();
if (QSBPlayerManager.PlayerExists(PlayerId))
@ -30,44 +84,193 @@ namespace QSB.Player.TransformSync
}
}
private Transform GetPlayerModel() =>
Locator.GetPlayerTransform().Find("Traveller_HEA_Player_v2");
protected override Transform InitLocalTransform()
protected override Component InitLocalTransform()
{
SectorSync.Init(Locator.GetPlayerSectorDetector(), this);
var body = GetPlayerModel();
QSBCore.UnityEvents.RunWhen(() => WorldObjectManager.AllReady, () => SectorSync.Init(Locator.GetPlayerSectorDetector(), this));
GetComponent<AnimationSync>().InitLocal(body);
GetComponent<InstrumentsManager>().InitLocal(body);
// player body
var player = Locator.GetPlayerTransform();
var playerModel = player.Find("Traveller_HEA_Player_v2");
GetComponent<AnimationSync>().InitLocal(playerModel);
GetComponent<InstrumentsManager>().InitLocal(player);
Player.Body = player.gameObject;
Player.Body = body.gameObject;
// camera
var cameraBody = Locator.GetPlayerCamera().gameObject.transform;
Player.Camera = Locator.GetPlayerCamera();
Player.CameraBody = cameraBody.gameObject;
_visibleCameraRoot = cameraBody;
return body;
// stick
var pivot = GetStickPivot();
Player.RoastingStick = pivot.parent.gameObject;
_visibleRoastingSystem = pivot.parent.parent;
_visibleStickPivot = pivot;
_visibleStickTip = pivot.Find("Stick_Tip");
DebugLog.DebugWrite("PlayerTransformSync init done - Request state!");
QSBEventManager.FireEvent(EventNames.QSBRequestStateResync);
return player;
}
protected override Transform InitRemoteTransform()
protected override Component InitRemoteTransform()
{
var body = Instantiate(GetPlayerModel());
Player.Body = body.gameObject;
/*
* CREATE PLAYER STRUCTURE
*/
GetComponent<AnimationSync>().InitRemote(body);
GetComponent<InstrumentsManager>().InitRemote(body);
// Variable naming convention is broken here to reflect OW unity project (with REMOTE_ prefixed) for readability
var marker = body.gameObject.AddComponent<PlayerHUDMarker>();
var REMOTE_Player_Body = new GameObject("REMOTE_Player_Body");
var REMOTE_PlayerCamera = new GameObject("REMOTE_PlayerCamera");
REMOTE_PlayerCamera.transform.parent = REMOTE_Player_Body.transform;
REMOTE_PlayerCamera.transform.localPosition = new Vector3(0f, 0.8496093f, 0.1500003f);
var REMOTE_RoastingSystem = new GameObject("REMOTE_RoastingSystem");
REMOTE_RoastingSystem.transform.parent = REMOTE_Player_Body.transform;
REMOTE_RoastingSystem.transform.localPosition = new Vector3(0f, 0.4f, 0f);
var REMOTE_Stick_Root = new GameObject("REMOTE_Stick_Root");
REMOTE_Stick_Root.transform.parent = REMOTE_RoastingSystem.transform;
REMOTE_Stick_Root.transform.localPosition = new Vector3(0.25f, 0f, 0.08f);
REMOTE_Stick_Root.transform.localRotation = Quaternion.Euler(0f, -10f, 0f);
/*
* SET UP PLAYER BODY
*/
var player = Locator.GetPlayerTransform();
var playerModel = player.Find("Traveller_HEA_Player_v2");
var REMOTE_Traveller_HEA_Player_v2 = Instantiate(playerModel);
REMOTE_Traveller_HEA_Player_v2.transform.parent = REMOTE_Player_Body.transform;
REMOTE_Traveller_HEA_Player_v2.transform.localPosition = new Vector3(0f, -1.03f, -0.2f);
REMOTE_Traveller_HEA_Player_v2.transform.localRotation = Quaternion.Euler(-1.500009f, 0f, 0f);
REMOTE_Traveller_HEA_Player_v2.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
Player.Body = REMOTE_Player_Body;
GetComponent<AnimationSync>().InitRemote(REMOTE_Traveller_HEA_Player_v2);
GetComponent<InstrumentsManager>().InitRemote(REMOTE_Player_Body.transform);
var marker = REMOTE_Player_Body.AddComponent<PlayerHUDMarker>();
marker.Init(Player);
body.gameObject.AddComponent<PlayerMapMarker>().PlayerName = Player.Name;
REMOTE_Player_Body.AddComponent<PlayerMapMarker>().PlayerName = Player.Name;
return body;
/*
* SET UP PLAYER CAMERA
*/
PlayerToolsManager.Init(REMOTE_PlayerCamera.transform);
var camera = REMOTE_PlayerCamera.AddComponent<Camera>();
camera.enabled = false;
var owcamera = REMOTE_PlayerCamera.AddComponent<OWCamera>();
owcamera.fieldOfView = 70;
owcamera.nearClipPlane = 0.1f;
owcamera.farClipPlane = 50000f;
Player.Camera = owcamera;
Player.CameraBody = REMOTE_PlayerCamera;
_visibleCameraRoot = REMOTE_PlayerCamera.transform;
/*
* SET UP ROASTING STICK
*/
var REMOTE_Stick_Pivot = Instantiate(GetStickPivot());
REMOTE_Stick_Pivot.name = "REMOTE_Stick_Pivot";
REMOTE_Stick_Pivot.parent = REMOTE_Stick_Root.transform;
REMOTE_Stick_Pivot.gameObject.SetActive(false);
Destroy(REMOTE_Stick_Pivot.Find("Stick_Tip/Props_HEA_RoastingStick/RoastingStick_Arm").gameObject);
Destroy(REMOTE_Stick_Pivot.Find("Stick_Tip/Props_HEA_RoastingStick/RoastingStick_Arm_NoSuit").gameObject);
var mallowRoot = REMOTE_Stick_Pivot.Find("Stick_Tip/Mallow_Root");
mallowRoot.gameObject.SetActive(false);
var oldMarshmallow = mallowRoot.GetComponent<Marshmallow>();
// Recreate particle system
Destroy(mallowRoot.Find("MallowSmoke").GetComponent<RelativisticParticleSystem>());
var newSystem = mallowRoot.Find("MallowSmoke").gameObject.AddComponent<CustomRelativisticParticleSystem>();
newSystem.Init(Player);
// Create new marshmallow
var newMarshmallow = mallowRoot.gameObject.AddComponent<QSBMarshmallow>();
newMarshmallow._fireRenderer = oldMarshmallow.GetValue<MeshRenderer>("_fireRenderer");
newMarshmallow._smokeParticles = oldMarshmallow.GetValue<ParticleSystem>("_smokeParticles");
newMarshmallow._mallowRenderer = oldMarshmallow.GetValue<MeshRenderer>("_mallowRenderer");
newMarshmallow._rawColor = oldMarshmallow.GetValue<Color>("_rawColor");
newMarshmallow._toastedColor = oldMarshmallow.GetValue<Color>("_toastedColor");
newMarshmallow._burntColor = oldMarshmallow.GetValue<Color>("_burntColor");
Destroy(oldMarshmallow);
Player.RoastingStick = REMOTE_Stick_Pivot.gameObject;
Player.Marshmallow = newMarshmallow;
mallowRoot.gameObject.SetActive(true);
_visibleRoastingSystem = REMOTE_RoastingSystem.transform;
_visibleStickPivot = REMOTE_Stick_Pivot;
_visibleStickTip = REMOTE_Stick_Pivot.Find("Stick_Tip");
return REMOTE_Player_Body.transform;
}
public override bool IsReady => Locator.GetPlayerTransform() != null
&& Player != null
&& QSBPlayerManager.PlayerExists(Player.PlayerId)
&& Player.PlayerStates.IsReady
&& NetId.Value != uint.MaxValue
&& NetId.Value != 0U;
protected override bool UpdateTransform()
{
if (!base.UpdateTransform())
{
return false;
}
UpdateSpecificTransform(_visibleStickPivot, _networkStickPivot, ref _pivotPositionVelocity, ref _pivotRotationVelocity);
UpdateSpecificTransform(_visibleStickTip, _networkStickTip, ref _tipPositionVelocity, ref _tipRotationVelocity);
UpdateSpecificTransform(_visibleCameraRoot, _networkCameraRoot, ref _cameraPositionVelocity, ref _cameraRotationVelocity);
UpdateSpecificTransform(_visibleRoastingSystem, _networkRoastingSystem, ref _roastingPositionVelocity, ref _roastingRotationVelocity);
return true;
}
private void UpdateSpecificTransform(Transform visible, Transform network, ref Vector3 positionVelocity, ref Quaternion rotationVelocity)
{
if (HasAuthority)
{
network.localPosition = visible.localPosition;
network.localRotation = visible.localRotation;
return;
}
visible.localPosition = Vector3.SmoothDamp(visible.localPosition, network.localPosition, ref positionVelocity, SmoothTime);
visible.localRotation = QuaternionHelper.SmoothDamp(visible.localRotation, network.localRotation, ref rotationVelocity, SmoothTime);
}
protected override void OnRenderObject()
{
base.OnRenderObject();
if (!QSBCore.WorldObjectsReady
|| !QSBCore.DebugMode
|| !QSBCore.ShowLinesInDebug
|| !IsReady
|| ReferenceTransform == null
|| _intermediaryTransform.GetReferenceTransform() == null)
{
return;
}
Popcron.Gizmos.Cube(ReferenceTransform.TransformPoint(_networkRoastingSystem.position), ReferenceTransform.TransformRotation(_networkRoastingSystem.rotation), Vector3.one / 4, Color.red);
Popcron.Gizmos.Cube(ReferenceTransform.TransformPoint(_networkStickPivot.position), ReferenceTransform.TransformRotation(_networkStickPivot.rotation), Vector3.one / 4, Color.red);
Popcron.Gizmos.Cube(ReferenceTransform.TransformPoint(_networkStickTip.position), ReferenceTransform.TransformRotation(_networkStickTip.rotation), Vector3.one / 4, Color.red);
Popcron.Gizmos.Cube(ReferenceTransform.TransformPoint(_networkCameraRoot.position), ReferenceTransform.TransformRotation(_networkCameraRoot.rotation), Vector3.one / 4, Color.red);
Popcron.Gizmos.Cube(_visibleRoastingSystem.position, _visibleRoastingSystem.rotation, Vector3.one / 4, Color.magenta);
Popcron.Gizmos.Cube(_visibleStickPivot.position, _visibleStickPivot.rotation, Vector3.one / 4, Color.blue);
Popcron.Gizmos.Cube(_visibleStickTip.position, _visibleStickTip.rotation, Vector3.one / 4, Color.yellow);
Popcron.Gizmos.Cube(_visibleCameraRoot.position, _visibleCameraRoot.rotation, Vector3.one / 4, Color.grey);
}
public override bool IsReady
=> Locator.GetPlayerTransform() != null;
public static PlayerTransformSync LocalInstance { get; private set; }

View File

@ -4,39 +4,30 @@ using QSB.Player;
namespace QSB.ProbeSync.Events
{
public class PlayerProbeEvent : QSBEvent<ToggleMessage>
internal class PlayerProbeEvent : QSBEvent<EnumMessage<ProbeEvent>>
{
public override EventType Type => EventType.ProbeActiveChange;
public override EventType Type => EventType.ProbeEvent;
public override void SetupListener()
{
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.LaunchProbe, HandleLaunch);
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.RetrieveProbe, HandleRetrieve);
}
=> GlobalMessenger<ProbeEvent>.AddListener(EventNames.QSBProbeEvent, Handler);
public override void CloseListener()
{
GlobalMessenger<SurveyorProbe>.RemoveListener(EventNames.LaunchProbe, HandleLaunch);
GlobalMessenger<SurveyorProbe>.RemoveListener(EventNames.RetrieveProbe, HandleRetrieve);
}
=> GlobalMessenger<ProbeEvent>.RemoveListener(EventNames.QSBProbeEvent, Handler);
private void HandleLaunch(SurveyorProbe probe) => SendEvent(CreateMessage(true));
private void HandleRetrieve(SurveyorProbe probe) => SendEvent(CreateMessage(false));
private void Handler(ProbeEvent probeEvent) => SendEvent(CreateMessage(probeEvent));
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
private EnumMessage<ProbeEvent> CreateMessage(ProbeEvent probeEvent) => new EnumMessage<ProbeEvent>
{
AboutId = LocalPlayerId,
ToggleValue = value
EnumValue = probeEvent
};
public override void OnReceiveRemote(bool server, ToggleMessage message)
public override void OnReceiveRemote(bool server, EnumMessage<ProbeEvent> message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.PlayerStates.ProbeActive = message.ToggleValue;
player.Probe?.SetState(message.ToggleValue);
}
var probe = player.Probe;
public override void OnReceiveLocal(bool server, ToggleMessage message) =>
QSBPlayerManager.LocalPlayer.PlayerStates.ProbeActive = message.ToggleValue;
probe.HandleEvent(message.EnumValue);
}
}
}
}

View File

@ -0,0 +1,32 @@
using QSB.Events;
using QSB.Messaging;
using QSB.Player;
namespace QSB.ProbeSync.Events
{
internal class ProbeStartRetrieveEvent : QSBEvent<FloatMessage>
{
public override EventType Type => EventType.ProbeStartRetrieve;
public override void SetupListener()
=> GlobalMessenger<float>.AddListener(EventNames.QSBProbeStartRetrieve, Handler);
public override void CloseListener()
=> GlobalMessenger<float>.RemoveListener(EventNames.QSBProbeStartRetrieve, Handler);
private void Handler(float duration) => SendEvent(CreateMessage(duration));
private FloatMessage CreateMessage(float duration) => new FloatMessage
{
AboutId = LocalPlayerId,
Value = duration
};
public override void OnReceiveRemote(bool server, FloatMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
var probe = player.Probe;
probe.OnStartRetrieve(message.Value);
}
}
}

View File

@ -0,0 +1,12 @@
namespace QSB.ProbeSync
{
public enum ProbeEvent
{
Invalid = 0,
Launch = 1,
Anchor = 2,
Unanchor = 3,
Retrieve = 4,
Destroy = 5
}
}

View File

@ -0,0 +1,54 @@
using QSB.Events;
using UnityEngine;
namespace QSB.ProbeSync
{
internal class ProbeListener : MonoBehaviour
{
private SurveyorProbe _attachedProbe;
public void Init(SurveyorProbe localProbe)
{
_attachedProbe = localProbe;
_attachedProbe.OnLaunchProbe += OnLaunchProbe;
_attachedProbe.OnAnchorProbe += OnAnchorProbe;
_attachedProbe.OnUnanchorProbe += OnUnanchorProbe;
_attachedProbe.OnRetrieveProbe += OnRetrieveProbe;
_attachedProbe.OnProbeDestroyed += OnProbeDestroyed;
_attachedProbe.OnStartRetrieveProbe += OnStartRetrieveProbe;
}
private void OnDestroy()
{
if (_attachedProbe == null)
{
return;
}
_attachedProbe.OnLaunchProbe -= OnLaunchProbe;
_attachedProbe.OnAnchorProbe -= OnAnchorProbe;
_attachedProbe.OnUnanchorProbe -= OnUnanchorProbe;
_attachedProbe.OnRetrieveProbe -= OnRetrieveProbe;
_attachedProbe.OnProbeDestroyed -= OnProbeDestroyed;
_attachedProbe.OnStartRetrieveProbe -= OnStartRetrieveProbe;
}
private void OnLaunchProbe()
=> QSBEventManager.FireEvent(EventNames.QSBProbeEvent, ProbeEvent.Launch);
private void OnAnchorProbe()
=> QSBEventManager.FireEvent(EventNames.QSBProbeEvent, ProbeEvent.Anchor);
private void OnUnanchorProbe()
=> QSBEventManager.FireEvent(EventNames.QSBProbeEvent, ProbeEvent.Unanchor);
private void OnRetrieveProbe()
=> QSBEventManager.FireEvent(EventNames.QSBProbeEvent, ProbeEvent.Retrieve);
private void OnProbeDestroyed()
=> QSBEventManager.FireEvent(EventNames.QSBProbeEvent, ProbeEvent.Destroy);
private void OnStartRetrieveProbe(float length)
=> QSBEventManager.FireEvent(EventNames.QSBProbeStartRetrieve, length);
}
}

View File

@ -1,20 +1,143 @@
using QSB.Utility;
using QSB.Player;
using QSB.Utility;
using UnityEngine;
namespace QSB.ProbeSync
{
public class QSBProbe : MonoBehaviour
{
public void SetState(bool state)
public delegate void SurveyorProbeEvent();
public delegate void RetrieveEvent(float retrieveLength);
public event SurveyorProbeEvent OnLaunchProbe;
public event SurveyorProbeEvent OnAnchorProbe;
public event SurveyorProbeEvent OnUnanchorProbe;
public event SurveyorProbeEvent OnRetrieveProbe;
public event SurveyorProbeEvent OnProbeDestroyed;
public event RetrieveEvent OnStartRetrieveProbe;
private GameObject _detectorObj;
private RulesetDetector _rulesetDetector;
private SingularityWarpEffect _warpEffect;
private bool _isRetrieving;
private PlayerInfo _owner;
public RulesetDetector GetRulesetDetector()
=> _rulesetDetector;
private void Awake()
{
if (state)
_detectorObj = GetComponentInChildren<RulesetDetector>().gameObject;
_rulesetDetector = _detectorObj.GetComponent<RulesetDetector>();
_warpEffect = GetComponentInChildren<SingularityWarpEffect>();
_warpEffect.OnWarpComplete += OnWarpComplete;
_isRetrieving = false;
}
private void Start() => gameObject.SetActive(false);
protected void OnDestroy() => _warpEffect.OnWarpComplete -= OnWarpComplete;
public void SetOwner(PlayerInfo player)
{
if (_owner != null)
{
gameObject.SetActive(true);
gameObject.Show();
DebugLog.ToConsole($"Warning - Trying to set owner of probe that already has an owner!", OWML.Common.MessageType.Warning);
}
_owner = player;
}
private void OnWarpComplete() => Deactivate();
public bool IsRetrieving()
=> IsLaunched() && _isRetrieving;
public bool IsLaunched()
=> gameObject.activeSelf;
public void HandleEvent(ProbeEvent probeEvent)
{
if (_owner == null)
{
DebugLog.ToConsole($"Error - Trying to handle event on probe with no owner.", OWML.Common.MessageType.Error);
return;
}
gameObject.Hide();
switch (probeEvent)
{
case ProbeEvent.Launch:
if (OnLaunchProbe == null)
{
DebugLog.ToConsole($"Warning - OnLaunchProbe is null!", OWML.Common.MessageType.Warning);
break;
}
gameObject.SetActive(true);
transform.position = _owner.ProbeLauncher.transform.position;
transform.rotation = _owner.ProbeLauncher.transform.rotation;
OnLaunchProbe();
break;
case ProbeEvent.Anchor:
if (OnAnchorProbe == null)
{
DebugLog.ToConsole($"Warning - OnAnchorProbe is null!", OWML.Common.MessageType.Warning);
break;
}
OnAnchorProbe();
break;
case ProbeEvent.Unanchor:
OnUnanchorProbe();
break;
case ProbeEvent.Retrieve:
if (OnRetrieveProbe == null)
{
DebugLog.ToConsole($"Warning - OnRetrieveProbe is null!", OWML.Common.MessageType.Warning);
break;
}
OnRetrieveProbe();
break;
case ProbeEvent.Destroy:
if (OnProbeDestroyed == null)
{
DebugLog.ToConsole($"Warning - OnProbeDestroyed is null!", OWML.Common.MessageType.Warning);
break;
}
OnProbeDestroyed();
break;
case ProbeEvent.Invalid:
default:
DebugLog.DebugWrite($"Warning - Unknown/Invalid probe event.", OWML.Common.MessageType.Warning);
break;
}
}
private void Deactivate()
{
transform.localScale = Vector3.one;
gameObject.SetActive(false);
_isRetrieving = false;
}
public void OnStartRetrieve(float duration)
{
if (!_isRetrieving)
{
_isRetrieving = true;
_warpEffect.WarpObjectOut(duration);
if (OnStartRetrieveProbe == null)
{
DebugLog.ToConsole($"Warning - OnStartRetrieveProbe is null!", OWML.Common.MessageType.Warning);
return;
}
OnStartRetrieveProbe(duration);
}
}
}
}

View File

@ -0,0 +1,62 @@
using QSB.Utility;
using System.Linq;
using UnityEngine;
namespace QSB.ProbeSync
{
internal class QSBProbeEffects : MonoBehaviour
{
public OWAudioSource _flightLoopAudio;
public OWAudioSource _anchorAudio;
public ParticleSystem _anchorParticles;
public ParticleSystem _underwaterAnchorParticles;
private QSBProbe _probe;
private void Awake()
{
_probe = Resources.FindObjectsOfTypeAll<QSBProbe>().First(x => gameObject.transform.IsChildOf(x.transform));
if (_probe == null)
{
DebugLog.ToConsole($"Error - Couldn't find QSBProbe!", OWML.Common.MessageType.Error);
}
_probe.OnLaunchProbe += OnLaunch;
_probe.OnAnchorProbe += OnAnchor;
_probe.OnUnanchorProbe += OnUnanchor;
_probe.OnStartRetrieveProbe += OnStartRetrieve;
}
private void OnDestroy()
{
_probe.OnLaunchProbe -= OnLaunch;
_probe.OnAnchorProbe -= OnAnchor;
_probe.OnUnanchorProbe -= OnUnanchor;
_probe.OnStartRetrieveProbe -= OnStartRetrieve;
}
private void OnLaunch() => _flightLoopAudio.FadeIn(0.1f, true, true, 1f);
private void OnAnchor()
{
// TODO : Come up with some other way of doing this
//if (this._fluidDetector.InFluidType(FluidVolume.Type.WATER))
//{
// this._underwaterAnchorParticles.Play();
//}
//else
//{
_anchorParticles.Play();
//}
_flightLoopAudio.FadeOut(0.5f, OWAudioSource.FadeOutCompleteAction.STOP, 0f);
_anchorAudio.PlayOneShot(AudioType.ToolProbeAttach, 1f);
}
private void OnUnanchor()
=> _flightLoopAudio.FadeIn(0.5f, false, false, 1f);
private void OnStartRetrieve(float retrieveLength)
=> _flightLoopAudio.FadeOut(retrieveLength, OWAudioSource.FadeOutCompleteAction.STOP, 0f);
}
}

View File

@ -0,0 +1,114 @@
using QSB.Utility;
using System.Linq;
using UnityEngine;
namespace QSB.ProbeSync
{
internal class QSBProbeLantern : MonoBehaviour
{
public float _fadeInDuration;
public AnimationCurve _fadeInCurve;
public AnimationCurve _fadeOutCurve;
public OWEmissiveRenderer _emissiveRenderer;
public float _originalRange;
private QSBProbe _probe;
private OWLight2 _light;
private float _fadeFraction;
private float _targetFade;
private float _startFade;
private float _startFadeTime;
private float _fadeDuration;
private void Awake()
{
_probe = Resources.FindObjectsOfTypeAll<QSBProbe>().First(x => gameObject.transform.IsChildOf(x.transform));
if (_probe == null)
{
DebugLog.ToConsole($"Error - Couldn't find QSBProbe!", OWML.Common.MessageType.Error);
}
_light = GetComponent<OWLight2>();
_probe.OnAnchorProbe += OnProbeAnchorToSurface;
_probe.OnStartRetrieveProbe += OnStartRetrieveProbe;
_probe.OnRetrieveProbe += OnFinishRetrieveProbe;
}
private void Start()
{
if (_emissiveRenderer != null)
{
_emissiveRenderer.SetEmissiveScale(0f);
}
_light.GetLight().enabled = false;
//_originalRange = _light.range;
enabled = false;
}
private void OnDestroy()
{
_probe.OnAnchorProbe -= OnProbeAnchorToSurface;
_probe.OnStartRetrieveProbe -= OnStartRetrieveProbe;
_probe.OnRetrieveProbe -= OnFinishRetrieveProbe;
}
private void Update()
{
var animationCurve = (_targetFade <= 0f)
? _fadeOutCurve
: _fadeInCurve;
var fadeTime = Mathf.InverseLerp(_startFadeTime, _startFadeTime + _fadeDuration, Time.time);
_fadeFraction = Mathf.Lerp(_startFade, _targetFade, animationCurve.Evaluate(fadeTime));
var probeRuleSet = _probe.GetRulesetDetector().GetProbeRuleSet();
var lanternRange = (!(probeRuleSet != null) || !probeRuleSet.GetOverrideLanternRange())
? _originalRange
: probeRuleSet.GetLanternRange();
_light.range = lanternRange * _fadeFraction;
if (_emissiveRenderer != null)
{
_emissiveRenderer.SetEmissiveScale(_fadeFraction);
}
if (fadeTime >= 1f)
{
enabled = false;
}
}
private void FadeTo(float fade, float duration)
{
_startFadeTime = Time.time;
_fadeDuration = duration;
_startFade = _fadeFraction;
_targetFade = fade;
enabled = true;
}
private void OnProbeAnchorToSurface()
{
if (!_probe.IsRetrieving())
{
_light.GetLight().enabled = true;
_light.range = 0f;
FadeTo(1f, _fadeInDuration);
}
}
private void OnStartRetrieveProbe(float retrieveLength)
=> FadeTo(0f, retrieveLength);
private void OnFinishRetrieveProbe()
{
_light.GetLight().enabled = false;
_light.range = 0f;
_fadeFraction = 0f;
enabled = false;
}
}
}

View File

@ -0,0 +1,78 @@
using QSB.Utility;
using System.Linq;
using UnityEngine;
namespace QSB.ProbeSync
{
internal class QSBProbeSpotlight : MonoBehaviour
{
public ProbeCamera.ID _id;
public float _fadeInLength = 1f;
public float _intensity;
private QSBProbe _probe;
private OWLight2 _light;
private bool _inFlight;
private float _timer;
private void Awake()
{
_probe = Resources.FindObjectsOfTypeAll<QSBProbe>().First(x => gameObject.transform.IsChildOf(x.transform));
if (_probe == null)
{
DebugLog.ToConsole($"Error - Couldn't find QSBProbe!", OWML.Common.MessageType.Error);
}
_light = GetComponent<OWLight2>();
//_intensity = _light.GetLight().intensity;
_light.GetLight().enabled = false;
enabled = false;
_probe.OnLaunchProbe += OnLaunch;
_probe.OnAnchorProbe += OnAnchorOrRetrieve;
_probe.OnRetrieveProbe += OnAnchorOrRetrieve;
}
private void OnDestroy()
{
_probe.OnLaunchProbe -= OnLaunch;
_probe.OnAnchorProbe -= OnAnchorOrRetrieve;
_probe.OnRetrieveProbe -= OnAnchorOrRetrieve;
}
private void Update()
{
_timer += Time.deltaTime;
var num = Mathf.Clamp01(_timer / _fadeInLength);
var intensityScale = (2f - num) * num * _intensity;
_light.SetIntensityScale(intensityScale);
}
private void StartFadeIn()
{
if (!enabled)
{
_light.GetLight().enabled = true;
_light.SetIntensityScale(0f);
_timer = 0f;
enabled = true;
}
}
private void OnLaunch()
{
if (_id == ProbeCamera.ID.Forward)
{
StartFadeIn();
}
_inFlight = true;
}
private void OnAnchorOrRetrieve()
{
_light.GetLight().enabled = false;
enabled = false;
_inFlight = false;
}
}
}

View File

@ -1,39 +1,51 @@
using OWML.Common;
using QSB.Player;
using OWML.Utils;
using QSB.SectorSync;
using QSB.Syncs.TransformSync;
using QSB.Tools;
using QSB.Tools.ProbeLauncherTool;
using QSB.Utility;
using QSB.WorldSync;
using UnityEngine;
namespace QSB.ProbeSync.TransformSync
{
public class PlayerProbeSync : SectoredTransformSync
{
protected override float DistanceLeeway => 10f;
public override bool UseInterpolation => true;
public override TargetType Type => TargetType.Probe;
public override bool IgnoreDisabledAttachedObject => true;
public static PlayerProbeSync LocalInstance { get; private set; }
public override void OnStartAuthority()
public override void OnStartAuthority() => LocalInstance = this;
protected override Component InitLocalTransform()
{
DebugLog.DebugWrite($"OnStartAuthority probe");
LocalInstance = this;
}
private Transform GetProbe() =>
Locator.GetProbe().transform.Find("CameraPivot").Find("Geometry");
protected override Transform InitLocalTransform()
{
SectorSync.Init(Locator.GetProbe().GetSectorDetector(), this);
var body = GetProbe();
QSBCore.UnityEvents.RunWhen(() => WorldObjectManager.AllReady, () => SectorSync.Init(Locator.GetProbe().GetSectorDetector(), this));
var body = Locator.GetProbe().transform;
Player.ProbeBody = body.gameObject;
if (Player.Body == null)
{
DebugLog.ToConsole($"Warning - Player.Body is null!", MessageType.Warning);
return null;
}
var listener = Player.Body.AddComponent<ProbeListener>();
listener.Init(Locator.GetProbe());
var launcherListener = Player.Body.AddComponent<ProbeLauncherListener>();
launcherListener.Init(Player.LocalProbeLauncher);
return body;
}
protected override Transform InitRemoteTransform()
protected override Component InitRemoteTransform()
{
var probe = GetProbe();
var probe = Locator.GetProbe().transform;
if (probe == null)
{
@ -41,10 +53,11 @@ namespace QSB.ProbeSync.TransformSync
return default;
}
var body = probe.InstantiateInactive();
body.name = "RemoteProbeTransform";
var body = probe.gameObject.activeSelf
? probe.InstantiateInactive()
: Instantiate(probe);
Destroy(body.GetComponentInChildren<ProbeAnimatorController>());
body.name = "RemoteProbeTransform";
PlayerToolsManager.CreateProbe(body, Player);
@ -53,17 +66,45 @@ namespace QSB.ProbeSync.TransformSync
return body;
}
public override bool IsReady => Locator.GetProbe() != null
&& Player != null
&& QSBPlayerManager.PlayerExists(Player.PlayerId)
&& Player.PlayerStates.IsReady
&& NetId.Value != uint.MaxValue
&& NetId.Value != 0U;
protected override bool UpdateTransform()
{
if (!base.UpdateTransform())
{
return false;
}
protected override float DistanceLeeway => 10f;
if (HasAuthority)
{
if (!AttachedObject.gameObject.activeInHierarchy)
{
var probeOWRigidbody = Locator.GetProbe().GetComponent<SurveyorProbe>().GetOWRigidbody();
if (probeOWRigidbody == null)
{
DebugLog.ToConsole($"Warning - Could not find OWRigidbody of local probe.", MessageType.Warning);
}
public override bool UseInterpolation => true;
var probeLauncher = Player.LocalProbeLauncher;
// TODO : make this sync to the *active* probe launcher's _launcherTransform
var launcherTransform = probeLauncher.GetValue<Transform>("_launcherTransform");
probeOWRigidbody.SetPosition(launcherTransform.position);
probeOWRigidbody.SetRotation(launcherTransform.rotation);
public override TargetType Type => TargetType.Probe;
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
var currentReferenceSector = ReferenceSector;
var playerReferenceSector = Player.TransformSync.ReferenceSector;
if (currentReferenceSector != playerReferenceSector)
{
SetReferenceSector(playerReferenceSector);
}
}
}
return true;
}
public override bool IsReady => Locator.GetProbe() != null;
}
}

View File

@ -132,6 +132,8 @@
<Compile Include="CampfireSync\Events\CampfireStateEvent.cs" />
<Compile Include="CampfireSync\Patches\CampfirePatches.cs" />
<Compile Include="CampfireSync\WorldObjects\QSBCampfire.cs" />
<Compile Include="ClientServerStateSync\ClientStateManager.cs" />
<Compile Include="ClientServerStateSync\Events\ClientStateEvent.cs" />
<Compile Include="ConversationSync\Events\DialogueConditionEvent.cs" />
<Compile Include="ConversationSync\Events\DialogueConditionMessage.cs" />
<Compile Include="ConversationSync\Events\ConversationEvent.cs" />
@ -141,8 +143,15 @@
<Compile Include="ConversationSync\Events\ConversationStartEndMessage.cs" />
<Compile Include="ConversationSync\ConversationType.cs" />
<Compile Include="ConversationSync\ConversationManager.cs" />
<Compile Include="DeathSync\EndLoopReason.cs" />
<Compile Include="DeathSync\Events\EndLoopEvent.cs" />
<Compile Include="DeathSync\Events\PlayerRespawnEvent.cs" />
<Compile Include="DeathSync\Events\StartLoopEvent.cs" />
<Compile Include="DeathSync\Patches\MapPatches.cs" />
<Compile Include="DeathSync\Events\PlayerDeathMessage.cs" />
<Compile Include="DeathSync\Patches\DeathPatches.cs" />
<Compile Include="DeathSync\Patches\RespawnPatches.cs" />
<Compile Include="DeathSync\RespawnManager.cs" />
<Compile Include="ElevatorSync\WorldObjects\QSBElevator.cs" />
<Compile Include="ElevatorSync\Events\ElevatorEvent.cs" />
<Compile Include="ElevatorSync\ElevatorManager.cs" />
@ -154,6 +163,7 @@
<Compile Include="FrequencySync\Events\IdentifyFrequencyEvent.cs" />
<Compile Include="FrequencySync\Events\IdentifySignalEvent.cs" />
<Compile Include="FrequencySync\Patches\FrequencyPatches.cs" />
<Compile Include="ClientServerStateSync\ClientState.cs" />
<Compile Include="GeyserSync\Patches\GeyserPatches.cs" />
<Compile Include="Inputs\Patches\InputPatches.cs" />
<Compile Include="Instruments\QSBCamera\CameraController.cs" />
@ -162,6 +172,9 @@
<Compile Include="Instruments\InstrumentsManager.cs" />
<Compile Include="Messaging\BoolMessage.cs" />
<Compile Include="OrbSync\TransformSync\NomaiOrbTransformSync.cs" />
<Compile Include="Player\Events\PlayerInformationEvent.cs" />
<Compile Include="Player\Events\PlayerInformationMessage.cs" />
<Compile Include="Player\Events\RequestStateResyncEvent.cs" />
<Compile Include="Player\Patches\PlayerPatches.cs" />
<Compile Include="Player\PlayerState.cs" />
<Compile Include="PoolSync\CustomNomaiRemoteCameraPlatform.cs" />
@ -201,7 +214,6 @@
<Compile Include="Patches\QSBPatchManager.cs" />
<Compile Include="Player\Events\PlayerEntangledEvent.cs" />
<Compile Include="Player\Events\PlayerKickEvent.cs" />
<Compile Include="Player\Events\ServerSendPlayerStatesEvent.cs" />
<Compile Include="Player\KickReason.cs" />
<Compile Include="Player\PlayerEntanglementWatcher.cs" />
<Compile Include="Player\PlayerMapMarker.cs" />
@ -209,6 +221,13 @@
<Compile Include="PoolSync\Patches\PoolPatches.cs" />
<Compile Include="PoolSync\PoolManager.cs" />
<Compile Include="Inputs\QSBInputManager.cs" />
<Compile Include="ProbeSync\Events\PlayerProbeEvent.cs" />
<Compile Include="ProbeSync\Events\ProbeStartRetrieveEvent.cs" />
<Compile Include="ProbeSync\ProbeEvent.cs" />
<Compile Include="ProbeSync\ProbeListener.cs" />
<Compile Include="ProbeSync\QSBProbeEffects.cs" />
<Compile Include="ProbeSync\QSBProbeLantern.cs" />
<Compile Include="ProbeSync\QSBProbeSpotlight.cs" />
<Compile Include="QSBNetworkLobby.cs" />
<Compile Include="Patches\QSBPatch.cs" />
<Compile Include="Patches\QSBPatchTypes.cs" />
@ -240,6 +259,9 @@
<Compile Include="QuantumSync\Patches\QuantumVisibilityPatches.cs" />
<Compile Include="QuantumSync\Patches\ServerQuantumPatches.cs" />
<Compile Include="SectorSync\TargetType.cs" />
<Compile Include="ClientServerStateSync\Events\ServerStateEvent.cs" />
<Compile Include="ClientServerStateSync\ServerState.cs" />
<Compile Include="ClientServerStateSync\ServerStateManager.cs" />
<Compile Include="ShipSync\ComponentType.cs" />
<Compile Include="ShipSync\Events\Component\ComponentDamagedEvent.cs" />
<Compile Include="ShipSync\Events\Component\ComponentRepairedEvent.cs" />
@ -257,10 +279,21 @@
<Compile Include="ShipSync\WorldObjects\QSBShipComponent.cs" />
<Compile Include="ShipSync\WorldObjects\QSBShipHull.cs" />
<Compile Include="Syncs\ISectoredSync.cs" />
<Compile Include="Syncs\ISync.cs" />
<Compile Include="Syncs\RigidbodySync\UnparentedBaseRigidbodySync.cs" />
<Compile Include="Syncs\RigidbodySync\SectoredRigidbodySync.cs" />
<Compile Include="Syncs\SyncBase.cs" />
<Compile Include="TimeSync\FastForwardReason.cs" />
<Compile Include="TimeSync\Patches\TimePatches.cs" />
<Compile Include="TimeSync\PauseReason.cs" />
<Compile Include="Tools\ProbeLauncherTool\Events\LaunchProbeEvent.cs" />
<Compile Include="Tools\ProbeLauncherTool\Events\PlayerLaunchProbeEvent.cs" />
<Compile Include="Tools\ProbeLauncherTool\Events\PlayerRetrieveProbeEvent.cs" />
<Compile Include="Tools\ProbeLauncherTool\Events\RetrieveProbeEvent.cs" />
<Compile Include="Tools\ProbeLauncherTool\Patches\LauncherPatches.cs" />
<Compile Include="Tools\ProbeLauncherTool\ProbeLauncherListener.cs" />
<Compile Include="Tools\ProbeLauncherTool\ProbeLauncherManager.cs" />
<Compile Include="Tools\ProbeLauncherTool\QSBProbeLauncherTool.cs" />
<Compile Include="Tools\ProbeLauncherTool\WorldObjects\QSBProbeLauncher.cs" />
<Compile Include="Utility\CustomRelativisticParticleSystem.cs" />
<Compile Include="RoastingSync\QSBMarshmallow.cs" />
<Compile Include="RoastingSync\Events\EnterExitRoastingEvent.cs" />
@ -276,7 +309,6 @@
<Compile Include="StatueSync\Events\StartStatueMessage.cs" />
<Compile Include="StatueSync\Patches\StatuePatches.cs" />
<Compile Include="StatueSync\StatueManager.cs" />
<Compile Include="RoastingSync\TransformSync\RoastingStickTransformSync.cs" />
<Compile Include="Syncs\TransformSync\BaseTransformSync.cs" />
<Compile Include="Syncs\IntermediaryTransform.cs" />
<Compile Include="Syncs\TransformSync\SectoredTransformSync.cs" />
@ -293,15 +325,13 @@
<Compile Include="TimeSync\TimeSyncUI.cs" />
<Compile Include="Tools\Events\PlayerFlashlightEvent.cs" />
<Compile Include="Player\Events\PlayerJoinEvent.cs" />
<Compile Include="ProbeSync\Events\PlayerProbeEvent.cs" />
<Compile Include="Player\Events\PlayerReadyEvent.cs" />
<Compile Include="Player\Events\PlayerStatesRequestEvent.cs" />
<Compile Include="Animation\Player\Events\PlayerSuitEvent.cs" />
<Compile Include="TimeSync\Events\ServerTimeEvent.cs" />
<Compile Include="GeyserSync\Events\GeyserEvent.cs" />
<Compile Include="GeyserSync\GeyserManager.cs" />
<Compile Include="GeyserSync\WorldObjects\QSBGeyser.cs" />
<Compile Include="ProbeSync\Events\PlayerProbeLauncherEvent.cs" />
<Compile Include="Tools\ProbeLauncherTool\Events\EquipProbeLauncherEvent.cs" />
<Compile Include="Tools\Events\PlayerSignalscopeEvent.cs" />
<Compile Include="Tools\Events\PlayerTranslatorEvent.cs" />
<Compile Include="Events\QSBEvent.cs" />
@ -341,7 +371,6 @@
<Compile Include="ProbeSync\TransformSync\PlayerProbeSync.cs" />
<Compile Include="Utility\DebugActions.cs" />
<Compile Include="Events\QSBEventManager.cs" />
<Compile Include="Player\Events\PlayerStateMessage.cs" />
<Compile Include="DeathSync\Necronomicon.cs" />
<Compile Include="Utility\DebugLog.cs" />
<Compile Include="Messaging\PlayerMessage.cs" />
@ -350,7 +379,6 @@
<Compile Include="Player\PlayerInfo.cs" />
<Compile Include="DeathSync\RespawnOnDeath.cs" />
<Compile Include="Player\QSBPlayerManager.cs" />
<Compile Include="Player\TransformSync\PlayerCameraSync.cs" />
<Compile Include="Player\PlayerHUDMarker.cs" />
<Compile Include="Tools\PlayerToolsManager.cs" />
<Compile Include="Utility\QuaternionHelper.cs" />

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<GameDir>D:\EpicGames\OuterWilds</GameDir>
<GameDir>E:\Epic\Epic Games\OuterWilds</GameDir>
<OwmlDir>C:\Users\Henry\AppData\Roaming\OuterWildsModManager\OWML</OwmlDir>
<ProjectView>ShowAllFiles</ProjectView>
</PropertyGroup>

View File

@ -5,6 +5,7 @@ using OWML.Utils;
using QSB.Animation.NPC;
using QSB.CampfireSync;
using QSB.ConversationSync;
using QSB.DeathSync;
using QSB.ElevatorSync;
using QSB.GeyserSync;
using QSB.Inputs;
@ -19,6 +20,7 @@ using QSB.SectorSync;
using QSB.ShipSync;
using QSB.StatueSync;
using QSB.TimeSync;
using QSB.Tools.ProbeLauncherTool;
using QSB.TranslationSync;
using QSB.Utility;
using QSB.WorldSync;
@ -58,14 +60,12 @@ namespace QSB
public static AssetBundle InstrumentAssetBundle { get; private set; }
public static AssetBundle ConversationAssetBundle { get; private set; }
public static bool WorldObjectsReady => WorldObjectManager.AllReady && IsInMultiplayer && PlayerTransformSync.LocalInstance != null;
public static bool IsServer => QNetworkServer.active;
public static bool IsHost => QNetworkServer.active;
public static bool IsInMultiplayer => QNetworkManager.singleton.isNetworkActive;
public static string QSBVersion => Helper.Manifest.Version;
public void Awake()
{
Application.runInBackground = true;
var instance = TextTranslation.Get().GetValue<TextTranslation.TranslationTable>("m_table");
instance.theUITable[(int)UITextType.PleaseUseController] =
"<color=orange>Quantum Space Buddies</color> is best experienced with friends...";
@ -91,6 +91,7 @@ namespace QSB
gameObject.AddComponent<RepeatingManager>();
gameObject.AddComponent<PlayerEntanglementWatcher>();
gameObject.AddComponent<DebugGUI>();
gameObject.AddComponent<RespawnManager>();
// WorldObject managers
gameObject.AddComponent<QuantumManager>();
@ -105,6 +106,7 @@ namespace QSB
gameObject.AddComponent<CampfireManager>();
gameObject.AddComponent<CharacterAnimManager>();
gameObject.AddComponent<ShipManager>();
gameObject.AddComponent<ProbeLauncherManager>();
DebugBoxManager.Init();
@ -112,6 +114,25 @@ namespace QSB
// Stop players being able to pause
Helper.HarmonyHelper.EmptyMethod(typeof(OWTime).GetMethod("Pause"));
QSBPatchManager.OnPatchType += OnPatchType;
QSBPatchManager.OnUnpatchType += OnUnpatchType;
}
private void OnPatchType(QSBPatchTypes type)
{
if (type == QSBPatchTypes.OnClientConnect)
{
Application.runInBackground = true;
}
}
private void OnUnpatchType(QSBPatchTypes type)
{
if (type == QSBPatchTypes.OnClientConnect)
{
Application.runInBackground = false;
}
}
public void Update() =>
@ -154,4 +175,6 @@ namespace QSB
* Jake Chudnow
* Murray Gold
* Teleskärm
* Daft Punk
* Natalie Holt
*/

View File

@ -2,6 +2,7 @@
using OWML.Utils;
using QSB.Animation.Player;
using QSB.Animation.Player.Thrusters;
using QSB.ClientServerStateSync;
using QSB.DeathSync;
using QSB.Events;
using QSB.Instruments;
@ -11,7 +12,6 @@ using QSB.Player;
using QSB.Player.TransformSync;
using QSB.PoolSync;
using QSB.ProbeSync.TransformSync;
using QSB.RoastingSync.TransformSync;
using QSB.ShipSync.TransformSync;
using QSB.TimeSync;
using QSB.Utility;
@ -40,9 +40,7 @@ namespace QSB
private QSBNetworkLobby _lobby;
private AssetBundle _assetBundle;
private GameObject _cameraPrefab;
private GameObject _probePrefab;
private GameObject _stickPrefab;
private bool _everConnected;
public new void Awake()
@ -53,7 +51,7 @@ namespace QSB
_lobby = gameObject.AddComponent<QSBNetworkLobby>();
_assetBundle = QSBCore.NetworkAssetBundle;
playerPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkplayer.prefab");
playerPrefab = _assetBundle.LoadAsset<GameObject>("assets/NETWORK_Player_Body.prefab");
SetupNetworkId(playerPrefab);
SetupNetworkTransform(playerPrefab);
playerPrefab.AddComponent<PlayerTransformSync>();
@ -63,15 +61,9 @@ namespace QSB
playerPrefab.AddComponent<JetpackAccelerationSync>();
playerPrefab.AddComponent<InstrumentsManager>();
_cameraPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkcameraroot.prefab");
SetupNetworkId(_cameraPrefab);
SetupNetworkTransform(_cameraPrefab);
_cameraPrefab.AddComponent<PlayerCameraSync>();
spawnPrefabs.Add(_cameraPrefab);
ShipPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkship.prefab");
SetupNetworkId(ShipPrefab);
SetupNetworkTransform(_cameraPrefab);
SetupNetworkTransform(ShipPrefab);
ShipPrefab.AddComponent<ShipTransformSync>();
spawnPrefabs.Add(ShipPrefab);
@ -87,12 +79,6 @@ namespace QSB
OrbPrefab.AddComponent<NomaiOrbTransformSync>();
spawnPrefabs.Add(OrbPrefab);
_stickPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkstickpivot.prefab");
SetupNetworkId(_stickPrefab);
SetupNetworkTransform(_stickPrefab);
_stickPrefab.AddComponent<RoastingStickTransformSync>();
spawnPrefabs.Add(_stickPrefab);
ConfigureNetworkManager();
}
@ -110,6 +96,7 @@ namespace QSB
{
var child = go.AddComponent<QNetworkTransformChild>();
child.Target = item.target;
child.m_ChildIndex = item.childIndex;
Destroy(item);
}
@ -146,9 +133,7 @@ namespace QSB
DebugLog.DebugWrite($"OnServerAddPlayer {playerControllerId}", MessageType.Info);
base.OnServerAddPlayer(connection, playerControllerId);
QNetworkServer.SpawnWithClientAuthority(Instantiate(_cameraPrefab), connection);
QNetworkServer.SpawnWithClientAuthority(Instantiate(_probePrefab), connection);
QNetworkServer.SpawnWithClientAuthority(Instantiate(_stickPrefab), connection);
}
public override void OnStartClient(QNetworkClient _)
@ -167,6 +152,8 @@ namespace QSB
QSBEventManager.Init();
gameObject.AddComponent<RespawnOnDeath>();
gameObject.AddComponent<ServerStateManager>();
gameObject.AddComponent<ClientStateManager>();
if (QSBSceneManager.IsInUniverse)
{
@ -185,10 +172,10 @@ namespace QSB
QSBCore.UnityEvents.RunWhen(() => QSBEventManager.Ready && PlayerTransformSync.LocalInstance != null,
() => QSBEventManager.FireEvent(EventNames.QSBPlayerJoin, _lobby.PlayerName));
if (!QSBCore.IsServer)
if (!QSBCore.IsHost)
{
QSBCore.UnityEvents.RunWhen(() => QSBEventManager.Ready && PlayerTransformSync.LocalInstance != null,
() => QSBEventManager.FireEvent(EventNames.QSBPlayerStatesRequest));
() => QSBEventManager.FireEvent(EventNames.QSBRequestStateResync));
}
_everConnected = true;
@ -199,6 +186,8 @@ namespace QSB
DebugLog.DebugWrite("OnStopClient", MessageType.Info);
DebugLog.ToConsole("Disconnecting from server...", MessageType.Info);
Destroy(GetComponent<RespawnOnDeath>());
Destroy(GetComponent<ServerStateManager>());
Destroy(GetComponent<ClientStateManager>());
QSBEventManager.Reset();
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
@ -263,6 +252,8 @@ namespace QSB
{
Destroy(streaming);
}
WorldObjectManager.SetNotReady();
}
}
}

View File

@ -11,8 +11,8 @@ namespace QSB
public static bool IsInUniverse => InUniverse(CurrentScene);
public static event Action<OWScene, bool> OnSceneLoaded;
public static event Action<OWScene> OnUniverseSceneLoaded;
public static event Action<OWScene, OWScene, bool> OnSceneLoaded;
public static event Action<OWScene, OWScene> OnUniverseSceneLoaded;
static QSBSceneManager()
{
@ -30,10 +30,10 @@ namespace QSB
QSBCore.UnityEvents.FireOnNextUpdate(() => WorldObjectManager.Rebuild(newScene));
}
OnSceneLoaded?.SafeInvoke(newScene, universe);
OnSceneLoaded?.SafeInvoke(oldScene, newScene, universe);
if (universe)
{
OnUniverseSceneLoaded?.SafeInvoke(newScene);
OnUniverseSceneLoaded?.SafeInvoke(oldScene, newScene);
}
}

View File

@ -1,6 +1,6 @@
using QSB.Patches;
using QSB.Player;
using QSB.WorldSync;
using QSB.Utility;
using System.Linq;
using System.Reflection;
using UnityEngine;
@ -22,10 +22,10 @@ namespace QSB.QuantumSync.Patches
}
public static void Shape_OnEnable(Shape __instance)
=> QSBWorldSync.RaiseEvent(__instance, "OnShapeActivated", __instance);
=> __instance.RaiseEvent("OnShapeActivated", __instance);
public static void Shape_OnDisable(Shape __instance)
=> QSBWorldSync.RaiseEvent(__instance, "OnShapeDeactivated", __instance);
=> __instance.RaiseEvent("OnShapeDeactivated", __instance);
// ShapeVisibilityTracker patches

View File

@ -47,7 +47,7 @@ namespace QSB.QuantumSync
public void PlayerLeave(uint playerId)
{
if (!QSBCore.IsServer)
if (!QSBCore.IsHost)
{
return;
}
@ -79,16 +79,21 @@ namespace QSB.QuantumSync
public static Tuple<bool, List<PlayerInfo>> IsVisibleUsingCameraFrustum(ShapeVisibilityTracker tracker, bool ignoreLocalCamera)
{
if (!AllReady)
{
return new Tuple<bool, List<PlayerInfo>>(false, new List<PlayerInfo>());
}
var playersWithCameras = QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera);
if (playersWithCameras.Count == 0)
{
DebugLog.ToConsole($"Warning - Trying to run IsVisibleUsingCameraFrustum when there are no players!", MessageType.Warning);
return new Tuple<bool, List<PlayerInfo>>(false, null);
return new Tuple<bool, List<PlayerInfo>>(false, new List<PlayerInfo>());
}
if (!tracker.gameObject.activeInHierarchy)
{
return new Tuple<bool, List<PlayerInfo>>(false, null);
return new Tuple<bool, List<PlayerInfo>>(false, new List<PlayerInfo>());
}
var frustumMethod = tracker.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance);
@ -114,13 +119,10 @@ namespace QSB.QuantumSync
return new Tuple<bool, List<PlayerInfo>>(foundPlayers, playersWhoCanSee);
}
public static bool IsVisible(ShapeVisibilityTracker tracker, bool ignoreLocalCamera)
{
return tracker.gameObject.activeInHierarchy
public static bool IsVisible(ShapeVisibilityTracker tracker, bool ignoreLocalCamera) => tracker.gameObject.activeInHierarchy
&& IsVisibleUsingCameraFrustum(tracker, ignoreLocalCamera).First
&& QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera)
.Any(x => VisibilityOccluder.CanYouSee(tracker, x.Camera.mainCamera.transform.position));
}
public static IEnumerable<PlayerInfo> GetEntangledPlayers(QuantumObject obj)
{

View File

@ -87,7 +87,7 @@ namespace QSB.QuantumSync.WorldObjects
private void OnEnable(Shape s)
{
IsEnabled = true;
if (!QSBCore.WorldObjectsReady && !QSBCore.IsServer)
if (!QSBCore.WorldObjectsReady && !QSBCore.IsHost)
{
return;
}
@ -116,7 +116,7 @@ namespace QSB.QuantumSync.WorldObjects
}
IsEnabled = false;
if (!QSBCore.WorldObjectsReady && !QSBCore.IsServer)
if (!QSBCore.WorldObjectsReady && !QSBCore.IsHost)
{
return;
}

View File

@ -72,7 +72,7 @@ namespace QSB.RoastingSync.Events
var rigidbody = tossedMallow.GetComponent<OWRigidbody>();
if (player.Campfire == null)
{
DebugLog.DebugWrite($"Error - Campfire for {playerId} is null.", OWML.Common.MessageType.Error);
DebugLog.ToConsole($"Error - Campfire for {playerId} is null.", OWML.Common.MessageType.Error);
return;
}
@ -80,7 +80,7 @@ namespace QSB.RoastingSync.Events
rigidbody.SetAngularVelocity(stickTip.right * 10f);
if (player.Marshmallow == null)
{
DebugLog.DebugWrite($"Error - Marshmallow for {playerId} is null.", OWML.Common.MessageType.Error);
DebugLog.ToConsole($"Error - Marshmallow for {playerId} is null.", OWML.Common.MessageType.Error);
return;
}

View File

@ -1,94 +0,0 @@
using OWML.Utils;
using QSB.Player;
using QSB.SectorSync;
using QSB.Syncs.TransformSync;
using QSB.Utility;
using System.Linq;
using UnityEngine;
namespace QSB.RoastingSync.TransformSync
{
internal class RoastingStickTransformSync : SectoredTransformSync
{
private Transform _stickTip;
private Transform _networkStickTip => gameObject.transform.GetChild(0);
private const float SmoothTime = 0.1f;
private Vector3 _positionSmoothVelocity;
private Quaternion _rotationSmoothVelocity;
private Transform GetPivot()
=> Resources.FindObjectsOfTypeAll<RoastingStickController>().First().transform.Find("Stick_Root/Stick_Pivot");
protected override Transform InitLocalTransform()
{
var pivot = GetPivot();
Player.RoastingStick = pivot.gameObject;
_stickTip = pivot.Find("Stick_Tip");
return pivot;
}
protected override Transform InitRemoteTransform()
{
var newPivot = Instantiate(GetPivot());
newPivot.parent = null;
newPivot.gameObject.SetActive(false);
Destroy(newPivot.Find("Stick_Tip/Props_HEA_RoastingStick/RoastingStick_Arm").gameObject);
Destroy(newPivot.Find("Stick_Tip/Props_HEA_RoastingStick/RoastingStick_Arm_NoSuit").gameObject);
var mallowRoot = newPivot.Find("Stick_Tip/Mallow_Root");
mallowRoot.gameObject.SetActive(false);
var oldMarshmallow = mallowRoot.GetComponent<Marshmallow>();
// Recreate particle system
Destroy(mallowRoot.Find("MallowSmoke").GetComponent<RelativisticParticleSystem>());
var newSystem = mallowRoot.Find("MallowSmoke").gameObject.AddComponent<CustomRelativisticParticleSystem>();
newSystem.Init(Player);
// Create new marshmallow
var newMarshmallow = mallowRoot.gameObject.AddComponent<QSBMarshmallow>();
newMarshmallow._fireRenderer = oldMarshmallow.GetValue<MeshRenderer>("_fireRenderer");
newMarshmallow._smokeParticles = oldMarshmallow.GetValue<ParticleSystem>("_smokeParticles");
newMarshmallow._mallowRenderer = oldMarshmallow.GetValue<MeshRenderer>("_mallowRenderer");
newMarshmallow._rawColor = oldMarshmallow.GetValue<Color>("_rawColor");
newMarshmallow._toastedColor = oldMarshmallow.GetValue<Color>("_toastedColor");
newMarshmallow._burntColor = oldMarshmallow.GetValue<Color>("_burntColor");
Destroy(oldMarshmallow);
Player.RoastingStick = newPivot.gameObject;
Player.Marshmallow = newMarshmallow;
mallowRoot.gameObject.SetActive(true);
_stickTip = newPivot.Find("Stick_Tip");
return newPivot;
}
protected override void UpdateTransform()
{
base.UpdateTransform();
if (_stickTip == null)
{
DebugLog.ToConsole($"Warning - _stickTip is null for player {PlayerId}", OWML.Common.MessageType.Warning);
return;
}
if (HasAuthority)
{
_networkStickTip.localPosition = _stickTip.localPosition;
_networkStickTip.localRotation = _stickTip.localRotation;
return;
}
_stickTip.localPosition = Vector3.SmoothDamp(_stickTip.localPosition, _networkStickTip.localPosition, ref _positionSmoothVelocity, SmoothTime);
_stickTip.localRotation = QuaternionHelper.SmoothDamp(_stickTip.localRotation, _networkStickTip.localRotation, ref _rotationSmoothVelocity, SmoothTime);
}
public override bool IsReady => Locator.GetPlayerTransform() != null
&& Player != null
&& QSBPlayerManager.PlayerExists(Player.PlayerId)
&& Player.PlayerStates.IsReady
&& NetId.Value != uint.MaxValue
&& NetId.Value != 0U;
public override bool UseInterpolation => true;
public override TargetType Type => TargetType.RoastingStick;
}
}

View File

@ -3,7 +3,6 @@ using QSB.SectorSync.WorldObjects;
using QSB.Syncs;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@ -19,11 +18,16 @@ namespace QSB.SectorSync
private void OnEnable() => RepeatingManager.Repeatings.Add(this);
private void OnDisable() => RepeatingManager.Repeatings.Remove(this);
public List<ISectoredSync<Transform>> SectoredTransformSyncs = new List<ISectoredSync<Transform>>();
public List<ISectoredSync<OWRigidbody>> SectoredRigidbodySyncs = new List<ISectoredSync<OWRigidbody>>();
public List<SyncBase> SectoredTransformSyncs = new List<SyncBase>();
public List<SyncBase> SectoredRigidbodySyncs = new List<SyncBase>();
public void Invoke()
{
if (!Instance.IsReady || !AllReady)
{
return;
}
foreach (var sync in SectoredTransformSyncs)
{
if (sync.AttachedObject == null)
@ -31,11 +35,11 @@ namespace QSB.SectorSync
continue;
}
if ((sync as QNetworkBehaviour).HasAuthority
if (sync.HasAuthority
&& sync.AttachedObject.gameObject.activeInHierarchy
&& sync.IsReady)
{
CheckTransformSyncSector(sync);
CheckTransformSyncSector(sync as ISectoredSync<Transform>);
}
}
@ -46,11 +50,11 @@ namespace QSB.SectorSync
continue;
}
if ((sync as QNetworkBehaviour).HasAuthority
if (sync.HasAuthority
&& sync.AttachedObject.gameObject.activeInHierarchy
&& sync.IsReady)
{
CheckTransformSyncSector(sync);
CheckTransformSyncSector(sync as ISectoredSync<OWRigidbody>);
}
}
}
@ -88,7 +92,7 @@ namespace QSB.SectorSync
private void CheckTransformSyncSector<T>(ISectoredSync<T> transformSync)
where T : Component
{
var attachedObject = transformSync.AttachedObject;
var attachedObject = (transformSync as SyncBase).AttachedObject;
var closestSector = transformSync.SectorSync.GetClosestSector(attachedObject.transform);
if (closestSector == default(QSBSector))
{

View File

@ -17,6 +17,7 @@ namespace QSB.SectorSync
private OWRigidbody _attachedOWRigidbody;
private SectorDetector _sectorDetector;
private TargetType _targetType;
private bool _isReady;
private void OnDestroy()
{
@ -25,6 +26,7 @@ namespace QSB.SectorSync
_sectorDetector.OnEnterSector -= AddSector;
_sectorDetector.OnExitSector -= RemoveSector;
}
_isReady = false;
}
public void Init<T>(SectorDetector detector, ISectoredSync<T> sectoredSync)
@ -35,6 +37,12 @@ namespace QSB.SectorSync
_sectorDetector.OnExitSector -= RemoveSector;
}
if (detector == null)
{
DebugLog.ToConsole($"Error - Trying to init SectorSync with null SectorDetector.", MessageType.Error);
return;
}
_sectorDetector = detector;
_sectorDetector.OnEnterSector += AddSector;
_sectorDetector.OnExitSector += RemoveSector;
@ -45,7 +53,26 @@ namespace QSB.SectorSync
DebugLog.ToConsole($"Warning - OWRigidbody for {_sectorDetector.name} is null!", MessageType.Warning);
}
PopulateSectorList();
_targetType = sectoredSync.Type;
_isReady = true;
}
private void PopulateSectorList()
{
var currentList = _sectorDetector.GetValue<List<Sector>>("_sectorList");
SectorList.Clear();
foreach (var sector in currentList)
{
if (sector == null)
{
continue;
}
AddSector(sector);
}
}
private void AddSector(Sector sector)
@ -85,9 +112,21 @@ namespace QSB.SectorSync
public QSBSector GetClosestSector(Transform trans) // trans rights \o/
{
if (!QSBSectorManager.Instance.IsReady)
if (QSBSectorManager.Instance == null || !QSBSectorManager.Instance.IsReady)
{
DebugLog.ToConsole($"Warning - Tried to get closest sector to {trans.name} before QSBSectorManager was ready.", MessageType.Warning);
return null;
}
if (!_isReady)
{
DebugLog.ToConsole($"Warning - Tried to use GetClosestSector before it was initialized. Transform:{trans.name}", MessageType.Warning);
return null;
}
if (_sectorDetector == null || _attachedOWRigidbody == null || _targetType == TargetType.None)
{
_isReady = false;
DebugLog.ToConsole($"Error - SectorSync is no longer ready. Detector Null : {_sectorDetector == null}, OWRigidbody Null : {_attachedOWRigidbody == null}, None TargetType : {_targetType == TargetType.None}", MessageType.Error);
return null;
}

View File

@ -5,9 +5,7 @@
None = 0,
Player = 1,
Probe = 2,
PlayerCamera = 3,
RoastingStick = 4,
Ship = 5,
Other = 6
Ship = 3,
Other = 4
}
}

View File

@ -1,12 +1,11 @@
using QSB.Events;
using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync.Events;
using QSB.WorldSync;
using QSB.WorldSync.Events;
namespace QSB.ShipSync.Events.Component
{
class ComponentDamagedEvent : QSBEvent<WorldObjectMessage>
internal class ComponentDamagedEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.ComponentDamaged;

View File

@ -1,11 +1,10 @@
using QSB.Events;
using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
namespace QSB.ShipSync.Events.Component
{
class ComponentRepairTickEvent : QSBEvent<RepairTickMessage>
internal class ComponentRepairTickEvent : QSBEvent<RepairTickMessage>
{
public override EventType Type => EventType.ComponentRepairTick;

View File

@ -1,12 +1,11 @@
using QSB.Events;
using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync.Events;
using QSB.WorldSync;
using QSB.WorldSync.Events;
namespace QSB.ShipSync.Events.Component
{
class ComponentRepairedEvent : QSBEvent<WorldObjectMessage>
internal class ComponentRepairedEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.ComponentRepaired;

View File

@ -57,7 +57,7 @@ namespace QSB.ShipSync.Events
? id
: uint.MaxValue;
if (QSBCore.IsServer)
if (QSBCore.IsHost)
{
var newAuthority = ShipManager.Instance.CurrentFlyer == uint.MaxValue
? QNetworkServer.connections.First(x => x.GetPlayerId() == QSBPlayerManager.LocalPlayerId)

View File

@ -3,7 +3,7 @@ using QSB.Messaging;
namespace QSB.ShipSync.Events
{
class FunnelEnableEvent : QSBEvent<PlayerMessage>
internal class FunnelEnableEvent : QSBEvent<PlayerMessage>
{
public override EventType Type => EventType.EnableFunnel;

View File

@ -1,11 +1,10 @@
using QSB.Events;
using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
namespace QSB.ShipSync.Events.Hull
{
class HullChangeIntegrityEvent : QSBEvent<HullChangeIntegrityMessage>
internal class HullChangeIntegrityEvent : QSBEvent<HullChangeIntegrityMessage>
{
public override EventType Type => EventType.HullChangeIntegrity;

View File

@ -1,12 +1,11 @@
using QSB.Events;
using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using QSB.WorldSync.Events;
namespace QSB.ShipSync.Events.Hull
{
class HullDamagedEvent : QSBEvent<WorldObjectMessage>
internal class HullDamagedEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.HullDamaged;

View File

@ -1,11 +1,10 @@
using QSB.Events;
using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
namespace QSB.ShipSync.Events.Hull
{
class HullImpactEvent : QSBEvent<HullImpactMessage>
internal class HullImpactEvent : QSBEvent<HullImpactMessage>
{
public override EventType Type => EventType.HullImpact;

View File

@ -4,7 +4,7 @@ using QSB.WorldSync;
namespace QSB.ShipSync.Events.Hull
{
class HullRepairTickEvent : QSBEvent<RepairTickMessage>
internal class HullRepairTickEvent : QSBEvent<RepairTickMessage>
{
public override EventType Type => EventType.HullRepairTick;

View File

@ -1,12 +1,11 @@
using QSB.Events;
using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync.Events;
using QSB.WorldSync;
using QSB.WorldSync.Events;
namespace QSB.ShipSync.Events.Hull
{
class HullRepairedEvent : QSBEvent<WorldObjectMessage>
internal class HullRepairedEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.HullRepaired;

View File

@ -3,7 +3,7 @@ using QuantumUNET.Transport;
namespace QSB.ShipSync.Events
{
class RepairTickMessage : WorldObjectMessage
internal class RepairTickMessage : WorldObjectMessage
{
public float RepairNumber { get; set; }

View File

@ -2,7 +2,6 @@
using QSB.Events;
using QSB.Patches;
using QSB.Utility;
using QSB.WorldSync;
using UnityEngine;
namespace QSB.ShipSync.Patches
@ -116,7 +115,7 @@ namespace QSB.ShipSync.Patches
____damaged = true;
____repairFraction = 0f;
__instance.GetType().GetAnyMethod("OnComponentDamaged").Invoke(__instance, null);
QSBWorldSync.RaiseEvent(__instance, "OnDamaged", __instance);
__instance.RaiseEvent("OnDamaged", __instance);
QSBEventManager.FireEvent(EventNames.QSBComponentDamaged, __instance);
}
else
@ -124,7 +123,7 @@ namespace QSB.ShipSync.Patches
____damaged = false;
____repairFraction = 1f;
__instance.GetType().GetAnyMethod("OnComponentRepaired").Invoke(__instance, null);
QSBWorldSync.RaiseEvent(__instance, "OnRepaired", __instance);
__instance.RaiseEvent("OnRepaired", __instance);
QSBEventManager.FireEvent(EventNames.QSBComponentRepaired, __instance);
}
@ -154,7 +153,7 @@ namespace QSB.ShipSync.Patches
if (!____damaged)
{
____damaged = true;
QSBWorldSync.RaiseEvent(__instance, "OnDamaged", __instance);
__instance.RaiseEvent("OnDamaged", __instance);
QSBEventManager.FireEvent(EventNames.QSBHullDamaged, __instance);
}
@ -177,7 +176,7 @@ namespace QSB.ShipSync.Patches
}
}
QSBWorldSync.RaiseEvent(__instance, "OnImpact", ____dominantImpact, damage);
__instance.RaiseEvent("OnImpact", ____dominantImpact, damage);
QSBEventManager.FireEvent(EventNames.QSBHullImpact, __instance, ____dominantImpact, damage);
____dominantImpact = null;
@ -187,7 +186,7 @@ namespace QSB.ShipSync.Patches
return false;
}
public static bool ShipDamageController_OnImpact()
public static bool ShipDamageController_OnImpact()
=> ShipManager.Instance.HasAuthority;
public static void ShipComponent_RepairTick(ShipComponent __instance, float ____repairFraction)
@ -209,7 +208,7 @@ namespace QSB.ShipSync.Patches
if (____integrity >= 1f)
{
____damaged = false;
QSBWorldSync.RaiseEvent(__instance, "OnRepaired", __instance);
__instance.RaiseEvent("OnRepaired", __instance);
QSBEventManager.FireEvent(EventNames.QSBHullRepaired, __instance);
}

View File

@ -6,7 +6,6 @@ using QSB.ShipSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@ -48,7 +47,19 @@ namespace QSB.ShipSync
protected override void RebuildWorldObjects(OWScene scene)
{
var shipTransform = GameObject.Find("Ship_Body");
if (shipTransform == null)
{
DebugLog.ToConsole($"Error - Couldn't find ship!", MessageType.Error);
return;
}
HatchController = shipTransform.GetComponentInChildren<HatchController>();
if (HatchController == null)
{
DebugLog.ToConsole($"Error - Couldn't find hatch controller!", MessageType.Error);
return;
}
HatchInteractZone = HatchController.GetComponent<InteractZone>();
ShipTractorBeam = Resources.FindObjectsOfTypeAll<ShipTractorBeamSwitch>().First();
CockpitController = Resources.FindObjectsOfTypeAll<ShipCockpitController>().First();
@ -58,14 +69,23 @@ namespace QSB.ShipSync
sphereShape.radius = 2.5f;
sphereShape.center = new Vector3(0, 0, 1);
if (QSBCore.IsServer)
if (QSBCore.IsHost)
{
if (ShipTransformSync.LocalInstance != null)
{
if (ShipTransformSync.LocalInstance.gameObject == null)
{
DebugLog.ToConsole($"Warning - ShipTransformSync's LocalInstance is not null, but it's gameobject is null!", MessageType.Warning);
return;
}
QNetworkServer.Destroy(ShipTransformSync.LocalInstance.gameObject);
}
QNetworkServer.Spawn(Instantiate(QSBNetworkManager.Instance.ShipPrefab));
if (QSBPlayerManager.LocalPlayer.TransformSync == null)
{
DebugLog.ToConsole($"Error - Tried to spawn ship, but LocalPlayer's TransformSync is null!", MessageType.Error);
}
QNetworkServer.SpawnWithClientAuthority(Instantiate(QSBNetworkManager.Instance.ShipPrefab), QSBPlayerManager.LocalPlayer.TransformSync.gameObject);
}
QSBWorldSync.Init<QSBShipComponent, ShipComponent>();

View File

@ -2,6 +2,8 @@ using QSB.Player;
using QSB.SectorSync;
using QSB.Syncs.RigidbodySync;
using QSB.Utility;
using QSB.WorldSync;
using UnityEngine;
namespace QSB.ShipSync.TransformSync
{
@ -14,32 +16,34 @@ namespace QSB.ShipSync.TransformSync
public override void Start()
{
DebugLog.DebugWrite($"START!");
base.Start();
LocalInstance = this;
}
protected override Component InitLocalTransform() => throw new System.NotImplementedException();
protected override Component InitRemoteTransform() => throw new System.NotImplementedException();
protected override OWRigidbody GetRigidbody()
{
SectorSync.Init(Locator.GetShipDetector().GetComponent<SectorDetector>(), this);
QSBCore.UnityEvents.RunWhen(() => WorldObjectManager.AllReady, () => SectorSync.Init(Locator.GetShipDetector().GetComponent<SectorDetector>(), this));
return Locator.GetShipBody();
}
protected override void UpdateTransform()
protected override bool UpdateTransform()
{
if (HasAuthority && ShipManager.Instance.CurrentFlyer != QSBPlayerManager.LocalPlayerId && ShipManager.Instance.CurrentFlyer != uint.MaxValue)
{
DebugLog.ToConsole("Warning - Has authority, but is not current flyer!", OWML.Common.MessageType.Warning);
return;
return false;
}
if (!HasAuthority && ShipManager.Instance.CurrentFlyer == QSBPlayerManager.LocalPlayerId)
{
DebugLog.ToConsole($"Warning - Doesn't have authority, but is current flyer!", OWML.Common.MessageType.Warning);
return;
return false;
}
base.UpdateTransform();
return base.UpdateTransform();
}
public override TargetType Type => TargetType.Ship;

View File

@ -4,7 +4,7 @@ using QSB.WorldSync;
namespace QSB.ShipSync.WorldObjects
{
class QSBShipComponent : WorldObject<ShipComponent>
internal class QSBShipComponent : WorldObject<ShipComponent>
{
public override void Init(ShipComponent component, int id)
{
@ -18,7 +18,7 @@ namespace QSB.ShipSync.WorldObjects
AttachedObject.SetValue("_damaged", true);
AttachedObject.SetValue("_repairFraction", 0f);
AttachedObject.GetType().GetAnyMethod("OnComponentDamaged").Invoke(AttachedObject, null);
QSBWorldSync.RaiseEvent(AttachedObject, "OnDamaged", AttachedObject);
AttachedObject.RaiseEvent("OnDamaged", AttachedObject);
AttachedObject.GetType().GetAnyMethod("UpdateColliderState").Invoke(AttachedObject, null);
var damageEffect = AttachedObject.GetValue<DamageEffect>("_damageEffect");
damageEffect.SetEffectBlend(1f);
@ -30,7 +30,7 @@ namespace QSB.ShipSync.WorldObjects
AttachedObject.SetValue("_damaged", false);
AttachedObject.SetValue("_repairFraction", 1f);
AttachedObject.GetType().GetAnyMethod("OnComponentRepaired").Invoke(AttachedObject, null);
QSBWorldSync.RaiseEvent(AttachedObject, "OnRepaired", AttachedObject);
AttachedObject.RaiseEvent("OnRepaired", AttachedObject);
AttachedObject.GetType().GetAnyMethod("UpdateColliderState").Invoke(AttachedObject, null);
var damageEffect = AttachedObject.GetValue<DamageEffect>("_damageEffect");
damageEffect.SetEffectBlend(0f);

View File

@ -4,7 +4,7 @@ using QSB.WorldSync;
namespace QSB.ShipSync.WorldObjects
{
class QSBShipHull : WorldObject<ShipHull>
internal class QSBShipHull : WorldObject<ShipHull>
{
public override void Init(ShipHull hull, int id)
{
@ -16,14 +16,14 @@ namespace QSB.ShipSync.WorldObjects
{
DebugLog.DebugWrite($"[HULL] {AttachedObject} Set damaged.");
AttachedObject.SetValue("_damaged", true);
QSBWorldSync.RaiseEvent(AttachedObject, "OnDamaged", AttachedObject);
AttachedObject.RaiseEvent("OnDamaged", AttachedObject);
}
public void SetRepaired()
{
DebugLog.DebugWrite($"[HULL] {AttachedObject} Set repaired.");
AttachedObject.SetValue("_damaged", false);
QSBWorldSync.RaiseEvent(AttachedObject, "OnRepaired", AttachedObject);
AttachedObject.RaiseEvent("OnRepaired", AttachedObject);
var damageEffect = AttachedObject.GetValue<DamageEffect>("_damageEffect");
damageEffect.SetEffectBlend(0f);
}

View File

@ -1,4 +1,5 @@
using QSB.Events;
using QSB.ClientServerStateSync;
using QSB.Events;
using UnityEngine;
namespace QSB.StatueSync.Events
@ -24,6 +25,15 @@ namespace QSB.StatueSync.Events
CameraDegrees = degrees
};
public override void OnReceiveLocal(bool server, StartStatueMessage message)
{
if (!QSBCore.IsHost)
{
return;
}
QSBEventManager.FireEvent(EventNames.QSBServerState, ServerState.InStatueCutscene);
}
public override void OnReceiveRemote(bool server, StartStatueMessage message)
=> StatueManager.Instance.BeginSequence(message.PlayerPosition, message.PlayerRotation, message.CameraDegrees);
}

View File

@ -12,11 +12,11 @@ namespace QSB.StatueSync
private void Awake()
{
Instance = this;
QSBSceneManager.OnUniverseSceneLoaded += (OWScene scene) => QSBPlayerManager.ShowAllPlayers();
QSBSceneManager.OnUniverseSceneLoaded += (OWScene oldScene, OWScene newScene) => QSBPlayerManager.ShowAllPlayers();
}
private void OnDestroy()
=> QSBSceneManager.OnUniverseSceneLoaded -= (OWScene scene) => QSBPlayerManager.ShowAllPlayers();
=> QSBSceneManager.OnUniverseSceneLoaded -= (OWScene oldScene, OWScene newScene) => QSBPlayerManager.ShowAllPlayers();
public void BeginSequence(Vector3 position, Quaternion rotation, float cameraDegrees)
=> StartCoroutine(BeginRemoteUplinkSequence(position, rotation, cameraDegrees));

View File

@ -3,7 +3,7 @@ using QSB.SectorSync.WorldObjects;
namespace QSB.Syncs
{
public interface ISectoredSync<T> : ISync<T>
public interface ISectoredSync<T>
{
SectorSync.SectorSync SectorSync { get; }
QSBSector ReferenceSector { get; }

View File

@ -1,13 +0,0 @@
using UnityEngine;
namespace QSB.Syncs
{
public interface ISync<T>
{
Transform ReferenceTransform { get; }
T AttachedObject { get; }
bool IsReady { get; }
bool UseInterpolation { get; }
}
}

View File

@ -1,5 +1,6 @@
using OWML.Common;
using QSB.Utility;
using System.Reflection;
using UnityEngine;
namespace QSB.Syncs
@ -43,6 +44,12 @@ namespace QSB.Syncs
public void SetReferenceTransform(Transform transform)
=> _referenceTransform = transform;
/// <summary>
/// Returns the reference transform - what transform this transform is syncing to.
/// </summary>
public Transform GetReferenceTransform()
=> _referenceTransform;
/// <summary>
/// Sets the position of the INVISIBLE transform to be correct, according to the reference sector and the position of the VISIBLE transform.
/// </summary>
@ -51,7 +58,7 @@ namespace QSB.Syncs
{
if (_referenceTransform == null)
{
DebugLog.DebugWrite($"Error - _referenceTransform has not been set for {_attachedTransform.name}", MessageType.Error);
DebugLog.ToConsole($"Error - _referenceTransform has not been set for {_attachedTransform.name} ({MethodBase.GetCurrentMethod().Name})", MessageType.Error);
return;
}
@ -66,7 +73,7 @@ namespace QSB.Syncs
{
if (_referenceTransform == null)
{
DebugLog.DebugWrite($"Error - _referenceTransform has not been set for {_attachedTransform.name}", MessageType.Error);
DebugLog.ToConsole($"Error - _referenceTransform has not been set for {_attachedTransform.name} ({MethodBase.GetCurrentMethod().Name})", MessageType.Error);
return;
}
@ -92,7 +99,7 @@ namespace QSB.Syncs
{
if (_referenceTransform == null)
{
DebugLog.DebugWrite($"Error - _referenceTransform has not been set for {_attachedTransform.name}", MessageType.Error);
DebugLog.ToConsole($"Error - _referenceTransform has not been set for {_attachedTransform.name} ({MethodBase.GetCurrentMethod().Name})", MessageType.Error);
return Vector3.zero;
}
@ -106,7 +113,7 @@ namespace QSB.Syncs
{
if (_referenceTransform == null)
{
DebugLog.DebugWrite($"Error - _referenceTransform has not been set for {_attachedTransform.name}", MessageType.Error);
DebugLog.ToConsole($"Error - _referenceTransform has not been set for {_attachedTransform.name} ({MethodBase.GetCurrentMethod().Name})", MessageType.Error);
return Quaternion.identity;
}

View File

@ -11,6 +11,9 @@ namespace QSB.Syncs.RigidbodySync
public SectorSync.SectorSync SectorSync { get; private set; }
public abstract TargetType Type { get; }
public override bool IgnoreDisabledAttachedObject => false;
public override bool IgnoreNullReferenceTransform => true;
public override void Start()
{
SectorSync = gameObject.AddComponent<SectorSync.SectorSync>();
@ -36,6 +39,11 @@ namespace QSB.Syncs.RigidbodySync
return;
}
if (!HasAuthority)
{
return;
}
var closestSector = SectorSync.GetClosestSector(AttachedObject.transform);
if (closestSector != null)
{
@ -43,7 +51,7 @@ namespace QSB.Syncs.RigidbodySync
}
}
public override void SerializeTransform(QNetworkWriter writer)
public override void SerializeTransform(QNetworkWriter writer, bool initialState)
{
if (_intermediaryTransform == null)
{
@ -59,10 +67,10 @@ namespace QSB.Syncs.RigidbodySync
writer.Write(-1);
}
base.SerializeTransform(writer);
base.SerializeTransform(writer, initialState);
}
public override void DeserializeTransform(QNetworkReader reader)
public override void DeserializeTransform(QNetworkReader reader, bool initialState)
{
if (!QSBCore.WorldObjectsReady)
{
@ -82,12 +90,12 @@ namespace QSB.Syncs.RigidbodySync
SetReferenceSector(sector);
}
base.DeserializeTransform(reader);
base.DeserializeTransform(reader, initialState);
}
protected override void UpdateTransform()
protected override bool UpdateTransform()
{
if ((ReferenceTransform == null || ReferenceSector == null) && QSBSectorManager.Instance.IsReady)
if ((ReferenceTransform == null || ReferenceSector == null || _intermediaryTransform.GetReferenceTransform() == null) && QSBSectorManager.Instance.IsReady && HasAuthority)
{
var closestSector = SectorSync.GetClosestSector(AttachedObject.transform);
if (closestSector != null)
@ -96,11 +104,11 @@ namespace QSB.Syncs.RigidbodySync
}
else
{
return;
return false;
}
}
base.UpdateTransform();
return base.UpdateTransform();
}
public void SetReferenceSector(QSBSector sector)
@ -109,4 +117,4 @@ namespace QSB.Syncs.RigidbodySync
SetReferenceTransform(sector?.Transform);
}
}
}
}

View File

@ -1,38 +1,28 @@
using OWML.Common;
using OWML.Utils;
using QSB.Player.TransformSync;
using QSB.Utility;
using QuantumUNET.Components;
using QuantumUNET.Transport;
using System.Linq;
using UnityEngine;
namespace QSB.Syncs.RigidbodySync
{
public abstract class UnparentedBaseRigidbodySync : QNetworkTransform, ISync<OWRigidbody>
public abstract class UnparentedBaseRigidbodySync : SyncBase
{
public Transform ReferenceTransform { get; set; }
public OWRigidbody AttachedObject { get; set; }
public abstract bool IsReady { get; }
public abstract bool UseInterpolation { get; }
protected virtual float DistanceLeeway { get; } = 5f;
private float _previousDistance;
private const float SmoothTime = 0.1f;
protected bool _isInitialized;
protected IntermediaryTransform _intermediaryTransform;
protected Vector3 _relativeVelocity;
protected Vector3 _relativeAngularVelocity;
protected Vector3 _prevVelocity;
protected Vector3 _prevAngularVelocity;
private string _logName => $"{NetId}:{GetType().Name}";
private Vector3 _positionSmoothVelocity;
private Quaternion _rotationSmoothVelocity;
protected abstract OWRigidbody GetRigidbody();
public virtual void Start()
{
var lowestBound = Resources.FindObjectsOfTypeAll<PlayerTransformSync>()
.Where(x => x.NetId.Value <= NetId.Value).OrderBy(x => x.NetId.Value).Last();
NetIdentity.SetRootIdentity(lowestBound.NetIdentity);
DontDestroyOnLoad(gameObject);
_intermediaryTransform = new IntermediaryTransform(transform);
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
@ -40,10 +30,10 @@ namespace QSB.Syncs.RigidbodySync
protected virtual void OnDestroy() => QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
private void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool isInUniverse)
=> _isInitialized = false;
protected virtual void Init()
protected override void Init()
{
if (!QSBSceneManager.IsInUniverse)
{
@ -54,7 +44,7 @@ namespace QSB.Syncs.RigidbodySync
_isInitialized = true;
}
public override void SerializeTransform(QNetworkWriter writer)
public override void SerializeTransform(QNetworkWriter writer, bool initialState)
{
if (_intermediaryTransform == null)
{
@ -85,7 +75,7 @@ namespace QSB.Syncs.RigidbodySync
_prevAngularVelocity = relativeAngularVelocity;
}
public override void DeserializeTransform(QNetworkReader reader)
public override void DeserializeTransform(QNetworkReader reader, bool initialState)
{
if (!QSBCore.WorldObjectsReady)
{
@ -122,53 +112,15 @@ namespace QSB.Syncs.RigidbodySync
}
}
public override void Update()
{
if (!_isInitialized && IsReady)
{
Init();
}
else if (_isInitialized && !IsReady)
{
_isInitialized = false;
return;
}
if (!_isInitialized)
{
return;
}
if (AttachedObject == null)
{
DebugLog.ToConsole($"Warning - AttachedRigidbody {_logName} is null.", MessageType.Warning);
return;
}
if (!AttachedObject.gameObject.activeInHierarchy)
{
return;
}
if (ReferenceTransform == null)
{
return;
}
UpdateTransform();
base.Update();
}
protected virtual void UpdateTransform()
protected override bool UpdateTransform()
{
if (HasAuthority)
{
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
_relativeVelocity = GetRelativeVelocity();
_relativeAngularVelocity = AttachedObject.GetRelativeAngularVelocity(ReferenceTransform.GetAttachedOWRigidbody());
return;
_relativeAngularVelocity = (AttachedObject as OWRigidbody).GetRelativeAngularVelocity(ReferenceTransform.GetAttachedOWRigidbody());
return true;
}
var targetPos = _intermediaryTransform.GetTargetPosition_Unparented();
@ -176,26 +128,28 @@ namespace QSB.Syncs.RigidbodySync
if (targetPos == Vector3.zero || _intermediaryTransform.GetTargetPosition_ParentedToReference() == Vector3.zero)
{
return;
return false;
}
if (UseInterpolation)
{
AttachedObject.SetPosition(SmartPositionSmoothDamp(AttachedObject.transform.position, targetPos));
AttachedObject.SetRotation(QuaternionHelper.SmoothDamp(AttachedObject.transform.rotation, targetRot, ref _rotationSmoothVelocity, SmoothTime));
(AttachedObject as OWRigidbody).SetPosition(SmartSmoothDamp(AttachedObject.transform.position, targetPos));
(AttachedObject as OWRigidbody).SetRotation(QuaternionHelper.SmoothDamp(AttachedObject.transform.rotation, targetRot, ref _rotationSmoothVelocity, SmoothTime));
}
else
{
AttachedObject.SetPosition(targetPos);
AttachedObject.SetRotation(targetRot);
(AttachedObject as OWRigidbody).SetPosition(targetPos);
(AttachedObject as OWRigidbody).SetRotation(targetRot);
}
var currentVelocity = GetRelativeVelocity();
var targetVelocity = ReferenceTransform.GetAttachedOWRigidbody().GetPointVelocity(targetPos) + _relativeVelocity;
var adjustedTarget = targetVelocity + Locator.GetCenterOfTheUniverse().GetStaticFrameWorldVelocity();
SetVelocity(AttachedObject, targetVelocity);
AttachedObject.SetAngularVelocity(ReferenceTransform.GetAttachedOWRigidbody().GetAngularVelocity() + _relativeAngularVelocity);
SetVelocity((AttachedObject as OWRigidbody), targetVelocity);
(AttachedObject as OWRigidbody).SetAngularVelocity(ReferenceTransform.GetAttachedOWRigidbody().GetAngularVelocity() + _relativeAngularVelocity);
return true;
}
private void SetVelocity(OWRigidbody rigidbody, Vector3 relativeVelocity)
@ -227,21 +181,12 @@ namespace QSB.Syncs.RigidbodySync
ReferenceTransform = transform;
_intermediaryTransform.SetReferenceTransform(transform);
}
// TODO : remove .Distance
private Vector3 SmartPositionSmoothDamp(Vector3 currentPosition, Vector3 targetPosition)
{
var distance = Vector3.Distance(currentPosition, targetPosition);
if (distance > _previousDistance + DistanceLeeway)
if (HasAuthority)
{
DebugLog.DebugWrite($"Warning - {AttachedObject.name} moved too far!", MessageType.Warning);
_previousDistance = distance;
return targetPosition;
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
}
_previousDistance = distance;
return Vector3.SmoothDamp(currentPosition, targetPosition, ref _positionSmoothVelocity, SmoothTime);
}
// TODO : optimize by using sqrMagnitude
@ -299,27 +244,7 @@ namespace QSB.Syncs.RigidbodySync
}
var pointVelocity = attachedRigid.GetPointVelocity(AttachedObject.transform.position);
return AttachedObject.GetVelocity() - pointVelocity;
}
private void OnRenderObject()
{
if (!QSBCore.WorldObjectsReady
|| !QSBCore.DebugMode
|| !QSBCore.ShowLinesInDebug
|| !IsReady
|| ReferenceTransform == null)
{
return;
}
Popcron.Gizmos.Cube(_intermediaryTransform.GetTargetPosition_Unparented(), _intermediaryTransform.GetTargetRotation_Unparented(), Vector3.one / 2, Color.red);
Popcron.Gizmos.Line(_intermediaryTransform.GetTargetPosition_Unparented(), AttachedObject.transform.position, Color.red);
var color = HasMoved() ? Color.green : Color.yellow;
Popcron.Gizmos.Cube(AttachedObject.transform.position, AttachedObject.transform.rotation, Vector3.one / 2, color);
Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceTransform.position, Color.cyan);
Popcron.Gizmos.Line(AttachedObject.transform.position, AttachedObject.transform.position + GetRelativeVelocity(), Color.blue);
return (AttachedObject as OWRigidbody).GetVelocity() - pointVelocity;
}
}
}
}

191
QSB/Syncs/SyncBase.cs Normal file
View File

@ -0,0 +1,191 @@
using OWML.Common;
using QSB.Player;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET.Components;
using UnityEngine;
namespace QSB.Syncs
{
public abstract class SyncBase : QNetworkTransform
{
public uint AttachedNetId
{
get
{
if (NetIdentity == null)
{
DebugLog.ToConsole($"Error - Trying to get AttachedNetId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error);
return uint.MaxValue;
}
return NetIdentity.NetId.Value;
}
}
public uint PlayerId
{
get
{
if (NetIdentity == null)
{
DebugLog.ToConsole($"Error - Trying to get PlayerId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error);
return uint.MaxValue;
}
return NetIdentity.RootIdentity != null
? NetIdentity.RootIdentity.NetId.Value
: AttachedNetId;
}
}
public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId);
private bool _baseIsReady => QSBPlayerManager.PlayerExists(PlayerId)
&& Player != null
&& Player.PlayerStates.IsReady
&& NetId.Value != uint.MaxValue
&& NetId.Value != 0U
&& WorldObjectManager.AllReady;
public abstract bool IsReady { get; }
public abstract bool UseInterpolation { get; }
public abstract bool IgnoreDisabledAttachedObject { get; }
public abstract bool IgnoreNullReferenceTransform { get; }
public Component AttachedObject { get; set; }
public Transform ReferenceTransform { get; set; }
protected string _logName => $"{PlayerId}.{GetType().Name}";
protected virtual float DistanceLeeway { get; } = 5f;
private float _previousDistance;
protected const float SmoothTime = 0.1f;
protected Vector3 _positionSmoothVelocity;
protected Quaternion _rotationSmoothVelocity;
protected IntermediaryTransform _intermediaryTransform;
protected bool _isInitialized;
protected abstract Component InitLocalTransform();
protected abstract Component InitRemoteTransform();
protected abstract bool UpdateTransform();
protected abstract void Init();
protected Vector3 SmartSmoothDamp(Vector3 currentPosition, Vector3 targetPosition)
{
var distance = Vector3.Distance(currentPosition, targetPosition);
if (distance > _previousDistance + DistanceLeeway)
{
_previousDistance = distance;
return targetPosition;
}
_previousDistance = distance;
return Vector3.SmoothDamp(currentPosition, targetPosition, ref _positionSmoothVelocity, SmoothTime);
}
public override void Update()
{
if (!_isInitialized && IsReady && _baseIsReady)
{
Init();
base.Update();
return;
}
else if (_isInitialized && (!IsReady || !_baseIsReady))
{
_isInitialized = false;
base.Update();
return;
}
if (!_isInitialized)
{
base.Update();
return;
}
if (AttachedObject == null)
{
DebugLog.ToConsole($"Warning - AttachedObject {_logName} is null.", MessageType.Warning);
_isInitialized = false;
base.Update();
return;
}
if (ReferenceTransform != null && ReferenceTransform.position == Vector3.zero)
{
DebugLog.ToConsole($"Warning - {_logName}'s ReferenceTransform is at (0,0,0). ReferenceTransform:{ReferenceTransform.name}, AttachedObject:{AttachedObject.name}", MessageType.Warning);
}
if (!AttachedObject.gameObject.activeInHierarchy && !IgnoreDisabledAttachedObject)
{
base.Update();
return;
}
if (ReferenceTransform == null && !IgnoreNullReferenceTransform)
{
DebugLog.ToConsole($"Warning - {_logName}'s ReferenceTransform is null. AttachedObject:{AttachedObject.name}", MessageType.Warning);
base.Update();
return;
}
if (ReferenceTransform != _intermediaryTransform.GetReferenceTransform())
{
DebugLog.ToConsole($"Warning - {_logName}'s ReferenceTransform does not match the reference transform set for the intermediary. ReferenceTransform null : {ReferenceTransform == null}, Intermediary reference null : {_intermediaryTransform.GetReferenceTransform() == null}");
base.Update();
return;
}
var state = UpdateTransform();
if (!state)
{
DebugLog.ToConsole($"{_logName} UpdateTransform() fail.", MessageType.Error);
base.Update();
return;
}
/*
var expectedPosition = _intermediaryTransform.GetTargetPosition_Unparented();
var actualPosition = AttachedObject.transform.position;
var distance = Vector3.Distance(expectedPosition, actualPosition);
if (distance > 20)
{
var intermediaryReference = _intermediaryTransform.GetReferenceTransform();
DebugLog.ToConsole($"Warning - {_logName}'s AttachedObject ({AttachedObject?.name}) is far away from it's expected position! Info:" +
$"\r\n AttachedObject's parent : {AttachedObject?.transform.parent?.name}" +
$"\r\n Distance : {distance}" +
$"\r\n ReferenceTransform : {(ReferenceTransform == null ? "NULL" : ReferenceTransform.name)}" +
$"\r\n Intermediary's ReferenceTransform : {(intermediaryReference == null ? "NULL" : intermediaryReference.name)}", MessageType.Warning);
}
*/
base.Update();
}
protected virtual void OnRenderObject()
{
if (!QSBCore.WorldObjectsReady
|| !QSBCore.DebugMode
|| !QSBCore.ShowLinesInDebug
|| !IsReady
|| ReferenceTransform == null
|| _intermediaryTransform.GetReferenceTransform() == null)
{
return;
}
/* Red Cube = Where visible object should be
* Green/Yellow Cube = Where visible object is
* Magenta cube = Reference transform
* Red Line = Connection between Red Cube and Green/Yellow Cube
* Cyan Line = Connection between Green/Yellow cube and reference transform
*/
Popcron.Gizmos.Cube(_intermediaryTransform.GetTargetPosition_Unparented(), _intermediaryTransform.GetTargetRotation_Unparented(), Vector3.one / 4, Color.red);
Popcron.Gizmos.Line(_intermediaryTransform.GetTargetPosition_Unparented(), AttachedObject.transform.position, Color.red);
var color = HasMoved() ? Color.green : Color.yellow;
Popcron.Gizmos.Cube(AttachedObject.transform.position, AttachedObject.transform.rotation, Vector3.one / 4, color);
Popcron.Gizmos.Cube(ReferenceTransform.position, ReferenceTransform.rotation, Vector3.one / 4, Color.magenta);
Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceTransform.position, Color.cyan);
}
}
}

View File

@ -2,70 +2,44 @@
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.Utility;
using QuantumUNET.Components;
using QuantumUNET;
using QuantumUNET.Transport;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.Syncs.TransformSync
{
/*
* Rewrite number : 5
* Rewrite number : 7
* God has cursed me for my hubris, and my work is never finished.
*/
public abstract class BaseTransformSync : QNetworkTransform, ISync<Transform>
public abstract class BaseTransformSync : SyncBase
{
public uint AttachedNetId
private static readonly Dictionary<PlayerInfo, Dictionary<Type, BaseTransformSync>> _storedTransformSyncs = new Dictionary<PlayerInfo, Dictionary<Type, BaseTransformSync>>();
public static T GetPlayers<T>(PlayerInfo player)
where T : BaseTransformSync
{
get
var dictOfOwnedSyncs = _storedTransformSyncs[player];
var wantedSync = dictOfOwnedSyncs[typeof(T)];
if (wantedSync == default)
{
if (NetIdentity == null)
DebugLog.ToConsole($"Error - _storedTransformSyncs does not contain type:{typeof(T)} under player {player.PlayerId}. Attempting to find manually...", MessageType.Error);
var allSyncs = Resources.FindObjectsOfTypeAll<T>();
wantedSync = allSyncs.First(x => x.Player == player);
if (wantedSync == default)
{
DebugLog.ToConsole($"Error - Trying to get AttachedNetId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error);
return uint.MaxValue;
DebugLog.ToConsole($"Error - Could not find type:{typeof(T)} for player {player.PlayerId} manually!", MessageType.Error);
return default;
}
return NetIdentity.NetId.Value;
}
return (T)wantedSync;
}
public uint PlayerId
{
get
{
if (NetIdentity == null)
{
DebugLog.ToConsole($"Error - Trying to get PlayerId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error);
return uint.MaxValue;
}
return NetIdentity.RootIdentity != null
? NetIdentity.RootIdentity.NetId.Value
: AttachedNetId;
}
}
public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId);
public Transform ReferenceTransform { get; set; }
public Transform AttachedObject { get; set; }
public abstract bool IsReady { get; }
public abstract bool UseInterpolation { get; }
protected abstract Transform InitLocalTransform();
protected abstract Transform InitRemoteTransform();
protected bool _isInitialized;
private const float SmoothTime = 0.1f;
protected virtual float DistanceLeeway { get; } = 5f;
private float _previousDistance;
private Vector3 _positionSmoothVelocity;
private Quaternion _rotationSmoothVelocity;
private string _logName => $"{PlayerId}.{GetType().Name}";
protected IntermediaryTransform _intermediaryTransform;
public virtual void Start()
{
var lowestBound = Resources.FindObjectsOfTypeAll<PlayerTransformSync>()
@ -75,6 +49,14 @@ namespace QSB.Syncs.TransformSync
DontDestroyOnLoad(gameObject);
_intermediaryTransform = new IntermediaryTransform(transform);
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
if (!_storedTransformSyncs.ContainsKey(Player))
{
_storedTransformSyncs.Add(Player, new Dictionary<Type, BaseTransformSync>());
}
var playerDict = _storedTransformSyncs[Player];
playerDict[GetType()] = this;
}
protected virtual void OnDestroy()
@ -85,12 +67,20 @@ namespace QSB.Syncs.TransformSync
}
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
if (!QSBPlayerManager.PlayerExists(PlayerId))
{
return;
}
var playerDict = _storedTransformSyncs[Player];
playerDict.Remove(GetType());
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
protected virtual void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool isInUniverse)
=> _isInitialized = false;
protected virtual void Init()
protected override void Init()
{
if (!QSBSceneManager.IsInUniverse)
{
@ -104,9 +94,47 @@ namespace QSB.Syncs.TransformSync
AttachedObject = HasAuthority ? InitLocalTransform() : InitRemoteTransform();
_isInitialized = true;
if (QSBCore.DebugMode)
{
DebugBoxManager.CreateBox(AttachedObject.transform, 0, _logName);
}
}
public override void SerializeTransform(QNetworkWriter writer)
public override bool OnSerialize(QNetworkWriter writer, bool initialState)
{
if (!initialState)
{
if (SyncVarDirtyBits == 0U)
{
writer.WritePackedUInt32(0U);
return false;
}
writer.WritePackedUInt32(1U);
}
SerializeTransform(writer, initialState);
return true;
}
public override void OnDeserialize(QNetworkReader reader, bool initialState)
{
if (!IsServer || !QNetworkServer.localClientActive)
{
if (!initialState)
{
if (reader.ReadPackedUInt32() == 0U)
{
return;
}
}
DeserializeTransform(reader, initialState);
}
}
public override void SerializeTransform(QNetworkWriter writer, bool initialState)
{
if (_intermediaryTransform == null)
{
@ -121,7 +149,7 @@ namespace QSB.Syncs.TransformSync
_prevRotation = worldRot;
}
public override void DeserializeTransform(QNetworkReader reader)
public override void DeserializeTransform(QNetworkReader reader, bool initialState)
{
if (!QSBCore.WorldObjectsReady)
{
@ -152,51 +180,13 @@ namespace QSB.Syncs.TransformSync
}
}
public override void Update()
{
if (!_isInitialized && IsReady)
{
Init();
}
else if (_isInitialized && !IsReady)
{
_isInitialized = false;
return;
}
if (!_isInitialized)
{
return;
}
if (AttachedObject == null)
{
DebugLog.ToConsole($"Warning - AttachedObject {_logName} is null.", MessageType.Warning);
return;
}
if (!AttachedObject.gameObject.activeInHierarchy)
{
return;
}
if (ReferenceTransform == null)
{
return;
}
UpdateTransform();
base.Update();
}
protected virtual void UpdateTransform()
protected override bool UpdateTransform()
{
if (HasAuthority)
{
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
return;
return true;
}
var targetPos = _intermediaryTransform.GetTargetPosition_ParentedToReference();
@ -214,6 +204,7 @@ namespace QSB.Syncs.TransformSync
AttachedObject.transform.localRotation = targetRot;
}
}
return true;
}
public override bool HasMoved()
@ -245,50 +236,23 @@ namespace QSB.Syncs.TransformSync
{
ReparentAttachedObject(transform);
}
if (HasAuthority)
{
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
}
}
private void ReparentAttachedObject(Transform sectorTransform)
private void ReparentAttachedObject(Transform newParent)
{
if (AttachedObject.transform.parent != null && AttachedObject.transform.parent.GetComponent<Sector>() == null)
{
DebugLog.ToConsole($"Warning - Trying to reparent AttachedObject {AttachedObject.name} which wasnt attached to sector!", MessageType.Warning);
}
AttachedObject.transform.SetParent(sectorTransform, true);
AttachedObject.transform.localScale = GetType() == typeof(PlayerTransformSync)
? Vector3.one / 10
: Vector3.one;
}
private Vector3 SmartSmoothDamp(Vector3 currentPosition, Vector3 targetPosition)
{
var distance = Vector3.Distance(currentPosition, targetPosition);
if (distance > _previousDistance + DistanceLeeway)
{
_previousDistance = distance;
return targetPosition;
}
_previousDistance = distance;
return Vector3.SmoothDamp(currentPosition, targetPosition, ref _positionSmoothVelocity, SmoothTime);
}
private void OnRenderObject()
{
if (!QSBCore.WorldObjectsReady
|| !QSBCore.DebugMode
|| !QSBCore.ShowLinesInDebug
|| !IsReady
|| ReferenceTransform == null)
{
return;
}
Popcron.Gizmos.Cube(_intermediaryTransform.GetTargetPosition_Unparented(), _intermediaryTransform.GetTargetRotation_Unparented(), Vector3.one / 2, Color.red);
Popcron.Gizmos.Line(_intermediaryTransform.GetTargetPosition_Unparented(), AttachedObject.transform.position, Color.red);
var color = HasMoved() ? Color.green : Color.yellow;
Popcron.Gizmos.Cube(AttachedObject.transform.position, AttachedObject.transform.rotation, Vector3.one / 2, color);
Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceTransform.position, Color.cyan);
AttachedObject.transform.SetParent(newParent, true);
AttachedObject.transform.localScale = Vector3.one;
}
}
}

View File

@ -1,5 +1,7 @@
using QSB.SectorSync;
using QSB.Player;
using QSB.SectorSync;
using QSB.SectorSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET.Transport;
using UnityEngine;
@ -12,6 +14,11 @@ namespace QSB.Syncs.TransformSync
public SectorSync.SectorSync SectorSync { get; private set; }
public abstract TargetType Type { get; }
public override bool IgnoreNullReferenceTransform => true;
public override bool IgnoreDisabledAttachedObject => false;
private int _sectorIdWaitingSlot = int.MinValue;
public override void Start()
{
SectorSync = gameObject.AddComponent<SectorSync.SectorSync>();
@ -37,58 +44,146 @@ namespace QSB.Syncs.TransformSync
return;
}
if (!HasAuthority)
{
return;
}
var closestSector = SectorSync.GetClosestSector(AttachedObject.transform);
if (closestSector != null)
{
SetReferenceTransform(closestSector.Transform);
SetReferenceSector(closestSector);
}
else
{
DebugLog.DebugWrite($"INIT - {PlayerId}.{GetType().Name}'s closest sector is null!");
}
}
public override void SerializeTransform(QNetworkWriter writer)
public override void Update()
{
if (_sectorIdWaitingSlot == int.MinValue)
{
base.Update();
return;
}
if (!WorldObjectManager.AllReady)
{
base.Update();
return;
}
var sector = _sectorIdWaitingSlot == -1
? null
: QSBWorldSync.GetWorldFromId<QSBSector>(_sectorIdWaitingSlot);
if (sector != ReferenceSector)
{
if (sector == null)
{
DebugLog.ToConsole($"Error - {PlayerId}.{GetType().Name} got sector of ID -1.", OWML.Common.MessageType.Error);
base.Update();
return;
}
SetReferenceSector(sector);
}
_sectorIdWaitingSlot = int.MinValue;
base.Update();
}
public override void SerializeTransform(QNetworkWriter writer, bool initialState)
{
if (_intermediaryTransform == null)
{
_intermediaryTransform = new IntermediaryTransform(transform);
}
if (!QSBPlayerManager.PlayerExists(PlayerId))
{
DebugLog.ToConsole($"Warning - Tried to serialize {_logName} before the right player exists.", OWML.Common.MessageType.Warning);
writer.Write(-1);
}
else if (!Player.PlayerStates.IsReady)
{
DebugLog.ToConsole($"Warning - Tried to serialize {_logName} before the player was ready.", OWML.Common.MessageType.Warning);
writer.Write(-1);
}
if (ReferenceSector != null)
{
writer.Write(ReferenceSector.ObjectId);
}
else
{
DebugLog.ToConsole($"Warning - ReferenceSector of {PlayerId}.{GetType().Name} is null.", OWML.Common.MessageType.Warning);
writer.Write(-1);
}
base.SerializeTransform(writer);
base.SerializeTransform(writer, initialState);
}
public override void DeserializeTransform(QNetworkReader reader)
public override void DeserializeTransform(QNetworkReader reader, bool initialState)
{
int sectorId;
if (!QSBCore.WorldObjectsReady)
{
reader.ReadInt32();
sectorId = reader.ReadInt32();
if (initialState && sectorId != -1)
{
DebugLog.DebugWrite($"SET WAITING FOR SECTOR SET - id {sectorId}");
_sectorIdWaitingSlot = sectorId;
}
reader.ReadVector3();
DeserializeRotation(reader);
return;
}
var sectorId = reader.ReadInt32();
sectorId = reader.ReadInt32();
var sector = sectorId == -1
? null
: QSBWorldSync.GetWorldFromId<QSBSector>(sectorId);
if (sector != ReferenceSector)
{
if (sector == null)
{
DebugLog.ToConsole($"Error - {PlayerId}.{GetType().Name} got sector of ID -1.", OWML.Common.MessageType.Error);
base.DeserializeTransform(reader, initialState);
return;
}
SetReferenceSector(sector);
}
base.DeserializeTransform(reader);
base.DeserializeTransform(reader, initialState);
}
protected override void UpdateTransform()
protected override bool UpdateTransform()
{
if ((ReferenceTransform == null || ReferenceSector == null) && QSBSectorManager.Instance.IsReady)
var referenceNull = ReferenceTransform == null || ReferenceSector == null || _intermediaryTransform.GetReferenceTransform() == null;
var sectorManagerReady = QSBSectorManager.Instance.IsReady;
if (!sectorManagerReady)
{
if (referenceNull && HasAuthority)
{
DebugLog.ToConsole($"Warning - Reference was null, but sector manager wasn't ready. " +
$"Transform:{ReferenceTransform == null}, Sector:{ReferenceSector == null}, Intermediary:{_intermediaryTransform.GetReferenceTransform() == null}",
OWML.Common.MessageType.Warning);
}
return base.UpdateTransform();
}
if (!HasAuthority)
{
return base.UpdateTransform();
}
if (referenceNull)
{
var closestSector = SectorSync.GetClosestSector(AttachedObject.transform);
if (closestSector != null)
@ -97,11 +192,12 @@ namespace QSB.Syncs.TransformSync
}
else
{
return;
DebugLog.ToConsole($"Error - No closest sector found to {PlayerId}.{GetType().Name}!", OWML.Common.MessageType.Error);
return false;
}
}
base.UpdateTransform();
return base.UpdateTransform();
}
public void SetReferenceSector(QSBSector sector)

Some files were not shown because too many files have changed in this diff Show More