Commit Graph

80 Commits

Author SHA1 Message Date
bridge
bf13cdf2d2 fix: incorrect relationship for new avatar 2026-01-19 21:14:20 +08:00
Zihao Xu
7f31d9884f test: add comprehensive tests for ai.py (13% -> 98% coverage) (#64)
- Test LLM response parsing (list and dict formats)
- Test null params conversion to empty dict
- Test invalid format handling and skipping
- Test emotion update logic with all emotion types
- Test fallback to CALM on invalid/missing emotion
- Test batch avatar processing
- Test AI.decide wrapper returns NULL_EVENT
- Test thinking field variants (avatar_thinking vs thinking)
- Add testing strategy documentation to test file

Closes #63
2026-01-19 20:49:24 +08:00
Zihao Xu
daa7a20679 test: add fixed_random_seed fixture with autouse=True (#52)
Ensures all tests have deterministic random behavior by setting
random.seed(42) before each test. This prevents flaky tests caused
by random number generation.

Closes #44
2026-01-19 20:46:59 +08:00
4thfever
6185d314af refactor: remove region_names dict, use regions traversal instead (#40)
The region_names dictionary was a redundant index that needed manual
sync when HistoryManager modified region names. This caused bugs where
resolve_query couldn't find regions by their new (history-modified) names.

Instead of maintaining two data structures (regions[id] and region_names[name]),
we now only use regions[id] as the single source of truth. The _resolve_region
function iterates over regions.values() to find matches by name.

This approach:
- Eliminates the sync bug entirely
- Simplifies the codebase
- Has negligible performance impact (region count is small)

Co-authored-by: Zihao Xu <xzhseh@gmail.com>
2026-01-18 17:13:28 +08:00
Zihao Xu
b68403e601 fix: mock StoryTeller in mock_llm_managers to prevent flaky test (#36)
The test_passive_update_loop test was flaky because when misfortune
randomly triggers during sim.step(), it calls StoryTeller.tell_story
which wasn't mocked, causing real LLM API calls to fail in CI.

Added StoryTeller.tell_story to the mock_llm_managers fixture.
2026-01-18 17:00:42 +08:00
bridge
47ad330b35 feat: data reload system 2026-01-18 16:53:24 +08:00
Zihao Xu
e3bf36bcd4 test: add tests for Avatar._init_known_regions (#34)
Verify that:
1. Avatar without sect knows current location's region
2. Avatar with sect knows their sect headquarters
3. Avatar without sect does not automatically know sect regions
4. Avatar only knows their own sect's headquarters, not others
2026-01-18 15:31:41 +08:00
Zihao Xu
7edae9188b fix(misc): CSV column name mismatches in data loading (#32)
* fix: CSV column name mismatches in data loading

- sect.py: Fix headquarter_name/headquarter_desc -> name/desc when reading sect_region.csv
- sect.py: Move sid initialization before technique lookup to fix unbound variable bug
- technique.py: Change sect (name) to sect_id (int) to match technique.csv column
- elixir.py: Remove redundant get_int(row, "id") that reads non-existent column

These fixes ensure:
1. Sect headquarters display correct location names (e.g., "大千光极城" instead of "不夜城")
2. Sect techniques are correctly associated and displayed
3. Technique sect restrictions work properly

* fix: update main.py to use sect_id, add CSV loading tests

- main.py: Change technique.sect to technique.sect_id in API response
- Add tests/test_csv_loading.py to verify CSV column names match code

* test: add API test for /api/meta/game_data endpoint

Verify that techniques in API response use sect_id field (not sect)

* fix: add None check for hq_region in AvatarFactory

Remove redundant code that adds sect headquarters to known_regions.
This logic is already handled by Avatar._init_known_regions() which
uses sect_id matching (more reliable than name-based lookup).

The removed code was causing a flaky test (~1% failure rate) because
resolve_query returns None in test environments with simplified maps.
2026-01-18 15:31:15 +08:00
bridge
e900c3e098 fix pytest 2026-01-14 17:17:21 +08:00
4thfever
df8b1b9433 Refactor/event (#31)
重构事件机制和部分拍卖会机制
2026-01-14 16:58:50 +08:00
4thfever
63fc2f828e Feat/auction (#30)
Add gathering events, in which multiple avatars participate
Add auction event

Closes #24
2026-01-14 02:33:13 +08:00
4thfever
0d34b27fff Feat: Add splash layer (#29)
Add splash layer, support game start, settings, exit
Modify settings layer, add "go back to splash" and "exit"
Add character threshold for history input
Closes #28
2026-01-13 22:00:23 +08:00
bridge
224e3e76f0 fix: pytest llm error only existed in github online CI 2026-01-13 00:08:42 +08:00
4thfever
95e1f11502 Refactor/history (#25)
add multi process history modification
2026-01-12 23:25:53 +08:00
bridge
2caa5586be refactor history archi 2026-01-12 00:36:10 +08:00
bridge
287f9d2ae4 update history pytest 2026-01-12 00:20:15 +08:00
bridge
57cf5ca51a add history class 2026-01-11 23:53:26 +08:00
bridge
5241f70ef3 refactor item ids 2026-01-11 23:12:48 +08:00
bridge
fa4c0340fd fix pytest 2026-01-11 22:48:05 +08:00
bridge
488758764e fix pytest for new awaken avatars 2026-01-11 21:03:02 +08:00
bridge
090e8fe32c fix remove avatar bug 2026-01-11 20:45:51 +08:00
bridge
3a0e432b02 refactor gift 2026-01-11 20:33:54 +08:00
bridge
1499c0cbc8 fix unittest bug 2026-01-09 01:07:52 +08:00
bridge
59824d9cd5 update readme and tips 2026-01-09 00:49:16 +08:00
bridge
9c21259577 refactor: add store mixin into city regions & refactor buying action 2026-01-08 22:16:33 +08:00
Zihao Xu
9485b62cfd feat: add loading screen with progress tracking
- Add async initialization with 6 phases: scanning_assets, loading_map,
  initializing_sects, generating_avatars, checking_llm, generating_initial_events
- Add /api/init-status endpoint for frontend polling
- Add /api/control/reinit endpoint for error recovery
- Add LoadingOverlay.vue component with:
  - Progress ring with gradient
  - Phase text in xianxia style (rotating messages for LLM phase)
  - Tips that rotate every 5 seconds
  - Time-based background transparency (fades to 80% over 20s)
  - Backdrop blur effect
  - Error state with retry button
- Preload map and avatars during LLM initialization for smoother UX
- Add comprehensive tests for init status API
2026-01-08 21:12:18 +08:00
Zihao Xu
8631be501b fix: prevent game from auto-starting to avoid stale initialization events
Problem:
When loading a save (e.g., from year 106), events from year 100 would appear.
This happened because the game auto-started on server startup and client
connection, generating initialization events before the user could load a save.

Solution:
1. Backend: Keep game paused on startup even if LLM check passes
2. Backend: Remove auto-resume on first WebSocket connection
3. Frontend: Start with game paused (isManualPaused = true)

Now the user must explicitly click 'resume' to start a new game, or load a
save first. This prevents the race condition where game_loop generates events
with stale world state.
2026-01-08 21:10:05 +08:00
bridge
58486f95e8 fix pytest bugs 2026-01-08 20:22:03 +08:00
Zihao Xu
06d1bed987 fix: integrate SQLite event storage into load/save system
- Fix load_game to use World.create_with_db() for SQLite event storage
- Add get_events_db_path() to compute event database path from save path
- Add JSON to SQLite migration for backward compatibility with old saves
- Close old EventManager before loading new save to prevent connection leaks
- Add events_db metadata to save file
- Add comprehensive tests for database switching bug and save/load cycle
2026-01-07 23:22:17 -08:00
Zihao Xu
a6b8198c3f Merge branch 'main' into xzhseh/sqlite-event-manager 2026-01-07 20:05:02 -08:00
bridge
1647494c7d update 2026-01-08 01:06:10 +08:00
bridge
a007292b60 update pytest 2026-01-08 00:53:13 +08:00
bridge
fabae13e87 update readme 2026-01-08 00:49:46 +08:00
bridge
40d8a0425b refactor self heal system 2026-01-08 00:33:41 +08:00
bridge
b53f428cbb update unittest 2026-01-07 23:14:48 +08:00
bridge
b2a021bf8a rename item -> material & refactor buying action 2026-01-07 22:43:26 +08:00
Zihao Xu
37518342fc fix: prevent character age from exceeding realm lifespan on creation 2026-01-07 01:08:12 -08:00
Zihao Xu
a1f08dd0ab feat: SQLite event storage with pagination and filtering
Implement SQLite-based event persistence as specified in sqlite-event-manager.md.

## Changes

### Backend
- **EventStorage** (`src/classes/event_storage.py`): New SQLite storage layer
  - Cursor-based pagination with compound cursor `{month_stamp}_{rowid}`
  - Avatar filtering (single and pair queries)
  - Major/minor event separation
  - Cleanup API with `keep_major` and `before_month_stamp` filters

- **EventManager** (`src/classes/event_manager.py`): Refactored to use SQLite
  - Delegates to EventStorage for persistence
  - Memory fallback mode for testing
  - New `get_events_paginated()` method

- **API** (`src/server/main.py`):
  - `GET /api/events` - Paginated event retrieval with filtering
  - `DELETE /api/events/cleanup` - User-triggered cleanup

### Frontend
- **EventPanel.vue**: Scroll-to-load pagination, dual-person filter UI
- **world.ts**: Event state management with pagination
- **game.ts**: New API client methods

### Testing
- 81 new tests for EventStorage, EventManager, and API
- Added `pytest-asyncio` and `httpx` to requirements.txt

## Known Issues: Save/Load is Currently Broken

After loading a saved game, the following issues occur:

1. **Wrong database used**: API returns events from the startup database instead
   of the loaded save's `_events.db` file
2. **Events from wrong time period**: Shows events from year 115 when loaded
   save is at year 114
3. **Pagination broken after load**: `has_more` returns `False` despite hundreds
   of events in the saved database
4. **Filter functionality broken**: Character selection filter stops working
   after loading a game

Root cause: `load_game.py` does not properly switch the EventManager's database
connection to the loaded save's events database.
2026-01-07 00:40:34 -08:00
bridge
35c0756e85 refactor all gather logic 2026-01-06 23:17:21 +08:00
bridge
fbb32adbf6 refactor normalize and resolution 2026-01-06 22:13:47 +08:00
bridge
b60481c99c fix death bug 2026-01-06 21:23:06 +08:00
bridge
3f980d4593 fix a bug 2026-01-06 20:42:53 +08:00
bridge
9f5ad04e92 refactor buy and sell 2026-01-05 23:52:38 +08:00
bridge
6873746d29 refactor buy and sell 2026-01-05 23:37:52 +08:00
bridge
4bff8e503b add buy action 2026-01-05 23:16:58 +08:00
bridge
8d7e11b021 add elixir 2026-01-05 23:04:55 +08:00
Zihao Xu
8d985e0a2b fix: prevent actions on dead avatars
- Add validate_target_avatar() to TargetingMixin for unified validation.
- Update Attack and Assassinate to use the new validation method.
- Add comment to MutualAction.can_start() explaining why it uses inline check.
- Add tests for dead target validation.
2026-01-04 19:29:35 -08:00
bridge
77390fa647 fix pytest 2026-01-04 22:55:59 +08:00
bridge
4fc74b1531 refactor battle strength system 2026-01-04 22:25:25 +08:00
bridge
806e2c1262 refactor price system 2026-01-04 21:49:58 +08:00