This commit is contained in:
Mister_Nebula 2021-04-26 14:30:21 +01:00
parent ec724f7353
commit 3523f3b806
43 changed files with 406 additions and 441 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,112 @@
using OWML.Common;
using QSB.Animation.Character.WorldObjects;
using QSB.Events;
using QSB.Patches;
using QSB.Player;
using QSB.Utility;
using QSB.WorldSync;
using System.Collections.Generic;
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,54 @@
using OWML.Common;
using OWML.Utils;
using QSB.Player;
using QSB.Utility;
using QSB.WorldSync;
using System.Collections.Generic;
using UnityEngine;
namespace QSB.Animation.Character.WorldObjects
{
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 OWML.Utils;
using UnityEngine; using UnityEngine;
namespace QSB.Animation namespace QSB.Animation.Player
{ {
public static class AnimControllerPatch public static class AnimControllerPatch
{ {

View File

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

View File

@ -7,7 +7,7 @@ using QuantumUNET.Components;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
namespace QSB.Animation namespace QSB.Animation.Player
{ {
public class AnimationSync : PlayerSyncObject public class AnimationSync : PlayerSyncObject
{ {
@ -32,6 +32,7 @@ namespace QSB.Animation
protected void Awake() protected void Awake()
{ {
DebugLog.DebugWrite($"Awake AnimationSync {PlayerId}");
InvisibleAnimator = gameObject.AddComponent<Animator>(); InvisibleAnimator = gameObject.AddComponent<Animator>();
NetworkAnimator = gameObject.AddComponent<QNetworkAnimator>(); NetworkAnimator = gameObject.AddComponent<QNetworkAnimator>();
NetworkAnimator.enabled = false; NetworkAnimator.enabled = false;
@ -42,6 +43,7 @@ namespace QSB.Animation
protected override void OnDestroy() protected override void OnDestroy()
{ {
DebugLog.DebugWrite($"OnDestroy AnimationSync {PlayerId}");
base.OnDestroy(); base.OnDestroy();
Destroy(InvisibleAnimator); Destroy(InvisibleAnimator);
Destroy(NetworkAnimator); Destroy(NetworkAnimator);

View File

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

View File

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

View File

@ -1,8 +1,9 @@
using QuantumUNET; using QSB.Animation.Player;
using QuantumUNET;
using System; using System;
using UnityEngine; using UnityEngine;
namespace QSB.Animation namespace QSB.Animation.Player
{ {
public class CrouchSync : QNetworkBehaviour public class CrouchSync : QNetworkBehaviour
{ {

View File

@ -1,8 +1,9 @@
using QSB.Events; using QSB.Animation.Player;
using QSB.Events;
using QSB.Player; using QSB.Player;
using QSB.Utility; using QSB.Utility;
namespace QSB.Animation.Events namespace QSB.Animation.Player.Events
{ {
class AnimationTriggerEvent : QSBEvent<AnimationTriggerMessage> class AnimationTriggerEvent : QSBEvent<AnimationTriggerMessage>
{ {

View File

@ -1,7 +1,7 @@
using QSB.Messaging; using QSB.Messaging;
using QuantumUNET.Transport; using QuantumUNET.Transport;
namespace QSB.Animation.Events namespace QSB.Animation.Player.Events
{ {
public class AnimationTriggerMessage : PlayerMessage public class AnimationTriggerMessage : PlayerMessage
{ {

View File

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

View File

@ -1,8 +1,9 @@
using QSB.Events; using QSB.Animation.Player;
using QSB.Events;
using QSB.Messaging; using QSB.Messaging;
using QSB.Player; using QSB.Player;
namespace QSB.Animation.Events namespace QSB.Animation.Player.Events
{ {
public class CrouchEvent : QSBEvent<FloatMessage> public class CrouchEvent : QSBEvent<FloatMessage>
{ {

View File

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

View File

@ -7,11 +7,11 @@ using UnityEngine;
namespace QSB.Animation.Patches namespace QSB.Animation.Patches
{ {
class AnimationPatches : QSBPatch class PlayerAnimationPatches : QSBPatch
{ {
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect; public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public override void DoPatches() => QSBCore.HarmonyHelper.AddPrefix<PlayerAnimController>("LateUpdate", typeof(AnimationPatches), nameof(PlayerAnimController_LateUpdate)); public override void DoPatches() => QSBCore.HarmonyHelper.AddPrefix<PlayerAnimController>("LateUpdate", typeof(PlayerAnimationPatches), nameof(PlayerAnimController_LateUpdate));
public override void DoUnpatches() => QSBCore.HarmonyHelper.Unpatch<PlayerAnimController>("LateUpdate"); public override void DoUnpatches() => QSBCore.HarmonyHelper.Unpatch<PlayerAnimController>("LateUpdate");
public static bool PlayerAnimController_LateUpdate( public static bool PlayerAnimController_LateUpdate(

View File

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

View File

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

View File

@ -18,8 +18,6 @@ namespace QSB.ConversationSync.Patches
QSBCore.HarmonyHelper.AddPrefix<CharacterDialogueTree>("InputDialogueOption", typeof(ConversationPatches), nameof(Tree_InputDialogueOption)); QSBCore.HarmonyHelper.AddPrefix<CharacterDialogueTree>("InputDialogueOption", typeof(ConversationPatches), nameof(Tree_InputDialogueOption));
QSBCore.HarmonyHelper.AddPostfix<CharacterDialogueTree>("StartConversation", typeof(ConversationPatches), nameof(Tree_StartConversation)); QSBCore.HarmonyHelper.AddPostfix<CharacterDialogueTree>("StartConversation", typeof(ConversationPatches), nameof(Tree_StartConversation));
QSBCore.HarmonyHelper.AddPrefix<CharacterDialogueTree>("EndConversation", typeof(ConversationPatches), nameof(Tree_EndConversation)); 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() public override void DoUnpatches()
@ -28,8 +26,6 @@ namespace QSB.ConversationSync.Patches
QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("InputDialogueOption"); QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("InputDialogueOption");
QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("StartConversation"); QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("StartConversation");
QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("EndConversation"); QSBCore.HarmonyHelper.Unpatch<CharacterDialogueTree>("EndConversation");
QSBCore.HarmonyHelper.Unpatch<CharacterAnimController>("OnAnimatorIK");
QSBCore.HarmonyHelper.Unpatch<CharacterAnimController>("OnZoneExit");
} }
public static void Tree_StartConversation(CharacterDialogueTree __instance) public static void Tree_StartConversation(CharacterDialogueTree __instance)
@ -82,45 +78,5 @@ namespace QSB.ConversationSync.Patches
QSBCore.UnityEvents.RunWhen(() => QSBPlayerManager.LocalPlayer.CurrentDialogueID != -1, QSBCore.UnityEvents.RunWhen(() => QSBPlayerManager.LocalPlayer.CurrentDialogueID != -1,
() => ConversationManager.Instance.SendCharacterDialogue(QSBPlayerManager.LocalPlayer.CurrentDialogueID, key)); () => 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

@ -61,5 +61,7 @@
public static string QSBCampfireState = "QSBCampfireState"; public static string QSBCampfireState = "QSBCampfireState";
public static string QSBMarshmallowEvent = "QSBMarshmallowEvent"; public static string QSBMarshmallowEvent = "QSBMarshmallowEvent";
public static string QSBAnimTrigger = "QSBAnimTrigger"; public static string QSBAnimTrigger = "QSBAnimTrigger";
public static string QSBEnterHeadZone = "QSBEnterHeadZone";
public static string QSBExitHeadZone = "QSBExitHeadZone";
} }
} }

View File

@ -1,5 +1,5 @@
using OWML.Common; using OWML.Common;
using QSB.Animation.Events; using QSB.Animation.Player.Events;
using QSB.CampfireSync.Events; using QSB.CampfireSync.Events;
using QSB.ConversationSync.Events; using QSB.ConversationSync.Events;
using QSB.DeathSync.Events; using QSB.DeathSync.Events;

View File

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

View File

@ -35,10 +35,15 @@ namespace QSB.OrbSync.TransformSync
_isReady = true; _isReady = true;
} }
public void OnDestroy() => QSBWorldSync.OrbSyncList.Remove(this); public void OnDestroy()
{
DebugLog.DebugWrite($"OnDestroy - parented to {gameObject.transform.parent.name}");
QSBWorldSync.OrbSyncList.Remove(this);
}
protected void Init() protected void Init()
{ {
DebugLog.DebugWrite($"Init");
OrbTransform = AttachedOrb.transform; OrbTransform = AttachedOrb.transform;
_orbParent = AttachedOrb.GetAttachedOWRigidbody().GetOrigParent(); _orbParent = AttachedOrb.GetAttachedOWRigidbody().GetOrigParent();
_isInitialized = true; _isInitialized = true;

View File

@ -15,6 +15,7 @@ using QSB.QuantumSync.Patches;
using QSB.RoastingSync.Patches; using QSB.RoastingSync.Patches;
using QSB.StatueSync.Patches; using QSB.StatueSync.Patches;
using QSB.TimeSync.Patches; using QSB.TimeSync.Patches;
using QSB.TransformSync.Patches;
using QSB.TranslationSync.Patches; using QSB.TranslationSync.Patches;
using QSB.Utility; using QSB.Utility;
using System; using System;
@ -53,7 +54,9 @@ namespace QSB.Patches
new CampfirePatches(), new CampfirePatches(),
new RoastingPatches(), new RoastingPatches(),
new PlayerPatches(), new PlayerPatches(),
new AnimationPatches() new PlayerAnimationPatches(),
new CharacterAnimationPatches(),
new TransformSyncPatches()
}; };
DebugLog.DebugWrite("Patch Manager ready.", MessageType.Success); DebugLog.DebugWrite("Patch Manager ready.", MessageType.Success);

View File

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

View File

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

View File

@ -135,5 +135,22 @@ namespace QSB.Player
renderer.enabled = visible; 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

@ -1,6 +1,8 @@
using QSB.Animation; using QSB.Animation;
using QSB.Animation.Player;
using QSB.Instruments; using QSB.Instruments;
using QSB.TransformSync; using QSB.TransformSync;
using QSB.Utility;
using UnityEngine; using UnityEngine;
namespace QSB.Player.TransformSync namespace QSB.Player.TransformSync

View File

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

View File

@ -102,17 +102,20 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Animation\AnimationSync.cs" /> <Compile Include="Animation\Character\CharacterAnimManager.cs" />
<Compile Include="Animation\AnimationType.cs" /> <Compile Include="Animation\Character\Patches\CharacterAnimationPatches.cs" />
<Compile Include="Animation\Events\AnimationTriggerEvent.cs" /> <Compile Include="Animation\Character\WorldObjects\QSBCharacterAnimController.cs" />
<Compile Include="Animation\Events\AnimationTriggerMessage.cs" /> <Compile Include="Animation\Player\AnimationSync.cs" />
<Compile Include="Animation\Events\CrouchEvent.cs" /> <Compile Include="Animation\Player\AnimationType.cs" />
<Compile Include="Animation\AnimatorMirror.cs" /> <Compile Include="Animation\Player\Events\AnimationTriggerEvent.cs" />
<Compile Include="Animation\AnimControllerPatch.cs" /> <Compile Include="Animation\Player\Events\AnimationTriggerMessage.cs" />
<Compile Include="Animation\AnimFloatParam.cs" /> <Compile Include="Animation\Player\Events\CrouchEvent.cs" />
<Compile Include="Animation\CrouchSync.cs" /> <Compile Include="Animation\Player\AnimatorMirror.cs" />
<Compile Include="Animation\Patches\AnimationPatches.cs" /> <Compile Include="Animation\Player\AnimControllerPatch.cs" />
<Compile Include="Animation\PlayerHeadRotationSync.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\CampfireManager.cs" />
<Compile Include="CampfireSync\Events\CampfireStateEvent.cs" /> <Compile Include="CampfireSync\Events\CampfireStateEvent.cs" />
<Compile Include="CampfireSync\Patches\CampfirePatches.cs" /> <Compile Include="CampfireSync\Patches\CampfirePatches.cs" />
@ -135,7 +138,7 @@
<Compile Include="Events\EventNames.cs" /> <Compile Include="Events\EventNames.cs" />
<Compile Include="DeathSync\Events\PlayerDeathEvent.cs" /> <Compile Include="DeathSync\Events\PlayerDeathEvent.cs" />
<Compile Include="Events\IQSBEvent.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\IdentifyFrequencyEvent.cs" />
<Compile Include="FrequencySync\Events\IdentifySignalEvent.cs" /> <Compile Include="FrequencySync\Events\IdentifySignalEvent.cs" />
<Compile Include="FrequencySync\Patches\FrequencyPatches.cs" /> <Compile Include="FrequencySync\Patches\FrequencyPatches.cs" />
@ -234,6 +237,7 @@
<Compile Include="StatueSync\Patches\StatuePatches.cs" /> <Compile Include="StatueSync\Patches\StatuePatches.cs" />
<Compile Include="StatueSync\StatueManager.cs" /> <Compile Include="StatueSync\StatueManager.cs" />
<Compile Include="RoastingSync\TransformSync\RoastingStickTransformSync.cs" /> <Compile Include="RoastingSync\TransformSync\RoastingStickTransformSync.cs" />
<Compile Include="TransformSync\Patches\TransformSyncPatches.cs" />
<Compile Include="TransformSync\QSBNetworkTransform.cs" /> <Compile Include="TransformSync\QSBNetworkTransform.cs" />
<Compile Include="TranslationSync\Events\SetAsTranslatedEvent.cs" /> <Compile Include="TranslationSync\Events\SetAsTranslatedEvent.cs" />
<Compile Include="TranslationSync\Events\SetAsTranslatedMessage.cs" /> <Compile Include="TranslationSync\Events\SetAsTranslatedMessage.cs" />
@ -252,7 +256,7 @@
<Compile Include="Player\Events\PlayerReadyEvent.cs" /> <Compile Include="Player\Events\PlayerReadyEvent.cs" />
<Compile Include="OrbSync\TransformSync\NomaiOrbTransformSync.cs" /> <Compile Include="OrbSync\TransformSync\NomaiOrbTransformSync.cs" />
<Compile Include="Player\Events\PlayerStatesRequestEvent.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="TimeSync\Events\ServerTimeEvent.cs" />
<Compile Include="GeyserSync\Events\GeyserEvent.cs" /> <Compile Include="GeyserSync\Events\GeyserEvent.cs" />
<Compile Include="GeyserSync\GeyserManager.cs" /> <Compile Include="GeyserSync\GeyserManager.cs" />

View File

@ -1,6 +1,7 @@
using OWML.Common; using OWML.Common;
using OWML.ModHelper; using OWML.ModHelper;
using OWML.Utils; using OWML.Utils;
using QSB.Animation.Character;
using QSB.CampfireSync; using QSB.CampfireSync;
using QSB.ConversationSync; using QSB.ConversationSync;
using QSB.ElevatorSync; using QSB.ElevatorSync;
@ -111,6 +112,7 @@ namespace QSB
gameObject.AddComponent<StatueManager>(); gameObject.AddComponent<StatueManager>();
gameObject.AddComponent<PoolManager>(); gameObject.AddComponent<PoolManager>();
gameObject.AddComponent<CampfireManager>(); gameObject.AddComponent<CampfireManager>();
gameObject.AddComponent<CharacterAnimManager>();
DebugBoxManager.Init(); DebugBoxManager.Init();

View File

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

View File

@ -0,0 +1,26 @@
using QSB.Patches;
namespace QSB.TransformSync.Patches
{
class TransformSyncPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public override void DoPatches()
{
//QSBCore.HarmonyHelper.AddPrefix<LoadManager>("LoadSceneAsync", typeof(TransformSyncPatches), nameof(Deparent));
//QSBCore.HarmonyHelper.AddPrefix<LoadManager>("LoadScene", typeof(TransformSyncPatches), nameof(Deparent));
//QSBCore.HarmonyHelper.AddPrefix<LoadManager>("ReloadSceneAsync", typeof(TransformSyncPatches), nameof(Deparent));;
}
public override void DoUnpatches()
{
//QSBCore.HarmonyHelper.Unpatch<LoadManager>("LoadSceneAsync");
//QSBCore.HarmonyHelper.Unpatch<LoadManager>("LoadScene");
//QSBCore.HarmonyHelper.Unpatch<LoadManager>("ReloadSceneAsync");
}
//public static void Deparent()
// => QSBNetworkTransform.DeparentAllTransforms();
}
}

View File

@ -38,6 +38,7 @@ namespace QSB.TransformSync
public virtual void Start() public virtual void Start()
{ {
DebugLog.DebugWrite($"Start {PlayerId}.{GetType().Name}");
var lowestBound = Resources.FindObjectsOfTypeAll<PlayerTransformSync>() var lowestBound = Resources.FindObjectsOfTypeAll<PlayerTransformSync>()
.Where(x => x.NetId.Value <= NetId.Value).OrderBy(x => x.NetId.Value).Last(); .Where(x => x.NetId.Value <= NetId.Value).OrderBy(x => x.NetId.Value).Last();
NetIdentity.SetRootIdentity(lowestBound.NetIdentity); NetIdentity.SetRootIdentity(lowestBound.NetIdentity);
@ -51,6 +52,7 @@ namespace QSB.TransformSync
protected virtual void OnDestroy() protected virtual void OnDestroy()
{ {
DebugLog.DebugWrite($"OnDestroy {PlayerId}.{GetType().Name}");
if (!HasAuthority && AttachedObject != null) if (!HasAuthority && AttachedObject != null)
{ {
Destroy(AttachedObject); Destroy(AttachedObject);
@ -68,6 +70,7 @@ namespace QSB.TransformSync
protected void Init() protected void Init()
{ {
DebugLog.DebugWrite($"Init {PlayerId}.{GetType().Name}");
AttachedObject = HasAuthority ? InitLocalTransform() : InitRemoteTransform(); AttachedObject = HasAuthority ? InitLocalTransform() : InitRemoteTransform();
SetReferenceSector(SectorSync.GetClosestSector(AttachedObject.transform)); SetReferenceSector(SectorSync.GetClosestSector(AttachedObject.transform));
_isInitialized = true; _isInitialized = true;
@ -84,10 +87,10 @@ namespace QSB.TransformSync
writer.Write(-1); writer.Write(-1);
} }
writer.Write(transform.localPosition); writer.Write(transform.position);
SerializeRotation(writer, transform.localRotation); SerializeRotation(writer, transform.rotation);
_prevPosition = transform.localPosition; _prevPosition = transform.position;
_prevRotation = transform.localRotation; _prevRotation = transform.rotation;
} }
public override void DeserializeTransform(QNetworkReader reader) public override void DeserializeTransform(QNetworkReader reader)
@ -110,20 +113,20 @@ namespace QSB.TransformSync
SetReferenceSector(sector); SetReferenceSector(sector);
} }
var localPosition = reader.ReadVector3(); var pos = reader.ReadVector3();
var localRotation = DeserializeRotation(reader); var rot = DeserializeRotation(reader);
if (HasAuthority) if (HasAuthority)
{ {
return; return;
} }
transform.localPosition = localPosition; transform.position = pos;
transform.localRotation = localRotation; transform.rotation = rot;
if (transform.position == Vector3.zero) if (transform.position == Vector3.zero)
{ {
DebugLog.ToConsole($"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given localPosition was {localPosition} at sector {sector?.Name}", MessageType.Warning); DebugLog.ToConsole($"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given position was {pos} at sector {sector?.Name}", MessageType.Warning);
} }
} }
@ -159,21 +162,23 @@ namespace QSB.TransformSync
{ {
if (HasAuthority) if (HasAuthority)
{ {
transform.position = AttachedObject.transform.position; transform.position = ReferenceSector.Transform.InverseTransformPoint(AttachedObject.transform.position);
transform.rotation = AttachedObject.transform.rotation; transform.rotation = ReferenceSector.Transform.InverseTransformRotation(AttachedObject.transform.rotation);
} }
else else
{ {
AttachedObject.transform.localPosition = SmartSmoothDamp(AttachedObject.transform.localPosition, transform.localPosition); var localToWorldPos = ReferenceSector.Transform.TransformPoint(transform.position);
AttachedObject.transform.localRotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.localRotation, transform.localRotation, ref _rotationSmoothVelocity, SmoothTime); var localToWorldRot = ReferenceSector.Transform.TransformRotation(transform.rotation);
AttachedObject.transform.localPosition = SmartSmoothDamp(AttachedObject.transform.localPosition, localToWorldPos);
AttachedObject.transform.localRotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.localRotation, localToWorldRot, ref _rotationSmoothVelocity, SmoothTime);
} }
} }
public override bool HasMoved() public override bool HasMoved()
{ {
var displacementMagnitude = (transform.localPosition - _prevPosition).magnitude; var displacementMagnitude = (transform.position - _prevPosition).magnitude;
return displacementMagnitude > 1E-03f return displacementMagnitude > 1E-03f
|| Quaternion.Angle(transform.localRotation, _prevRotation) > 1E-03f; || Quaternion.Angle(transform.rotation, _prevRotation) > 1E-03f;
} }
public void SetReferenceSector(QSBSector sector) public void SetReferenceSector(QSBSector sector)
@ -183,7 +188,6 @@ namespace QSB.TransformSync
return; return;
} }
ReferenceSector = sector; ReferenceSector = sector;
transform.SetParent(sector.Transform, true);
if (AttachedObject == null) 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 sector to {sector.Name}. Waiting until not null...", MessageType.Warning);
@ -200,6 +204,15 @@ namespace QSB.TransformSync
private void ReparentAttachedObject(Transform sectorTransform) private void ReparentAttachedObject(Transform sectorTransform)
{ {
if (AttachedObject.transform.parent != null && AttachedObject.transform.parent.GetComponent<Sector>() == null)
{
DebugLog.DebugWrite($" - ERROR - Trying to reparent attachedObject which wasnt attached to sector!", MessageType.Error);
return;
}
else
{
DebugLog.DebugWrite($"Reparent {AttachedObject.name} to {sectorTransform.name}");
}
AttachedObject.transform.SetParent(sectorTransform, true); AttachedObject.transform.SetParent(sectorTransform, true);
AttachedObject.transform.localScale = GetType() == typeof(PlayerTransformSync) AttachedObject.transform.localScale = GetType() == typeof(PlayerTransformSync)
? Vector3.one / 10 ? Vector3.one / 10
@ -211,7 +224,6 @@ namespace QSB.TransformSync
var distance = Vector3.Distance(currentPosition, targetPosition); var distance = Vector3.Distance(currentPosition, targetPosition);
if (distance > _previousDistance + DistanceLeeway) if (distance > _previousDistance + DistanceLeeway)
{ {
DebugLog.DebugWrite($"Warning - {PlayerId}.{GetType().Name} moved too fast!", MessageType.Warning);
_previousDistance = distance; _previousDistance = distance;
return targetPosition; return targetPosition;
} }

View File

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

View File

@ -266,7 +266,7 @@ namespace QuantumUNET.Components
}; };
if (HasAuthority && LocalPlayerAuthority) if (HasAuthority && LocalPlayerAuthority)
{ {
if (QNetworkClient.allClients.Count <= 0) if (QNetworkClient.AllClients.Count <= 0)
{ {
return; return;
} }

View File

@ -213,7 +213,7 @@ namespace QuantumUNET.Components
QLog.FatalError($"Exception in OnStartServer:{ex.Message} {ex.StackTrace}"); QLog.FatalError($"Exception in OnStartServer:{ex.Message} {ex.StackTrace}");
} }
} }
if (QNetworkClient.active && QNetworkServer.localClientActive) if (QNetworkClient.Active && QNetworkServer.localClientActive)
{ {
QClientScene.SetLocalObject(NetId, gameObject); QClientScene.SetLocalObject(NetId, gameObject);
OnStartClient(); OnStartClient();

View File

@ -22,7 +22,6 @@ namespace QuantumUNET.Components
public bool autoCreatePlayer { get; set; } = true; public bool autoCreatePlayer { get; set; } = true;
public bool isNetworkActive; public bool isNetworkActive;
public bool useWebSockets { get; set; } public bool useWebSockets { get; set; }
public bool useSimulator { get; set; }
public bool clientLoadedScene { get; set; } public bool clientLoadedScene { get; set; }
public string serverBindAddress { get; set; } = ""; public string serverBindAddress { get; set; } = "";
public string networkAddress { get; set; } = "localhost"; public string networkAddress { get; set; } = "localhost";
@ -236,7 +235,7 @@ namespace QuantumUNET.Components
{ {
OnStopClient(); OnStopClient();
QClientScene.DestroyAllClientObjects(); QClientScene.DestroyAllClientObjects();
QClientScene.HandleClientDisconnect(client.connection); QClientScene.HandleClientDisconnect(client.Connection);
client = null; client = null;
if (!string.IsNullOrEmpty(offlineScene)) if (!string.IsNullOrEmpty(offlineScene))
{ {
@ -289,14 +288,7 @@ namespace QuantumUNET.Components
QLog.Error("Must set the Network Address field in the manager"); QLog.Error("Must set the Network Address field in the manager");
return null; return null;
} }
if (useSimulator) client.Connect(networkAddress, networkPort);
{
client.ConnectWithSimulator(networkAddress, networkPort, simulatedLatency, packetLossPercentage);
}
else
{
client.Connect(networkAddress, networkPort);
}
OnStartClient(client); OnStartClient(client);
s_Address = networkAddress; s_Address = networkAddress;
return client; return client;
@ -313,7 +305,7 @@ namespace QuantumUNET.Components
if (StartServer(config, maxConnections)) if (StartServer(config, maxConnections))
{ {
var networkClient = ConnectLocalClient(); var networkClient = ConnectLocalClient();
OnServerConnect(networkClient.connection); OnServerConnect(networkClient.Connection);
OnStartClient(networkClient); OnStartClient(networkClient);
result = networkClient; result = networkClient;
} }
@ -462,7 +454,7 @@ namespace QuantumUNET.Components
if (IsClientConnected() && client != null) if (IsClientConnected() && client != null)
{ {
RegisterClientMessages(client); RegisterClientMessages(client);
OnClientSceneChanged(client.connection); OnClientSceneChanged(client.Connection);
} }
} }

View File

@ -16,7 +16,7 @@ namespace QuantumUNET.Components
{ {
var xOffset = 10; var xOffset = 10;
var yOffset = 30; var yOffset = 30;
var flag = Manager.client == null || Manager.client.connection == null || Manager.client.connection.connectionId == -1; var flag = Manager.client == null || Manager.client.Connection == null || Manager.client.Connection.connectionId == -1;
if (!Manager.IsClientConnected() && !QNetworkServer.active) if (!Manager.IsClientConnected() && !QNetworkServer.active)
{ {
if (flag) if (flag)
@ -69,7 +69,7 @@ namespace QuantumUNET.Components
{ {
if (GUI.Button(new Rect(xOffset, yOffset, 200f, 20f), "Client Ready")) if (GUI.Button(new Rect(xOffset, yOffset, 200f, 20f), "Client Ready"))
{ {
QClientScene.Ready(Manager.client.connection); QClientScene.Ready(Manager.client.Connection);
if (QClientScene.localPlayers.Count == 0) if (QClientScene.localPlayers.Count == 0)
{ {
QClientScene.AddPlayer(0); QClientScene.AddPlayer(0);

View File

@ -153,7 +153,7 @@ namespace QuantumUNET.Components
{ {
if (LastSyncTime != 0f) if (LastSyncTime != 0f)
{ {
if (QNetworkServer.active || QNetworkClient.active) if (QNetworkServer.active || QNetworkClient.Active)
{ {
if (IsServer || IsClient) if (IsServer || IsClient)
{ {

View File

@ -94,11 +94,11 @@ namespace QuantumUNET
} }
s_InternalMessage.Reader.ReadInt16(); s_InternalMessage.Reader.ReadInt16();
s_InternalMessage.ChannelId = msg.channelId; s_InternalMessage.ChannelId = msg.channelId;
s_InternalMessage.Connection = connection; s_InternalMessage.Connection = Connection;
s_InternalMessage.MsgType = s_InternalMessage.Reader.ReadInt16(); s_InternalMessage.MsgType = s_InternalMessage.Reader.ReadInt16();
m_Connection.InvokeHandler(s_InternalMessage); m_Connection.InvokeHandler(s_InternalMessage);
m_FreeMessages.Push(msg); m_FreeMessages.Push(msg);
connection.lastMessageTime = Time.time; Connection.lastMessageTime = Time.time;
} }
m_InternalMsgs = internalMsgs; m_InternalMsgs = internalMsgs;
m_InternalMsgs.Clear(); m_InternalMsgs.Clear();

View File

@ -13,45 +13,28 @@ namespace QuantumUNET
{ {
public class QNetworkClient public class QNetworkClient
{ {
public QNetworkClient() public static List<QNetworkClient> AllClients { get; private set; } = new List<QNetworkClient>();
{ public static bool Active { get; private set; }
m_MsgBuffer = new byte[65535]; public string ServerIp { get; private set; } = "";
m_MsgReader = new NetworkReader(m_MsgBuffer); public int ServerPort { get; private set; }
AddClient(this); public QNetworkConnection Connection => m_Connection;
}
public QNetworkClient(QNetworkConnection conn)
{
m_MsgBuffer = new byte[65535];
m_MsgReader = new NetworkReader(m_MsgBuffer);
AddClient(this);
SetActive(true);
m_Connection = conn;
m_AsyncConnect = ConnectState.Connected;
conn.SetHandlers(m_MessageHandlers);
RegisterSystemHandlers(false);
}
public static List<QNetworkClient> allClients { get; private set; } = new List<QNetworkClient>();
public static bool active { get; private set; }
internal void SetHandlers(QNetworkConnection conn) => conn.SetHandlers(m_MessageHandlers);
public string serverIp { get; private set; } = "";
public int serverPort { get; private set; }
public QNetworkConnection connection => m_Connection;
internal int hostId { get; private set; } = -1; internal int hostId { get; private set; } = -1;
public Dictionary<short, QNetworkMessageDelegate> handlers => m_MessageHandlers.GetHandlers(); public Dictionary<short, QNetworkMessageDelegate> handlers => m_MessageHandlers.GetHandlers();
public int numChannels => hostTopology.DefaultConfig.ChannelCount; public int numChannels => hostTopology.DefaultConfig.ChannelCount;
public HostTopology hostTopology { get; private set; } 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 public int hostPort
{ {
get => m_HostPort; get => m_HostPort;
@ -70,11 +53,30 @@ namespace QuantumUNET
} }
public bool isConnected => m_AsyncConnect == ConnectState.Connected; public bool isConnected => m_AsyncConnect == ConnectState.Connected;
public Type networkConnectionClass { get; private set; } = typeof(QNetworkConnection); public Type networkConnectionClass { get; private set; } = typeof(QNetworkConnection);
public void SetNetworkConnectionClass<T>() where T : QNetworkConnection => networkConnectionClass = typeof(T); public void SetNetworkConnectionClass<T>() where T : QNetworkConnection => networkConnectionClass = typeof(T);
public QNetworkClient()
{
m_MsgBuffer = new byte[65535];
m_MsgReader = new NetworkReader(m_MsgBuffer);
AddClient(this);
}
public QNetworkClient(QNetworkConnection conn)
{
m_MsgBuffer = new byte[65535];
m_MsgReader = new NetworkReader(m_MsgBuffer);
AddClient(this);
SetActive(true);
m_Connection = conn;
m_AsyncConnect = ConnectState.Connected;
conn.SetHandlers(m_MessageHandlers);
RegisterSystemHandlers(false);
}
internal void SetHandlers(QNetworkConnection conn) => conn.SetHandlers(m_MessageHandlers);
public bool Configure(ConnectionConfig config, int maxConnections) public bool Configure(ConnectionConfig config, int maxConnections)
{ {
var topology = new HostTopology(config, maxConnections); var topology = new HostTopology(config, maxConnections);
@ -87,159 +89,26 @@ namespace QuantumUNET
return true; 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) => private static bool IsValidIpV6(string address) =>
address.All(c => c == ':' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); address.All(c => c == ':' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
public void Connect(string serverIp, int serverPort) public void Connect(string serverIp, int serverPort)
{ {
PrepareForConnect(); PrepareForConnect();
this.serverPort = serverPort; this.ServerPort = serverPort;
if (Application.platform == RuntimePlatform.WebGLPlayer) if (Application.platform == RuntimePlatform.WebGLPlayer)
{ {
this.serverIp = serverIp; this.ServerIp = serverIp;
m_AsyncConnect = ConnectState.Resolved; m_AsyncConnect = ConnectState.Resolved;
} }
else if (serverIp.Equals("127.0.0.1") || serverIp.Equals("localhost")) else if (serverIp.Equals("127.0.0.1") || serverIp.Equals("localhost"))
{ {
this.serverIp = "127.0.0.1"; this.ServerIp = "127.0.0.1";
m_AsyncConnect = ConnectState.Resolved; m_AsyncConnect = ConnectState.Resolved;
} }
else if (serverIp.IndexOf(":") != -1 && IsValidIpV6(serverIp)) else if (serverIp.IndexOf(":") != -1 && IsValidIpV6(serverIp))
{ {
this.serverIp = serverIp; this.ServerIp = serverIp;
m_AsyncConnect = ConnectState.Resolved; m_AsyncConnect = ConnectState.Resolved;
} }
else else
@ -251,63 +120,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() private void PrepareForConnect()
{ {
SetActive(true); SetActive(true);
@ -320,21 +132,7 @@ namespace QuantumUNET
connectionConfig.UsePlatformSpecificProtocols = false; connectionConfig.UsePlatformSpecificProtocols = false;
hostTopology = new HostTopology(connectionConfig, 8); hostTopology = new HostTopology(connectionConfig, 8);
} }
if (m_UseSimulator) hostId = NetworkTransport.AddHost(hostTopology, m_HostPort);
{
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);
}
} }
internal static void GetHostAddressesCallback(IAsyncResult ar) internal static void GetHostAddressesCallback(IAsyncResult ar)
@ -350,10 +148,10 @@ namespace QuantumUNET
} }
else else
{ {
networkClient.serverIp = array[0].ToString(); networkClient.ServerIp = array[0].ToString();
networkClient.m_AsyncConnect = ConnectState.Resolved; networkClient.m_AsyncConnect = ConnectState.Resolved;
QLog.Log( QLog.Log(
$"Async DNS Result:{networkClient.serverIp} for {networkClient.m_RequestedServerHost}: {networkClient.serverIp}"); $"Async DNS Result:{networkClient.ServerIp} for {networkClient.m_RequestedServerHost}: {networkClient.ServerIp}");
} }
} }
catch (SocketException ex) catch (SocketException ex)
@ -367,25 +165,10 @@ namespace QuantumUNET
internal void ContinueConnect() internal void ContinueConnect()
{ {
if (m_UseSimulator) m_ClientConnectionId = NetworkTransport.Connect(hostId, ServerIp, ServerPort, 0, out var b);
{
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_Connection = (QNetworkConnection)Activator.CreateInstance(networkConnectionClass); m_Connection = (QNetworkConnection)Activator.CreateInstance(networkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers); m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(serverIp, hostId, m_ClientConnectionId, hostTopology); m_Connection.Initialize(ServerIp, hostId, m_ClientConnectionId, hostTopology);
} }
public virtual void Disconnect() public virtual void Disconnect()
@ -541,7 +324,7 @@ namespace QuantumUNET
hostId = -1; hostId = -1;
} }
RemoveClient(this); RemoveClient(this);
if (allClients.Count == 0) if (AllClients.Count == 0)
{ {
SetActive(false); SetActive(false);
} }
@ -748,7 +531,7 @@ namespace QuantumUNET
public static Dictionary<short, QNetworkConnection.PacketStat> GetTotalConnectionStats() public static Dictionary<short, QNetworkConnection.PacketStat> GetTotalConnectionStats()
{ {
var dictionary = new Dictionary<short, QNetworkConnection.PacketStat>(); var dictionary = new Dictionary<short, QNetworkConnection.PacketStat>();
foreach (var networkClient in allClients) foreach (var networkClient in AllClients)
{ {
var connectionStats = networkClient.GetConnectionStats(); var connectionStats = networkClient.GetConnectionStats();
foreach (var key in connectionStats.Keys) foreach (var key in connectionStats.Keys)
@ -769,73 +552,45 @@ namespace QuantumUNET
return dictionary; return dictionary;
} }
internal static void AddClient(QNetworkClient client) => allClients.Add(client); internal static void AddClient(QNetworkClient client) => AllClients.Add(client);
internal static bool RemoveClient(QNetworkClient client) => allClients.Remove(client); internal static bool RemoveClient(QNetworkClient client) => AllClients.Remove(client);
internal static void UpdateClients() internal static void UpdateClients()
{ {
for (var i = 0; i < allClients.Count; i++) for (var i = 0; i < AllClients.Count; i++)
{ {
if (allClients[i] != null) if (AllClients[i] != null)
{ {
allClients[i].Update(); AllClients[i].Update();
} }
else else
{ {
allClients.RemoveAt(i); AllClients.RemoveAt(i);
} }
} }
} }
public static void ShutdownAll() public static void ShutdownAll()
{ {
while (allClients.Count != 0) while (AllClients.Count != 0)
{ {
allClients[0].Shutdown(); AllClients[0].Shutdown();
} }
allClients = new List<QNetworkClient>(); AllClients = new List<QNetworkClient>();
active = false; Active = false;
QClientScene.Shutdown(); QClientScene.Shutdown();
} }
internal static void SetActive(bool state) internal static void SetActive(bool state)
{ {
if (!active && state) if (!Active && state)
{ {
NetworkTransport.Init(); NetworkTransport.Init();
} }
active = state; 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 protected enum ConnectState
{ {
None, None,

View File

@ -1173,7 +1173,7 @@ namespace QuantumUNET
}; };
SendToObservers(uv.gameObject, 1, objectDestroyMessage); SendToObservers(uv.gameObject, 1, objectDestroyMessage);
uv.ClearObservers(); uv.ClearObservers();
if (QNetworkClient.active && instance.m_LocalClientActive) if (QNetworkClient.Active && instance.m_LocalClientActive)
{ {
uv.OnNetworkDestroy(); uv.OnNetworkDestroy();
QClientScene.SetLocalObject(objectDestroyMessage.NetId, null); QClientScene.SetLocalObject(objectDestroyMessage.NetId, null);