This commit is contained in:
Tourswen
2025-11-04 00:45:25 +08:00
parent 0c02135040
commit 9905782298
36 changed files with 1851 additions and 1238 deletions

View File

@@ -0,0 +1,391 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
using System;
using System.Text;
namespace WulaFallenEmpire
{
public class CompResourceSubmitter : ThingComp, IThingHolder
{
public ThingOwner innerContainer;
public List<TransferableOneWay> leftToLoad;
private bool massUsageDirty = true;
private float cachedMassUsage;
public CompProperties_ResourceSubmitter Props => (CompProperties_ResourceSubmitter)props;
public float MassUsage
{
get
{
if (massUsageDirty)
{
massUsageDirty = false;
cachedMassUsage = CollectionsMassCalculator.MassUsage(innerContainer, IgnorePawnsInventoryMode.IgnoreIfAssignedToUnload, includePawnsMass: false);
}
return cachedMassUsage;
}
}
public bool OverMassCapacity => MassUsage > Props.massCapacity;
public bool AnythingLeftToLoad => FirstThingLeftToLoad != null;
public Thing FirstThingLeftToLoad
{
get
{
if (leftToLoad == null) return null;
for (int i = 0; i < leftToLoad.Count; i++)
{
if (leftToLoad[i].CountToTransfer != 0 && leftToLoad[i].HasAnyThing)
return leftToLoad[i].AnyThing;
}
return null;
}
}
public CompResourceSubmitter()
{
innerContainer = new ThingOwner<Thing>(this);
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
Scribe_Collections.Look(ref leftToLoad, "leftToLoad", LookMode.Deep);
if (Scribe.mode == LoadSaveMode.Saving)
{
leftToLoad?.RemoveWhere(t => t == null);
}
}
public ThingOwner GetDirectlyHeldThings()
{
return innerContainer;
}
public void GetChildHolders(List<IThingHolder> outChildren)
{
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
}
// 在 CompResourceSubmitter 类中添加或更新以下方法:
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
massUsageDirty = true;
}
public override void PostDeSpawn(Map map, DestroyMode mode = DestroyMode.Vanish)
{
base.PostDeSpawn(map, mode);
if (mode != DestroyMode.WillReplace)
{
innerContainer.TryDropAll(parent.Position, map, ThingPlaceMode.Near);
}
}
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
foreach (Gizmo g in base.CompGetGizmosExtra())
{
yield return g;
}
// 装载命令
Command_LoadToResourceSubmitter loadCommand = new Command_LoadToResourceSubmitter();
loadCommand.defaultLabel = "WULA_LoadResourceSubmitter".Translate();
loadCommand.defaultDesc = "WULA_LoadResourceSubmitterDesc".Translate();
loadCommand.icon = ContentFinder<Texture2D>.Get("UI/Commands/LoadTransporter");
loadCommand.submitterComp = this;
// 禁用检查
if (!parent.Spawned)
{
loadCommand.Disable("WULA_NotSpawned".Translate());
}
else if (!IsOperational())
{
loadCommand.Disable(GetInoperativeReason());
}
yield return loadCommand;
// 取消装载/卸载命令
if (innerContainer.Any || AnythingLeftToLoad)
{
Command_Action cancelCommand = new Command_Action();
cancelCommand.defaultLabel = innerContainer.Any ? "WULA_Unload".Translate() : "WULA_CancelLoad".Translate();
cancelCommand.defaultDesc = innerContainer.Any ? "WULA_UnloadDesc".Translate() : "WULA_CancelLoadDesc".Translate();
cancelCommand.icon = ContentFinder<Texture2D>.Get("UI/Designators/Cancel");
cancelCommand.action = CancelLoad;
yield return cancelCommand;
}
// 发射命令
Command_Action launchCommand = new Command_Action();
launchCommand.defaultLabel = "WULA_LaunchSubmitter".Translate();
launchCommand.defaultDesc = "WULA_LaunchSubmitterDesc".Translate();
launchCommand.icon = ContentFinder<Texture2D>.Get("UI/Commands/Launch");
launchCommand.action = TryLaunch;
// 发射条件检查
if (!parent.Spawned)
{
launchCommand.Disable("WULA_NotSpawned".Translate());
}
else if (!IsOperational())
{
launchCommand.Disable(GetInoperativeReason());
}
else if (!innerContainer.Any)
{
launchCommand.Disable("WULA_NoItemsToSubmit".Translate());
}
else if (OverMassCapacity)
{
launchCommand.Disable("WULA_OverMassCapacity".Translate(MassUsage.ToString("F1"), Props.massCapacity.ToString("F1")));
}
yield return launchCommand;
}
public override string CompInspectStringExtra()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("WULA_SubmitterContents".Translate() + ": " + innerContainer.ContentsString.CapitalizeFirst());
string massString = "WULA_Mass".Translate() + ": " + MassUsage.ToString("F1") + " / " + Props.massCapacity.ToString("F1") + " kg";
stringBuilder.AppendLine().Append(OverMassCapacity ? massString.Colorize(ColorLibrary.RedReadable) : massString);
if (!IsOperational())
{
stringBuilder.AppendLine().Append("WULA_Status".Translate() + ": " + "WULA_Inoperative".Translate().Colorize(ColorLibrary.RedReadable));
}
return stringBuilder.ToString();
}
public void AddToTheToLoadList(TransferableOneWay t, int count)
{
if (!t.HasAnyThing || count <= 0) return;
if (leftToLoad == null)
{
leftToLoad = new List<TransferableOneWay>();
}
TransferableOneWay existing = TransferableUtility.TransferableMatching(t.AnyThing, leftToLoad, TransferAsOneMode.PodsOrCaravanPacking);
if (existing != null)
{
for (int i = 0; i < t.things.Count; i++)
{
if (!existing.things.Contains(t.things[i]))
{
existing.things.Add(t.things[i]);
}
}
if (existing.CanAdjustBy(count).Accepted)
{
existing.AdjustBy(count);
}
}
else
{
TransferableOneWay newTransferable = new TransferableOneWay();
leftToLoad.Add(newTransferable);
newTransferable.things.AddRange(t.things);
newTransferable.AdjustTo(count);
}
}
public void Notify_ThingAdded(Thing t)
{
SubtractFromToLoadList(t, t.stackCount);
massUsageDirty = true;
}
public void Notify_ThingRemoved(Thing t)
{
massUsageDirty = true;
}
public void Notify_ThingAddedAndMergedWith(Thing t, int mergedCount)
{
SubtractFromToLoadList(t, mergedCount);
massUsageDirty = true;
}
private int SubtractFromToLoadList(Thing t, int count)
{
if (leftToLoad == null) return 0;
TransferableOneWay transferable = TransferableUtility.TransferableMatchingDesperate(t, leftToLoad, TransferAsOneMode.PodsOrCaravanPacking);
if (transferable == null || transferable.CountToTransfer <= 0) return 0;
int num = Mathf.Min(count, transferable.CountToTransfer);
transferable.AdjustBy(-num);
if (transferable.CountToTransfer <= 0)
{
leftToLoad.Remove(transferable);
}
return num;
}
private void CancelLoad()
{
if (leftToLoad != null)
{
leftToLoad.Clear();
}
innerContainer.TryDropAll(parent.Position, parent.Map, ThingPlaceMode.Near);
massUsageDirty = true;
}
private void TryLaunch()
{
if (!IsOperational())
{
Messages.Message(GetInoperativeReason(), MessageTypeDefOf.RejectInput);
return;
}
if (!innerContainer.Any)
{
Messages.Message("WULA_NoItemsToSubmit".Translate(), MessageTypeDefOf.RejectInput);
return;
}
if (OverMassCapacity)
{
Messages.Message("WULA_OverMassCapacity".Translate(MassUsage.ToString("F1"), Props.massCapacity.ToString("F1")), MessageTypeDefOf.RejectInput);
return;
}
if (SubmitContentsToStorage())
{
CreateLaunchEffect();
parent.Destroy();
}
}
private bool SubmitContentsToStorage()
{
try
{
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
if (globalStorage == null)
{
Log.Error("GlobalStorageWorldComponent not found");
return false;
}
int submittedCount = 0;
List<Thing> processedItems = new List<Thing>();
// 复制列表以避免修改时迭代
List<Thing> itemsToProcess = innerContainer.ToList();
foreach (Thing item in itemsToProcess)
{
if (item == null || item.Destroyed) continue;
if (IsEquipment(item.def))
{
globalStorage.AddToOutputStorage(item.def, item.stackCount);
}
else
{
globalStorage.AddToInputStorage(item.def, item.stackCount);
}
processedItems.Add(item);
submittedCount += item.stackCount;
}
// 从容器中移除已提交的物品
foreach (Thing item in processedItems)
{
innerContainer.Remove(item);
}
Messages.Message("WULA_ItemsSubmitted".Translate(submittedCount), MessageTypeDefOf.PositiveEvent);
Log.Message($"Successfully submitted {submittedCount} items to global storage");
return submittedCount > 0;
}
catch (Exception ex)
{
Log.Error($"Error submitting items to storage: {ex}");
Messages.Message("WULA_SubmissionFailed".Translate(), MessageTypeDefOf.NegativeEvent);
return false;
}
}
private bool IsEquipment(ThingDef thingDef)
{
return thingDef.IsApparel || thingDef.IsWeapon || thingDef.category == ThingCategory.Building;
}
private void CreateLaunchEffect()
{
try
{
// 使用自定义的 Skyfaller 定义
ThingDef skyfallerDef = DefDatabase<ThingDef>.GetNamedSilentFail("ResourceSubmitterSkyfaller");
if (skyfallerDef == null)
{
// 备用:使用运输舱效果
skyfallerDef = DefDatabase<ThingDef>.GetNamedSilentFail("DropPodIncoming");
}
if (skyfallerDef != null)
{
Skyfaller skyfaller = (Skyfaller)ThingMaker.MakeThing(skyfallerDef);
GenSpawn.Spawn(skyfaller, parent.Position, parent.Map);
}
// 视觉效果
for (int i = 0; i < 3; i++)
{
FleckMaker.ThrowLightningGlow(parent.DrawPos, parent.Map, 2f);
}
FleckMaker.ThrowSmoke(parent.DrawPos, parent.Map, 3f);
}
catch (Exception ex)
{
Log.Error($"Error creating launch effect: {ex}");
}
}
private bool IsOperational()
{
var building = parent as Building_ResourceSubmitter;
return building?.IsOperational ?? false;
}
private string GetInoperativeReason()
{
var building = parent as Building_ResourceSubmitter;
return building?.GetInoperativeReason() ?? "WULA_UnknownReason".Translate();
}
}
public class CompProperties_ResourceSubmitter : CompProperties
{
public float massCapacity = 150f;
public CompProperties_ResourceSubmitter()
{
compClass = typeof(CompResourceSubmitter);
}
}
}