diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index 195a9b4..17d032e 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo index 74e14a2..f351ef6 100644 Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json index a23da55..5cd4f8b 100644 --- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json +++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json @@ -2,12 +2,32 @@ "Version": 1, "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "Documents": [ + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_uniquepawn\\uniquepawnmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_uniquepawn\\uniquepawnmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_uniquepawn\\compuniquepawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_uniquepawn\\compuniquepawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\needs\\need_honeyproduction.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:needs\\need_honeyproduction.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_extracthoney\\jobdriver_extracthoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_extracthoney\\jobdriver_extracthoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\needs\\need_chitinarmor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:needs\\need_chitinarmor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, { "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_psychicloaddump\\compabilityeffect_psychicloaddump.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_psychicloaddump\\compabilityeffect_psychicloaddump.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_psychicloaddump\\compproperties_abilitypsychicloaddump.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_psychicloaddump\\compproperties_abilitypsychicloaddump.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_psychicloaddump\\compproperties_abilitypsychicloaddump.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { @@ -23,7 +43,7 @@ "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_psychicloadcost\\compabilityeffect_psychicloadcost.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_psychicresearchharvest\\compabilityeffect_psychicresearchharvest.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_psychicresearchharvest\\compabilityeffect_psychicresearchharvest.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_psychicresearchharvest\\compabilityeffect_psychicresearchharvest.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { @@ -82,7 +102,7 @@ "DocumentGroups": [ { "DockedWidth": 200, - "SelectedChildIndex": 2, + "SelectedChildIndex": 1, "Children": [ { "$type": "Bookmark", @@ -90,33 +110,97 @@ }, { "$type": "Document", - "DocumentIndex": 1, - "Title": "CompProperties_AbilityPsychicLoadDump.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs", - "RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs*", - "RelativeToolTip": "Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs*", - "ViewState": "AgIAACIAAAAAAAAAAAApwH0AAAAFAAAAAAAAAA==", + "DocumentIndex": 0, + "Title": "UniquePawnManager.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", + "RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", + "RelativeToolTip": "Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs", + "ViewState": "AgIAAIYAAAAAAAAAAAAUwJ4AAAANAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-02-04T08:36:24.395Z", + "WhenOpened": "2026-02-05T03:36:35.207Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 0, + "DocumentIndex": 1, + "Title": "CompUniquePawn.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", + "RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", + "RelativeToolTip": "Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs", + "ViewState": "AgIAAKgAAAAAAAAAAAAtwLkAAAARAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-02-05T03:36:24.458Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 3, + "Title": "JobDriver_ExtractHoney.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs", + "RelativeDocumentMoniker": "Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs", + "RelativeToolTip": "Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs", + "ViewState": "AgIAAAQAAAAAAAAAAAAswBMAAAAJAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-02-05T03:32:58.466Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 2, + "Title": "Need_HoneyProduction.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_HoneyProduction.cs", + "RelativeDocumentMoniker": "Needs\\Need_HoneyProduction.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_HoneyProduction.cs", + "RelativeToolTip": "Needs\\Need_HoneyProduction.cs", + "ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAAIAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-02-05T03:21:22.655Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 4, + "Title": "Need_ChitinArmor.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_ChitinArmor.cs", + "RelativeDocumentMoniker": "Needs\\Need_ChitinArmor.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_ChitinArmor.cs", + "RelativeToolTip": "Needs\\Need_ChitinArmor.cs", + "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-02-05T03:21:22.016Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 6, + "Title": "CompProperties_AbilityPsychicLoadDump.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs", + "RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs", + "RelativeToolTip": "Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs", + "ViewState": "AgIAACIAAAAAAAAAAAApwH0AAAAFAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2026-02-04T08:36:24.395Z" + }, + { + "$type": "Document", + "DocumentIndex": 5, "Title": "CompAbilityEffect_PsychicLoadDump.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs", "RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs*", - "RelativeToolTip": "Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs*", - "ViewState": "AgIAAGoAAAAAAAAAAAAtwGsAAAAvAAAAAAAAAA==", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs", + "RelativeToolTip": "Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs", + "ViewState": "AgIAAAgAAAAAAAAAAAAowBIAAAASAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2026-02-04T08:36:23.647Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 5, + "DocumentIndex": 10, "Title": "CompAbilityEffect_PsychicResearchHarvest.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicResearchHarvest\\CompAbilityEffect_PsychicResearchHarvest.cs", "RelativeDocumentMoniker": "Abilities\\ARA_PsychicResearchHarvest\\CompAbilityEffect_PsychicResearchHarvest.cs", @@ -124,12 +208,11 @@ "RelativeToolTip": "Abilities\\ARA_PsychicResearchHarvest\\CompAbilityEffect_PsychicResearchHarvest.cs", "ViewState": "AgIAAD0AAAAAAAAAAAA7wGkAAAASAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-02-04T03:35:17.441Z", - "EditorCaption": "" + "WhenOpened": "2026-02-04T03:35:17.441Z" }, { "$type": "Document", - "DocumentIndex": 9, + "DocumentIndex": 14, "Title": "CompProperties_AbilityPsychicLoadCost.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs", "RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs", @@ -141,7 +224,7 @@ }, { "$type": "Document", - "DocumentIndex": 8, + "DocumentIndex": 13, "Title": "SwarmSpellUtility.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs", "RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs", @@ -153,7 +236,7 @@ }, { "$type": "Document", - "DocumentIndex": 4, + "DocumentIndex": 9, "Title": "CompAbilityEffect_PsychicLoadCost.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs", "RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs", @@ -161,12 +244,11 @@ "RelativeToolTip": "Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs", "ViewState": "AgIAAMwAAAAAAAAAAAAawOcAAABZAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-30T08:16:09.317Z", - "EditorCaption": "" + "WhenOpened": "2026-01-30T08:16:09.317Z" }, { "$type": "Document", - "DocumentIndex": 2, + "DocumentIndex": 7, "Title": "Comp_SwarmSpellHolder.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs", "RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs", @@ -174,12 +256,11 @@ "RelativeToolTip": "Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs", "ViewState": "AgIAAFgCAAAAAAAAAAAYwGkCAAASAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-30T07:11:59.797Z", - "EditorCaption": "" + "WhenOpened": "2026-01-30T07:11:59.797Z" }, { "$type": "Document", - "DocumentIndex": 3, + "DocumentIndex": 8, "Title": "Gizmo_SwarmSpellStatus.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs", "RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs", @@ -187,12 +268,11 @@ "RelativeToolTip": "Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs", "ViewState": "AgIAAIAAAAAAAAAAAAAIwIsAAAATAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2026-01-30T08:20:07.463Z", - "EditorCaption": "" + "WhenOpened": "2026-01-30T08:20:07.463Z" }, { "$type": "Document", - "DocumentIndex": 10, + "DocumentIndex": 15, "Title": "CompAbilityEffect_HediffGacha.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffGacha\\CompAbilityEffect_HediffGacha.cs", "RelativeDocumentMoniker": "Abilities\\ARA_HediffGacha\\CompAbilityEffect_HediffGacha.cs", @@ -204,7 +284,7 @@ }, { "$type": "Document", - "DocumentIndex": 7, + "DocumentIndex": 12, "Title": "CompFighterInvisible.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Fighter_Invisible\\CompFighterInvisible.cs", "RelativeDocumentMoniker": "Pawn_Comps\\ARA_Fighter_Invisible\\CompFighterInvisible.cs", @@ -216,7 +296,7 @@ }, { "$type": "Document", - "DocumentIndex": 6, + "DocumentIndex": 11, "Title": "CompProperties_AbilityPsychicResearchHarvest.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicResearchHarvest\\CompProperties_AbilityPsychicResearchHarvest.cs", "RelativeDocumentMoniker": "Abilities\\ARA_PsychicResearchHarvest\\CompProperties_AbilityPsychicResearchHarvest.cs", @@ -228,7 +308,7 @@ }, { "$type": "Document", - "DocumentIndex": 11, + "DocumentIndex": 16, "Title": "CompAbilityEffect_HediffRestriction.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffRestriction\\CompAbilityEffect_HediffRestriction.cs", "RelativeDocumentMoniker": "Abilities\\ARA_HediffRestriction\\CompAbilityEffect_HediffRestriction.cs", @@ -240,7 +320,7 @@ }, { "$type": "Document", - "DocumentIndex": 12, + "DocumentIndex": 17, "Title": "Window_HediffSelection.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffGacha\\Window_HediffSelection.cs", "RelativeDocumentMoniker": "Abilities\\ARA_HediffGacha\\Window_HediffSelection.cs", @@ -252,7 +332,7 @@ }, { "$type": "Document", - "DocumentIndex": 13, + "DocumentIndex": 18, "Title": "ARA_PowerArmor.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PowerArmor\\ARA_PowerArmor.cs", "RelativeDocumentMoniker": "PowerArmor\\ARA_PowerArmor.cs", @@ -264,7 +344,7 @@ }, { "$type": "Document", - "DocumentIndex": 14, + "DocumentIndex": 19, "Title": "PawnCapacityWorker_PsychicStange.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PawnCapacityWorker\\PawnCapacityWorker_PsychicStange.cs", "RelativeDocumentMoniker": "PawnCapacityWorker\\PawnCapacityWorker_PsychicStange.cs", @@ -276,7 +356,7 @@ }, { "$type": "Document", - "DocumentIndex": 16, + "DocumentIndex": 21, "Title": "CompAbilityEffect_PsychicBrainburn.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs", "RelativeDocumentMoniker": "Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs", @@ -288,7 +368,7 @@ }, { "$type": "Document", - "DocumentIndex": 15, + "DocumentIndex": 20, "Title": "ARA_DefOf.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs", "RelativeDocumentMoniker": "ARA_DefOf.cs", @@ -300,7 +380,7 @@ }, { "$type": "Document", - "DocumentIndex": 17, + "DocumentIndex": 22, "Title": "CompAutoMechCarrier.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs", "RelativeDocumentMoniker": "Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs", diff --git a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompAbilityEffect_PsychicLoadDump.cs b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompAbilityEffect_PsychicLoadDump.cs index 665da6c..7db8adf 100644 --- a/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompAbilityEffect_PsychicLoadDump.cs +++ b/Source/ArachnaeSwarm/Abilities/ARA_PsychicLoadDump/CompAbilityEffect_PsychicLoadDump.cs @@ -450,60 +450,6 @@ namespace ArachnaeSwarm } #endregion - #region 验证和工具提示 - public override bool Valid(LocalTargetInfo target, bool throwMessages = false) - { - if (!base.Valid(target, throwMessages)) - return false; - - Pawn targetPawn = target.Pawn; - if (targetPawn == null) - { - if (throwMessages) - Messages.Message("需要选择一个目标单位", MessageTypeDefOf.RejectInput); - return false; - } - - // 检查目标是否活着且没有倒下(如果技能不允许对倒下单位使用) - if (!Props.canTargetDowned && targetPawn.Downed) - { - if (throwMessages) - Messages.Message("目标已经倒下,无法转储负载", MessageTypeDefOf.RejectInput); - return false; - } - - // 检查施法者是否有术法组件且有负载 - Pawn caster = parent.pawn; - if (caster != null) - { - Comp_SwarmSpellHolder spellHolder = caster.TryGetComp(); - if (spellHolder == null) - { - if (throwMessages) - Messages.Message("施法者没有灵能术法系统", MessageTypeDefOf.RejectInput); - return false; - } - - if (!spellHolder.IsSystemInitialized) - { - if (throwMessages) - Messages.Message("灵能术法系统未初始化", MessageTypeDefOf.RejectInput); - return false; - } - - // 检查是否有负载可转储 - if (spellHolder.PsychicLoad <= 0f) - { - if (throwMessages) - Messages.Message("没有可转储的灵能负载", MessageTypeDefOf.RejectInput); - return false; - } - } - - return true; - } - #endregion - #region AI 行为 public override bool AICanTargetNow(LocalTargetInfo target) { diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/CompUniquePawn.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/CompUniquePawn.cs index 3f07b0b..0591bab 100644 --- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/CompUniquePawn.cs +++ b/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/CompUniquePawn.cs @@ -22,14 +22,12 @@ namespace ArachnaeSwarm { if (Props == null || string.IsNullOrEmpty(Props.globalVariable)) { - Log.Warning("CompUniquePawn: Props.globalVariable is null or empty"); + Log.Warning("[唯一Pawn系统] Props.globalVariable为空"); return null; } return Props.globalVariable; } } - - public int SpawnTick { get; private set; } = -1; #endregion #region 生命周期方法 @@ -40,10 +38,6 @@ namespace ArachnaeSwarm if (this.parent == null || !(this.parent is Pawn pawn) || !pawn.Spawned) return; - // 记录生成时间 - if (SpawnTick < 0) - SpawnTick = Find.TickManager.TicksGame; - // 如果是重新生成,检查是否有效 if (respawningAfterLoad) { @@ -76,14 +70,14 @@ namespace ArachnaeSwarm } catch (Exception ex) { - Log.Error($"Error in delayed unique pawn check: {ex}"); + Log.Error($"[唯一Pawn系统] 延迟检查错误: {ex}"); _scheduledForCheck = false; } }, "ArachnaeSwarm_UniquePawnCheck", false, null); } catch (Exception ex) { - Log.Error($"Error in CompUniquePawn.PostSpawnSetup: {ex}"); + Log.Error($"[唯一Pawn系统] PostSpawnSetup错误: {ex}"); _scheduledForCheck = false; } } @@ -107,7 +101,11 @@ namespace ArachnaeSwarm // Pawn被销毁时注销 if (this.parent is Pawn pawn && !string.IsNullOrEmpty(GlobalVariable)) { - UniquePawnManager.Instance?.UnregisterPawn(pawn, GlobalVariable); + var manager = Current.Game?.GetComponent(); + if (manager != null) + { + manager.UnregisterPawn(pawn, GlobalVariable); + } } } @@ -116,7 +114,11 @@ namespace ArachnaeSwarm // Pawn被反生成时也注销 if (this.parent is Pawn pawn && !string.IsNullOrEmpty(GlobalVariable)) { - UniquePawnManager.Instance?.UnregisterPawn(pawn, GlobalVariable); + var manager = Current.Game?.GetComponent(); + if (manager != null) + { + manager.UnregisterPawn(pawn, GlobalVariable); + } } } #endregion @@ -129,7 +131,11 @@ namespace ArachnaeSwarm { if (this.parent is Pawn pawn && !string.IsNullOrEmpty(GlobalVariable) && pawn.Spawned && !pawn.Destroyed) { - UniquePawnManager.Instance?.SendVerificationSignal(pawn, GlobalVariable); + var manager = Current.Game?.GetComponent(); + if (manager != null) + { + manager.SendVerificationSignal(pawn, GlobalVariable); + } } } @@ -140,7 +146,11 @@ namespace ArachnaeSwarm { if (this.parent is Pawn pawn && !string.IsNullOrEmpty(GlobalVariable)) { - return UniquePawnManager.Instance?.IsEarliestPawn(pawn, GlobalVariable) ?? false; + var manager = Current.Game?.GetComponent(); + if (manager != null) + { + return manager.IsEarliestPawn(pawn, GlobalVariable); + } } return false; } @@ -155,26 +165,29 @@ namespace ArachnaeSwarm if (string.IsNullOrEmpty(variable)) { - Log.Error("CompUniquePawn: globalVariable is null or empty"); + Log.Error("[唯一Pawn系统] globalVariable为空"); return; } // 向管理器注册 - bool registered = UniquePawnManager.Instance.RegisterPawn(pawn, variable); + var manager = Current.Game?.GetComponent(); + if (manager == null) + { + Log.Error("[唯一Pawn系统] 无法获取UniquePawnManager"); + return; + } + + bool registered = manager.RegisterPawn(pawn, variable); if (!registered) { // 注册失败,说明有更早的Pawn存在 KillPawn(pawn, variable); } - else - { - Log.Message($"[唯一Pawn系统] 成功注册Pawn: {pawn.Label} (变量: {variable})"); - } } catch (Exception ex) { - Log.Error($"Error in CheckAndHandleUniquePawn: {ex}"); + Log.Error($"[唯一Pawn系统] CheckAndHandleUniquePawn错误: {ex}"); } } @@ -188,7 +201,11 @@ namespace ArachnaeSwarm return; // 检查是否仍然是最早的Pawn - bool isEarliest = UniquePawnManager.Instance?.IsEarliestPawn(pawn, variable) ?? false; + var manager = Current.Game?.GetComponent(); + if (manager == null) + return; + + bool isEarliest = manager.IsEarliestPawn(pawn, variable); if (!isEarliest) { @@ -204,7 +221,7 @@ namespace ArachnaeSwarm } catch (Exception ex) { - Log.Error($"Error in HandleRespawnAfterLoad: {ex}"); + Log.Error($"[唯一Pawn系统] HandleRespawnAfterLoad错误: {ex}"); } } @@ -222,8 +239,6 @@ namespace ArachnaeSwarm } } - Log.Message($"[唯一Pawn系统] 移除重复Pawn: {pawn.Label} (变量: {variable})"); - // 延迟执行杀死操作 LongEventHandler.QueueLongEvent(() => { @@ -244,20 +259,21 @@ namespace ArachnaeSwarm } catch (Exception ex) { - Log.Error($"Error in delayed pawn kill: {ex}"); + Log.Error($"[唯一Pawn系统] 延迟杀死错误: {ex}"); } }, "ArachnaeSwarm_KillDuplicatePawn", false, null); } catch (Exception ex) { - Log.Error($"Error in KillPawn: {ex}"); + Log.Error($"[唯一Pawn系统] KillPawn错误: {ex}"); } } #endregion #region 序列化 - public void ExposeData() + public override void PostExposeData() { + base.PostExposeData(); Scribe_Values.Look(ref _checked, "checked", false); Scribe_Values.Look(ref _scheduledForCheck, "scheduledForCheck", false); Scribe_Values.Look(ref _lastVerificationTick, "lastVerificationTick", -1); diff --git a/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/UniquePawnManager.cs b/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/UniquePawnManager.cs index e94309c..c1a5b33 100644 --- a/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/UniquePawnManager.cs +++ b/Source/ArachnaeSwarm/Pawn_Comps/ARA_UniquePawn/UniquePawnManager.cs @@ -10,29 +10,10 @@ namespace ArachnaeSwarm /// /// 唯一Pawn管理器 /// 管理所有具有唯一标识的Pawn,确保同一标识只有一个存活 + /// 注意:数据完全绑定到当前Game,不会跨存档生效 /// public class UniquePawnManager : GameComponent { - #region 单例和静态访问 - private static UniquePawnManager _instance; - public static UniquePawnManager Instance - { - get - { - if (_instance == null && Current.Game != null) - { - _instance = Current.Game.GetComponent(); - if (_instance == null) - { - _instance = new UniquePawnManager(Current.Game); - Current.Game.components.Add(_instance); - } - } - return _instance; - } - } - #endregion - #region 数据定义 /// /// Pawn注册信息 @@ -46,6 +27,7 @@ namespace ArachnaeSwarm public string pawnName; public bool isValid = true; public int lastVerificationTick = -1; + public string gameId; // 添加游戏ID,确保只对当前游戏有效 public void ExposeData() { @@ -56,6 +38,7 @@ namespace ArachnaeSwarm Scribe_Values.Look(ref pawnName, "pawnName"); Scribe_Values.Look(ref isValid, "isValid", true); Scribe_Values.Look(ref lastVerificationTick, "lastVerificationTick", -1); + Scribe_Values.Look(ref gameId, "gameId"); } } #endregion @@ -65,21 +48,100 @@ namespace ArachnaeSwarm private int lastVerificationTick = -1; private const int VERIFICATION_INTERVAL = 600; // 每10秒验证一次 private const int VERIFICATION_TIMEOUT = 1200; // 20秒无响应视为失效 - private object syncLock = new object(); + private string currentGameId; + private bool initialized = false; #endregion #region 构造函数 public UniquePawnManager(Game game) : base() { + if (game == null) + return; + Initialize(); } private void Initialize() { - lock (syncLock) + if (initialized) + return; + + try { - if (registeredPawns == null) - registeredPawns = new List(); + // 生成当前游戏的唯一ID(基于游戏开始时间和随机数) + GenerateGameId(); + + // 清理不属于当前游戏的注册信息 + CleanupForeignRegistrations(); + + initialized = true; + } + catch (Exception ex) + { + Log.Error($"[唯一Pawn系统] 初始化失败: {ex.Message}"); + } + } + + + /// + /// 生成当前游戏的唯一ID + /// + private void GenerateGameId() + { + if (Current.Game == null) + { + currentGameId = "NoGame"; + return; + } + + try + { + // 获取游戏开始时间(使用tickManager的gameStartAbsTick) + int gameStartTick = Find.TickManager.gameStartAbsTick; + int randomSeed = UnityEngine.Random.Range(1000, 9999); + + // 获取游戏信息 + string gameName = GetGameName(); + + // 创建唯一ID + currentGameId = $"Game_{gameStartTick}_{randomSeed}_{gameName.GetHashCode():X8}"; + } + catch (Exception ex) + { + Log.Error($"[唯一Pawn系统] 生成游戏ID失败: {ex.Message}"); + // 使用备用ID + currentGameId = $"Game_{Find.TickManager.TicksGame}_{UnityEngine.Random.Range(1000, 9999)}"; + } + } + // + /// 获取游戏名称 + /// + private string GetGameName() + { + try + { + // 方法1:尝试从存档文件获取 + if (Current.Game.Info != null) + { + // GameInfo中没有name属性,但可能有其他标识 + if (!string.IsNullOrEmpty(Current.Game.Info.permadeathModeUniqueName)) + { + return Current.Game.Info.permadeathModeUniqueName; + } + } + + // 方法2:使用世界种子 + if (Current.Game.World != null && Current.Game.World.info != null) + { + return Current.Game.World.info.seedString ?? "UnknownSeed"; + } + + // 方法3:使用当前时间 + return DateTime.Now.ToString("yyyyMMdd_HHmmss"); + } + catch (Exception) + { + return "UnknownGame"; } } #endregion @@ -92,69 +154,72 @@ namespace ArachnaeSwarm { if (pawn == null || string.IsNullOrEmpty(globalVariable)) { - Log.Warning("尝试注册空Pawn或空全局变量"); + Log.Warning("[唯一Pawn系统] 尝试注册空Pawn或空全局变量"); return false; } - lock (syncLock) + if (!initialized) + Initialize(); + + // 清理无效注册 + CleanupInvalidRegistrations(); + + // 获取当前tick + int currentTick = Find.TickManager.TicksGame; + + // 检查是否已存在相同全局变量的Pawn(仅限当前游戏) + var existingInfos = GetInfosForVariable(globalVariable, true); + var validExistingInfos = existingInfos.Where(info => info.isValid).ToList(); + + // 如果有有效的已注册Pawn + if (validExistingInfos.Count > 0) { - // 清理无效注册 - CleanupInvalidRegistrations(); - - // 获取当前tick - int currentTick = Find.TickManager.TicksGame; - - // 检查是否已存在相同全局变量的Pawn - var existingInfos = GetInfosForVariable(globalVariable); - var validExistingInfos = existingInfos.Where(info => info.isValid).ToList(); - - // 如果有有效的已注册Pawn - if (validExistingInfos.Count > 0) + // 按生成时间排序,保留最早的 + var earliestInfo = validExistingInfos.OrderBy(info => info.spawnTick).First(); + + // 如果当前Pawn不是最早的,则杀死 + if (earliestInfo.thingID != pawn.thingIDNumber) { - // 按生成时间排序,保留最早的 - var earliestInfo = validExistingInfos.OrderBy(info => info.spawnTick).First(); - - // 如果当前Pawn不是最早的,则杀死 - if (earliestInfo.thingID != pawn.thingIDNumber) - { - Log.Message($"[唯一Pawn系统] 检测到重复Pawn: {pawn.Label} (变量: {globalVariable})"); - Log.Message($"[唯一Pawn系统] 保留最早Pawn: {earliestInfo.pawnName} (生成于tick: {earliestInfo.spawnTick})"); - - // 杀死当前Pawn - KillDuplicatePawn(pawn, globalVariable, earliestInfo.pawnName); - return false; - } - else - { - // 当前Pawn就是最早的,更新验证时间 - var info = registeredPawns.FirstOrDefault(i => i.globalVariable == globalVariable && i.thingID == pawn.thingIDNumber); - if (info != null) - { - info.lastVerificationTick = currentTick; - info.isValid = true; - } - return true; - } + // 杀死当前Pawn + KillDuplicatePawn(pawn, globalVariable, earliestInfo.pawnName); + return false; } else { - // 创建新注册信息 - var newInfo = new UniquePawnInfo + // 当前Pawn就是最早的,更新验证时间 + var info = registeredPawns.FirstOrDefault(i => + i.globalVariable == globalVariable && + i.thingID == pawn.thingIDNumber && + i.gameId == currentGameId); + + if (info != null) { - globalVariable = globalVariable, - thingID = pawn.thingIDNumber, - spawnTick = currentTick, - map = pawn.Map, - pawnName = pawn.Label, - isValid = true, - lastVerificationTick = currentTick - }; - - registeredPawns.Add(newInfo); - Log.Message($"[唯一Pawn系统] 注册新Pawn: {pawn.Label} (变量: {globalVariable}, ID: {pawn.thingIDNumber})"); + info.lastVerificationTick = currentTick; + info.isValid = true; + info.map = pawn.Map; + } return true; } } + else + { + // 创建新注册信息(绑定到当前游戏) + var newInfo = new UniquePawnInfo + { + globalVariable = globalVariable, + thingID = pawn.thingIDNumber, + spawnTick = currentTick, + map = pawn.Map, + pawnName = pawn.Label, + isValid = true, + lastVerificationTick = currentTick, + gameId = currentGameId + }; + + registeredPawns.Add(newInfo); + + return true; + } } /// @@ -165,17 +230,17 @@ namespace ArachnaeSwarm if (pawn == null || string.IsNullOrEmpty(globalVariable)) return; - lock (syncLock) + if (!initialized) + Initialize(); + + var info = registeredPawns.FirstOrDefault(i => + i.globalVariable == globalVariable && + i.thingID == pawn.thingIDNumber && + i.gameId == currentGameId); + + if (info != null) { - var info = registeredPawns.FirstOrDefault(i => - i.globalVariable == globalVariable && - i.thingID == pawn.thingIDNumber); - - if (info != null) - { - info.isValid = false; - Log.Message($"[唯一Pawn系统] 注销Pawn: {pawn.Label} (变量: {globalVariable})"); - } + info.isValid = false; } } @@ -187,53 +252,63 @@ namespace ArachnaeSwarm if (pawn == null || string.IsNullOrEmpty(globalVariable) || pawn.Destroyed || !pawn.Spawned) return; - lock (syncLock) + if (!initialized) + Initialize(); + + var info = registeredPawns.FirstOrDefault(i => + i.globalVariable == globalVariable && + i.thingID == pawn.thingIDNumber && + i.gameId == currentGameId); + + if (info != null) { - var info = registeredPawns.FirstOrDefault(i => - i.globalVariable == globalVariable && - i.thingID == pawn.thingIDNumber); - - if (info != null) - { - info.lastVerificationTick = Find.TickManager.TicksGame; - info.isValid = true; - info.map = pawn.Map; - } - else - { - // Pawn未注册,尝试重新注册 - RegisterPawn(pawn, globalVariable); - } + info.lastVerificationTick = Find.TickManager.TicksGame; + info.isValid = true; + info.map = pawn.Map; + } + else + { + // Pawn未注册,尝试重新注册(只注册到当前游戏) + RegisterPawn(pawn, globalVariable); } } /// - /// 检查Pawn是否是最早的 + /// 检查Pawn是否是最早的(仅限当前游戏) /// public bool IsEarliestPawn(Pawn pawn, string globalVariable) { if (pawn == null || string.IsNullOrEmpty(globalVariable)) return false; - lock (syncLock) - { - var existingInfos = GetInfosForVariable(globalVariable); - var validExistingInfos = existingInfos.Where(info => info.isValid).ToList(); - - if (validExistingInfos.Count == 0) - return true; + if (!initialized) + Initialize(); - var earliestInfo = validExistingInfos.OrderBy(info => info.spawnTick).First(); - return earliestInfo.thingID == pawn.thingIDNumber; - } + var existingInfos = GetInfosForVariable(globalVariable, true); + var validExistingInfos = existingInfos.Where(info => info.isValid).ToList(); + + if (validExistingInfos.Count == 0) + return true; + + var earliestInfo = validExistingInfos.OrderBy(info => info.spawnTick).First(); + return earliestInfo.thingID == pawn.thingIDNumber; } /// /// 获取指定变量的所有Pawn信息 /// - public List GetInfosForVariable(string globalVariable) + public List GetInfosForVariable(string globalVariable, bool onlyCurrentGame = true) { - lock (syncLock) + if (!initialized) + Initialize(); + + if (onlyCurrentGame) + { + return registeredPawns.Where(info => + info.globalVariable == globalVariable && + info.gameId == currentGameId).ToList(); + } + else { return registeredPawns.Where(info => info.globalVariable == globalVariable).ToList(); } @@ -246,32 +321,32 @@ namespace ArachnaeSwarm { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("=== 唯一Pawn管理器调试信息 ==="); - sb.AppendLine($"已注册Pawn数量: {registeredPawns.Count}"); + sb.AppendLine($"当前游戏ID: {currentGameId}"); + sb.AppendLine($"已注册Pawn总数: {registeredPawns.Count}"); + sb.AppendLine($"当前游戏Pawn数: {registeredPawns.Count(info => info.gameId == currentGameId)}"); - lock (syncLock) - { - var grouped = registeredPawns - .Where(info => info.isValid) - .GroupBy(info => info.globalVariable) - .OrderBy(g => g.Key); + var grouped = registeredPawns + .Where(info => info.gameId == currentGameId) // 只显示当前游戏的 + .GroupBy(info => info.globalVariable) + .OrderBy(g => g.Key); - foreach (var group in grouped) + foreach (var group in grouped) + { + sb.AppendLine($"\n变量: {group.Key}"); + var ordered = group.OrderBy(info => info.spawnTick).ToList(); + + for (int i = 0; i < ordered.Count; i++) { - sb.AppendLine($"变量: {group.Key}"); - var ordered = group.OrderBy(info => info.spawnTick).ToList(); + var info = ordered[i]; + string status = i == 0 ? "[最早]" : "[重复]"; + int ageTicks = Find.TickManager.TicksGame - info.spawnTick; + int lastVerifyAgo = Find.TickManager.TicksGame - info.lastVerificationTick; - for (int i = 0; i < ordered.Count; i++) - { - var info = ordered[i]; - string status = i == 0 ? "[最早]" : "[重复]"; - int ageTicks = Find.TickManager.TicksGame - info.spawnTick; - int lastVerifyAgo = Find.TickManager.TicksGame - info.lastVerificationTick; - - sb.AppendLine($" {status} {info.pawnName} (ID: {info.thingID})"); - sb.AppendLine($" 生成时间: {info.spawnTick} ({ageTicks} ticks前)"); - sb.AppendLine($" 最后验证: {info.lastVerificationTick} ({lastVerifyAgo} ticks前)"); - sb.AppendLine($" 地图: {info.map?.Index ?? -1}"); - } + sb.AppendLine($" {status} {info.pawnName} (ID: {info.thingID})"); + sb.AppendLine($" 生成时间: {info.spawnTick} ({ageTicks} ticks前)"); + sb.AppendLine($" 最后验证: {info.lastVerificationTick} ({lastVerifyAgo} ticks前)"); + sb.AppendLine($" 地图: {info.map?.Index ?? -1}"); + sb.AppendLine($" 有效: {info.isValid}"); } } @@ -300,8 +375,9 @@ namespace ArachnaeSwarm continue; } - // 检查超时 - if (info.lastVerificationTick > 0 && + // 检查超时(只检查当前游戏的) + if (info.gameId == currentGameId && + info.lastVerificationTick > 0 && currentTick - info.lastVerificationTick > VERIFICATION_TIMEOUT) { // 尝试查找Pawn @@ -311,7 +387,6 @@ namespace ArachnaeSwarm info.isValid = false; registeredPawns.RemoveAt(i); removedCount++; - Log.Message($"[唯一Pawn系统] 清理超时Pawn: {info.pawnName} (变量: {info.globalVariable})"); } else { @@ -322,6 +397,26 @@ namespace ArachnaeSwarm } } + /// + /// 清理不属于当前游戏的注册信息 + /// + private void CleanupForeignRegistrations() + { + if (string.IsNullOrEmpty(currentGameId)) + return; + + int foreignCount = 0; + for (int i = registeredPawns.Count - 1; i >= 0; i--) + { + var info = registeredPawns[i]; + if (info.gameId != currentGameId) + { + registeredPawns.RemoveAt(i); + foreignCount++; + } + } + } + /// /// 通过ID查找Pawn /// @@ -338,7 +433,7 @@ namespace ArachnaeSwarm } catch (Exception ex) { - Log.Error($"查找Pawn失败: {ex.Message}"); + Log.Error($"[唯一Pawn系统] 查找Pawn失败: {ex.Message}"); return null; } } @@ -359,51 +454,46 @@ namespace ArachnaeSwarm // 使用安全的杀死方法 pawn.Kill(null); - - Log.Message($"[唯一Pawn系统] 移除重复Pawn: {pawn.Label} (变量: {globalVariable})"); } catch (Exception ex) { - Log.Error($"杀死重复Pawn失败: {ex.Message}"); + Log.Error($"[唯一Pawn系统] 杀死重复Pawn失败: {ex.Message}"); } } /// - /// 定期验证所有Pawn + /// 定期验证所有Pawn(只验证当前游戏的) /// private void VerifyAllPawns() { - lock (syncLock) + int currentTick = Find.TickManager.TicksGame; + int verifiedCount = 0; + int timeoutCount = 0; + + foreach (var info in registeredPawns.Where(i => i.isValid && i.gameId == currentGameId)) { - int currentTick = Find.TickManager.TicksGame; - int verifiedCount = 0; - int timeoutCount = 0; - - foreach (var info in registeredPawns.Where(i => i.isValid)) + // 查找Pawn + Pawn pawn = FindPawnByID(info.thingID, info.map); + + if (pawn == null || pawn.Destroyed || !pawn.Spawned) { - // 查找Pawn - Pawn pawn = FindPawnByID(info.thingID, info.map); - - if (pawn == null || pawn.Destroyed || !pawn.Spawned) - { - // Pawn已不存在 - info.isValid = false; - timeoutCount++; - } - else if (currentTick - info.lastVerificationTick > VERIFICATION_INTERVAL) - { - // 需要发送验证请求 - SendVerificationRequest(pawn, info.globalVariable); - } - else - { - verifiedCount++; - } + // Pawn已不存在 + info.isValid = false; + timeoutCount++; + } + else if (currentTick - info.lastVerificationTick > VERIFICATION_INTERVAL) + { + // 需要发送验证请求 + SendVerificationRequest(pawn, info.globalVariable); + } + else + { + verifiedCount++; } - - // 清理无效的 - CleanupInvalidRegistrations(); } + + // 清理无效的 + CleanupInvalidRegistrations(); } /// @@ -411,9 +501,7 @@ namespace ArachnaeSwarm /// private void SendVerificationRequest(Pawn pawn, string globalVariable) { - // 这里可以发送信号或事件给Pawn - // 为了简化,我们直接更新验证时间 - // 实际应用中,Pawn应该定期主动发送验证信号 + // 发送验证信号 var comp = pawn.TryGetComp(); if (comp != null) { @@ -427,6 +515,9 @@ namespace ArachnaeSwarm { base.GameComponentTick(); + if (!initialized) + Initialize(); + if (Find.TickManager.TicksGame - lastVerificationTick > VERIFICATION_INTERVAL) { VerifyAllPawns(); @@ -438,21 +529,42 @@ namespace ArachnaeSwarm { base.ExposeData(); - lock (syncLock) + Scribe_Collections.Look(ref registeredPawns, "registeredPawns", LookMode.Deep); + Scribe_Values.Look(ref lastVerificationTick, "lastVerificationTick", -1); + Scribe_Values.Look(ref currentGameId, "currentGameId"); + Scribe_Values.Look(ref initialized, "initialized", false); + + if (Scribe.mode == LoadSaveMode.LoadingVars) { - Scribe_Collections.Look(ref registeredPawns, "registeredPawns", LookMode.Deep); - - if (Scribe.mode == LoadSaveMode.PostLoadInit) - { - // 加载后初始化 - Initialize(); - - // 清理无效数据 - CleanupInvalidRegistrations(); - - Log.Message($"[唯一Pawn系统] 加载了 {registeredPawns?.Count ?? 0} 个Pawn注册信息"); - } + // 加载后重新初始化 + initialized = false; } + else if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + // 加载后初始化 + Initialize(); + + // 清理无效数据 + CleanupInvalidRegistrations(); + } + } + + public override void StartedNewGame() + { + base.StartedNewGame(); + + // 开始新游戏时重新初始化 + initialized = false; + Initialize(); + } + + public override void LoadedGame() + { + base.LoadedGame(); + + // 加载游戏时确保初始化 + if (!initialized) + Initialize(); } #endregion }