Merge pull request #208 from misternebula/conversation-system

Conversation system
This commit is contained in:
Mister_Nebula 2020-11-06 22:32:17 +00:00 committed by GitHub
commit c35f0c2bc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 887 additions and 62 deletions

3
.gitignore vendored
View File

@ -358,4 +358,5 @@ MigrationBackup/
# Unecessary asset bundle file
/AssetBundles/AssetBundles*
QSB.csproj.user
QSB.csproj.user
GameAssets/

BIN
AssetBundles/conversation Normal file

Binary file not shown.

View File

@ -0,0 +1,32 @@
ManifestFileVersion: 0
CRC: 3469869292
Hashes:
AssetFileHash:
serializedVersion: 2
Hash: 86686b50f40f37c15d0bca36dcaff7af
TypeTreeHash:
serializedVersion: 2
Hash: 6ce89620af51ba381c9e4f226a2ebb1b
HashAppended: 0
ClassTypes:
- Class: 1
Script: {instanceID: 0}
- Class: 114
Script: {fileID: 1741964061, guid: f70555f144d8491a825f0804e09c671c, type: 3}
- Class: 114
Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
- Class: 114
Script: {fileID: -900027084, guid: f70555f144d8491a825f0804e09c671c, type: 3}
- Class: 114
Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
- Class: 115
Script: {instanceID: 0}
- Class: 222
Script: {instanceID: 0}
- Class: 223
Script: {instanceID: 0}
- Class: 224
Script: {instanceID: 0}
Assets:
- Assets/DialogueBubble.prefab
Dependencies: []

View File

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

View File

@ -3,7 +3,7 @@ CRC: 3416116897
Hashes:
AssetFileHash:
serializedVersion: 2
Hash: f304be71f6b3202b0c75695ffc81dd4e
Hash: b7cbaa1eac609b9c1db0db0b47b32195
TypeTreeHash:
serializedVersion: 2
Hash: 47ee499ae8022a6b96ca6a5fd541f154

View File

@ -0,0 +1,50 @@
using QSB.Events;
using QSB.Messaging;
using QSB.WorldSync;
namespace QSB.ConversationSync
{
public class ConversationEvent : QSBEvent<ConversationMessage>
{
public override EventType Type => EventType.Conversation;
public override void SetupListener() => GlobalMessenger<uint, string, ConversationType>.AddListener(EventNames.QSBConversation, Handler);
public override void CloseListener() => GlobalMessenger<uint, string, ConversationType>.RemoveListener(EventNames.QSBConversation, Handler);
private void Handler(uint id, string message, ConversationType type) => SendEvent(CreateMessage(id, message, type));
private ConversationMessage CreateMessage(uint id, string message, ConversationType type) => new ConversationMessage
{
AboutId = LocalPlayerId,
ObjectId = (int)id,
Type = type,
Message = message
};
public override void OnReceiveRemote(ConversationMessage message)
{
switch (message.Type)
{
case ConversationType.Character:
var translated = TextTranslation.Translate(message.Message).Trim();
ConversationManager.Instance.DisplayCharacterConversationBox(message.ObjectId, translated);
break;
case ConversationType.Player:
ConversationManager.Instance.DisplayPlayerConversationBox((uint)message.ObjectId, message.Message);
break;
case ConversationType.CloseCharacter:
if (message.ObjectId == -1)
{
break;
}
var tree = WorldRegistry.OldDialogueTrees[message.ObjectId];
UnityEngine.Object.Destroy(ConversationManager.Instance.BoxMappings[tree]);
break;
case ConversationType.ClosePlayer:
UnityEngine.Object.Destroy(PlayerRegistry.GetPlayer((uint)message.ObjectId).CurrentDialogueBox);
break;
}
}
}
}

View File

@ -0,0 +1,145 @@
using OWML.Common;
using OWML.ModHelper.Events;
using QSB.Events;
using QSB.Utility;
using QSB.WorldSync;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace QSB.ConversationSync
{
public class ConversationManager : MonoBehaviour
{
public static ConversationManager Instance { get; private set; }
public AssetBundle ConversationAssetBundle { get; private set; }
private GameObject BoxPrefab;
public Dictionary<CharacterDialogueTree, GameObject> BoxMappings = new Dictionary<CharacterDialogueTree, GameObject>();
private void Start()
{
Instance = this;
ConversationAssetBundle = QSB.Helper.Assets.LoadBundle("assets/conversation");
DebugLog.LogState("ConversationBundle", ConversationAssetBundle);
BoxPrefab = ConversationAssetBundle.LoadAsset<GameObject>("assets/dialoguebubble.prefab");
var font = (Font)Resources.Load(@"fonts\english - latin\spacemono-bold");
if (font == null)
{
DebugLog.ToConsole("Error - Font is null!", MessageType.Error);
}
BoxPrefab.GetComponent<Text>().font = font;
BoxPrefab.GetComponent<Text>().color = Color.white;
DebugLog.LogState("BoxPrefab", BoxPrefab);
}
public uint GetPlayerTalkingToTree(CharacterDialogueTree tree)
{
var treeIndex = WorldRegistry.OldDialogueTrees.IndexOf(tree);
if (!PlayerRegistry.PlayerList.Any(x => x.CurrentDialogueID == treeIndex))
{
// No player talking to tree
return uint.MaxValue;
}
// .First() should be fine here as only one player should be talking to a character.
return PlayerRegistry.PlayerList.First(x => x.CurrentDialogueID == treeIndex).PlayerId;
}
public void SendPlayerOption(string text)
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, PlayerRegistry.LocalPlayerId, text, ConversationType.Player);
}
public void SendCharacterDialogue(int id, string text)
{
if (id == -1)
{
DebugLog.ToConsole("Warning - Tried to send conv. event with char id -1.", MessageType.Warning);
return;
}
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, (uint)id, text, ConversationType.Character);
}
public void CloseBoxPlayer()
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, PlayerRegistry.LocalPlayerId, "", ConversationType.ClosePlayer);
}
public void CloseBoxCharacter(int id)
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, (uint)id, "", ConversationType.CloseCharacter);
}
public void SendConvState(int charId, bool state)
{
if (charId == -1)
{
DebugLog.ToConsole("Warning - Tried to send conv. start/end event with char id -1.", MessageType.Warning);
return;
}
GlobalMessenger<int, uint, bool>
.FireEvent(EventNames.QSBConversationStartEnd, charId, PlayerRegistry.LocalPlayerId, state);
}
public void DisplayPlayerConversationBox(uint playerId, string text)
{
if (playerId == PlayerRegistry.LocalPlayerId)
{
DebugLog.ToConsole("Error - Cannot display conversation box for local player!", MessageType.Error);
return;
}
var player = PlayerRegistry.GetPlayer(playerId);
// Destroy old box if it exists
var playerBox = player.CurrentDialogueBox;
if (playerBox != null)
{
Destroy(playerBox);
}
PlayerRegistry.GetPlayer(playerId).CurrentDialogueBox = CreateBox(player.Body.transform, 25, text);
}
public void DisplayCharacterConversationBox(int index, string text)
{
if (WorldRegistry.OldDialogueTrees.ElementAtOrDefault(index) == null)
{
DebugLog.ToConsole($"Error - Tried to display character conversation box for id {index}! (Doesn't exist!)", MessageType.Error);
return;
}
// Remove old box if it exists
var oldDialogueTree = WorldRegistry.OldDialogueTrees[index];
if (BoxMappings.ContainsKey(oldDialogueTree))
{
Destroy(BoxMappings[oldDialogueTree]);
BoxMappings.Remove(oldDialogueTree);
}
BoxMappings.Add(oldDialogueTree, CreateBox(oldDialogueTree.gameObject.transform, 2, text));
}
private GameObject CreateBox(Transform parent, float vertOffset, string text)
{
var newBox = Instantiate(BoxPrefab);
newBox.SetActive(false);
newBox.transform.parent = parent;
newBox.transform.localPosition = new Vector3(0, vertOffset, 0);
newBox.transform.rotation = parent.rotation;
var lookAt = newBox.AddComponent<FaceActiveCamera>();
lookAt.SetValue("_useLookAt", false);
lookAt.SetValue("_localFacingVector", Vector3.back);
lookAt.SetValue("_localRotationAxis", Vector3.up);
newBox.GetComponent<Text>().text = text;
newBox.SetActive(true);
return newBox;
}
}
}

View File

@ -0,0 +1,28 @@
using QSB.Messaging;
using UnityEngine.Networking;
namespace QSB.ConversationSync
{
public class ConversationMessage : PlayerMessage
{
public ConversationType Type { get; set; }
public int ObjectId { get; set; }
public string Message { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
ObjectId = reader.ReadInt32();
Type = (ConversationType)reader.ReadInt32();
Message = reader.ReadString();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(ObjectId);
writer.Write((int)Type);
writer.Write(Message);
}
}
}

View File

@ -0,0 +1,111 @@
using OWML.Common;
using QSB.Utility;
using QSB.WorldSync;
using System.Collections.Generic;
using UnityEngine;
namespace QSB.ConversationSync
{
public static class ConversationPatches
{
public static void StartConversation(CharacterDialogueTree __instance)
{
var index = WorldRegistry.OldDialogueTrees.FindIndex(x => x == __instance);
if (index == -1)
{
DebugLog.ToConsole($"Warning - Index for tree {__instance.name} was -1.", MessageType.Warning);
}
PlayerRegistry.LocalPlayer.CurrentDialogueID = index;
ConversationManager.Instance.SendConvState(index, true);
}
public static bool EndConversation(CharacterDialogueTree __instance)
{
if (!__instance.enabled)
{
return false;
}
if (PlayerRegistry.LocalPlayer.CurrentDialogueID == -1)
{
DebugLog.ToConsole($"Warning - Ending conversation with CurrentDialogueId of -1! Called from {__instance.name}", MessageType.Warning);
return false;
}
ConversationManager.Instance.SendConvState(PlayerRegistry.LocalPlayer.CurrentDialogueID, false);
ConversationManager.Instance.CloseBoxCharacter(PlayerRegistry.LocalPlayer.CurrentDialogueID);
PlayerRegistry.LocalPlayer.CurrentDialogueID = -1;
ConversationManager.Instance.CloseBoxPlayer();
return true;
}
public static bool InputDialogueOption(int optionIndex, DialogueBoxVer2 ____currentDialogueBox)
{
if (optionIndex < 0)
{
// in a page where there is no selectable options
ConversationManager.Instance.CloseBoxPlayer();
return true;
}
var selectedOption = ____currentDialogueBox.OptionFromUIIndex(optionIndex);
ConversationManager.Instance.SendPlayerOption(selectedOption.Text);
return true;
}
public static void GetNextPage(string ____name, List<string> ____listPagesToDisplay, int ____currentPage)
{
var key = ____name + ____listPagesToDisplay[____currentPage];
// Sending key so translation can be done on client side - should make different language-d clients compatible
QSB.Helper.Events.Unity.RunWhen(() => PlayerRegistry.LocalPlayer.CurrentDialogueID != -1,
() => ConversationManager.Instance.SendCharacterDialogue(PlayerRegistry.LocalPlayer.CurrentDialogueID, key));
}
public static bool 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)
{
// TODO : Find closest player and track to that camera.
position = Locator.GetActiveCamera().transform.position;
}
else
{
position = PlayerRegistry.GetPlayer(playerId).Camera.transform.position;
}
float b = ___headTrackingWeight * Mathf.Min(1, (!___lookOnlyWhenTalking) ? ((!____playerInHeadZone) ? 0 : 1) : ((!____inConversation || !____playerInHeadZone) ? 0 : 1));
____currentLookWeight = Mathf.Lerp(____currentLookWeight, b, Time.deltaTime * 2f);
____currentLookTarget = ___lookSpring.Update(____currentLookTarget, position, Time.deltaTime);
____animator.SetLookAtPosition(____currentLookTarget);
____animator.SetLookAtWeight(____currentLookWeight);
return false;
}
public static bool OnZoneExit(CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
if (playerId == uint.MaxValue)
{
return true;
}
return false;
}
public static void AddPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<DialogueNode>("GetNextPage", typeof(ConversationPatches), nameof(GetNextPage));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterDialogueTree>("InputDialogueOption", typeof(ConversationPatches), nameof(InputDialogueOption));
QSB.Helper.HarmonyHelper.AddPostfix<CharacterDialogueTree>("StartConversation", typeof(ConversationPatches), nameof(StartConversation));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterDialogueTree>("EndConversation", typeof(ConversationPatches), nameof(EndConversation));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterAnimController>("OnAnimatorIK", typeof(ConversationPatches), nameof(OnAnimatorIK));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterAnimController>("OnZoneExit", typeof(ConversationPatches), nameof(OnZoneExit));
}
}
}

View File

@ -0,0 +1,84 @@
using OWML.Common;
using OWML.ModHelper.Events;
using QSB.Events;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
using UnityEngine;
namespace QSB.ConversationSync
{
public class ConversationStartEndEvent : QSBEvent<ConversationStartEndMessage>
{
public override Messaging.EventType Type => Messaging.EventType.ConversationStartEnd;
public override void SetupListener() => GlobalMessenger<int, uint, bool>.AddListener(EventNames.QSBConversationStartEnd, Handler);
public override void CloseListener() => GlobalMessenger<int, uint, bool>.RemoveListener(EventNames.QSBConversationStartEnd, Handler);
private void Handler(int charId, uint playerId, bool state) => SendEvent(CreateMessage(charId, playerId, state));
private ConversationStartEndMessage CreateMessage(int charId, uint playerId, bool state) => new ConversationStartEndMessage
{
AboutId = LocalPlayerId,
CharacterId = charId,
PlayerId = playerId,
State = state
};
public override void OnReceiveRemote(ConversationStartEndMessage message)
{
if (message.CharacterId == -1)
{
DebugLog.ToConsole("Warning - Received conv. start/end event with char id -1.", MessageType.Warning);
return;
}
var dialogueTree = WorldRegistry.OldDialogueTrees[message.CharacterId];
var animController = Resources.FindObjectsOfTypeAll<CharacterAnimController>().FirstOrDefault(x => x.GetValue<CharacterDialogueTree>("_dialogueTree") == dialogueTree);
// Make character face player and talk
if (animController != default(CharacterAnimController))
{
if (message.State)
{
// Start talking
PlayerRegistry.GetPlayer(message.PlayerId).CurrentDialogueID = message.CharacterId;
animController.SetValue("_inConversation", true);
animController.SetValue("_playerInHeadZone", true);
if (animController.GetValue<bool>("_hasTalkAnimation"))
{
animController.GetValue<Animator>("_animator").SetTrigger("Talking");
}
dialogueTree.GetComponent<InteractVolume>().DisableInteraction();
}
else
{
// Stop talking
PlayerRegistry.GetPlayer(message.PlayerId).CurrentDialogueID = -1;
animController.SetValue("_inConversation", false);
animController.SetValue("_playerInHeadZone", false);
if (animController.GetValue<bool>("_hasTalkAnimation"))
{
animController.GetValue<Animator>("_animator").SetTrigger("Idle");
}
dialogueTree.GetComponent<InteractVolume>().EnableInteraction();
}
}
// Make character turn to player (if they're meant to)
var qsbFacePlayer = dialogueTree.GetComponentInParent<QSBFacePlayerWhenTalking>();
if (qsbFacePlayer != null)
{
if (message.State)
{
DebugLog.DebugWrite("start convo faceplayer for " + message.CharacterId);
qsbFacePlayer.StartConversation(PlayerRegistry.GetPlayer(message.PlayerId).Body.transform.position);
}
else
{
qsbFacePlayer.EndConversation();
}
}
}
}
}

View File

@ -0,0 +1,28 @@
using QSB.Messaging;
using UnityEngine.Networking;
namespace QSB.ConversationSync
{
public class ConversationStartEndMessage : PlayerMessage
{
public int CharacterId { get; set; }
public uint PlayerId { get; set; }
public bool State { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
CharacterId = reader.ReadInt32();
PlayerId = reader.ReadUInt32();
State = reader.ReadBoolean();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(CharacterId);
writer.Write(PlayerId);
writer.Write(State);
}
}
}

View File

@ -0,0 +1,10 @@
namespace QSB.ConversationSync
{
public enum ConversationType
{
Character,
Player,
CloseCharacter,
ClosePlayer
}
}

View File

@ -0,0 +1,68 @@
using QSB.Utility;
using UnityEngine;
namespace QSB.ConversationSync
{
class QSBFacePlayerWhenTalking : MonoBehaviour
{
private CharacterDialogueTree _dialogueTree;
private Quaternion _origLocalRotation;
private Quaternion _targetLocalRotation;
private void Awake()
{
_dialogueTree = GetComponentInChildren<CharacterDialogueTree>();
DebugLog.DebugWrite("Awake of QSBFacePlayer. Attached to " + _dialogueTree.name);
if (_dialogueTree != null)
{
_dialogueTree.OnStartConversation += () => StartConversation(Locator.GetPlayerTransform().position);
_dialogueTree.OnEndConversation += EndConversation;
}
_origLocalRotation = base.transform.localRotation;
}
private void OnDestroy()
{
if (_dialogueTree != null)
{
_dialogueTree.OnStartConversation -= () => StartConversation(Locator.GetPlayerTransform().position);
_dialogueTree.OnEndConversation -= EndConversation;
}
}
private void Start()
{
enabled = false;
}
public void StartConversation(Vector3 playerPosition)
{
Vector3 vector = playerPosition - transform.position;
Vector3 vector2 = vector - Vector3.Project(vector, transform.up);
float angle = Vector3.Angle(transform.forward, vector2) * Mathf.Sign(Vector3.Dot(vector2, transform.right));
Vector3 axis = transform.parent.InverseTransformDirection(transform.up);
Quaternion lhs = Quaternion.AngleAxis(angle, axis);
this.FaceLocalRotation(lhs * transform.localRotation);
}
public void EndConversation()
{
FaceLocalRotation(_origLocalRotation);
}
private void FaceLocalRotation(Quaternion targetLocalRotation)
{
enabled = true;
_targetLocalRotation = targetLocalRotation;
}
private void Update()
{
transform.localRotation = Quaternion.Slerp(transform.localRotation, _targetLocalRotation, 0.1f);
if (Mathf.Abs(Quaternion.Angle(transform.localRotation, _targetLocalRotation)) < 1f)
{
enabled = false;
}
}
}
}

View File

@ -1,4 +1,5 @@
using QSB.Animation;
using QSB.ConversationSync;
using QSB.DeathSync;
using QSB.ElevatorSync;
using QSB.GeyserSync;
@ -40,7 +41,9 @@ namespace QSB.Events
new ServerTimeEvent(),
new AnimTriggerEvent(),
new OrbSlotEvent(),
new OrbUserEvent()
new OrbUserEvent(),
new ConversationEvent(),
new ConversationStartEndEvent()
};
_eventList.ForEach(ev => ev.SetupListener());

View File

@ -32,5 +32,7 @@
public static string QSBAnimTrigger = "QSBAnimTrigger";
public static string QSBOrbSlot = "QSBOrbSlot";
public static string QSBOrbUser = "QSBOrbUser";
public static string QSBConversation = "QSBConversation";
public static string QSBConversationStartEnd = "QSBConversationStartEnd";
}
}

View File

@ -21,6 +21,8 @@
Elevator,
Geyser,
OrbSlot,
OrbUser
OrbUser,
Conversation,
ConversationStartEnd
}
}

View File

@ -29,15 +29,16 @@ namespace QSB.Messaging
private void Init()
{
var eventName = Enum.GetName(typeof(EventType), _eventType - 1 - MsgType.Highest).ToUpper();
if (NetworkServer.handlers.Keys.Contains((short)_eventType))
{
DebugLog.LogState($"{_eventType} HANDLER", false);
DebugLog.LogState($"({_eventType}) {eventName} HANDLER", false);
DebugLog.ToConsole($"Warning - NetworkServer already contains a handler for EventType {_eventType}", MessageType.Warning);
NetworkServer.handlers.Remove((short)_eventType);
}
NetworkServer.RegisterHandler((short)_eventType, OnServerReceiveMessageHandler);
NetworkManager.singleton.client.RegisterHandler((short)_eventType, OnClientReceiveMessageHandler);
DebugLog.LogState($"{_eventType} HANDLER", true);
DebugLog.LogState($"({_eventType}) {eventName} HANDLER", true);
}
public void SendToAll(T message)

View File

@ -1,4 +1,5 @@
using QSB.Utility;
using OWML.Common;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
using UnityEngine;
@ -26,7 +27,7 @@ namespace QSB.OrbSync
qsbOrbSlot.Init(orbSlots[id], id);
}
DebugLog.DebugWrite($"Finished orb build with {WorldRegistry.OldOrbList.Count} interface orbs and {WorldRegistry.OrbSyncList.Count} orb syncs.");
DebugLog.DebugWrite($"Finished orb build with {WorldRegistry.OldOrbList.Count} interface orbs and {WorldRegistry.OrbSyncList.Count} orb syncs.", MessageType.Success);
}
public void BuildOrbs()
@ -48,5 +49,11 @@ namespace QSB.OrbSync
DebugLog.DebugWrite("Queueing build of QSBOrbSlots...");
QSB.Helper.Events.Unity.RunWhen(() => QSB.HasWokenUp, BuildOrbSlots);
}
public void QueueBuildOrbs()
{
DebugLog.DebugWrite("Queueing build of NetworkOrbs...");
QSB.Helper.Events.Unity.RunWhen(() => NetworkServer.active, BuildOrbs);
}
}
}

View File

@ -11,21 +11,28 @@ namespace QSB
{
public uint PlayerId { get; }
public GameObject Camera { get; set; }
public GameObject Body { get; set; }
// Tools
public GameObject ProbeBody { get; set; }
public QSBProbe Probe { get; set; }
public QSBFlashlight FlashLight => Camera?.GetComponentInChildren<QSBFlashlight>();
public QSBTool Signalscope => GetToolByType(ToolType.Signalscope);
public QSBTool Translator => GetToolByType(ToolType.Translator);
public QSBTool ProbeLauncher => GetToolByType(ToolType.ProbeLauncher);
public PlayerHUDMarker HudMarker { get; set; }
public string Name { get; set; }
public bool IsReady { get; set; }
public int CurrentDialogueID { get; set; }
public GameObject CurrentDialogueBox { get; set; }
public State State { get; set; }
public PlayerInfo(uint id)
{
DebugLog.DebugWrite($"Creating PlayerInfo with id {id}");
PlayerId = id;
CurrentDialogueID = -1;
}
public void UpdateState(State state, bool value)

View File

@ -1,5 +1,6 @@
using OWML.Common;
using OWML.ModHelper;
using QSB.ConversationSync;
using QSB.DeathSync;
using QSB.ElevatorSync;
using QSB.GeyserSync;
@ -47,6 +48,24 @@ namespace QSB
gameObject.AddComponent<GeyserManager>();
gameObject.AddComponent<OrbManager>();
gameObject.AddComponent<QSBSectorManager>();
gameObject.AddComponent<ConversationManager>();
Helper.Events.Unity.RunWhen(() => PlayerData.IsLoaded(), RebuildSettingsSave);
}
private void RebuildSettingsSave()
{
if (PlayerData.GetFreezeTimeWhileReadingConversations()
|| PlayerData.GetFreezeTimeWhileReadingTranslator()
|| PlayerData.GetFreezeTimeWhileReadingShipLog())
{
DebugLog.DebugWrite("Rebuilding SettingsSave...");
var clonedData = PlayerData.CloneSettingsData();
clonedData.freezeTimeWhileReading = false;
clonedData.freezeTimeWhileReadingConversations = false;
clonedData.freezeTimeWhileReadingShipLog = false;
PlayerData.SetSettingsData(clonedData);
}
}
public override void Configure(IModConfig config)

View File

@ -126,6 +126,14 @@
<Compile Include="Animation\AnimTrigger.cs" />
<Compile Include="Animation\AnimTriggerMessage.cs" />
<Compile Include="Animation\CrouchSync.cs" />
<Compile Include="ConversationSync\ConversationEvent.cs" />
<Compile Include="ConversationSync\ConversationMessage.cs" />
<Compile Include="ConversationSync\ConversationPatches.cs" />
<Compile Include="ConversationSync\ConversationStartEndEvent.cs" />
<Compile Include="ConversationSync\ConversationStartEndMessage.cs" />
<Compile Include="ConversationSync\ConversationType.cs" />
<Compile Include="ConversationSync\ConversationManager.cs" />
<Compile Include="ConversationSync\QSBFacePlayerWhenTalking.cs" />
<Compile Include="DeathSync\DeathPatches.cs" />
<Compile Include="ElevatorSync\ElevatorDirection.cs" />
<Compile Include="ElevatorSync\QSBElevator.cs" />

View File

@ -3,5 +3,6 @@
<PropertyGroup>
<GameDir>D:\EpicGames\OuterWilds</GameDir>
<OwmlDir>C:\Users\Henry\AppData\Roaming\OuterWildsModManager\OWML</OwmlDir>
<ProjectView>ShowAllFiles</ProjectView>
</PropertyGroup>
</Project>
</Project>

View File

@ -1,6 +1,7 @@
using OWML.Common;
using OWML.ModHelper.Events;
using QSB.Animation;
using QSB.ConversationSync;
using QSB.DeathSync;
using QSB.ElevatorSync;
using QSB.Events;
@ -76,6 +77,14 @@ namespace QSB
if (inUniverse)
{
OrbManager.Instance.BuildOrbs();
WorldRegistry.OldDialogueTrees.Clear();
WorldRegistry.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
foreach (var item in Resources.FindObjectsOfTypeAll<FacePlayerWhenTalking>())
{
item.gameObject.AddComponent<QSBFacePlayerWhenTalking>();
Destroy(item);
}
}
}
@ -99,7 +108,16 @@ namespace QSB
DebugLog.DebugWrite("~~ ON START SERVER ~~", MessageType.Info);
if (WorldRegistry.OrbSyncList.Count == 0 && QSBSceneManager.IsInUniverse)
{
QSB.Helper.Events.Unity.RunWhen(() => NetworkServer.active, OrbManager.Instance.BuildOrbs);
OrbManager.Instance.QueueBuildOrbs();
}
if (WorldRegistry.OldDialogueTrees.Count == 0 && QSBSceneManager.IsInUniverse)
{
WorldRegistry.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
foreach (var item in Resources.FindObjectsOfTypeAll<FacePlayerWhenTalking>())
{
item.gameObject.AddComponent<QSBFacePlayerWhenTalking>();
Destroy(item);
}
}
}
@ -132,6 +150,7 @@ namespace QSB
}
OrbPatches.AddPatches();
ConversationPatches.AddPatches();
_lobby.CanEditName = false;
@ -166,8 +185,8 @@ namespace QSB
WorldRegistry.RemoveObjects<QSBElevator>();
WorldRegistry.RemoveObjects<QSBGeyser>();
WorldRegistry.RemoveObjects<QSBSector>();
DebugLog.DebugWrite("Clearing OrbSyncList...", MessageType.Info);
WorldRegistry.OrbSyncList.Clear();
WorldRegistry.OldDialogueTrees.Clear();
_lobby.CanEditName = true;
}

View File

@ -7,15 +7,9 @@ namespace QSB.TimeSync
{
public override EventType Type => EventType.ServerTime;
public override void SetupListener()
{
GlobalMessenger<float, int>.AddListener(EventNames.QSBServerTime, Handler);
}
public override void SetupListener() => GlobalMessenger<float, int>.AddListener(EventNames.QSBServerTime, Handler);
public override void CloseListener()
{
GlobalMessenger<float, int>.RemoveListener(EventNames.QSBServerTime, Handler);
}
public override void CloseListener() => GlobalMessenger<float, int>.RemoveListener(EventNames.QSBServerTime, Handler);
private void Handler(float time, int count) => SendEvent(CreateMessage(time, count));

View File

@ -21,6 +21,5 @@ namespace QSB.TimeSync
writer.Write(ServerTime);
writer.Write(LoopCount);
}
}
}

View File

@ -72,6 +72,7 @@ namespace QSB.Tools
private void FixedUpdate()
{
// This really isn't needed... but it makes it look that extra bit nicer.
var lhs = Quaternion.FromToRotation(_basePivot.up, _root.up) * Quaternion.FromToRotation(_baseForward, _root.forward);
var b = lhs * _baseRotation;
_baseRotation = Quaternion.Slerp(_baseRotation, b, 6f * Time.deltaTime);

View File

@ -93,4 +93,4 @@ namespace QSB.TransformSync
}
}
}
}
}

View File

@ -28,6 +28,8 @@ namespace QSB.TransformSync
GetComponent<AnimationSync>().InitLocal(body);
Player.Body = body.gameObject;
return body;
}
@ -40,6 +42,8 @@ namespace QSB.TransformSync
var marker = body.gameObject.AddComponent<PlayerHUDMarker>();
marker.Init(Player);
Player.Body = body.gameObject;
return body;
}

View File

@ -1,33 +0,0 @@
using UnityEngine;
namespace QSB.TransformSync
{
public static class QuaternionHelper
{
// Stolen from here: https://gist.github.com/maxattack/4c7b4de00f5c1b95a33b
public static Quaternion SmoothDamp(Quaternion rot, Quaternion target, ref Quaternion deriv, float time)
{
// account for double-cover
var dot = Quaternion.Dot(rot, target);
var multi = dot > 0f ? 1f : -1f;
target.x *= multi;
target.y *= multi;
target.z *= multi;
target.w *= multi;
// smooth damp (nlerp approx)
var result = new Vector4(
Mathf.SmoothDamp(rot.x, target.x, ref deriv.x, time),
Mathf.SmoothDamp(rot.y, target.y, ref deriv.y, time),
Mathf.SmoothDamp(rot.z, target.z, ref deriv.z, time),
Mathf.SmoothDamp(rot.w, target.w, ref deriv.w, time)
).normalized;
// compute deriv
var dtInv = 1f / Time.deltaTime;
deriv.x = (result.x - rot.x) * dtInv;
deriv.y = (result.y - rot.y) * dtInv;
deriv.z = (result.z - rot.z) * dtInv;
deriv.w = (result.w - rot.w) * dtInv;
return new Quaternion(result.x, result.y, result.z, result.w);
}
}
}

View File

@ -9,6 +9,8 @@ namespace QSB.Utility
{
public static void ToConsole(string message, MessageType type = MessageType.Message)
{
// hack to make custom method name in owml log.
// i wrote the owml code for this so this is fine?? shut up i dont want to change owml
var console = (ModSocketOutput)QSB.Helper.Console;
var method = console.GetType()
.GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
@ -45,10 +47,7 @@ namespace QSB.Utility
{
var status = state ? "OK" : "FAIL";
var messageType = state ? MessageType.Success : MessageType.Error;
if (!state) // to stop "OK" spam
{
DebugWrite($"* {name} {status}", messageType);
}
DebugWrite($"* {name} {status}", messageType);
}
private static string GetCallingType(StackTrace frame)

View File

@ -29,6 +29,5 @@ namespace QSB.Utility
{
return original.gameObject.InstantiateInactive().transform;
}
}
}

View File

@ -14,6 +14,7 @@ namespace QSB.WorldSync
private static readonly List<WorldObject> WorldObjects = new List<WorldObject>();
public static List<NomaiOrbTransformSync> OrbSyncList = new List<NomaiOrbTransformSync>();
public static List<NomaiInterfaceOrb> OldOrbList = new List<NomaiInterfaceOrb>();
public static List<CharacterDialogueTree> OldDialogueTrees = new List<CharacterDialogueTree>();
public static void AddObject(WorldObject worldObject)
{

View File

@ -3,6 +3,6 @@
"settings": {
"defaultServerIP": "localhost",
"port": 7777,
"debugMode": false
"debugMode": true
}
}

View File

@ -4,6 +4,6 @@
"name": "Quantum Space Buddies",
"description": "Adds online multiplayer to the game.",
"uniqueName": "Raicuparta.QuantumSpaceBuddies",
"version": "0.6.0",
"version": "0.7.0",
"owmlVersion": "0.7.3"
}

View File

@ -0,0 +1,227 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 1531056750600734}
m_IsPrefabParent: 1
--- !u!1 &1143829915878388
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224902966460615240}
- component: {fileID: 222785523450871998}
- component: {fileID: 114075889546086968}
- component: {fileID: 223100826173633414}
m_Layer: 0
m_Name: Background
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!1 &1531056750600734
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224161822944405660}
- component: {fileID: 222075293424074192}
- component: {fileID: 114008001535486946}
- component: {fileID: 223470330008512890}
- component: {fileID: 114167403308441852}
- component: {fileID: 114670735829080676}
m_Layer: 0
m_Name: DialogueBubble
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &114008001535486946
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1531056750600734}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 2100000, guid: 08e1a88dddd41604db20b0dcb92d17d8, type: 2}
m_Color: {r: 1, g: 0.68275857, b: 0, a: 1}
m_RaycastTarget: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 12800000, guid: 67f35d66c98319540bc681e5a18105d2, type: 2}
m_FontSize: 1
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 0
m_MaxSize: 150
m_Alignment: 4
m_AlignByGeometry: 1
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 1
m_LineSpacing: 1
m_Text:
--- !u!114 &114075889546086968
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1143829915878388}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0, g: 0, b: 0, a: 0.50980395}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!114 &114167403308441852
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1531056750600734}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1741964061, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_HorizontalFit: 0
m_VerticalFit: 2
--- !u!114 &114670735829080676
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1531056750600734}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -900027084, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Name:
m_EditorClassIdentifier:
m_EffectColor: {r: 0, g: 0, b: 0, a: 1}
m_EffectDistance: {x: -0.04, y: -0.04}
m_UseGraphicAlpha: 1
--- !u!222 &222075293424074192
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1531056750600734}
--- !u!222 &222785523450871998
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1143829915878388}
--- !u!223 &223100826173633414
Canvas:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1143829915878388}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 2
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 1
m_OverridePixelPerfect: 1
m_SortingBucketNormalizedSize: 0
m_AdditionalShaderChannelsFlag: 0
m_SortingLayerID: 0
m_SortingOrder: -9999
m_TargetDisplay: 0
--- !u!223 &223470330008512890
Canvas:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1531056750600734}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 2
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_AdditionalShaderChannelsFlag: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!224 &224161822944405660
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1531056750600734}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.1, y: 0.1, z: 1}
m_Children:
- {fileID: 224902966460615240}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 25, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!224 &224902966460615240
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1143829915878388}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 224161822944405660}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -1, y: -1}
m_SizeDelta: {x: 2, y: 2}
m_Pivot: {x: 0, y: 0}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8a96f886e4fad144f8fb9a5e3c2712df
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 100100000
userData:
assetBundleName: conversation
assetBundleVariant: