382 lines
15 KiB
Markdown
382 lines
15 KiB
Markdown
# AIInfluence Save Data Reverse Engineering
|
|
|
|
Date examined: 2026-04-30
|
|
|
|
## Scope
|
|
|
|
This note reverse-engineers AIInfluence behavior from:
|
|
|
|
- `reference/data/`, a campaign save folder copied from `Modules/AIInfluence/save_data/...`
|
|
- `reference/aiinfulence_features.md`
|
|
- `reference/AIInfluence/TECHNICAL_GUIDE.en.md`
|
|
- `reference/AIInfluence/actionrules_description_EN.txt`
|
|
- `reference/AIInfluence_analysis/README.md` and recovered strings
|
|
|
|
The DLL is protected/obfuscated, so this is based on observable save state, bundled docs/rules, and recovered strings rather than source-level decompilation.
|
|
|
|
## High-Level Architecture
|
|
|
|
AIInfluence appears to run a campaign-local simulation layer beside Bannerlord. The save folder is not only persistence; it is the working memory for the AI systems.
|
|
|
|
The core loop looks like this:
|
|
|
|
1. Bannerlord events and dialogue are captured into compact records.
|
|
2. Per-NPC JSON files are updated with conversation, relationship, location, military, and memory context.
|
|
3. Periodic systems generate `dynamic_events.json` entries from world state and dialogue.
|
|
4. Events are selectively propagated into each NPC's `DynamicEvents` array.
|
|
5. Diplomacy-capable events trigger ruler statements.
|
|
6. Diplomatic statements are analyzed into concrete game actions such as peace, territory demands, trade agreements, tribute, reparations, alliances, and war.
|
|
7. Economic effects and settlement/war ledgers track the consequences.
|
|
|
|
For LocalDiplomacy, the important lesson is not to copy this as giant prompts. The useful shape is a set of bounded ledgers: NPC memory, world events, diplomacy events, war statistics, settlement history, and action results.
|
|
|
|
## Save Folder Inventory
|
|
|
|
The examined folder contains 193 JSON files:
|
|
|
|
- 183 per-NPC files shaped as `Name (string_id).json`
|
|
- `dynamic_events.json`
|
|
- `diplomatic_events.json`
|
|
- `diplomatic_statements.json`
|
|
- `war_statistics.json`
|
|
- `settlement_ownership_history.json`
|
|
- `kingdom_leadership_history.json`
|
|
- `alliances.json`
|
|
- `economic_effects.json`
|
|
- `settlement_penalties.json`
|
|
- `trade_agreements.json`
|
|
|
|
The technical guide also names additional diplomacy files that may exist in other campaigns: `pending_player_statements.json`, `territory_transfers.json`, `tributes.json`, and `reparations.json`.
|
|
|
|
## Per-NPC Memory Files
|
|
|
|
Every NPC file has the same broad schema. Important fields:
|
|
|
|
- Identity/context: `Name`, `StringId`, `Gender`, `IsInPlayerParty`, `IsWithPlayer`, `CurrentTask`, `LocationType`, `TimeContext`
|
|
- Player knowledge: `PlayerInfo`, `IsPlayerKnown`, claimed vs real player identity, lie suspicion
|
|
- Dialogue memory: `ConversationHistory`, `LastAIResponseJson`, `DialogueAnalysisEvents`
|
|
- Recent world context: `WarStatus`, `RecentEvents`, `PlayerForces`, `NPCForces`
|
|
- Relationship/emotion: `PlayerRelation`, `EmotionalState`, `TrustLevel`, `InformationAccessLevel`, `LiePenaltySum`, `NegativeToneCount`, `EscalationState`
|
|
- Generated persona: `CharacterDescription`, `AIGeneratedPersonality`, `AIGeneratedBackstory`, `AIGeneratedSpeechQuirks`, `Quirks`
|
|
- Knowledge: `KnownSecrets`, `KnownInfo`, `KnowledgeGenerated`
|
|
- Romance/service fields: `RomanceLevel`, `LastRomanceInteractionDays`, `LastIntimateInteractionDays`, `IsRomanceEligible`
|
|
- Combat/service fields: `PendingSettlementCombat`, `SettlementCombatResponse`, `SettlementCombatInfo`, `PendingDeath`, `RoleplayDeathReason`, `KillerStringId`
|
|
- Event propagation: `DynamicEvents`, `LastEventAnalysisMessageIndex`, `ProcessedMessageHashes`
|
|
- Disease/settlement/travel: `IsSick`, `CurrentDiseases`, `DiseaseProgress`, `VisitedSettlements`, `LastSeenFriends`
|
|
- AI tasks/quests: `ActiveAIQuests`, `IncomingAIQuests`, `CompletedQuestHistory`, `BattleCommandHistory`
|
|
|
|
The NPC file is effectively a ready-to-prompt context cache. It stores both facts the game can verify and model-generated character color. The stronger pieces to replicate are the factual ledgers and stable summaries; long raw dialogue should be bounded or summarized in LocalDiplomacy.
|
|
|
|
## Dynamic Events
|
|
|
|
`dynamic_events.json` contains 33 events in the examined save. Event types observed:
|
|
|
|
- `military`: 13
|
|
- `political`: 10
|
|
- `economic`: 5
|
|
- `social`: 3
|
|
- `news`: 1
|
|
- `rumor`: 1
|
|
|
|
Each event has:
|
|
|
|
- `id`, `type`, `title`, `description`
|
|
- `event_history`: dated descriptions with `update_reason`
|
|
- `player_involved`
|
|
- `kingdoms_involved`, `characters_involved`
|
|
- `importance` from 1 to 10
|
|
- `spread_speed`
|
|
- `allows_diplomatic_response`
|
|
- `applicable_npcs`
|
|
- `economic_effects`
|
|
- creation and expiration time in real time and campaign days
|
|
- `participating_kingdoms`
|
|
- `kingdom_statements`
|
|
- diplomacy scheduling state: `requires_diplomatic_analysis`, `diplomatic_rounds`, `next_statement_attempt_days`, `failed_statement_attempts`
|
|
|
|
This is the best feature to replicate early. It gives NPCs something current to talk about and gives diplomacy a narrative input instead of making rulers act from raw numbers only.
|
|
|
|
Recommended LocalDiplomacy version:
|
|
|
|
- Store events in SQLite, not loose JSON.
|
|
- Keep fields close to AIInfluence's shape: id, type, title, summary, history, involved entities, importance, spread, expiry, economic effects.
|
|
- Give each NPC a memory relation to event ids instead of copying event text into every NPC memory.
|
|
- Add event generation from `WorldTickRequest` diffs and from dialogue analysis.
|
|
|
|
## Event Propagation
|
|
|
|
AIInfluence does not make every NPC know every event. The global event file stores the event, while each NPC file stores known event ids in `DynamicEvents`.
|
|
|
|
Likely propagation factors based on fields and docs:
|
|
|
|
- NPC type via `applicable_npcs`
|
|
- Importance
|
|
- `spread_speed`
|
|
- Kingdom participation
|
|
- Player involvement
|
|
- NPC status such as ruler/lord/merchant/notable/companion
|
|
- Proximity or current location
|
|
|
|
LocalDiplomacy should implement propagation as a deterministic service with a little randomness:
|
|
|
|
- Always inform directly involved characters and rulers of involved kingdoms.
|
|
- Inform lords in involved kingdoms by importance/spread chance.
|
|
- Inform nearby NPCs when location is known.
|
|
- Keep an audit reason for why an NPC learned an event.
|
|
|
|
## Diplomacy System
|
|
|
|
AIInfluence diplomacy is event-driven. `diplomatic_events.json` contains active diplomatic situations linked to dynamic events. In the sample, one political event has pending analysis and two ruler statements.
|
|
|
|
`diplomatic_statements.json` is a rolling history of kingdom statements. Observed actions:
|
|
|
|
- `ProposePeace`: 16
|
|
- `AcceptPeace`: 5
|
|
- `DemandTerritory`: 2
|
|
- `RejectTerritory`: 2
|
|
- `None`: 9
|
|
|
|
The rules and recovered strings show broader supported actions:
|
|
|
|
- `DeclareWar`
|
|
- `ProposePeace`, `AcceptPeace`, `RejectPeace`
|
|
- `ProposeAlliance`, `AcceptAlliance`, `RejectAlliance`, `BreakAlliance`
|
|
- `ProposeTradeAgreement`, `AcceptTradeAgreement`, `RejectTradeAgreement`, `EndTradeAgreement`
|
|
- `DemandTerritory`, `TransferTerritory`
|
|
- `DemandTribute`, `AcceptTribute`, `RejectTribute`
|
|
- `DemandReparations`, `AcceptReparations`, `RejectReparations`
|
|
- `TransferKingdom`
|
|
- recruitment actions such as mercenary/vassal offers and dismissal
|
|
|
|
Statement records include:
|
|
|
|
- `kingdom_id`
|
|
- `statement_text`
|
|
- `action` and `actions`
|
|
- `target_kingdom_id` and `target_kingdom_ids`
|
|
- optional `target_clan_id`
|
|
- `reason`
|
|
- `campaign_days`
|
|
- `event_id`
|
|
- optional `settlement_id`
|
|
- tribute/reparations/trade duration fields
|
|
|
|
In LocalDiplomacy, diplomacy should be split into three layers:
|
|
|
|
1. Ruler statement generation: produces public text plus intended actions.
|
|
2. Validation: checks war/peace/alliance/territory/legal state in Bannerlord.
|
|
3. Execution: applies only validated and confirmed actions.
|
|
|
|
This avoids the bug visible in the Stannis sample conversation, where the AI keeps arguing that Griffin's Roost must be returned even while the player says Dragonstone already controls it. The agent needs a live validated settlement-owner fact, and diplomacy actions must be rechecked before becoming campaign truth.
|
|
|
|
## War Statistics
|
|
|
|
`war_statistics.json` tracks kingdom-level war pressure. Each kingdom has:
|
|
|
|
- `initial_troops`, `current_troops`, `previous_troops`
|
|
- `total_casualties`, `previous_casualties`
|
|
- `total_lords_captured`, `total_lords_killed`
|
|
- `total_settlements_lost`
|
|
- `total_caravans_destroyed`
|
|
- `days_at_war`
|
|
- `initial_settlements`, `current_settlements`
|
|
- `war_fatigue`, `base_fatigue`
|
|
- `stats_history` snapshots with campaign-day timestamps
|
|
|
|
This data likely feeds peace desire and statement prompts. Recovered strings include `CalculateWarFatigue`, `CalculatePeaceDesire`, `UpdateWarStatistics`, and `CurrentWarInfo`.
|
|
|
|
LocalDiplomacy should keep a `kingdom_war_stats` table and compute:
|
|
|
|
- troop loss rate
|
|
- settlement loss/gain
|
|
- war duration
|
|
- lord capture/death pressure
|
|
- caravan/economic pressure
|
|
- fatigue score
|
|
- peace desire score
|
|
|
|
Then pass only the relevant scores and a short explanation into statement prompts.
|
|
|
|
## Settlement Ownership And Penalties
|
|
|
|
`settlement_ownership_history.json` tracks every settlement:
|
|
|
|
- `SettlementId`, `SettlementName`
|
|
- original owner kingdom id/name
|
|
- current owner kingdom id/name
|
|
- `OwnershipChanges`
|
|
|
|
It also stores `kingdomCapitals`.
|
|
|
|
`settlement_penalties.json` stores short-lived direct penalties by settlement id. The sample has a prosperity penalty for `ROT_town9` with start day, duration, and reason.
|
|
|
|
`economic_effects.json` stores active effects:
|
|
|
|
- target type/id
|
|
- prosperity, food, security, loyalty deltas per day
|
|
- income multiplier
|
|
- start day and duration
|
|
- reason
|
|
|
|
Dynamic events can contain similar `economic_effects`, so there are two shapes: proposed event effects and currently active applied effects.
|
|
|
|
LocalDiplomacy should model these as:
|
|
|
|
- settlement ownership history ledger
|
|
- active settlement modifiers with expiry
|
|
- event-linked proposed modifiers
|
|
- validation before applying any prosperity/security/loyalty/food change
|
|
|
|
## Alliances And Trade
|
|
|
|
`alliances.json` is simple:
|
|
|
|
- `alliances`: kingdom id to allied kingdom id list
|
|
- `alliance_times`: start time keyed by pair
|
|
- `save_time`, `campaign_days`
|
|
|
|
`trade_agreements.json` is empty in this sample, but the docs and action rules say trade agreements are supported and capped in practice.
|
|
|
|
LocalDiplomacy should represent alliances and trade agreements as first-class diplomacy agreements with:
|
|
|
|
- participants
|
|
- start day
|
|
- optional expiry
|
|
- source statement/event id
|
|
- status
|
|
|
|
## Action System
|
|
|
|
AIInfluence supports both dialogue decisions and technical actions.
|
|
|
|
Party/world task actions from the bundled action guide:
|
|
|
|
- `follow_player`
|
|
- `go_to_settlement`
|
|
- `return_to_player`
|
|
- `attack_party`
|
|
- `patrol_settlement`
|
|
- `wait_near_settlement`
|
|
- `siege_settlement`
|
|
- `raid_village`
|
|
- `create_party`
|
|
- `transfer_troops_and_prisoners`
|
|
|
|
Dialogue decisions:
|
|
|
|
- `attack`
|
|
- `surrender`
|
|
- `accept_surrender`
|
|
- `release`
|
|
- `propose_marriage`
|
|
- `accept_marriage`
|
|
- `reject_marriage`
|
|
- `intimate`
|
|
|
|
Other actions:
|
|
|
|
- `money_transfer`
|
|
- `workshop_action`
|
|
- `create_rp_item`
|
|
- diplomacy and recruitment actions listed above
|
|
|
|
The guide says actions can be chained. That implies AIInfluence persists task state for multi-step NPC behavior. Recovered strings include `AIInfluence.Behaviors.AIActions.TaskSystem`, `CreateGoToSettlementWaitThenReturn`, and `_serializedActionState`.
|
|
|
|
LocalDiplomacy already has `GameAction`. To replicate this well:
|
|
|
|
- Add `action_chain_id`, `sequence_index`, and `status`.
|
|
- Keep action execution in Bannerlord, but action planning in the agent.
|
|
- Require exact target ids from the context packet.
|
|
- For risky actions, require player confirmation and live validation.
|
|
- Return `ActionResultRequest` to the agent so memory and event generation can react.
|
|
|
|
## Prompt And Backend Lessons
|
|
|
|
AIInfluence supports several backends and appears to use specialized prompts/rules for dialogue, events, diplomacy, and actions. The reference files include hot-reloaded lore files:
|
|
|
|
- `world.txt`
|
|
- `world_info.json`
|
|
- `world_secrets.json`
|
|
- `cultural_traditions.json`
|
|
- `actionrules.txt`
|
|
|
|
The save files show the model returning structured JSON in `LastAIResponseJson`, with fields such as:
|
|
|
|
- `response`
|
|
- `decision`
|
|
- `tone`
|
|
- `threat_level`
|
|
- `escalation_state`
|
|
- `suspected_lie`
|
|
- `tts_instructions`
|
|
- `money_transfer`
|
|
- `item_transfers`
|
|
- `kingdom_action_reason`
|
|
- `settlement_id`
|
|
- `technical_action`
|
|
- `workshop_action`
|
|
- `witnesses`
|
|
- `notable_phrases`
|
|
|
|
LocalDiplomacy should keep the structured response idea but make it explicit through tool calls and Pydantic contracts. This is already aligned with the current agent design.
|
|
|
|
## Recommended Replication Roadmap
|
|
|
|
1. Event ledger first
|
|
- Extend `WorldTickRequest` with better battles, wars, settlement captures, prisoner events, and kingdom changes.
|
|
- Generate bounded dynamic events and persist them in SQLite.
|
|
- Return visible events from `/world/tick`.
|
|
|
|
2. NPC memory second
|
|
- Store per-NPC conversation summaries, known event ids, trust, lie suspicion, mood, and last interaction day.
|
|
- Avoid writing giant raw dialogue forever; summarize after a small turn window.
|
|
|
|
3. Diplomacy statements third
|
|
- Generate ruler statements only from active diplomatic events.
|
|
- Use a small action enum and exact target ids.
|
|
- Validate every action in C# before execution.
|
|
|
|
4. War fatigue fourth
|
|
- Track war duration, casualties, settlement changes, captures, and troop trends.
|
|
- Feed fatigue/peace desire into diplomacy prompts.
|
|
|
|
5. Economic effects fifth
|
|
- Convert selected events into temporary settlement modifiers.
|
|
- Keep them mild, visible, and reversible.
|
|
|
|
6. NPC task chains later
|
|
- Start with `follow_player`, `go_to_settlement`, `patrol_settlement`, and `wait_near_settlement`.
|
|
- Add combat actions only after validation and confirmation are solid.
|
|
|
|
## Contract Changes To Consider
|
|
|
|
Add or expand these DTOs:
|
|
|
|
- `WorldEvent`: id, type, title, summary, involved kingdoms/chars/settlements, importance, expiry, history
|
|
- `KnownEventRef`: event id, learned day, learned reason, confidence
|
|
- `DiplomaticStatement`: kingdom id, text, actions, targets, reason, event id
|
|
- `WarStats`: kingdom id, enemy id, days at war, casualties, settlements lost/gained, fatigue, peace desire
|
|
- `SettlementOwnership`: settlement id, owner kingdom id, original kingdom id, last changed day
|
|
- `EconomicEffect`: target id, deltas, multiplier, start day, duration, reason, source event id
|
|
- `ActionChain`: chain id, actor id, steps, current index, status
|
|
|
|
## Main Cautions
|
|
|
|
- Do not let generated diplomacy override live game facts. Settlement ownership, war state, clan membership, and kingdom leadership must come from Bannerlord at execution time.
|
|
- Do not put every event into every prompt. Store event ids and retrieve the few relevant ones.
|
|
- Do not use raw AI text as source of truth. Store structured intent separately from public statement prose.
|
|
- Keep campaign mutations reversible where possible until the system has a long test run.
|
|
- Preserve a full audit log for every generated event, statement, validation decision, and executed action.
|
|
|
|
## Best Feature Targets
|
|
|
|
The features most worth copying in spirit are:
|
|
|
|
- NPCs remember conversations and known world events.
|
|
- World events spread unevenly across the world.
|
|
- Rulers make public statements before diplomacy changes.
|
|
- War fatigue pushes kingdoms toward peace without forcing it immediately.
|
|
- Settlement ownership and economic damage create consequences NPCs can discuss.
|
|
- AI can propose actions, but game-side validation decides what actually happens.
|
|
|