Commit
This commit is contained in:
242
old/INTERACTABLE_COOLDOWN_SYSTEM.md
Normal file
242
old/INTERACTABLE_COOLDOWN_SYSTEM.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# Interactable Cooldown System - Real-Time Updates
|
||||
|
||||
## Overview
|
||||
Implemented a complete real-time notification and live countdown system for interactable cooldowns, similar to the combat turn timer system.
|
||||
|
||||
## Implementation Date
|
||||
November 8, 2025
|
||||
|
||||
## Features Implemented
|
||||
|
||||
### 1. WebSocket Broadcasts on Interaction
|
||||
**Location**: `api/main.py` - `/api/game/interact` endpoint
|
||||
|
||||
When a player interacts with an object:
|
||||
- **Broadcast sent to all players in location** with message type `interactable_cooldown`
|
||||
- Includes:
|
||||
- `instance_id`: The interactable's unique identifier
|
||||
- `cooldown_expiry`: Unix timestamp when cooldown expires (60 seconds from interaction)
|
||||
- `message`: "{username} interacted with {interactable_name}"
|
||||
- All players in the same location see the cooldown start immediately
|
||||
|
||||
### 2. Background Task for Cooldown Expiry
|
||||
**Location**: `api/background_tasks.py` - `cleanup_interactable_cooldowns()`
|
||||
|
||||
- **Runs every 30 seconds** to check for expired cooldowns
|
||||
- Gets expired cooldowns from database before removal
|
||||
- Maps `instance_id` to `location_id` by searching through world locations
|
||||
- **Broadcasts `interactable_ready` message** to all players in affected locations
|
||||
- Message: "{interactable_name} is ready to use again"
|
||||
- Added as 7th background task in the system
|
||||
|
||||
**Task Count**: System now runs 7 background tasks:
|
||||
1. Enemy spawn/despawn
|
||||
2. Dropped item decay
|
||||
3. Stamina regeneration
|
||||
4. Combat timers
|
||||
5. Corpse decay
|
||||
6. Status effects processor
|
||||
7. **Interactable cooldown cleanup** ← NEW
|
||||
|
||||
### 3. Database Functions
|
||||
**Location**: `api/database.py`
|
||||
|
||||
Added two new functions:
|
||||
- `get_expired_interactable_cooldowns()`: Returns list of expired cooldowns with instance_id
|
||||
- `remove_expired_interactable_cooldowns()`: Removes expired cooldowns and returns count
|
||||
|
||||
### 4. Frontend Real-Time Countdown
|
||||
**Location**: `pwa/src/components/Game.tsx`
|
||||
|
||||
#### State Management
|
||||
```typescript
|
||||
const [interactableCooldowns, setInteractableCooldowns] = useState<Record<string, number>>({})
|
||||
```
|
||||
- Stores mapping of `instance_id` → `expiry_timestamp`
|
||||
|
||||
#### WebSocket Handlers
|
||||
Two new message types:
|
||||
- **`interactable_cooldown`**: Adds cooldown to state when someone interacts
|
||||
- **`interactable_ready`**: Removes cooldown from state when expired
|
||||
|
||||
#### Live Countdown Timer
|
||||
```typescript
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
const now = Date.now() / 1000
|
||||
setInteractableCooldowns(prev => {
|
||||
// Remove expired cooldowns every second
|
||||
// Updates UI automatically
|
||||
})
|
||||
}, 1000)
|
||||
}, [interactableCooldowns])
|
||||
```
|
||||
|
||||
#### Updated Rendering
|
||||
- **Live calculation** of remaining seconds: `Math.ceil(cooldownExpiry - now)`
|
||||
- **Dynamic display**: Shows `⏳{remainingSeconds}s` next to interactable name
|
||||
- **Live button state**: Disables button when cooldown > 0
|
||||
- **Live tooltip**: Updates every second with current remaining time
|
||||
- **Automatic cleanup**: Timer removed when cooldown reaches 0
|
||||
|
||||
## Message Flow
|
||||
|
||||
### When Player A Interacts with Dumpster:
|
||||
|
||||
1. **Player A clicks "Search Dumpster" button**
|
||||
|
||||
2. **API receives interaction**
|
||||
- Sets 60-second cooldown in database
|
||||
- Broadcasts to all players in location:
|
||||
```json
|
||||
{
|
||||
"type": "interactable_cooldown",
|
||||
"data": {
|
||||
"instance_id": "start_point_dumpster",
|
||||
"cooldown_expiry": 1731108178.5,
|
||||
"message": "PlayerA interacted with Dumpster"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **All Players' Clients (including Player A)**
|
||||
- Add cooldown to state: `interactableCooldowns["start_point_dumpster"] = 1731108178.5`
|
||||
- Start live countdown: `⏳60s → ⏳59s → ⏳58s...`
|
||||
- Disable interaction buttons
|
||||
- Show message in location log: "PlayerA interacted with Dumpster"
|
||||
- Refresh game data to update inventory/location state
|
||||
|
||||
4. **After 60 Seconds - Background Task**
|
||||
- Detects cooldown expired
|
||||
- Removes from database
|
||||
- Broadcasts to all players in location:
|
||||
```json
|
||||
{
|
||||
"type": "interactable_ready",
|
||||
"data": {
|
||||
"instance_id": "start_point_dumpster",
|
||||
"message": "Dumpster is ready to use again"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5. **All Players' Clients**
|
||||
- Remove cooldown from state
|
||||
- Enable interaction buttons
|
||||
- Show message in location log: "Dumpster is ready to use again"
|
||||
- Refresh game data
|
||||
|
||||
## Key Benefits
|
||||
|
||||
### 1. **Real-Time Synchronization**
|
||||
- All players see cooldowns at the same time
|
||||
- No stale data from page loads
|
||||
- Automatic updates without manual refresh
|
||||
|
||||
### 2. **Live Countdown Display**
|
||||
- Updates every second like combat turn timer
|
||||
- Shows exact time remaining: `⏳5s`
|
||||
- More engaging than static "on cooldown" message
|
||||
|
||||
### 3. **Consistent UX**
|
||||
- Same pattern as combat turn timer
|
||||
- Familiar to players
|
||||
- Professional feel
|
||||
|
||||
### 4. **Efficient Updates**
|
||||
- Targeted broadcasts only to players in affected locations
|
||||
- No unnecessary network traffic
|
||||
- Client-side countdown reduces server load
|
||||
|
||||
### 5. **Clear Feedback**
|
||||
- Players know who interacted ("PlayerA interacted with Dumpster")
|
||||
- Know when it's ready again ("Dumpster is ready to use again")
|
||||
- See exact time remaining in both tooltip and display
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Cooldown Duration
|
||||
- **Default**: 60 seconds (hardcoded in `game_logic.py` line 271)
|
||||
- Can be modified per-interactable if needed
|
||||
|
||||
### Timer Precision
|
||||
- **Backend check**: Every 30 seconds
|
||||
- **Frontend update**: Every 1 second
|
||||
- **Display**: Rounds up to nearest second (shows 1s until truly expired)
|
||||
|
||||
### Performance Considerations
|
||||
- Background task only runs in one worker (file lock)
|
||||
- Broadcasts only to affected locations (not global)
|
||||
- Client-side countdown reduces API calls
|
||||
- Timer automatically cleared when no cooldowns active
|
||||
|
||||
## Files Modified
|
||||
|
||||
### Backend
|
||||
1. `api/main.py`
|
||||
- Added `time` import
|
||||
- Updated `/api/game/interact` endpoint to broadcast cooldown start
|
||||
|
||||
2. `api/database.py`
|
||||
- Added `get_expired_interactable_cooldowns()`
|
||||
- Added `remove_expired_interactable_cooldowns()`
|
||||
|
||||
3. `api/background_tasks.py`
|
||||
- Added `cleanup_interactable_cooldowns()` task
|
||||
- Updated `start_background_tasks()` to include new task (7 total)
|
||||
- Updated `start_background_tasks()` signature to accept `world_locations`
|
||||
- Updated `lifespan()` in main.py to pass `LOCATIONS`
|
||||
|
||||
### Frontend
|
||||
1. `pwa/src/components/Game.tsx`
|
||||
- Added `interactableCooldowns` state
|
||||
- Added `interactable_cooldown` WebSocket handler
|
||||
- Added `interactable_ready` WebSocket handler
|
||||
- Added live countdown timer effect
|
||||
- Updated interactable rendering with live countdown display
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
✅ Player interacts with dumpster → All players see cooldown start
|
||||
✅ Cooldown shows live countdown: `⏳60s → ⏳59s → ...`
|
||||
✅ Button disabled during cooldown
|
||||
✅ Tooltip shows remaining time
|
||||
✅ After 60 seconds, all players see "ready" message
|
||||
✅ Button re-enabled when cooldown expires
|
||||
✅ Multiple interactables can have independent cooldowns
|
||||
✅ Players in different locations don't see each other's cooldowns
|
||||
✅ Background task runs every 30 seconds (check logs)
|
||||
✅ 7 background tasks started (check startup logs)
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Potential Improvements:
|
||||
1. **Variable cooldown durations** per interactable type
|
||||
2. **Cooldown persistence** across server restarts (already in DB)
|
||||
3. **Sound notification** when interactable becomes ready
|
||||
4. **Visual effects** like pulsing when cooldown expires
|
||||
5. **Skill-based cooldown reduction** (faster cooldowns for skilled players)
|
||||
6. **Multiple interaction types** per interactable with separate cooldowns
|
||||
|
||||
## Deployment
|
||||
|
||||
```bash
|
||||
# Build both containers
|
||||
docker compose build echoes_of_the_ashes_api echoes_of_the_ashes_pwa
|
||||
|
||||
# Deploy
|
||||
docker compose up -d
|
||||
|
||||
# Verify 7 background tasks started
|
||||
docker compose logs echoes_of_the_ashes_api | grep "background tasks"
|
||||
# Output: ✅ Started 7 background tasks in this worker
|
||||
```
|
||||
|
||||
## Related Systems
|
||||
|
||||
This implementation follows the same pattern as:
|
||||
- **Combat turn timer** (PvP countdown)
|
||||
- **Movement cooldown** (travel between locations)
|
||||
- **Location messages log** (activity feed)
|
||||
|
||||
All use WebSocket broadcasts + client-side countdown for smooth real-time experience.
|
||||
Reference in New Issue
Block a user