From 97fbe79814e1dae3173d930991d32e8af14b91ba Mon Sep 17 00:00:00 2001 From: starfish <50672801+starfi5h@users.noreply.github.com> Date: Mon, 9 Dec 2024 03:46:55 +0800 Subject: [PATCH 1/2] Sync UIReferenceSpeedTip --- .../StatisticsReferenceSpeedTipPacket.cs | 21 ++ .../StatisticsReferenceSpeedTipProcessor.cs | 50 +++ .../Dynamic/UIReferenceSpeedTip_Patch.cs | 47 +++ .../UIReferenceSpeedTip_Transpiler.cs | 43 +++ NebulaWorld/Statistics/StatisticsManager.cs | 328 ++++++++++++++++++ 5 files changed, 489 insertions(+) create mode 100644 NebulaModel/Packets/Statistics/StatisticsReferenceSpeedTipPacket.cs create mode 100644 NebulaNetwork/PacketProcessors/Statistics/StatisticsReferenceSpeedTipProcessor.cs create mode 100644 NebulaPatcher/Patches/Dynamic/UIReferenceSpeedTip_Patch.cs create mode 100644 NebulaPatcher/Patches/Transpilers/UIReferenceSpeedTip_Transpiler.cs diff --git a/NebulaModel/Packets/Statistics/StatisticsReferenceSpeedTipPacket.cs b/NebulaModel/Packets/Statistics/StatisticsReferenceSpeedTipPacket.cs new file mode 100644 index 000000000..8d7bc5385 --- /dev/null +++ b/NebulaModel/Packets/Statistics/StatisticsReferenceSpeedTipPacket.cs @@ -0,0 +1,21 @@ +namespace NebulaModel.Packets.Statistics; + +public class StatisticsReferenceSpeedTipPacket +{ + public StatisticsReferenceSpeedTipPacket() { } + + public StatisticsReferenceSpeedTipPacket(int itemId, int astroFilter, int itemCycle, int productionProtoId, byte[] binaryData) + { + ItemId = itemId; + AstroFilter = astroFilter; + ItemCycle = itemCycle; + ProductionProtoId = productionProtoId; + BinaryData = binaryData; + } + + public int ItemId { get; set; } + public int AstroFilter { get; set; } + public int ItemCycle { get; set; } + public int ProductionProtoId { get; set; } + public byte[] BinaryData { get; set; } +} diff --git a/NebulaNetwork/PacketProcessors/Statistics/StatisticsReferenceSpeedTipProcessor.cs b/NebulaNetwork/PacketProcessors/Statistics/StatisticsReferenceSpeedTipProcessor.cs new file mode 100644 index 000000000..63f044bc7 --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Statistics/StatisticsReferenceSpeedTipProcessor.cs @@ -0,0 +1,50 @@ +#region + +using System; +using System.IO; +using NebulaAPI.Packets; +using NebulaModel.Logger; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Statistics; +using NebulaWorld; + +#endregion + +namespace NebulaNetwork.PacketProcessors.Statistics; + +[RegisterPacketProcessor] +internal class StatisticsReferenceSpeedTipProcessor : PacketProcessor +{ + protected override void ProcessPacket(StatisticsReferenceSpeedTipPacket packet, NebulaConnection conn) + { + if (IsHost) + { + try + { + using var writer = new BinaryUtils.Writer(); + Multiplayer.Session.Statistics.GetReferenceSpeedTip(writer.BinaryWriter, packet.ItemId, packet.AstroFilter, packet.ItemCycle, packet.ProductionProtoId); + packet.BinaryData = writer.CloseAndGetBytes(); + conn.SendPacket(packet); + } + catch (Exception ex) + { + Log.Warn("StatisticsReferenceSpeedTipPacket request error!"); + Log.Warn(ex); + } + } + if (IsClient) + { + try + { + using var reader = new BinaryUtils.Reader(packet.BinaryData); + Multiplayer.Session.Statistics.SetReferenceSpeedTip(reader.BinaryReader, packet.ItemId, packet.AstroFilter, packet.ItemCycle, packet.ProductionProtoId); + } + catch (Exception ex) + { + Log.Warn("StatisticsReferenceSpeedTipPacket response error!"); + Log.Warn(ex); + } + } + } +} diff --git a/NebulaPatcher/Patches/Dynamic/UIReferenceSpeedTip_Patch.cs b/NebulaPatcher/Patches/Dynamic/UIReferenceSpeedTip_Patch.cs new file mode 100644 index 000000000..86ad75a45 --- /dev/null +++ b/NebulaPatcher/Patches/Dynamic/UIReferenceSpeedTip_Patch.cs @@ -0,0 +1,47 @@ +#region + +using System; +using HarmonyLib; +using NebulaModel.Packets.Statistics; +using NebulaWorld; +#pragma warning disable IDE0301 // Simplify collection initialization + +#endregion + +namespace NebulaPatcher.Patches.Dynamic; + +[HarmonyPatch(typeof(UIReferenceSpeedTip))] +internal class UIReferenceSpeedTip_Patch +{ + [HarmonyPrefix] + [HarmonyPatch(nameof(UIReferenceSpeedTip.AddEntryDataWithFactory))] + public static bool AddEntryDataWithFactory_Prefix() + { + // Client will use server response to update loadedEntryDatas and loadedSubTipDatas + return !Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost; + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(UIReferenceSpeedTip.SetTip))] + public static void SetTip_Prefix(UIReferenceSpeedTip __instance, int _itemId, int _astroFilter, UIReferenceSpeedTip.EItemCycle _itemCycle) + { + if (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost) return; + + // Client: Send request to server when setting a new tip + if (__instance.itemId == _itemId && __instance.astroFilter == _astroFilter && __instance.itemCycle == _itemCycle) return; + Multiplayer.Session.Network.SendPacket(new StatisticsReferenceSpeedTipPacket( + _itemId, _astroFilter, (int)_itemCycle, 0, Array.Empty())); + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(UIReferenceSpeedTip.SetSubTip))] + public static void SetSubTip_Prefix(UIReferenceSpeedTip __instance, int _productionProtoId) + { + if (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost) return; + + // Client: Send request to server when setting a valid subtip + if (_productionProtoId == 0) return; + Multiplayer.Session.Network.SendPacket(new StatisticsReferenceSpeedTipPacket( + __instance.itemId, __instance.astroFilter, (int)__instance.itemCycle, _productionProtoId, Array.Empty())); + } +} diff --git a/NebulaPatcher/Patches/Transpilers/UIReferenceSpeedTip_Transpiler.cs b/NebulaPatcher/Patches/Transpilers/UIReferenceSpeedTip_Transpiler.cs new file mode 100644 index 000000000..c23f57db9 --- /dev/null +++ b/NebulaPatcher/Patches/Transpilers/UIReferenceSpeedTip_Transpiler.cs @@ -0,0 +1,43 @@ +#region + +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using HarmonyLib; +using NebulaModel.Logger; + +#endregion + +namespace NebulaPatcher.Patches.Transpilers; + +[HarmonyPatch(typeof(UIReferenceSpeedTip))] +public static class UIReferenceSpeedTip_Transpiler +{ + [HarmonyTranspiler] + [HarmonyPatch(nameof(UIReferenceSpeedTip.RefreshSubEntries))] + private static IEnumerable RefreshSubEntries_Transpiler(IEnumerable instructions) + { + //Remove planetData.factory != null condiction check + //Change: if (planetData != null && planetData.factory != null && this.loadedSubTipDatas[planetData.astroId].astroId == planetData.astroId) + //To: if (planetData != null && this.loadedSubTipDatas[planetData.astroId].astroId == planetData.astroId) + var codeInstructions = instructions as CodeInstruction[] ?? instructions.ToArray(); + try + { + return new CodeMatcher(instructions) + .MatchForward(true, + new CodeMatch(OpCodes.Ldfld, + AccessTools.Field(typeof(PlanetData), nameof(PlanetData.factory))), + new CodeMatch(OpCodes.Brfalse) + ) + .Repeat(matcher => matcher + .SetAndAdvance(OpCodes.Pop, null) + ) + .InstructionEnumeration(); + } + catch + { + Log.Error("Transpiler UIReferenceSpeedTip.RefreshSubEntries failed. Reference speed tip may not work properly."); + return codeInstructions; + } + } +} diff --git a/NebulaWorld/Statistics/StatisticsManager.cs b/NebulaWorld/Statistics/StatisticsManager.cs index a8447dba2..7c7682ab5 100644 --- a/NebulaWorld/Statistics/StatisticsManager.cs +++ b/NebulaWorld/Statistics/StatisticsManager.cs @@ -5,8 +5,12 @@ using System.IO; using NebulaAPI.DataStructures; using NebulaModel.DataStructures; +using NebulaModel.Logger; using NebulaModel.Networking; using NebulaModel.Packets.Statistics; +using UnityEngine; +#pragma warning disable IDE0007 // Use implicit type +#pragma warning disable IDE1006 // Naming rule #endregion @@ -22,12 +26,30 @@ public class StatisticsManager : IDisposable private List statisticalSnapShots = []; private long lastUpdateTime; + private readonly UIReferenceSpeedTip referenceSpeedTip; public bool IsStatisticsNeeded { get; set; } public long[] PowerEnergyStoredData { get; set; } public int FactoryCount { get; set; } public int TechHashedFor10Frames { get; set; } + public StatisticsManager() + { + var gameObject = GameObject.Find("UI Root/Overlay Canvas/In Game/Top Tips/Item Reference Speed Tips/ref-speed-tip"); + if (gameObject == null) + { + Log.Warn("StatisticsManager: Can't find ref-speed-tip!"); + } + else + { + referenceSpeedTip = gameObject.GetComponent(); + if (referenceSpeedTip == null) + { + Log.Warn("StatisticsManager: Can't find UIReferenceSpeedTip component!"); + } + } + } + public void Dispose() { statisticalSnapShots = null; @@ -268,6 +290,312 @@ public long UpdateTotalChargedEnergy(int factoryIndex) return PowerEnergyStoredData[factoryIndex]; } + public void GetReferenceSpeedTip(BinaryWriter bw, int itemId, int astroFilter, int itemCycle, int productionProtoId) + { + if (referenceSpeedTip == null) return; + + var tmpItemId = referenceSpeedTip.itemId; + var tmpAstroFilter = referenceSpeedTip.astroFilter; + var tmpItemCycle = referenceSpeedTip.itemCycle; + var tmpProductionProtoId = referenceSpeedTip.productionProtoId; + + referenceSpeedTip.itemId = itemId; + referenceSpeedTip.astroFilter = astroFilter; + referenceSpeedTip.itemCycle = (UIReferenceSpeedTip.EItemCycle)itemCycle; + referenceSpeedTip.productionProtoId = productionProtoId; + CalculateReferenceSpeedTip(); + + var list = new List(); + for (var i = 0; i < referenceSpeedTip.loadedEntryDatas.Length; i++) + { + if (referenceSpeedTip.loadedEntryDatas[i].productionProtoId != 0) list.Add(i); + } + bw.Write(list.Count); + foreach (var index in list) + { + ref var ptr = ref referenceSpeedTip.loadedEntryDatas[index]; + bw.Write(index); + bw.Write(ptr.productionProtoId); + bw.Write(ptr.normalCount); + bw.Write(ptr.normalSpeed); + bw.Write(ptr.useInc2IncCount); + bw.Write(ptr.useInc2IncSpeed); + bw.Write(ptr.useInc2AccCount); + bw.Write(ptr.useInc2AccSpeed); + bw.Write(ptr.outNetworkCount); + bw.Write(ptr.outNetworkSpeed); + } + + list.Clear(); + for (var i = 0; i < referenceSpeedTip.loadedSubTipDatas.Length; i++) + { + if (referenceSpeedTip.loadedSubTipDatas[i].astroId != 0) list.Add(i); + } + bw.Write(list.Count); + foreach (var index in list) + { + ref var ptr = ref referenceSpeedTip.loadedSubTipDatas[index]; + bw.Write(index); + bw.Write(ptr.astroId); + bw.Write(ptr.normalCount); + bw.Write(ptr.normalSpeed); + bw.Write(ptr.useInc2IncCount); + bw.Write(ptr.useInc2IncSpeed); + bw.Write(ptr.useInc2AccCount); + bw.Write(ptr.useInc2AccSpeed); + bw.Write(ptr.outNetworkCount); + bw.Write(ptr.outNetworkSpeed); + } + + referenceSpeedTip.itemId = tmpItemId; + referenceSpeedTip.astroFilter = tmpAstroFilter; + referenceSpeedTip.itemCycle = tmpItemCycle; + referenceSpeedTip.productionProtoId = tmpProductionProtoId; + CalculateReferenceSpeedTip(); + } + + public void SetReferenceSpeedTip(BinaryReader br, int itemId, int astroFilter, int itemCycle, int productionProtoId) + { + if (referenceSpeedTip == null) return; + if (referenceSpeedTip.itemId != itemId || referenceSpeedTip.astroFilter != astroFilter || (int)referenceSpeedTip.itemCycle != itemCycle) return; + + Array.Clear(referenceSpeedTip.loadedEntryDatas, 0, referenceSpeedTip.loadedEntryDatas.Length); + var listCount = br.ReadInt32(); + for (var i = 0; i < listCount; i++) + { + var index = br.ReadInt32(); + ref var ptr = ref referenceSpeedTip.loadedEntryDatas[index]; + ptr.productionProtoId = br.ReadInt32(); + ptr.normalCount = br.ReadInt32(); + ptr.normalSpeed = br.ReadSingle(); + ptr.useInc2IncCount = br.ReadInt32(); + ptr.useInc2IncSpeed = br.ReadSingle(); + ptr.useInc2AccCount = br.ReadInt32(); + ptr.useInc2AccSpeed = br.ReadSingle(); + ptr.outNetworkCount = br.ReadInt32(); + ptr.outNetworkSpeed = br.ReadSingle(); + } + // Refresh UI + RefreshReferenceSpeedTipEntries(); + + if (productionProtoId != 0 && referenceSpeedTip.productionProtoId == productionProtoId) + { + Array.Clear(referenceSpeedTip.loadedSubTipDatas, 0, referenceSpeedTip.loadedSubTipDatas.Length); + listCount = br.ReadInt32(); + for (var i = 0; i < listCount; i++) + { + var index = br.ReadInt32(); + ref var ptr = ref referenceSpeedTip.loadedSubTipDatas[index]; + ptr.astroId = br.ReadInt32(); + ptr.normalCount = br.ReadInt32(); + ptr.normalSpeed = br.ReadSingle(); + ptr.useInc2IncCount = br.ReadInt32(); + ptr.useInc2IncSpeed = br.ReadSingle(); + ptr.useInc2AccCount = br.ReadInt32(); + ptr.useInc2AccSpeed = br.ReadSingle(); + ptr.outNetworkCount = br.ReadInt32(); + ptr.outNetworkSpeed = br.ReadSingle(); + } + referenceSpeedTip.RefreshSubEntries(); + } + } + + private void CalculateReferenceSpeedTip() + { + // Part of UIReferenceSpeedTip.SetSubTip + if (referenceSpeedTip == null) return; + + if (referenceSpeedTip.loadedEntryDatas == null) + { + referenceSpeedTip.loadedEntryDatas = new RefSpeedTipEntryData[12000]; + } + if (referenceSpeedTip.loadedSubTipDatas == null) + { + referenceSpeedTip.loadedSubTipDatas = new RefSpeedSubTipEntryData[25700]; + } + Array.Clear(referenceSpeedTip.loadedEntryDatas, 0, referenceSpeedTip.loadedEntryDatas.Length); + Array.Clear(referenceSpeedTip.loadedSubTipDatas, 0, referenceSpeedTip.loadedSubTipDatas.Length); + var data = GameMain.data; + var history = data.history; + var itemProto = LDB.items.Select(2313); + var array = ((itemProto != null) ? itemProto.prefabDesc.incItemId : null); + var num = 0; + if (array != null) + { + for (var i = 0; i < array.Length; i++) + { + if (history.ItemUnlocked(array[i])) + { + var itemProto2 = LDB.items.Select(array[i]); + if (itemProto2 != null && itemProto2.Ability > num) + { + num = itemProto2.Ability; + } + } + } + } + var incMulti = 1f + (float)Cargo.incTableMilli[num]; + var accMulti = 1f + (float)Cargo.accTableMilli[num]; + var maxStack = 1; + if (history.TechUnlocked(1607)) + { + maxStack = 4; + } + var inserterStackOutput = history.inserterStackOutput; + var stationPilerLevel = history.stationPilerLevel; + if (inserterStackOutput > maxStack) + { + maxStack = inserterStackOutput; + } + if (inserterStackOutput > maxStack) + { + maxStack = stationPilerLevel; + } + if (referenceSpeedTip.astroFilter == 0) + { + var factoryCount = data.factoryCount; + for (var j = 0; j < factoryCount; j++) + { + referenceSpeedTip.AddEntryDataWithFactory(data.factories[j], incMulti, accMulti, maxStack, referenceSpeedTip.productionProtoId); + } + } + else if (referenceSpeedTip.astroFilter % 100 == 0) + { + var starData = data.galaxy.StarById(referenceSpeedTip.astroFilter / 100); + if (starData != null) + { + var planets = starData.planets; + for (var k = 0; k < starData.planetCount; k++) + { + var planetData = planets[k]; + if (planetData != null && planetData.factory != null) + { + referenceSpeedTip.AddEntryDataWithFactory(data.factories[planetData.factoryIndex], incMulti, accMulti, maxStack, referenceSpeedTip.productionProtoId); + } + } + } + else + { + var factoryCount = data.factoryCount; + for (var l = 0; l < factoryCount; l++) + { + referenceSpeedTip.AddEntryDataWithFactory(data.factories[l], incMulti, accMulti, maxStack, referenceSpeedTip.productionProtoId); + } + } + } + else + { + var planetData = data.galaxy.PlanetById(referenceSpeedTip.astroFilter); + if (planetData != null && planetData.factory != null) + { + referenceSpeedTip.AddEntryDataWithFactory(planetData.factory, incMulti, accMulti, maxStack, referenceSpeedTip.productionProtoId); + } + } + } + + private void RefreshReferenceSpeedTipEntries() + { + // Lower part of UIReferenceSpeedTip.SetTip + if (referenceSpeedTip == null) return; + + ItemProto[] dataArray = LDB.items.dataArray; + referenceSpeedTip.activeEntryCount = 0; + float num5 = 0f; + int num6 = (int)referenceSpeedTip.entryPrefab.rectTrans.anchoredPosition.y; + int num7 = (int)(referenceSpeedTip.entryPrefab.rectTrans.rect.width + 0.5f); + for (int m = 0; m < dataArray.Length; m++) + { + if (referenceSpeedTip.loadedEntryDatas[dataArray[m].ID].productionProtoId != 0) + { + if (referenceSpeedTip.activeEntryCount >= referenceSpeedTip.entries.Count) + { + UIReferenceSpeedTipEntry uireferenceSpeedTipEntry = UnityEngine.Object.Instantiate(referenceSpeedTip.entryPrefab, referenceSpeedTip.entryPrefab.rectTrans.parent); + referenceSpeedTip.entries.Add(uireferenceSpeedTipEntry); + } + ref RefSpeedTipEntryData ptr = ref referenceSpeedTip.loadedEntryDatas[dataArray[m].ID]; + referenceSpeedTip.entries[referenceSpeedTip.activeEntryCount].gameObject.SetActive(true); + referenceSpeedTip.entries[referenceSpeedTip.activeEntryCount].entryData = ptr; + referenceSpeedTip.entries[referenceSpeedTip.activeEntryCount].Refresh(); + referenceSpeedTip.entries[referenceSpeedTip.activeEntryCount].rectTrans.anchoredPosition = new Vector2(referenceSpeedTip.entryPrefab.rectTrans.anchoredPosition.x, (float)num6); + num6 -= referenceSpeedTip.entries[referenceSpeedTip.activeEntryCount].entryHeight; + if (num7 < referenceSpeedTip.entries[referenceSpeedTip.activeEntryCount].entryWidth) + { + num7 = referenceSpeedTip.entries[referenceSpeedTip.activeEntryCount].entryWidth; + } + num5 += ptr.normalSpeed + ptr.useInc2IncSpeed + ptr.useInc2AccSpeed + ptr.outNetworkSpeed; + referenceSpeedTip.activeEntryCount++; + } + } + for (int n = referenceSpeedTip.activeEntryCount; n < referenceSpeedTip.entries.Count; n++) + { + referenceSpeedTip.entries[n].gameObject.SetActive(false); + } + if (referenceSpeedTip.activeEntryCount == 0) + { + referenceSpeedTip.zeroCountTipText.gameObject.SetActive(true); + if (referenceSpeedTip.itemCycle == UIReferenceSpeedTip.EItemCycle.Production) + { + referenceSpeedTip.zeroCountTipText.text = "参考速率无生产设施".Translate(); + } + else if (referenceSpeedTip.itemCycle == UIReferenceSpeedTip.EItemCycle.Consumption) + { + referenceSpeedTip.zeroCountTipText.text = "参考速率无消耗设施".Translate(); + } + num6 -= (int)(referenceSpeedTip.zeroCountTipText.rectTransform.rect.height + 0.5f); + } + else + { + referenceSpeedTip.zeroCountTipText.gameObject.SetActive(false); + } + referenceSpeedTip.totalSpeedText.text = ((long)(num5 + 0.5f)).ToString("#,##0") + " / min"; + if (referenceSpeedTip.itemCycle == UIReferenceSpeedTip.EItemCycle.Production) + { + referenceSpeedTip.totalSpeedLabel.color = referenceSpeedTip.productColor; + referenceSpeedTip.totalSpeedText.color = referenceSpeedTip.productColor; + } + else if (referenceSpeedTip.itemCycle == UIReferenceSpeedTip.EItemCycle.Consumption) + { + referenceSpeedTip.totalSpeedLabel.color = referenceSpeedTip.consumeColor; + referenceSpeedTip.totalSpeedText.color = referenceSpeedTip.consumeColor; + } + else + { + referenceSpeedTip.totalSpeedLabel.color = Color.white; + referenceSpeedTip.totalSpeedText.color = Color.white; + } + referenceSpeedTip.rectTrans.SetParent(UIRoot.instance.itemReferenceSpeedTipTransform, true); + referenceSpeedTip.rectTrans.sizeDelta = new Vector2(num7 + 20f, (float)(-(float)num6) + 2f); + Rect rect = UIRoot.instance.itemReferenceSpeedTipTransform.rect; + float num8 = Mathf.RoundToInt(rect.width); + float num9 = Mathf.RoundToInt(rect.height); + Vector2 anchoredPosition = referenceSpeedTip.rectTrans.anchoredPosition; + float num10 = referenceSpeedTip.rectTrans.anchorMin.x * num8 + anchoredPosition.x; + float num11 = referenceSpeedTip.rectTrans.anchorMin.y * num9 + anchoredPosition.y; + Rect rect2 = referenceSpeedTip.rectTrans.rect; + rect2.x += num10; + rect2.y += num11; + Vector2 zero = Vector2.zero; + if (rect2.xMin < 0f) + { + zero.x -= rect2.xMin; + } + if (rect2.yMin < 0f) + { + zero.y -= rect2.yMin; + } + if (rect2.xMax > num8) + { + zero.x -= rect2.xMax - num8; + } + if (rect2.yMax > num9) + { + zero.y -= rect2.yMax - num9; + } + Vector2 vector2 = anchoredPosition + zero; + vector2 = new Vector2(Mathf.Round(vector2.x), Mathf.Round(vector2.y)); + referenceSpeedTip.rectTrans.anchoredPosition = vector2; + } + private sealed class ThreadSafe { internal readonly Dictionary Requestors = new(); From bb31f4cb39de9fe77806bf63e9729cde33b75aa8 Mon Sep 17 00:00:00 2001 From: starfish <50672801+starfi5h@users.noreply.github.com> Date: Mon, 9 Dec 2024 04:01:18 +0800 Subject: [PATCH 2/2] Bump version and changelog to v0.9.12 --- CHANGELOG.md | 7 +++++++ README.md | 9 +++++---- version.json | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0371ca76..90f3af0b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ## Changelog +0.9.12: +- Compatible with game version 0.10.31.24697 +- @starfi5h: Client can now use metadata to unlock tech. Sandbox unlock by client is now synced +- @starfi5h: Remove metadata requirement for blueprint tech due to client can't get metadata in MP +- @starfi5h: The right part of logistics control panel (I) is available for loaded planet +- @starfi5h: Sync Reference rate, Import/Export storage, Storage amount in production statistics panel + 0.9.11: - @starfi5h: Fix half-growth dark fog bases keep regenerating - @starfi5h: Fix combat drones doesn't increase ground base threat diff --git a/README.md b/README.md index 48d7bb94c..cd249975a 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ This mod has an API, that makes it easier for other mod developers to make their ### Chat -The chat window can opened/closed using Alt + Backtick (configurable in Settings - Multiplayer - Chat). Type `/help` to view all commands. Also in settings is an option to disable the chat window from automatically opening when a message is received. +The chat window can opened/closed using `Alt + Backtick` (configurable in Settings - Multiplayer - Chat). Type `/help` to view all commands. Also in settings is an option to disable the chat window from automatically opening when a message is received. ### What is the current status? Major refactors will happen while the project grows or game updates. Join the [Discord Server](https://discord.gg/UHeB2QvgDa) if you want to see to latest state of our development. Check [Wiki](https://github.com/NebulaModTeam/nebula/wiki/About-Nebula) for overview of features. -The multiplayer mod now supports Dark Fog combat mode in the latest game version (0.10.30.x). +The multiplayer mod now supports Dark Fog combat mode in the latest game version (0.10.31.x). Most of the battle aspects are sync, only few features are still WIP.
@@ -59,7 +59,7 @@ Most of the battle aspects are sync, only few features are still WIP. - [x] Entity upgrade syncing - [x] Dyson spheres syncing - [x] Researches syncing -- [x] Factories statistics syncing +- [x] Factories statistics syncing (some new extra info is not sync) - [x] Containers inventory syncing - [x] Building Interaction syncing - [x] Belts interaction syncing (pickup, putdown) @@ -71,7 +71,8 @@ Most of the battle aspects are sync, only few features are still WIP. - [x] Power network syncing (charger and request power from dyson sphere) - [x] Warning alarm syncing - [x] Broadcast notification syncing (events with guide icon) -- [x] Logistics Control Panel (I) syncing (entry list without detail panel) +- [x] Logistics Control Panel (I) syncing (entry list and detail panel) +- [ ] Goal system (currently not available in client)
diff --git a/version.json b/version.json index 6efe545d0..93cf786e6 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.9.11", + "version": "0.9.12", "assemblyVersion": { "precision": "build" },