Merge pull request #287 from misternebula/animations

Fix transform sync, fix orbs, fix quantum objects, add land anim, add head tracking
This commit is contained in:
_nebula 2021-04-28 16:33:26 +01:00 committed by GitHub
commit 9c76f0420e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 987 additions and 545 deletions

View File

@ -0,0 +1,11 @@
using QSB.Animation.Character.WorldObjects;
using QSB.WorldSync;
namespace QSB.Animation.Character
{
internal class CharacterAnimManager : WorldObjectManager
{
protected override void RebuildWorldObjects(OWScene scene)
=> QSBWorldSync.Init<QSBCharacterAnimController, CharacterAnimController>();
}
}

View File

@ -0,0 +1,111 @@
using OWML.Common;
using QSB.Animation.Character.WorldObjects;
using QSB.Events;
using QSB.Patches;
using QSB.Player;
using QSB.Utility;
using QSB.WorldSync;
using UnityEngine;
namespace QSB.ConversationSync.Patches
{
public class CharacterAnimationPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public override void DoPatches()
{
QSBCore.HarmonyHelper.AddPrefix<CharacterAnimController>("OnAnimatorIK", typeof(CharacterAnimationPatches), nameof(AnimController_OnAnimatorIK));
QSBCore.HarmonyHelper.AddPrefix<CharacterAnimController>("OnZoneEntry", typeof(CharacterAnimationPatches), nameof(AnimController_OnZoneEntry));
QSBCore.HarmonyHelper.AddPrefix<CharacterAnimController>("OnZoneExit", typeof(CharacterAnimationPatches), nameof(AnimController_OnZoneExit));
}
public override void DoUnpatches()
{
QSBCore.HarmonyHelper.Unpatch<CharacterAnimController>("OnAnimatorIK");
QSBCore.HarmonyHelper.Unpatch<CharacterAnimController>("OnZoneExit");
}
public static bool AnimController_OnAnimatorIK(
CharacterAnimController __instance,
float ___headTrackingWeight,
bool ___lookOnlyWhenTalking,
bool ____playerInHeadZone,
bool ____inConversation,
ref float ____currentLookWeight,
ref Vector3 ____currentLookTarget,
DampedSpring3D ___lookSpring,
Animator ____animator,
CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
var qsbObj = QSBWorldSync.GetWorldFromUnity<QSBCharacterAnimController, CharacterAnimController>(__instance); // TODO : maybe cache this somewhere... or assess how slow this is
Vector3 position;
if (____inConversation)
{
if (playerId == uint.MaxValue)
{
DebugLog.DebugWrite($"Error - {__instance.name} is in conversation with a null player! Defaulting to active camera.", MessageType.Error);
position = Locator.GetActiveCamera().transform.position;
}
else
{
var player = QSBPlayerManager.GetPlayer(playerId);
position = player.CameraBody == null
? Locator.GetActiveCamera().transform.position
: player.CameraBody.transform.position;
}
}
else if (!___lookOnlyWhenTalking && qsbObj.GetPlayersInHeadZone().Count != 0)
{
position = QSBPlayerManager.GetClosestPlayerToWorldPoint(qsbObj.GetPlayersInHeadZone(), __instance.transform.position).CameraBody.transform.position;
}
else
{
position = QSBPlayerManager.GetClosestPlayerToWorldPoint(__instance.transform.position, true).CameraBody.transform.position;
}
var localPosition = ____animator.transform.InverseTransformPoint(position);
var targetWeight = ___headTrackingWeight;
if (___lookOnlyWhenTalking)
{
if (!____inConversation || qsbObj.GetPlayersInHeadZone().Count == 0)
{
targetWeight *= 0;
}
}
else
{
if (qsbObj.GetPlayersInHeadZone().Count == 0)
{
targetWeight *= 0;
}
}
____currentLookWeight = Mathf.Lerp(____currentLookWeight, targetWeight, Time.deltaTime * 2f);
____currentLookTarget = ___lookSpring.Update(____currentLookTarget, localPosition, Time.deltaTime);
____animator.SetLookAtPosition(____animator.transform.TransformPoint(____currentLookTarget));
____animator.SetLookAtWeight(____currentLookWeight);
return false;
}
public static bool AnimController_OnZoneExit(CharacterAnimController __instance)
{
var qsbObj = QSBWorldSync.GetWorldFromUnity<QSBCharacterAnimController, CharacterAnimController>(__instance);
QSBEventManager.FireEvent(EventNames.QSBExitHeadZone, qsbObj.ObjectId);
return false;
}
public static bool AnimController_OnZoneEntry(CharacterAnimController __instance)
{
var qsbObj = QSBWorldSync.GetWorldFromUnity<QSBCharacterAnimController, CharacterAnimController>(__instance);
QSBEventManager.FireEvent(EventNames.QSBEnterHeadZone, qsbObj.ObjectId);
return false;
}
}
}

View File

@ -0,0 +1,51 @@
using OWML.Utils;
using QSB.Player;
using QSB.WorldSync;
using System.Collections.Generic;
namespace QSB.Animation.Character.WorldObjects
{
internal class QSBCharacterAnimController : WorldObject<CharacterAnimController>
{
private readonly List<PlayerInfo> _playersInHeadZone = new List<PlayerInfo>();
public override void Init(CharacterAnimController controller, int id)
{
ObjectId = id;
AttachedObject = controller;
}
public List<PlayerInfo> GetPlayersInHeadZone()
=> _playersInHeadZone;
public void AddPlayerToHeadZone(PlayerInfo player)
{
if (_playersInHeadZone.Contains(player))
{
return;
}
_playersInHeadZone.Add(player);
}
public void RemovePlayerFromHeadZone(PlayerInfo player)
{
if (!_playersInHeadZone.Contains(player))
{
return;
}
_playersInHeadZone.Remove(player);
}
public void StartConversation()
{
AttachedObject.SetValue("_inConversation", true);
QSBWorldSync.RaiseEvent(AttachedObject, "OnStartConversation");
}
public void EndConversation()
{
AttachedObject.SetValue("_inConversation", false);
QSBWorldSync.RaiseEvent(AttachedObject, "OnEndConversation");
}
}
}

View File

@ -1,7 +1,7 @@
using OWML.Utils;
using UnityEngine;
namespace QSB.Animation
namespace QSB.Animation.Player
{
public static class AnimControllerPatch
{

View File

@ -1,6 +1,6 @@
using UnityEngine;
namespace QSB.Animation
namespace QSB.Animation.Player
{
public class AnimFloatParam
{

View File

@ -7,13 +7,10 @@ using QuantumUNET.Components;
using System.Linq;
using UnityEngine;
namespace QSB.Animation
namespace QSB.Animation.Player
{
public class AnimationSync : PlayerSyncObject
{
private Animator _anim;
private QNetworkAnimator _netAnim;
private RuntimeAnimatorController _suitedAnimController;
private AnimatorOverrideController _unsuitedAnimController;
private GameObject _suitedGraphics;
@ -30,13 +27,15 @@ namespace QSB.Animation
public AnimatorMirror Mirror { get; private set; }
public AnimationType CurrentType { get; set; }
public Animator VisibleAnimator { get; private set; }
public Animator InvisibleAnimator { get; private set; }
public QNetworkAnimator NetworkAnimator { get; private set; }
protected void Awake()
{
_anim = gameObject.AddComponent<Animator>();
_netAnim = gameObject.AddComponent<QNetworkAnimator>();
_netAnim.enabled = false;
_netAnim.animator = _anim;
InvisibleAnimator = gameObject.AddComponent<Animator>();
NetworkAnimator = gameObject.AddComponent<QNetworkAnimator>();
NetworkAnimator.enabled = false;
NetworkAnimator.animator = InvisibleAnimator;
QSBSceneManager.OnUniverseSceneLoaded += OnUniverseSceneLoaded;
}
@ -44,16 +43,9 @@ namespace QSB.Animation
protected override void OnDestroy()
{
base.OnDestroy();
Destroy(_anim);
Destroy(_netAnim);
Destroy(InvisibleAnimator);
Destroy(NetworkAnimator);
QSBSceneManager.OnUniverseSceneLoaded -= OnUniverseSceneLoaded;
if (_playerController == null)
{
return;
}
_playerController.OnJump -= OnJump;
_playerController.OnBecomeGrounded -= OnBecomeGrounded;
_playerController.OnBecomeUngrounded -= OnBecomeUngrounded;
}
private void OnUniverseSceneLoaded(OWScene obj) => LoadControllers();
@ -71,21 +63,21 @@ namespace QSB.Animation
{
LoadControllers();
}
_netAnim.enabled = true;
NetworkAnimator.enabled = true;
VisibleAnimator = body.GetComponent<Animator>();
Mirror = body.gameObject.AddComponent<AnimatorMirror>();
if (IsLocalPlayer)
{
Mirror.Init(VisibleAnimator, _anim);
Mirror.Init(VisibleAnimator, InvisibleAnimator);
}
else
{
Mirror.Init(_anim, VisibleAnimator);
Mirror.Init(InvisibleAnimator, VisibleAnimator);
}
for (var i = 0; i < _anim.parameterCount; i++)
for (var i = 0; i < InvisibleAnimator.parameterCount; i++)
{
_netAnim.SetParameterAutoSend(i, true);
NetworkAnimator.SetParameterAutoSend(i, true);
}
var playerAnimController = body.GetComponent<PlayerAnimController>();
@ -100,9 +92,6 @@ namespace QSB.Animation
InitCommon(body);
_playerController = body.parent.GetComponent<PlayerCharacterController>();
_playerController.OnJump += OnJump;
_playerController.OnBecomeGrounded += OnBecomeGrounded;
_playerController.OnBecomeUngrounded += OnBecomeUngrounded;
InitCrouchSync();
}
@ -140,12 +129,6 @@ namespace QSB.Animation
_crouchSync.Init(this, _playerController, VisibleAnimator);
}
private void OnJump() => _netAnim.SetTrigger("Jump");
private void OnBecomeGrounded() => _netAnim.SetTrigger("Grounded");
private void OnBecomeUngrounded() => _netAnim.SetTrigger("Ungrounded");
public void SendCrouch(float value = 0) => QSBEventManager.FireEvent(EventNames.QSBCrouch, value);
public void HandleCrouch(float value) => _crouchSync.CrouchParam.Target = value;
@ -226,24 +209,24 @@ namespace QSB.Animation
controller = _riebeckController;
break;
}
_anim.runtimeAnimatorController = controller;
InvisibleAnimator.runtimeAnimatorController = controller;
VisibleAnimator.runtimeAnimatorController = controller;
if (type != AnimationType.PlayerSuited && type != AnimationType.PlayerUnsuited)
{
VisibleAnimator.SetTrigger("Playing");
_anim.SetTrigger("Playing");
InvisibleAnimator.SetTrigger("Playing");
}
else
{
// Avoids "jumping" when exiting instrument and putting on suit
VisibleAnimator.SetTrigger("Grounded");
_anim.SetTrigger("Grounded");
InvisibleAnimator.SetTrigger("Grounded");
}
_netAnim.animator = _anim; // Probably not needed.
NetworkAnimator.animator = InvisibleAnimator; // Probably not needed.
Mirror.RebuildFloatParams();
for (var i = 0; i < _anim.parameterCount; i++)
for (var i = 0; i < InvisibleAnimator.parameterCount; i++)
{
_netAnim.SetParameterAutoSend(i, true);
NetworkAnimator.SetParameterAutoSend(i, true);
}
}
}

View File

@ -1,4 +1,4 @@
namespace QSB.Animation
namespace QSB.Animation.Player
{
public enum AnimationType
{

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.Animation
namespace QSB.Animation.Player
{
public class AnimatorMirror : MonoBehaviour
{

View File

@ -2,7 +2,7 @@
using System;
using UnityEngine;
namespace QSB.Animation
namespace QSB.Animation.Player
{
public class CrouchSync : QNetworkBehaviour
{

View File

@ -0,0 +1,28 @@
using QSB.Events;
using QSB.Player;
namespace QSB.Animation.Player.Events
{
internal class AnimationTriggerEvent : QSBEvent<AnimationTriggerMessage>
{
public override EventType Type => EventType.AnimTrigger;
public override void SetupListener() => GlobalMessenger<uint, string>.AddListener(EventNames.QSBAnimTrigger, Handler);
public override void CloseListener() => GlobalMessenger<uint, string>.RemoveListener(EventNames.QSBAnimTrigger, Handler);
private void Handler(uint attachedNetId, string name) => SendEvent(CreateMessage(attachedNetId, name));
private AnimationTriggerMessage CreateMessage(uint attachedNetId, string name) => new AnimationTriggerMessage
{
AboutId = LocalPlayerId,
AttachedNetId = attachedNetId,
Name = name
};
public override void OnReceiveRemote(bool server, AnimationTriggerMessage message)
{
var animationSync = QSBPlayerManager.GetSyncObject<AnimationSync>(message.AttachedNetId);
animationSync.VisibleAnimator.SetTrigger(message.Name);
}
}
}

View File

@ -0,0 +1,25 @@
using QSB.Messaging;
using QuantumUNET.Transport;
namespace QSB.Animation.Player.Events
{
public class AnimationTriggerMessage : PlayerMessage
{
public uint AttachedNetId { get; set; }
public string Name { get; set; }
public override void Deserialize(QNetworkReader reader)
{
base.Deserialize(reader);
AttachedNetId = reader.ReadUInt32();
Name = reader.ReadString();
}
public override void Serialize(QNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(AttachedNetId);
writer.Write(Name);
}
}
}

View File

@ -3,7 +3,7 @@ using QSB.Instruments;
using QSB.Messaging;
using QSB.Player;
namespace QSB.Animation.Events
namespace QSB.Animation.Player.Events
{
public class ChangeAnimTypeEvent : QSBEvent<EnumMessage<AnimationType>>
{

View File

@ -2,11 +2,11 @@
using QSB.Messaging;
using QSB.Player;
namespace QSB.Animation.Events
namespace QSB.Animation.Player.Events
{
public class CrouchEvent : QSBEvent<FloatMessage>
{
public override EventType Type => EventType.AnimTrigger;
public override EventType Type => EventType.Crouch;
public override void SetupListener() => GlobalMessenger<float>.AddListener(EventNames.QSBCrouch, Handler);
public override void CloseListener() => GlobalMessenger<float>.RemoveListener(EventNames.QSBCrouch, Handler);

View File

@ -2,7 +2,7 @@
using QSB.Messaging;
using QSB.Player;
namespace QSB.Animation.Events
namespace QSB.Animation.Player.Events
{
public class PlayerSuitEvent : QSBEvent<ToggleMessage>
{

View File

@ -0,0 +1,122 @@
using QSB.Events;
using QSB.Patches;
using QSB.Player;
using QSB.WorldSync;
using UnityEngine;
namespace QSB.Animation.Patches
{
internal class PlayerAnimationPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public override void DoPatches() => QSBCore.HarmonyHelper.AddPrefix<PlayerAnimController>("LateUpdate", typeof(PlayerAnimationPatches), nameof(PlayerAnimController_LateUpdate));
public override void DoUnpatches() => QSBCore.HarmonyHelper.Unpatch<PlayerAnimController>("LateUpdate");
public static bool PlayerAnimController_LateUpdate(
PlayerAnimController __instance,
PlayerCharacterController ____playerController,
ThrusterModel ____playerJetpack,
ref float ____ungroundedTime,
Animator ____animator,
ref bool ____justBecameGrounded,
ref bool ____justTookFallDamage,
ref bool ____leftFootGrounded,
ref bool ____rightFootGrounded,
ref bool ____rightArmHidden,
GameObject[] ____rightArmObjects,
int ____defaultLayer,
int ____probeOnlyLayer)
{
var isGrounded = ____playerController.IsGrounded();
var isAttached = PlayerState.IsAttached();
var isInZeroG = PlayerState.InZeroG();
var isFlying = ____playerJetpack.GetLocalAcceleration().y > 0f;
var movementVector = Vector3.zero;
if (!isAttached)
{
movementVector = ____playerController.GetRelativeGroundVelocity();
}
if (Mathf.Abs(movementVector.x) < 0.05f)
{
movementVector.x = 0f;
}
if (Mathf.Abs(movementVector.z) < 0.05f)
{
movementVector.z = 0f;
}
if (isFlying)
{
____ungroundedTime = Time.time;
}
var freefallMagnitude = 0f;
var timeInFreefall = 0f;
var lastGroundBody = ____playerController.GetLastGroundBody();
if (!isGrounded && !isAttached && !isInZeroG && lastGroundBody != null)
{
freefallMagnitude = (____playerController.GetAttachedOWRigidbody(false).GetVelocity() - lastGroundBody.GetPointVelocity(____playerController.transform.position)).magnitude;
timeInFreefall = Time.time - ____ungroundedTime;
}
____animator.SetFloat("RunSpeedX", movementVector.x / 3f);
____animator.SetFloat("RunSpeedY", movementVector.z / 3f);
____animator.SetFloat("TurnSpeed", ____playerController.GetTurning());
____animator.SetBool("Grounded", isGrounded || isAttached || PlayerState.IsRecentlyDetached());
____animator.SetLayerWeight(1, ____playerController.GetJumpChargeFraction());
____animator.SetFloat("FreefallSpeed", freefallMagnitude / 15f * (timeInFreefall / 3f));
____animator.SetBool("InZeroG", isInZeroG || isFlying);
____animator.SetBool("UsingJetpack", isInZeroG && PlayerState.IsWearingSuit());
if (____justBecameGrounded)
{
var playerAnimationSync = QSBPlayerManager.LocalPlayer.AnimationSync;
if (____justTookFallDamage)
{
____animator.SetTrigger("LandHard");
QSBEventManager.FireEvent(EventNames.QSBAnimTrigger, playerAnimationSync.AttachedNetId, "LandHard");
}
else
{
____animator.SetTrigger("Land");
QSBEventManager.FireEvent(EventNames.QSBAnimTrigger, playerAnimationSync.AttachedNetId, "Land");
}
}
if (isGrounded)
{
var leftFootLift = ____animator.GetFloat("LeftFootLift");
if (!____leftFootGrounded && leftFootLift < 0.333f)
{
____leftFootGrounded = true;
QSBWorldSync.RaiseEvent(__instance, "OnLeftFootGrounded");
}
else if (____leftFootGrounded && leftFootLift > 0.666f)
{
____leftFootGrounded = false;
QSBWorldSync.RaiseEvent(__instance, "OnLeftFootLift");
}
var rightFootLift = ____animator.GetFloat("RightFootLift");
if (!____rightFootGrounded && rightFootLift < 0.333f)
{
____rightFootGrounded = true;
QSBWorldSync.RaiseEvent(__instance, "OnRightFootGrounded");
}
else if (____rightFootGrounded && rightFootLift > 0.666f)
{
____rightFootGrounded = false;
QSBWorldSync.RaiseEvent(__instance, "OnRightFootLift");
}
}
____justBecameGrounded = false;
____justTookFallDamage = false;
var usingTool = Locator.GetToolModeSwapper().GetToolMode() != ToolMode.None;
if ((usingTool && !____rightArmHidden) || (!usingTool && ____rightArmHidden))
{
____rightArmHidden = usingTool;
for (var i = 0; i < ____rightArmObjects.Length; i++)
{
____rightArmObjects[i].layer = (!____rightArmHidden) ? ____defaultLayer : ____probeOnlyLayer;
}
}
return false;
}
}
}

View File

@ -2,7 +2,7 @@
using QSB.Utility;
using UnityEngine;
namespace QSB.Animation
namespace QSB.Animation.Player
{
public class PlayerHeadRotationSync : MonoBehaviour
{

View File

@ -1,5 +1,6 @@
using OWML.Common;
using OWML.Utils;
using QSB.Animation.Character.WorldObjects;
using QSB.Events;
using QSB.Player;
using QSB.Utility;
@ -64,12 +65,8 @@ namespace QSB.ConversationSync.Events
CharacterDialogueTree tree)
{
QSBPlayerManager.GetPlayer(playerId).CurrentDialogueID = characterId;
controller.SetValue("_inConversation", true);
controller.SetValue("_playerInHeadZone", true);
if (controller.GetValue<bool>("_hasTalkAnimation"))
{
controller.GetValue<Animator>("_animator").SetTrigger("Talking");
}
var qsbObj = QSBWorldSync.GetWorldFromUnity<QSBCharacterAnimController, CharacterAnimController>(controller);
qsbObj.StartConversation();
tree.GetInteractVolume().DisableInteraction();
}
@ -79,12 +76,8 @@ namespace QSB.ConversationSync.Events
CharacterDialogueTree tree)
{
QSBPlayerManager.GetPlayer(playerId).CurrentDialogueID = -1;
controller.SetValue("_inConversation", false);
controller.SetValue("_playerInHeadZone", false);
if (controller.GetValue<bool>("_hasTalkAnimation"))
{
controller.GetValue<Animator>("_animator").SetTrigger("Idle");
}
var qsbObj = QSBWorldSync.GetWorldFromUnity<QSBCharacterAnimController, CharacterAnimController>(controller);
qsbObj.EndConversation();
tree.GetInteractVolume().EnableInteraction();
}
}

View File

@ -4,7 +4,6 @@ using QSB.Player;
using QSB.Utility;
using QSB.WorldSync;
using System.Collections.Generic;
using UnityEngine;
namespace QSB.ConversationSync.Patches
{
@ -18,8 +17,6 @@ namespace QSB.ConversationSync.Patches
QSBCore.HarmonyHelper.AddPrefix<CharacterDialogueTree>("InputDialogueOption", typeof(ConversationPatches), nameof(Tree_InputDialogueOption));
QSBCore.HarmonyHelper.AddPostfix<CharacterDialogueTree>("StartConversation", typeof(ConversationPatches), nameof(Tree_StartConversation));
QSBCore.HarmonyHelper.AddPrefix<CharacterDialogueTree>("EndConversation", typeof(ConversationPatches), nameof(Tree_EndConversation));
QSBCore.HarmonyHelper.AddPrefix<CharacterAnimController>("OnAnimatorIK", typeof(ConversationPatches), nameof(AnimController_OnAnimatorIK));
QSBCore.HarmonyHelper.AddPrefix<CharacterAnimController>("OnZoneExit", typeof(ConversationPatches), nameof(AnimController_OnZoneExit));
}
public override void DoUnpatches()
@ -28,8 +25,6 @@ namespace QSB.ConversationSync.Patches
QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("InputDialogueOption");
QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("StartConversation");
QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("EndConversation");
QSBCore.HarmonyHelper.Unpatch<CharacterAnimController>("OnAnimatorIK");
QSBCore.HarmonyHelper.Unpatch<CharacterAnimController>("OnZoneExit");
}
public static void Tree_StartConversation(CharacterDialogueTree __instance)
@ -82,45 +77,5 @@ namespace QSB.ConversationSync.Patches
QSBCore.UnityEvents.RunWhen(() => QSBPlayerManager.LocalPlayer.CurrentDialogueID != -1,
() => ConversationManager.Instance.SendCharacterDialogue(QSBPlayerManager.LocalPlayer.CurrentDialogueID, key));
}
public static bool AnimController_OnAnimatorIK(float ___headTrackingWeight,
bool ___lookOnlyWhenTalking,
bool ____playerInHeadZone,
bool ____inConversation,
ref float ____currentLookWeight,
ref Vector3 ____currentLookTarget,
DampedSpring3D ___lookSpring,
Animator ____animator,
CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
Vector3 position;
if (playerId == uint.MaxValue)
{
position = Locator.GetActiveCamera().transform.position;
}
else
{
var player = QSBPlayerManager.GetPlayer(playerId);
position = player.CameraBody == null
? Locator.GetActiveCamera().transform.position
: player.CameraBody.transform.position;
}
var localPosition = ____animator.transform.InverseTransformPoint(position);
var targetWeight = ___headTrackingWeight * Mathf.Min(1, !___lookOnlyWhenTalking
? !____playerInHeadZone ? 0 : 1
: !____inConversation || !____playerInHeadZone ? 0 : 1);
____currentLookWeight = Mathf.Lerp(____currentLookWeight, targetWeight, Time.deltaTime * 2f);
____currentLookTarget = ___lookSpring.Update(____currentLookTarget, localPosition, Time.deltaTime);
____animator.SetLookAtPosition(____animator.transform.TransformPoint(____currentLookTarget));
____animator.SetLookAtWeight(____currentLookWeight);
return false;
}
public static bool AnimController_OnZoneExit(CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
return playerId == uint.MaxValue;
}
}
}

View File

@ -60,5 +60,8 @@
public static string QSBExitPlatform = "QSBExitPlatform";
public static string QSBCampfireState = "QSBCampfireState";
public static string QSBMarshmallowEvent = "QSBMarshmallowEvent";
public static string QSBAnimTrigger = "QSBAnimTrigger";
public static string QSBEnterHeadZone = "QSBEnterHeadZone";
public static string QSBExitHeadZone = "QSBExitHeadZone";
}
}

View File

@ -3,7 +3,7 @@
public enum EventType
{
ServerTime,
AnimTrigger,
Crouch,
PlayerState,
PlayerStatesRequest,
FlashlightActiveChange,
@ -41,6 +41,7 @@
PlayerKick,
CampfireState,
Roasting,
MarshmallowEvent
MarshmallowEvent,
AnimTrigger
}
}

View File

@ -1,5 +1,5 @@
using OWML.Common;
using QSB.Animation.Events;
using QSB.Animation.Player.Events;
using QSB.CampfireSync.Events;
using QSB.ConversationSync.Events;
using QSB.DeathSync.Events;
@ -51,6 +51,7 @@ namespace QSB.Events
new PlayerKickEvent(),
new EnterExitRoastingEvent(),
new MarshmallowEventEvent(),
new AnimationTriggerEvent(),
// World Objects
new ElevatorEvent(),
new GeyserEvent(),

View File

@ -1,5 +1,5 @@
using OWML.Common;
using QSB.Animation;
using QSB.Animation.Player;
using QSB.Events;
using QSB.Instruments.QSBCamera;
using QSB.Player;

View File

@ -1,5 +1,6 @@
using OWML.Common;
using QSB.Events;
using QSB.OrbSync.TransformSync;
using QSB.Utility;
using QSB.WorldSync;
using QSB.WorldSync.Events;
@ -51,9 +52,9 @@ namespace QSB.OrbSync.Events
private static void HandleServer(WorldObjectMessage message)
{
var fromPlayer = QNetworkServer.connections.First(x => x.GetPlayerId() == message.FromId);
if (QSBWorldSync.OrbSyncList == null || QSBWorldSync.OrbSyncList.Count == 0)
if (NomaiOrbTransformSync.OrbTransformSyncs == null || NomaiOrbTransformSync.OrbTransformSyncs.Count == 0)
{
DebugLog.ToConsole($"Error - OrbSyncList is empty or null. (ID {message.ObjectId})", MessageType.Error);
DebugLog.ToConsole($"Error - OrbTransformSyncs is empty or null. (ID {message.ObjectId})", MessageType.Error);
return;
}
if (QSBWorldSync.OldOrbList == null || QSBWorldSync.OldOrbList.Count == 0)
@ -65,8 +66,8 @@ namespace QSB.OrbSync.Events
{
DebugLog.ToConsole("Error - FromPlayer is null!", MessageType.Error);
}
var orbSync = QSBWorldSync.OrbSyncList
.FirstOrDefault(x => x.AttachedOrb == QSBWorldSync.OldOrbList[message.ObjectId]);
var orbSync = NomaiOrbTransformSync.OrbTransformSyncs
.FirstOrDefault(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].gameObject);
if (orbSync == null)
{
DebugLog.ToConsole($"Error - No orb found for user event. (ID {message.ObjectId})", MessageType.Error);
@ -78,6 +79,7 @@ namespace QSB.OrbSync.Events
DebugLog.ToConsole($"Error - Orb identity is null. (ID {message.ObjectId})", MessageType.Error);
return;
}
DebugLog.DebugWrite($"Orb {message.ObjectId} to owner {message.FromId}");
if (orbIdentity.ClientAuthorityOwner != null && orbIdentity.ClientAuthorityOwner != fromPlayer)
{
orbIdentity.RemoveClientAuthority(orbIdentity.ClientAuthorityOwner);
@ -88,9 +90,9 @@ namespace QSB.OrbSync.Events
private static void HandleClient(WorldObjectMessage message)
{
if (QSBWorldSync.OrbSyncList == null || QSBWorldSync.OrbSyncList.Count == 0)
if (NomaiOrbTransformSync.OrbTransformSyncs == null || NomaiOrbTransformSync.OrbTransformSyncs.Count == 0)
{
DebugLog.ToConsole($"Error - OrbSyncList is empty or null. (ID {message.ObjectId})", MessageType.Error);
DebugLog.ToConsole($"Error - OrbTransformSyncs is empty or null. (ID {message.ObjectId})", MessageType.Error);
return;
}
if (QSBWorldSync.OldOrbList == null || QSBWorldSync.OldOrbList.Count == 0)
@ -98,13 +100,14 @@ namespace QSB.OrbSync.Events
DebugLog.ToConsole($"Error - OldOrbList is empty or null. (ID {message.ObjectId})", MessageType.Error);
return;
}
if (!QSBWorldSync.OrbSyncList.Any(x => x.AttachedOrb == QSBWorldSync.OldOrbList[message.ObjectId]))
if (!NomaiOrbTransformSync.OrbTransformSyncs.Any(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].gameObject))
{
DebugLog.ToConsole($"Error - No NomaiOrbTransformSync has AttachedOrb with objectId {message.ObjectId}!");
return;
}
var orb = QSBWorldSync.OrbSyncList
.First(x => x.AttachedOrb == QSBWorldSync.OldOrbList[message.ObjectId]);
DebugLog.DebugWrite($"Orb {message.ObjectId} to owner {message.FromId}");
var orb = NomaiOrbTransformSync.OrbTransformSyncs
.First(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].gameObject);
orb.enabled = true;
}
}

View File

@ -1,4 +1,5 @@
using OWML.Common;
using QSB.OrbSync.TransformSync;
using QSB.OrbSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
@ -23,8 +24,8 @@ namespace QSB.OrbSync
QSBWorldSync.OldOrbList = Resources.FindObjectsOfTypeAll<NomaiInterfaceOrb>().ToList();
if (QSBCore.IsServer)
{
QSBWorldSync.OrbSyncList.ForEach(x => QNetworkServer.Destroy(x.gameObject));
QSBWorldSync.OrbSyncList.Clear();
NomaiOrbTransformSync.OrbTransformSyncs.ForEach(x => QNetworkServer.Destroy(x.gameObject));
NomaiOrbTransformSync.OrbTransformSyncs.Clear();
QSBWorldSync.OldOrbList.ForEach(x => QNetworkServer.Spawn(Instantiate(QSBNetworkManager.Instance.OrbPrefab)));
}
DebugLog.DebugWrite($"Finished orb build with {QSBWorldSync.OldOrbList.Count} orbs.", MessageType.Success);

View File

@ -1,81 +1,51 @@
using QSB.Utility;
using QSB.TransformSync;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using System.Collections.Generic;
using UnityEngine;
namespace QSB.OrbSync.TransformSync
{
public class NomaiOrbTransformSync : QNetworkBehaviour
internal class NomaiOrbTransformSync : UnparentedBaseTransformSync
{
public NomaiInterfaceOrb AttachedOrb { get; private set; }
public Transform OrbTransform { get; private set; }
public static List<NomaiOrbTransformSync> OrbTransformSyncs = new List<NomaiOrbTransformSync>();
private int Index => QSBWorldSync.OrbSyncList.IndexOf(this);
private bool _isInitialized;
private int _index => OrbTransformSyncs.IndexOf(this);
private bool _isReady;
private Transform _orbParent;
public override void OnStartClient()
{
DontDestroyOnLoad(this);
QSBWorldSync.OrbSyncList.Add(this);
OrbTransformSyncs.Add(this);
QSBCore.UnityEvents.RunWhen(() => QSBCore.HasWokenUp, () => QSBCore.UnityEvents.FireOnNextUpdate(OnReady));
}
private void OnReady()
{
if (QSBWorldSync.OldOrbList == null || QSBWorldSync.OldOrbList.Count < Index)
if (QSBWorldSync.OldOrbList == null || QSBWorldSync.OldOrbList.Count < _index)
{
DebugLog.ToConsole($"Error - OldOrbList is null or does not contain index {Index}.", OWML.Common.MessageType.Error);
DebugLog.ToConsole($"Error - OldOrbList is null or does not contain index {_index}.", OWML.Common.MessageType.Error);
return;
}
AttachedOrb = QSBWorldSync.OldOrbList[Index];
_isReady = true;
}
public void OnDestroy() => QSBWorldSync.OrbSyncList.Remove(this);
protected void Init()
protected override void OnDestroy()
{
OrbTransform = AttachedOrb.transform;
_orbParent = AttachedOrb.GetAttachedOWRigidbody().GetOrigParent();
_isInitialized = true;
OrbTransformSyncs.Remove(this);
base.OnDestroy();
}
public void Update()
protected override void Init()
{
if (!_isInitialized && _isReady)
{
Init();
}
else if (_isInitialized && !_isReady)
{
_isInitialized = false;
}
if (OrbTransform == null || !_isInitialized)
{
return;
}
UpdateTransform();
base.Init();
SetReferenceTransform(AttachedObject.GetAttachedOWRigidbody().GetOrigParent());
}
private void UpdateTransform()
{
if (HasAuthority)
{
transform.position = _orbParent.InverseTransformPoint(OrbTransform.position);
transform.rotation = OrbTransform.rotation;
return;
}
if (transform.position != Vector3.zero)
{
OrbTransform.position = _orbParent.TransformPoint(transform.position);
OrbTransform.rotation = transform.rotation;
}
}
protected override GameObject InitLocalTransform() => QSBWorldSync.OldOrbList[_index].gameObject;
protected override GameObject InitRemoteTransform() => QSBWorldSync.OldOrbList[_index].gameObject;
public override bool IsReady => _isReady;
public override bool UseInterpolation => false;
}
}
}

View File

@ -1,4 +1,5 @@
using OWML.Common;
using QSB.Animation.Patches;
using QSB.CampfireSync.Patches;
using QSB.ConversationSync.Patches;
using QSB.DeathSync.Patches;
@ -51,7 +52,9 @@ namespace QSB.Patches
new PoolPatches(),
new CampfirePatches(),
new RoastingPatches(),
new PlayerPatches()
new PlayerPatches(),
new PlayerAnimationPatches(),
new CharacterAnimationPatches()
};
DebugLog.DebugWrite("Patch Manager ready.", MessageType.Success);

View File

@ -7,6 +7,8 @@
EnterShrine = 2,
ExitShrine = 3,
EnterPlatform = 4,
ExitPlatform = 5
ExitPlatform = 5,
EnterHeadZone = 6,
ExitHeadZone = 7
}
}

View File

@ -1,6 +1,8 @@
using QSB.Events;
using QSB.Animation.Character.WorldObjects;
using QSB.Events;
using QSB.PoolSync;
using QSB.Utility;
using QSB.WorldSync;
using QSB.WorldSync.Events;
namespace QSB.Player.Events
@ -17,6 +19,8 @@ namespace QSB.Player.Events
GlobalMessenger.AddListener(EventNames.QSBExitShrine, () => Handler(EnterLeaveType.ExitShrine));
GlobalMessenger<int>.AddListener(EventNames.QSBEnterPlatform, (int id) => Handler(EnterLeaveType.EnterPlatform, id));
GlobalMessenger<int>.AddListener(EventNames.QSBExitPlatform, (int id) => Handler(EnterLeaveType.ExitPlatform, id));
GlobalMessenger<int>.AddListener(EventNames.QSBEnterHeadZone, (int id) => Handler(EnterLeaveType.EnterHeadZone, id));
GlobalMessenger<int>.AddListener(EventNames.QSBExitHeadZone, (int id) => Handler(EnterLeaveType.ExitHeadZone, id));
}
public override void CloseListener()
@ -64,6 +68,12 @@ namespace QSB.Player.Events
CustomNomaiRemoteCameraPlatform.CustomPlatformList[message.ObjectId]
.OnRemotePlayerExit(message.AboutId);
break;
case EnterLeaveType.EnterHeadZone:
QSBWorldSync.GetWorldFromId<QSBCharacterAnimController>(message.ObjectId).AddPlayerToHeadZone(player);
break;
case EnterLeaveType.ExitHeadZone:
QSBWorldSync.GetWorldFromId<QSBCharacterAnimController>(message.ObjectId).RemovePlayerFromHeadZone(player);
break;
default:
DebugLog.ToConsole($"Warning - Unknown EnterLeaveType : {message.EnumValue}", OWML.Common.MessageType.Warning);
break;

View File

@ -1,4 +1,4 @@
using QSB.Animation;
using QSB.Animation.Player;
using QSB.CampfireSync.WorldObjects;
using QSB.Player.TransformSync;
using QSB.ProbeSync;

View File

@ -135,5 +135,22 @@ namespace QSB.Player
renderer.enabled = visible;
}
}
public static PlayerInfo GetClosestPlayerToWorldPoint(Vector3 worldPoint, bool includeLocalPlayer)
{
return 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);
return null;
}
return playerList.Where(x => x.PlayerStates.IsReady).OrderBy(x => Vector3.Distance(x.Body.transform.position, worldPoint)).FirstOrDefault();
}
}
}

View File

@ -6,7 +6,7 @@ using UnityEngine;
namespace QSB.Player.TransformSync
{
public class PlayerCameraSync : QSBNetworkTransform
public class PlayerCameraSync : SectoredTransformSync
{
protected override GameObject InitLocalTransform()
{
@ -47,5 +47,7 @@ namespace QSB.Player.TransformSync
&& QSBPlayerManager.PlayerExists(Player.PlayerId)
&& NetId.Value != uint.MaxValue
&& NetId.Value != 0U;
public override bool UseInterpolation => true;
}
}

View File

@ -1,13 +1,14 @@
using QSB.Animation;
using QSB.Animation.Player;
using QSB.Instruments;
using QSB.TransformSync;
using UnityEngine;
namespace QSB.Player.TransformSync
{
public class PlayerTransformSync : QSBNetworkTransform
public class PlayerTransformSync : SectoredTransformSync
{
public static PlayerTransformSync LocalInstance { get; private set; }
public override bool UseInterpolation => true;
static PlayerTransformSync() => AnimControllerPatch.Init();

View File

@ -1,6 +1,6 @@
using OWML.Common;
using OWML.Utils;
using QSB.Animation;
using QSB.Animation.Player;
using QSB.Events;
using QSB.Player;
using QSB.Utility;

View File

@ -7,14 +7,18 @@ using UnityEngine;
namespace QSB.ProbeSync.TransformSync
{
public class PlayerProbeSync : QSBNetworkTransform
public class PlayerProbeSync : SectoredTransformSync
{
public static PlayerProbeSync LocalInstance { get; private set; }
protected override float DistanceLeeway => 10f;
public override bool UseInterpolation => true;
public override void OnStartAuthority()
=> LocalInstance = this;
{
DebugLog.DebugWrite($"OnStartAuthority probe");
LocalInstance = this;
}
private Transform GetProbe() =>
Locator.GetProbe().transform.Find("CameraPivot").Find("Geometry");

View File

@ -102,14 +102,20 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Animation\AnimationSync.cs" />
<Compile Include="Animation\AnimationType.cs" />
<Compile Include="Animation\Events\CrouchEvent.cs" />
<Compile Include="Animation\AnimatorMirror.cs" />
<Compile Include="Animation\AnimControllerPatch.cs" />
<Compile Include="Animation\AnimFloatParam.cs" />
<Compile Include="Animation\CrouchSync.cs" />
<Compile Include="Animation\PlayerHeadRotationSync.cs" />
<Compile Include="Animation\Character\CharacterAnimManager.cs" />
<Compile Include="Animation\Character\Patches\CharacterAnimationPatches.cs" />
<Compile Include="Animation\Character\WorldObjects\QSBCharacterAnimController.cs" />
<Compile Include="Animation\Player\AnimationSync.cs" />
<Compile Include="Animation\Player\AnimationType.cs" />
<Compile Include="Animation\Player\Events\AnimationTriggerEvent.cs" />
<Compile Include="Animation\Player\Events\AnimationTriggerMessage.cs" />
<Compile Include="Animation\Player\Events\CrouchEvent.cs" />
<Compile Include="Animation\Player\AnimatorMirror.cs" />
<Compile Include="Animation\Player\AnimControllerPatch.cs" />
<Compile Include="Animation\Player\AnimFloatParam.cs" />
<Compile Include="Animation\Player\CrouchSync.cs" />
<Compile Include="Animation\Player\Patches\PlayerAnimationPatches.cs" />
<Compile Include="Animation\Player\PlayerHeadRotationSync.cs" />
<Compile Include="CampfireSync\CampfireManager.cs" />
<Compile Include="CampfireSync\Events\CampfireStateEvent.cs" />
<Compile Include="CampfireSync\Patches\CampfirePatches.cs" />
@ -132,7 +138,7 @@
<Compile Include="Events\EventNames.cs" />
<Compile Include="DeathSync\Events\PlayerDeathEvent.cs" />
<Compile Include="Events\IQSBEvent.cs" />
<Compile Include="Animation\Events\ChangeAnimTypeEvent.cs" />
<Compile Include="Animation\Player\Events\ChangeAnimTypeEvent.cs" />
<Compile Include="FrequencySync\Events\IdentifyFrequencyEvent.cs" />
<Compile Include="FrequencySync\Events\IdentifySignalEvent.cs" />
<Compile Include="FrequencySync\Patches\FrequencyPatches.cs" />
@ -142,6 +148,7 @@
<Compile Include="Instruments\QSBCamera\CameraMode.cs" />
<Compile Include="Instruments\InstrumentsManager.cs" />
<Compile Include="Messaging\BoolMessage.cs" />
<Compile Include="OrbSync\TransformSync\NomaiOrbTransformSync.cs" />
<Compile Include="Player\Patches\PlayerPatches.cs" />
<Compile Include="Player\PlayerState.cs" />
<Compile Include="PoolSync\CustomNomaiRemoteCameraPlatform.cs" />
@ -231,7 +238,10 @@
<Compile Include="StatueSync\Patches\StatuePatches.cs" />
<Compile Include="StatueSync\StatueManager.cs" />
<Compile Include="RoastingSync\TransformSync\RoastingStickTransformSync.cs" />
<Compile Include="TransformSync\QSBNetworkTransform.cs" />
<Compile Include="TransformSync\BaseTransformSync.cs" />
<Compile Include="TransformSync\IntermediaryTransform.cs" />
<Compile Include="TransformSync\SectoredTransformSync.cs" />
<Compile Include="TransformSync\UnparentedBaseTransformSync.cs" />
<Compile Include="TranslationSync\Events\SetAsTranslatedEvent.cs" />
<Compile Include="TranslationSync\Events\SetAsTranslatedMessage.cs" />
<Compile Include="TranslationSync\NomaiTextType.cs" />
@ -247,9 +257,8 @@
<Compile Include="Player\Events\PlayerJoinEvent.cs" />
<Compile Include="ProbeSync\Events\PlayerProbeEvent.cs" />
<Compile Include="Player\Events\PlayerReadyEvent.cs" />
<Compile Include="OrbSync\TransformSync\NomaiOrbTransformSync.cs" />
<Compile Include="Player\Events\PlayerStatesRequestEvent.cs" />
<Compile Include="Animation\Events\PlayerSuitEvent.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" />

View File

@ -1,6 +1,7 @@
using OWML.Common;
using OWML.ModHelper;
using OWML.Utils;
using QSB.Animation.Character;
using QSB.CampfireSync;
using QSB.ConversationSync;
using QSB.ElevatorSync;
@ -111,6 +112,7 @@ namespace QSB
gameObject.AddComponent<StatueManager>();
gameObject.AddComponent<PoolManager>();
gameObject.AddComponent<CampfireManager>();
gameObject.AddComponent<CharacterAnimManager>();
DebugBoxManager.Init();
@ -147,9 +149,13 @@ namespace QSB
}
var offset3 = 10f;
GUI.Label(new Rect(420, offset3, 400f, 20f), $"Current sector : {PlayerTransformSync.LocalInstance.ReferenceSector.Name}");
var playerSector = PlayerTransformSync.LocalInstance.ReferenceSector;
var playerText = playerSector == null ? "NULL" : playerSector.Name;
GUI.Label(new Rect(420, offset3, 400f, 20f), $"Current sector : {playerText}");
offset3 += _debugLineSpacing;
GUI.Label(new Rect(420, offset3, 400f, 20f), $"Probe sector : {PlayerProbeSync.LocalInstance.ReferenceSector.Name}");
var probeSector = PlayerProbeSync.LocalInstance.ReferenceSector;
var probeText = probeSector == null ? "NULL" : probeSector.Name;
GUI.Label(new Rect(420, offset3, 400f, 20f), $"Probe sector : {probeText}");
offset3 += _debugLineSpacing;
var offset2 = 10f;

View File

@ -1,6 +1,6 @@
using OWML.Common;
using OWML.Utils;
using QSB.Animation;
using QSB.Animation.Player;
using QSB.DeathSync;
using QSB.Events;
using QSB.Instruments;
@ -215,7 +215,7 @@ namespace QSB
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
RemoveWorldObjects();
QSBWorldSync.OrbSyncList.Clear();
NomaiOrbTransformSync.OrbTransformSyncs.Clear();
QSBWorldSync.OldDialogueTrees.Clear();
if (_everConnected)
@ -237,7 +237,7 @@ namespace QSB
base.OnServerDisconnect(connection);
DebugLog.DebugWrite("OnServerDisconnect", MessageType.Info);
foreach (var item in QSBWorldSync.OrbSyncList)
foreach (var item in NomaiOrbTransformSync.OrbTransformSyncs)
{
var identity = item.GetComponent<QNetworkIdentity>();
if (identity.ClientAuthorityOwner == connection)

View File

@ -103,7 +103,7 @@ namespace QSB.QuantumSync.WorldObjects
{
return;
}
if (GetAttachedShapes().Any(x => x.gameObject.activeInHierarchy))
if (GetAttachedShapes().Any(x => x.isActiveAndEnabled))
{
return;
}

View File

@ -7,8 +7,10 @@ using UnityEngine;
namespace QSB.RoastingSync.TransformSync
{
internal class RoastingStickTransformSync : QSBNetworkTransform
internal class RoastingStickTransformSync : SectoredTransformSync
{
public override bool UseInterpolation => true;
private Transform _stickTip;
private Transform _networkStickTip => gameObject.transform.GetChild(0);
private const float SmoothTime = 0.1f;

View File

@ -20,7 +20,7 @@ namespace QSB.SectorSync
public void Invoke()
{
foreach (var sync in QSBNetworkTransform.NetworkTransformList)
foreach (var sync in SectoredTransformSync.SectoredNetworkTransformList)
{
if (sync.AttachedObject == null)
{
@ -64,7 +64,7 @@ namespace QSB.SectorSync
IsReady = QSBWorldSync.GetWorldObjects<QSBSector>().Any();
}
private void CheckTransformSyncSector(QSBNetworkTransform transformSync)
private void CheckTransformSyncSector(SectoredTransformSync transformSync)
{
var attachedObject = transformSync.AttachedObject;
var closestSector = transformSync.SectorSync.GetClosestSector(attachedObject.transform);

View File

@ -4,9 +4,10 @@ using UnityEngine;
namespace QSB.ShipSync.TransformSync
{
public class ShipTransformSync : QSBNetworkTransform
public class ShipTransformSync : SectoredTransformSync
{
protected override float DistanceLeeway => 20f;
public override bool UseInterpolation => true;
private Transform GetShipModel() => Locator.GetShipTransform();

View File

@ -1,30 +1,30 @@
using OWML.Common;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.SectorSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET.Components;
using QuantumUNET.Transport;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.TransformSync
{
public abstract class QSBNetworkTransform : QNetworkTransform
/*
* Rewrite number : 4
* God has cursed me for my hubris, and my work is never finished.
*/
public abstract class BaseTransformSync : QNetworkTransform
{
public uint AttachedNetId => NetIdentity?.NetId.Value ?? uint.MaxValue;
public uint PlayerId => NetIdentity.RootIdentity?.NetId.Value ?? NetIdentity.NetId.Value;
public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId);
public static List<QSBNetworkTransform> NetworkTransformList = new List<QSBNetworkTransform>();
public QSBSector ReferenceSector { get; set; }
public Transform ReferenceTransform { get; set; }
public GameObject AttachedObject { get; set; }
public SectorSync.SectorSync SectorSync { get; private set; }
public abstract bool IsReady { get; }
public abstract bool UseInterpolation { get; }
protected abstract GameObject InitLocalTransform();
protected abstract GameObject InitRemoteTransform();
@ -35,6 +35,7 @@ namespace QSB.TransformSync
private float _previousDistance;
private Vector3 _positionSmoothVelocity;
private Quaternion _rotationSmoothVelocity;
protected IntermediaryTransform _intermediaryTransform;
public virtual void Start()
{
@ -42,10 +43,8 @@ namespace QSB.TransformSync
.Where(x => x.NetId.Value <= NetId.Value).OrderBy(x => x.NetId.Value).Last();
NetIdentity.SetRootIdentity(lowestBound.NetIdentity);
SectorSync = gameObject.AddComponent<SectorSync.SectorSync>();
NetworkTransformList.Add(this);
DontDestroyOnLoad(gameObject);
_intermediaryTransform = new IntermediaryTransform(transform);
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
}
@ -55,75 +54,61 @@ namespace QSB.TransformSync
{
Destroy(AttachedObject);
}
NetworkTransformList.Remove(this);
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
if (SectorSync != null)
{
Destroy(SectorSync);
}
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse) =>
_isInitialized = false;
protected void Init()
protected virtual void Init()
{
AttachedObject = HasAuthority ? InitLocalTransform() : InitRemoteTransform();
SetReferenceSector(SectorSync.GetClosestSector(AttachedObject.transform));
_isInitialized = true;
}
public override void SerializeTransform(QNetworkWriter writer)
{
if (ReferenceSector != null)
if (_intermediaryTransform == null)
{
writer.Write(ReferenceSector.ObjectId);
}
else
{
writer.Write(-1);
_intermediaryTransform = new IntermediaryTransform(transform);
}
writer.Write(transform.localPosition);
SerializeRotation(writer, transform.localRotation);
_prevPosition = transform.localPosition;
_prevRotation = transform.localRotation;
var worldPos = _intermediaryTransform.GetPosition();
var worldRot = _intermediaryTransform.GetRotation();
writer.Write(worldPos);
SerializeRotation(writer, worldRot);
_prevPosition = worldPos;
_prevRotation = worldRot;
}
public override void DeserializeTransform(QNetworkReader reader)
{
if (!QSBCore.HasWokenUp)
{
reader.ReadInt32();
reader.ReadVector3();
DeserializeRotation(reader);
return;
}
var sectorId = reader.ReadInt32();
var sector = sectorId == -1
? null
: QSBWorldSync.GetWorldFromId<QSBSector>(sectorId);
if (sector != ReferenceSector)
{
SetReferenceSector(sector);
}
var localPosition = reader.ReadVector3();
var localRotation = DeserializeRotation(reader);
var pos = reader.ReadVector3();
var rot = DeserializeRotation(reader);
if (HasAuthority)
{
return;
}
transform.localPosition = localPosition;
transform.localRotation = localRotation;
if (transform.position == Vector3.zero)
if (_intermediaryTransform == null)
{
DebugLog.ToConsole($"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given localPosition was {localPosition} at sector {sector?.Name}", MessageType.Warning);
_intermediaryTransform = new IntermediaryTransform(transform);
}
_intermediaryTransform.SetPosition(pos);
_intermediaryTransform.SetRotation(rot);
if (_intermediaryTransform.GetPosition() == Vector3.zero)
{
DebugLog.ToConsole($"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given position was {pos}", MessageType.Warning);
}
}
@ -159,47 +144,62 @@ namespace QSB.TransformSync
{
if (HasAuthority)
{
transform.position = AttachedObject.transform.position;
transform.rotation = AttachedObject.transform.rotation;
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
return;
}
else
var targetPos = _intermediaryTransform.GetTargetPosition_ParentedToReference();
var targetRot = _intermediaryTransform.GetTargetRotation_ParentedToReference();
if (targetPos != Vector3.zero && _intermediaryTransform.GetTargetPosition_Unparented() != Vector3.zero)
{
AttachedObject.transform.localPosition = SmartSmoothDamp(AttachedObject.transform.localPosition, transform.localPosition);
AttachedObject.transform.localRotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.localRotation, transform.localRotation, ref _rotationSmoothVelocity, SmoothTime);
if (UseInterpolation)
{
AttachedObject.transform.localPosition = SmartSmoothDamp(AttachedObject.transform.localPosition, targetPos);
AttachedObject.transform.localRotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.localRotation, targetRot, ref _rotationSmoothVelocity, SmoothTime);
}
else
{
AttachedObject.transform.localPosition = targetPos;
AttachedObject.transform.localRotation = targetRot;
}
}
}
public override bool HasMoved()
{
var displacementMagnitude = (transform.localPosition - _prevPosition).magnitude;
var displacementMagnitude = (_intermediaryTransform.GetPosition() - _prevPosition).magnitude;
return displacementMagnitude > 1E-03f
|| Quaternion.Angle(transform.localRotation, _prevRotation) > 1E-03f;
|| Quaternion.Angle(_intermediaryTransform.GetRotation(), _prevRotation) > 1E-03f;
}
public void SetReferenceSector(QSBSector sector)
public void SetReferenceTransform(Transform transform)
{
if (ReferenceSector == sector)
if (ReferenceTransform == transform)
{
return;
}
ReferenceSector = sector;
transform.SetParent(sector.Transform, true);
ReferenceTransform = transform;
_intermediaryTransform.SetReferenceTransform(transform);
if (AttachedObject == null)
{
DebugLog.ToConsole($"Warning - AttachedObject was null for {PlayerId}.{GetType().Name} when trying to set reference sector to {sector.Name}. Waiting until not null...", MessageType.Warning);
DebugLog.ToConsole($"Warning - AttachedObject was null for {PlayerId}.{GetType().Name} when trying to set reference transform to {transform.name}. Waiting until not null...", MessageType.Warning);
QSBCore.UnityEvents.RunWhen(
() => AttachedObject != null,
() => ReparentAttachedObject(sector.Transform));
() => ReparentAttachedObject(transform));
return;
}
if (!HasAuthority)
{
ReparentAttachedObject(sector.Transform);
ReparentAttachedObject(transform);
}
}
private void ReparentAttachedObject(Transform sectorTransform)
{
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
@ -211,7 +211,6 @@ namespace QSB.TransformSync
var distance = Vector3.Distance(currentPosition, targetPosition);
if (distance > _previousDistance + DistanceLeeway)
{
DebugLog.DebugWrite($"Warning - {PlayerId}.{GetType().Name} moved too fast!", MessageType.Warning);
_previousDistance = distance;
return targetPosition;
}
@ -226,10 +225,10 @@ namespace QSB.TransformSync
return;
}
Popcron.Gizmos.Cube(transform.position, transform.rotation, Vector3.one / 2, Color.red);
Popcron.Gizmos.Cube(_intermediaryTransform.GetTargetPosition_Unparented(), _intermediaryTransform.GetTargetRotation_Unparented(), Vector3.one / 2, 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, ReferenceSector.Transform.position, Color.cyan);
Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceTransform.position, Color.cyan);
}
}
}

View File

@ -0,0 +1,83 @@
using QSB.Utility;
using UnityEngine;
namespace QSB.TransformSync
{
public class IntermediaryTransform
{
private Transform _attachedTransform;
private Transform _referenceTransform;
public IntermediaryTransform(Transform transform)
=> _attachedTransform = transform;
/// <summary>
/// Get the world position of this INVISIBLE transform.
/// </summary>
public Vector3 GetPosition()
=> _attachedTransform.position;
/// <summary>
/// Set the world position of this INVISIBLE transform.
/// </summary>
public void SetPosition(Vector3 worldPos)
=> _attachedTransform.position = worldPos;
/// <summary>
/// Get the world rotation of this INVISIBLE transform.
/// </summary>
public Quaternion GetRotation()
=> _attachedTransform.rotation;
/// <summary>
/// Set the world rotation of this INVISIBLE transform.
/// </summary>
public void SetRotation(Quaternion worldRot)
=> _attachedTransform.rotation = worldRot;
/// <summary>
/// Sets the reference transform - what transform this transform is syncing to.
/// </summary>
/// <param name="sector">The new reference sector.</param>
public void SetReferenceTransform(Transform transform)
=> _referenceTransform = transform;
/// <summary>
/// Sets the position of the INVISIBLE transform to be correct, according to the reference sector and the position of the VISIBLE transform.
/// </summary>
/// <param name="worldPosition">The world position of the VISIBLE transform.</param>
public void EncodePosition(Vector3 worldPosition)
=> SetPosition(_referenceTransform.InverseTransformPoint(worldPosition));
/// <summary>
/// Sets the rotation of the INVISIBLE transform to be correct, according to the reference sector and the rotation of the VISIBLE transform.
/// </summary>
/// <param name="worldPosition">The world rotation of the VISIBLE transform.</param>
public void EncodeRotation(Quaternion worldRotation)
=> SetRotation(_referenceTransform.InverseTransformRotation(worldRotation));
/// <summary>
/// Returns the local position the VISIBLE transform should be set to, from the INVISIBLE transform.
/// </summary>
public Vector3 GetTargetPosition_ParentedToReference()
=> GetPosition();
/// <summary>
/// Returns the local rotation the VISIBLE transform should be set to, from the INVISIBLE transform.
/// </summary>
public Quaternion GetTargetRotation_ParentedToReference()
=> GetRotation();
/// <summary>
/// Returns the world position the VISIBLE transform should be set to, from the INVISIBLE transform.
/// </summary>
public Vector3 GetTargetPosition_Unparented()
=> _referenceTransform.TransformPoint(GetPosition());
/// <summary>
/// Returns the world rotation the VISIBLE transform should be set to, from the INVISIBLE transform.
/// </summary>
public Quaternion GetTargetRotation_Unparented()
=> _referenceTransform.TransformRotation(GetRotation());
}
}

View File

@ -0,0 +1,83 @@
using QSB.SectorSync.WorldObjects;
using QSB.WorldSync;
using QuantumUNET.Transport;
using System.Collections.Generic;
namespace QSB.TransformSync
{
public abstract class SectoredTransformSync : BaseTransformSync
{
public QSBSector ReferenceSector { get; set; }
public SectorSync.SectorSync SectorSync { get; private set; }
public static List<SectoredTransformSync> SectoredNetworkTransformList = new List<SectoredTransformSync>();
public override void Start()
{
SectorSync = gameObject.AddComponent<SectorSync.SectorSync>();
SectoredNetworkTransformList.Add(this);
base.Start();
}
protected override void OnDestroy()
{
base.OnDestroy();
SectoredNetworkTransformList.Remove(this);
if (SectorSync != null)
{
Destroy(SectorSync);
}
}
protected override void Init()
{
base.Init();
SetReferenceTransform(SectorSync.GetClosestSector(AttachedObject.transform).Transform);
}
public override void SerializeTransform(QNetworkWriter writer)
{
if (_intermediaryTransform == null)
{
_intermediaryTransform = new IntermediaryTransform(transform);
}
if (ReferenceSector != null)
{
writer.Write(ReferenceSector.ObjectId);
}
else
{
writer.Write(-1);
}
base.SerializeTransform(writer);
}
public override void DeserializeTransform(QNetworkReader reader)
{
if (!QSBCore.HasWokenUp)
{
reader.ReadInt32();
reader.ReadVector3();
DeserializeRotation(reader);
return;
}
var sectorId = reader.ReadInt32();
var sector = sectorId == -1
? null
: QSBWorldSync.GetWorldFromId<QSBSector>(sectorId);
if (sector != ReferenceSector)
{
SetReferenceSector(sector);
}
base.DeserializeTransform(reader);
}
public void SetReferenceSector(QSBSector sector)
{
ReferenceSector = sector;
SetReferenceTransform(sector.Transform);
}
}
}

View File

@ -0,0 +1,205 @@
using OWML.Common;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.Utility;
using QuantumUNET.Components;
using QuantumUNET.Transport;
using System.Linq;
using UnityEngine;
namespace QSB.TransformSync
{
public abstract class UnparentedBaseTransformSync : QNetworkTransform
{
public uint AttachedNetId => NetIdentity?.NetId.Value ?? uint.MaxValue;
public uint PlayerId => NetIdentity.RootIdentity?.NetId.Value ?? NetIdentity.NetId.Value;
public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId);
public Transform ReferenceTransform { get; set; }
public GameObject AttachedObject { get; set; }
public abstract bool IsReady { get; }
public abstract bool UseInterpolation { get; }
protected abstract GameObject InitLocalTransform();
protected abstract GameObject InitRemoteTransform();
private bool _isInitialized;
private const float SmoothTime = 0.1f;
protected virtual float DistanceLeeway { get; } = 5f;
private float _previousDistance;
private Vector3 _positionSmoothVelocity;
private Quaternion _rotationSmoothVelocity;
protected IntermediaryTransform _intermediaryTransform;
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;
}
protected virtual void OnDestroy()
{
if (!HasAuthority && AttachedObject != null)
{
Destroy(AttachedObject);
}
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse) =>
_isInitialized = false;
protected virtual void Init()
{
AttachedObject = HasAuthority ? InitLocalTransform() : InitRemoteTransform();
_isInitialized = true;
}
public override void SerializeTransform(QNetworkWriter writer)
{
if (_intermediaryTransform == null)
{
_intermediaryTransform = new IntermediaryTransform(transform);
}
var worldPos = _intermediaryTransform.GetPosition();
var worldRot = _intermediaryTransform.GetRotation();
writer.Write(worldPos);
SerializeRotation(writer, worldRot);
_prevPosition = worldPos;
_prevRotation = worldRot;
}
public override void DeserializeTransform(QNetworkReader reader)
{
if (!QSBCore.HasWokenUp)
{
reader.ReadVector3();
DeserializeRotation(reader);
return;
}
var pos = reader.ReadVector3();
var rot = DeserializeRotation(reader);
if (HasAuthority)
{
return;
}
if (_intermediaryTransform == null)
{
_intermediaryTransform = new IntermediaryTransform(transform);
}
_intermediaryTransform.SetPosition(pos);
_intermediaryTransform.SetRotation(rot);
if (_intermediaryTransform.GetPosition() == Vector3.zero)
{
DebugLog.ToConsole($"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given position was {pos}", MessageType.Warning);
}
}
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 {Player.PlayerId}.{GetType().Name} is null.", MessageType.Warning);
return;
}
UpdateTransform();
base.Update();
}
protected virtual void UpdateTransform()
{
if (HasAuthority)
{
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
return;
}
var targetPos = _intermediaryTransform.GetTargetPosition_Unparented();
var targetRot = _intermediaryTransform.GetTargetRotation_Unparented();
if (targetPos != Vector3.zero && _intermediaryTransform.GetTargetPosition_ParentedToReference() != Vector3.zero)
{
if (UseInterpolation)
{
AttachedObject.transform.position = SmartSmoothDamp(AttachedObject.transform.position, targetPos);
AttachedObject.transform.rotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.rotation, targetRot, ref _rotationSmoothVelocity, SmoothTime);
}
else
{
AttachedObject.transform.position = targetPos;
AttachedObject.transform.rotation = targetRot;
}
}
}
public override bool HasMoved()
{
var displacementMagnitude = (_intermediaryTransform.GetPosition() - _prevPosition).magnitude;
return displacementMagnitude > 1E-03f
|| Quaternion.Angle(_intermediaryTransform.GetRotation(), _prevRotation) > 1E-03f;
}
public void SetReferenceTransform(Transform transform)
{
if (ReferenceTransform == transform)
{
return;
}
ReferenceTransform = transform;
_intermediaryTransform.SetReferenceTransform(transform);
}
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.HasWokenUp || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug || !IsReady)
{
return;
}
Popcron.Gizmos.Cube(_intermediaryTransform.GetTargetPosition_ParentedToReference(), _intermediaryTransform.GetTargetRotation_ParentedToReference(), Vector3.one / 2, 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);
}
}
}

View File

@ -12,7 +12,6 @@ namespace QSB.WorldSync
{
public static class QSBWorldSync
{
public static List<NomaiOrbTransformSync> OrbSyncList { get; } = new List<NomaiOrbTransformSync>();
public static List<NomaiInterfaceOrb> OldOrbList { get; set; } = new List<NomaiInterfaceOrb>();
public static List<CharacterDialogueTree> OldDialogueTrees { get; set; } = new List<CharacterDialogueTree>();
public static Dictionary<string, bool> DialogueConditions { get; } = new Dictionary<string, bool>();
@ -119,7 +118,7 @@ namespace QSB.WorldSync
return worldObject;
}
public static void RaiseEvent<T>(T instance, string eventName, params object[] args)
public static void RaiseEvent<T>(T instance, string eventName, params object[] args) // TODO : move this to qsb.utility
{
if (!(typeof(T)
.GetField(eventName, Flags)?
@ -147,7 +146,7 @@ namespace QSB.WorldSync
DebugLog.ToConsole($"Error - No QSBOrbSlot found for {slot.name}!", MessageType.Error);
return;
}
var orbSync = OrbSyncList.FirstOrDefault(x => x.AttachedOrb == affectingOrb);
var orbSync = NomaiOrbTransformSync.OrbTransformSyncs.FirstOrDefault(x => x.AttachedObject == affectingOrb.gameObject);
if (orbSync == null)
{
DebugLog.ToConsole($"Error - No NomaiOrbTransformSync found for {affectingOrb.name} (For slot {slot.name})!", MessageType.Error);

View File

@ -3,7 +3,7 @@
"settings": {
"defaultServerIP": "localhost",
"port": 7777,
"debugMode": false,
"debugMode": true,
"showLinesInDebug": false,
"socketedObjToDebug": -1
}

View File

@ -289,14 +289,7 @@ namespace QuantumUNET.Components
QLog.Error("Must set the Network Address field in the manager");
return null;
}
if (useSimulator)
{
client.ConnectWithSimulator(networkAddress, networkPort, simulatedLatency, packetLossPercentage);
}
else
{
client.Connect(networkAddress, networkPort);
}
client.Connect(networkAddress, networkPort);
OnStartClient(client);
s_Address = networkAddress;
return client;

View File

@ -268,29 +268,29 @@ namespace QuantumUNET
{
if (localClient)
{
client.RegisterHandlerSafe(1, OnLocalClientObjectDestroy);
client.RegisterHandlerSafe(13, OnLocalClientObjectHide);
client.RegisterHandlerSafe(3, OnLocalClientObjectSpawn);
client.RegisterHandlerSafe(10, OnLocalClientObjectSpawnScene);
client.RegisterHandlerSafe(15, OnClientAuthority);
client.RegisterHandlerSafe(QMsgType.ObjectDestroy, OnLocalClientObjectDestroy);
client.RegisterHandlerSafe(QMsgType.ObjectSpawn, OnLocalClientObjectSpawn);
client.RegisterHandlerSafe(QMsgType.ObjectSpawnScene, OnLocalClientObjectSpawnScene);
client.RegisterHandlerSafe(QMsgType.ObjectHide, OnLocalClientObjectHide);
client.RegisterHandlerSafe(QMsgType.LocalClientAuthority, OnClientAuthority);
}
else
{
client.RegisterHandlerSafe(3, OnObjectSpawn);
client.RegisterHandlerSafe(10, OnObjectSpawnScene);
client.RegisterHandlerSafe(12, OnObjectSpawnFinished);
client.RegisterHandlerSafe(1, OnObjectDestroy);
client.RegisterHandlerSafe(13, OnObjectDestroy);
client.RegisterHandlerSafe(8, OnUpdateVarsMessage);
client.RegisterHandlerSafe(4, OnOwnerMessage);
client.RegisterHandlerSafe(9, OnSyncListMessage);
client.RegisterHandlerSafe(40, QNetworkAnimator.OnAnimationClientMessage);
client.RegisterHandlerSafe(41, QNetworkAnimator.OnAnimationParametersClientMessage);
client.RegisterHandlerSafe(15, OnClientAuthority);
client.RegisterHandlerSafe(QMsgType.ObjectDestroy, OnObjectDestroy);
client.RegisterHandlerSafe(QMsgType.ObjectSpawn, OnObjectSpawn);
client.RegisterHandlerSafe(QMsgType.Owner, OnOwnerMessage);
client.RegisterHandlerSafe(QMsgType.UpdateVars, OnUpdateVarsMessage);
client.RegisterHandlerSafe(QMsgType.SyncList, OnSyncListMessage);
client.RegisterHandlerSafe(QMsgType.ObjectSpawnScene, OnObjectSpawnScene);
client.RegisterHandlerSafe(QMsgType.SpawnFinished, OnObjectSpawnFinished);
client.RegisterHandlerSafe(QMsgType.ObjectHide, OnObjectDestroy);
client.RegisterHandlerSafe(QMsgType.LocalClientAuthority, OnClientAuthority);
client.RegisterHandlerSafe(QMsgType.Animation, QNetworkAnimator.OnAnimationClientMessage);
client.RegisterHandlerSafe(QMsgType.AnimationParameters, QNetworkAnimator.OnAnimationParametersClientMessage);
}
client.RegisterHandlerSafe(2, OnRPCMessage);
client.RegisterHandlerSafe(7, OnSyncEventMessage);
client.RegisterHandlerSafe(42, QNetworkAnimator.OnAnimationTriggerClientMessage);
client.RegisterHandlerSafe(QMsgType.Rpc, OnRPCMessage);
client.RegisterHandlerSafe(QMsgType.SyncEvent, OnSyncEventMessage);
client.RegisterHandlerSafe(QMsgType.AnimationTrigger, QNetworkAnimator.OnAnimationTriggerClientMessage);
}
internal static string GetStringForAssetId(NetworkHash128 assetId)

View File

@ -52,6 +52,18 @@ namespace QuantumUNET
public HostTopology hostTopology { get; private set; }
private const int k_MaxEventsPerFrame = 500;
private int m_HostPort;
private int m_ClientConnectionId = -1;
private int m_StatResetTime;
private static readonly QCRCMessage s_CRCMessage = new QCRCMessage();
private readonly QNetworkMessageHandlers m_MessageHandlers = new QNetworkMessageHandlers();
protected QNetworkConnection m_Connection;
private readonly byte[] m_MsgBuffer;
private readonly NetworkReader m_MsgReader;
protected ConnectState m_AsyncConnect = ConnectState.None;
private string m_RequestedServerHost = "";
public int hostPort
{
get => m_HostPort;
@ -87,139 +99,6 @@ namespace QuantumUNET
return true;
}
public bool ReconnectToNewHost(string serverIp, int serverPort)
{
bool result;
if (!active)
{
QLog.Error("Reconnect - NetworkClient must be active");
result = false;
}
else if (m_Connection == null)
{
QLog.Error("Reconnect - no old connection exists");
result = false;
}
else
{
QLog.Log($"NetworkClient Reconnect {serverIp}:{serverPort}");
QClientScene.HandleClientDisconnect(m_Connection);
QClientScene.ClearLocalPlayers();
m_Connection.Disconnect();
m_Connection = null;
hostId = NetworkTransport.AddHost(hostTopology, m_HostPort);
this.serverPort = serverPort;
if (Application.platform == RuntimePlatform.WebGLPlayer)
{
this.serverIp = serverIp;
m_AsyncConnect = ConnectState.Resolved;
}
else if (serverIp.Equals("127.0.0.1") || serverIp.Equals("localhost"))
{
this.serverIp = "127.0.0.1";
m_AsyncConnect = ConnectState.Resolved;
}
else
{
QLog.Log($"Async DNS START:{serverIp}");
m_AsyncConnect = ConnectState.Resolving;
Dns.BeginGetHostAddresses(serverIp, GetHostAddressesCallback, this);
}
result = true;
}
return result;
}
public bool ReconnectToNewHost(EndPoint secureTunnelEndPoint)
{
bool result;
if (!active)
{
QLog.Error("Reconnect - NetworkClient must be active");
result = false;
}
else if (m_Connection == null)
{
QLog.Error("Reconnect - no old connection exists");
result = false;
}
else
{
QLog.Log("NetworkClient Reconnect to remoteSockAddr");
QClientScene.HandleClientDisconnect(m_Connection);
QClientScene.ClearLocalPlayers();
m_Connection.Disconnect();
m_Connection = null;
hostId = NetworkTransport.AddHost(hostTopology, m_HostPort);
if (secureTunnelEndPoint == null)
{
QLog.Error("Reconnect failed: null endpoint passed in");
m_AsyncConnect = ConnectState.Failed;
result = false;
}
else if (secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetwork && secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetworkV6)
{
QLog.Error("Reconnect failed: Endpoint AddressFamily must be either InterNetwork or InterNetworkV6");
m_AsyncConnect = ConnectState.Failed;
result = false;
}
else
{
var fullName = secureTunnelEndPoint.GetType().FullName;
if (fullName == "System.Net.IPEndPoint")
{
var ipendPoint = (IPEndPoint)secureTunnelEndPoint;
Connect(ipendPoint.Address.ToString(), ipendPoint.Port);
result = m_AsyncConnect != ConnectState.Failed;
}
else if (fullName != "UnityEngine.XboxOne.XboxOneEndPoint" && fullName != "UnityEngine.PS4.SceEndPoint")
{
QLog.Error("Reconnect failed: invalid Endpoint (not IPEndPoint or XboxOneEndPoint or SceEndPoint)");
m_AsyncConnect = ConnectState.Failed;
result = false;
}
else
{
m_RemoteEndPoint = secureTunnelEndPoint;
m_AsyncConnect = ConnectState.Connecting;
byte b;
try
{
m_ClientConnectionId = NetworkTransport.ConnectEndPoint(hostId, m_RemoteEndPoint, 0, out b);
}
catch (Exception arg)
{
QLog.Error($"Reconnect failed: Exception when trying to connect to EndPoint: {arg}");
m_AsyncConnect = ConnectState.Failed;
return false;
}
if (m_ClientConnectionId == 0)
{
QLog.Error($"Reconnect failed: Unable to connect to EndPoint ({b})");
m_AsyncConnect = ConnectState.Failed;
result = false;
}
else
{
m_Connection = (QNetworkConnection)Activator.CreateInstance(networkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(serverIp, hostId, m_ClientConnectionId, hostTopology);
result = true;
}
}
}
}
return result;
}
public void ConnectWithSimulator(string serverIp, int serverPort, int latency, float packetLoss)
{
m_UseSimulator = true;
m_SimulatedLatency = latency;
m_PacketLoss = packetLoss;
Connect(serverIp, serverPort);
}
private static bool IsValidIpV6(string address) =>
address.All(c => c == ':' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
@ -251,63 +130,6 @@ namespace QuantumUNET
}
}
public void Connect(EndPoint secureTunnelEndPoint)
{
PrepareForConnect();
QLog.Log("Client Connect to remoteSockAddr");
if (secureTunnelEndPoint == null)
{
QLog.Error("Connect failed: null endpoint passed in");
m_AsyncConnect = ConnectState.Failed;
}
else if (secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetwork && secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetworkV6)
{
QLog.Error("Connect failed: Endpoint AddressFamily must be either InterNetwork or InterNetworkV6");
m_AsyncConnect = ConnectState.Failed;
}
else
{
var fullName = secureTunnelEndPoint.GetType().FullName;
if (fullName == "System.Net.IPEndPoint")
{
var ipendPoint = (IPEndPoint)secureTunnelEndPoint;
Connect(ipendPoint.Address.ToString(), ipendPoint.Port);
}
else if (fullName != "UnityEngine.XboxOne.XboxOneEndPoint" && fullName != "UnityEngine.PS4.SceEndPoint" && fullName != "UnityEngine.PSVita.SceEndPoint")
{
QLog.Error("Connect failed: invalid Endpoint (not IPEndPoint or XboxOneEndPoint or SceEndPoint)");
m_AsyncConnect = ConnectState.Failed;
}
else
{
byte b = 0;
m_RemoteEndPoint = secureTunnelEndPoint;
m_AsyncConnect = ConnectState.Connecting;
try
{
m_ClientConnectionId = NetworkTransport.ConnectEndPoint(hostId, m_RemoteEndPoint, 0, out b);
}
catch (Exception arg)
{
QLog.Error($"Connect failed: Exception when trying to connect to EndPoint: {arg}");
m_AsyncConnect = ConnectState.Failed;
return;
}
if (m_ClientConnectionId == 0)
{
QLog.Error($"Connect failed: Unable to connect to EndPoint ({b})");
m_AsyncConnect = ConnectState.Failed;
}
else
{
m_Connection = (QNetworkConnection)Activator.CreateInstance(networkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(serverIp, hostId, m_ClientConnectionId, hostTopology);
}
}
}
}
private void PrepareForConnect()
{
SetActive(true);
@ -320,21 +142,7 @@ namespace QuantumUNET
connectionConfig.UsePlatformSpecificProtocols = false;
hostTopology = new HostTopology(connectionConfig, 8);
}
if (m_UseSimulator)
{
var num = m_SimulatedLatency / 3 - 1;
if (num < 1)
{
num = 1;
}
var num2 = m_SimulatedLatency * 3;
QLog.Log($"AddHost Using Simulator {num}/{num2}");
hostId = NetworkTransport.AddHostWithSimulator(hostTopology, num, num2, m_HostPort);
}
else
{
hostId = NetworkTransport.AddHost(hostTopology, m_HostPort);
}
hostId = NetworkTransport.AddHost(hostTopology, m_HostPort);
}
internal static void GetHostAddressesCallback(IAsyncResult ar)
@ -367,22 +175,7 @@ namespace QuantumUNET
internal void ContinueConnect()
{
if (m_UseSimulator)
{
var num = m_SimulatedLatency / 3;
if (num < 1)
{
num = 1;
}
QLog.Log(
$"Connect Using Simulator {m_SimulatedLatency / 3}/{m_SimulatedLatency}");
var conf = new ConnectionSimulatorConfig(num, m_SimulatedLatency, num, m_SimulatedLatency, m_PacketLoss);
m_ClientConnectionId = NetworkTransport.ConnectWithSimulator(hostId, serverIp, serverPort, 0, out var b, conf);
}
else
{
m_ClientConnectionId = NetworkTransport.Connect(hostId, serverIp, serverPort, 0, out var b);
}
m_ClientConnectionId = NetworkTransport.Connect(hostId, serverIp, serverPort, 0, out var b);
m_Connection = (QNetworkConnection)Activator.CreateInstance(networkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(serverIp, hostId, m_ClientConnectionId, hostTopology);
@ -808,34 +601,6 @@ namespace QuantumUNET
active = state;
}
private const int k_MaxEventsPerFrame = 500;
private int m_HostPort;
private bool m_UseSimulator;
private int m_SimulatedLatency;
private float m_PacketLoss;
private int m_ClientConnectionId = -1;
private int m_StatResetTime;
private EndPoint m_RemoteEndPoint;
private static readonly QCRCMessage s_CRCMessage = new QCRCMessage();
private readonly QNetworkMessageHandlers m_MessageHandlers = new QNetworkMessageHandlers();
protected QNetworkConnection m_Connection;
private readonly byte[] m_MsgBuffer;
private readonly NetworkReader m_MsgReader;
protected ConnectState m_AsyncConnect = ConnectState.None;
private string m_RequestedServerHost = "";
protected enum ConnectState
{
None,