fix(jump-hop): preserve themed runtime metadata
This commit is contained in:
@@ -283,7 +283,10 @@ pub async fn start_jump_hop_run(
|
|||||||
) -> Result<Json<Value>, Response> {
|
) -> Result<Json<Value>, Response> {
|
||||||
let Json(payload) = jump_hop_json(payload, &request_context, JUMP_HOP_RUNTIME_PROVIDER)?;
|
let Json(payload) = jump_hop_json(payload, &request_context, JUMP_HOP_RUNTIME_PROVIDER)?;
|
||||||
ensure_non_empty(&request_context, &payload.profile_id, "profileId")?;
|
ensure_non_empty(&request_context, &payload.profile_id, "profileId")?;
|
||||||
let is_draft_runtime = payload.runtime_mode.as_deref() == Some("draft");
|
let is_draft_runtime = payload
|
||||||
|
.runtime_mode
|
||||||
|
.as_deref()
|
||||||
|
.is_some_and(is_jump_hop_draft_runtime_mode);
|
||||||
let owner_user_id = principal.subject().to_string();
|
let owner_user_id = principal.subject().to_string();
|
||||||
let principal_kind = principal.kind().as_str();
|
let principal_kind = principal.kind().as_str();
|
||||||
let run = state
|
let run = state
|
||||||
@@ -1240,6 +1243,10 @@ fn build_jump_hop_work_play_tracking_draft(
|
|||||||
WorkPlayTrackingDraft::runtime_principal("jump-hop", work_id, principal, source_route)
|
WorkPlayTrackingDraft::runtime_principal("jump-hop", work_id, principal, source_route)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_jump_hop_draft_runtime_mode(runtime_mode: &str) -> bool {
|
||||||
|
runtime_mode.trim().eq_ignore_ascii_case("draft")
|
||||||
|
}
|
||||||
|
|
||||||
fn build_jump_hop_draft(payload: &JumpHopWorkspaceCreateRequest) -> JumpHopDraftResponse {
|
fn build_jump_hop_draft(payload: &JumpHopWorkspaceCreateRequest) -> JumpHopDraftResponse {
|
||||||
let theme_text = normalize_theme_text(&payload.theme_text, &payload.work_title);
|
let theme_text = normalize_theme_text(&payload.theme_text, &payload.work_title);
|
||||||
JumpHopDraftResponse {
|
JumpHopDraftResponse {
|
||||||
@@ -1422,6 +1429,14 @@ fn current_utc_micros() -> i64 {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn jump_hop_draft_runtime_mode_detection_matches_client_normalization() {
|
||||||
|
assert!(is_jump_hop_draft_runtime_mode("draft"));
|
||||||
|
assert!(is_jump_hop_draft_runtime_mode(" DRAFT "));
|
||||||
|
assert!(!is_jump_hop_draft_runtime_mode("published"));
|
||||||
|
assert!(!is_jump_hop_draft_runtime_mode(""));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn jump_hop_tile_atlas_prompt_uses_dedicated_five_by_five_floor_layout() {
|
fn jump_hop_tile_atlas_prompt_uses_dedicated_five_by_five_floor_layout() {
|
||||||
let prompt = build_jump_hop_tile_atlas_prompt("森林冒险", "森林主题清爽游戏化立体感平台");
|
let prompt = build_jump_hop_tile_atlas_prompt("森林冒险", "森林主题清爽游戏化立体感平台");
|
||||||
|
|||||||
@@ -37,3 +37,93 @@ test('jump hop creation keeps image2 generation requests alive long enough', asy
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('jump hop work detail preserves flattened back button asset', async () => {
|
||||||
|
const backButtonAsset = {
|
||||||
|
assetId: 'back-button-1',
|
||||||
|
imageSrc: '/generated-jump-hop-assets/back-button-1.png',
|
||||||
|
imageObjectKey: 'jump-hop/back-button-1.png',
|
||||||
|
assetObjectId: 'asset-object-back-button-1',
|
||||||
|
generationProvider: 'image2',
|
||||||
|
prompt: '主题返回按钮',
|
||||||
|
width: 1024,
|
||||||
|
height: 1024,
|
||||||
|
};
|
||||||
|
const characterAsset = {
|
||||||
|
assetId: 'character-1',
|
||||||
|
imageSrc: 'builtin://jump-hop/default-character',
|
||||||
|
imageObjectKey: '',
|
||||||
|
assetObjectId: 'character-object-1',
|
||||||
|
generationProvider: 'builtin-three',
|
||||||
|
prompt: '内置默认角色',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
};
|
||||||
|
const draft = {
|
||||||
|
templateId: 'jump-hop',
|
||||||
|
templateName: '跳一跳',
|
||||||
|
profileId: 'profile-1',
|
||||||
|
themeText: '森林茶馆',
|
||||||
|
workTitle: '森林茶馆跳一跳',
|
||||||
|
workDescription: '森林茶馆主题',
|
||||||
|
themeTags: ['森林茶馆', '跳一跳'],
|
||||||
|
difficulty: 'standard',
|
||||||
|
stylePreset: 'minimal-blocks',
|
||||||
|
defaultCharacter: null,
|
||||||
|
characterPrompt: '内置默认角色',
|
||||||
|
tilePrompt: '森林茶馆主题地块',
|
||||||
|
endMoodPrompt: null,
|
||||||
|
characterAsset,
|
||||||
|
tileAtlasAsset: characterAsset,
|
||||||
|
tileAssets: [],
|
||||||
|
path: {
|
||||||
|
seed: 'profile-1',
|
||||||
|
difficulty: 'standard',
|
||||||
|
platforms: [],
|
||||||
|
scoring: {
|
||||||
|
perfectRadiusRatio: 0.24,
|
||||||
|
hitRadiusRatio: 0.52,
|
||||||
|
maxChargeMs: 1200,
|
||||||
|
minChargeMs: 80,
|
||||||
|
maxJumpDistance: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
coverComposite: null,
|
||||||
|
backButtonAsset: null,
|
||||||
|
generationStatus: 'ready',
|
||||||
|
};
|
||||||
|
requestJsonMock.mockResolvedValue({
|
||||||
|
item: {
|
||||||
|
runtimeKind: 'jump-hop',
|
||||||
|
workId: 'work-1',
|
||||||
|
profileId: 'profile-1',
|
||||||
|
ownerUserId: 'owner-1',
|
||||||
|
sourceSessionId: 'session-1',
|
||||||
|
themeText: '森林茶馆',
|
||||||
|
workTitle: '森林茶馆跳一跳',
|
||||||
|
workDescription: '森林茶馆主题',
|
||||||
|
themeTags: ['森林茶馆', '跳一跳'],
|
||||||
|
difficulty: 'standard',
|
||||||
|
stylePreset: 'minimal-blocks',
|
||||||
|
coverImageSrc: null,
|
||||||
|
publicationStatus: 'published',
|
||||||
|
playCount: 0,
|
||||||
|
updatedAt: '2026-06-05T00:00:00Z',
|
||||||
|
publishedAt: '2026-06-05T00:00:00Z',
|
||||||
|
publishReady: true,
|
||||||
|
generationStatus: 'ready',
|
||||||
|
draft,
|
||||||
|
path: draft.path,
|
||||||
|
defaultCharacter: null,
|
||||||
|
characterAsset,
|
||||||
|
tileAtlasAsset: characterAsset,
|
||||||
|
tileAssets: [],
|
||||||
|
backButtonAsset,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { jumpHopClient } = await import('./jumpHopClient');
|
||||||
|
const response = await jumpHopClient.getWorkDetail('profile-1');
|
||||||
|
|
||||||
|
expect(response.item.backButtonAsset).toEqual(backButtonAsset);
|
||||||
|
});
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ function normalizeJumpHopWorkProfile(
|
|||||||
characterAsset: flattened.characterAsset,
|
characterAsset: flattened.characterAsset,
|
||||||
tileAtlasAsset: flattened.tileAtlasAsset,
|
tileAtlasAsset: flattened.tileAtlasAsset,
|
||||||
tileAssets: flattened.tileAssets,
|
tileAssets: flattened.tileAssets,
|
||||||
|
backButtonAsset:
|
||||||
|
flattened.backButtonAsset ?? flattened.draft?.backButtonAsset ?? null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user