9.6 KiB
9.6 KiB
Session Management
This document describes the game session system for Code of Conquest, covering both solo and multiplayer sessions.
Last Updated: November 22, 2025
Overview
Game sessions track the state of gameplay including:
- Current location and discovered locations
- Conversation history between player and AI DM
- Active quests (max 2)
- World events
- Combat encounters
Sessions support both solo play (single character) and multiplayer (party-based).
Data Models
SessionType Enum
class SessionType(Enum):
SOLO = "solo" # Single-player session
MULTIPLAYER = "multiplayer" # Multi-player party session
LocationType Enum
class LocationType(Enum):
TOWN = "town" # Town or city
TAVERN = "tavern" # Tavern or inn
WILDERNESS = "wilderness" # Outdoor wilderness areas
DUNGEON = "dungeon" # Underground dungeons/caves
RUINS = "ruins" # Ancient ruins
LIBRARY = "library" # Library or archive
SAFE_AREA = "safe_area" # Safe rest areas
GameState
Tracks current world state for a session:
@dataclass
class GameState:
current_location: str = "Crossroads Village"
location_type: LocationType = LocationType.TOWN
discovered_locations: List[str] = []
active_quests: List[str] = [] # Max 2
world_events: List[Dict] = []
ConversationEntry
Single turn in the conversation history:
@dataclass
class ConversationEntry:
turn: int # Turn number (1-indexed)
character_id: str # Acting character
character_name: str # Character display name
action: str # Player's action text
dm_response: str # AI DM's response
timestamp: str # ISO timestamp (auto-generated)
combat_log: List[Dict] = [] # Combat actions if any
quest_offered: Optional[Dict] = None # Quest offering info
GameSession
Main session object:
@dataclass
class GameSession:
session_id: str
session_type: SessionType = SessionType.SOLO
solo_character_id: Optional[str] = None # For solo sessions
user_id: str = ""
party_member_ids: List[str] = [] # For multiplayer
config: SessionConfig
combat_encounter: Optional[CombatEncounter] = None
conversation_history: List[ConversationEntry] = []
game_state: GameState
turn_order: List[str] = []
current_turn: int = 0
turn_number: int = 0
created_at: str # ISO timestamp
last_activity: str # ISO timestamp
status: SessionStatus = SessionStatus.ACTIVE
SessionService
The SessionService class (app/services/session_service.py) provides all session operations.
Initialization
from app.services.session_service import get_session_service
service = get_session_service()
Creating Sessions
Solo Session
session = service.create_solo_session(
user_id="user_123",
character_id="char_456",
starting_location="Crossroads Village", # Optional
starting_location_type=LocationType.TOWN # Optional
)
Validations:
- User must own the character
- User cannot exceed 5 active sessions
Returns: GameSession instance
Raises:
CharacterNotFound- Character doesn't exist or user doesn't own itSessionLimitExceeded- User has 5+ active sessions
Retrieving Sessions
Get Single Session
session = service.get_session(
session_id="sess_789",
user_id="user_123" # Optional, validates ownership
)
Raises: SessionNotFound
Get User's Sessions
sessions = service.get_user_sessions(
user_id="user_123",
active_only=True, # Default: True
limit=25 # Default: 25
)
Count Sessions
count = service.count_user_sessions(
user_id="user_123",
active_only=True
)
Updating Sessions
Direct Update
session.turn_number += 1
session = service.update_session(session)
End Session
session = service.end_session(
session_id="sess_789",
user_id="user_123"
)
# Sets status to COMPLETED
Conversation History
Adding Entries
session = service.add_conversation_entry(
session_id="sess_789",
character_id="char_456",
character_name="Brave Hero",
action="I explore the tavern",
dm_response="You enter a smoky tavern filled with patrons...",
combat_log=[], # Optional
quest_offered={"quest_id": "q1", "name": "..."} # Optional
)
Automatic behaviors:
- Increments
turn_number - Adds timestamp
- Updates
last_activity
Retrieving History
# Get all history (with pagination)
history = service.get_conversation_history(
session_id="sess_789",
limit=20, # Optional
offset=0 # Optional, from end
)
# Get recent entries for AI context
recent = service.get_recent_history(
session_id="sess_789",
num_turns=3 # Default: 3
)
Game State Tracking
Location Management
# Update current location
session = service.update_location(
session_id="sess_789",
new_location="Dark Forest",
location_type=LocationType.WILDERNESS
)
# Also adds to discovered_locations if new
# Add discovered location without traveling
session = service.add_discovered_location(
session_id="sess_789",
location="Ancient Ruins"
)
Quest Management
# Add active quest (max 2)
session = service.add_active_quest(
session_id="sess_789",
quest_id="quest_goblin_cave"
)
# Remove quest (on completion or abandonment)
session = service.remove_active_quest(
session_id="sess_789",
quest_id="quest_goblin_cave"
)
Raises: SessionValidationError if adding 3rd quest
World Events
session = service.add_world_event(
session_id="sess_789",
event={
"type": "festival",
"description": "A harvest festival begins in town"
}
)
# Timestamp auto-added
Session Limits
| Limit | Value | Notes |
|---|---|---|
| Active sessions per user | 5 | End existing sessions to create new |
| Active quests per session | 2 | Complete or abandon to accept new |
| Conversation history | Unlimited | Consider archiving for very long sessions |
Database Schema
Sessions are stored in Appwrite game_sessions collection:
| Field | Type | Description |
|---|---|---|
$id |
string | Session ID (document ID) |
userId |
string | Owner's user ID |
sessionData |
string | JSON serialized GameSession |
status |
string | "active", "completed", "timeout" |
sessionType |
string | "solo" or "multiplayer" |
Indexes
userId- For user session queriesstatus- For active session filteringuserId + status- Composite for active user sessions
Usage Examples
Complete Solo Gameplay Flow
from app.services.session_service import get_session_service
from app.models.enums import LocationType
service = get_session_service()
# 1. Create session
session = service.create_solo_session(
user_id="user_123",
character_id="char_456"
)
# 2. Player takes action, AI responds
session = service.add_conversation_entry(
session_id=session.session_id,
character_id="char_456",
character_name="Hero",
action="I look around the village square",
dm_response="The village square bustles with activity..."
)
# 3. Player travels
session = service.update_location(
session_id=session.session_id,
new_location="The Rusty Anchor Tavern",
location_type=LocationType.TAVERN
)
# 4. Quest offered and accepted
session = service.add_active_quest(
session_id=session.session_id,
quest_id="quest_goblin_cave"
)
# 5. End session
session = service.end_session(
session_id=session.session_id,
user_id="user_123"
)
Checking Session State
session = service.get_session("sess_789")
# Check session type
if session.is_solo():
char_id = session.solo_character_id
else:
char_id = session.get_current_character_id()
# Check current location
location = session.game_state.current_location
location_type = session.game_state.location_type
# Check active quests
quests = session.game_state.active_quests
can_accept_quest = len(quests) < 2
# Get recent context for AI
recent = service.get_recent_history(session.session_id, num_turns=3)
Error Handling
Exception Classes
from app.services.session_service import (
SessionNotFound,
SessionLimitExceeded,
SessionValidationError,
)
try:
session = service.get_session("invalid_id", "user_123")
except SessionNotFound:
# Session doesn't exist or user doesn't own it
pass
try:
service.create_solo_session(user_id, char_id)
except SessionLimitExceeded:
# User has 5+ active sessions
pass
try:
service.add_active_quest(session_id, "quest_3")
except SessionValidationError:
# Already have 2 active quests
pass
Testing
Run session tests:
# Unit tests
pytest tests/test_session_model.py -v
pytest tests/test_session_service.py -v
# Verification script (requires TEST_USER_ID and TEST_CHARACTER_ID in .env)
python scripts/verify_session_persistence.py
Related Documentation
- DATA_MODELS.md - Character and item models
- STORY_PROGRESSION.md - Story turn system
- QUEST_SYSTEM.md - Quest mechanics
- API_REFERENCE.md - Session API endpoints