1
0
mirror of https://github.com/soarqin/DSP_Mods.git synced 2025-12-09 04:53:30 +08:00

UXAssist v1.3.2

This commit is contained in:
2025-04-28 19:40:25 +08:00
parent 5545d7a2bf
commit f407928579
6 changed files with 509 additions and 299 deletions

View File

@@ -4,8 +4,11 @@
## Changlog
* 1.3.2
+ New feature: `Disable battle-related techs in Peace mode`
+ New button: `Unlock all techs with metadata`
+ Add a checkbox to make union of results in starmap filter.
+ Fix some starmap vein/planet filter conditions.
+ Fix a crash caused by `Re-initialize planet` in peace mode.
+ Fix compatibility with `NebulaMultiplayerMod`.
* 1.3.1
+ Fix an issue that some UI elements are hidden while hitting the newly added combobox on Starmap.
@@ -294,8 +297,11 @@
## 更新日志
* 1.3.2
+ 添加了一个勾选框用于对星图过滤器的结果进行并集操作
+ 修复了一些星图过滤条件
+ 新功能:`在和平模式下隐藏战斗相关科技`
+ 新按钮:`使用元数据解锁所有科技`
+ 在星图过滤器中添加复选框以合并结果
+ 修复了一些星图矿脉/行星过滤条件
+ 修复了在和平模式下`初始化本行星`导致的崩溃问题
+ 修复了与`NebulaMultiplayerMod`的兼容性问题
* 1.3.1
+ 修复了在星图上点击新增的下拉框时部分UI元素被隐藏的问题

View File

@@ -151,15 +151,19 @@ public static class PlanetFunctions
if (warningPool[i].id == i && warningPool[i].factoryId == index)
warningSystem.RemoveWarningData(warningPool[i].id);
}
var hive = GameMain.spaceSector.dfHives[planet.star.index];
var relays = hive.relays.buffer;
var hives = GameMain.spaceSector?.dfHives;
if (hives != null)
{
var hive = hives[planet.star.index];
var relays = hive?.relays?.buffer;
if (relays != null)
{
var astroId = planet.astroId;
for (var i = relays.Length - 1; i >= 0; i--)
{
var relay = relays[i];
if (relay.id != i) continue;
if (relay.targetAstroId == astroId || relay.searchAstroId == astroId)
{
if (relay != null && relay.id != i) continue;
if (relay.targetAstroId != astroId && relay.searchAstroId != astroId) continue;
relay.targetAstroId = 0;
relay.searchAstroId = 0;
if (relay.baseId > 0)
@@ -167,6 +171,7 @@ public static class PlanetFunctions
relay.LeaveBase();
}
}
}
var isCombatMode = factory.gameData.gameDesc.isCombatMode;
factory.entityCursor = 1;
factory.entityRecycleCursor = 0;

View File

@@ -0,0 +1,313 @@
namespace UXAssist.Functions;
using System;
using System.Collections.Generic;
using Common;
using UnityEngine;
public static class TechFunctions
{
public static void Init()
{
I18N.Add("Do you want to use metadata to buyout the following tech?", "Do you want to use metadata to buyout the following tech?", "要使用元数据买断以下科技吗?");
I18N.Add("The following is the required metadata for buyout:", "The following is the required metadata for buyout:", "以下是买断所需元数据:");
I18N.Add("Batch buyout tech", "Batch buyout tech", "批量买断科技");
}
public static void GenerateTechListWithPrerequisites(GameHistoryData history, int techId, List<int> techIdList)
{
var techProto = LDB.techs.Select(techId);
if (techProto == null || !techProto.Published) return;
var flag = true;
for (var i = 0; i < 2; i++)
{
foreach (var preTechId in (i == 1 ? techProto.PreTechsImplicit : techProto.PreTechs))
{
if (!history.techStates.ContainsKey(preTechId) || history.techStates[preTechId].unlocked) continue;
if (history.techStates[preTechId].maxLevel > history.techStates[preTechId].curLevel)
{
flag = false;
}
GenerateTechListWithPrerequisites(history, preTechId, techIdList);
}
}
if (history.techStates.ContainsKey(techId) && !history.techStates[techId].unlocked && flag)
{
techIdList.Add(techId);
}
}
private static void CheckTechUnlockProperties(GameHistoryData history, TechProto techProto, SortedList<int, int> properties, List<Tuple<TechProto, int, int>> techList, int maxLevel = 10000, bool withPrerequisites = true)
{
var techStates = history.techStates;
var techID = techProto.ID;
if (techStates == null || !techStates.TryGetValue(techID, out var value)) return;
if (value.unlocked) return;
var maxLvl = Math.Min(maxLevel < 0 ? value.curLevel - maxLevel - 1 : maxLevel, value.maxLevel);
if (withPrerequisites)
{
foreach (var preid in techProto.PreTechs)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level, true);
}
foreach (var preid in techProto.PreTechsImplicit)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level, true);
}
}
if (value.curLevel < techProto.Level) value.curLevel = techProto.Level;
techList.Add(new Tuple<TechProto, int, int>(techProto, value.curLevel, techProto.Level));
while (value.curLevel <= maxLvl)
{
if (techProto.PropertyOverrideItemArray != null)
{
var propertyOverrideItemArray = techProto.PropertyOverrideItemArray;
for (var i = 0; i < propertyOverrideItemArray.Length; i++)
{
var id = propertyOverrideItemArray[i].id;
var count = (float)propertyOverrideItemArray[i].count;
var ratio = Mathf.Clamp01((float)((double)value.hashUploaded / value.hashNeeded));
var consume = Mathf.CeilToInt(count * (1f - ratio));
if (properties.TryGetValue(id, out var existingCount))
properties[id] = existingCount + consume;
else
properties.Add(id, consume);
}
}
else
{
for (var i = 0; i < techProto.itemArray.Length; i++)
{
var id = techProto.itemArray[i].ID;
var consume = (int)(techProto.ItemPoints[i] * (value.hashNeeded - value.hashUploaded) / 3600L);
if (properties.TryGetValue(id, out var existingCount))
properties[id] = existingCount + consume;
else
properties.Add(id, consume);
}
}
value.curLevel++;
value.hashUploaded = 0;
value.hashNeeded = techProto.GetHashNeeded(value.curLevel);
}
}
private static int UnlockTechImpl(GameHistoryData history, TechProto techProto, int maxLevel = 10000, bool withPrerequisites = true)
{
var techStates = history.techStates;
var techID = techProto.ID;
if (techStates == null || !techStates.TryGetValue(techID, out var value))
{
return -1;
}
if (value.unlocked)
{
return -1;
}
var maxLvl = Math.Min(maxLevel < 0 ? value.curLevel - maxLevel - 1 : maxLevel, value.maxLevel);
if (withPrerequisites)
{
foreach (var preid in techProto.PreTechs)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
UnlockTechImpl(history, preProto, techProto.PreTechsMax ? 10000 : preProto.Level, true);
}
foreach (var preid in techProto.PreTechsImplicit)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
UnlockTechImpl(history, preProto, techProto.PreTechsMax ? 10000 : preProto.Level, true);
}
}
if (value.curLevel < techProto.Level) value.curLevel = techProto.Level;
while (value.curLevel <= maxLvl)
{
if (value.curLevel == 0)
{
foreach (var recipe in techProto.UnlockRecipes)
{
history.UnlockRecipe(recipe);
}
}
for (var j = 0; j < techProto.UnlockFunctions.Length; j++)
{
history.UnlockTechFunction(techProto.UnlockFunctions[j], techProto.UnlockValues[j], value.curLevel);
}
for (var k = 0; k < techProto.AddItems.Length; k++)
{
history.GainTechAwards(techProto.AddItems[k], techProto.AddItemCounts[k]);
}
value.curLevel++;
}
value.unlocked = maxLvl >= value.maxLevel;
value.curLevel = value.unlocked ? maxLvl : maxLvl + 1;
value.hashNeeded = techProto.GetHashNeeded(value.curLevel);
value.hashUploaded = value.unlocked ? value.hashNeeded : 0;
techStates[techID] = value;
return maxLvl;
}
private static bool UnlockTechImmediately(TechProto techProto, int maxLevel = 10000, bool withPrerequisites = true)
{
if (techProto == null) return false;
var history = GameMain.history;
var ulvl = UnlockTechImpl(history, techProto, maxLevel, withPrerequisites);
if (ulvl < 0) return false;
history.RegFeatureKey(1000100);
history.NotifyTechUnlock(techProto.ID, ulvl);
return true;
}
public static void UnlockAllProtoWithMetadataAndPrompt()
{
var history = GameMain.history;
List<TechProto> techProtos = [];
foreach (var techProto in LDB.techs.dataArray)
{
if (techProto.Published && !techProto.IsObsolete && !techProto.IsHiddenTech && !history.TechUnlocked(techProto.ID) && (techProto.MaxLevel <= techProto.Level || techProto.MaxLevel <= 16) && (techProto.ID is (< 3301 or > 3309) and (< 3601 or > 3609) and (< 3901 or > 3909)) && techProto.ID != 1508)
{
techProtos.Add(techProto);
}
}
UnlockProtoWithMetadataAndPrompt([.. techProtos], false);
}
public static void UnlockProtoWithMetadataAndPrompt(TechProto[] techProtos, bool withPrerequisites = true)
{
var techList = new List<Tuple<TechProto, int, int>>();
var properties = new SortedList<int, int>();
var history = GameMain.history;
foreach (var techProto in techProtos)
{
CheckTechUnlockProperties(history, techProto, properties, techList, -1, withPrerequisites);
}
var propertySystem = DSPGame.propertySystem;
var clusterSeedKey = history.gameData.GetClusterSeedKey();
var enough = true;
foreach (var consumption in properties)
{
if (propertySystem.GetItemAvaliableProperty(clusterSeedKey, consumption.Key) >= consumption.Value) continue;
enough = false;
break;
}
if (!enough)
{
UIRealtimeTip.Popup("元数据不足".Translate(), true, 0);
return;
}
if (!history.hasUsedPropertyBanAchievement)
{
UIMessageBox.Show("初次使用元数据标题".Translate(), "初次使用元数据描述".Translate(), "取消".Translate(), "确定".Translate(), 2, null, DoUnlockCalculatedTechs);
return;
}
DoUnlockCalculatedTechs();
return;
void DoUnlockCalculatedTechs()
{
if (techList.Count <= 1)
{
UnlockWithPropertiesImmediately();
return;
}
var msg = "Do you want to use metadata to buyout the following tech?".Translate();
if (techList.Count <= 10)
{
foreach (var tuple in techList)
{
AddToMsg(ref msg, tuple);
}
}
else
{
for (var i = 0; i < 5; i++)
{
AddToMsg(ref msg, techList[i]);
}
msg += "\n ...";
for (var i = techList.Count - 5; i < techList.Count; i++)
{
AddToMsg(ref msg, techList[i]);
}
}
msg += "\n\n";
msg += "The following is the required metadata for buyout:".Translate();
foreach (var consumption in properties)
{
if (consumption.Value <= 0) continue;
msg += $"\n {LDB.items.Select(consumption.Key).propertyName}x{consumption.Value}";
}
UIMessageBox.Show("Batch buyout tech".Translate(), msg, "取消".Translate(), "确定".Translate(), 2, null, UnlockWithPropertiesImmediately);
return;
void AddToMsg(ref string str, Tuple<TechProto, int, int> tuple)
{
if (tuple.Item2 == tuple.Item3)
{
if (tuple.Item2 <= 0)
str += $"\n {tuple.Item1.name}";
else
str += $"\n {tuple.Item1.name}{"".Translate()}{tuple.Item2}";
}
else
str += $"\n {tuple.Item1.name}{"".Translate()}{tuple.Item2}->{tuple.Item3}";
}
}
void UnlockWithPropertiesImmediately()
{
var mainPlayer = GameMain.mainPlayer;
foreach (var consumption in properties)
{
if (consumption.Value <= 0) continue;
propertySystem.AddItemConsumption(clusterSeedKey, consumption.Key, consumption.Value);
history.AddPropertyItemConsumption(consumption.Key, consumption.Value, true);
mainPlayer.mecha.AddProductionStat(consumption.Key, consumption.Value, mainPlayer.nearestFactory);
mainPlayer.mecha.AddConsumptionStat(consumption.Key, consumption.Value, mainPlayer.nearestFactory);
}
foreach (var techProto in techProtos)
{
UnlockTechImmediately(techProto, -1, withPrerequisites);
}
history.VarifyTechQueue();
if (history.currentTech != history.techQueue[0])
{
history.currentTech = history.techQueue[0];
}
}
}
public static void RemoveCargoStackingTechs()
{
var history = GameMain.data?.history;
if (history == null) return;
history.inserterStackCountObsolete = 1;
for (var id = 3301; id <= 3305; id++)
{
history.techStates.TryGetValue(id, out var state);
if (!state.unlocked) continue;
state.unlocked = false;
state.hashUploaded = 0;
history.techStates[id] = state;
}
}
}

View File

@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;
using UXAssist.Common;
namespace UXAssist.Patches;
@@ -11,47 +13,54 @@ namespace UXAssist.Patches;
public static class TechPatch
{
public static ConfigEntry<bool> SorterCargoStackingEnabled;
public static ConfigEntry<bool> DisableBattleRelatedTechsInPeaceModeEnabled;
public static ConfigEntry<bool> BatchBuyoutTechEnabled;
public static void Init()
{
I18N.Add("分拣器运货量", "Sorter Mk.III cargo stacking : ", "极速分拣器每次可运送 ");
SorterCargoStackingEnabled.SettingChanged += (_, _) => SorterCargoStacking.Enable(SorterCargoStackingEnabled.Value);
DisableBattleRelatedTechsInPeaceModeEnabled.SettingChanged += (_, _) => DisableBattleRelatedTechsInPeaceMode.Enable(DisableBattleRelatedTechsInPeaceModeEnabled.Value);
BatchBuyoutTechEnabled.SettingChanged += (_, _) => BatchBuyoutTech.Enable(BatchBuyoutTechEnabled.Value);
}
public static void Start()
{
SorterCargoStacking.Enable(SorterCargoStackingEnabled.Value);
DisableBattleRelatedTechsInPeaceMode.Enable(DisableBattleRelatedTechsInPeaceModeEnabled.Value);
BatchBuyoutTech.Enable(BatchBuyoutTechEnabled.Value);
}
public static void Uninit()
{
BatchBuyoutTech.Enable(false);
DisableBattleRelatedTechsInPeaceMode.Enable(false);
SorterCargoStacking.Enable(false);
}
private class SorterCargoStacking: PatchImpl<SorterCargoStacking>
private class SorterCargoStacking
{
private static bool _protoPatched;
protected override void OnEnable()
public static void Enable(bool enable)
{
if (enable)
{
TryPatchProto(true);
GameLogic.OnDataLoaded += VFPreload_InvokeOnLoadWorkEnded_Postfix;
}
protected override void OnDisable()
else
{
GameLogic.OnDataLoaded -= VFPreload_InvokeOnLoadWorkEnded_Postfix;
TryPatchProto(false);
}
}
private static void TryPatchProto(bool on)
{
if (DSPGame.IsMenuDemo) return;
var techs = LDB.techs;
if (techs == null || techs.dataArray == null || techs.dataArray.Length == 0) return;
if (techs == null || techs?.dataArray == null || techs.dataArray.Length == 0) return;
if (on)
{
var delim = -26.0f;
@@ -114,162 +123,145 @@ public static class TechPatch
}
}
private class BatchBuyoutTech: PatchImpl<BatchBuyoutTech>
private static class DisableBattleRelatedTechsInPeaceMode
{
private static void GenerateTechList(GameHistoryData history, int techId, List<int> techIdList)
{
var techProto = LDB.techs.Select(techId);
if (techProto == null || !techProto.Published) return;
var flag = true;
for (var i = 0; i < 2; i++)
{
var array = techProto.PreTechs;
if (i == 1)
{
array = techProto.PreTechsImplicit;
}
for (var j = 0; j < array.Length; j++)
{
if (!history.techStates.ContainsKey(array[j]) || history.techStates[array[j]].unlocked) continue;
if (history.techStates[array[j]].maxLevel > history.techStates[array[j]].curLevel)
{
flag = false;
}
GenerateTechList(history, array[j], techIdList);
}
}
if (history.techStates.ContainsKey(techId) && !history.techStates[techId].unlocked && flag)
{
techIdList.Add(techId);
}
}
private static bool _protoPatched;
private static HashSet<int> _techsToDisableSet;
private static Dictionary<int, TechProto[]> _originTechPosts = [];
private static void CheckTechUnlockProperties(GameHistoryData history, TechProto techProto, int[] properties, List<Tuple<TechProto, int, int>> techList, int maxLevel = 10000)
public static void Enable(bool enable)
{
var techStates = history.techStates;
var techID = techProto.ID;
if (techStates == null || !techStates.TryGetValue(techID, out var value)) return;
if (value.unlocked) return;
var maxLvl = Math.Min(maxLevel < 0 ? value.curLevel - maxLevel - 1 : maxLevel, value.maxLevel);
foreach (var preid in techProto.PreTechs)
if (_techsToDisableSet == null)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level);
(int, int)[] techListToDisable =
[
// Combustible Unit, Explosive Unit, Crystal Explosive Unit
// 燃烧单元,爆破单元,晶石爆破单元
(1802, 1804),
// Implosion Cannon
// 聚爆加农炮
(1807, 1807),
// Signal Tower, Planetary Defense System, Jammer Tower, Plasma Turret, Titanium Ammo Box, Superalloy Ammo Box, High-Explosive Shell Set, Supersonic Missile Set, Crystal Shell Set, Gravity Missile Set, Antimatter Capsule, Precision Drone, Prototype, Attack Drone, Corvette, Destroyer, Suppressing Capsule, EM Capsule Mk.III
// 信号塔, 行星防御系统, 干扰塔, 磁化电浆炮, 钛化弹箱, 超合金弹箱, 高爆炮弹组, 超音速导弹组, 晶石炮弹组, 引力导弹组, 反物质胶囊, 地面战斗机-A型, 地面战斗机-E型, 地面战斗机-F型, 太空战斗机-A型, 太空战斗机-F型, 电磁胶囊II, 电磁胶囊III
(1809, 1825),
// Auto Reconstruction Marking
// 自动标记重建
(2951, 2956),
// Energy Shield
// 能量护盾
(2801, 2807),
// Kinetic Weapon Damage
// 动能武器伤害
(5001, 5006),
// Energy Weapon Damage
// 能量武器伤害
(5101, 5106),
// Explosive Weapon Damage
// 爆炸武器伤害
(5201, 5206),
// Combat Drone Damage
// 战斗无人机伤害
(5301, 5305),
// Combat Drone Attack Speed
// 战斗无人机攻击速度
(5401, 5405),
// Combat Drone Engine
// 战斗无人机引擎
(5601, 5605),
// Combat Drone Durability
// 战斗无人机耐久
(5701, 5705),
// Ground Squadron Expansion
// 地面编队扩容
(5801, 5807),
// Space Fleet Expansion
// 太空编队扩容
(5901, 5907),
// Enhanced Structure
// 结构强化
(6001, 6006),
// Planetary Shield
// 行星护盾
(6101, 6106),
];
_techsToDisableSet = [.. techListToDisable.SelectMany(t => Enumerable.Range(t.Item1, t.Item2 - t.Item1 + 1))];
}
foreach (var preid in techProto.PreTechsImplicit)
if (enable)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level);
}
if (value.curLevel < techProto.Level) value.curLevel = techProto.Level;
techList.Add(new Tuple<TechProto, int, int>(techProto, value.curLevel, techProto.Level));
while (value.curLevel <= maxLvl)
{
if (techProto.PropertyOverrideItemArray != null)
{
var propertyOverrideItemArray = techProto.PropertyOverrideItemArray;
for (var i = 0; i < propertyOverrideItemArray.Length; i++)
{
var id = propertyOverrideItemArray[i].id;
var count = (float)propertyOverrideItemArray[i].count;
var ratio = Mathf.Clamp01((float)((double)value.hashUploaded / value.hashNeeded));
var consume = Mathf.CeilToInt(count * (1f - ratio));
properties[id - 6001] += consume;
}
if (DSPGame.GameDesc != null)
TryPatchProto(DSPGame.GameDesc.isPeaceMode);
GameLogic.OnGameBegin += OnGameBegin;
}
else
{
for (var j = 0; j < techProto.itemArray.Length; j++)
{
var id = techProto.itemArray[j].ID;
var consume = (int)(techProto.ItemPoints[j] * (value.hashNeeded - value.hashUploaded) / 3600L);
properties[id - 6001] += consume;
}
}
value.curLevel++;
value.hashUploaded = 0;
value.hashNeeded = techProto.GetHashNeeded(value.curLevel);
GameLogic.OnGameBegin -= OnGameBegin;
TryPatchProto(false);
}
}
private static int UnlockTechRecursiveImpl(GameHistoryData history, TechProto techProto, int maxLevel = 10000)
private static void OnGameBegin()
{
var techStates = history.techStates;
var techID = techProto.ID;
if (techStates == null || !techStates.TryGetValue(techID, out var value))
{
return -1;
TryPatchProto(DSPGame.GameDesc.isPeaceMode);
}
if (value.unlocked)
private static void TryPatchProto(bool on)
{
return -1;
if (DSPGame.IsMenuDemo || on == _protoPatched) return;
var techs = LDB.techs;
if (techs?.dataArray == null || techs.dataArray.Length == 0) return;
if (on)
{
foreach (var tp in techs.dataArray)
{
if (_techsToDisableSet.Contains(tp.ID))
{
tp.IsObsolete = true;
}
var maxLvl = Math.Min(maxLevel < 0 ? value.curLevel - maxLevel - 1 : maxLevel, value.maxLevel);
foreach (var preid in techProto.PreTechs)
var postTechs = tp.postTechArray;
for (var i = postTechs.Length - 1; i >= 0; i--)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
UnlockTechRecursiveImpl(history, preProto, techProto.PreTechsMax ? 10000 : preProto.Level);
if (_techsToDisableSet.Contains(postTechs[i].ID))
{
_originTechPosts[tp.ID] = postTechs;
tp.postTechArray = [.. postTechs.Where(p => !_techsToDisableSet.Contains(p.ID))];
break;
}
foreach (var preid in techProto.PreTechsImplicit)
{
var preProto = LDB.techs.Select(preid);
if (preProto != null)
UnlockTechRecursiveImpl(history, preProto, techProto.PreTechsMax ? 10000 : preProto.Level);
}
if (value.curLevel < techProto.Level) value.curLevel = techProto.Level;
while (value.curLevel <= maxLvl)
}
_protoPatched = true;
}
else
{
if (value.curLevel == 0)
foreach (var tp in techs.dataArray)
{
foreach (var recipe in techProto.UnlockRecipes)
if (_techsToDisableSet.Contains(tp.ID))
{
history.UnlockRecipe(recipe);
tp.IsObsolete = false;
}
if (_originTechPosts.TryGetValue(tp.ID, out var postTechs))
{
tp.postTechArray = postTechs;
}
}
_originTechPosts.Clear();
_protoPatched = false;
}
foreach (var item in UIRoot.instance.uiGame.techTree.nodes)
{
var node = item.Value;
foreach (var arrow in node.arrows)
{
arrow.gameObject.SetActive(false);
}
var active = node.techProto.postTechArray.Length > 0;
node.connGroup.gameObject.SetActive(active);
node.connImages = active ? node.connGroup.GetComponentsInChildren<Image>(true) : [];
}
}
}
for (var j = 0; j < techProto.UnlockFunctions.Length; j++)
private class BatchBuyoutTech: PatchImpl<BatchBuyoutTech>
{
history.UnlockTechFunction(techProto.UnlockFunctions[j], techProto.UnlockValues[j], value.curLevel);
}
for (var k = 0; k < techProto.AddItems.Length; k++)
{
history.GainTechAwards(techProto.AddItems[k], techProto.AddItemCounts[k]);
}
value.curLevel++;
}
value.unlocked = maxLvl >= value.maxLevel;
value.curLevel = value.unlocked ? maxLvl : maxLvl + 1;
value.hashNeeded = techProto.GetHashNeeded(value.curLevel);
value.hashUploaded = value.unlocked ? value.hashNeeded : 0;
techStates[techID] = value;
return maxLvl;
}
private static bool UnlockTechRecursive(TechProto techProto, int maxLevel = 10000)
{
if (techProto == null) return false;
var history = GameMain.history;
var ulvl = UnlockTechRecursiveImpl(history, techProto, maxLevel);
if (ulvl < 0) return false;
history.RegFeatureKey(1000100);
history.NotifyTechUnlock(techProto.ID, ulvl);
return true;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(UITechNode), nameof(UITechNode.UpdateInfoDynamic))]
private static IEnumerable<CodeInstruction> UITechNode_UpdateInfoDynamic_Transpiler(IEnumerable<CodeInstruction> instructions)
@@ -296,109 +288,8 @@ public static class TechPatch
}
var techProto = __instance.techProto;
if (techProto == null) return false;
var properties = new int[6];
List<Tuple<TechProto, int, int>> techList = new();
var history = GameMain.history;
var maxLevel = -1;
CheckTechUnlockProperties(history, techProto, properties, techList, maxLevel);
var propertySystem = DSPGame.propertySystem;
var clusterSeedKey = history.gameData.GetClusterSeedKey();
var enough = true;
for (var i = 0; i < 6; i++)
{
if (propertySystem.GetItemAvaliableProperty(clusterSeedKey, 6001 + i) >= properties[i]) continue;
enough = false;
break;
}
if (!enough)
{
UIRealtimeTip.Popup("元数据不足".Translate());
Functions.TechFunctions.UnlockProtoWithMetadataAndPrompt([techProto], true);
return false;
}
if (!history.hasUsedPropertyBanAchievement)
{
UIMessageBox.Show("初次使用元数据标题".Translate(), "初次使用元数据描述".Translate(), "取消".Translate(), "确定".Translate(), 2, null, DoUnlockFunc);
return false;
}
DoUnlockFunc();
return false;
void DoUnlockFunc()
{
if (techList.Count <= 1)
{
DoUnlockFuncInternal();
return;
}
var msg = "要使用元数据买断以下科技吗?";
if (techList.Count <= 10)
{
foreach (var tuple in techList)
{
AddToMsg(ref msg, tuple);
}
}
else
{
for (var i = 0; i < 5; i++)
{
AddToMsg(ref msg, techList[i]);
}
msg += " ...\n";
for (var i = techList.Count - 5; i < techList.Count; i++)
{
AddToMsg(ref msg, techList[i]);
}
}
msg += "\n\n";
msg += "以下是买断所需元数据:";
for (var i = 0; i < 6; i++)
{
var itemCount = properties[i];
if (itemCount <= 0) continue;
msg += $"\n {LDB.items.Select(6001 + i).propertyName}x{itemCount}";
}
UIMessageBox.Show("批量买断科技", msg, "取消".Translate(), "确定".Translate(), 2, null, DoUnlockFuncInternal);
return;
void AddToMsg(ref string str, Tuple<TechProto, int, int> tuple)
{
if (tuple.Item2 == tuple.Item3)
{
if (tuple.Item2 <= 0)
str += $"\n {tuple.Item1.name}";
else
str += $"\n {tuple.Item1.name}{"".Translate()}{tuple.Item2}";
}
else
str += $"\n {tuple.Item1.name}{"".Translate()}{tuple.Item2}->{tuple.Item3}";
}
}
void DoUnlockFuncInternal()
{
var mainPlayer = GameMain.mainPlayer;
for (var i = 0; i < 6; i++)
{
var itemCount = properties[i];
if (itemCount <= 0) continue;
var itemId = 6001 + i;
propertySystem.AddItemConsumption(clusterSeedKey, itemId, itemCount);
history.AddPropertyItemConsumption(itemId, itemCount, true);
mainPlayer.mecha.AddProductionStat(itemId, itemCount, mainPlayer.nearestFactory);
mainPlayer.mecha.AddConsumptionStat(itemId, itemCount, mainPlayer.nearestFactory);
}
UnlockTechRecursive(__instance.techProto, maxLevel);
history.VarifyTechQueue();
if (history.currentTech != history.techQueue[0])
{
history.currentTech = history.techQueue[0];
}
}
}
}
}

View File

@@ -149,8 +149,10 @@ public static class UIConfigWindow
I18N.Add("Dismantle selected layer Confirm", "This operation will dismantle selected layer, are you sure?", "此操作将会拆除选中的戴森壳,确定吗?");
I18N.Add("Auto Fast Build Speed Multiplier", "Auto Fast Build Speed Multiplier", "自动快速建造速度倍率");
I18N.Add("Restore upgrades of \"Sorter Cargo Stacking\" on panel", "Restore upgrades of \"Sorter Cargo Stacking\" on panel", "在升级面板上恢复\"分拣器货物叠加\"的升级");
I18N.Add("Disable battle-related techs in Peace mode", "Disable battle-related techs in Peace mode", "在和平模式下隐藏战斗相关科技");
I18N.Add("Buy out techs with their prerequisites", "Buy out techs with their prerequisites", "购买科技也同时购买所有前置科技");
I18N.Add("Set \"Sorter Cargo Stacking\" to unresearched state", "Set \"Sorter Cargo Stacking\" to unresearched state", "将\"分拣器货物叠加\"设为未研究状态");
I18N.Add("Unlock all techs with metadata", "Unlock all techs with metadata", "使用元数据解锁所有科技");
I18N.Add("Open Dark Fog Communicator", "Open Dark Fog Communicator", "打开黑雾通讯器");
I18N.Apply();
MyConfigWindow.OnUICreated += CreateUI;
@@ -727,20 +729,11 @@ public static class UIConfigWindow
y += 36f;
wnd.AddCheckBox(x, y, tab6, TechPatch.SorterCargoStackingEnabled, "Restore upgrades of \"Sorter Cargo Stacking\" on panel");
y += 36f;
wnd.AddButton(x, y, 300f, tab6, "Set \"Sorter Cargo Stacking\" to unresearched state", 16, "button-remove-cargo-stacking", () =>
{
var history = GameMain.data?.history;
if (history == null) return;
history.inserterStackCountObsolete = 1;
for (var id = 3301; id <= 3305; id++)
{
history.techStates.TryGetValue(id, out var state);
if (!state.unlocked) continue;
state.unlocked = false;
state.hashUploaded = 0;
history.techStates[id] = state;
}
});
wnd.AddCheckBox(x, y, tab6, TechPatch.DisableBattleRelatedTechsInPeaceModeEnabled, "Disable battle-related techs in Peace mode");
y += 36f;
wnd.AddButton(x, y, 300f, tab6, "Set \"Sorter Cargo Stacking\" to unresearched state", 16, "button-remove-cargo-stacking", TechFunctions.RemoveCargoStackingTechs);
y += 36f;
wnd.AddButton(x, y, 300f, tab6, "Unlock all techs with metadata", 16, "button-unlock-all-techs-with-metadata", TechFunctions.UnlockAllProtoWithMetadataAndPrompt);
y += 36f;
y += 36f;
wnd.AddButton(x, y, 300f, tab6, "Open Dark Fog Communicator", 16, "button-open-df-communicator", () =>

View File

@@ -188,6 +188,8 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
PlayerPatch.DistanceToWarp = Config.Bind("Player", "DistanceToWarp", 5.0, "Distance to warp (in AU)");
TechPatch.SorterCargoStackingEnabled = Config.Bind("Tech", "SorterCargoStacking", false,
"Restore upgrades of `Sorter Cargo Stacking` on panel");
TechPatch.DisableBattleRelatedTechsInPeaceModeEnabled = Config.Bind("Tech", "DisableBattleRelatedTechsInPeaceMode", false,
"Disable battle-related techs in Peace mode");
TechPatch.BatchBuyoutTechEnabled = Config.Bind("Tech", "BatchBuyoutTech", false,
"Can buy out techs with their prerequisites");
DysonSpherePatch.StopEjectOnNodeCompleteEnabled = Config.Bind("DysonSphere", "StopEjectOnNodeComplete", false,