228 lines
7.2 KiB
Rust
228 lines
7.2 KiB
Rust
use crate::big_fish::tables::{
|
|
BigFishCreationSession, BigFishRuntimeRun, big_fish_creation_session, big_fish_runtime_run,
|
|
};
|
|
use crate::*;
|
|
use module_big_fish::{
|
|
StartBigFishRunCommand, SubmitBigFishInputCommand, deserialize_runtime_snapshot,
|
|
serialize_runtime_snapshot, start_big_fish_run as start_big_fish_run_domain,
|
|
submit_big_fish_input as submit_big_fish_input_domain,
|
|
};
|
|
|
|
#[spacetimedb::procedure]
|
|
pub fn start_big_fish_run(
|
|
ctx: &mut ProcedureContext,
|
|
input: BigFishRunStartInput,
|
|
) -> BigFishRunProcedureResult {
|
|
match ctx.try_with_tx(|tx| start_big_fish_run_tx(tx, input.clone())) {
|
|
Ok(run) => BigFishRunProcedureResult {
|
|
ok: true,
|
|
run: Some(run),
|
|
error_message: None,
|
|
},
|
|
Err(message) => BigFishRunProcedureResult {
|
|
ok: false,
|
|
run: None,
|
|
error_message: Some(message),
|
|
},
|
|
}
|
|
}
|
|
|
|
#[spacetimedb::procedure]
|
|
pub fn get_big_fish_run(
|
|
ctx: &mut ProcedureContext,
|
|
input: BigFishRunGetInput,
|
|
) -> BigFishRunProcedureResult {
|
|
match ctx.try_with_tx(|tx| get_big_fish_run_tx(tx, input.clone())) {
|
|
Ok(run) => BigFishRunProcedureResult {
|
|
ok: true,
|
|
run: Some(run),
|
|
error_message: None,
|
|
},
|
|
Err(message) => BigFishRunProcedureResult {
|
|
ok: false,
|
|
run: None,
|
|
error_message: Some(message),
|
|
},
|
|
}
|
|
}
|
|
|
|
#[spacetimedb::procedure]
|
|
pub fn submit_big_fish_input(
|
|
ctx: &mut ProcedureContext,
|
|
input: BigFishInputSubmitInput,
|
|
) -> BigFishRunProcedureResult {
|
|
match ctx.try_with_tx(|tx| submit_big_fish_input_tx(tx, input.clone())) {
|
|
Ok(run) => BigFishRunProcedureResult {
|
|
ok: true,
|
|
run: Some(run),
|
|
error_message: None,
|
|
},
|
|
Err(message) => BigFishRunProcedureResult {
|
|
ok: false,
|
|
run: None,
|
|
error_message: Some(message),
|
|
},
|
|
}
|
|
}
|
|
|
|
pub(crate) fn start_big_fish_run_tx(
|
|
ctx: &ReducerContext,
|
|
input: BigFishRunStartInput,
|
|
) -> Result<BigFishRuntimeSnapshot, String> {
|
|
validate_run_start_input(&input).map_err(|error| error.to_string())?;
|
|
if ctx
|
|
.db
|
|
.big_fish_runtime_run()
|
|
.run_id()
|
|
.find(&input.run_id)
|
|
.is_some()
|
|
{
|
|
return Err("big_fish_runtime_run.run_id 已存在".to_string());
|
|
}
|
|
|
|
let session = ctx
|
|
.db
|
|
.big_fish_creation_session()
|
|
.session_id()
|
|
.find(&input.session_id)
|
|
.ok_or_else(|| "big_fish_creation_session 不存在".to_string())?;
|
|
ensure_big_fish_session_playable(&session, &input.owner_user_id)?;
|
|
let draft = session
|
|
.draft_json
|
|
.as_deref()
|
|
.map(deserialize_draft)
|
|
.transpose()
|
|
.map_err(|error| format!("big_fish.draft_json 非法: {error}"))?;
|
|
let work_level_count = draft
|
|
.as_ref()
|
|
.map(|value| value.runtime_params.level_count)
|
|
.or_else(|| Some(BIG_FISH_DEFAULT_LEVEL_COUNT));
|
|
let result = start_big_fish_run_domain(StartBigFishRunCommand {
|
|
run_id: input.run_id,
|
|
session_id: input.session_id,
|
|
owner_user_id: input.owner_user_id.clone(),
|
|
draft,
|
|
work_level_count,
|
|
started_at_micros: input.started_at_micros,
|
|
})
|
|
.map_err(|error| error.to_string())?;
|
|
|
|
insert_big_fish_runtime_run(
|
|
ctx,
|
|
&result.snapshot,
|
|
&input.owner_user_id,
|
|
input.started_at_micros,
|
|
)?;
|
|
Ok(result.snapshot)
|
|
}
|
|
|
|
pub(crate) fn get_big_fish_run_tx(
|
|
ctx: &ReducerContext,
|
|
input: BigFishRunGetInput,
|
|
) -> Result<BigFishRuntimeSnapshot, String> {
|
|
validate_run_get_input(&input).map_err(|error| error.to_string())?;
|
|
let row = get_owned_big_fish_run_row(ctx, &input.run_id, &input.owner_user_id)?;
|
|
deserialize_runtime_snapshot(&row.snapshot_json)
|
|
.map_err(|error| format!("big_fish.runtime_snapshot_json 非法: {error}"))
|
|
}
|
|
|
|
pub(crate) fn submit_big_fish_input_tx(
|
|
ctx: &ReducerContext,
|
|
input: BigFishInputSubmitInput,
|
|
) -> Result<BigFishRuntimeSnapshot, String> {
|
|
validate_input_submit_input(&input).map_err(|error| error.to_string())?;
|
|
let row = get_owned_big_fish_run_row(ctx, &input.run_id, &input.owner_user_id)?;
|
|
let current_snapshot = deserialize_runtime_snapshot(&row.snapshot_json)
|
|
.map_err(|error| format!("big_fish.runtime_snapshot_json 非法: {error}"))?;
|
|
let result = submit_big_fish_input_domain(SubmitBigFishInputCommand {
|
|
owner_user_id: input.owner_user_id,
|
|
x: input.x,
|
|
y: input.y,
|
|
submitted_at_micros: input.submitted_at_micros,
|
|
current_snapshot,
|
|
})
|
|
.map_err(|error| error.to_string())?;
|
|
|
|
replace_big_fish_runtime_run(ctx, &row, &result.snapshot, input.submitted_at_micros)?;
|
|
Ok(result.snapshot)
|
|
}
|
|
|
|
fn ensure_big_fish_session_playable(
|
|
session: &BigFishCreationSession,
|
|
player_user_id: &str,
|
|
) -> Result<(), String> {
|
|
if session.owner_user_id == player_user_id {
|
|
return Ok(());
|
|
}
|
|
if session.stage == BigFishCreationStage::Published {
|
|
return Ok(());
|
|
}
|
|
Err("未发布的大鱼吃小鱼作品不允许非作者启动运行态".to_string())
|
|
}
|
|
|
|
fn get_owned_big_fish_run_row(
|
|
ctx: &ReducerContext,
|
|
run_id: &str,
|
|
owner_user_id: &str,
|
|
) -> Result<BigFishRuntimeRun, String> {
|
|
let row = ctx
|
|
.db
|
|
.big_fish_runtime_run()
|
|
.run_id()
|
|
.find(&run_id.to_string())
|
|
.ok_or_else(|| "big_fish_runtime_run 不存在".to_string())?;
|
|
if row.owner_user_id != owner_user_id {
|
|
return Err("无权访问该 big_fish_runtime_run".to_string());
|
|
}
|
|
Ok(row)
|
|
}
|
|
|
|
fn insert_big_fish_runtime_run(
|
|
ctx: &ReducerContext,
|
|
run: &BigFishRuntimeSnapshot,
|
|
owner_user_id: &str,
|
|
created_at_micros: i64,
|
|
) -> Result<(), String> {
|
|
let timestamp = Timestamp::from_micros_since_unix_epoch(created_at_micros);
|
|
ctx.db.big_fish_runtime_run().insert(BigFishRuntimeRun {
|
|
run_id: run.run_id.clone(),
|
|
session_id: run.session_id.clone(),
|
|
owner_user_id: owner_user_id.to_string(),
|
|
status: run.status,
|
|
snapshot_json: serialize_runtime_snapshot(run)
|
|
.map_err(|error| format!("big_fish.runtime_snapshot 序列化失败: {error}"))?,
|
|
last_input_x: run.last_input.x,
|
|
last_input_y: run.last_input.y,
|
|
tick: run.tick,
|
|
created_at: timestamp,
|
|
updated_at: timestamp,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
fn replace_big_fish_runtime_run(
|
|
ctx: &ReducerContext,
|
|
current: &BigFishRuntimeRun,
|
|
run: &BigFishRuntimeSnapshot,
|
|
updated_at_micros: i64,
|
|
) -> Result<(), String> {
|
|
ctx.db
|
|
.big_fish_runtime_run()
|
|
.run_id()
|
|
.delete(¤t.run_id);
|
|
ctx.db.big_fish_runtime_run().insert(BigFishRuntimeRun {
|
|
run_id: run.run_id.clone(),
|
|
session_id: run.session_id.clone(),
|
|
owner_user_id: current.owner_user_id.clone(),
|
|
status: run.status,
|
|
snapshot_json: serialize_runtime_snapshot(run)
|
|
.map_err(|error| format!("big_fish.runtime_snapshot 序列化失败: {error}"))?,
|
|
last_input_x: run.last_input.x,
|
|
last_input_y: run.last_input.y,
|
|
tick: run.tick,
|
|
created_at: current.created_at,
|
|
updated_at: Timestamp::from_micros_since_unix_epoch(updated_at_micros),
|
|
});
|
|
Ok(())
|
|
}
|