- Removed terminal.clear() calls that were clearing screen on every output
update, letting the game process control the display
- Added letterSpacing: 0 to xterm.js config to disable automatic spacing
adjustments that were creating unwanted span tags
- Improved font family to 'Source Code Pro' for better handling of CJK
characters and monospace alignment
- Added lineHeight adjustment (1.2) for better vertical spacing
- Enabled allowProposedApi for access to additional xterm.js features
- Game process output is now properly displayed without formatting artifacts
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Modified startup script to instantiate GameProcessServer separately
before wrapping in WsServer/HttpServer, allowing direct access to
set event loop after IoServer creation
- Implemented setLoop() method to set event loop after construction
- Added error handling for fwrite() to gracefully handle broken pipes
when process closes
- Suppressed fread() warnings with @ operator to avoid noise
- Simplified startOutputReader() since event loop polling is now
handled directly in onOpen()
- Added null checks for event loop before using in timers
- Server now properly starts with continuous 100ms output polling
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Issues fixed:
- GameProcessServer.readProcessOutput() was using fgets() which could cause
line breaks to be mishandled when reading multiple lines at once
- Changed to use fread() with 8KB buffer for non-blocking I/O
- fread() is better for interactive programs
- Properly handles newlines within chunks
- Doesn't break lines unnecessarily
Frontend improvements:
- Changed sendInput() to use terminal.writeln() instead of write() + write('\n')
- Ensures consistent line ending handling
- Cleaner terminal output
Changes:
1. GameProcessServer.php (readProcessOutput):
- Replaced fgets() loop with fread() loops
- 8192-byte buffer size for optimal performance
- Better handles non-blocking I/O streams
2. web/process.html (sendInput):
- Use terminal.writeln() for user input display
- More consistent with xterm.js behavior
Results:
- Line breaks now display correctly
- Output formatting preserved
- Better handling of rapid output
- No double line breaks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
New simplified approach: WebSocket server spawns bin/game process and forwards I/O
Backend Changes:
- New GameProcessServer class (src/Core/GameProcessServer.php)
- Implements MessageComponentInterface (Ratchet)
- For each WebSocket connection, spawns independent php bin/game process
- Uses proc_open() to manage process I/O pipes
- Reads process STDOUT/STDERR in non-blocking mode
- Writes client input to process STDIN
- Automatic process cleanup on disconnect
- No game code modifications required
- New websocket-process-server.php startup script
- Listens on port 9002
- Simple process forwarder without game-specific logic
- Suitable for any interactive CLI application
Frontend Changes:
- New web/process.html
- Ultra-simple WebSocket frontend for process I/O
- Direct STDIN/STDOUT forwarding
- ANSI color support via xterm.js
- Minimal dependencies, minimal code
- Suitable for any CLI game/application
Architecture Benefits:
✓ Zero game code changes needed
✓ Each user gets independent process (isolation)
✓ Real process STDIO, not emulation
✓ ANSI colors work perfectly
✓ Can run ANY CLI application (not just this game)
✓ Simpler than GameSession-based approach
✓ Easier to deploy and manage
Usage:
1. Start WebSocket server:
php websocket-process-server.php
2. Start HTTP file server (for static files):
php -S 0.0.0.0:8080 web/server.php
3. Open browser:
http://localhost:8080/process.html
Message Protocol:
Client → Server:
{ "type": "input", "input": "command" } - Send stdin to process
{ "type": "ping" } - Heartbeat
Server → Client:
{ "type": "output", "text": "..." } - Process stdout/stderr
{ "type": "system", "message": "..." } - Server messages
{ "type": "error", "message": "..." } - Error messages
{ "type": "pong" } - Heartbeat response
Features:
- Non-blocking I/O reading
- Stream buffering management
- Automatic reconnection support
- 30-second heartbeat for keep-alive
- Process termination on disconnect
- Proper error handling
This is the simplest and most elegant approach for running CLI games on web!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Issues fixed:
- GameSession.handleInput() was returning plain text, causing WebSocket frontend
to lose state information after each input
- GameWebSocketServer.handleGameInput() was calling unnecessary getStateInfo()
- Duplicate state saves in runCurrentState() and handleInput()
Changes:
1. GameSession.php:
- handleInput() now returns structured array with output + state info
- runCurrentState() no longer saves state (already done in handleInput)
- Consistent return format: { output, state, stateName, playerInfo }
2. GameWebSocketServer.php:
- handleGameInput() simplified to use handleInput() return value
- Direct merge of result into WebSocket message
3. web/server.php:
- handleGameInput() simplified to just return handleInput() result
- No duplicate getStateInfo() call
Results:
- Web frontend now receives complete state info after each input
- State transitions in submenus now work correctly
- No more state desynchronization between client and server
Testing:
- Input in level 3+ menus now executes correctly
- State name updates properly in header
- Player info (HP, etc) stays synchronized
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Issues fixed:
- Remove redundant parameter in handleGameInput (line 195)
- Add getStateInfo() method to GameSession to return current game state
- Return state metadata in both handleGameRender() and handleGameInput()
- Add playerInfo (hp, mana, exp) to responses for UI sync
- Add state name mapping for debugging
Changes:
1. GameSession.php:
- Rename getPlayerInfo() to include full stats (mana, exp)
- Add getStateInfo() returning state, stateName, playerInfo
- Add getStateName() helper to convert state constant to string
2. server.php:
- Fix handleGameInput() parameter error
- handleGameRender() now returns state metadata
- handleGameInput() now returns state metadata
3. index.html (web):
- Add console.log for debugging state sync
- Add stateName logging to track state transitions
- Prepare for renderGame() refresh (commented)
These changes allow:
- Frontend to verify correct game state after each action
- Debugging state sync issues via browser console
- Foundation for state validation in UI
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Redesign web battle system from buffered to streaming architecture:
Backend Changes:
- New SSEOutput class for real-time event streaming to clients
- GameSession::streamBattle() for SSE-based battle execution
- Enhanced Screen::delay() to support SSE timing and buffering modes
- New /api/game/battle-stream endpoint handling SSE connections
Frontend Changes:
- Enhanced sendInput() to detect battle command (input "1")
- New streamBattle() function using EventSource for SSE connections
- Real-time log display matching terminal experience
- Event handlers for start, message, complete, error events
Benefits:
✓ Real-time streaming instead of waiting for complete battle
✓ Web frontend experience identical to terminal
✓ Lightweight implementation without WebSocket
✓ Automatic browser reconnection support
✓ ANSI colors fully preserved
✓ Backward compatible for non-battle screens
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add 5 spell templates (fire, ice, thunder, heal, defense) with base damage values and growth rates for 4 quality levels (common, rare, epic, legendary)
- Add base values and growth rates to 100+ spell configurations across all 13 maps and 39+ monsters
- Implement dynamic damage calculation: baseValue + (level * growth) + randomBonus
- Ensure all spells reference appropriate templates for proper scaling mechanics
- Follow cultivation stage progression (Qi Refinement → Foundation Establishment → Core Formation → Nascent Soul → Ascension)
This enables spells to scale dynamically with character level and quality tier, providing the foundation for implementing the damage calculation system in game code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>