diff --git a/NebulaModel/Packets/Session/GlobalGameDataResponse.cs b/NebulaModel/Packets/Session/GlobalGameDataResponse.cs index 32d81a795..ef80c7d61 100644 --- a/NebulaModel/Packets/Session/GlobalGameDataResponse.cs +++ b/NebulaModel/Packets/Session/GlobalGameDataResponse.cs @@ -17,6 +17,7 @@ public enum EDataType : byte SpaceSector, MilestoneSystem, TrashSystem, + GalacticDigital, Ready } diff --git a/NebulaModel/Packets/Universe/MarkerSettingUpdatePacket.cs b/NebulaModel/Packets/Universe/MarkerSettingUpdatePacket.cs new file mode 100644 index 000000000..54b6f1b7a --- /dev/null +++ b/NebulaModel/Packets/Universe/MarkerSettingUpdatePacket.cs @@ -0,0 +1,40 @@ +namespace NebulaModel.Packets.Universe; + +public class MarkerSettingUpdatePacket +{ + public MarkerSettingUpdatePacket() { } + + public MarkerSettingUpdatePacket(int planetId, int markerId, MarkerSettingEvent settingEvent, int intValue = 0, + float floatValue = 0f, string stringValue = null, short[] colorData = null) + { + PlanetId = planetId; + MarkerId = markerId; + Event = settingEvent; + IntValue = intValue; + FloatValue = floatValue; + StringValue = stringValue; + ColorData = colorData; + } + + public int PlanetId { get; set; } + public int MarkerId { get; set; } + public MarkerSettingEvent Event { get; set; } + public int IntValue { get; set; } + public float FloatValue { get; set; } + public string StringValue { get; set; } + public short[] ColorData { get; set; } +} + +public enum MarkerSettingEvent +{ + SetName = 0, + SetWord = 1, + SetTags = 2, + SetTodoContent = 3, + SetIcon = 4, + SetColor = 5, + SetVisibility = 6, + SetDetailLevel = 7, + SetHeight = 8, + SetRadius = 9 +} diff --git a/NebulaNetwork/PacketProcessors/Planet/FactoryLoadRequestProcessor.cs b/NebulaNetwork/PacketProcessors/Planet/FactoryLoadRequestProcessor.cs index e826b201d..906d43d74 100644 --- a/NebulaNetwork/PacketProcessors/Planet/FactoryLoadRequestProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Planet/FactoryLoadRequestProcessor.cs @@ -76,6 +76,6 @@ static void OnPlanetFactoryLoad(PlanetData planet) buffer[id].HandleFullHp(GameMain.data, spaceSector.skillSystem); } } - } + } diff --git a/NebulaNetwork/PacketProcessors/Session/GlobalGameDataRequestProcessor.cs b/NebulaNetwork/PacketProcessors/Session/GlobalGameDataRequestProcessor.cs index 19cb8e1f8..4fd10a94c 100644 --- a/NebulaNetwork/PacketProcessors/Session/GlobalGameDataRequestProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Session/GlobalGameDataRequestProcessor.cs @@ -1,6 +1,7 @@ #region using NebulaAPI.Packets; +using NebulaModel.Logger; using NebulaModel.Networking; using NebulaModel.Packets; using NebulaModel.Packets.GameStates; @@ -69,6 +70,14 @@ protected override void ProcessPacket(GlobalGameDataRequest packet, NebulaConnec GlobalGameDataResponse.EDataType.TrashSystem, writer.CloseAndGetBytes())); } + using (var writer = new BinaryUtils.Writer()) + { + GameMain.data.galacticDigital.Export(writer.BinaryWriter); + + conn.SendPacket(new GlobalGameDataResponse( + GlobalGameDataResponse.EDataType.GalacticDigital, writer.CloseAndGetBytes())); + } + using (var writer = new BinaryUtils.Writer()) { writer.BinaryWriter.Write(GameMain.sandboxToolsEnabled); diff --git a/NebulaNetwork/PacketProcessors/Universe/MarkerSettingUpdateProcessor.cs b/NebulaNetwork/PacketProcessors/Universe/MarkerSettingUpdateProcessor.cs new file mode 100644 index 000000000..6290add76 --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Universe/MarkerSettingUpdateProcessor.cs @@ -0,0 +1,265 @@ +#region + +using System.Linq; +using NebulaAPI.Packets; +using NebulaModel.Logger; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Universe; +using NebulaWorld; + +#endregion + +namespace NebulaNetwork.PacketProcessors.Universe; + +[RegisterPacketProcessor] +internal class MarkerSettingUpdateProcessor : PacketProcessor +{ + // Cache for the Marker owner type (discovered via reflection) + private static object _markerOwnerType; + private static bool _markerOwnerTypeDiscovered; + + /// + /// Creates a TodoModule for a marker using galacticDigital.AddTodoModule(). + /// This properly registers the todo in the global pool. + /// + private static TodoModule CreateMarkerTodoModule(int markerId) + { + var galacticDigital = GameMain.data?.galacticDigital; + if (galacticDigital == null) + { + Log.Warn("CreateMarkerTodoModule: galacticDigital is null"); + return null; + } + + try + { + var bindingFlags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance; + var addTodoMethod = galacticDigital.GetType().GetMethod("AddTodoModule", bindingFlags); + + if (addTodoMethod == null) + { + Log.Warn("CreateMarkerTodoModule: AddTodoModule method not found"); + return null; + } + + // Discover the Marker owner type if not already cached + if (!_markerOwnerTypeDiscovered) + { + var ownerTypeEnum = addTodoMethod.GetParameters()[0].ParameterType; + var enumValues = System.Enum.GetValues(ownerTypeEnum); + + // Log all enum values for debugging + Log.Debug($"CreateMarkerTodoModule: ETodoModuleOwnerType values: {string.Join(", ", enumValues.Cast().Select(v => $"{v}={System.Convert.ToInt32(v)}"))}"); + + // Search for "Entity" type in the enum (markers use ETodoModuleOwnerType.Entity = 2) + foreach (var val in enumValues) + { + var name = val.ToString(); + if (name == "Entity") + { + _markerOwnerType = val; + Log.Debug($"CreateMarkerTodoModule: Found Entity owner type: {val}"); + break; + } + } + + // If not found, log warning but don't fail + if (_markerOwnerType == null) + { + Log.Warn("CreateMarkerTodoModule: Could not find Entity owner type in ETodoModuleOwnerType enum"); + } + + _markerOwnerTypeDiscovered = true; + } + + if (_markerOwnerType == null) + { + return null; + } + + // Call AddTodoModule(markerOwnerType, markerId) + Log.Debug($"CreateMarkerTodoModule: Calling AddTodoModule({_markerOwnerType}, {markerId})"); + var result = addTodoMethod.Invoke(galacticDigital, new object[] { _markerOwnerType, markerId }); + + if (result is TodoModule todoModule) + { + Log.Debug($"CreateMarkerTodoModule: Created TodoModule for marker {markerId}"); + return todoModule; + } + + Log.Warn($"CreateMarkerTodoModule: AddTodoModule returned {result?.GetType().Name ?? "null"} instead of TodoModule"); + return null; + } + catch (System.Exception ex) + { + Log.Warn($"CreateMarkerTodoModule: Exception - {ex.Message}\n{ex.StackTrace}"); + return null; + } + } + + /// + /// Finds an existing TodoModule for a marker in the galactic todos pool. + /// + private static TodoModule FindMarkerTodoInPool(int markerId) + { + var todos = GameMain.data?.galacticDigital?.todos; + if (todos == null) return null; + + for (int i = 1; i < todos.cursor; i++) + { + ref var todo = ref todos.buffer[i]; + if (todo.id == i && todo.ownerId == markerId) + { + // Verify it's a marker type (not planet or other) + if (_markerOwnerType != null && System.Convert.ToInt32(todo.ownerType) == System.Convert.ToInt32(_markerOwnerType)) + { + return todo; + } + } + } + + return null; + } + + protected override void ProcessPacket(MarkerSettingUpdatePacket packet, NebulaConnection conn) + { + Log.Debug($"MarkerSettingUpdatePacket received: Planet={packet.PlanetId}, Marker={packet.MarkerId}, Event={packet.Event}"); + + var factory = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory; + if (factory == null) + { + Log.Warn($"MarkerSettingUpdatePacket: Can't find factory for planet {packet.PlanetId}"); + return; + } + + var markers = factory.digitalSystem?.markers; + if (markers == null || packet.MarkerId <= 0 || packet.MarkerId >= markers.cursor) + { + Log.Warn($"MarkerSettingUpdatePacket: Can't find marker ({packet.PlanetId}, {packet.MarkerId}), cursor={markers?.cursor}"); + return; + } + + ref var marker = ref markers.buffer[packet.MarkerId]; + if (marker.id != packet.MarkerId) + { + Log.Warn($"MarkerSettingUpdatePacket: Marker id mismatch ({packet.PlanetId}, {packet.MarkerId})"); + return; + } + + if (IsHost) + { + // Relay packet to other clients + Server.SendPacketExclude(packet, conn); + } + + using (Multiplayer.Session.Warning.IsIncomingMarkerPacket.On()) + { + switch (packet.Event) + { + case MarkerSettingEvent.SetName: + marker.name = packet.StringValue; + break; + + case MarkerSettingEvent.SetWord: + marker.word = packet.StringValue; + break; + + case MarkerSettingEvent.SetTags: + marker.tags = packet.StringValue; + break; + + case MarkerSettingEvent.SetTodoContent: + if (marker.todo != null) + { + marker.todo.content = packet.StringValue; + // Apply color data if provided (colors and text are sent together) + if (packet.ColorData != null) + { + marker.todo.contentColorIndex = packet.ColorData; + } + Log.Debug($"SetTodoContent: Updated todo for marker {packet.MarkerId}, colors={packet.ColorData?.Length ?? 0}"); + } + else + { + // marker.todo is null - create via galacticDigital.AddTodoModule() for proper registration + Log.Debug($"SetTodoContent: marker.todo is null for marker {packet.MarkerId}, creating via AddTodoModule"); + + // First check if there's already a todo in the pool for this marker + var existingTodo = FindMarkerTodoInPool(packet.MarkerId); + if (existingTodo != null) + { + // Link existing pool todo to marker and update content + marker.todo = existingTodo; + marker.todo.content = packet.StringValue; + if (packet.ColorData != null) + { + marker.todo.contentColorIndex = packet.ColorData; + } + Log.Debug($"SetTodoContent: Found existing todo in pool, linked to marker {packet.MarkerId}"); + } + else + { + // Create new todo via AddTodoModule + var newTodo = CreateMarkerTodoModule(packet.MarkerId); + if (newTodo != null) + { + marker.todo = newTodo; + marker.todo.content = packet.StringValue; + if (packet.ColorData != null) + { + marker.todo.contentColorIndex = packet.ColorData; + } + Log.Debug($"SetTodoContent: Created and linked TodoModule for marker {packet.MarkerId}"); + } + else + { + Log.Warn($"SetTodoContent: Failed to create TodoModule for marker {packet.MarkerId}"); + } + } + } + break; + + case MarkerSettingEvent.SetIcon: + marker.icon = packet.IntValue; + break; + + case MarkerSettingEvent.SetColor: + marker.color = (byte)packet.IntValue; + break; + + case MarkerSettingEvent.SetVisibility: + marker.visibility = (EMarkerVisibility)packet.IntValue; + break; + + case MarkerSettingEvent.SetDetailLevel: + marker.detailLevel = (EMarkerDetailLevel)packet.IntValue; + break; + + case MarkerSettingEvent.SetHeight: + marker.SetHeight(factory.entityPool, packet.FloatValue); + break; + + case MarkerSettingEvent.SetRadius: + marker.SetRadius(packet.FloatValue); + break; + + default: + Log.Warn($"MarkerSettingUpdatePacket: Unknown MarkerSettingEvent {packet.Event}"); + break; + } + + Log.Debug($"MarkerSettingUpdatePacket applied: Event={packet.Event}, icon={marker.icon}, color={marker.color}, name='{marker.name}'"); + + // Trigger visual update on the marker + try + { + marker.InternalUpdate(); + } + catch (System.Exception) + { + // InternalUpdate may fail if marker visuals aren't fully initialized yet + } + } + } +} diff --git a/NebulaPatcher/Patches/Dynamic/GalacticDigitalSystem_Patch.cs b/NebulaPatcher/Patches/Dynamic/GalacticDigitalSystem_Patch.cs new file mode 100644 index 000000000..1ca7dd4fd --- /dev/null +++ b/NebulaPatcher/Patches/Dynamic/GalacticDigitalSystem_Patch.cs @@ -0,0 +1,61 @@ +#region + +using System; +using HarmonyLib; +using NebulaModel.Logger; +using NebulaWorld; + +#endregion + +namespace NebulaPatcher.Patches.Dynamic; + +[HarmonyPatch(typeof(GalacticDigitalSystem))] +internal class GalacticDigitalSystem_Patch +{ + [HarmonyPostfix] + [HarmonyPatch(nameof(GalacticDigitalSystem.Import))] + public static void Import_Postfix(GalacticDigitalSystem __instance) + { + // Only run on client - host doesn't need this refresh since they created the markers + if (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost) + { + return; + } + + // Refresh marker rendering after import to ensure visual holograms are created + // Use reflection since RecollectMarkerData location varies between game versions + try + { + var bindingFlags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance; + var instanceType = __instance.GetType(); + + var recollectMethod = instanceType.GetMethod("RecollectMarkerData", bindingFlags); + if (recollectMethod != null) + { + recollectMethod.Invoke(__instance, null); + Log.Debug("RecollectMarkerData called on GalacticDigitalSystem in Import_Postfix"); + } + else + { + var markerRendererField = instanceType.GetField("markerRenderer", bindingFlags); + if (markerRendererField != null) + { + var markerRenderer = markerRendererField.GetValue(__instance); + if (markerRenderer != null) + { + var rendererRecollectMethod = markerRenderer.GetType().GetMethod("RecollectMarkerData", bindingFlags); + if (rendererRecollectMethod != null) + { + rendererRecollectMethod.Invoke(markerRenderer, null); + Log.Debug("RecollectMarkerData called on markerRenderer in Import_Postfix"); + } + } + } + } + } + catch (Exception e) + { + Log.Warn($"RecollectMarkerData in Import_Postfix failed: {e.Message}"); + } + } +} diff --git a/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs b/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs index 7ada57469..8eb83cd33 100644 --- a/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs @@ -87,6 +87,7 @@ public static bool GetOrCreateFactory_Prefix(GameData __instance, ref PlanetFact } planet.factory = __instance.factories[factoryIndex]; } + // Initial FactoryProductionStat for other in-game stats checking functions if (GameMain.statistics.production.factoryStatPool[factoryIndex] == null) { @@ -430,4 +431,5 @@ public static bool CreateDysonSphere_Prefix(GameData __instance, int starIndex, __result = __instance.dysonSpheres[starIndex]; return false; } + } diff --git a/NebulaPatcher/Patches/Dynamic/UIMarkerDesc_Patch.cs b/NebulaPatcher/Patches/Dynamic/UIMarkerDesc_Patch.cs new file mode 100644 index 000000000..afe5ae09b --- /dev/null +++ b/NebulaPatcher/Patches/Dynamic/UIMarkerDesc_Patch.cs @@ -0,0 +1,237 @@ +#region + +using HarmonyLib; +using NebulaModel.Packets.Universe; +using NebulaWorld; + +#endregion + +namespace NebulaPatcher.Patches.Dynamic; + +[HarmonyPatch(typeof(UIMarkerDesc))] +internal class UIMarkerDesc_Patch +{ + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnTitleInputFieldEndEdit))] + public static void OnTitleInputFieldEndEdit_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetName, stringValue: __instance.marker.name)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnWordInputFieldEndEdit))] + public static void OnWordInputFieldEndEdit_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetWord, stringValue: __instance.marker.word)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnTagsInputFieldEndEdit))] + public static void OnTagsInputFieldEndEdit_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetTags, stringValue: __instance.marker.tags)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnTodoInputFieldEndEdit))] + public static void OnTodoInputFieldEndEdit_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + // Send both content and colors together - they're logically connected + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetTodoContent, + stringValue: __instance.marker.todo?.content, + colorData: __instance.marker.todo?.contentColorIndex)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnVisibilityBoxItemIndexChanged))] + public static void OnVisibilityBoxItemIndexChanged_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetVisibility, intValue: (int)__instance.marker.visibility)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnDetailLevelBoxItemIndexChanged))] + public static void OnDetailLevelBoxItemIndexChanged_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetDetailLevel, intValue: (int)__instance.marker.detailLevel)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnHeightSliderValueChanged))] + public static void OnHeightSliderValueChanged_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetHeight, floatValue: __instance.marker.height)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnRadiusSliderValueChanged))] + public static void OnRadiusSliderValueChanged_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetRadius, floatValue: __instance.marker.radius)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnIconSelectRightButtonClick))] + public static void OnIconSelectRightButtonClick_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetIcon, intValue: __instance.marker.icon)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnIconSelectLeftButtonClick))] + public static void OnIconSelectLeftButtonClick_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetIcon, intValue: __instance.marker.icon)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnIconSelectSignalPickerReturn))] + public static void OnIconSelectSignalPickerReturn_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetIcon, intValue: __instance.marker.icon)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnBriefSwitchButtonClick))] + public static void OnBriefSwitchButtonClick_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetIcon, intValue: __instance.marker.icon)); + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMarkerDesc.OnColorPanelPickerReturn))] + public static void OnColorPanelPickerReturn_Postfix(UIMarkerDesc __instance) + { + if (!Multiplayer.IsActive || Multiplayer.Session.Warning.IsIncomingMarkerPacket) + { + return; + } + if (__instance.marker == null || __instance.factory == null) + { + return; + } + Multiplayer.Session.Network.SendPacket( + new MarkerSettingUpdatePacket(__instance.factory.planetId, __instance.marker.id, + MarkerSettingEvent.SetColor, intValue: __instance.marker.color)); + } +} diff --git a/NebulaWorld/GameStates/GameStatesManager.cs b/NebulaWorld/GameStates/GameStatesManager.cs index dcce0a58a..b7f9fc499 100644 --- a/NebulaWorld/GameStates/GameStatesManager.cs +++ b/NebulaWorld/GameStates/GameStatesManager.cs @@ -37,6 +37,7 @@ public class GameStatesManager : IDisposable private byte[] spaceSectorBinaryData; private byte[] milestoneSystemBinaryData; private byte[] trashSystemBinaryData; + private byte[] galacticDigitalBinaryData; public GameStatesManager() { @@ -52,6 +53,7 @@ public void Dispose() spaceSectorBinaryData = null; milestoneSystemBinaryData = null; trashSystemBinaryData = null; + galacticDigitalBinaryData = null; GC.SuppressFinalize(this); } @@ -196,6 +198,11 @@ public void ImportGlobalGameData(GlobalGameDataResponse packet) case GlobalGameDataResponse.EDataType.TrashSystem: trashSystemBinaryData = packet.BinaryData; + Log.Info("Waiting for GalacticDigital data from the server..."); + break; + + case GlobalGameDataResponse.EDataType.GalacticDigital: + galacticDigitalBinaryData = packet.BinaryData; Log.Info("Waiting for the remaining data from the server..."); break; @@ -277,5 +284,53 @@ public void OverwriteGlobalGameData(GameData data) } trashSystemBinaryData = null; } + if (galacticDigitalBinaryData != null) + { + Log.Info("Parsing GalacticDigital data from the server..."); + using (var reader = new BinaryUtils.Reader(galacticDigitalBinaryData)) + { + data.galacticDigital.Import(reader.BinaryReader); + } + galacticDigitalBinaryData = null; + + // Refresh marker rendering after import + RefreshMarkerRendering(); + } } + + private static void RefreshMarkerRendering() + { + try + { + var galacticDigital = GameMain.data?.galacticDigital; + if (galacticDigital == null) return; + + var instanceType = galacticDigital.GetType(); + var bindingFlags = System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.Public | + System.Reflection.BindingFlags.NonPublic; + + // Try to call RecollectMarkerData directly + var recollectMethod = instanceType.GetMethod("RecollectMarkerData", bindingFlags); + if (recollectMethod != null) + { + recollectMethod.Invoke(galacticDigital, null); + return; + } + + // Fallback: Try markerRenderer field + var rendererField = instanceType.GetField("markerRenderer", bindingFlags); + if (rendererField != null) + { + var renderer = rendererField.GetValue(galacticDigital); + var rendererRecollect = renderer?.GetType().GetMethod("RecollectMarkerData", bindingFlags); + rendererRecollect?.Invoke(renderer, null); + } + } + catch (System.Exception ex) + { + Log.Warn($"RefreshMarkerRendering: {ex.Message}"); + } + } + } diff --git a/NebulaWorld/Warning/WarningManager.cs b/NebulaWorld/Warning/WarningManager.cs index 58e558b0c..c5292733a 100644 --- a/NebulaWorld/Warning/WarningManager.cs +++ b/NebulaWorld/Warning/WarningManager.cs @@ -17,6 +17,7 @@ public class WarningManager : IDisposable { public readonly ToggleSwitch IsIncomingMonitorPacket = new(); public readonly ToggleSwitch IsIncomingBroadcast = new(); + public readonly ToggleSwitch IsIncomingMarkerPacket = new(); private int idleCycle; private ConcurrentBag requesters = [];