GameContextProtocol / backend /game_models.py
ArturoNereu's picture
Improvements
0614dda
"""
Data models for GCP - Game Context Protocol
Using plain dictionaries for simplicity and clarity.
"""
from typing import Optional, Literal, Dict, Any, List
from datetime import datetime
import uuid
# Game Types
ObjectType = Literal["cube", "sphere", "cylinder", "plane", "cone", "torus", "model"]
LightType = Literal["ambient", "directional", "point", "spot", "hemisphere"]
LightingPreset = Literal["day", "night", "sunset", "studio"]
CameraMode = Literal["fps", "orbit", "top_down", "free"]
MaterialType = Literal["standard", "basic", "phong", "toon"]
# Factory functions for creating default data structures
def create_vector3(x: float = 0.0, y: float = 0.0, z: float = 0.0) -> Dict[str, float]:
"""Create a 3D vector for position, rotation, or scale."""
return {"x": x, "y": y, "z": z}
def create_material(
type: MaterialType = "standard",
color: str = "#ffffff",
metalness: float = 0.5,
roughness: float = 0.5,
opacity: float = 1.0,
wireframe: bool = False
) -> Dict[str, Any]:
"""Create material properties."""
return {
"type": type,
"color": color,
"metalness": metalness,
"roughness": roughness,
"opacity": opacity,
"wireframe": wireframe
}
def create_game_object(
object_type: ObjectType = "cube",
name: Optional[str] = None,
position: Optional[Dict[str, float]] = None,
rotation: Optional[Dict[str, float]] = None,
scale: Optional[Dict[str, float]] = None,
material: Optional[Dict[str, Any]] = None,
model_path: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
"""Create a 3D game object."""
return {
"id": str(uuid.uuid4()),
"name": name,
"type": object_type,
"position": position or create_vector3(),
"rotation": rotation or create_vector3(),
"scale": scale or create_vector3(1, 1, 1),
"material": material or create_material(),
"model_path": model_path,
"metadata": metadata or {},
"created_at": datetime.utcnow().isoformat()
}
def create_light(
light_type: LightType = "directional",
name: Optional[str] = None,
color: str = "#ffffff",
intensity: float = 1.0,
position: Optional[Dict[str, float]] = None,
target: Optional[Dict[str, float]] = None,
cast_shadow: bool = True,
ground_color: Optional[str] = None, # For hemisphere lights
distance: Optional[float] = None, # For point/spot lights
decay: float = 2.0 # Physically correct decay for point lights
) -> Dict[str, Any]:
"""
Create a light source.
Args:
light_type: Type of light (ambient, directional, point, spot, hemisphere)
name: Light name for identification
color: Light color in hex format (sky color for hemisphere)
intensity: Light intensity (0.0-2.0 typical, higher for specific effects)
position: Light position in 3D space
target: Target position for directional/spot lights
cast_shadow: Whether the light casts shadows (directional/spot only)
ground_color: Ground color for hemisphere lights (defaults to darker version of color)
distance: Maximum range for point/spot lights (0 = infinite)
decay: Light falloff rate for point/spot (2.0 = physically correct)
"""
light = {
"id": str(uuid.uuid4()),
"name": name,
"type": light_type,
"color": color,
"intensity": intensity,
"position": position or create_vector3(10, 10, 10),
"target": target,
"cast_shadow": cast_shadow,
}
# Add hemisphere-specific properties
if light_type == "hemisphere":
light["ground_color"] = ground_color or "#444444"
# Add point/spot-specific properties
if light_type in ["point", "spot"]:
if distance is not None:
light["distance"] = distance
light["decay"] = decay
return light
def create_environment(
background_color: str = "#87CEEB",
fog_enabled: bool = False,
fog_color: str = "#ffffff",
fog_near: float = 10.0,
fog_far: float = 100.0,
ambient_light_intensity: float = 0.5,
lighting_preset: LightingPreset = "day"
) -> Dict[str, Any]:
"""Create environment settings."""
return {
"background_color": background_color,
"fog_enabled": fog_enabled,
"fog_color": fog_color,
"fog_near": fog_near,
"fog_far": fog_far,
"ambient_light_intensity": ambient_light_intensity,
"lighting_preset": lighting_preset
}
def create_player(
position: Optional[Dict[str, float]] = None,
rotation: Optional[Dict[str, float]] = None,
camera_mode: CameraMode = "orbit",
movement_speed: float = 5.0,
look_sensitivity: float = 0.002
) -> Dict[str, Any]:
"""Create player/camera configuration."""
return {
"position": position or create_vector3(0, 5, 10),
"rotation": rotation or create_vector3(),
"camera_mode": camera_mode,
"movement_speed": movement_speed,
"look_sensitivity": look_sensitivity
}
def create_player_config(
move_speed: float = 8.0,
jump_force: float = 5.0,
mouse_sensitivity: float = 0.002,
invert_y: bool = False,
gravity: float = -9.82,
player_height: float = 1.7,
player_radius: float = 0.3,
eye_height: float = 1.6,
player_mass: float = 80.0,
linear_damping: float = 0.0,
movement_acceleration: float = 0.0,
air_control: float = 1.0,
camera_fov: float = 75.0,
min_pitch: float = -89.0,
max_pitch: float = 89.0
) -> Dict[str, Any]:
"""
Create player controller configuration for FPS mode.
Args:
move_speed: Horizontal movement speed in units/second
jump_force: Initial upward velocity for jumps in m/s
mouse_sensitivity: Mouse look sensitivity multiplier
invert_y: Whether to invert vertical mouse look
gravity: World gravity in m/s² (negative = downward)
player_height: Player collision capsule height in meters
player_radius: Player collision capsule radius in meters
eye_height: Camera height from player feet in meters
player_mass: Player body mass in kg
linear_damping: Air resistance (0.0-1.0, higher = more friction)
movement_acceleration: Acceleration time (0.0=instant, higher=slower)
air_control: Movement control while airborne (0.0-1.0)
camera_fov: Field of view in degrees (typical: 60-90)
min_pitch: Minimum vertical look angle in degrees (looking down)
max_pitch: Maximum vertical look angle in degrees (looking up)
Returns:
Dictionary with player controller configuration
"""
return {
"move_speed": move_speed,
"jump_force": jump_force,
"mouse_sensitivity": mouse_sensitivity,
"invert_y": invert_y,
"gravity": gravity,
"player_height": player_height,
"player_radius": player_radius,
"eye_height": eye_height,
"player_mass": player_mass,
"linear_damping": linear_damping,
"movement_acceleration": movement_acceleration,
"air_control": air_control,
"camera_fov": camera_fov,
"min_pitch": min_pitch,
"max_pitch": max_pitch
}
def create_scene(
name: str = "Untitled Scene",
description: Optional[str] = None,
world_width: float = 100.0,
world_height: float = 100.0,
world_depth: float = 100.0,
objects: Optional[List[Dict[str, Any]]] = None,
lights: Optional[List[Dict[str, Any]]] = None,
environment: Optional[Dict[str, Any]] = None,
player: Optional[Dict[str, Any]] = None,
show_grid: bool = False,
grid_size: float = 100.0,
grid_divisions: int = 20,
tags: Optional[List[str]] = None
) -> Dict[str, Any]:
"""Create a complete 3D scene."""
now = datetime.utcnow().isoformat()
return {
"scene_id": str(uuid.uuid4()),
"name": name,
"description": description,
"world_width": world_width,
"world_height": world_height,
"world_depth": world_depth,
"objects": objects or [],
"lights": lights or [],
"environment": environment or create_environment(),
"player": player or create_player(),
"show_grid": show_grid,
"grid_size": grid_size,
"grid_divisions": grid_divisions,
"tags": tags or [],
"created_at": now,
"updated_at": now
}
# Validation helpers (optional, for type checking)
def validate_vector3(v: Dict[str, float]) -> bool:
"""Check if a dict is a valid Vector3."""
return isinstance(v, dict) and all(k in v for k in ["x", "y", "z"])
def validate_lighting_preset(preset: str) -> bool:
"""Check if a string is a valid lighting preset."""
return preset in ["day", "night", "sunset", "studio"]
def validate_object_type(obj_type: str) -> bool:
"""Check if a string is a valid object type."""
return obj_type in ["cube", "sphere", "cylinder", "plane", "cone", "torus", "model"]