feat(studio,stacking,animations,collections): M16 ModBison Studio, object stacking, model animations, and poly collections for MVP 2
checkpoint / checkpoint (push) Successful in 6m32s
checkpoint / checkpoint (push) Successful in 6m32s
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
class_name MBWorldProjectIO
|
||||
extends RefCounted
|
||||
## Manages serialization and deserialization of local .mbworld project files
|
||||
## and cloud sync with ModBison backend.
|
||||
|
||||
const RECENT_PROJECTS_PATH: String = "user://recent_projects.json"
|
||||
|
||||
|
||||
static func save_project(path: String, project_data: Dictionary) -> bool:
|
||||
var fa := FileAccess.open(path, FileAccess.WRITE)
|
||||
if fa == null:
|
||||
push_error("Failed to open %s for write" % path)
|
||||
return false
|
||||
|
||||
var json_str := JSON.stringify(project_data, " ")
|
||||
fa.store_string(json_str)
|
||||
fa.close()
|
||||
record_recent_project(path)
|
||||
return true
|
||||
|
||||
|
||||
static func load_project(path: String) -> Dictionary:
|
||||
if not FileAccess.file_exists(path):
|
||||
push_error("Project file does not exist: %s" % path)
|
||||
return {}
|
||||
|
||||
var fa := FileAccess.open(path, FileAccess.READ)
|
||||
if fa == null:
|
||||
return {}
|
||||
|
||||
var text := fa.get_as_text()
|
||||
fa.close()
|
||||
|
||||
var parsed = JSON.parse_string(text)
|
||||
if parsed is Dictionary:
|
||||
record_recent_project(path)
|
||||
return parsed
|
||||
return {}
|
||||
|
||||
|
||||
static func create_template(template_name: String) -> Dictionary:
|
||||
var base := {
|
||||
"format_version": 1,
|
||||
"title": "Untitled World",
|
||||
"template": template_name,
|
||||
"created_at": Time.get_datetime_string_from_system(),
|
||||
"objects": [],
|
||||
"tile_layers": [
|
||||
{
|
||||
"name": "ground",
|
||||
"width": 32,
|
||||
"height": 32,
|
||||
"tiles": []
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"ambient_color": [0.4, 0.4, 0.45],
|
||||
"sky_color": [0.3, 0.6, 0.9],
|
||||
"gravity": 9.8
|
||||
}
|
||||
}
|
||||
|
||||
match template_name.to_lower():
|
||||
"baseplate":
|
||||
base["title"] = "Baseplate World"
|
||||
base["objects"] = [
|
||||
{
|
||||
"id": "spawn_pad",
|
||||
"catalog_id": "spawn_pad",
|
||||
"asset_id": "props/crate_small.glb",
|
||||
"position": [0, 0, 0],
|
||||
"rotation": [0, 0, 0, 1],
|
||||
"scale": [2, 2, 0.2],
|
||||
"properties": {"display_name": "Spawn Pad"}
|
||||
}
|
||||
]
|
||||
"terrain":
|
||||
base["title"] = "Rolling Hills World"
|
||||
base["objects"] = [
|
||||
{
|
||||
"id": "tree_01",
|
||||
"catalog_id": "tree_pine",
|
||||
"asset_id": "props/tree_pine_01.glb",
|
||||
"position": [4, 4, 0],
|
||||
"rotation": [0, 0, 0, 1],
|
||||
"scale": [1, 1, 1],
|
||||
"properties": {"display_name": "Pine Tree"}
|
||||
},
|
||||
{
|
||||
"id": "bison_01",
|
||||
"catalog_id": "bison",
|
||||
"asset_id": "props/bison.glb",
|
||||
"position": [0, 6, 0],
|
||||
"rotation": [0, 0, 0, 1],
|
||||
"scale": [1, 1, 1],
|
||||
"properties": {"display_name": "Wild Bison"}
|
||||
}
|
||||
]
|
||||
"obby", "platformer":
|
||||
base["title"] = "Obby Parkour World"
|
||||
base["objects"] = [
|
||||
{
|
||||
"id": "start_platform",
|
||||
"catalog_id": "crate_small",
|
||||
"asset_id": "props/crate_small.glb",
|
||||
"position": [0, 0, 0],
|
||||
"rotation": [0, 0, 0, 1],
|
||||
"scale": [3, 3, 0.5],
|
||||
"properties": {"display_name": "Start Platform"}
|
||||
},
|
||||
{
|
||||
"id": "moving_plat_01",
|
||||
"catalog_id": "crate_small",
|
||||
"asset_id": "props/crate_small.glb",
|
||||
"position": [0, 6, 1],
|
||||
"rotation": [0, 0, 0, 1],
|
||||
"scale": [2, 2, 0.3],
|
||||
"properties": {
|
||||
"display_name": "Moving Elevator",
|
||||
"motion": {
|
||||
"motion_type": "waypoint",
|
||||
"move_speed": 3.0,
|
||||
"waypoints": [[0, 6, 1], [0, 6, 6]]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "goal_platform",
|
||||
"catalog_id": "crate_small",
|
||||
"asset_id": "props/crate_small.glb",
|
||||
"position": [0, 14, 6],
|
||||
"rotation": [0, 0, 0, 1],
|
||||
"scale": [3, 3, 0.5],
|
||||
"properties": {"display_name": "Finish Goal"}
|
||||
}
|
||||
]
|
||||
|
||||
return base
|
||||
|
||||
|
||||
static func record_recent_project(path: String) -> void:
|
||||
var recents: Array = get_recent_projects()
|
||||
if path in recents:
|
||||
recents.erase(path)
|
||||
recents.push_front(path)
|
||||
if recents.size() > 10:
|
||||
recents.resize(10)
|
||||
var fa := FileAccess.open(RECENT_PROJECTS_PATH, FileAccess.WRITE)
|
||||
if fa != null:
|
||||
fa.store_string(JSON.stringify(recents))
|
||||
fa.close()
|
||||
|
||||
|
||||
static func get_recent_projects() -> Array:
|
||||
if not FileAccess.file_exists(RECENT_PROJECTS_PATH):
|
||||
return []
|
||||
var fa := FileAccess.open(RECENT_PROJECTS_PATH, FileAccess.READ)
|
||||
if fa == null:
|
||||
return []
|
||||
var parsed = JSON.parse_string(fa.get_as_text())
|
||||
fa.close()
|
||||
if parsed is Array:
|
||||
return parsed
|
||||
return []
|
||||
Reference in New Issue
Block a user