Switch to VectorEngine gpt-image-2 and edits

Replace uses of the legacy `gpt-image-2-all` model with `gpt-image-2` and standardize image workflows: no-reference generation uses POST /v1/images/generations, any-reference flows use POST /v1/images/edits with multipart `image` parts. Update SKILLs, generation scripts, decision logs, and docs to reflect the contract change and edits-vs-generations guidance. Apply corresponding changes across backend (api-server match3d/puzzle modules, openai image adapter, mappers, telemetry, spacetime client/module), frontend components and services (Match3D, Puzzle, CreativeImageInputPanel, runtime shells), and add new spritesheet/parser files and tests. Also add media/logo.png. These changes align repository code and documentation with the VectorEngine image API contract and update generation/upload handling (green-screen -> alpha processing, spritesheet handling, and related tests).
This commit is contained in:
2026-05-22 03:06:41 +08:00
parent 321e1ea33a
commit ae014ac881
90 changed files with 7078 additions and 3389 deletions

View File

@@ -5,11 +5,11 @@ use crate::mapper::{
map_jump_hop_works_procedure_result,
};
use shared_contracts::jump_hop::{
JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType, JumpHopCharacterAsset, JumpHopDifficulty,
JumpHopDraftResponse, JumpHopGalleryResponse, JumpHopGenerationStatus, JumpHopJumpRequest,
JumpHopRestartRunRequest, JumpHopRuntimeRunSnapshotResponse, JumpHopSessionSnapshotResponse,
JumpHopStartRunRequest, JumpHopStylePreset, JumpHopTileAsset, JumpHopTileType,
JumpHopWorkProfileResponse,
JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType, JumpHopCharacterAsset,
JumpHopDifficulty, JumpHopDraftResponse, JumpHopGalleryResponse, JumpHopGenerationStatus,
JumpHopJumpRequest, JumpHopRestartRunRequest, JumpHopRuntimeRunSnapshotResponse,
JumpHopSessionSnapshotResponse, JumpHopStartRunRequest, JumpHopStylePreset, JumpHopTileAsset,
JumpHopTileType, JumpHopWorkProfileResponse,
};
use shared_kernel::build_prefixed_uuid_id;
@@ -21,10 +21,9 @@ impl SpacetimeClient {
&self,
session: JumpHopSessionSnapshotResponse,
) -> Result<JumpHopSessionSnapshotResponse, SpacetimeClientError> {
let draft = session
.draft
.clone()
.ok_or_else(|| SpacetimeClientError::validation_failed("jump-hop session 缺少 draft"))?;
let draft = session.draft.clone().ok_or_else(|| {
SpacetimeClientError::validation_failed("jump-hop session 缺少 draft")
})?;
let theme_tags_json = Some(json_string(&draft.theme_tags)?);
let config_json = Some(build_config_json(&draft)?);
let work_title = draft.work_title.clone();
@@ -164,15 +163,14 @@ impl SpacetimeClient {
procedure_input: JumpHopWorkUpdateInput,
) -> Result<JumpHopWorkProfileResponse, SpacetimeClientError> {
self.call_after_connect("update_jump_hop_work", move |connection, sender| {
connection.procedures().update_jump_hop_work_then(
procedure_input,
move |_, result| {
connection
.procedures()
.update_jump_hop_work_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_jump_hop_work_procedure_result);
send_once(&sender, mapped);
},
);
});
})
.await
}
@@ -212,15 +210,14 @@ impl SpacetimeClient {
};
self.call_after_connect("list_jump_hop_works", move |connection, sender| {
connection.procedures().list_jump_hop_works_then(
procedure_input,
move |_, result| {
connection
.procedures()
.list_jump_hop_works_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_jump_hop_works_procedure_result);
send_once(&sender, mapped);
},
);
});
})
.await
}
@@ -229,7 +226,8 @@ impl SpacetimeClient {
&self,
profile_id: String,
) -> Result<JumpHopWorkProfileResponse, SpacetimeClientError> {
self.get_jump_hop_work_profile(profile_id, String::new()).await
self.get_jump_hop_work_profile(profile_id, String::new())
.await
}
pub async fn start_jump_hop_run(
@@ -253,15 +251,14 @@ impl SpacetimeClient {
procedure_input: JumpHopRunStartInput,
) -> Result<JumpHopRuntimeRunSnapshotResponse, SpacetimeClientError> {
self.call_after_connect("start_jump_hop_run", move |connection, sender| {
connection.procedures().start_jump_hop_run_then(
procedure_input,
move |_, result| {
connection
.procedures()
.start_jump_hop_run_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_jump_hop_run_procedure_result);
send_once(&sender, mapped);
},
);
});
})
.await
}
@@ -277,15 +274,14 @@ impl SpacetimeClient {
};
self.call_after_connect("get_jump_hop_run", move |connection, sender| {
connection.procedures().get_jump_hop_run_then(
procedure_input,
move |_, result| {
connection
.procedures()
.get_jump_hop_run_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_jump_hop_run_procedure_result);
send_once(&sender, mapped);
},
);
});
})
.await
}
@@ -305,15 +301,14 @@ impl SpacetimeClient {
};
self.call_after_connect("jump_hop_jump", move |connection, sender| {
connection.procedures().jump_hop_jump_then(
procedure_input,
move |_, result| {
connection
.procedures()
.jump_hop_jump_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_jump_hop_run_procedure_result);
send_once(&sender, mapped);
},
);
});
})
.await
}
@@ -333,15 +328,14 @@ impl SpacetimeClient {
};
self.call_after_connect("restart_jump_hop_run", move |connection, sender| {
connection.procedures().restart_jump_hop_run_then(
procedure_input,
move |_, result| {
connection
.procedures()
.restart_jump_hop_run_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_jump_hop_run_procedure_result);
send_once(&sender, mapped);
},
);
});
})
.await
}
@@ -430,16 +424,16 @@ fn build_jump_hop_action_plan(
JumpHopAssetRefresh::Preserve,
now_micros,
)?),
JumpHopActionType::RegenerateCharacter => JumpHopActionProcedure::Compile(
build_compile_input(
JumpHopActionType::RegenerateCharacter => {
JumpHopActionProcedure::Compile(build_compile_input(
current,
owner_user_id,
&profile_id,
&mut draft,
JumpHopAssetRefresh::Character,
now_micros,
)?,
),
)?)
}
JumpHopActionType::RegenerateTiles => JumpHopActionProcedure::Compile(build_compile_input(
current,
owner_user_id,
@@ -472,7 +466,11 @@ fn merge_action_into_draft(
scope,
JumpHopDraftMergeScope::CompileDraft | JumpHopDraftMergeScope::UpdateWorkMeta
) {
if let Some(value) = payload.work_title.as_ref().filter(|value| !value.trim().is_empty()) {
if let Some(value) = payload
.work_title
.as_ref()
.filter(|value| !value.trim().is_empty())
{
draft.work_title = value.trim().to_string();
}
if let Some(value) = payload.work_description.as_ref() {
@@ -523,7 +521,9 @@ fn merge_action_into_draft(
draft.tile_prompt = value.trim().to_string();
}
if draft.work_title.trim().is_empty() {
return Err(SpacetimeClientError::validation_failed("jump-hop work_title 不能为空"));
return Err(SpacetimeClientError::validation_failed(
"jump-hop work_title 不能为空",
));
}
Ok(draft)
}
@@ -762,7 +762,9 @@ fn ensure_tile_assets(
.map(|(index, tile_type)| JumpHopTileAsset {
tile_type,
image_src: format!("/generated-jump-hop-assets/{profile_id}/tiles/{index}{suffix}.png"),
image_object_key: format!("generated-jump-hop-assets/{profile_id}/tiles/{index}{suffix}.png"),
image_object_key: format!(
"generated-jump-hop-assets/{profile_id}/tiles/{index}{suffix}.png"
),
asset_object_id: format!("{profile_id}-tile-{index}{suffix}-object"),
source_atlas_cell: format!("cell-{index}{suffix}"),
visual_width: 256,
@@ -788,7 +790,9 @@ fn resolve_cover_composite(
{
return Some(value.to_string());
}
let suffix = asset_revision_suffix((!matches!(refresh, JumpHopAssetRefresh::Preserve)).then_some(now_micros));
let suffix = asset_revision_suffix(
(!matches!(refresh, JumpHopAssetRefresh::Preserve)).then_some(now_micros),
);
Some(format!(
"/generated-jump-hop-assets/{profile_id}/cover-composite{suffix}.png"
))
@@ -850,9 +854,27 @@ mod tests {
assert_eq!(input.session_id, SESSION_ID);
assert_eq!(input.owner_user_id, OWNER_USER_ID);
assert_eq!(input.generation_status.as_deref(), Some("ready"));
assert!(input.character_asset_json.as_deref().unwrap_or("").contains("-character"));
assert!(input.tile_atlas_asset_json.as_deref().unwrap_or("").contains("-tile-atlas"));
assert!(input.tile_assets_json.as_deref().unwrap_or("").contains("tile-0-object"));
assert!(
input
.character_asset_json
.as_deref()
.unwrap_or("")
.contains("-character")
);
assert!(
input
.tile_atlas_asset_json
.as_deref()
.unwrap_or("")
.contains("-tile-atlas")
);
assert!(
input
.tile_assets_json
.as_deref()
.unwrap_or("")
.contains("tile-0-object")
);
assert_eq!(draft.generation_status, JumpHopGenerationStatus::Ready);
}
@@ -869,10 +891,34 @@ mod tests {
let JumpHopActionProcedure::Compile(input) = plan else {
panic!("regenerate-character should call compile_jump_hop_draft");
};
assert!(!input.character_asset_json.as_deref().unwrap_or("").contains("old-character"));
assert!(input.character_asset_json.as_deref().unwrap_or("").contains(&NOW_MICROS.to_string()));
assert!(input.tile_atlas_asset_json.as_deref().unwrap_or("").contains("old-tile-atlas"));
assert!(input.tile_assets_json.as_deref().unwrap_or("").contains("old-normal-tile"));
assert!(
!input
.character_asset_json
.as_deref()
.unwrap_or("")
.contains("old-character")
);
assert!(
input
.character_asset_json
.as_deref()
.unwrap_or("")
.contains(&NOW_MICROS.to_string())
);
assert!(
input
.tile_atlas_asset_json
.as_deref()
.unwrap_or("")
.contains("old-tile-atlas")
);
assert!(
input
.tile_assets_json
.as_deref()
.unwrap_or("")
.contains("old-normal-tile")
);
}
#[test]
@@ -888,11 +934,41 @@ mod tests {
let JumpHopActionProcedure::Compile(input) = plan else {
panic!("regenerate-tiles should call compile_jump_hop_draft");
};
assert!(input.character_asset_json.as_deref().unwrap_or("").contains("old-character"));
assert!(!input.tile_atlas_asset_json.as_deref().unwrap_or("").contains("old-tile-atlas"));
assert!(!input.tile_assets_json.as_deref().unwrap_or("").contains("old-normal-tile"));
assert!(input.tile_atlas_asset_json.as_deref().unwrap_or("").contains(&NOW_MICROS.to_string()));
assert!(input.tile_assets_json.as_deref().unwrap_or("").contains(&NOW_MICROS.to_string()));
assert!(
input
.character_asset_json
.as_deref()
.unwrap_or("")
.contains("old-character")
);
assert!(
!input
.tile_atlas_asset_json
.as_deref()
.unwrap_or("")
.contains("old-tile-atlas")
);
assert!(
!input
.tile_assets_json
.as_deref()
.unwrap_or("")
.contains("old-normal-tile")
);
assert!(
input
.tile_atlas_asset_json
.as_deref()
.unwrap_or("")
.contains(&NOW_MICROS.to_string())
);
assert!(
input
.tile_assets_json
.as_deref()
.unwrap_or("")
.contains(&NOW_MICROS.to_string())
);
}
#[test]
@@ -934,8 +1010,20 @@ mod tests {
};
assert_eq!(input.difficulty.as_deref(), Some("challenge"));
assert!(input.style_preset.is_none());
assert_eq!(draft.character_asset.as_ref().map(|asset| asset.asset_id.as_str()), Some("old-character"));
assert_eq!(draft.tile_assets.first().map(|asset| asset.asset_object_id.as_str()), Some("old-normal-tile-object"));
assert_eq!(
draft
.character_asset
.as_ref()
.map(|asset| asset.asset_id.as_str()),
Some("old-character")
);
assert_eq!(
draft
.tile_assets
.first()
.map(|asset| asset.asset_object_id.as_str()),
Some("old-normal-tile-object")
);
}
fn action(action_type: JumpHopActionType) -> JumpHopActionRequest {

View File

@@ -30,16 +30,8 @@ pub use mapper::{
CustomWorldPublishGateRecord, CustomWorldPublishWorldRecord,
CustomWorldPublishWorldRecordInput, CustomWorldPublishedProfileCompileRecord,
CustomWorldResultPreviewBlockerRecord, CustomWorldSupportedActionRecord,
CustomWorldWorkSummaryRecord, Match3DAgentMessageFinalizeRecordInput,
Match3DAgentMessageRecord, Match3DAgentMessageSubmitRecordInput,
Match3DAgentSessionCreateRecordInput, Match3DAgentSessionRecord, Match3DAnchorItemRecord,
Match3DAnchorPackRecord, Match3DClickConfirmationRecord, Match3DCompileDraftRecordInput,
Match3DCreatorConfigRecord, Match3DItemSnapshotRecord, Match3DResultDraftRecord,
Match3DRunClickRecordInput, Match3DRunRecord, Match3DRunRestartRecordInput,
Match3DRunStartRecordInput, Match3DRunStopRecordInput, Match3DRunTimeUpRecordInput,
Match3DTraySlotRecord, Match3DWorkProfileRecord, Match3DWorkUpdateRecordInput,
JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType, JumpHopCharacterAsset,
JumpHopDifficulty, JumpHopDraftResponse, JumpHopGalleryCardResponse,
CustomWorldWorkSummaryRecord, JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType,
JumpHopCharacterAsset, JumpHopDifficulty, JumpHopDraftResponse, JumpHopGalleryCardResponse,
JumpHopGalleryDetailResponse, JumpHopGalleryResponse, JumpHopGenerationStatus,
JumpHopJumpRequest, JumpHopJumpResponse, JumpHopJumpResult, JumpHopLastJump, JumpHopPath,
JumpHopPlatform, JumpHopRestartRunRequest, JumpHopRunResponse, JumpHopRunStatus,
@@ -47,7 +39,14 @@ pub use mapper::{
JumpHopSessionSnapshotResponse, JumpHopStartRunRequest, JumpHopStylePreset, JumpHopTileAsset,
JumpHopTileType, JumpHopWorkDetailResponse, JumpHopWorkMutationResponse,
JumpHopWorkProfileResponse, JumpHopWorkSummaryResponse, JumpHopWorksResponse,
JumpHopWorkspaceCreateRequest,
JumpHopWorkspaceCreateRequest, Match3DAgentMessageFinalizeRecordInput,
Match3DAgentMessageRecord, Match3DAgentMessageSubmitRecordInput,
Match3DAgentSessionCreateRecordInput, Match3DAgentSessionRecord, Match3DAnchorItemRecord,
Match3DAnchorPackRecord, Match3DClickConfirmationRecord, Match3DCompileDraftRecordInput,
Match3DCreatorConfigRecord, Match3DItemSnapshotRecord, Match3DResultDraftRecord,
Match3DRunClickRecordInput, Match3DRunRecord, Match3DRunRestartRecordInput,
Match3DRunStartRecordInput, Match3DRunStopRecordInput, Match3DRunTimeUpRecordInput,
Match3DTraySlotRecord, Match3DWorkProfileRecord, Match3DWorkUpdateRecordInput,
NpcBattleInteractionRecord, NpcInteractionRecord, NpcStateRecord,
PuzzleAgentMessageFinalizeRecordInput, PuzzleAgentMessageRecord,
PuzzleAgentMessageSubmitRecordInput, PuzzleAgentSessionCreateRecordInput,

View File

@@ -36,18 +36,6 @@ pub use self::combat::{
BarkBattleDraftConfigRecord, BarkBattleRunRecord, BarkBattleRuntimeConfigRecord,
ResolveCombatActionRecord,
};
pub use self::jump_hop::{
JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType, JumpHopCharacterAsset,
JumpHopDifficulty, JumpHopDraftResponse, JumpHopGalleryCardResponse,
JumpHopGalleryDetailResponse, JumpHopGalleryResponse, JumpHopGenerationStatus,
JumpHopJumpRequest, JumpHopJumpResponse, JumpHopJumpResult, JumpHopLastJump, JumpHopPath,
JumpHopPlatform, JumpHopRestartRunRequest, JumpHopRunResponse, JumpHopRunStatus,
JumpHopRuntimeRunSnapshotResponse, JumpHopScoring, JumpHopSessionResponse,
JumpHopSessionSnapshotResponse, JumpHopStartRunRequest, JumpHopStylePreset, JumpHopTileAsset,
JumpHopTileType, JumpHopWorkDetailResponse, JumpHopWorkMutationResponse,
JumpHopWorkProfileResponse, JumpHopWorkSummaryResponse, JumpHopWorksResponse,
JumpHopWorkspaceCreateRequest,
};
pub use self::common::{
BigFishAgentMessageRecord, BigFishAnchorItemRecord, BigFishAnchorPackRecord,
BigFishBackgroundBlueprintRecord, BigFishDraftCompileRecordInput,
@@ -77,6 +65,18 @@ pub use self::common::{
VisualNovelRunSnapshotRecordInput, VisualNovelRunStartRecordInput,
VisualNovelWorkCompileRecordInput,
};
pub use self::jump_hop::{
JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType, JumpHopCharacterAsset,
JumpHopDifficulty, JumpHopDraftResponse, JumpHopGalleryCardResponse,
JumpHopGalleryDetailResponse, JumpHopGalleryResponse, JumpHopGenerationStatus,
JumpHopJumpRequest, JumpHopJumpResponse, JumpHopJumpResult, JumpHopLastJump, JumpHopPath,
JumpHopPlatform, JumpHopRestartRunRequest, JumpHopRunResponse, JumpHopRunStatus,
JumpHopRuntimeRunSnapshotResponse, JumpHopScoring, JumpHopSessionResponse,
JumpHopSessionSnapshotResponse, JumpHopStartRunRequest, JumpHopStylePreset, JumpHopTileAsset,
JumpHopTileType, JumpHopWorkDetailResponse, JumpHopWorkMutationResponse,
JumpHopWorkProfileResponse, JumpHopWorkSummaryResponse, JumpHopWorksResponse,
JumpHopWorkspaceCreateRequest,
};
pub use self::match3d::{
Match3DAgentMessageFinalizeRecordInput, Match3DAgentMessageRecord,
Match3DAgentMessageSubmitRecordInput, Match3DAgentSessionCreateRecordInput,

View File

@@ -161,7 +161,11 @@ fn map_jump_hop_work_snapshot(
path: map_jump_hop_path(snapshot.path),
character_asset,
tile_atlas_asset,
tile_assets: snapshot.tile_assets.into_iter().map(map_tile_asset).collect(),
tile_assets: snapshot
.tile_assets
.into_iter()
.map(map_tile_asset)
.collect(),
})
}
@@ -180,7 +184,11 @@ fn map_jump_hop_draft_snapshot(snapshot: JumpHopDraftSnapshot) -> JumpHopDraftRe
end_mood_prompt: snapshot.end_mood_prompt,
character_asset: snapshot.character_asset.map(map_character_asset),
tile_atlas_asset: snapshot.tile_atlas_asset.map(map_character_asset),
tile_assets: snapshot.tile_assets.into_iter().map(map_tile_asset).collect(),
tile_assets: snapshot
.tile_assets
.into_iter()
.map(map_tile_asset)
.collect(),
path: snapshot.path.map(map_jump_hop_path),
cover_composite: snapshot.cover_composite,
generation_status: parse_generation_status(&snapshot.generation_status),
@@ -268,7 +276,9 @@ fn map_jump_hop_run_snapshot(snapshot: JumpHopRunSnapshot) -> JumpHopRuntimeRunS
crate::module_bindings::JumpHopJumpResultKind::Miss => JumpHopJumpResult::Miss,
crate::module_bindings::JumpHopJumpResultKind::Hit => JumpHopJumpResult::Hit,
crate::module_bindings::JumpHopJumpResultKind::Finish => JumpHopJumpResult::Finish,
crate::module_bindings::JumpHopJumpResultKind::Perfect => JumpHopJumpResult::Perfect,
crate::module_bindings::JumpHopJumpResultKind::Perfect => {
JumpHopJumpResult::Perfect
}
},
}),
started_at_ms: snapshot.started_at_ms,

View File

@@ -145,6 +145,12 @@ pub(crate) fn map_puzzle_draft_level(snapshot: PuzzleDraftLevel) -> PuzzleDraftL
ui_background_prompt: snapshot.ui_background_prompt,
ui_background_image_src: snapshot.ui_background_image_src,
ui_background_image_object_key: snapshot.ui_background_image_object_key,
level_scene_image_src: snapshot.level_scene_image_src,
level_scene_image_object_key: snapshot.level_scene_image_object_key,
ui_spritesheet_image_src: snapshot.ui_spritesheet_image_src,
ui_spritesheet_image_object_key: snapshot.ui_spritesheet_image_object_key,
level_background_image_src: snapshot.level_background_image_src,
level_background_image_object_key: snapshot.level_background_image_object_key,
background_music: snapshot.background_music.map(map_puzzle_audio_asset),
candidates: snapshot
.candidates
@@ -392,6 +398,10 @@ pub(crate) fn map_puzzle_runtime_level_snapshot(
cover_image_src: snapshot.cover_image_src,
ui_background_image_src: snapshot.ui_background_image_src,
ui_background_image_object_key: snapshot.ui_background_image_object_key,
level_background_image_src: snapshot.level_background_image_src,
level_background_image_object_key: snapshot.level_background_image_object_key,
ui_spritesheet_image_src: snapshot.ui_spritesheet_image_src,
ui_spritesheet_image_object_key: snapshot.ui_spritesheet_image_object_key,
background_music: snapshot.background_music.map(map_puzzle_audio_asset),
board: map_puzzle_board_snapshot(snapshot.board),
status: format_puzzle_runtime_level_status(snapshot.status).to_string(),
@@ -835,6 +845,12 @@ pub struct PuzzleDraftLevelRecord {
pub ui_background_prompt: Option<String>,
pub ui_background_image_src: Option<String>,
pub ui_background_image_object_key: Option<String>,
pub level_scene_image_src: Option<String>,
pub level_scene_image_object_key: Option<String>,
pub ui_spritesheet_image_src: Option<String>,
pub ui_spritesheet_image_object_key: Option<String>,
pub level_background_image_src: Option<String>,
pub level_background_image_object_key: Option<String>,
pub background_music: Option<PuzzleAudioAssetRecord>,
pub candidates: Vec<PuzzleGeneratedImageCandidateRecord>,
pub selected_candidate_id: Option<String>,
@@ -1038,6 +1054,10 @@ pub struct PuzzleRuntimeLevelRecord {
pub cover_image_src: Option<String>,
pub ui_background_image_src: Option<String>,
pub ui_background_image_object_key: Option<String>,
pub level_background_image_src: Option<String>,
pub level_background_image_object_key: Option<String>,
pub ui_spritesheet_image_src: Option<String>,
pub ui_spritesheet_image_object_key: Option<String>,
pub background_music: Option<PuzzleAudioAssetRecord>,
pub board: PuzzleBoardRecord,
pub status: String,

View File

@@ -1,4 +1,3 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.

View File

@@ -17,6 +17,12 @@ pub struct PuzzleDraftLevel {
pub ui_background_prompt: Option<String>,
pub ui_background_image_src: Option<String>,
pub ui_background_image_object_key: Option<String>,
pub level_scene_image_src: Option<String>,
pub level_scene_image_object_key: Option<String>,
pub ui_spritesheet_image_src: Option<String>,
pub ui_spritesheet_image_object_key: Option<String>,
pub level_background_image_src: Option<String>,
pub level_background_image_object_key: Option<String>,
pub background_music: Option<PuzzleAudioAsset>,
pub candidates: Vec<PuzzleGeneratedImageCandidate>,
pub selected_candidate_id: Option<String>,

View File

@@ -23,6 +23,10 @@ pub struct PuzzleRuntimeLevelSnapshot {
pub cover_image_src: Option<String>,
pub ui_background_image_src: Option<String>,
pub ui_background_image_object_key: Option<String>,
pub level_background_image_src: Option<String>,
pub level_background_image_object_key: Option<String>,
pub ui_spritesheet_image_src: Option<String>,
pub ui_spritesheet_image_object_key: Option<String>,
pub background_music: Option<PuzzleAudioAsset>,
pub board: PuzzleBoardSnapshot,
pub status: PuzzleRuntimeLevelStatus,

View File

@@ -81,7 +81,9 @@ fn spacetime_metrics() -> &'static SpacetimeMetrics {
read_duration_ms: meter
.f64_histogram("genarrative.spacetime.read.duration_ms")
.with_unit("ms")
.with_description("SpacetimeDB local subscription cache read duration in milliseconds")
.with_description(
"SpacetimeDB local subscription cache read duration in milliseconds",
)
.build(),
}
})