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 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(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 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 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.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.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.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 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(); if (globalStorage == null) { Log.Error("GlobalStorageWorldComponent not found"); return false; } int submittedCount = 0; List processedItems = new List(); // 复制列表以避免修改时迭代 List 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.GetNamedSilentFail("ResourceSubmitterSkyfaller"); if (skyfallerDef == null) { // 备用:使用运输舱效果 skyfallerDef = DefDatabase.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); } } }