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

finished new mechanism for blueprint building sorting

This commit is contained in:
2025-06-18 01:39:00 +08:00
parent b79cfbc994
commit b7abb3a32a
3 changed files with 142 additions and 118 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
namespace UXAssist.Functions;
@@ -135,4 +136,117 @@ public static class FactoryFunctions
blueprintCopyTool.RefreshBlueprintData();
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;
}
}
}

View File

@@ -764,8 +764,15 @@ public static class LogisticsPatch
public static void Enable(bool on)
{
if (_stationTipsRoot)
_stationTipsRoot.SetActive(on);
if (_stationTipsRoot == null) return;
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)

View File

@@ -88,126 +88,29 @@ public class PersistPatch : PatchImpl<PersistPatch>
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;
public int itemType;
public double offset;
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchForward(false,
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;
public double offset;
}
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;
}
if (!__instance.isValid) return;
Functions.FactoryFunctions.SortBlueprintData(__instance);
}
// Increase maximum value of property realizing, 2000 -> 20000