1
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -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",
|
||||
|
||||
@@ -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<Comp_SwarmSpellHolder>();
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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<UniquePawnManager>();
|
||||
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<UniquePawnManager>();
|
||||
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<UniquePawnManager>();
|
||||
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<UniquePawnManager>();
|
||||
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<UniquePawnManager>();
|
||||
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<UniquePawnManager>();
|
||||
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);
|
||||
|
||||
@@ -10,29 +10,10 @@ namespace ArachnaeSwarm
|
||||
/// <summary>
|
||||
/// 唯一Pawn管理器
|
||||
/// 管理所有具有唯一标识的Pawn,确保同一标识只有一个存活
|
||||
/// 注意:数据完全绑定到当前Game,不会跨存档生效
|
||||
/// </summary>
|
||||
public class UniquePawnManager : GameComponent
|
||||
{
|
||||
#region 单例和静态访问
|
||||
private static UniquePawnManager _instance;
|
||||
public static UniquePawnManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null && Current.Game != null)
|
||||
{
|
||||
_instance = Current.Game.GetComponent<UniquePawnManager>();
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new UniquePawnManager(Current.Game);
|
||||
Current.Game.components.Add(_instance);
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 数据定义
|
||||
/// <summary>
|
||||
/// 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<UniquePawnInfo>();
|
||||
// 生成当前游戏的唯一ID(基于游戏开始时间和随机数)
|
||||
GenerateGameId();
|
||||
|
||||
// 清理不属于当前游戏的注册信息
|
||||
CleanupForeignRegistrations();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[唯一Pawn系统] 初始化失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 生成当前游戏的唯一ID
|
||||
/// </summary>
|
||||
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)}";
|
||||
}
|
||||
}
|
||||
// <summary>
|
||||
/// 获取游戏名称
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查Pawn是否是最早的
|
||||
/// 检查Pawn是否是最早的(仅限当前游戏)
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定变量的所有Pawn信息
|
||||
/// </summary>
|
||||
public List<UniquePawnInfo> GetInfosForVariable(string globalVariable)
|
||||
public List<UniquePawnInfo> 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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理不属于当前游戏的注册信息
|
||||
/// </summary>
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过ID查找Pawn
|
||||
/// </summary>
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定期验证所有Pawn
|
||||
/// 定期验证所有Pawn(只验证当前游戏的)
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -411,9 +501,7 @@ namespace ArachnaeSwarm
|
||||
/// </summary>
|
||||
private void SendVerificationRequest(Pawn pawn, string globalVariable)
|
||||
{
|
||||
// 这里可以发送信号或事件给Pawn
|
||||
// 为了简化,我们直接更新验证时间
|
||||
// 实际应用中,Pawn应该定期主动发送验证信号
|
||||
// 发送验证信号
|
||||
var comp = pawn.TryGetComp<CompUniquePawn>();
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user