first commit
This commit is contained in:
767
godot_client/docs/ARCHITECTURE.md
Normal file
767
godot_client/docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,767 @@
|
||||
# Godot Client Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
The Godot client is a native frontend for Code of Conquest that connects to the Flask backend via REST API. It provides a consistent experience across desktop, mobile, and web platforms.
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Godot Client │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ UI Layer (Scenes) │ │
|
||||
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
|
||||
│ │ │ Auth │ │ Char │ │ Combat │ │ World │ │ │
|
||||
│ │ │ Screens│ │ Mgmt │ │ UI │ │ UI │ │ │
|
||||
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ Component Layer │ │
|
||||
│ │ ┌─────────┐ ┌──────┐ ┌──────────┐ ┌──────┐ │ │
|
||||
│ │ │ Buttons │ │ Cards│ │FormFields│ │ ... │ │ │
|
||||
│ │ └─────────┘ └──────┘ └──────────┘ └──────┘ │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ Service Layer (Singletons) │ │
|
||||
│ │ ┌──────────────┐ ┌────────────────┐ │ │
|
||||
│ │ │ HTTPClient │ │ StateManager │ │ │
|
||||
│ │ │ - API calls │ │ - Session │ │ │
|
||||
│ │ │ - Auth token │ │ - Characters │ │ │
|
||||
│ │ │ - Error │ │ - Wizard state │ │ │
|
||||
│ │ │ handling │ │ - Persistence │ │ │
|
||||
│ │ └──────────────┘ └────────────────┘ │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ Data Models (GDScript) │ │
|
||||
│ │ Character, CharacterClass, Origin, Skill, etc. │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
HTTP/JSON REST API
|
||||
│
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Flask Backend │
|
||||
│ (Existing REST API) │
|
||||
│ /api/v1/auth/*, /api/v1/characters/* │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Layers
|
||||
|
||||
### 1. UI Layer (Scenes)
|
||||
|
||||
**Location**: `scenes/`
|
||||
|
||||
Individual screens and pages of the application.
|
||||
|
||||
**Responsibilities**:
|
||||
- Render UI elements
|
||||
- Handle user input
|
||||
- Display data from StateManager
|
||||
- Trigger API calls via HTTPClient
|
||||
- Navigate between scenes
|
||||
|
||||
**Examples**:
|
||||
- `scenes/auth/login.tscn` - Login screen
|
||||
- `scenes/character/character_list.tscn` - Character list
|
||||
- `scenes/character/create_wizard_step1.tscn` - Character creation step 1
|
||||
|
||||
**Communication**:
|
||||
- Uses components from Component Layer
|
||||
- Reads/writes to StateManager
|
||||
- Calls HTTPClient for API requests
|
||||
- Emits signals for navigation
|
||||
|
||||
### 2. Component Layer
|
||||
|
||||
**Location**: `scenes/components/`, `scripts/components/`
|
||||
|
||||
Reusable UI components shared across scenes.
|
||||
|
||||
**Responsibilities**:
|
||||
- Provide consistent UI elements
|
||||
- Encapsulate common patterns
|
||||
- Handle component-specific logic
|
||||
- Emit signals for parent scenes
|
||||
|
||||
**Examples**:
|
||||
- `CustomButton` - Themed button with variants
|
||||
- `Card` - Container with header/footer
|
||||
- `FormField` - Input field with validation
|
||||
|
||||
**Communication**:
|
||||
- Receives props from parent scenes
|
||||
- Emits signals to parent scenes
|
||||
- Uses ThemeColors for styling
|
||||
- Independent of business logic
|
||||
|
||||
### 3. Service Layer (Singletons)
|
||||
|
||||
**Location**: `scripts/services/`
|
||||
|
||||
Global services accessible from anywhere in the app.
|
||||
|
||||
**Responsibilities**:
|
||||
- Manage API communication
|
||||
- Store global state
|
||||
- Handle persistence
|
||||
- Provide utilities
|
||||
|
||||
**Singletons**:
|
||||
|
||||
#### HTTPClient
|
||||
- Base URL configuration
|
||||
- Authentication token management
|
||||
- JSON request/response handling
|
||||
- Error handling and retries
|
||||
- Timeout management
|
||||
|
||||
**API**:
|
||||
```gdscript
|
||||
HTTPClient.http_get(endpoint, callback, error_callback)
|
||||
HTTPClient.http_post(endpoint, data, callback, error_callback)
|
||||
HTTPClient.http_put(endpoint, data, callback, error_callback)
|
||||
HTTPClient.http_delete(endpoint, callback, error_callback)
|
||||
HTTPClient.http_patch(endpoint, data, callback, error_callback)
|
||||
HTTPClient.set_auth_token(token)
|
||||
```
|
||||
|
||||
#### StateManager
|
||||
- User session state
|
||||
- Character data cache
|
||||
- Wizard state (character creation)
|
||||
- Navigation history
|
||||
- Settings and preferences
|
||||
- Save/load to local storage
|
||||
|
||||
**API**:
|
||||
```gdscript
|
||||
StateManager.set_user_session(user_data, token)
|
||||
StateManager.get_characters()
|
||||
StateManager.set_wizard_origin(origin_data)
|
||||
StateManager.save_state()
|
||||
```
|
||||
|
||||
**Communication**:
|
||||
- HTTPClient → Backend API (HTTP)
|
||||
- StateManager → Local storage (FileAccess)
|
||||
- Services → UI via signals
|
||||
|
||||
**Accessing Autoloads**:
|
||||
|
||||
Autoload singletons can be accessed in three ways:
|
||||
|
||||
1. **Direct access** (simple, works in `_ready()` and later):
|
||||
```gdscript
|
||||
func _ready():
|
||||
HTTPClient.http_get("/api/v1/characters", _on_success)
|
||||
```
|
||||
|
||||
2. **Get node explicitly** (verbose but always works):
|
||||
```gdscript
|
||||
func _on_button_clicked():
|
||||
get_node("/root/HTTPClient").http_get("/api/v1/characters", _on_success)
|
||||
```
|
||||
|
||||
3. **Cached reference with @onready** (best for multiple uses):
|
||||
```gdscript
|
||||
@onready var http_client = get_node("/root/HTTPClient")
|
||||
@onready var state_manager = get_node("/root/StateManager")
|
||||
|
||||
func _ready():
|
||||
http_client.http_get("/api/v1/characters", _on_success)
|
||||
```
|
||||
|
||||
**Important**: When one autoload needs to reference another (like StateManager calling HTTPClient), use `@onready` to avoid script parsing errors. Direct access (`HTTPClient.method()`) only works during runtime, not during script compilation.
|
||||
|
||||
### 4. Data Models
|
||||
|
||||
**Location**: `scripts/models/`
|
||||
|
||||
GDScript classes that mirror backend data structures.
|
||||
|
||||
**Responsibilities**:
|
||||
- Define typed data structures
|
||||
- Validate data
|
||||
- Serialize/deserialize JSON
|
||||
- Provide helper methods
|
||||
|
||||
**Examples**:
|
||||
```gdscript
|
||||
class_name Character
|
||||
|
||||
var id: String
|
||||
var name: String
|
||||
var origin_id: String
|
||||
var class_id: String
|
||||
var level: int
|
||||
var hp: int
|
||||
var max_hp: int
|
||||
var gold: int
|
||||
var skills: Array[Skill]
|
||||
|
||||
static func from_json(data: Dictionary) -> Character:
|
||||
# Parse JSON to Character object
|
||||
pass
|
||||
```
|
||||
|
||||
**Communication**:
|
||||
- Created from API responses
|
||||
- Stored in StateManager
|
||||
- Displayed in UI scenes
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Example: User Login
|
||||
|
||||
```
|
||||
1. User enters credentials in LoginScene
|
||||
↓
|
||||
2. LoginScene calls HTTPClient.http_post("/api/v1/auth/login", {...})
|
||||
↓
|
||||
3. HTTPClient sends HTTP request to Flask backend
|
||||
↓
|
||||
4. Backend validates and returns JWT token + user data
|
||||
↓
|
||||
5. HTTPClient receives response, creates APIResponse object
|
||||
↓
|
||||
6. LoginScene receives APIResponse via callback
|
||||
↓
|
||||
7. LoginScene calls StateManager.set_user_session(user_data, token)
|
||||
↓
|
||||
8. StateManager stores session and emits user_logged_in signal
|
||||
↓
|
||||
9. StateManager saves state to local storage
|
||||
↓
|
||||
10. LoginScene navigates to CharacterListScene
|
||||
```
|
||||
|
||||
### Example: Load Characters
|
||||
|
||||
```
|
||||
1. CharacterListScene calls HTTPClient.http_get("/api/v1/characters")
|
||||
↓
|
||||
2. HTTPClient includes auth token in headers
|
||||
↓
|
||||
3. Backend returns array of character data
|
||||
↓
|
||||
4. CharacterListScene receives response
|
||||
↓
|
||||
5. CharacterListScene calls StateManager.set_characters(characters)
|
||||
↓
|
||||
6. StateManager emits characters_updated signal
|
||||
↓
|
||||
7. CharacterListScene updates UI with character cards
|
||||
```
|
||||
|
||||
### Example: Character Creation Wizard
|
||||
|
||||
```
|
||||
1. User selects origin in WizardStep1Scene
|
||||
↓
|
||||
2. Scene calls StateManager.set_wizard_origin(origin_data)
|
||||
↓
|
||||
3. Scene navigates to WizardStep2Scene
|
||||
↓
|
||||
4. User selects class in WizardStep2Scene
|
||||
↓
|
||||
5. Scene calls StateManager.set_wizard_class(class_data)
|
||||
↓
|
||||
6. User continues through steps 3 and 4
|
||||
↓
|
||||
7. WizardStep4Scene (confirmation) calls HTTPClient.http_post(
|
||||
"/api/v1/characters",
|
||||
{
|
||||
"origin_id": StateManager.get_wizard_origin().id,
|
||||
"class_id": StateManager.get_wizard_class().id,
|
||||
"name": StateManager.get_wizard_name()
|
||||
}
|
||||
)
|
||||
↓
|
||||
8. Backend creates character and returns character data
|
||||
↓
|
||||
9. Scene calls StateManager.add_character(character_data)
|
||||
↓
|
||||
10. Scene calls StateManager.reset_wizard()
|
||||
↓
|
||||
11. Scene navigates back to CharacterListScene
|
||||
```
|
||||
|
||||
## Navigation
|
||||
|
||||
### Scene Management
|
||||
|
||||
Godot's built-in scene tree is used for navigation:
|
||||
|
||||
```gdscript
|
||||
# Navigate to another scene
|
||||
get_tree().change_scene_to_file("res://scenes/character/character_list.tscn")
|
||||
|
||||
# Or use PackedScene for preloading
|
||||
var next_scene = preload("res://scenes/auth/login.tscn")
|
||||
get_tree().change_scene_to_packed(next_scene)
|
||||
```
|
||||
|
||||
### Navigation Flow
|
||||
|
||||
```
|
||||
App Start
|
||||
↓
|
||||
Main Scene (checks auth)
|
||||
├─ Authenticated? → CharacterListScene
|
||||
└─ Not authenticated? → LoginScene
|
||||
↓
|
||||
Login successful → CharacterListScene
|
||||
↓
|
||||
Create Character → WizardStep1Scene
|
||||
↓
|
||||
Step 2 → WizardStep2Scene
|
||||
↓
|
||||
Step 3 → WizardStep3Scene
|
||||
↓
|
||||
Step 4 → WizardStep4Scene
|
||||
↓
|
||||
Complete → CharacterListScene
|
||||
↓
|
||||
Select Character → CharacterDetailScene
|
||||
↓
|
||||
Start Game → GameWorldScene
|
||||
↓
|
||||
Enter Combat → CombatScene
|
||||
```
|
||||
|
||||
### Navigation Helper
|
||||
|
||||
Consider creating a navigation manager:
|
||||
|
||||
```gdscript
|
||||
# scripts/services/navigation_manager.gd
|
||||
extends Node
|
||||
|
||||
const SCENE_LOGIN = "res://scenes/auth/login.tscn"
|
||||
const SCENE_CHARACTER_LIST = "res://scenes/character/character_list.tscn"
|
||||
const SCENE_WIZARD_STEP_1 = "res://scenes/character/create_wizard_step1.tscn"
|
||||
# ... etc
|
||||
|
||||
func navigate_to(scene_path: String) -> void:
|
||||
StateManager.set_current_scene(scene_path)
|
||||
get_tree().change_scene_to_file(scene_path)
|
||||
|
||||
func navigate_to_login() -> void:
|
||||
navigate_to(SCENE_LOGIN)
|
||||
|
||||
func navigate_to_character_list() -> void:
|
||||
navigate_to(SCENE_CHARACTER_LIST)
|
||||
|
||||
# etc.
|
||||
```
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
### Initial Load
|
||||
|
||||
```gdscript
|
||||
# main.gd (attached to main.tscn, first scene loaded)
|
||||
extends Control
|
||||
|
||||
func _ready() -> void:
|
||||
# StateManager auto-loads from local storage in its _ready()
|
||||
# Check if user is authenticated
|
||||
if StateManager.is_authenticated():
|
||||
# Validate token by making a test API call
|
||||
HTTPClient.http_get("/api/v1/auth/validate", _on_token_validated, _on_token_invalid)
|
||||
else:
|
||||
# Go to login
|
||||
NavigationManager.navigate_to_login()
|
||||
|
||||
func _on_token_validated(response: HTTPClient.APIResponse) -> void:
|
||||
if response.is_success():
|
||||
# Token is valid, go to character list
|
||||
NavigationManager.navigate_to_character_list()
|
||||
else:
|
||||
# Token expired, clear and go to login
|
||||
StateManager.clear_user_session()
|
||||
NavigationManager.navigate_to_login()
|
||||
|
||||
func _on_token_invalid(response: HTTPClient.APIResponse) -> void:
|
||||
# Network error or token invalid
|
||||
StateManager.clear_user_session()
|
||||
NavigationManager.navigate_to_login()
|
||||
```
|
||||
|
||||
### Login
|
||||
|
||||
```gdscript
|
||||
# scenes/auth/login.gd
|
||||
extends Control
|
||||
|
||||
@onready var email_field: FormField = $EmailField
|
||||
@onready var password_field: FormField = $PasswordField
|
||||
@onready var login_button: CustomButton = $LoginButton
|
||||
@onready var error_label: Label = $ErrorLabel
|
||||
|
||||
func _on_login_button_clicked() -> void:
|
||||
# Validate fields
|
||||
if not email_field.validate() or not password_field.validate():
|
||||
return
|
||||
|
||||
# Show loading state
|
||||
login_button.set_loading(true)
|
||||
error_label.visible = false
|
||||
|
||||
# Make API call
|
||||
var credentials = {
|
||||
"email": email_field.get_value(),
|
||||
"password": password_field.get_value()
|
||||
}
|
||||
|
||||
HTTPClient.http_post("/api/v1/auth/login", credentials, _on_login_success, _on_login_error)
|
||||
|
||||
func _on_login_success(response: APIResponse) -> void:
|
||||
login_button.set_loading(false)
|
||||
|
||||
if response.is_success():
|
||||
# Extract user data and token from response
|
||||
var user_data = response.result.get("user", {})
|
||||
var token = response.result.get("token", "")
|
||||
|
||||
# Store in StateManager
|
||||
StateManager.set_user_session(user_data, token)
|
||||
|
||||
# Navigate to character list
|
||||
NavigationManager.navigate_to_character_list()
|
||||
else:
|
||||
# Show error
|
||||
error_label.text = response.get_error_message()
|
||||
error_label.visible = true
|
||||
|
||||
func _on_login_error(response: APIResponse) -> void:
|
||||
login_button.set_loading(false)
|
||||
error_label.text = "Failed to connect. Please try again."
|
||||
error_label.visible = true
|
||||
```
|
||||
|
||||
### Logout
|
||||
|
||||
```gdscript
|
||||
func _on_logout_button_clicked() -> void:
|
||||
# Call logout endpoint (optional, for server-side cleanup)
|
||||
HTTPClient.http_post("/api/v1/auth/logout", {}, _on_logout_complete)
|
||||
|
||||
func _on_logout_complete(response: APIResponse) -> void:
|
||||
# Clear local session regardless of API response
|
||||
StateManager.clear_user_session()
|
||||
|
||||
# Navigate to login
|
||||
NavigationManager.navigate_to_login()
|
||||
```
|
||||
|
||||
## State Persistence
|
||||
|
||||
### What Gets Saved
|
||||
|
||||
StateManager saves to `user://coc_state.save` (platform-specific location):
|
||||
|
||||
- User session data
|
||||
- Auth token (if "remember me")
|
||||
- Character list cache
|
||||
- Selected character ID
|
||||
- Character limits
|
||||
- Settings/preferences
|
||||
- Timestamp of last save
|
||||
|
||||
### Save Triggers
|
||||
|
||||
State is saved automatically:
|
||||
- On login
|
||||
- On logout (clears save)
|
||||
- On character list update
|
||||
- On character selection
|
||||
- On settings change
|
||||
- On app exit (if auto-save enabled)
|
||||
|
||||
Manual save:
|
||||
```gdscript
|
||||
StateManager.save_state()
|
||||
```
|
||||
|
||||
### Load on Startup
|
||||
|
||||
StateManager automatically loads on `_ready()`:
|
||||
- Restores user session if valid
|
||||
- Restores character list
|
||||
- Sets HTTPClient auth token
|
||||
|
||||
## Error Handling
|
||||
|
||||
### API Errors
|
||||
|
||||
```gdscript
|
||||
HTTPClient.http_get("/api/v1/characters", _on_success, _on_error)
|
||||
|
||||
func _on_success(response: APIResponse) -> void:
|
||||
if response.is_success():
|
||||
# Handle success
|
||||
var characters = response.result
|
||||
else:
|
||||
# API returned error (4xx, 5xx)
|
||||
_show_error(response.get_error_message())
|
||||
|
||||
func _on_error(response: APIResponse) -> void:
|
||||
# Network error or JSON parse error
|
||||
_show_error("Failed to connect to server")
|
||||
```
|
||||
|
||||
### Network Errors
|
||||
|
||||
HTTPClient handles:
|
||||
- Connection timeout (30s default)
|
||||
- DNS resolution failure
|
||||
- TLS/SSL errors
|
||||
- No response from server
|
||||
- Invalid JSON responses
|
||||
|
||||
All errors return an `APIResponse` with:
|
||||
- `status`: HTTP status code (or 500 for network errors)
|
||||
- `error.message`: Human-readable error message
|
||||
- `error.code`: Machine-readable error code
|
||||
|
||||
### User-Facing Errors
|
||||
|
||||
Show errors to users:
|
||||
|
||||
```gdscript
|
||||
# Toast notification (create a notification system)
|
||||
NotificationManager.show_error("Failed to load characters")
|
||||
|
||||
# Inline error label
|
||||
error_label.text = response.get_error_message()
|
||||
error_label.visible = true
|
||||
|
||||
# Error dialog
|
||||
var dialog = AcceptDialog.new()
|
||||
dialog.dialog_text = "An error occurred. Please try again."
|
||||
dialog.popup_centered()
|
||||
```
|
||||
|
||||
## Platform Considerations
|
||||
|
||||
### Mobile
|
||||
|
||||
**Touch Input**:
|
||||
- Larger tap targets (minimum 44x44 dp)
|
||||
- No hover states
|
||||
- Swipe gestures for navigation
|
||||
|
||||
**Screen Sizes**:
|
||||
- Responsive layouts
|
||||
- Safe areas (notches, rounded corners)
|
||||
- Portrait and landscape orientations
|
||||
|
||||
**Performance**:
|
||||
- Limit draw calls
|
||||
- Use compressed textures
|
||||
- Reduce particle effects
|
||||
|
||||
**Networking**:
|
||||
- Handle intermittent connectivity
|
||||
- Show loading indicators
|
||||
- Cache data locally
|
||||
|
||||
### Desktop
|
||||
|
||||
**Input**:
|
||||
- Keyboard shortcuts
|
||||
- Mouse hover effects
|
||||
- Scroll wheel support
|
||||
|
||||
**Window Management**:
|
||||
- Resizable windows
|
||||
- Fullscreen mode
|
||||
- Multiple monitor support
|
||||
|
||||
### Web
|
||||
|
||||
**Limitations**:
|
||||
- No threading (slower)
|
||||
- No file system access (use IndexedDB)
|
||||
- Larger download size
|
||||
- CORS restrictions
|
||||
|
||||
**Requirements**:
|
||||
- HTTPS for SharedArrayBuffer
|
||||
- Proper MIME types
|
||||
- COOP/COEP headers
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Token Storage
|
||||
|
||||
**Desktop/Mobile**: Tokens stored in encrypted local storage
|
||||
**Web**: Tokens stored in localStorage (less secure, consider sessionStorage)
|
||||
|
||||
### HTTPS Only
|
||||
|
||||
Always use HTTPS in production for API calls.
|
||||
|
||||
### Token Expiration
|
||||
|
||||
Handle expired tokens:
|
||||
```gdscript
|
||||
func _on_api_error(response: HTTPClient.APIResponse) -> void:
|
||||
if response.status == 401: # Unauthorized
|
||||
# Token expired, logout
|
||||
StateManager.clear_user_session()
|
||||
NavigationManager.navigate_to_login()
|
||||
```
|
||||
|
||||
### Input Validation
|
||||
|
||||
Always validate user input:
|
||||
- FormField components have built-in validation
|
||||
- Re-validate on backend (never trust client)
|
||||
- Sanitize before displaying (prevent XSS if user-generated content)
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
|
||||
Test individual components:
|
||||
- HTTPClient request/response handling
|
||||
- StateManager save/load
|
||||
- Data model serialization
|
||||
- Component validation logic
|
||||
|
||||
### Integration Tests
|
||||
|
||||
Test scene flows:
|
||||
- Login → Character List
|
||||
- Character Creation wizard
|
||||
- Character selection → Game
|
||||
|
||||
### Platform Tests
|
||||
|
||||
Test on each platform:
|
||||
- Desktop: Windows, Mac, Linux
|
||||
- Mobile: Android, iOS
|
||||
- Web: Chrome, Firefox, Safari
|
||||
|
||||
### API Mocking
|
||||
|
||||
For offline testing, create mock responses:
|
||||
|
||||
```gdscript
|
||||
# scripts/services/mock_http_client.gd
|
||||
extends Node
|
||||
|
||||
# Same API as HTTPClient but returns mock data
|
||||
func get(endpoint: String, callback: Callable, error_callback: Callable = Callable()) -> void:
|
||||
match endpoint:
|
||||
"/api/v1/characters":
|
||||
callback.call(_mock_character_list_response())
|
||||
_:
|
||||
error_callback.call(_mock_error_response())
|
||||
|
||||
func _mock_character_list_response() -> HTTPClient.APIResponse:
|
||||
var mock_data = {
|
||||
"app": "Code of Conquest",
|
||||
"version": "0.1.0",
|
||||
"status": 200,
|
||||
"timestamp": Time.get_datetime_string_from_system(),
|
||||
"result": [
|
||||
{"id": "1", "name": "Warrior", "level": 5, "hp": 100, "max_hp": 100},
|
||||
{"id": "2", "name": "Mage", "level": 3, "hp": 60, "max_hp": 60}
|
||||
],
|
||||
"error": {}
|
||||
}
|
||||
return HTTPClient.APIResponse.new(mock_data)
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Minimize API Calls
|
||||
|
||||
- Cache data in StateManager
|
||||
- Only refetch when necessary
|
||||
- Use pagination for large lists
|
||||
|
||||
### Optimize Rendering
|
||||
|
||||
- Use object pooling for lists
|
||||
- Minimize StyleBox allocations
|
||||
- Use TextureRect instead of Sprite when possible
|
||||
- Reduce shadow/glow effects on mobile
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
Load scenes only when needed:
|
||||
```gdscript
|
||||
# Preload for instant transition
|
||||
const CharacterList = preload("res://scenes/character/character_list.tscn")
|
||||
|
||||
# Or load on-demand
|
||||
var scene = load("res://scenes/character/character_list.tscn")
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Logging
|
||||
|
||||
```gdscript
|
||||
# Add to HTTPClient, StateManager, etc.
|
||||
print("[HTTPClient] GET /api/v1/characters")
|
||||
print("[StateManager] User logged in: ", user_data.get("email"))
|
||||
```
|
||||
|
||||
### Remote Debugging
|
||||
|
||||
For mobile:
|
||||
1. Enable remote debug in Godot
|
||||
2. Connect device via USB
|
||||
3. Run with "Remote Debug" option
|
||||
|
||||
### Network Inspector
|
||||
|
||||
Monitor network traffic:
|
||||
- Desktop: Use browser dev tools for Godot Web export
|
||||
- Mobile: Use Charles Proxy or similar
|
||||
- Check request/response bodies, headers, timing
|
||||
|
||||
## Next Steps (Phase 2)
|
||||
|
||||
After Phase 1 (Foundation) is complete:
|
||||
|
||||
1. **Implement Auth Screens** (Week 2)
|
||||
- Login, Register, Password Reset
|
||||
- Email verification
|
||||
- Form validation
|
||||
|
||||
2. **Implement Character Management** (Weeks 3-4)
|
||||
- Character creation wizard
|
||||
- Character list
|
||||
- Character detail
|
||||
- Delete character
|
||||
|
||||
3. **Platform Optimization** (Week 5)
|
||||
- Mobile touch controls
|
||||
- Desktop keyboard shortcuts
|
||||
- Web export configuration
|
||||
|
||||
4. **Future Features** (Week 6+)
|
||||
- Combat UI
|
||||
- World exploration
|
||||
- Quest system
|
||||
- Multiplayer
|
||||
|
||||
## Resources
|
||||
|
||||
- [Godot Documentation](https://docs.godotengine.org/)
|
||||
- [GDScript Style Guide](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_styleguide.html)
|
||||
- [Godot UI Tutorials](https://docs.godotengine.org/en/stable/tutorials/ui/index.html)
|
||||
- [HTTP Request](https://docs.godotengine.org/en/stable/classes/class_httprequest.html)
|
||||
- [FileAccess](https://docs.godotengine.org/en/stable/classes/class_fileaccess.html)
|
||||
Reference in New Issue
Block a user