From 6580f2c3de06e3be1aeb8887acee08f70e35eed6 Mon Sep 17 00:00:00 2001 From: Jordon Bedwell Date: Thu, 6 Aug 2026 00:50:09 -0500 Subject: [PATCH] Fix possible race condition when chaining item conversions Attempts to fix a race when chaining item conversions quickly. Successful conversions were clearing the action asynchronously, so the clear from the previous conversion could sometimes run after the next one started and reset it to None. Successful conversions now clear the action immediately. Failed conversions keep the existing scheduled clear since their transaction gets rolled back. --- .../game/handlers/player_craft/item_convert.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/BitCraftServer/packages/game/src/game/handlers/player_craft/item_convert.rs b/BitCraftServer/packages/game/src/game/handlers/player_craft/item_convert.rs index bdb66c00..365c624e 100644 --- a/BitCraftServer/packages/game/src/game/handlers/player_craft/item_convert.rs +++ b/BitCraftServer/packages/game/src/game/handlers/player_craft/item_convert.rs @@ -4,6 +4,7 @@ use std::time::Duration; use spacetimedb::ReducerContext; use crate::game::game_state; +use crate::game::handlers::server::player_clear_action_state; use crate::game::reducer_helpers::player_action_helpers; use crate::game::terrain_chunk::TerrainChunkCache; use crate::{ @@ -51,11 +52,17 @@ pub fn item_convert_start(ctx: &ReducerContext, request: PlayerItemConvertReques pub fn item_convert(ctx: &ReducerContext, request: PlayerItemConvertRequest) -> Result<(), String> { let actor_id = game_state::actor_id(&ctx, true)?; PlayerTimestampState::refresh(ctx, actor_id, ctx.timestamp); - player_action_helpers::schedule_clear_player_action( - actor_id, - PlayerActionType::ConvertItems.get_layer(ctx), - reduce(ctx, actor_id, &request, false), - ) + let layer = PlayerActionType::ConvertItems.get_layer(ctx); + match reduce(ctx, actor_id, &request, false) { + Ok(()) => player_clear_action_state::reduce( + ctx, + actor_id, + PlayerActionType::None, + layer, + PlayerActionResult::Success, + ), + Err(error) => player_action_helpers::schedule_clear_player_action_on_err(actor_id, layer, Err(error)), + } } fn reduce(ctx: &ReducerContext, actor_id: u64, request: &PlayerItemConvertRequest, dry_run: bool) -> Result<(), String> {