2419 lines
88 KiB
Python
2419 lines
88 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate the Cocos Creator 3.8 Stage 1 project assets.
|
|
|
|
All layout numbers come from source_export/stage1_world_camera_source.json.
|
|
Stage 1B land nodes also read source_export/stage1_visible_lands_source.json.
|
|
Stage 1C empty-land interaction nodes read
|
|
source_export/stage1_land_interaction_source.json.
|
|
Stage 1D top HUD nodes read source_export/stage1_top_hud_source.json.
|
|
The script writes Cocos Creator assets under CocosFarm/assets and leaves
|
|
Creator cache folders alone so the reconstruction remains reproducible.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import json
|
|
import shutil
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
from PIL import Image
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
PROJECT = ROOT / "CocosFarm"
|
|
ASSETS = PROJECT / "assets"
|
|
SPINE_DIR = ASSETS / "spine" / "stage1"
|
|
SOURCE_JSON = ROOT / "source_export" / "stage1_world_camera_source.json"
|
|
LAND_SOURCE_JSON = ROOT / "source_export" / "stage1_visible_lands_source.json"
|
|
INTERACTION_SOURCE_JSON = ROOT / "source_export" / "stage1_land_interaction_source.json"
|
|
DECOR_SOURCE_JSON = ROOT / "source_export" / "stage1_scene_decor_source.json"
|
|
TOP_HUD_SOURCE_JSON = ROOT / "source_export" / "stage1_top_hud_source.json"
|
|
RULES_PATH = ROOT / "source_export" / "cocos_creator38_conversion_rules.md"
|
|
SCENE_TEMPLATE = Path(
|
|
"/Applications/Cocos/Creator/3.8.8/CocosCreator.app/Contents/Resources/"
|
|
"resources/3d/engine/editor/assets/default_file_content/scene/scene-2d.scene"
|
|
)
|
|
|
|
SCENE_UUID = "02bb8b9c-d1f7-40d3-b9d3-3568d015c285"
|
|
SOURCE_WORLD_LAYER = 1073741824
|
|
SOURCE_UI_LAYER = 33554432
|
|
CAMERA_VISIBILITY = 1083179010
|
|
NAMESPACE = uuid.UUID("4799205f-8960-4807-a28e-9e32ad821936")
|
|
COCOS_BASE64_KEYS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
|
|
|
|
def stable_uuid(name: str) -> str:
|
|
return str(uuid.uuid5(NAMESPACE, f"stage1-world-camera:{name}"))
|
|
|
|
|
|
def compress_uuid(uuid_text: str) -> str:
|
|
hex_text = uuid_text.replace("-", "")
|
|
result = hex_text[:5]
|
|
index = 5
|
|
while index < len(hex_text):
|
|
first = int(hex_text[index], 16)
|
|
second = int(hex_text[index + 1], 16) if index + 1 < len(hex_text) else 0
|
|
third = int(hex_text[index + 2], 16) if index + 2 < len(hex_text) else 0
|
|
result += COCOS_BASE64_KEYS[(first << 2) | (second >> 2)]
|
|
result += COCOS_BASE64_KEYS[((second & 3) << 4) | third]
|
|
index += 3
|
|
return result
|
|
|
|
|
|
def script_class_id(relative_asset_path: str) -> str:
|
|
return compress_uuid(stable_uuid(f"script:assets/{relative_asset_path}"))
|
|
|
|
|
|
def read_json(path: Path) -> dict | list:
|
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
|
|
|
|
def write_json(path: Path, data: dict | list) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
|
|
|
|
def write_text(path: Path, text: str) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(text, encoding="utf-8")
|
|
|
|
|
|
def ensure_directory_meta(path: Path) -> None:
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
if path == ASSETS:
|
|
return
|
|
meta = {
|
|
"ver": "1.2.0",
|
|
"importer": "directory",
|
|
"imported": True,
|
|
"uuid": stable_uuid(f"dir:{path.relative_to(PROJECT)}"),
|
|
"files": [],
|
|
"subMetas": {},
|
|
"userData": {"compressionType": {}, "isRemoteBundle": {}},
|
|
}
|
|
write_json(path.with_suffix(path.suffix + ".meta"), meta)
|
|
|
|
|
|
def vec2(x: float, y: float) -> dict:
|
|
return {"__type__": "cc.Vec2", "x": x, "y": y}
|
|
|
|
|
|
def vec3(x: float, y: float, z: float) -> dict:
|
|
return {"__type__": "cc.Vec3", "x": x, "y": y, "z": z}
|
|
|
|
|
|
def quat_identity() -> dict:
|
|
return {"__type__": "cc.Quat", "x": 0, "y": 0, "z": 0, "w": 1}
|
|
|
|
|
|
def color(r: int, g: int, b: int, a: int) -> dict:
|
|
return {"__type__": "cc.Color", "r": r, "g": g, "b": b, "a": a}
|
|
|
|
|
|
def size(width: float, height: float) -> dict:
|
|
return {"__type__": "cc.Size", "width": width, "height": height}
|
|
|
|
|
|
def ref(index: int) -> dict:
|
|
return {"__id__": index}
|
|
|
|
|
|
def uuid_ref(asset_uuid: str, expected_type: str | None = None) -> dict:
|
|
result = {"__uuid__": asset_uuid}
|
|
if expected_type:
|
|
result["__expectedType__"] = expected_type
|
|
return result
|
|
|
|
|
|
def node(
|
|
name: str,
|
|
parent: int | None,
|
|
children: list[int],
|
|
components: list[int],
|
|
position: dict,
|
|
active: bool = True,
|
|
layer: int = SOURCE_WORLD_LAYER,
|
|
id_key: str | None = None,
|
|
) -> dict:
|
|
return {
|
|
"__type__": "cc.Node",
|
|
"_name": name,
|
|
"_objFlags": 0,
|
|
"_parent": None if parent is None else ref(parent),
|
|
"_children": [ref(item) for item in children],
|
|
"_active": active,
|
|
"_components": [ref(item) for item in components],
|
|
"_prefab": None,
|
|
"_lpos": position,
|
|
"_lrot": quat_identity(),
|
|
"_lscale": vec3(1, 1, 1),
|
|
"_layer": layer,
|
|
"_euler": vec3(0, 0, 0),
|
|
"_id": stable_uuid(f"node:{id_key or name}:{position['x']}:{position['y']}:{position['z']}"),
|
|
}
|
|
|
|
|
|
def ui_transform(node_index: int, width: float, height: float, anchor_x: float = 0.5, anchor_y: float = 0.5) -> dict:
|
|
return {
|
|
"__type__": "cc.UITransform",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_priority": 0,
|
|
"_contentSize": size(width, height),
|
|
"_anchorPoint": vec2(anchor_x, anchor_y),
|
|
"_id": stable_uuid(f"uitransform:{node_index}:{width}:{height}:{anchor_x}:{anchor_y}"),
|
|
}
|
|
|
|
|
|
def camera_component(
|
|
node_index: int,
|
|
source_camera: dict,
|
|
*,
|
|
priority: int | None = None,
|
|
clear_flags: int | None = None,
|
|
component_id: str = "component:main-camera",
|
|
) -> dict:
|
|
return {
|
|
"__type__": "cc.Camera",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_projection": int(source_camera["projection"]),
|
|
"_priority": int(source_camera.get("priority", priority if priority is not None else 0)),
|
|
"_fov": 45,
|
|
"_fovAxis": 0,
|
|
"_orthoHeight": float(source_camera["orthographicHeight"]),
|
|
"_near": float(source_camera["near"]),
|
|
"_far": float(source_camera["far"]),
|
|
"_color": color(0, 0, 0, 255),
|
|
"_depth": 1,
|
|
"_stencil": 0,
|
|
"_clearFlags": int(source_camera.get("clearFlags", clear_flags if clear_flags is not None else 7)),
|
|
"_rect": {"__type__": "cc.Rect", "x": 0, "y": 0, "width": 1, "height": 1},
|
|
"_aperture": 19,
|
|
"_shutter": 7,
|
|
"_iso": 0,
|
|
"_screenScale": 1,
|
|
"_visibility": int(source_camera["visibility"]),
|
|
"_targetTexture": None,
|
|
"_id": stable_uuid(component_id),
|
|
}
|
|
|
|
|
|
def canvas_component(node_index: int, camera_index: int) -> dict:
|
|
return {
|
|
"__type__": "cc.Canvas",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_cameraComponent": ref(camera_index),
|
|
"_alignCanvasWithScreen": True,
|
|
"_id": stable_uuid("component:canvas"),
|
|
}
|
|
|
|
|
|
def widget_component(node_index: int) -> dict:
|
|
return {
|
|
"__type__": "cc.Widget",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_alignFlags": 45,
|
|
"_target": None,
|
|
"_left": 0,
|
|
"_right": 0,
|
|
"_top": 0,
|
|
"_bottom": 0,
|
|
"_horizontalCenter": 0,
|
|
"_verticalCenter": 0,
|
|
"_isAbsLeft": True,
|
|
"_isAbsRight": True,
|
|
"_isAbsTop": True,
|
|
"_isAbsBottom": True,
|
|
"_isAbsHorizontalCenter": True,
|
|
"_isAbsVerticalCenter": True,
|
|
"_originalWidth": 0,
|
|
"_originalHeight": 0,
|
|
"_alignMode": 2,
|
|
"_lockFlags": 0,
|
|
"_id": stable_uuid("component:root-widget"),
|
|
}
|
|
|
|
|
|
def source_widget_component(node_index: int, widget_source: dict, id_key: str) -> dict:
|
|
# Cocos compact scenes omit fields that equal engine defaults. Widget's
|
|
# omitted `_alignMode` defaults to ON_WINDOW_RESIZE in Cocos Creator 3.8.
|
|
return {
|
|
"__type__": "cc.Widget",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_alignFlags": int(widget_source["alignFlags"]),
|
|
"_target": None,
|
|
"_left": float(widget_source.get("left") or 0),
|
|
"_right": float(widget_source.get("right") or 0),
|
|
"_top": float(widget_source.get("top") or 0),
|
|
"_bottom": float(widget_source.get("bottom") or 0),
|
|
"_horizontalCenter": 0,
|
|
"_verticalCenter": 0,
|
|
"_isAbsLeft": bool(widget_source.get("isAbsLeft", True)),
|
|
"_isAbsRight": bool(widget_source.get("isAbsRight", True)),
|
|
"_isAbsTop": bool(widget_source.get("isAbsTop", True)),
|
|
"_isAbsBottom": bool(widget_source.get("isAbsBottom", True)),
|
|
"_isAbsHorizontalCenter": bool(widget_source.get("isAbsHorizontalCenter", True)),
|
|
"_isAbsVerticalCenter": bool(widget_source.get("isAbsVerticalCenter", True)),
|
|
"_originalWidth": float(widget_source.get("originalWidth") or 0),
|
|
"_originalHeight": float(widget_source.get("originalHeight") or 0),
|
|
"_alignMode": int(widget_source.get("alignMode", 2)),
|
|
"_lockFlags": 0,
|
|
"_id": stable_uuid(f"widget:{id_key}:{widget_source['alignFlags']}:{widget_source.get('sourceTemplate')}"),
|
|
}
|
|
|
|
|
|
def sprite_component(
|
|
node_index: int,
|
|
sprite_frame_uuid: str,
|
|
sprite_type: int = 0,
|
|
size_mode: int = 0,
|
|
) -> dict:
|
|
return {
|
|
"__type__": "cc.Sprite",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"_srcBlendFactor": 2,
|
|
"_dstBlendFactor": 4,
|
|
"_color": color(255, 255, 255, 255),
|
|
"_sharedMaterial": None,
|
|
"_spriteFrame": {"__uuid__": sprite_frame_uuid},
|
|
"_type": sprite_type,
|
|
"_fillType": 0,
|
|
"_sizeMode": size_mode,
|
|
"_fillCenter": vec2(0, 0),
|
|
"_fillStart": 0,
|
|
"_fillRange": 0,
|
|
"_isTrimmedMode": True,
|
|
"_useGrayscale": False,
|
|
"_atlas": None,
|
|
"_id": stable_uuid(f"component:sprite:{node_index}:{sprite_frame_uuid}"),
|
|
}
|
|
|
|
|
|
def uint32_to_color(value: int) -> dict:
|
|
# Cocos compact JSON stores label colors in the same packed order as Color.toUint32.
|
|
return color(value & 255, (value >> 8) & 255, (value >> 16) & 255, (value >> 24) & 255)
|
|
|
|
|
|
def label_component(node_index: int, label: dict) -> dict:
|
|
return {
|
|
"__type__": "cc.Label",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_customMaterial": None,
|
|
"_srcBlendFactor": 2,
|
|
"_dstBlendFactor": 4,
|
|
"_color": uint32_to_color(int(label["colorUint32"])),
|
|
"_string": str(label["string"]),
|
|
"_horizontalAlign": int(label.get("horizontalAlign", 1)),
|
|
"_verticalAlign": int(label.get("verticalAlign", 1)),
|
|
"_actualFontSize": float(label["actualFontSize"]),
|
|
"_fontSize": float(label["fontSize"]),
|
|
"_fontFamily": "Arial",
|
|
"_lineHeight": float(label["lineHeight"]),
|
|
"_overflow": int(label.get("overflow", 0)),
|
|
"_enableWrapText": bool(label.get("enableWrapText", True)),
|
|
"_font": None,
|
|
"_isSystemFontUsed": True,
|
|
"_spacingX": 0,
|
|
"_isBold": bool(label["bold"]),
|
|
"_isItalic": False,
|
|
"_isUnderline": False,
|
|
"_underlineHeight": 2,
|
|
"_cacheMode": 0,
|
|
"_id": stable_uuid(f"component:label:{node_index}:{label['string']}"),
|
|
}
|
|
|
|
|
|
def mask_component(node_index: int, mask: dict) -> dict:
|
|
return {
|
|
"__type__": "cc.Mask",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"_srcBlendFactor": 2,
|
|
"_dstBlendFactor": 4,
|
|
"_color": color(255, 255, 255, 255),
|
|
"_sharedMaterial": None,
|
|
"_type": int(mask["type"]),
|
|
"_segments": int(mask["segments"]),
|
|
"_id": stable_uuid(f"component:mask:{node_index}:{mask['type']}:{mask['segments']}"),
|
|
"__prefab": None,
|
|
}
|
|
|
|
|
|
def graphics_component(node_index: int, graphics: dict) -> dict:
|
|
fill = uint32_to_color(int(graphics["fillColorUint32"]))
|
|
return {
|
|
"__type__": "cc.Graphics",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_visFlags": 0,
|
|
"_customMaterial": None,
|
|
"_srcBlendFactor": 2,
|
|
"_dstBlendFactor": 4,
|
|
"_color": color(255, 255, 255, 255),
|
|
"_lineWidth": 1,
|
|
"_strokeColor": color(0, 0, 0, 255),
|
|
"_lineJoin": 2,
|
|
"_lineCap": 0,
|
|
"_fillColor": fill,
|
|
"_miterLimit": 10,
|
|
"_id": stable_uuid(f"component:graphics:{node_index}:{graphics['fillColorUint32']}"),
|
|
}
|
|
|
|
|
|
def progress_bar_component(node_index: int, progress_bar: dict, progress: float) -> dict:
|
|
return {
|
|
"__type__": "cc.ProgressBar",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"_barSprite": None,
|
|
"_mode": 0,
|
|
"_totalLength": float(progress_bar["totalLength"]),
|
|
"_progress": float(progress),
|
|
"_reverse": False,
|
|
"_id": stable_uuid(f"component:progress-bar:{node_index}:{progress_bar['totalLength']}"),
|
|
"__prefab": None,
|
|
}
|
|
|
|
|
|
def layout_component(node_index: int, layout: dict) -> dict:
|
|
return {
|
|
"__type__": "cc.Layout",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_resizeMode": int(layout.get("resizeMode", 0)),
|
|
"_layoutType": int(layout.get("layoutType", 0)),
|
|
"_cellSize": size(40, 40),
|
|
"_startAxis": 0,
|
|
"_paddingLeft": float(layout.get("paddingLeft", 0)),
|
|
"_paddingRight": float(layout.get("paddingRight", 0)),
|
|
"_paddingTop": float(layout.get("paddingTop", 0)),
|
|
"_paddingBottom": float(layout.get("paddingBottom", 0)),
|
|
"_spacingX": float(layout.get("spacingX", 0)),
|
|
"_spacingY": 0,
|
|
"_verticalDirection": 1,
|
|
"_horizontalDirection": int(layout.get("horizontalDirection", 0)),
|
|
"_constraint": 0,
|
|
"_constraintNum": 2,
|
|
"_affectedByScale": bool(layout.get("affectedByScale", False)),
|
|
"_isAlign": bool(layout.get("isAlign", False)),
|
|
"_id": stable_uuid(f"component:layout:{node_index}:{layout.get('sourceNode', '')}"),
|
|
}
|
|
|
|
|
|
def stage1_land_interaction_component(node_index: int) -> dict:
|
|
return {
|
|
"__type__": script_class_id("scripts/stage1/Stage1LandInteraction.ts"),
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_id": stable_uuid("component:stage1-land-interaction"),
|
|
}
|
|
|
|
|
|
def stage1_world_camera_component(node_index: int, camera_component_index: int) -> dict:
|
|
return {
|
|
"__type__": script_class_id("scripts/stage1/Stage1WorldCamera.ts"),
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"mainCamera": ref(camera_component_index),
|
|
"_id": stable_uuid("component:stage1-world-camera"),
|
|
}
|
|
|
|
|
|
def stage1_top_hud_component(node_index: int) -> dict:
|
|
return {
|
|
"__type__": script_class_id("scripts/stage1/Stage1TopHud.ts"),
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_id": stable_uuid("component:stage1-top-hud"),
|
|
}
|
|
|
|
|
|
def stage1_ui_camera_viewport_component(node_index: int) -> dict:
|
|
return {
|
|
"__type__": script_class_id("scripts/stage1/Stage1UiCameraViewport.ts"),
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_id": stable_uuid("component:stage1-ui-camera-viewport"),
|
|
}
|
|
|
|
|
|
def scene_land_spine_uuids() -> dict[str, str]:
|
|
return {
|
|
"skeletonDataUuid": stable_uuid("spine:scene_land.json"),
|
|
"atlasUuid": stable_uuid("spine:scene_land.atlas"),
|
|
"imageUuid": stable_uuid("spine:scene_land.png"),
|
|
}
|
|
|
|
|
|
def decor_spine_uuids(asset_id: str) -> dict[str, str]:
|
|
return {
|
|
"skeletonDataUuid": stable_uuid(f"spine:{asset_id}.skel"),
|
|
"atlasUuid": stable_uuid(f"spine:{asset_id}.atlas"),
|
|
"imageUuid": stable_uuid(f"spine:{asset_id}.png"),
|
|
}
|
|
|
|
|
|
def spine_skeleton_component(node_index: int, skeleton_data_uuid: str, default_skin: str, default_animation: str) -> dict:
|
|
return {
|
|
"__type__": "sp.Skeleton",
|
|
"_name": "",
|
|
"_objFlags": 0,
|
|
"node": ref(node_index),
|
|
"_enabled": True,
|
|
"__prefab": None,
|
|
"_materials": [],
|
|
"_srcBlendFactor": 2,
|
|
"_dstBlendFactor": 4,
|
|
"_color": color(255, 255, 255, 255),
|
|
"_skeletonData": uuid_ref(skeleton_data_uuid, "sp.SkeletonData"),
|
|
"defaultSkin": default_skin,
|
|
"defaultAnimation": default_animation,
|
|
"_premultipliedAlpha": True,
|
|
"loop": False,
|
|
"_timeScale": 1,
|
|
"_preCacheMode": 1,
|
|
"_cacheMode": 1,
|
|
"_sockets": [],
|
|
"_useTint": False,
|
|
"_debugMesh": False,
|
|
"_debugBones": False,
|
|
"_debugSlots": False,
|
|
"_enableBatch": True,
|
|
"_id": stable_uuid(f"component:spine-skeleton:{node_index}:{default_skin}:{default_animation}"),
|
|
}
|
|
|
|
|
|
def remap_ids(value: object, mapping: dict[int, int]) -> object:
|
|
if isinstance(value, dict):
|
|
if set(value.keys()) == {"__id__"} and value["__id__"] in mapping:
|
|
return {"__id__": mapping[value["__id__"]]}
|
|
return {key: remap_ids(item, mapping) for key, item in value.items()}
|
|
if isinstance(value, list):
|
|
return [remap_ids(item, mapping) for item in value]
|
|
return value
|
|
|
|
|
|
def image_meta(name: str, image_uuid: str, width: int, height: int, sprite_frame: dict | None = None) -> dict:
|
|
texture_uuid = f"{image_uuid}@6c48a"
|
|
sprite_uuid = f"{image_uuid}@f9941"
|
|
if sprite_frame:
|
|
frame_rect = sprite_frame["rect"]
|
|
original_size = sprite_frame["originalSize"]
|
|
offset = sprite_frame.get("offset", {"x": 0, "y": 0})
|
|
pivot = sprite_frame.get("pivot", {"x": 0.5, "y": 0.5})
|
|
cap = sprite_frame.get("capInsets", [0, 0, 0, 0])
|
|
frame_width = int(frame_rect["width"])
|
|
frame_height = int(frame_rect["height"])
|
|
raw_width = int(original_size["width"])
|
|
raw_height = int(original_size["height"])
|
|
else:
|
|
offset = {"x": 0, "y": 0}
|
|
pivot = {"x": 0.5, "y": 0.5}
|
|
cap = [0, 0, 0, 0]
|
|
frame_width = width
|
|
frame_height = height
|
|
raw_width = width
|
|
raw_height = height
|
|
return {
|
|
"ver": "1.0.27",
|
|
"importer": "image",
|
|
"imported": True,
|
|
"uuid": image_uuid,
|
|
"files": [".json", ".png"],
|
|
"subMetas": {
|
|
"6c48a": {
|
|
"ver": "1.0.22",
|
|
"importer": "texture",
|
|
"uuid": texture_uuid,
|
|
"imported": True,
|
|
"files": [".json"],
|
|
"subMetas": {},
|
|
"userData": {
|
|
"wrapModeS": "clamp-to-edge",
|
|
"wrapModeT": "clamp-to-edge",
|
|
"minfilter": "linear",
|
|
"magfilter": "linear",
|
|
"mipfilter": "none",
|
|
"premultiplyAlpha": False,
|
|
"anisotropy": 0,
|
|
"isUuid": True,
|
|
"imageUuidOrDatabaseUri": image_uuid,
|
|
"visible": False,
|
|
},
|
|
"displayName": name,
|
|
"id": "6c48a",
|
|
"name": "texture",
|
|
},
|
|
"f9941": {
|
|
"ver": "1.0.12",
|
|
"importer": "sprite-frame",
|
|
"uuid": sprite_uuid,
|
|
"imported": True,
|
|
"files": [".json"],
|
|
"subMetas": {},
|
|
"userData": {
|
|
"wrapModeS": "clamp-to-edge",
|
|
"wrapModeT": "clamp-to-edge",
|
|
"minfilter": "linear",
|
|
"magfilter": "linear",
|
|
"premultiplyAlpha": False,
|
|
"generateMipmap": False,
|
|
"anisotropy": 1,
|
|
"trimType": "custom",
|
|
"trimThreshold": 1,
|
|
"rotated": False,
|
|
"offsetX": float(offset["x"]),
|
|
"offsetY": float(offset["y"]),
|
|
"trimX": 0,
|
|
"trimY": 0,
|
|
"width": frame_width,
|
|
"height": frame_height,
|
|
"rawWidth": raw_width,
|
|
"rawHeight": raw_height,
|
|
"borderTop": int(cap[0]),
|
|
"borderBottom": int(cap[2]),
|
|
"borderLeft": int(cap[3]),
|
|
"borderRight": int(cap[1]),
|
|
"isUuid": True,
|
|
"imageUuidOrDatabaseUri": texture_uuid,
|
|
"atlasUuid": "",
|
|
"mipfilter": "none",
|
|
"packable": True,
|
|
"vertices": {
|
|
"rawPosition": [
|
|
-frame_width / 2,
|
|
-frame_height / 2,
|
|
0,
|
|
frame_width / 2,
|
|
-frame_height / 2,
|
|
0,
|
|
-frame_width / 2,
|
|
frame_height / 2,
|
|
0,
|
|
frame_width / 2,
|
|
frame_height / 2,
|
|
0,
|
|
],
|
|
"indexes": [0, 1, 2, 2, 1, 3],
|
|
"uv": [0, frame_height, frame_width, frame_height, 0, 0, frame_width, 0],
|
|
"nuv": [0, 0, 1, 0, 0, 1, 1, 1],
|
|
"minPos": [-frame_width / 2, -frame_height / 2, 0],
|
|
"maxPos": [frame_width / 2, frame_height / 2, 0],
|
|
},
|
|
"pixelsToUnit": 100,
|
|
"pivotX": float(pivot["x"]),
|
|
"pivotY": float(pivot["y"]),
|
|
"meshType": 0,
|
|
},
|
|
"displayName": name,
|
|
"id": "f9941",
|
|
"name": "spriteFrame",
|
|
},
|
|
},
|
|
"userData": {
|
|
"type": "sprite-frame",
|
|
"redirect": texture_uuid,
|
|
"hasAlpha": True,
|
|
"fixAlphaTransparencyArtifacts": False,
|
|
},
|
|
}
|
|
|
|
|
|
def write_script_assets(land_evidence: dict, interaction_evidence: dict, top_hud_evidence: dict) -> None:
|
|
core_dir = ASSETS / "scripts" / "core"
|
|
stage_dir = ASSETS / "scripts" / "stage1"
|
|
mock_dir = ASSETS / "scripts" / "mock"
|
|
ensure_directory_meta(ASSETS / "scripts")
|
|
ensure_directory_meta(core_dir)
|
|
ensure_directory_meta(stage_dir)
|
|
ensure_directory_meta(mock_dir)
|
|
|
|
source_space = """export interface SourceVec2 {
|
|
x: number;
|
|
y: number;
|
|
}
|
|
|
|
export interface SourceVec3 extends SourceVec2 {
|
|
z: number;
|
|
}
|
|
|
|
export interface SourceNodeTransform {
|
|
position: SourceVec3;
|
|
scale: SourceVec3;
|
|
euler: SourceVec3;
|
|
size: SourceVec2;
|
|
pivot: SourceVec2;
|
|
}
|
|
|
|
export interface CreatorNodeTransform extends SourceNodeTransform {
|
|
layer: number;
|
|
}
|
|
|
|
export interface SourceCameraState {
|
|
position: SourceVec3;
|
|
orthographicHeight: number;
|
|
near: number;
|
|
far: number;
|
|
visibility: number;
|
|
}
|
|
|
|
export const SOURCE_DESIGN_WIDTH = 720;
|
|
export const SOURCE_DESIGN_HEIGHT = 1280;
|
|
export const SOURCE_WORLD_LAYER = 1073741824;
|
|
export const SOURCE_CAMERA_VISIBILITY = 1083179010;
|
|
export const SOURCE_CAMERA_ORTHO_HEIGHT = 640;
|
|
export const SOURCE_CAMERA_MIN_ZOOM = 0.8;
|
|
export const SOURCE_CAMERA_MAX_ZOOM = 2.4;
|
|
export const SOURCE_CAMERA_MAX_VISIBLE_WIDTH = 2300;
|
|
|
|
export function sourceCameraInitialZoom(): number {
|
|
return SOURCE_CAMERA_MIN_ZOOM;
|
|
}
|
|
|
|
export function sourceCameraInitialOrthoHeight(): number {
|
|
return SOURCE_CAMERA_ORTHO_HEIGHT / sourceCameraInitialZoom();
|
|
}
|
|
|
|
export function toCreatorNodeTransform(source: SourceNodeTransform): CreatorNodeTransform {
|
|
return {
|
|
position: { ...source.position },
|
|
scale: { ...source.scale },
|
|
euler: { ...source.euler },
|
|
size: { ...source.size },
|
|
pivot: { ...source.pivot },
|
|
layer: SOURCE_WORLD_LAYER,
|
|
};
|
|
}
|
|
|
|
export function toCreatorCameraState(source: SourceCameraState): SourceCameraState {
|
|
return {
|
|
position: { ...source.position },
|
|
orthographicHeight: source.orthographicHeight,
|
|
near: source.near,
|
|
far: source.far,
|
|
visibility: source.visibility,
|
|
};
|
|
}
|
|
"""
|
|
source_visible_land = """export interface SourceLandAssetRule {
|
|
landLevel: number;
|
|
levelName: string;
|
|
landRes: string;
|
|
landDryRes: string;
|
|
}
|
|
|
|
export interface SourceVisibleLand {
|
|
landId: number;
|
|
gridName: string;
|
|
assetId: string;
|
|
landLevel: number;
|
|
state: string;
|
|
}
|
|
|
|
export function resolveLandAssetId(rule: SourceLandAssetRule, dry: boolean): string {
|
|
const resource = dry ? rule.landDryRes : rule.landRes;
|
|
const match = resource.match(/model\\/v3\\/(.+?)\\/spriteFrame/);
|
|
return match ? match[1] : resource;
|
|
}
|
|
"""
|
|
source_land_interaction = """export interface SourceSeedMock {
|
|
seedItemId: number;
|
|
cropConfigId: number;
|
|
name: string;
|
|
assetId: string;
|
|
count: number;
|
|
bundle: string;
|
|
resource: string;
|
|
}
|
|
|
|
export interface SourceLandInteractionRule {
|
|
selectableState: string;
|
|
noResponseStates: string[];
|
|
}
|
|
"""
|
|
source_top_hud = """export interface Stage1UserMock {
|
|
nickname: string;
|
|
level: number;
|
|
exp: number;
|
|
expMax: number;
|
|
gold: number;
|
|
goldDisplay: string;
|
|
diamond: number;
|
|
avatarAssetId: string;
|
|
}
|
|
|
|
export function stage1ExpProgress(user: Stage1UserMock): number {
|
|
if (user.expMax <= 0) {
|
|
return 0;
|
|
}
|
|
return Math.max(0, Math.min(1, user.exp / user.expMax));
|
|
}
|
|
"""
|
|
stage_script = """import { _decorator, Camera, Component } from 'cc';
|
|
import { SOURCE_CAMERA_VISIBILITY, SOURCE_DESIGN_HEIGHT, SOURCE_DESIGN_WIDTH, sourceCameraInitialOrthoHeight, sourceCameraInitialZoom } from '../core/SourceSpace';
|
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
@ccclass('Stage1WorldCamera')
|
|
export class Stage1WorldCamera extends Component {
|
|
@property(Camera)
|
|
public mainCamera: Camera | null = null;
|
|
|
|
start() {
|
|
if (!this.mainCamera) {
|
|
return;
|
|
}
|
|
this.mainCamera.orthoHeight = sourceCameraInitialOrthoHeight();
|
|
this.mainCamera.visibility = SOURCE_CAMERA_VISIBILITY;
|
|
this.mainCamera.camera.update(true);
|
|
}
|
|
|
|
public sourceDesignSize() {
|
|
return {
|
|
width: SOURCE_DESIGN_WIDTH,
|
|
height: SOURCE_DESIGN_HEIGHT,
|
|
initialZoom: sourceCameraInitialZoom(),
|
|
initialOrthoHeight: sourceCameraInitialOrthoHeight(),
|
|
};
|
|
}
|
|
}
|
|
"""
|
|
ui_camera_viewport_script = """import { _decorator, Camera, Component, view } from 'cc';
|
|
import { SOURCE_DESIGN_HEIGHT } from '../core/SourceSpace';
|
|
|
|
const { ccclass } = _decorator;
|
|
|
|
@ccclass('Stage1UiCameraViewport')
|
|
export class Stage1UiCameraViewport extends Component {
|
|
private camera: Camera | null = null;
|
|
|
|
onLoad() {
|
|
this.camera = this.getComponent(Camera);
|
|
}
|
|
|
|
onEnable() {
|
|
this.syncToSourceDesignHeight();
|
|
view.on('canvas-resize', this.syncToSourceDesignHeight, this);
|
|
view.on('design-resolution-changed', this.syncToSourceDesignHeight, this);
|
|
}
|
|
|
|
start() {
|
|
this.syncToSourceDesignHeight();
|
|
}
|
|
|
|
onDisable() {
|
|
view.off('canvas-resize', this.syncToSourceDesignHeight, this);
|
|
view.off('design-resolution-changed', this.syncToSourceDesignHeight, this);
|
|
}
|
|
|
|
private syncToSourceDesignHeight() {
|
|
if (!this.camera) {
|
|
return;
|
|
}
|
|
// Keep the recovered UI camera in the source Canvas coordinate system.
|
|
this.camera.orthoHeight = SOURCE_DESIGN_HEIGHT / 2;
|
|
this.camera.camera.update(true);
|
|
}
|
|
}
|
|
"""
|
|
first_land_icon = land_evidence["visibleLands"][0]["icon"]
|
|
source_land_icon_x = float(first_land_icon["localPosition"]["x"])
|
|
source_land_icon_y = float(first_land_icon["localPosition"]["y"])
|
|
source_land_icon_width = float(first_land_icon["size"]["x"])
|
|
source_land_icon_height = float(first_land_icon["size"]["y"])
|
|
slot_layout = interaction_evidence["slotLayout"]
|
|
layout_component_evidence = slot_layout["layoutComponent"]
|
|
seed_slot_width = float(slot_layout["slotSize"]["x"])
|
|
seed_layout_spacing_x = float(layout_component_evidence["spacingX"])
|
|
seed_layout_padding_right = float(layout_component_evidence["paddingRight"])
|
|
interaction_script = """import { _decorator, Camera, Component, EventTouch, Label, Layout, Node, Sprite, UITransform, Vec3 } from 'cc';
|
|
import { STAGE1_VISIBLE_LAND_STATE } from '../mock/Stage1LandMock';
|
|
import { STAGE1_SEED_MOCK } from '../mock/Stage1SeedMock';
|
|
|
|
const { ccclass } = _decorator;
|
|
|
|
@ccclass('Stage1LandInteraction')
|
|
export class Stage1LandInteraction extends Component {
|
|
private gridOrigin: Node | null = null;
|
|
private uiRoot: Node | null = null;
|
|
private interactionRoot: Node | null = null;
|
|
private mainCamera: Camera | null = null;
|
|
private uiCamera: Camera | null = null;
|
|
private readonly selectableState = 'unlocked_normal';
|
|
private readonly sourceLandIconX = __SOURCE_LAND_ICON_X__;
|
|
private readonly sourceLandIconY = __SOURCE_LAND_ICON_Y__;
|
|
private readonly sourceLandIconWidth = __SOURCE_LAND_ICON_WIDTH__;
|
|
private readonly sourceLandIconHeight = __SOURCE_LAND_ICON_HEIGHT__;
|
|
private readonly seedSlotWidth = __SEED_SLOT_WIDTH__;
|
|
private readonly seedLayoutSpacingX = __SEED_LAYOUT_SPACING_X__;
|
|
private readonly seedLayoutPaddingRight = __SEED_LAYOUT_PADDING_RIGHT__;
|
|
|
|
start() {
|
|
this.gridOrigin = this.findDescendant(this.node, 'GridOrigin');
|
|
this.uiRoot = this.findDescendant(this.node, 'ui');
|
|
this.interactionRoot = this.findDescendant(this.node, 'plant_interactive_v2');
|
|
this.mainCamera = this.findDescendant(this.node, 'Camera')?.getComponent(Camera) ?? null;
|
|
this.uiCamera = this.findDescendant(this.node, 'uiCamera')?.getComponent(Camera) ?? null;
|
|
if (!this.gridOrigin || !this.uiRoot || !this.interactionRoot || !this.mainCamera || !this.uiCamera) {
|
|
return;
|
|
}
|
|
|
|
this.interactionRoot.active = false;
|
|
this.bindSeedMock();
|
|
this.mountLandDetailBubble();
|
|
this.setSelectedLandVisual(false);
|
|
this.node.off(Node.EventType.TOUCH_END, this.onRootTouchEnd, this);
|
|
this.node.on(Node.EventType.TOUCH_END, this.onRootTouchEnd, this);
|
|
|
|
for (const land of STAGE1_VISIBLE_LAND_STATE) {
|
|
const grid = this.gridOrigin.getChildByName(land.gridName);
|
|
if (!grid) {
|
|
continue;
|
|
}
|
|
grid.off(Node.EventType.TOUCH_END);
|
|
grid.on(Node.EventType.TOUCH_END, (event: EventTouch) => {
|
|
this.onLandClick(land.gridName, event);
|
|
}, this);
|
|
}
|
|
}
|
|
|
|
private onLandClick(gridName: string, event: EventTouch) {
|
|
const resolvedGridName = this.resolveGridNameFromTouch(event, true);
|
|
if (!resolvedGridName) {
|
|
return;
|
|
}
|
|
const land = STAGE1_VISIBLE_LAND_STATE.find((item) => item.gridName === resolvedGridName);
|
|
if (!land || land.state !== this.selectableState || !this.gridOrigin || !this.interactionRoot) {
|
|
return;
|
|
}
|
|
event.propagationStopped = true;
|
|
|
|
const grid = this.gridOrigin.getChildByName(resolvedGridName);
|
|
if (!grid) {
|
|
return;
|
|
}
|
|
|
|
const targetPosition = this.gridIconPosition(grid);
|
|
this.interactionRoot.setPosition(0, 0, 0);
|
|
this.applySourceTargetPositions(targetPosition);
|
|
this.interactionRoot.active = true;
|
|
this.setSelectedLandVisual(true);
|
|
|
|
const mountedLandBubble = this.landBubbleNode();
|
|
if (mountedLandBubble) {
|
|
mountedLandBubble.active = true;
|
|
}
|
|
}
|
|
|
|
private onRootTouchEnd(event: EventTouch) {
|
|
if (!this.interactionRoot?.active) {
|
|
return;
|
|
}
|
|
if (this.resolveGridNameFromTouch(event, true)) {
|
|
return;
|
|
}
|
|
if (this.isTouchInsideInteraction(event)) {
|
|
return;
|
|
}
|
|
this.hideInteraction();
|
|
}
|
|
|
|
private hideInteraction() {
|
|
if (!this.interactionRoot) {
|
|
return;
|
|
}
|
|
this.interactionRoot.active = false;
|
|
this.setSelectedLandVisual(false);
|
|
const mountedLandBubble = this.landBubbleNode();
|
|
if (mountedLandBubble) {
|
|
mountedLandBubble.active = false;
|
|
}
|
|
}
|
|
|
|
private applySourceTargetPositions(targetPosition: Vec3) {
|
|
if (!this.interactionRoot) {
|
|
return;
|
|
}
|
|
const activeSeedCount = this.activeSeedCount();
|
|
const followNode = this.findByPath(this.interactionRoot, 'followNode');
|
|
const landTarget = this.findByPath(this.interactionRoot, 'landTarget');
|
|
const guideNode = this.findByPath(this.interactionRoot, 'guide');
|
|
const followPosition = targetPosition.clone();
|
|
|
|
if (activeSeedCount > 3) {
|
|
followPosition.x = 0;
|
|
}
|
|
if (followNode) {
|
|
followNode.setPosition(followPosition);
|
|
}
|
|
if (landTarget) {
|
|
landTarget.setPosition(targetPosition);
|
|
}
|
|
if (guideNode) {
|
|
guideNode.setPosition(targetPosition);
|
|
}
|
|
}
|
|
|
|
private activeSeedCount(): number {
|
|
if (!this.interactionRoot) {
|
|
return STAGE1_SEED_MOCK.length;
|
|
}
|
|
const group = this.findByPath(this.interactionRoot, 'followNode/seedGroup/group_5');
|
|
if (!group) {
|
|
return STAGE1_SEED_MOCK.length;
|
|
}
|
|
return group.children.filter((child) => child.active && /^node\d+$/.test(child.name)).length;
|
|
}
|
|
|
|
private resolveGridNameFromTouch(event: EventTouch, requireInsideIcon: boolean): string | null {
|
|
if (!this.gridOrigin) {
|
|
return null;
|
|
}
|
|
const location = event.getUILocation();
|
|
const halfWidth = this.sourceLandIconWidth / 2;
|
|
const halfHeight = this.sourceLandIconHeight / 2;
|
|
let bestGridName: string | null = null;
|
|
let bestScore = Number.POSITIVE_INFINITY;
|
|
|
|
for (const land of STAGE1_VISIBLE_LAND_STATE) {
|
|
const grid = this.gridOrigin.getChildByName(land.gridName);
|
|
const icon = grid?.getChildByName('icon');
|
|
if (!grid || !icon) {
|
|
continue;
|
|
}
|
|
const center = icon.worldPosition;
|
|
const dx = Math.abs(location.x - center.x);
|
|
const dy = Math.abs(location.y - center.y);
|
|
const insideIcon = dx <= halfWidth && dy <= halfHeight;
|
|
if (requireInsideIcon && !insideIcon) {
|
|
continue;
|
|
}
|
|
const score = dx / halfWidth + dy / halfHeight;
|
|
if (score < bestScore) {
|
|
bestScore = score;
|
|
bestGridName = land.gridName;
|
|
}
|
|
}
|
|
return bestGridName;
|
|
}
|
|
|
|
private gridIconPosition(grid: Node): Vec3 {
|
|
const icon = grid.getChildByName('icon');
|
|
if (icon && this.mainCamera && this.uiCamera && this.interactionRoot?.parent) {
|
|
const screenPosition = this.mainCamera.worldToScreen(icon.worldPosition, new Vec3());
|
|
const uiWorldPosition = this.uiCamera.screenToWorld(screenPosition, new Vec3());
|
|
const parentTransform = this.interactionRoot.parent.getComponent(UITransform);
|
|
if (parentTransform) {
|
|
return parentTransform.convertToNodeSpaceAR(uiWorldPosition);
|
|
}
|
|
return uiWorldPosition;
|
|
}
|
|
const iconPosition = icon ? icon.position : new Vec3(this.sourceLandIconX, this.sourceLandIconY, 0);
|
|
return new Vec3(grid.position.x + iconPosition.x, grid.position.y + iconPosition.y, 0);
|
|
}
|
|
|
|
private setSelectedLandVisual(active: boolean) {
|
|
if (!this.interactionRoot) {
|
|
return;
|
|
}
|
|
const selected = this.findByPath(this.interactionRoot, 'landTarget/land_valid_selected');
|
|
if (selected) {
|
|
selected.active = active;
|
|
}
|
|
}
|
|
|
|
private bindSeedMock() {
|
|
if (!this.interactionRoot) {
|
|
return;
|
|
}
|
|
const group = this.findByPath(this.interactionRoot, 'followNode/seedGroup/group_5');
|
|
if (!group) {
|
|
return;
|
|
}
|
|
for (let index = 1; index <= 5; index += 1) {
|
|
const slot = group.getChildByName(`node${index}`);
|
|
if (!slot) {
|
|
continue;
|
|
}
|
|
const seed = STAGE1_SEED_MOCK[index - 1];
|
|
slot.active = !!seed;
|
|
const countLabel = this.findByPath(slot, 'count')?.getComponent(Label);
|
|
if (seed && countLabel) {
|
|
countLabel.string = String(seed.count);
|
|
}
|
|
const icon = this.findByPath(slot, 'icon');
|
|
const iconSprite = icon?.getComponent(Sprite);
|
|
if (iconSprite) {
|
|
iconSprite.enabled = !!seed;
|
|
}
|
|
}
|
|
this.updateSeedBackgroundVariant();
|
|
this.updateSeedLayout(group);
|
|
}
|
|
|
|
private mountLandDetailBubble() {
|
|
if (!this.interactionRoot) {
|
|
return;
|
|
}
|
|
const detailNode = this.findByPath(this.interactionRoot, 'followNode/detailNode');
|
|
const landBubble = this.findByPath(this.interactionRoot, 'land_detail/land');
|
|
if (detailNode && landBubble && landBubble.parent !== detailNode) {
|
|
landBubble.setParent(detailNode, false);
|
|
}
|
|
}
|
|
|
|
private landBubbleNode(): Node | null {
|
|
if (!this.interactionRoot) {
|
|
return null;
|
|
}
|
|
return this.findByPath(this.interactionRoot, 'followNode/detailNode/land')
|
|
?? this.findByPath(this.interactionRoot, 'land_detail/land');
|
|
}
|
|
|
|
private updateSeedBackgroundVariant() {
|
|
if (!this.interactionRoot) {
|
|
return;
|
|
}
|
|
const compactBg = this.findByPath(this.interactionRoot, 'followNode/seedGroup/bg_node3');
|
|
const wideBg = this.findByPath(this.interactionRoot, 'followNode/seedGroup/bg_node5');
|
|
const group = this.findByPath(this.interactionRoot, 'followNode/seedGroup/group_5');
|
|
const activeSlotCount = this.activeSeedCount();
|
|
const useWideBackground = activeSlotCount > 3;
|
|
if (compactBg) {
|
|
compactBg.active = !useWideBackground;
|
|
}
|
|
if (wideBg) {
|
|
wideBg.active = useWideBackground;
|
|
}
|
|
}
|
|
|
|
private isTouchInsideInteraction(event: EventTouch): boolean {
|
|
if (!this.interactionRoot) {
|
|
return false;
|
|
}
|
|
for (const path of ['followNode/detailNode/land', 'land_detail/land', 'followNode/seedGroup', 'landTarget/land_valid_selected']) {
|
|
const node = this.findByPath(this.interactionRoot, path);
|
|
const transform = node?.getComponent(UITransform);
|
|
if (node?.activeInHierarchy && transform?.hitTest(event.getUILocation())) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private updateSeedLayout(group: Node) {
|
|
const layout = group.getComponent(Layout);
|
|
if (layout) {
|
|
layout.updateLayout(true);
|
|
return;
|
|
}
|
|
const activeSlots = group.children.filter((child) => child.active && /^node\\d+$/.test(child.name));
|
|
const totalWidth = activeSlots.length * this.seedSlotWidth
|
|
+ Math.max(activeSlots.length - 1, 0) * this.seedLayoutSpacingX
|
|
+ this.seedLayoutPaddingRight;
|
|
const firstX = -totalWidth / 2 + this.seedSlotWidth / 2;
|
|
activeSlots.forEach((slot, index) => {
|
|
slot.setPosition(firstX + index * (this.seedSlotWidth + this.seedLayoutSpacingX), slot.position.y, slot.position.z);
|
|
});
|
|
}
|
|
|
|
private findDescendant(root: Node, name: string): Node | null {
|
|
if (root.name === name) {
|
|
return root;
|
|
}
|
|
for (const child of root.children) {
|
|
const match = this.findDescendant(child, name);
|
|
if (match) {
|
|
return match;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private findByPath(root: Node, path: string): Node | null {
|
|
return path.split('/').reduce<Node | null>((current, name) => {
|
|
return current ? current.getChildByName(name) : null;
|
|
}, root);
|
|
}
|
|
}
|
|
"""
|
|
interaction_script = (
|
|
interaction_script
|
|
.replace("__SOURCE_LAND_ICON_X__", f"{source_land_icon_x:.3f}")
|
|
.replace("__SOURCE_LAND_ICON_Y__", f"{source_land_icon_y:.3f}")
|
|
.replace("__SOURCE_LAND_ICON_WIDTH__", f"{source_land_icon_width:.3f}")
|
|
.replace("__SOURCE_LAND_ICON_HEIGHT__", f"{source_land_icon_height:.3f}")
|
|
.replace("__SEED_SLOT_WIDTH__", f"{seed_slot_width:.3f}")
|
|
.replace("__SEED_LAYOUT_SPACING_X__", f"{seed_layout_spacing_x:.3f}")
|
|
.replace("__SEED_LAYOUT_PADDING_RIGHT__", f"{seed_layout_padding_right:.3f}")
|
|
)
|
|
land_level_rules = [
|
|
{
|
|
"landLevel": item["landLevel"],
|
|
"levelName": item["levelName"],
|
|
"landRes": item["landRes"],
|
|
"landDryRes": item["landDryRes"],
|
|
}
|
|
for item in land_evidence["levelConfig"]["landLevelAssetRules"]
|
|
]
|
|
visible_land_state = [
|
|
{
|
|
"landId": item["landId"],
|
|
"gridName": item["gridName"],
|
|
"assetId": item["mockRender"]["assetId"],
|
|
"landLevel": item["mockRender"]["landLevel"],
|
|
"state": item["mockRender"]["state"],
|
|
}
|
|
for item in land_evidence["visibleLands"]
|
|
]
|
|
land_mock_script = f"""import type {{ SourceLandAssetRule, SourceVisibleLand }} from '../core/SourceVisibleLand';
|
|
|
|
export const STAGE1_LAND_LEVEL_ASSET_RULES: SourceLandAssetRule[] = {json.dumps(land_level_rules, ensure_ascii=False, indent=2)};
|
|
|
|
export const STAGE1_VISIBLE_LAND_STATE: SourceVisibleLand[] = {json.dumps(visible_land_state, ensure_ascii=False, indent=2)};
|
|
"""
|
|
seed_mock_script = f"""import type {{ SourceSeedMock }} from '../core/SourceLandInteraction';
|
|
|
|
export const STAGE1_SEED_MOCK: SourceSeedMock[] = {json.dumps(interaction_evidence["mockSeeds"], ensure_ascii=False, indent=2)};
|
|
"""
|
|
user_mock_script = f"""import type {{ Stage1UserMock }} from '../core/SourceTopHud';
|
|
|
|
export const STAGE1_USER_MOCK: Stage1UserMock = {json.dumps(top_hud_evidence["mockUser"], ensure_ascii=False, indent=2)};
|
|
"""
|
|
top_hud_script = """import { _decorator, Component, Label, Node, ProgressBar } from 'cc';
|
|
import { stage1ExpProgress } from '../core/SourceTopHud';
|
|
import { STAGE1_USER_MOCK } from '../mock/Stage1UserMock';
|
|
|
|
const { ccclass } = _decorator;
|
|
|
|
@ccclass('Stage1TopHud')
|
|
export class Stage1TopHud extends Component {
|
|
start() {
|
|
this.bindMockUser();
|
|
}
|
|
|
|
private bindMockUser() {
|
|
this.setLabel('HeadInfo/SubHeadInfo/txtName', STAGE1_USER_MOCK.nickname);
|
|
this.setLabel('HeadInfo/SubHeadInfo/txtLevel', ` ${STAGE1_USER_MOCK.level} `);
|
|
this.setLabel('HeadInfo/SubHeadInfo/txtExp', `${STAGE1_USER_MOCK.exp}/${STAGE1_USER_MOCK.expMax}`);
|
|
this.setLabel('Source/root/txtGold', STAGE1_USER_MOCK.goldDisplay);
|
|
this.setLabel('Source/root/txtDiamond', String(STAGE1_USER_MOCK.diamond));
|
|
|
|
const progress = this.findByPath(this.node, 'HeadInfo/SubHeadInfo/expBar')?.getComponent(ProgressBar);
|
|
if (progress) {
|
|
progress.progress = stage1ExpProgress(STAGE1_USER_MOCK);
|
|
}
|
|
}
|
|
|
|
private setLabel(path: string, value: string) {
|
|
const label = this.findByPath(this.node, path)?.getComponent(Label);
|
|
if (label) {
|
|
label.string = value;
|
|
}
|
|
}
|
|
|
|
private findByPath(root: Node, path: string): Node | null {
|
|
return path.split('/').reduce<Node | null>((current, name) => {
|
|
return current ? current.getChildByName(name) : null;
|
|
}, root);
|
|
}
|
|
}
|
|
"""
|
|
write_text(core_dir / "SourceSpace.ts", source_space)
|
|
write_text(core_dir / "SourceVisibleLand.ts", source_visible_land)
|
|
write_text(core_dir / "SourceLandInteraction.ts", source_land_interaction)
|
|
write_text(core_dir / "SourceTopHud.ts", source_top_hud)
|
|
write_text(stage_dir / "Stage1WorldCamera.ts", stage_script)
|
|
write_text(stage_dir / "Stage1UiCameraViewport.ts", ui_camera_viewport_script)
|
|
write_text(stage_dir / "Stage1LandInteraction.ts", interaction_script)
|
|
write_text(stage_dir / "Stage1TopHud.ts", top_hud_script)
|
|
write_text(mock_dir / "Stage1LandMock.ts", land_mock_script)
|
|
write_text(mock_dir / "Stage1SeedMock.ts", seed_mock_script)
|
|
write_text(mock_dir / "Stage1UserMock.ts", user_mock_script)
|
|
for path in [
|
|
core_dir / "SourceSpace.ts",
|
|
core_dir / "SourceVisibleLand.ts",
|
|
core_dir / "SourceLandInteraction.ts",
|
|
core_dir / "SourceTopHud.ts",
|
|
stage_dir / "Stage1WorldCamera.ts",
|
|
stage_dir / "Stage1UiCameraViewport.ts",
|
|
stage_dir / "Stage1LandInteraction.ts",
|
|
stage_dir / "Stage1TopHud.ts",
|
|
mock_dir / "Stage1LandMock.ts",
|
|
mock_dir / "Stage1SeedMock.ts",
|
|
mock_dir / "Stage1UserMock.ts",
|
|
]:
|
|
meta = {
|
|
"ver": "1.0.0",
|
|
"importer": "*",
|
|
"imported": True,
|
|
"uuid": stable_uuid(f"script:{path.relative_to(PROJECT)}"),
|
|
"files": ["", ".json"],
|
|
"subMetas": {},
|
|
"userData": {},
|
|
}
|
|
write_json(path.with_suffix(path.suffix + ".meta"), meta)
|
|
|
|
|
|
def write_config_assets(evidence: dict, land_evidence: dict, interaction_evidence: dict, decor_evidence: dict, top_hud_evidence: dict) -> None:
|
|
config_dir = ASSETS / "configs"
|
|
ensure_directory_meta(config_dir)
|
|
stage_config = copy.deepcopy(evidence)
|
|
stage_config["conversionRulesPath"] = str(RULES_PATH)
|
|
manifest = {
|
|
"module": "stage1_world_camera_visible_lands",
|
|
"sourceEvidence": "source_export/stage1_world_camera_source.json",
|
|
"landSourceEvidence": "source_export/stage1_visible_lands_source.json",
|
|
"interactionSourceEvidence": "source_export/stage1_land_interaction_source.json",
|
|
"decorSourceEvidence": "source_export/stage1_scene_decor_source.json",
|
|
"topHudSourceEvidence": "source_export/stage1_top_hud_source.json",
|
|
"conversionRules": "source_export/cocos_creator38_conversion_rules.md",
|
|
"creatorScene": "assets/scenes/stage1_world_camera.scene",
|
|
"designResolution": evidence["canvas"],
|
|
"camera": evidence["camera"],
|
|
"assets": evidence["assets"],
|
|
"landAssets": land_evidence["assets"],
|
|
"interactionAssets": interaction_evidence["assets"],
|
|
"topHudAssets": top_hud_evidence["assets"],
|
|
"decorSpineAssets": decor_evidence["decorSpineAssets"],
|
|
"decorNodes": decor_evidence["generatedNodes"],
|
|
"mockSeeds": interaction_evidence["mockSeeds"],
|
|
"mockUser": top_hud_evidence["mockUser"],
|
|
"topHudNodeCount": len(top_hud_evidence["nodes"]),
|
|
"visibleLandCount": len(land_evidence["visibleLands"]),
|
|
"excludedStaticGrid": land_evidence["excludedStaticGrid"],
|
|
"landLevelAssetRules": land_evidence["levelConfig"]["landLevelAssetRules"],
|
|
"nodes": evidence["nodes"],
|
|
"layerRule": {
|
|
"sourceCameraVisibility": evidence["camera"]["visibility"],
|
|
"sourceUiCameraVisibility": evidence["uiCamera"]["visibility"],
|
|
"creatorWorldLayer": SOURCE_WORLD_LAYER,
|
|
"creatorUiLayer": SOURCE_UI_LAYER,
|
|
"reason": "Source world camera includes bit 30 but not UI_2D; source uiCamera visibility includes UI_2D and renders interaction prefabs.",
|
|
},
|
|
}
|
|
write_json(config_dir / "stage1_world_camera.source.json", stage_config)
|
|
write_json(config_dir / "stage1_visible_lands.source.json", land_evidence)
|
|
write_json(config_dir / "stage1_land_interaction.source.json", interaction_evidence)
|
|
write_json(config_dir / "stage1_scene_decor.source.json", decor_evidence)
|
|
write_json(config_dir / "stage1_top_hud.source.json", top_hud_evidence)
|
|
write_json(config_dir / "stage1_world_camera.manifest.json", manifest)
|
|
for name in [
|
|
"stage1_world_camera.source.json",
|
|
"stage1_visible_lands.source.json",
|
|
"stage1_land_interaction.source.json",
|
|
"stage1_scene_decor.source.json",
|
|
"stage1_top_hud.source.json",
|
|
"stage1_world_camera.manifest.json",
|
|
]:
|
|
path = config_dir / name
|
|
meta = {
|
|
"ver": "1.0.0",
|
|
"importer": "json",
|
|
"imported": True,
|
|
"uuid": stable_uuid(f"json:{path.relative_to(PROJECT)}"),
|
|
"files": [".json"],
|
|
"subMetas": {},
|
|
"userData": {},
|
|
}
|
|
write_json(path.with_suffix(path.suffix + ".meta"), meta)
|
|
|
|
|
|
def write_project_settings(evidence: dict) -> None:
|
|
settings_path = PROJECT / "settings" / "v2" / "packages" / "project.json"
|
|
settings = read_json(settings_path) if settings_path.exists() else {"__version__": "1.0.6"}
|
|
settings.setdefault("general", {})
|
|
settings["general"]["designResolution"] = {
|
|
"width": int(evidence["canvas"]["width"]),
|
|
"height": int(evidence["canvas"]["height"]),
|
|
"policy": 2,
|
|
}
|
|
write_json(settings_path, settings)
|
|
|
|
builder_profile_path = PROJECT / "profiles" / "v2" / "packages" / "builder.json"
|
|
builder_profile = read_json(builder_profile_path) if builder_profile_path.exists() else {"__version__": "1.3.9"}
|
|
builder_profile["useSplashScreen"] = True
|
|
builder_profile["splashScreen"] = {
|
|
"displayRatio": 0.756,
|
|
"totalTime": 0,
|
|
"logo": {"type": "none"},
|
|
"background": {
|
|
"type": "color",
|
|
"color": {"x": 1, "y": 1, "z": 1, "w": 1},
|
|
},
|
|
"watermarkLocation": "default",
|
|
"autoFit": True,
|
|
}
|
|
write_json(builder_profile_path, builder_profile)
|
|
|
|
|
|
def write_texture_assets(evidence: dict, land_evidence: dict, interaction_evidence: dict, top_hud_evidence: dict) -> dict[str, dict]:
|
|
texture_dir = ASSETS / "textures" / "stage1"
|
|
ensure_directory_meta(ASSETS / "textures")
|
|
ensure_directory_meta(texture_dir)
|
|
by_id: dict[str, dict] = {}
|
|
scene_land_atlas = {
|
|
"id": "scene_land_atlas",
|
|
"sourcePath": land_evidence["sceneLandSkeletonData"]["atlasImagePath"],
|
|
}
|
|
for asset in [*evidence["assets"], *land_evidence["assets"], *interaction_evidence["assets"], *top_hud_evidence["assets"], scene_land_atlas]:
|
|
asset_id = asset["id"]
|
|
src = Path(asset["sourcePath"])
|
|
dst = texture_dir / f"{asset_id}.png"
|
|
shutil.copy2(src, dst)
|
|
with Image.open(dst) as image:
|
|
width, height = image.size
|
|
image_uuid = stable_uuid(f"image:{asset_id}")
|
|
write_json(
|
|
dst.with_suffix(dst.suffix + ".meta"),
|
|
image_meta(asset_id, image_uuid, width, height, asset.get("spriteFrame")),
|
|
)
|
|
by_id[asset_id] = {
|
|
"path": str(dst),
|
|
"uuid": image_uuid,
|
|
"textureUuid": f"{image_uuid}@6c48a",
|
|
"spriteFrameUuid": f"{image_uuid}@f9941",
|
|
"pixelWidth": width,
|
|
"pixelHeight": height,
|
|
}
|
|
return by_id
|
|
|
|
|
|
def write_spine_assets(land_evidence: dict) -> dict[str, str]:
|
|
scene_land = land_evidence["sceneLandSkeletonData"]
|
|
uuids = scene_land_spine_uuids()
|
|
ensure_directory_meta(ASSETS / "spine")
|
|
ensure_directory_meta(SPINE_DIR)
|
|
|
|
json_path = SPINE_DIR / "scene_land.json"
|
|
atlas_path = SPINE_DIR / "scene_land.atlas"
|
|
png_path = SPINE_DIR / "scene_land.png"
|
|
write_text(json_path, json.dumps(scene_land["skeletonJson"], ensure_ascii=False, separators=(",", ":")) + "\n")
|
|
write_text(atlas_path, scene_land["atlasText"].lstrip("\n"))
|
|
shutil.copy2(scene_land["atlasImagePath"], png_path)
|
|
|
|
with Image.open(png_path) as image:
|
|
width, height = image.size
|
|
write_json(png_path.with_suffix(png_path.suffix + ".meta"), image_meta("scene_land", uuids["imageUuid"], width, height))
|
|
write_json(
|
|
atlas_path.with_suffix(atlas_path.suffix + ".meta"),
|
|
{
|
|
"ver": "1.0.0",
|
|
"importer": "*",
|
|
"imported": True,
|
|
"uuid": uuids["atlasUuid"],
|
|
"files": [".atlas", ".json"],
|
|
"subMetas": {},
|
|
"userData": {},
|
|
},
|
|
)
|
|
write_json(
|
|
json_path.with_suffix(json_path.suffix + ".meta"),
|
|
{
|
|
"ver": "1.2.7",
|
|
"importer": "spine-data",
|
|
"imported": True,
|
|
"uuid": uuids["skeletonDataUuid"],
|
|
"files": [".json"],
|
|
"subMetas": {},
|
|
"userData": {"atlasUuid": uuids["atlasUuid"]},
|
|
},
|
|
)
|
|
return {
|
|
**uuids,
|
|
"jsonPath": str(json_path),
|
|
"atlasPath": str(atlas_path),
|
|
"pngPath": str(png_path),
|
|
"textureUuid": f"{uuids['imageUuid']}@6c48a",
|
|
}
|
|
|
|
|
|
def write_decor_spine_assets(decor_evidence: dict) -> dict[str, dict]:
|
|
ensure_directory_meta(ASSETS / "spine")
|
|
ensure_directory_meta(SPINE_DIR)
|
|
written: dict[str, dict] = {}
|
|
for asset in decor_evidence["decorSpineAssets"]:
|
|
asset_id = asset["id"]
|
|
skin_cfg_id = str(asset["skinCfgId"])
|
|
uuids = decor_spine_uuids(asset_id)
|
|
asset_dir = SPINE_DIR / asset_id
|
|
ensure_directory_meta(asset_dir)
|
|
|
|
skel_path = asset_dir / f"{skin_cfg_id}.skel"
|
|
atlas_path = asset_dir / f"{skin_cfg_id}.atlas"
|
|
png_path = asset_dir / asset["atlasImageName"]
|
|
shutil.copy2(asset["skeletonBinaryPath"], skel_path)
|
|
shutil.copy2(asset["atlasPath"], atlas_path)
|
|
shutil.copy2(asset["atlasImagePath"], png_path)
|
|
|
|
with Image.open(png_path) as image:
|
|
width, height = image.size
|
|
write_json(png_path.with_suffix(png_path.suffix + ".meta"), image_meta(asset_id, uuids["imageUuid"], width, height))
|
|
write_json(
|
|
atlas_path.with_suffix(atlas_path.suffix + ".meta"),
|
|
{
|
|
"ver": "1.0.0",
|
|
"importer": "*",
|
|
"imported": True,
|
|
"uuid": uuids["atlasUuid"],
|
|
"files": [".atlas", ".json"],
|
|
"subMetas": {},
|
|
"userData": {},
|
|
},
|
|
)
|
|
write_json(
|
|
skel_path.with_suffix(skel_path.suffix + ".meta"),
|
|
{
|
|
"ver": "1.2.7",
|
|
"importer": "spine-data",
|
|
"imported": True,
|
|
"uuid": uuids["skeletonDataUuid"],
|
|
"files": [".skel"],
|
|
"subMetas": {},
|
|
"userData": {"atlasUuid": uuids["atlasUuid"]},
|
|
},
|
|
)
|
|
written[asset_id] = {
|
|
**uuids,
|
|
"skeletonPath": str(skel_path),
|
|
"atlasPath": str(atlas_path),
|
|
"pngPath": str(png_path),
|
|
"textureUuid": f"{uuids['imageUuid']}@6c48a",
|
|
}
|
|
return written
|
|
|
|
|
|
def source_node(evidence: dict, path: str) -> dict:
|
|
for item in evidence["nodes"]:
|
|
if item["path"] == path:
|
|
return item
|
|
raise KeyError(path)
|
|
|
|
|
|
def interaction_source_node(interaction_evidence: dict, path: str) -> dict:
|
|
for item in interaction_evidence["nodes"]:
|
|
if item["path"] == path:
|
|
return item
|
|
raise KeyError(path)
|
|
|
|
|
|
def top_hud_source_node(top_hud_evidence: dict, path: str) -> dict:
|
|
for item in top_hud_evidence["nodes"]:
|
|
if item["path"] == path:
|
|
return item
|
|
raise KeyError(path)
|
|
|
|
|
|
def top_hud_mock_label(top_hud_evidence: dict, source: dict) -> dict:
|
|
label = copy.deepcopy(source["label"])
|
|
mock_user = top_hud_evidence["mockUser"]
|
|
mock_field = label.get("mockField")
|
|
if mock_field == "nickname":
|
|
label["string"] = str(mock_user["nickname"])
|
|
elif mock_field == "level":
|
|
label["string"] = f" {mock_user['level']} "
|
|
elif mock_field == "experience":
|
|
label["string"] = f"{mock_user['exp']}/{mock_user['expMax']}"
|
|
elif mock_field == "goldDisplay":
|
|
label["string"] = str(mock_user["goldDisplay"])
|
|
elif mock_field == "diamond":
|
|
label["string"] = str(mock_user["diamond"])
|
|
return label
|
|
|
|
|
|
def top_hud_mock_progress(top_hud_evidence: dict) -> float:
|
|
mock_user = top_hud_evidence["mockUser"]
|
|
exp_max = float(mock_user["expMax"])
|
|
if exp_max <= 0:
|
|
return 0.0
|
|
return max(0.0, min(1.0, float(mock_user["exp"]) / exp_max))
|
|
|
|
|
|
def add_generated_node(
|
|
objects: list[dict],
|
|
name: str,
|
|
parent_index: int,
|
|
source: dict,
|
|
textures: dict[str, dict],
|
|
id_key: str,
|
|
sprite_type: int = 0,
|
|
layer: int = SOURCE_WORLD_LAYER,
|
|
label_override: dict | None = None,
|
|
) -> int:
|
|
node_index = len(objects)
|
|
position = source["localPosition"]
|
|
objects.append(
|
|
node(
|
|
name,
|
|
parent_index,
|
|
[],
|
|
[],
|
|
vec3(position["x"], position["y"], position["z"]),
|
|
active=bool(source.get("active", True)),
|
|
layer=layer,
|
|
id_key=id_key,
|
|
)
|
|
)
|
|
components: list[int] = []
|
|
size_source = source.get("size")
|
|
if size_source:
|
|
ui_index = len(objects)
|
|
anchor = source.get("anchor", {"x": 0.5, "y": 0.5})
|
|
objects.append(ui_transform(node_index, size_source["x"], size_source["y"], anchor["x"], anchor["y"]))
|
|
components.append(ui_index)
|
|
if source.get("widget"):
|
|
widget_index = len(objects)
|
|
objects.append(source_widget_component(node_index, source["widget"], id_key))
|
|
components.append(widget_index)
|
|
sprite_asset_id = source.get("spriteAssetId")
|
|
if sprite_asset_id:
|
|
sprite_index = len(objects)
|
|
objects.append(
|
|
sprite_component(
|
|
node_index,
|
|
textures[sprite_asset_id]["spriteFrameUuid"],
|
|
sprite_type=sprite_type,
|
|
size_mode=0,
|
|
)
|
|
)
|
|
components.append(sprite_index)
|
|
label_source = label_override if label_override is not None else source.get("label")
|
|
if label_source:
|
|
label_index = len(objects)
|
|
objects.append(label_component(node_index, label_source))
|
|
components.append(label_index)
|
|
objects[node_index]["_components"] = [ref(item) for item in components]
|
|
return node_index
|
|
|
|
|
|
def build_top_hud_nodes(
|
|
objects: list[dict],
|
|
ui_root_index: int,
|
|
top_hud_evidence: dict,
|
|
textures: dict[str, dict],
|
|
) -> int:
|
|
node_indexes: dict[str, int] = {}
|
|
|
|
def add(path: str, parent_index: int, sprite_type: int = 0) -> int:
|
|
source = top_hud_source_node(top_hud_evidence, path)
|
|
label_override = top_hud_mock_label(top_hud_evidence, source) if source.get("label") else None
|
|
node_index = add_generated_node(
|
|
objects,
|
|
path.rsplit("/", 1)[-1],
|
|
parent_index,
|
|
source,
|
|
textures,
|
|
path,
|
|
sprite_type=sprite_type,
|
|
layer=SOURCE_UI_LAYER,
|
|
label_override=label_override,
|
|
)
|
|
if source.get("mask"):
|
|
mask_index = len(objects)
|
|
objects.append(mask_component(node_index, source["mask"]))
|
|
objects[node_index]["_components"].append(ref(mask_index))
|
|
if source["mask"].get("fillColorUint32") is not None:
|
|
graphics_index = len(objects)
|
|
objects.append(graphics_component(node_index, {"fillColorUint32": source["mask"]["fillColorUint32"]}))
|
|
objects[node_index]["_components"].append(ref(graphics_index))
|
|
if source.get("progressBar"):
|
|
progress_index = len(objects)
|
|
objects.append(progress_bar_component(node_index, source["progressBar"], top_hud_mock_progress(top_hud_evidence)))
|
|
objects[node_index]["_components"].append(ref(progress_index))
|
|
node_indexes[path] = node_index
|
|
return node_index
|
|
|
|
main_index = add("main_ui_v2", ui_root_index)
|
|
top_hud_component_index = len(objects)
|
|
objects.append(stage1_top_hud_component(main_index))
|
|
objects[main_index]["_components"].append(ref(top_hud_component_index))
|
|
|
|
head_info = add("main_ui_v2/HeadInfo", main_index)
|
|
source_root = add("main_ui_v2/Source", main_index)
|
|
sub_head = add("main_ui_v2/HeadInfo/SubHeadInfo", head_info)
|
|
btn_exit = add("main_ui_v2/HeadInfo/btnExit", head_info)
|
|
|
|
head_di = add("main_ui_v2/HeadInfo/SubHeadInfo/head_di", sub_head, sprite_type=1)
|
|
img_head_di1 = add("main_ui_v2/HeadInfo/SubHeadInfo/img_head_di1", sub_head)
|
|
head_mask = add("main_ui_v2/HeadInfo/SubHeadInfo/headMask", sub_head)
|
|
head = add("main_ui_v2/HeadInfo/SubHeadInfo/headMask/head", head_mask)
|
|
node_head_frame = add("main_ui_v2/HeadInfo/SubHeadInfo/node_head_frame", sub_head)
|
|
exp_bar = add("main_ui_v2/HeadInfo/SubHeadInfo/expBar", sub_head, sprite_type=1)
|
|
bar = add("main_ui_v2/HeadInfo/SubHeadInfo/expBar/Bar", exp_bar)
|
|
img_level = add("main_ui_v2/HeadInfo/SubHeadInfo/img_level", sub_head)
|
|
txt_name = add("main_ui_v2/HeadInfo/SubHeadInfo/txtName", sub_head)
|
|
txt_level = add("main_ui_v2/HeadInfo/SubHeadInfo/txtLevel", sub_head)
|
|
txt_exp = add("main_ui_v2/HeadInfo/SubHeadInfo/txtExp", sub_head)
|
|
|
|
source_root_child = add("main_ui_v2/Source/root", source_root)
|
|
img_source_di = add("main_ui_v2/Source/root/img_source_di", source_root_child, sprite_type=1)
|
|
img_gold = add("main_ui_v2/Source/root/img_gold", source_root_child)
|
|
txt_gold = add("main_ui_v2/Source/root/txtGold", source_root_child)
|
|
img_source_di1 = add("main_ui_v2/Source/root/img_source_di1", source_root_child, sprite_type=1)
|
|
img_diamond = add("main_ui_v2/Source/root/img_diamond", source_root_child)
|
|
txt_diamond = add("main_ui_v2/Source/root/txtDiamond", source_root_child)
|
|
|
|
objects[main_index]["_children"] = [ref(head_info), ref(source_root)]
|
|
objects[head_info]["_children"] = [ref(sub_head), ref(btn_exit)]
|
|
objects[sub_head]["_children"] = [
|
|
ref(head_di),
|
|
ref(img_head_di1),
|
|
ref(head_mask),
|
|
ref(node_head_frame),
|
|
ref(exp_bar),
|
|
ref(img_level),
|
|
ref(txt_name),
|
|
ref(txt_level),
|
|
ref(txt_exp),
|
|
]
|
|
objects[head_mask]["_children"] = [ref(head)]
|
|
objects[exp_bar]["_children"] = [ref(bar)]
|
|
objects[source_root]["_children"] = [ref(source_root_child)]
|
|
objects[source_root_child]["_children"] = [
|
|
ref(img_source_di),
|
|
ref(img_gold),
|
|
ref(txt_gold),
|
|
ref(img_source_di1),
|
|
ref(img_diamond),
|
|
ref(txt_diamond),
|
|
]
|
|
return main_index
|
|
|
|
|
|
def build_land_interaction_nodes(
|
|
objects: list[dict],
|
|
ui_root_index: int,
|
|
interaction_evidence: dict,
|
|
textures: dict[str, dict],
|
|
) -> int:
|
|
root_source = interaction_source_node(interaction_evidence, "plant_interactive_v2")
|
|
interaction_index = add_generated_node(
|
|
objects,
|
|
"plant_interactive_v2",
|
|
ui_root_index,
|
|
root_source,
|
|
textures,
|
|
"plant_interactive_v2",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
|
|
land_detail = add_generated_node(
|
|
objects,
|
|
"land_detail",
|
|
interaction_index,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/land_detail"),
|
|
textures,
|
|
"plant_interactive_v2/land_detail",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
land = add_generated_node(
|
|
objects,
|
|
"land",
|
|
land_detail,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/land_detail/land"),
|
|
textures,
|
|
"plant_interactive_v2/land_detail/land",
|
|
sprite_type=1,
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
title = add_generated_node(
|
|
objects,
|
|
"title",
|
|
land,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/land_detail/land/title"),
|
|
textures,
|
|
"plant_interactive_v2/land_detail/land/title",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
land_icon = add_generated_node(
|
|
objects,
|
|
"icon",
|
|
land,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/land_detail/land/icon"),
|
|
textures,
|
|
"plant_interactive_v2/land_detail/land/icon",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
objects[land]["_children"] = [ref(title), ref(land_icon)]
|
|
objects[land_detail]["_children"] = [ref(land)]
|
|
|
|
follow_node = add_generated_node(
|
|
objects,
|
|
"followNode",
|
|
interaction_index,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/followNode"),
|
|
textures,
|
|
"plant_interactive_v2/followNode",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
detail_node = add_generated_node(
|
|
objects,
|
|
"detailNode",
|
|
follow_node,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/followNode/detailNode"),
|
|
textures,
|
|
"plant_interactive_v2/followNode/detailNode",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
seed_group = add_generated_node(
|
|
objects,
|
|
"seedGroup",
|
|
follow_node,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/followNode/seedGroup"),
|
|
textures,
|
|
"plant_interactive_v2/followNode/seedGroup",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
bg_node3 = add_generated_node(
|
|
objects,
|
|
"bg_node3",
|
|
seed_group,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/followNode/seedGroup/bg_node3"),
|
|
textures,
|
|
"plant_interactive_v2/followNode/seedGroup/bg_node3",
|
|
sprite_type=1,
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
bg_node5 = add_generated_node(
|
|
objects,
|
|
"bg_node5",
|
|
seed_group,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/followNode/seedGroup/bg_node5"),
|
|
textures,
|
|
"plant_interactive_v2/followNode/seedGroup/bg_node5",
|
|
sprite_type=1,
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
group_5 = add_generated_node(
|
|
objects,
|
|
"group_5",
|
|
seed_group,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/followNode/seedGroup/group_5"),
|
|
textures,
|
|
"plant_interactive_v2/followNode/seedGroup/group_5",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
group_layout_index = len(objects)
|
|
objects.append(layout_component(group_5, interaction_evidence["slotLayout"]["layoutComponent"]))
|
|
objects[group_5]["_components"].append(ref(group_layout_index))
|
|
|
|
slot_indices: list[int] = []
|
|
for slot_number in range(1, 6):
|
|
slot_path = f"plant_interactive_v2/followNode/seedGroup/group_5/node{slot_number}"
|
|
slot = add_generated_node(objects, f"node{slot_number}", group_5, interaction_source_node(interaction_evidence, slot_path), textures, slot_path, layer=SOURCE_UI_LAYER)
|
|
seed_bg = add_generated_node(objects, "seed_bg", slot, interaction_source_node(interaction_evidence, f"{slot_path}/seed_bg"), textures, f"{slot_path}/seed_bg", layer=SOURCE_UI_LAYER)
|
|
icon = add_generated_node(objects, "icon", slot, interaction_source_node(interaction_evidence, f"{slot_path}/icon"), textures, f"{slot_path}/icon", layer=SOURCE_UI_LAYER)
|
|
bg_txt = add_generated_node(
|
|
objects,
|
|
"bg_txt",
|
|
slot,
|
|
interaction_source_node(interaction_evidence, f"{slot_path}/bg_txt"),
|
|
textures,
|
|
f"{slot_path}/bg_txt",
|
|
sprite_type=1,
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
color_block = add_generated_node(
|
|
objects,
|
|
"color_block",
|
|
bg_txt,
|
|
interaction_source_node(interaction_evidence, f"{slot_path}/bg_txt/color_block"),
|
|
textures,
|
|
f"{slot_path}/bg_txt/color_block",
|
|
sprite_type=1,
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
count = add_generated_node(objects, "count", slot, interaction_source_node(interaction_evidence, f"{slot_path}/count"), textures, f"{slot_path}/count", layer=SOURCE_UI_LAYER)
|
|
objects[bg_txt]["_children"] = [ref(color_block)]
|
|
objects[slot]["_children"] = [ref(seed_bg), ref(icon), ref(bg_txt), ref(count)]
|
|
slot_indices.append(slot)
|
|
objects[group_5]["_children"] = [ref(item) for item in slot_indices]
|
|
objects[seed_group]["_children"] = [ref(bg_node3), ref(bg_node5), ref(group_5)]
|
|
objects[follow_node]["_children"] = [ref(detail_node), ref(seed_group)]
|
|
|
|
land_target = add_generated_node(
|
|
objects,
|
|
"landTarget",
|
|
interaction_index,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/landTarget"),
|
|
textures,
|
|
"plant_interactive_v2/landTarget",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
selected_land = add_generated_node(
|
|
objects,
|
|
"land_valid_selected",
|
|
land_target,
|
|
interaction_source_node(interaction_evidence, "plant_interactive_v2/landTarget/land_valid_selected"),
|
|
textures,
|
|
"plant_interactive_v2/landTarget/land_valid_selected",
|
|
layer=SOURCE_UI_LAYER,
|
|
)
|
|
objects[land_target]["_children"] = [ref(selected_land)]
|
|
objects[interaction_index]["_children"] = [ref(land_target), ref(land_detail), ref(follow_node)]
|
|
return interaction_index
|
|
|
|
|
|
def build_scene(
|
|
evidence: dict,
|
|
land_evidence: dict,
|
|
interaction_evidence: dict,
|
|
decor_evidence: dict,
|
|
top_hud_evidence: dict,
|
|
textures: dict[str, dict],
|
|
decor_spines: dict[str, dict],
|
|
) -> list[dict]:
|
|
root = source_node(evidence, "root")
|
|
scene_mount = source_node(evidence, "root/scene")
|
|
ui_root_source = evidence.get(
|
|
"uiRoot",
|
|
{
|
|
"localPosition": {"x": 0.0, "y": 0.0, "z": 0.0},
|
|
"size": {"x": root["size"]["x"], "y": root["size"]["y"]},
|
|
"pivot": root["pivot"],
|
|
"layer": SOURCE_UI_LAYER,
|
|
},
|
|
)
|
|
farm_root = source_node(evidence, "root/scene/farm_scene_v3")
|
|
map_root = source_node(evidence, "root/scene/farm_scene_v3/Scene")
|
|
bg_layer = source_node(evidence, "root/scene/farm_scene_v3/Scene/BgLayer")
|
|
bg = source_node(evidence, "root/scene/farm_scene_v3/Scene/BgLayer/defaultbg")
|
|
fg_layer = source_node(evidence, "root/scene/farm_scene_v3/Scene/FgLayer")
|
|
fg = source_node(evidence, "root/scene/farm_scene_v3/Scene/FgLayer/default")
|
|
source_camera = evidence["camera"]
|
|
root_widget_source = root.get(
|
|
"widget",
|
|
{
|
|
"alignFlags": 45,
|
|
"originalWidth": root["size"]["x"],
|
|
"originalHeight": root["size"]["y"],
|
|
"sourceTemplate": "cc.Widget compact root default",
|
|
},
|
|
)
|
|
ui_widget_source = ui_root_source.get(
|
|
"widget",
|
|
{
|
|
"alignFlags": 45,
|
|
"originalWidth": ui_root_source["size"]["x"],
|
|
"originalHeight": ui_root_source["size"]["y"],
|
|
"sourceTemplate": "cc.Widget compact ui default",
|
|
},
|
|
)
|
|
|
|
objects: list[dict] = [
|
|
{
|
|
"__type__": "cc.SceneAsset",
|
|
"_name": "stage1_world_camera",
|
|
"_objFlags": 0,
|
|
"_native": "",
|
|
"scene": ref(1),
|
|
},
|
|
{
|
|
"__type__": "cc.Scene",
|
|
"_name": "stage1_world_camera",
|
|
"_objFlags": 0,
|
|
"_parent": None,
|
|
"_children": [ref(2)],
|
|
"_active": True,
|
|
"_components": [],
|
|
"_prefab": None,
|
|
"autoReleaseAssets": False,
|
|
"_globals": ref(20),
|
|
"_id": SCENE_UUID,
|
|
},
|
|
node("root", 1, [3], [6, 7, 8], vec3(root["localPosition"]["x"], root["localPosition"]["y"], root["localPosition"]["z"]), id_key="root"),
|
|
node("scene", 2, [4, 10], [9], vec3(scene_mount["localPosition"]["x"], scene_mount["localPosition"]["y"], scene_mount["localPosition"]["z"]), id_key="root/scene"),
|
|
node("Camera", 3, [], [5], vec3(source_camera["sourcePosition"]["x"], source_camera["sourcePosition"]["y"], source_camera["sourcePosition"]["z"]), id_key="root/scene/Camera"),
|
|
camera_component(4, source_camera),
|
|
ui_transform(2, root["size"]["x"], root["size"]["y"], root["pivot"]["x"], root["pivot"]["y"]),
|
|
canvas_component(2, 5),
|
|
source_widget_component(2, root_widget_source, "root"),
|
|
ui_transform(3, scene_mount["size"]["x"], scene_mount["size"]["y"], scene_mount["pivot"]["x"], scene_mount["pivot"]["y"]),
|
|
node("farm_scene_v3", 3, [11], [], vec3(farm_root["localPosition"]["x"], farm_root["localPosition"]["y"], farm_root["localPosition"]["z"]), id_key="root/scene/farm_scene_v3"),
|
|
node("Scene", 10, [12, 16], [], vec3(map_root["localPosition"]["x"], map_root["localPosition"]["y"], map_root["localPosition"]["z"]), id_key="root/scene/farm_scene_v3/Scene"),
|
|
node("BgLayer", 11, [13], [], vec3(bg_layer["localPosition"]["x"], bg_layer["localPosition"]["y"], bg_layer["localPosition"]["z"]), id_key="root/scene/farm_scene_v3/Scene/BgLayer"),
|
|
node("defaultbg", 12, [], [14, 15], vec3(bg["localPosition"]["x"], bg["localPosition"]["y"], bg["localPosition"]["z"]), id_key="root/scene/farm_scene_v3/Scene/BgLayer/defaultbg"),
|
|
ui_transform(13, bg["size"]["x"], bg["size"]["y"], bg["pivot"]["x"], bg["pivot"]["y"]),
|
|
sprite_component(13, textures["scene_bg"]["spriteFrameUuid"]),
|
|
node("FgLayer", 11, [17], [], vec3(fg_layer["localPosition"]["x"], fg_layer["localPosition"]["y"], fg_layer["localPosition"]["z"]), id_key="root/scene/farm_scene_v3/Scene/FgLayer"),
|
|
node("default", 16, [], [18, 19], vec3(fg["localPosition"]["x"], fg["localPosition"]["y"], fg["localPosition"]["z"]), id_key="root/scene/farm_scene_v3/Scene/FgLayer/default"),
|
|
ui_transform(17, fg["size"]["x"], fg["size"]["y"], fg["pivot"]["x"], fg["pivot"]["y"]),
|
|
sprite_component(17, textures["scene_fg"]["spriteFrameUuid"]),
|
|
]
|
|
|
|
world_camera_component_index = len(objects)
|
|
objects.append(stage1_world_camera_component(4, 5))
|
|
objects[4]["_components"].append(ref(world_camera_component_index))
|
|
|
|
if scene_mount.get("widget"):
|
|
scene_widget_index = len(objects)
|
|
objects.append(source_widget_component(3, scene_mount["widget"], "root/scene"))
|
|
objects[3]["_components"].append(ref(scene_widget_index))
|
|
|
|
decor_nodes = {item["path"]: item for item in decor_evidence["generatedNodes"]}
|
|
decor_assets = {item["id"]: item for item in decor_evidence["decorSpineAssets"]}
|
|
decor_parents = decor_evidence["sourceParentNodes"]
|
|
fg_child_indices_by_name: dict[str, int] = {"default": 17}
|
|
farm_skin_source = decor_parents["farmSkin"]
|
|
farm_skin_index = len(objects)
|
|
fg_child_indices_by_name["FarmSkin"] = farm_skin_index
|
|
objects.append(
|
|
node(
|
|
"FarmSkin",
|
|
16,
|
|
[],
|
|
[],
|
|
vec3(
|
|
farm_skin_source["localPosition"]["x"],
|
|
farm_skin_source["localPosition"]["y"],
|
|
farm_skin_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/Scene/FgLayer/FarmSkin",
|
|
)
|
|
)
|
|
farm_skin_layer_indices: dict[str, int] = {}
|
|
for layer_source in decor_parents["farmSkinLayers"]:
|
|
layer_index = len(objects)
|
|
farm_skin_layer_indices[layer_source["name"]] = layer_index
|
|
objects.append(
|
|
node(
|
|
layer_source["name"],
|
|
farm_skin_index,
|
|
[],
|
|
[],
|
|
vec3(
|
|
layer_source["localPosition"]["x"],
|
|
layer_source["localPosition"]["y"],
|
|
layer_source["localPosition"]["z"],
|
|
),
|
|
id_key=f"root/scene/{layer_source['path']}",
|
|
)
|
|
)
|
|
objects[farm_skin_index]["_children"] = [ref(farm_skin_layer_indices[item["name"]]) for item in decor_parents["farmSkinLayers"]]
|
|
|
|
house_source = decor_nodes["farm_scene_v3/Scene/FgLayer/FarmSkin/Layer2/house_201001"]
|
|
house_asset = decor_assets[house_source["spineAssetId"]]
|
|
house_index = len(objects)
|
|
house_skeleton_index = house_index + 1
|
|
layer2_index = farm_skin_layer_indices["Layer2"]
|
|
objects.extend(
|
|
[
|
|
node(
|
|
house_source["name"],
|
|
layer2_index,
|
|
[],
|
|
[house_skeleton_index],
|
|
vec3(
|
|
house_source["localPosition"]["x"],
|
|
house_source["localPosition"]["y"],
|
|
house_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/Scene/FgLayer/FarmSkin/Layer2/house_201001",
|
|
),
|
|
spine_skeleton_component(
|
|
house_index,
|
|
decor_spines[house_source["spineAssetId"]]["skeletonDataUuid"],
|
|
str(house_asset["defaultSkin"]),
|
|
str(house_asset["defaultAnimation"]),
|
|
),
|
|
]
|
|
)
|
|
objects[layer2_index]["_children"] = [ref(house_index)]
|
|
|
|
dog_layer_source = decor_parents["dogLayer"]
|
|
dog_layer_index = len(objects)
|
|
fg_child_indices_by_name["DogLayer"] = dog_layer_index
|
|
objects.append(
|
|
node(
|
|
"DogLayer",
|
|
16,
|
|
[],
|
|
[],
|
|
vec3(
|
|
dog_layer_source["localPosition"]["x"],
|
|
dog_layer_source["localPosition"]["y"],
|
|
dog_layer_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/Scene/FgLayer/DogLayer",
|
|
)
|
|
)
|
|
doghouse_source = decor_nodes["farm_scene_v3/Scene/FgLayer/DogLayer/dogHouse"]
|
|
doghouse_asset = decor_assets[doghouse_source["spineAssetId"]]
|
|
doghouse_index = len(objects)
|
|
doghouse_skeleton_index = doghouse_index + 1
|
|
objects.extend(
|
|
[
|
|
node(
|
|
doghouse_source["name"],
|
|
dog_layer_index,
|
|
[],
|
|
[doghouse_skeleton_index],
|
|
vec3(
|
|
doghouse_source["localPosition"]["x"],
|
|
doghouse_source["localPosition"]["y"],
|
|
doghouse_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/Scene/FgLayer/DogLayer/dogHouse",
|
|
),
|
|
spine_skeleton_component(
|
|
doghouse_index,
|
|
decor_spines[doghouse_source["spineAssetId"]]["skeletonDataUuid"],
|
|
str(doghouse_asset["defaultSkin"]),
|
|
str(doghouse_asset["defaultAnimation"]),
|
|
),
|
|
]
|
|
)
|
|
objects[dog_layer_index]["_children"] = [ref(doghouse_index)]
|
|
for layer_source in decor_parents["fgLayerChildrenOrder"]:
|
|
layer_name = layer_source["name"]
|
|
if layer_name in fg_child_indices_by_name:
|
|
continue
|
|
layer_index = len(objects)
|
|
fg_child_indices_by_name[layer_name] = layer_index
|
|
objects.append(
|
|
node(
|
|
layer_name,
|
|
16,
|
|
[],
|
|
[],
|
|
vec3(
|
|
layer_source["localPosition"]["x"],
|
|
layer_source["localPosition"]["y"],
|
|
layer_source["localPosition"]["z"],
|
|
),
|
|
id_key=f"root/scene/{layer_source['path']}",
|
|
)
|
|
)
|
|
objects[16]["_children"] = [
|
|
ref(fg_child_indices_by_name[layer_source["name"]])
|
|
for layer_source in decor_parents["fgLayerChildrenOrder"]
|
|
if layer_source["name"] in fg_child_indices_by_name
|
|
]
|
|
|
|
ui_index = len(objects)
|
|
ui_camera_index = ui_index + 1
|
|
ui_transform_index = ui_index + 2
|
|
ui_widget_index = ui_index + 3
|
|
ui_camera_component_index = ui_index + 4
|
|
ui_camera_viewport_component_index = ui_index + 5
|
|
ui_camera_source = evidence["uiCamera"]
|
|
objects[2]["_children"] = [ref(3), ref(ui_index)]
|
|
objects.extend(
|
|
[
|
|
node(
|
|
"ui",
|
|
2,
|
|
[ui_camera_index],
|
|
[ui_transform_index, ui_widget_index],
|
|
vec3(
|
|
ui_root_source["localPosition"]["x"],
|
|
ui_root_source["localPosition"]["y"],
|
|
ui_root_source["localPosition"]["z"],
|
|
),
|
|
layer=int(ui_root_source.get("layer", SOURCE_UI_LAYER)),
|
|
id_key="root/ui",
|
|
),
|
|
node(
|
|
"uiCamera",
|
|
ui_index,
|
|
[],
|
|
[ui_camera_component_index, ui_camera_viewport_component_index],
|
|
vec3(
|
|
ui_camera_source["sourcePosition"]["x"],
|
|
ui_camera_source["sourcePosition"]["y"],
|
|
ui_camera_source["sourcePosition"]["z"],
|
|
),
|
|
layer=SOURCE_UI_LAYER,
|
|
id_key="root/ui/uiCamera",
|
|
),
|
|
ui_transform(ui_index, ui_root_source["size"]["x"], ui_root_source["size"]["y"], ui_root_source["pivot"]["x"], ui_root_source["pivot"]["y"]),
|
|
source_widget_component(ui_index, ui_widget_source, "root/ui"),
|
|
camera_component(ui_camera_index, ui_camera_source, component_id="component:ui-camera"),
|
|
stage1_ui_camera_viewport_component(ui_camera_index),
|
|
]
|
|
)
|
|
# Source startup.scene Canvas serializes `_cameraComponent=-5`; Cocos
|
|
# compiled-json refs resolve that to instance 7, the `root/ui/uiCamera`
|
|
# Camera component. Keep the world camera independent from Canvas resize.
|
|
objects[7]["_cameraComponent"] = ref(ui_camera_component_index)
|
|
|
|
pre_plant_source = interaction_evidence["farmGridGraphics"]["prePlantNode"]
|
|
post_plant_source = interaction_evidence["farmGridGraphics"]["postPlantNode"]
|
|
pre_plant_index = len(objects)
|
|
post_plant_index = pre_plant_index + 1
|
|
objects.extend(
|
|
[
|
|
node(
|
|
"PrePlant",
|
|
10,
|
|
[],
|
|
[],
|
|
vec3(
|
|
pre_plant_source["localPosition"]["x"],
|
|
pre_plant_source["localPosition"]["y"],
|
|
pre_plant_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/PrePlant",
|
|
),
|
|
node(
|
|
"PostPlant",
|
|
10,
|
|
[],
|
|
[],
|
|
vec3(
|
|
post_plant_source["localPosition"]["x"],
|
|
post_plant_source["localPosition"]["y"],
|
|
post_plant_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/PostPlant",
|
|
),
|
|
]
|
|
)
|
|
|
|
transform_nodes = land_evidence["gridRoot"]["transformNodes"]
|
|
scaled_source, rotate_source, grid_origin_source = transform_nodes
|
|
scaled_index = len(objects)
|
|
rotate_index = scaled_index + 1
|
|
grid_origin_index = scaled_index + 2
|
|
objects[10]["_children"] = [ref(11), ref(scaled_index), ref(pre_plant_index), ref(post_plant_index)]
|
|
objects.extend(
|
|
[
|
|
node(
|
|
"Scaled",
|
|
10,
|
|
[rotate_index],
|
|
[],
|
|
vec3(
|
|
scaled_source["localPosition"]["x"],
|
|
scaled_source["localPosition"]["y"],
|
|
scaled_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/Scaled",
|
|
),
|
|
node(
|
|
"Rotate",
|
|
scaled_index,
|
|
[grid_origin_index],
|
|
[],
|
|
vec3(
|
|
rotate_source["localPosition"]["x"],
|
|
rotate_source["localPosition"]["y"],
|
|
rotate_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/Scaled/Rotate",
|
|
),
|
|
node(
|
|
"GridOrigin",
|
|
rotate_index,
|
|
[],
|
|
[],
|
|
vec3(
|
|
grid_origin_source["localPosition"]["x"],
|
|
grid_origin_source["localPosition"]["y"],
|
|
grid_origin_source["localPosition"]["z"],
|
|
),
|
|
id_key="root/scene/farm_scene_v3/Scaled/Rotate/GridOrigin",
|
|
),
|
|
]
|
|
)
|
|
|
|
grid_indices: list[int] = []
|
|
icon_skeleton_sources = land_evidence["iconSkeletonComponents"]
|
|
scene_land_skeleton_uuid = scene_land_spine_uuids()["skeletonDataUuid"]
|
|
for source_order, land in enumerate(sorted(land_evidence["visibleLands"], key=lambda item: item["cell"]["sourceIndex"])):
|
|
cell = land["cell"]
|
|
icon = land["icon"]
|
|
asset_id = land["mockRender"]["assetId"]
|
|
skeleton_source = icon_skeleton_sources[source_order]
|
|
default_animation = "land_locked" if asset_id == "land_extend" else asset_id
|
|
has_expand_board = asset_id == "land_extend"
|
|
grid_index = len(objects)
|
|
icon_index = grid_index + 1
|
|
grid_ui_index = grid_index + 2
|
|
icon_ui_index = grid_index + 3
|
|
icon_skeleton_index = grid_index + 4
|
|
board_index = grid_index + 5
|
|
board_ui_index = grid_index + 6
|
|
board_sprite_index = grid_index + 7
|
|
grid_indices.append(grid_index)
|
|
land_objects = [
|
|
node(
|
|
cell["name"],
|
|
grid_origin_index,
|
|
[board_index, icon_index] if has_expand_board else [icon_index],
|
|
[grid_ui_index],
|
|
vec3(cell["localPosition"]["x"], cell["localPosition"]["y"], cell["localPosition"]["z"]),
|
|
id_key=f"root/scene/{cell['path']}",
|
|
),
|
|
node(
|
|
"icon",
|
|
grid_index,
|
|
[],
|
|
[icon_ui_index, icon_skeleton_index],
|
|
vec3(icon["localPosition"]["x"], icon["localPosition"]["y"], icon["localPosition"]["z"]),
|
|
id_key=f"root/scene/{icon['path']}",
|
|
),
|
|
ui_transform(grid_index, cell["size"]["x"], cell["size"]["y"], cell["anchor"]["x"], cell["anchor"]["y"]),
|
|
ui_transform(icon_index, icon["size"]["x"], icon["size"]["y"], icon["anchor"]["x"], icon["anchor"]["y"]),
|
|
spine_skeleton_component(
|
|
icon_index,
|
|
scene_land_skeleton_uuid,
|
|
str(skeleton_source["defaultSkin"]),
|
|
default_animation,
|
|
),
|
|
]
|
|
if has_expand_board:
|
|
board_texture = textures["land_extend"]
|
|
land_objects.extend(
|
|
[
|
|
node(
|
|
"expand_board",
|
|
grid_index,
|
|
[],
|
|
[board_ui_index, board_sprite_index],
|
|
vec3(icon["localPosition"]["x"], icon["localPosition"]["y"], icon["localPosition"]["z"]),
|
|
id_key=f"root/scene/{icon['path']}/expand_board",
|
|
),
|
|
ui_transform(
|
|
board_index,
|
|
board_texture["pixelWidth"],
|
|
board_texture["pixelHeight"],
|
|
0.5,
|
|
0.5,
|
|
),
|
|
sprite_component(board_index, board_texture["spriteFrameUuid"]),
|
|
]
|
|
)
|
|
objects.extend(land_objects)
|
|
top_hud_index = build_top_hud_nodes(objects, ui_index, top_hud_evidence, textures)
|
|
interaction_index = build_land_interaction_nodes(objects, ui_index, interaction_evidence, textures)
|
|
objects[grid_origin_index]["_children"] = [ref(index) for index in grid_indices]
|
|
objects[ui_index]["_children"] = [ref(ui_camera_index), ref(top_hud_index), ref(interaction_index)]
|
|
|
|
interaction_component_index = len(objects)
|
|
objects.append(stage1_land_interaction_component(2))
|
|
objects[2]["_components"].append(ref(interaction_component_index))
|
|
|
|
template = read_json(SCENE_TEMPLATE)
|
|
globals_start = len(objects)
|
|
mapping = {old: globals_start + (old - 8) for old in range(8, 15)}
|
|
objects.extend(remap_ids(copy.deepcopy(template[8:15]), mapping))
|
|
objects[1]["_globals"] = ref(globals_start)
|
|
return objects
|
|
|
|
|
|
def write_scene_assets(
|
|
evidence: dict,
|
|
land_evidence: dict,
|
|
interaction_evidence: dict,
|
|
decor_evidence: dict,
|
|
top_hud_evidence: dict,
|
|
textures: dict[str, dict],
|
|
decor_spines: dict[str, dict],
|
|
) -> None:
|
|
scene_dir = ASSETS / "scenes"
|
|
ensure_directory_meta(scene_dir)
|
|
scene_path = scene_dir / "stage1_world_camera.scene"
|
|
write_json(scene_path, build_scene(evidence, land_evidence, interaction_evidence, decor_evidence, top_hud_evidence, textures, decor_spines))
|
|
write_json(
|
|
scene_path.with_suffix(scene_path.suffix + ".meta"),
|
|
{
|
|
"ver": "1.1.50",
|
|
"importer": "scene",
|
|
"imported": True,
|
|
"uuid": SCENE_UUID,
|
|
"files": [".json"],
|
|
"subMetas": {},
|
|
"userData": {},
|
|
},
|
|
)
|
|
|
|
|
|
def main() -> int:
|
|
evidence = read_json(SOURCE_JSON)
|
|
land_evidence = read_json(LAND_SOURCE_JSON)
|
|
interaction_evidence = read_json(INTERACTION_SOURCE_JSON)
|
|
decor_evidence = read_json(DECOR_SOURCE_JSON)
|
|
top_hud_evidence = read_json(TOP_HUD_SOURCE_JSON)
|
|
for path in [ASSETS, ASSETS / "textures", ASSETS / "spine", ASSETS / "scenes", ASSETS / "scripts", ASSETS / "configs"]:
|
|
ensure_directory_meta(path)
|
|
textures = write_texture_assets(evidence, land_evidence, interaction_evidence, top_hud_evidence)
|
|
spine_asset = write_spine_assets(land_evidence)
|
|
decor_spines = write_decor_spine_assets(decor_evidence)
|
|
write_script_assets(land_evidence, interaction_evidence, top_hud_evidence)
|
|
write_config_assets(evidence, land_evidence, interaction_evidence, decor_evidence, top_hud_evidence)
|
|
write_project_settings(evidence)
|
|
write_scene_assets(evidence, land_evidence, interaction_evidence, decor_evidence, top_hud_evidence, textures, decor_spines)
|
|
report = {
|
|
"status": "pass",
|
|
"project": str(PROJECT),
|
|
"sceneUuid": SCENE_UUID,
|
|
"scenePath": str(ASSETS / "scenes" / "stage1_world_camera.scene"),
|
|
"textures": textures,
|
|
"spineAsset": spine_asset,
|
|
"decorSpineAssets": decor_spines,
|
|
"decorNodeCount": len(decor_evidence["generatedNodes"]),
|
|
"visibleLandCount": len(land_evidence["visibleLands"]),
|
|
"interactionAssetCount": len(interaction_evidence["assets"]),
|
|
"topHudAssetCount": len(top_hud_evidence["assets"]),
|
|
"topHudNodeCount": len(top_hud_evidence["nodes"]),
|
|
"mockSeedCount": len(interaction_evidence["mockSeeds"]),
|
|
"mockUser": top_hud_evidence["mockUser"],
|
|
}
|
|
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|