forked from SubnauticaNitrox/Nitrox
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPlayerPreferencesInitialSyncProcessor.cs
More file actions
147 lines (135 loc) · 5.7 KB
/
PlayerPreferencesInitialSyncProcessor.cs
File metadata and controls
147 lines (135 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NitroxClient.Communication;
using NitroxClient.GameLogic.InitialSync.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxClient.Unity.Helper;
using Nitrox.Model.Subnautica.DataStructures.GameLogic;
using Nitrox.Model.Subnautica.Packets;
namespace NitroxClient.GameLogic.InitialSync;
public sealed class PlayerPreferencesInitialSyncProcessor : InitialSyncProcessor
{
public PlayerPreferencesInitialSyncProcessor()
{
// list of processors which may cause the spawn of Signal pings
AddDependency<PlayerInitialSyncProcessor>();
AddDependency<GlobalRootInitialSyncProcessor>();
AddDependency<StoryGoalInitialSyncProcessor>();
AddDependency<PdaInitialSyncProcessor>();
AddDependency<RemotePlayerInitialSyncProcessor>();
}
public override List<Func<InitialPlayerSync, IEnumerator>> Steps { get; } =
[
UpdatePins,
UpdatePingInstancePreferences
];
private static IEnumerator UpdatePins(InitialPlayerSync packet)
{
using (PacketSuppressor<RecipePinned>.Suppress())
{
PinManager.main.Deserialize(packet.Preferences.PinnedTechTypes.Select(techType => (TechType)techType).ToList());
}
yield break;
}
private static IEnumerator UpdatePingInstancePreferences(InitialPlayerSync packet)
{
Dictionary<string, PingInstancePreference> pingPreferences = packet.Preferences.PingPreferences;
void UpdateInstance(PingInstance instance)
{
ModifyPingInstanceIfPossible(instance, pingPreferences, () => UpdateInstance(instance));
RefreshPingEntryInPDA(instance);
}
PingManager.onAdd += UpdateInstance;
UnityEngine.Object.FindObjectsOfType<PingInstance>().ForEach(UpdateInstance);
yield break;
}
/// <summary>
/// Updates the given pingInstance if it has a specified preference
/// </summary>
private static void ModifyPingInstanceIfPossible(PingInstance pingInstance, Dictionary<string, PingInstancePreference> preferences, Action callback)
{
if (!TryGetKeyForPingInstance(pingInstance, out string pingKey, out bool isRemotePlayerPing, callback) ||
!preferences.TryGetValue(pingKey, out PingInstancePreference preference))
{
return;
}
using (PacketSuppressor<SignalPingPreferenceChanged>.Suppress())
{
// We don't want to set the color for a remote player's signal
if (!isRemotePlayerPing)
{
pingInstance.SetColor(preference.Color);
}
pingInstance.SetVisible(preference.Visible);
}
}
// Right after initial sync modifications, uGUI_PingEntry elements don't show their updated state
private static void RefreshPingEntryInPDA(PingInstance pingInstance)
{
if (!uGUI_PDA.main || !uGUI_PDA.main.tabs.TryGetValue(PDATab.Ping, out uGUI_PDATab pdaTab))
{
return;
}
uGUI_PingTab pingTab = pdaTab as uGUI_PingTab;
if (pingTab && pingTab.entries.TryGetValue(pingInstance.Id, out uGUI_PingEntry pingEntry))
{
pingEntry.SetColor(pingInstance.colorIndex);
pingEntry.SetVisible(pingInstance.visible);
}
}
/// <summary>
/// Retrieves the identifier of a PingInstance depending on its type and container
/// </summary>
/// <remarks>
/// We need to differentiate three types of pings, the "normal pings" from objects that emit a signal, these objects generally contain a NitroxEntity
/// Another type is Signal pings that are generated by the story events, they are located in the Global Root and don't contain a NitroxEntity, to be identified, they have another object: a SignalPing which contains a description key
/// The last type possible is RemotePlayers' pings which are located in a GameObject that is 2 steps under the main object
/// </remarks>
public static bool TryGetKeyForPingInstance(PingInstance pingInstance, out string pingKey, out bool isRemotePlayerPing, Action failCallback = null)
{
isRemotePlayerPing = false;
if (pingInstance.IsLocalOnly)
{
pingKey = string.Empty;
return false;
}
if (pingInstance.TryGetComponent(out SignalPing signalPing))
{
pingKey = signalPing.descriptionKey;
// Sometimes, the SignalPing will not have loaded properly so we need to postpone the key detection
if (pingKey == null)
{
pingInstance.StartCoroutine(DelayPingKeyDetection(failCallback));
return false;
}
return true;
}
if (pingInstance.TryGetComponent(out NitroxEntity nitroxEntity))
{
pingKey = nitroxEntity.Id.ToString();
return true;
}
if (pingInstance.transform.TryGetComponentInAscendance(2, out nitroxEntity))
{
pingKey = nitroxEntity.Id.ToString();
isRemotePlayerPing = true;
return true;
}
// Known issue for a ping named "xSignal(Clone)" that appears temporarily when another player joins
if (pingInstance.name.Equals("xSignal(Clone)"))
{
pingKey = string.Empty;
return false;
}
Log.Warn($"Couldn't find {nameof(PingInstance)} identifier for {pingInstance.name} under {pingInstance.transform.parent}");
pingKey = string.Empty;
return false;
}
private static IEnumerator DelayPingKeyDetection(Action delayedAction)
{
yield return Yielders.WaitForHalfSecond;
delayedAction?.Invoke();
}
}