clockworklabs / clockworklabs/SpacetimeDB

Windows spacetime w/ rapier build rust panic

Open
#2,581 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
25.2k
Forks
1.1k
Avg merge
2d 7h
Merged PRs (30d)
46

Description

I'm on windows x64 and experimenting with a simple lib file even when I comment-out most of my code:

lib.rs
use once_cell::sync::Lazy;

use spacetimedb::{
    Identity, ReducerContext, ScheduleAt, Table, Timestamp,
};

// serde imports removed as they were unused

use std::time::Duration;

mod ai;
mod common;
mod game_logic;
mod inventory_logic;
mod physics;
mod reducers;
mod tick;

pub use crate::common::*;

pub use crate::reducers::player_actions::{gather_resource, move_player};

pub use crate::reducers::ship_actions::build_ship;

pub use crate::reducers::test_actions::{
    apply_force_to_player, get_player_position, list_all_players, list_all_resources,
    list_all_ships, spawn_test_player, spawn_test_resource, spawn_test_ship,
};

pub use crate::tick::server_tick;

#[spacetimedb::table(name = inventory)]
#[derive(Clone, Debug)]
pub struct InventoryData {
    #[primary_key]
    #[auto_inc]
    pub inventory_id: u64,

    #[index(btree)]
    pub owner_player: Option<Identity>,

    #[index(btree)]
    pub owner_ship: Option<u64>,

    #[index(btree)]
    pub owner_ai: Option<u64>,

    pub capacity: u32,
}

#[spacetimedb::table(name = inventory_item)]
#[derive(Clone, Debug)]
pub struct InventoryItemData {
    #[primary_key]
    #[auto_inc]
    pub item_id: u64,

    #[index(btree)]
    pub inventory_id: u64,

    pub resource_type: ResourceType,

    pub quantity: u32,
}

#[spacetimedb::table(name = player, public)]
#[derive(Clone, Debug)]

pub struct PlayerData {
    #[primary_key]
    pub identity: Identity,

    pub name: Option<String>,

    pub health: u32,

    #[unique]
    pub inventory_id: u64,

    pub position: Vec3,

    pub rotation: Vec3,

    pub online: bool,
}

#[spacetimedb::table(name = ai_player)]
#[derive(Clone, Debug)]
pub struct AIPlayerData {
    #[primary_key]
    #[auto_inc]
    pub ai_id: u64,

    pub name: String,

    pub health: u32,

    #[unique]
    pub inventory_id: u64,

    pub position: Vec3,

    pub rotation: Vec3,

    pub ai_state: AIState,

    pub target_position: Option<Vec3>,
}

#[spacetimedb::table(name = ship)]
#[derive(Clone, Debug)]
pub struct ShipData {
    #[primary_key]
    #[auto_inc]
    pub ship_id: u64,

    #[index(btree)]
    pub owner_identity: Option<Identity>,

    #[index(btree)]
    pub owner_ai_id: Option<u64>,

    pub name: String,

    pub health: u32,

    #[unique]
    pub inventory_id: u64,

    pub position: Vec3,

    pub rotation: Vec3,

    pub sail_deployment: f32,

    pub anchor_deployed: bool,
}

#[spacetimedb::table(name = ship_cannon)]
#[derive(Clone, Debug)]
pub struct ShipCannonData {
    #[primary_key]
    #[auto_inc]
    pub cannon_id: u64,

    #[index(btree)]
    pub ship_id: u64,

    pub horizontal_angle: f32,

    pub vertical_angle: f32,

    pub loaded_resource: Option<ResourceType>,

    pub cooldown_finish_time: Option<Timestamp>,
}

#[spacetimedb::table(name = resource_node)]
#[derive(Clone, Debug)]
pub struct ResourceNodeData {
    #[primary_key]
    #[auto_inc]
    pub resource_node_id: u64,

    pub resource_type: ResourceType,

    pub position: Vec3,

    pub current_amount: u32,

    pub max_amount: u32,

    pub respawn_cooldown_finish_time: Option<Timestamp>,
}

#[spacetimedb::table(name = server_tick_schedule, public, scheduled(server_tick_reducer))]
#[derive(Clone, Debug)]

pub struct ServerTickSchedule {
    #[primary_key]
    #[auto_inc]
    pub schedule_id: u64,

    pub scheduled_at: ScheduleAt,
}

pub static STARTUP: Lazy<()> = Lazy::new(|| {
    let _ = env_logger::try_init();

    spacetimedb::log::info!("Global STARTUP: Initializing Physics World...");

    // Try to initialize the physics world, but don't fail if it doesn't work
    match std::panic::catch_unwind(|| {
        physics::init_physics_world_state();
    }) {
        Ok(_) => spacetimedb::log::info!("Global STARTUP: Physics World Initialized."),
        Err(e) => spacetimedb::log::error!("Global STARTUP: Physics World Initialization failed: {:?}", e),
    }
});


#[spacetimedb::reducer(init)]
pub fn init(ctx: &ReducerContext, _timestamp: Timestamp) -> Result<(), String> {
    spacetimedb::log::info!("Forcing STARTUP");
    
    Lazy::force(&STARTUP);
    spacetimedb::log::info!("Running init reducer.");
    let count = ctx.db.server_tick_schedule().count();
    spacetimedb::log::info!("Server tick schedule count: {}", count);
    if count == 0 {
        let tick_interval_duration = Duration::from_secs_f64(1.0 / SERVER_TICK_RATE_HZ);
        spacetimedb::log::info!("Tick interval: {:?}", tick_interval_duration);
        if tick_interval_duration.is_zero() {
            let err_msg = "Server tick rate must be positive!".to_string();
            spacetimedb::log::error!("{}", err_msg);
            return Err(err_msg);
        }
        spacetimedb::log::info!(
            "Scheduling initial server tick (interval: {:?})...",
            tick_interval_duration
        );
        let schedule = ServerTickSchedule {
            schedule_id: 0,
            scheduled_at: ScheduleAt::Interval(tick_interval_duration.into()),
        };
        spacetimedb::log::info!("Attempting to insert schedule: {:?}", schedule);
        match ctx.db.server_tick_schedule().try_insert(schedule) {
            Ok(row) => spacetimedb::log::info!(
                "Server tick schedule inserted successfully. ID: {}",
                row.schedule_id
            ),
            Err(e) => {
                let err_msg = format!("FAILED to insert server tick schedule: {}", e);
                spacetimedb::log::error!("{}", err_msg);
                return Err(err_msg);
            }
        }
    } else {
        spacetimedb::log::info!("Server tick already scheduled.");
    }
    
    spacetimedb::log::info!("Init reducer completed successfully.");
    Ok(())
    
}

#[spacetimedb::reducer(client_connected)]

pub fn identity_connected(ctx: &ReducerContext) {
    let player_identity = ctx.sender;

    spacetimedb::log::info!("Client connected: {:?}", player_identity);

    if let Some(existing_player) = ctx.db.player().identity().find(player_identity) {
        spacetimedb::log::info!("PlayerData {:?} reconnected.", player_identity);

        let mut updated_player = existing_player.clone();

        updated_player.online = true;

        ctx.db.player().identity().update(updated_player.clone());

        physics::create_player_body(&updated_player);
    } else {
        spacetimedb::log::info!(
            "New player {:?} joining. Creating character.",
            player_identity
        );

        let inventory_insert_result = ctx.db.inventory().try_insert(InventoryData {
            inventory_id: 0,

            owner_player: Some(player_identity),

            owner_ship: None,

            owner_ai: None,

            capacity: DEFAULT_PLAYER_INVENTORY_CAPACITY,
        });

        let inventory = match inventory_insert_result {
            Ok(inv) => inv,

            Err(e) => {
                spacetimedb::log::error!(
                    "Failed to create inventory for new player {:?}: {}",
                    player_identity,
                    e
                );

                return;
            }
        };

        let player_name_num = identity_to_u64_simple(&player_identity);

        let player_name = format!("Pirate_{}", player_name_num % 10000);

        let new_player_data = PlayerData {
            identity: player_identity,

            name: Some(player_name.clone()),

            health: PLAYER_DEFAULT_HEALTH,

            inventory_id: inventory.inventory_id,

            position: PLAYER_SPAWN_POS,

            rotation: Vec3 {
                x: 0.0,
                y: 0.0,
                z: 1.0,
            },

            online: true,
        };

        match ctx.db.player().try_insert(new_player_data.clone()) {
            Ok(inserted_player) => {
                spacetimedb::log::info!(
                    "PlayerData {:?} ({}) created successfully.",
                    player_identity,
                    player_name
                );

                physics::create_player_body(&inserted_player);
            }

            Err(e) => {
                spacetimedb::log::error!(
                    "Failed to insert new player {:?}: {}",
                    player_identity,
                    e
                );

                ctx.db
                    .inventory()
                    .inventory_id()
                    .delete(inventory.inventory_id);
            }
        }
    }
}

#[spacetimedb::reducer(client_disconnected)]

pub fn identity_disconnected(ctx: &ReducerContext) {
    let player_identity = ctx.sender;

    spacetimedb::log::info!("Client disconnected: {:?}", player_identity);

    if let Some(player_to_update) = ctx.db.player().identity().find(player_identity) {
        let mut updated_player = player_to_update.clone();

        updated_player.online = false;

        ctx.db.player().identity().update(updated_player);

        spacetimedb::log::info!("PlayerData {:?} marked as disconnected.", player_identity);

        physics::remove_player_body(&player_identity);
    } else {
        spacetimedb::log::warn!(
            "Disconnect event for player {:?} who was not found in the PlayerData table.",
            player_identity
        );
    }
}

#[spacetimedb::reducer]

pub fn move_player_reducer(
    ctx: &ReducerContext,
    direction: Vec3,
    jump: bool,
    run: bool,
) -> Result<(), String> {
    reducers::player_actions::move_player(ctx, direction, jump, run)
}

#[spacetimedb::reducer]

pub fn gather_resource_reducer(ctx: &ReducerContext, node_id: u64) -> Result<(), String> {
    reducers::player_actions::gather_resource(ctx, node_id)
}

#[spacetimedb::reducer]

pub fn build_ship_reducer(
    ctx: &ReducerContext,
    name: String,
    position: Vec3,
) -> Result<(), String> {
    reducers::ship_actions::build_ship(ctx, name, position)
}

#[spacetimedb::reducer]

pub fn spawn_test_player_reducer(
    ctx: &ReducerContext,
    position: Vec3,
    name: String,
) -> Result<(), String> {
    reducers::test_actions::spawn_test_player(ctx, position, name)
}

#[spacetimedb::reducer]

pub fn spawn_test_ship_reducer(
    ctx: &ReducerContext,
    position: Vec3,
    name: String,
) -> Result<(), String> {
    reducers::test_actions::spawn_test_ship(ctx, position, name)
}

#[spacetimedb::reducer]

pub fn spawn_test_resource_reducer(
    ctx: &ReducerContext,
    position: Vec3,
    resource_type: ResourceType,
    amount: u32,
) -> Result<(), String> {
    reducers::test_actions::spawn_test_resource(ctx, position, resource_type, amount)
}

#[spacetimedb::reducer]

pub fn apply_force_to_player_reducer(
    ctx: &ReducerContext,
    direction: Vec3,
    jump: bool,
    run: bool,
) -> Result<(), String> {
    reducers::test_actions::apply_force_to_player(ctx, direction, jump, run)
}

#[spacetimedb::reducer]

pub fn get_player_position_reducer(ctx: &ReducerContext) -> Result<(), String> {
    reducers::test_actions::get_player_position(ctx)
}

#[spacetimedb::reducer]

pub fn list_all_players_reducer(ctx: &ReducerContext) -> Result<(), String> {
    reducers::test_actions::list_all_players(ctx)
}

#[spacetimedb::reducer]

pub fn list_all_ships_reducer(ctx: &ReducerContext) -> Result<(), String> {
    reducers::test_actions::list_all_ships(ctx)
}

#[spacetimedb::reducer]

pub fn list_all_resources_reducer(ctx: &ReducerContext) -> Result<(), String> {
    reducers::test_actions::list_all_resources(ctx)
}

#[spacetimedb::reducer(update)]

pub fn server_tick_reducer(
    ctx: &ReducerContext,
    _tick_info: ServerTickSchedule, /* Remove _prev_tick_info argument */
) -> Result<(), String> {
    let current_time = ctx.timestamp;

    let zero_timestamp = Timestamp::from_micros_since_unix_epoch(0);

    tick::server_tick(ctx, current_time, zero_timestamp);

    Ok(())
}

Server output
ule.rs:14: reducer "init" runtime error: error while executing at wasm backtrace:
    0: 0x1b258e - pirates_rust.wasm!__rust_start_panic
    1: 0x1b24e9 - pirates_rust.wasm!rust_panic
    2: 0x1b242e - pirates_rust.wasm!std::panicking::rust_panic_with_hook::h4501cceb7dbe383d
    3: 0x1b18ed - pirates_rust.wasm!std::panicking::begin_panic_handler::{{closure}}::hc2b9d3fc26dda7f9
    4: 0x1b1859 - pirates_rust.wasm!std::sys::backtrace::__rust_end_short_backtrace::hf6a83a0a2155b9c0
    5: 0x1b1fc3 - pirates_rust.wasm!rust_begin_unwind
    6: 0x1b82c8 - pirates_rust.wasm!core::panicking::panic_fmt::h619600efce2da276
    7: 0x1b9f30 - pirates_rust.wasm!core::result::unwrap_failed::h4ec8ebc0cd29f54b
    8: 0xa6ef - pirates_rust.wasm!pirates_rust::init::invoke::hf8b7175ed331661d
    9: 0x1a62bc - pirates_rust.wasm!__call_reducer__
2025-04-09T20:01:00.975245Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #10: __rust_start_panic
2025-04-09T20:01:00.975330Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #9: rust_panic
2025-04-09T20:01:00.975382Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #8: std::panicking::rust_panic_with_hook::h4501cceb7dbe383d
2025-04-09T20:01:00.975446Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #7: std::panicking::begin_panic_handler::{{closure}}::hc2b9d3fc26dda7f9
2025-04-09T20:01:00.975501Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #6: std::sys::backtrace::__rust_end_short_backtrace::hf6a83a0a2155b9c0
2025-04-09T20:01:00.975577Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #5: rust_begin_unwind
2025-04-09T20:01:00.975633Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #4: core::panicking::panic_fmt::h619600efce2da276        
2025-04-09T20:01:00.975715Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #3: core::result::unwrap_failed::h4ec8ebc0cd29f54b       
2025-04-09T20:01:00.975790Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #2: pirates_rust::init::invoke::hf8b7175ed331661d        
2025-04-09T20:01:00.975849Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #1: __call_reducer__
2025-04-09T20:01:00.977058Z ERROR D:\a\SpacetimeDB\SpacetimeDB\crates\client-api\src\lib.rs:373: internal error: failed to get or launch module host: The Wasm instance encountered a fatal error.
2025-04-09T20:01:00.977239Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:202: exiting persister task
2025-04-09T20:01:04.827510Z  INFO crates\core\src\auth\token_validation.rs:209: Fetching key for issuer https://auth.spacetimedb.com
2025-04-09T20:01:37.969200Z DEBUG crates\core\src\auth\token_validation.rs:231: Getting validator for issuer https://auth.spacetimedb.com
2025-04-09T20:01:37.969327Z DEBUG crates\core\src\auth\token_validation.rs:301: No key id in header. Trying all keys.
2025-04-09T20:01:37.969442Z DEBUG crates\core\src\auth\token_validation.rs:306: Trying key 0
2025-04-09T20:01:37.970619Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:98: open local durability
2025-04-09T20:01:37.971154Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:257: starting syncer task
2025-04-09T20:01:37.971226Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:182: starting persister task
2025-04-09T20:01:37.971201Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:98: open local durability
2025-04-09T20:01:37.980608Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:257: starting syncer task
2025-04-09T20:01:37.980613Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:182: starting persister task
2025-04-09T20:01:37.980806Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\core\src\db\relational_db.rs:312: [c20045e7c025414a5edb2373c9119525107dca1e28b6ed85d28d42d4f2de8082] DATABASE: durable_tx_offset is None
2025-04-09T20:01:37.980897Z  INFO crates\core\src\db\relational_db.rs:463: [c20045e7c025414a5edb2373c9119525107dca1e28b6ed85d28d42d4f2de8082] DATABASE: no snapshot on disk
2025-04-09T20:01:37.981234Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\core\src\db\relational_db.rs:1213: [c20045e7c025414a5edb2373c9119525107dca1e28b6ed85d28d42d4f2de8082] DATABASE: applying transaction history...
2025-04-09T20:01:37.989490Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\core\src\db\relational_db.rs:1247: [c20045e7c025414a5edb2373c9119525107dca1e28b6ed85d28d42d4f2de8082] DATABASE: applied transaction history
2025-04-09T20:01:37.989927Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\core\src\db\relational_db.rs:1249: [c20045e7c025414a5edb2373c9119525107dca1e28b6ed85d28d42d4f2de8082] DATABASE: rebuilt state after replay
2025-04-09T20:01:37.990135Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:202: exiting persister task
2025-04-09T20:01:38.013497Z DEBUG D:\a\SpacetimeDB\SpacetimeDB\crates\core\src\host\wasm_common\module_host_actor.rs:272: init database
2025-04-09T20:01:38.016376Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:14: reducer "init" runtime error: error while executing at wasm backtrace:
    0: 0x1b258e - pirates_rust.wasm!__rust_start_panic
    1: 0x1b24e9 - pirates_rust.wasm!rust_panic
    2: 0x1b242e - pirates_rust.wasm!std::panicking::rust_panic_with_hook::h4501cceb7dbe383d
    3: 0x1b18ed - pirates_rust.wasm!std::panicking::begin_panic_handler::{{closure}}::hc2b9d3fc26dda7f9
    4: 0x1b1859 - pirates_rust.wasm!std::sys::backtrace::__rust_end_short_backtrace::hf6a83a0a2155b9c0
    5: 0x1b1fc3 - pirates_rust.wasm!rust_begin_unwind
    6: 0x1b82c8 - pirates_rust.wasm!core::panicking::panic_fmt::h619600efce2da276
    7: 0x1b9f30 - pirates_rust.wasm!core::result::unwrap_failed::h4ec8ebc0cd29f54b
    8: 0xa6ef - pirates_rust.wasm!pirates_rust::init::invoke::hf8b7175ed331661d
    9: 0x1a62bc - pirates_rust.wasm!__call_reducer__
2025-04-09T20:01:38.016578Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #10: __rust_start_panic
2025-04-09T20:01:38.016650Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #9: rust_panic
2025-04-09T20:01:38.016714Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #8: std::panicking::rust_panic_with_hook::h4501cceb7dbe383d
2025-04-09T20:01:38.016769Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #7: std::panicking::begin_panic_handler::{{closure}}::hc2b9d3fc26dda7f9
2025-04-09T20:01:38.016823Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #6: std::sys::backtrace::__rust_end_short_backtrace::hf6a83a0a2155b9c0
2025-04-09T20:01:38.016875Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #5: rust_begin_unwind
2025-04-09T20:01:38.016919Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #4: core::panicking::panic_fmt::h619600efce2da276        
2025-04-09T20:01:38.016977Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #3: core::result::unwrap_failed::h4ec8ebc0cd29f54b       
2025-04-09T20:01:38.017031Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #2: pirates_rust::init::invoke::hf8b7175ed331661d        
2025-04-09T20:01:38.017101Z  INFO crates\core\src\host\wasmtime\wasmtime_module.rs:18:   Frame #1: __call_reducer__
2025-04-09T20:01:38.018059Z ERROR D:\a\SpacetimeDB\SpacetimeDB\crates\client-api\src\lib.rs:373: internal error: failed to get or launch module host: The Wasm instance encountered a fatal error.
2025-04-09T20:01:38.018223Z  INFO D:\a\SpacetimeDB\SpacetimeDB\crates\durability\src\imp\local.rs:202: exiting persister task
Builder output
Optimising module with wasm-opt...
Could not find wasm-opt to optimise the module.
For best performance install wasm-opt from https://github.com/WebAssembly/binaryen/releases.
Continuing with unoptimised module.
Build finished successfully.
Uploading to local => http://127.0.0.1:3000
Publishing module...
Error: failed to get or launch module host: The Wasm instance encountered a fatal error.

Caused by:
    HTTP status server error (500 Internal Server Error) for url (http://127.0.0.1:3000/v1/database/pirates-rust)
Cargo.toml
[package]
name = "pirates-rust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]

[dependencies]
spacetimedb = "1.0.1"
log = "0.4"
rapier3d = { version = "0.22.0", features = ["serde-serialize", "wasm-bindgen"] }
nalgebra = "0.33.2"
env_logger = "0.11.8"
serde = { version = "1.0.219", features = ["derive"] }
once_cell = "1.19.0"
tracing = { version = "0.1", features = ["max_level_debug", "release_max_level_warn"] }

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the Windows x64 failure while running the init reducer from lib.rs, then inspect physics::init_physics_world_state and the truncated server output. Determine why initialization panics with the Rapier build and verify that the init reducer completes successfully on Windows without the panic.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.