Conversation
kvirund
commented
Jan 31, 2026
32619ee to
8f8ab53
Compare
- Test file was in UTF-8, should be in KOI8-R like all source files - Russian comments now properly encoded in KOI8-R - Word 'тест' now shows correct bytes: 0xD4 0xC5 0xD3 0xD4 - All tests still pass Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Problem: - YAML::Emitter validates strings as UTF-8 - KOI8-R bytes → UTF-8 replacement chars (�) in quoted/literal strings - byte/ubyte fields → "\xNN" instead of numbers Solution: Custom Koi8rYamlEmitter - Manual YAML writing without UTF-8 validation - API: Key(), Value(), BeginMap(), IncreaseIndent(), Comment() - Literal blocks (|) for multiline strings - KOI8-R bytes pass through unchanged - Cast byte/ubyte to int before writing - Comments match converter format (material names, skill names, trigger names, etc.) Changes: - Add Koi8rYamlEmitter class (~100 lines) - Add helper functions for comments (~40 lines) - Rewrite SaveMobs using emitter (~450 lines) - Rewrite SaveObjects using emitter (~340 lines) - Rewrite SaveRooms using emitter (~230 lines) - Rewrite SaveTriggers using emitter (~140 lines) - Remove YAML::Node creation and WriteYamlAtomic usage - Total: ~1300 new lines, remove ~600 old lines Tested: - Compiles successfully with YAML support - Server boots with YAML world without errors Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Core Features:
- Unix Domain Socket JSON API (#ifdef ENABLE_ADMIN_API)
- Authentication via existing imm/builder credentials
- OLC integration for mob/object/room/trigger operations
- UTF-8 support for Admin API connections
Admin API Endpoints:
- Authentication: auth (username/password)
- Mobs: list_mobs, get_mob, update_mob, create_mob, delete_mob
- Objects: list_objects, get_object, update_object, create_object, delete_object
- Rooms: list_rooms, get_room, update_room, create_room, delete_room
- Triggers: list_triggers, get_trigger, update_trigger, create_trigger, delete_trigger
- Zones: list_zones, get_zone, update_zone
Implementation:
- src/engine/network/admin_api.{cpp,h} - Admin API protocol handler
- src/engine/core/comm.cpp - Unix socket initialization and connection handling
- src/engine/core/config.{cpp,h} - Admin API configuration
- lib.template/misc/configuration.xml - Admin API settings (socket_path, require_auth)
Testing:
- tests/test_admin_api.py - Python test client
- Uses environment variables MUD_USERNAME and MUD_PASSWORD for authentication
Bug Fixes:
- zedit.cpp: Add null check for d->character in zedit_disp_menu()
- do_telegram.cpp: Fix memory leak in curl_easy_escape()
- utils_time.h: Fix profiler log path (log/ instead of ../log/)
- yaml_world_data_source.cpp: Add YAML quoting for special characters
Documentation:
- CLAUDE.md: Add proper KOI8-R file editing workflow
- WEB_ADMIN_READY.md: Implementation status and next steps
- WEB_ADMIN_IMPLEMENTATION_STATUS.md: Detailed progress tracking
- YAML_BUGS.md: Known YAML converter issues
Configuration:
- .gitattributes: Add UTF-8 exception for Python test files
- .gitignore: Add __pycache__/ for Python bytecode
- Fix memory allocation: use NEWCREATE instead of CREATE - Fix kInvalidSocket reference: use -1 directly - Fix write_to_descriptor: add iosystem:: namespace - Add admin_socket to epoll monitoring - Add admin connection handling in game_loop - Add conditional process_input for admin_api_mode - Add EAGAIN/EWOULDBLOCK handling in admin_api_process_input - Add koi8r_to_utf8 helper function for encoding conversion - Remove hardcoded credentials from test script Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Initialize output buffer in new_admin_descriptor - Skip formatting in process_output for Admin API - Admin API uses raw JSON output without \r\n formatting Fixes segfault in get_mob command. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add test_get_room and test_update_room functions - Add get_room and update_room commands - Add room tests to full_crud_test - Improve error messages with command list All CRUD operations tested and working: - Mobs: get, update - Objects: get, update - Rooms: get, update YAML files update correctly with proper KOI8-R encoding. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add test_list_mobs, test_list_objects, test_list_rooms, test_list_zones - Add list commands to CLI interface - Add list tests to full_crud_test - Update usage messages All list commands tested and working: - list_zones: 640 zones - list_mobs: zone-filtered mob listing - list_objects: zone-filtered object listing - list_rooms: zone-filtered room listing Full test suite now includes: - List commands (zones, mobs, objects, rooms) - GET commands (mob, object, room) - UPDATE commands (mob, object, room) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add test_create_mob and test_delete_mob functions - Add create_delete_test command for testing mob creation - Update usage messages Create functionality tested and working: - Mobs can be created with auto-assigned vnums - Data persists to YAML files - Uses OLC backend (medit_save_internally) Delete functionality intentionally disabled for safety: - "Mob deletion via API disabled for safety. Use in-game OLC instead." Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add test_create_object, test_delete_object - Add test_create_room, test_delete_room - Extend create_delete_test to cover all entity types - Handle zone capacity issues (use zone 10 for objects) - Add explicit vnum for room creation Testing shows: - create_mob: ✓ works (auto-vnum in zone range) - create_object: requires available vnum space - create_room: requires explicit vnum field - delete_*: disabled for safety on all entity types Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed critical issues in Admin API implementation:
1. **Fix create_room crash (SIGSEGV)**
- OLC functions (redit_disp_menu) call SendMsgToChar which requires ch->desc
- Create dummy CharData with descriptor set for temp_d
- Initialize output buffer for temp_d to capture OLC messages
- Applied to all create functions (mob/object/room/trigger)
2. **Fix room file naming (zero-padding)**
- Room files were saved as "0.yaml" instead of "00.yaml"
- Changed yaml_world_data_source.cpp to use fmt::format("{:02d}")
- Now correctly creates 00.yaml, 01.yaml, ..., 99.yaml
3. **Add OLC output to JSON responses**
- Capture OLC menu/messages from temp_d->output buffer
- Convert KOI8-R to UTF-8 and add to JSON as "olc_output" field
- Added to all create functions for debugging/logging
4. **Extend test suite**
- Updated test_admin_api.py to display olc_output when present
- Helps verify OLC integration is working correctly
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Log all Admin API commands (except auth/ping) to immortals via IMLOG channel:
- Uses admin_user_name saved during authentication
- Logs with BRF level, visible to implementators (level 34+)
- Format: "Admin API: {username} executed '{command}'"
This provides audit trail and real-time monitoring of Admin API usage.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
YAML Emitter fixes: - Fix comment placement: moved comment output from Key() to Value() - Comments now appear AFTER values: "spell: 0 # comment" (was "spell: # comment 0") - Affects all numeric fields with comments (spell, material, etc) YAML serialization fixes: - Fix short_desc saving: use get_short_description() instead of get_description() - This bug caused short_desc and description to be swapped in saved files Test improvements: - Add field mapping in verify_yaml_file() for API→YAML structure - Map flat fields (aliases, short_desc) to nested YAML (names.aliases, descriptions.short_desc) - Tests now correctly verify YAML file contents after updates All CRUD tests now pass with YAML verification. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
YAML verification fixes: - Add field mapping for 'name' field (mob/object → names.aliases, room/zone → root) - Add field mapping for 'level' field (mob → stats.level, object → root) - Filter out 'vnum' from verification (it's in filename, not content) - Expand short_desc/long_desc mapping for different entity types Test improvements: - Use explicit vnum for create_object to avoid "no available vnums" error - Change test zone from 10 to 3 (has free vnums) - All create tests now pass with YAML verification Results: ✅ create_mob: YAML verified ✅ create_object: YAML verified ✅ create_room: YAML verified Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changes: - get_room: return triggers array (vnums from proto_script) - update_room: accept triggers array to update proto_script - Verify trigger vnums exist before adding Triggers are now fully supported in room editing via Admin API, matching OLC functionality (redit 'S' command). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
New test command: comprehensive_test - Tests ALL supported fields for mobs (names, descriptions, stats, sex, position) - Tests ALL supported fields for objects (weight, cost, rent, type, material, durability) - Tests ALL supported fields for rooms (name, description, sector, triggers) All comprehensive tests pass successfully. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Admin API improvements: - Add get_stats endpoint returning zones/mobs/objects/rooms/triggers counts - Fix alignment field assignment (use direct field access instead of non-existent setter) - Fix heap-buffer-overflow with bounds checking in list_mobs - Fix JSON parsing to read from correct nested form structures - Fix triggers handling (shared_ptr<list> instead of vector) Web UI improvements: - Redesign all 16 templates in unified Modern Skeuomorphic style - Update CSS with new design system (parchment cards, typography) - Add full mob edit form with 50+ fields (names, stats, abilities, resistances, etc.) - Fix header logo/title layout (remove button wrapper from text) - Connect index page to get_stats endpoint for live statistics - Add get_stats method to MudAdminClient Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
JavaScript fixes:
- Skip empty string fields (don't call setNestedValue for empty values)
- Add cleanEmptyObjects() to remove empty nested objects before sending
- Prevents sending malformed JSON with empty objects causing type errors
Admin API improvements:
- Add authentication logging (notify immortals on login/failed login)
- Add detailed JSON logging in update_mob for debugging
- Log format: "Admin API: {username} connected and authenticated"
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace separate stats grid + nav cards with single unified section - Each card now shows statistic number AND is clickable link - Visual hierarchy: icon → number → label → description - Add .stat-nav-card classes with hover/active states - Keep legacy .stat-card and .nav-card classes for compatibility - Reduce index.html from 171 to 112 lines Design: Modern Skeuomorphic parchment cards with tactile feedback Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove log() call that dumps full JSON on every mob update - Debug logging was added for diagnostics, no longer needed - Keep only mudlog() for authentication and command execution Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Removed: - Encoding conversion hex dumps (koi8r->utf8, utf8->koi8r) - "Received command" logs (duplicates mudlog) - All operation logs (create/update/delete for mobs/objects/rooms/triggers) - 40+ lines of debug code eliminated Kept: - Error logs (buffer overflow, read errors, disconnects) - Authentication logs (success/failure, access denied) - Warning logs (missing triggers) - mudlog() for immortals (command execution) Fixed: - Unused parameter warnings in delete_* functions Result: Clean production-ready logging Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Current situation: - API supports: names, descriptions, stats, abilities, triggers - API does NOT support: position, behavior, resistances, savings, flags Solution: Filter unsupported fields before sending JSON This ensures saving works NOW. Full support will be added separately. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements comprehensive mob field handling including resistances, savings, position (nested object), and behavior (nested object). Changes: - admin_api.cpp: Add support for resistances (7 fields), savings (3 fields), position as nested object (default_position, load_position), and behavior (class, attack_type). Fixes "type must be number, but is object" error. - mob_edit.html: Remove JavaScript filtering - all fields now sent to API - test_admin_api.py: Update comprehensive test to validate all new fields All fields now work as in OLC. Tested compilation - no errors/warnings. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Removes redundant comprehensive_test command and merges it into full_crud_test. Now full_crud_test runs comprehensive field testing for all entity types (mobs, objects, rooms) including all new fields. Changes: - full_crud_test now uses test_comprehensive_mob/object/room functions - Removed separate comprehensive_test command (redundant) - Updated help text to clarify Individual commands vs Test suites Benefits: - Single command to test all endpoints with comprehensive data - No confusion about which test to run - Tests ALL fields including resistances, savings, position, behavior Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Extends get_mob to return ALL fields that can be updated via update_mob, so web forms can display current values instead of empty defaults. New fields added to get_mob response: - abilities: strength, dexterity, constitution, intelligence, wisdom, charisma - resistances: fire, air, water, earth, vitality, mind, immunity (7 fields) - savings: will, stability, reflex (3 fields) - position: default_position, load_position (nested object) - behavior: class, attack_type (nested object) - stats.sex, stats.race, stats.alignment - triggers: array of trigger vnums This ensures parity between get_mob and update_mob - every field that can be updated is also returned, enabling proper form pre-population. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v5 supports tokenless upload for public repos via OIDC, fixing the JSON parse error from v4. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nch) Coverage summary and HTML artifact remain available in GitHub Actions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Token via CODECOV_TOKEN secret (required for protected branch master). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Expose is_substring/word_check/compare_cmd/one_phrase via new dg_triggers.h header for unit testing - tests/trigger_indenter.cpp: 9 tests for TriggerIndenter::indent() covering if/else/end, while/done, switch/case/break, nesting, level clamp at zero, and reset - tests/dg_string_matching.cpp: 20 tests for string-matching functions (word boundary checks, wildcards, quoted phrases, compare_cmd modes) - tests/dg_var_context.cpp: 8 tests for add/find/remove_var_cntx covering context separation, upsert semantics, and removal - All 334 tests pass Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All build configurations are passing. Soft-failure mode was a temporary measure during initial CI setup -- remove it so a broken build actually turns the check red. Also update the build-summary note to reflect the new policy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- dg_scripts.cpp: indent body of `if (!char_handled)` block by one tab level -- the block was split from a long if/else chain to work around MSVC C1061, but the contents were left at the wrong level - CMakeLists.txt: remove duplicate vim modeline that ended up in the middle of the file (correct one remains at the end) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Проверка была добавлена при введении Admin API, чтобы избежать краша при вызове zedit_disp_menu без персонажа. Код, который это вызывал, больше не существует: HandleUpdateZone работает напрямую с zone_table, не используя OLC и не вызывая zedit_setup. Заодно заменён вводящий в заблуждение TODO в HandleUpdateZone на объяснение намеренного дизайна: Admin API и OLC оба работают с zone_table в памяти; сохранение на диск -- отдельный явный шаг (эндпоинт save_zone / команда сохранения в OLC) через IWorldDataSource. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Баг: setup_full_world() не очищала dest_dir перед распаковкой архива. При повторном запуске `mv lib/* dest_dir/` падало с "cannot overwrite ... Directory not empty", оставляя данные от предыдущего Admin API теста. Следующий прогон считал чексуммы изменённого мира → несовпадение. Фикс: - Добавить `rm -rf "$dest_dir"` перед `mkdir -p` в setup_full_world() - Убрать условные пропуски setup_full_world для legacy и yaml — полный мир всегда пересоздаётся при каждом запуске Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Та же проблема, что и с полным миром: setup_small_world не чистила dest_dir перед cmake, а вызовы для legacy и yaml были условными. После Admin API тестов (создание/удаление триггера 103, изменения комнат/мобов/объектов) грязные данные оставались и чексуммы расходились. Фикс: - rm -rf "$dest_dir" в начале setup_small_world (до cmake) - Убрать условные пропуски для всех трёх форматов малого мира Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CMake создавал симлинк build/lib -> source/lib.template при конфигурации. Это ошибочное поведение: сервер запускается с -d small (или -d full), а не из корня build-директории. Симлинк не нужен и вводит в заблуждение. Заодно: в setup_full_world для yaml убрать lib/world перед mv, чтобы не было "cannot overwrite" (world уже создан конвертором). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Раньше конвертор читал из dest_dir/lib/ и писал в dest_dir/ — это порождало конфликт mv (dest_dir/world/ уже существовал после конверсии). Теперь: сначала mv lib/* → dest_dir/ (flatten), затем конвертация in-place (-i dest_dir -o dest_dir), как у малого мира. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Порядок: распаковка в full/lib/, конвертация in-place там же (все конфиги на месте), затем mv lib/* full/ + rmdir lib. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lib/misc/grouping и lib/misc/noob_help.xml не трекаются в git — они находятся в lib.template/. На свежем клоне без cp lib.template/* lib/ cmake падал с "Cannot find source file". Исправлено на lib.template/misc/grouping и lib.template/misc/noob_help.xml. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… constant The zone_table[0]-as-sentinel pattern conflicted with `kNowhere = 0` which is a room-specific constant. Using kNowhere as a zone sentinel was a design mistake: GetZoneRnum() returning 0 was indistinguishable from a valid zone at index 0. Changes: - Add `const ZoneRnum kNoZone = -1` to structs.h (zone-specific nil sentinel) - db.cpp: GetZoneRnum() starts search from bot=0, returns kNoZone on miss - db.cpp: zone_table no longer pre-allocates sentinel slot at index 0 - db.cpp: CalculateFirstAndLastRooms() sets zone_table[0].first = 1 explicitly (first zone never gets a transition-in, so the loop never sets its .first) - db.cpp: all kNowhere/0 zone comparisons updated to kNoZone - yaml_world_data_source.cpp, sqlite_world_data_source.cpp: vnum→idx mapping no longer adds +1 offset; zone_idx starts at 0 - boot_data_files.cpp: s_zone_number starts at 0 (not 1) - zedit.cpp, do_show_zone_stat.cpp: comparisons updated to kNoZone Fix crash in find_first_step (graph.cpp) when mob has kStayZone flag and is not in the world (in_room == kNowhere): GetZoneRooms() return value was unchecked, leading to rnum_start=-1 and world[-1]->unset_flag() SIGSEGV. - graph.cpp: guard GetZoneRooms() failure with early return kBfsError - do_stat.cpp: skip path-finding when mob is not in the world Fix perslog path: ../log/perslog/ → log/perslog/ (logs are inside data dir) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In master, setup_logs() was called before chdir(), creating log/ and log/perslog/ directories next to the binary (where autorun and other production scripts expect them). Our branch swapped the order, moving all log files inside the data directory. Fix: pass the data dir path explicitly to runtime_config.load() so it can read misc/configuration.xml without needing chdir() first, then restore setup_logs() before chdir() as in master. Also revert log path changes in logger.cpp: - log/perslog/ → ../log/perslog/ - log/olc.log → ../log/olc.log Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…torun PORT defaults to 4000 but can be overridden with MUD_PORT. FLAGS defaults to empty but can be overridden with MUD_FLAGS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bare & does not protect against SIGHUP on session close. nohup ensures autorun survives terminal disconnect. autorun.pid allows stopping the server with: kill $(cat autorun.pid) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Убраны захардкоженные PORT/FLAGS из autorun — дефолты (lib/, 4000) уже определены в бинарнике. Вместо этого все аргументы пробрасываются через "$@", что позволяет при необходимости передавать флаги и порт: ./launch -W 5555 ./launch -d /path/to/world Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
По умолчанию build/circle, можно переопределить: MUD_BINARY=build_debug/circle ./launch Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…UD_BINARY → CIRCLE Запуск из произвольной директории: CIRCLE=./circle ../launch -d ../lib/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
setup_logs() теперь вызывается до chdir(), поэтому syslog создаётся в рабочей директории бинарника. Запуск с 'cd $data_dir && binary -d .' гарантирует, что syslog и log/ окажутся внутри data_dir, где их ожидает тест. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… PID
logger.cpp: mkdir("../log/perslog") перед первым открытием файла персонального лога.
setup_logs() создаёт log/ рядом с бинарником, но ../log/perslog/ может не
совпадать с этим местом (например, ./circle -d ../lib/ из build/).
run_load_tests.sh: заменить (cd && binary) & на (cd && exec binary) &,
чтобы $! захватывал PID бинарника, а не сабшелла. Без exec kill убивал
только сабшелл, оставляя сервер висеть на порту и ломая следующий тест.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Заменить все жёстко прописанные пути ../log/X.log на runtime_config.log_dir() + "/X.log". setup_logs() теперь вычисляет абсолютный путь к log/ через getcwd() до chdir() и сохраняет в m_log_dir. Это устраняет проблему с perslog и прочими логами, которые создавались не там при запуске бинарника из произвольной директории. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Добавить fuser -k 4001/tcp перед запуском чтобы убить зависший сервер от предыдущего запуска тестов. Добавить wait $server_pid в обоих путях завершения — чтобы порт 4001 освобождался до старта следующего теста. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.