mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2025-12-09 14:53:30 +08:00
finished new mechanism for blueprint building sorting
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace UXAssist.Functions;
|
namespace UXAssist.Functions;
|
||||||
|
|
||||||
@@ -135,4 +136,117 @@ public static class FactoryFunctions
|
|||||||
blueprintCopyTool.RefreshBlueprintData();
|
blueprintCopyTool.RefreshBlueprintData();
|
||||||
blueprintCopyTool.DeterminePreviews();
|
blueprintCopyTool.DeterminePreviews();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct BPBuildingData
|
||||||
|
{
|
||||||
|
public BlueprintBuilding building;
|
||||||
|
public int itemType;
|
||||||
|
public double offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct BPBeltData
|
||||||
|
{
|
||||||
|
public BlueprintBuilding building;
|
||||||
|
public double offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HashSet<int> _itemIsBelt = null;
|
||||||
|
private static Dictionary<int, int> _upgradeTypes = null;
|
||||||
|
|
||||||
|
public static void SortBlueprintData(BlueprintData blueprintData)
|
||||||
|
{
|
||||||
|
// Initialize itemIsBelt and upgradeTypes
|
||||||
|
if (_itemIsBelt == null)
|
||||||
|
{
|
||||||
|
_itemIsBelt = [];
|
||||||
|
_upgradeTypes = [];
|
||||||
|
foreach (var proto in LDB.items.dataArray)
|
||||||
|
{
|
||||||
|
if (proto.prefabDesc?.isBelt ?? false)
|
||||||
|
{
|
||||||
|
_itemIsBelt.Add(proto.ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (proto.Upgrades != null && proto.Upgrades.Length > 0)
|
||||||
|
{
|
||||||
|
var minUpgrade = proto.Upgrades.Min(u => u);
|
||||||
|
if (minUpgrade != 0 && minUpgrade != proto.ID)
|
||||||
|
{
|
||||||
|
_upgradeTypes.Add(proto.ID, minUpgrade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate belt and non-belt buildings
|
||||||
|
List<BPBuildingData> bpBuildings = [];
|
||||||
|
Dictionary<BlueprintBuilding, BPBeltData> bpBelts = [];
|
||||||
|
foreach (var building in blueprintData.buildings)
|
||||||
|
{
|
||||||
|
var offset = building.areaIndex * 1073741824.0 + building.localOffset_y * 262144.0 + building.localOffset_x * 1024.0 + building.localOffset_z;
|
||||||
|
if (_itemIsBelt.Contains(building.itemId))
|
||||||
|
{
|
||||||
|
bpBelts.Add(building, new BPBeltData { building = building, offset = offset });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var itemType = _upgradeTypes.TryGetValue(building.itemId, out var upgradeType) ? upgradeType : building.itemId;
|
||||||
|
bpBuildings.Add(new BPBuildingData { building = building, itemType = itemType, offset = offset });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var beltsWithInput = bpBelts.Select(pair => pair.Value.building.outputObj).ToHashSet();
|
||||||
|
var beltHeads = bpBelts.Where(pair => !beltsWithInput.Contains(pair.Value.building)).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||||
|
// Sort belt buildings
|
||||||
|
List<BlueprintBuilding> sortedBpBelts = [];
|
||||||
|
// Deal with non-cycle belt paths
|
||||||
|
foreach (var pair in beltHeads.OrderByDescending(pair => pair.Value.offset))
|
||||||
|
{
|
||||||
|
var building = pair.Key;
|
||||||
|
while (building != null)
|
||||||
|
{
|
||||||
|
if (!bpBelts.Remove(building)) break;
|
||||||
|
sortedBpBelts.Add(building);
|
||||||
|
building = building.outputObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Deal with cycle belt paths
|
||||||
|
foreach (var pair in bpBelts.OrderByDescending(pair => pair.Value.offset))
|
||||||
|
{
|
||||||
|
var building = pair.Key;
|
||||||
|
while (building != null)
|
||||||
|
{
|
||||||
|
if (!bpBelts.Remove(building)) break;
|
||||||
|
sortedBpBelts.Add(building);
|
||||||
|
building = building.outputObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort non-belt buildings
|
||||||
|
bpBuildings.Sort((a, b) =>
|
||||||
|
{
|
||||||
|
var sign = b.itemType.CompareTo(a.itemType);
|
||||||
|
if (sign != 0) return sign;
|
||||||
|
|
||||||
|
sign = b.building.modelIndex.CompareTo(a.building.modelIndex);
|
||||||
|
if (sign != 0) return sign;
|
||||||
|
|
||||||
|
sign = b.building.recipeId.CompareTo(a.building.recipeId);
|
||||||
|
if (sign != 0) return sign;
|
||||||
|
|
||||||
|
sign = a.building.areaIndex.CompareTo(b.building.areaIndex);
|
||||||
|
if (sign != 0) return sign;
|
||||||
|
|
||||||
|
return b.offset.CompareTo(a.offset);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Concatenate sorted belts and non-belt buildings
|
||||||
|
sortedBpBelts.Reverse();
|
||||||
|
blueprintData.buildings = [.. bpBuildings.Select(b => b.building), .. sortedBpBelts];
|
||||||
|
var buildings = blueprintData.buildings;
|
||||||
|
|
||||||
|
for (var i = buildings.Length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
buildings[i].index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -764,8 +764,15 @@ public static class LogisticsPatch
|
|||||||
|
|
||||||
public static void Enable(bool on)
|
public static void Enable(bool on)
|
||||||
{
|
{
|
||||||
if (_stationTipsRoot)
|
if (_stationTipsRoot == null) return;
|
||||||
_stationTipsRoot.SetActive(on);
|
if (!on)
|
||||||
|
{
|
||||||
|
_stationTipsRoot.SetActive(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DSPGame.IsMenuDemo || !GameMain.isRunning) return;
|
||||||
|
_lastPlanet = GameMain.localPlanet;
|
||||||
|
_stationTipsRoot.SetActive(on && _lastPlanet != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EnableBars(bool on)
|
public static void EnableBars(bool on)
|
||||||
|
|||||||
@@ -88,126 +88,29 @@ public class PersistPatch : PatchImpl<PersistPatch>
|
|||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort blueprint structures by item id, model index, recipe id, area index, and position before saving
|
|
||||||
private struct BPBuildingData
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_BlueprintCopy), nameof(BuildTool_BlueprintCopy.UseToPasteNow))]
|
||||||
|
private static IEnumerable<CodeInstruction> BuildTool_BlueprintCopy_UseToPasteNow_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
{
|
{
|
||||||
public BlueprintBuilding building;
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
public int itemType;
|
matcher.MatchForward(false,
|
||||||
public double offset;
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(BuildTool_BlueprintCopy), nameof(BuildTool_BlueprintCopy.RefreshBlueprintData)))
|
||||||
|
).Advance(2).Insert(
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(BuildTool_BlueprintCopy), nameof(BuildTool_BlueprintCopy.blueprint))),
|
||||||
|
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Functions.FactoryFunctions), nameof(Functions.FactoryFunctions.SortBlueprintData)))
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct BPBeltData
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(BlueprintData), nameof(BlueprintData.SaveBlueprintData))]
|
||||||
|
private static void BlueprintData_SaveBlueprintData_Prefix(BlueprintData __instance)
|
||||||
{
|
{
|
||||||
public BlueprintBuilding building;
|
if (!__instance.isValid) return;
|
||||||
public double offset;
|
Functions.FactoryFunctions.SortBlueprintData(__instance);
|
||||||
}
|
|
||||||
|
|
||||||
private static HashSet<int> _itemIsBelt = null;
|
|
||||||
private static Dictionary<int, int> _upgradeTypes = null;
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(BlueprintUtils), nameof(BlueprintUtils.GenerateBlueprintData))]
|
|
||||||
private static void BlueprintUtils_GenerateBlueprintData_Postfix(BlueprintData _blueprintData)
|
|
||||||
{
|
|
||||||
// Initialize itemIsBelt and upgradeTypes
|
|
||||||
if (_itemIsBelt == null)
|
|
||||||
{
|
|
||||||
_itemIsBelt = [];
|
|
||||||
_upgradeTypes = [];
|
|
||||||
foreach (var proto in LDB.items.dataArray)
|
|
||||||
{
|
|
||||||
if (proto.prefabDesc?.isBelt ?? false)
|
|
||||||
{
|
|
||||||
_itemIsBelt.Add(proto.ID);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (proto.Upgrades != null && proto.Upgrades.Length > 0)
|
|
||||||
{
|
|
||||||
var minUpgrade = proto.Upgrades.Min(u => u);
|
|
||||||
if (minUpgrade != 0 && minUpgrade != proto.ID)
|
|
||||||
{
|
|
||||||
_upgradeTypes.Add(proto.ID, minUpgrade);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Separate belt and non-belt buildings
|
|
||||||
List<BPBuildingData> bpBuildings = [];
|
|
||||||
Dictionary<BlueprintBuilding, BPBeltData> bpBelts = [];
|
|
||||||
for (var i = 0; i < _blueprintData.buildings.Length; i++)
|
|
||||||
{
|
|
||||||
var building = _blueprintData.buildings[i];
|
|
||||||
var offset = building.localOffset_y * 262144.0 + building.localOffset_x * 1024.0 + building.localOffset_z;
|
|
||||||
if (_itemIsBelt.Contains(building.itemId))
|
|
||||||
{
|
|
||||||
bpBelts.Add(building, new BPBeltData { building = building, offset = offset });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var itemType = _upgradeTypes.TryGetValue(building.itemId, out var upgradeType) ? upgradeType : building.itemId;
|
|
||||||
bpBuildings.Add(new BPBuildingData { building = building, itemType = itemType, offset = offset });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Dictionary<BlueprintBuilding, BPBeltData> beltHeads = new(bpBelts);
|
|
||||||
foreach (var building in bpBelts.Keys)
|
|
||||||
{
|
|
||||||
var next = building.outputObj;
|
|
||||||
if (next == null) continue;
|
|
||||||
beltHeads.Remove(next);
|
|
||||||
}
|
|
||||||
// Sort belt buildings
|
|
||||||
List<BlueprintBuilding> sortedBpBelts = [];
|
|
||||||
// Deal with non-cycle belt paths
|
|
||||||
foreach (var pair in beltHeads.OrderByDescending(pair => pair.Value.offset))
|
|
||||||
{
|
|
||||||
var building = pair.Key;
|
|
||||||
while (building != null)
|
|
||||||
{
|
|
||||||
if (!bpBelts.Remove(building)) break;
|
|
||||||
sortedBpBelts.Add(building);
|
|
||||||
building = building.outputObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Deal with cycle belt paths
|
|
||||||
while (bpBelts.Count > 0)
|
|
||||||
{
|
|
||||||
var building = bpBelts.OrderByDescending(pair => pair.Value.offset).First().Key;
|
|
||||||
while (building != null)
|
|
||||||
{
|
|
||||||
if (!bpBelts.Remove(building)) break;
|
|
||||||
sortedBpBelts.Add(building);
|
|
||||||
building = building.outputObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort non-belt buildings
|
|
||||||
bpBuildings.Sort((a, b) =>
|
|
||||||
{
|
|
||||||
var sign = b.itemType.CompareTo(a.itemType);
|
|
||||||
if (sign != 0) return sign;
|
|
||||||
|
|
||||||
sign = b.building.modelIndex.CompareTo(a.building.modelIndex);
|
|
||||||
if (sign != 0) return sign;
|
|
||||||
|
|
||||||
sign = b.building.recipeId.CompareTo(a.building.recipeId);
|
|
||||||
if (sign != 0) return sign;
|
|
||||||
|
|
||||||
sign = a.building.areaIndex.CompareTo(b.building.areaIndex);
|
|
||||||
if (sign != 0) return sign;
|
|
||||||
|
|
||||||
return b.offset.CompareTo(a.offset);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Concatenate sorted belts and non-belt buildings
|
|
||||||
sortedBpBelts.Reverse();
|
|
||||||
_blueprintData.buildings = [.. bpBuildings.Select(b => b.building), .. sortedBpBelts];
|
|
||||||
var buildings = _blueprintData.buildings;
|
|
||||||
|
|
||||||
for (var i = buildings.Length - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
buildings[i].index = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase maximum value of property realizing, 2000 -> 20000
|
// Increase maximum value of property realizing, 2000 -> 20000
|
||||||
|
|||||||
Reference in New Issue
Block a user