Skip to content

Release v0.40.0

Latest
Compare
Choose a tag to compare
@github-actions github-actions released this 05 Oct 01:32
· 4 commits to main since this release
1e9b22d

Horizon v0.40.0 Release Notes

Overview

Horizon v0.40.0 represents a complete architectural evolution, delivering both foundational type-safety improvements and advanced performance optimizations. This release replaces string-based replication with compile-time validated systems while introducing zone virtualization and fixing critical event system gaps.

Type-Safe GORC System

New Type-Based Architecture

The GORC system now uses compile-time validated data structures instead of runtime string matching:

// Define zone data structures
#[derive(Clone, Debug, Serialize, Deserialize)]
struct PlayerCriticalData {
    pub position: Vec3,
    pub health: f32,
}
impl GorcZoneData for PlayerCriticalData {
    fn zone_type_name() -> &'static str { "PlayerCriticalData" }
}

// Define main object with typed zones
#[derive(Clone, Debug, Serialize, Deserialize)]
struct GorcPlayer {
    pub critical_data: PlayerCriticalData, // Zone 0
    pub detailed_data: PlayerDetailedData, // Zone 1
}

// Implement with explicit zone mapping
impl_gorc_object! {
    GorcPlayer {
        0 => critical_data: PlayerCriticalData,
        1 => detailed_data: PlayerDetailedData,
    }
}

Secure Client-Server Communication

New gorc_client: event category creates security boundaries between untrusted client input and server state:

events.on_gorc_client(
    luminal_handle,
    "Asteroid", 
    3, 
    "mine", 
    |event: GorcEvent, client_player: PlayerId, connection: ClientConnectionRef, instance: &mut ObjectInstance| {
        if !connection.is_authenticated() {
            return Err(EventError::HandlerExecution("Not authenticated".to_string()));
        }
        // Process validated mining action
        Ok(())
    }
).await?;

Zone Event System Fixes

Complete Event Coverage

Resolved Issues:

  • Missing zone entry events for existing players when objects spawn nearby
  • Missing zone events when objects move toward stationary players
  • Inconsistent event delivery causing desynchronization

New Automatic Behaviors:

// Object creation triggers automatic zone notifications
let object_id = gorc_instances.register_object(new_object, position).await;
// Existing players automatically receive zone entry events

// Object movement generates events for stationary players
events.update_object_position(object_id, new_position).await?;
// Affected players receive zone entry/exit events

// Enhanced player movement maintains compatibility
events.update_player_position(player_id, new_position).await?;

Performance Improvements

Spatial Indexing Optimization

Algorithmic Enhancement:

  • Before: O(n) linear search through all objects
  • After: O(log n) quadtree-based proximity queries

Measured Performance Gains:

Object Count | Old Time (ms) | New Time (ms) | Improvement
-------------|---------------|---------------|------------
100          | 2.1           | 0.3           | 7x faster
500          | 12.4          | 0.6           | 20x faster
1000         | 28.7          | 0.9           | 32x faster
2000         | 67.3          | 1.2           | 56x faster

Zone Check Optimization

Inner zone optimization reduces redundant calculations:

  • 75% reduction in zone checks for multi-zone objects
  • Smart spatial queries using adaptive radius sizing
  • Hysteresis implementation prevents zone boundary oscillation

Architecture Redesign

// Previous implementation
spatial_index: Arc<RwLock<HashMap<GorcObjectId, Vec3>>>

// Current implementation
spatial_index: Arc<RwLock<SpatialPartition>>
object_positions: Arc<RwLock<HashMap<GorcObjectId, Vec3>>>
zone_size_warnings: Arc<RwLock<HashMap<GorcObjectId, f64>>>
virtualization_manager: Arc<VirtualizationManager>

Zone Virtualization System

Automatic High-Density Optimization

Zone virtualization merges overlapping zones in crowded areas to reduce spatial indexing load:

[gorc.virtualization]
enabled = true
density_threshold = 0.3        # Merge threshold
overlap_threshold = 0.3        # Minimum overlap required
max_virtual_zone_radius = 1000.0
check_interval_ms = 1000
max_objects_per_virtual_zone = 20

Dynamic Zone Management

Merge Operations:

  • Automatic detection of overlapping zones exceeding density thresholds
  • Optimal bounding circle calculation for merged zones
  • Event-driven merge notifications

Split Operations:

  • Object movement tracking for split detection
  • Automatic virtual zone decomposition when objects separate
  • Performance-based splitting when zones exceed size limits

Edge Case Handling

Comprehensive testing covers virtualization edge cases:

  • Rapid merge-split cycles during dynamic scenarios
  • Boundary condition management for overlapping zones
  • Concurrent operation support under heavy load
  • Configuration validation for extreme parameter values

Runtime System Migration

Luminal Async Runtime

Migration from tokio::runtime::Handle to luminal::Handle resolves cross-DLL async conflicts:

// Previous approach
let tokio_handle = context.tokio_handle();
tokio_handle.spawn(async move { ... });

// Current approach
let luminal_handle = context.luminal_handle();
luminal_handle.spawn(async move { ... });

This change ensures stable plugin architecture across dynamic library boundaries.

Hierarchical Event Routing

New PathRouter treats event keys as hierarchical paths:

  • O(log n) handler lookups instead of linear scans
  • Efficient similarity searches for debugging missing handlers
  • Improved developer experience during handler registration

Configuration System

Comprehensive GORC Settings

Production-ready configuration with full validation:

[gorc.general]
max_objects = 10000
max_players = 1000
max_channels_per_object = 8
auto_optimize_zones = true
optimization_interval_ms = 5000
debug_logging = false

[gorc.spatial]
world_bounds = [-10000.0, -10000.0, -1000.0, 10000.0, 10000.0, 1000.0]
max_quadtree_depth = 10
max_objects_per_node = 8
enable_caching = true
cache_expiry_ms = 30000

[gorc.network]
max_batch_size = 1000
channel_frequencies = [60.0, 30.0, 15.0, 5.0]
enable_compression = true
compression_threshold = 1024
network_timeout_ms = 5000

[gorc.monitoring]
enable_stats = true
stats_interval_ms = 10000
enable_profiling = false
track_memory_usage = true
slow_operation_threshold_us = 1000

Configuration Presets

Built-in presets for deployment scenarios:

  • High Performance: 50K objects, 5K players, aggressive virtualization
  • Development: Extensive debugging, profiling enabled
  • Low Resource: Optimized for constrained environments
  • Testing: Minimal overhead, virtualization disabled

Player Plugin Redesign

Modular Handler Architecture

Complete replacement of gorc_example_plugin with production-ready plugin_player:

impl SimplePlugin for PlayerPlugin {
    async fn register_handlers(&mut self, events: Arc<EventSystem>, context: Arc<dyn ServerContext>) -> Result<(), PluginError> {
        let luminal_handle = context.luminal_handle();

        // Core lifecycle management
        self.register_connection_handlers(Arc::clone(&events), context.clone(), luminal_handle.clone()).await?;
        
        // Real-time gameplay handlers
        self.register_movement_handler(Arc::clone(&events), luminal_handle.clone()).await?;
        self.register_combat_handler(Arc::clone(&events), luminal_handle.clone()).await?;
        self.register_communication_handler(Arc::clone(&events), luminal_handle.clone()).await?;
        self.register_scanning_handler(Arc::clone(&events), luminal_handle).await?;

        Ok(())
    }
}

Enhanced Event Handlers

Movement Handler:

events.on_gorc_client(
    luminal_handle,
    "GorcPlayer",
    0, // Critical channel
    "move",
    move |gorc_event, client_player, connection, object_instance| {
        // Security validation
        if !connection.is_authenticated() {
            return Err(EventError::HandlerExecution("Unauthenticated request".to_string()));
        }
        
        // Process movement with automatic replication
        object_instance.object.update_position(new_position);
        Ok(())
    }
).await?;

Combat Handler:

events.on_gorc_client(
    luminal_handle,
    "GorcPlayer",
    1, // Combat channel
    "attack",
    move |gorc_event, client_player, connection, object_instance| {
        // Validate weapon authorization
        if attack_data.player_id != client_player {
            return Err(EventError::HandlerExecution("Unauthorized weapon fire".to_string()));
        }
        
        // Broadcast to nearby players
        Ok(())
    }
).await?;

Credits

  • @tristanpoland - GORC virtualization system, zone event fixes, configuration system
  • @haywoodspartan - Type-safe GORC architecture, security model implementation
  • @a-catgirl-dev - Player plugin redesign, testing infrastructure
  • @Tuafo - Spatial indexing overhaul
  • @DoctorWhoFR - Testing, documentation, sample project