Files
modbison/scripts/studio/mbworld_project_io.gd

201 lines
5.1 KiB
GDScript

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": "crate_small",
"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", "catalog_id": "crate_small"}
},
{
"id": "modbison_mascot",
"catalog_id": "bison",
"asset_id": "props/bison.glb",
"position": [0, 4, 0],
"rotation": [0, 0, 0, 1],
"scale": [1, 1, 1],
"properties": {"display_name": "ModBison", "catalog_id": "bison"}
},
{
"id": "crate_base",
"catalog_id": "crate_small",
"asset_id": "props/crate_small.glb",
"position": [4, 0, 0],
"rotation": [0, 0, 0, 1],
"scale": [1, 1, 1],
"properties": {"display_name": "Wooden Crate", "catalog_id": "crate_small"}
},
{
"id": "crate_stacked",
"catalog_id": "crate_small",
"asset_id": "props/crate_small.glb",
"position": [4, 0, 1],
"rotation": [0, 0, 0, 1],
"scale": [1, 1, 1],
"properties": {"display_name": "Stacked Crate", "catalog_id": "crate_small", "parent_id": "crate_base"}
},
{
"id": "lamp_01",
"catalog_id": "lamp_post_01",
"asset_id": "props/lamp_post_01.glb",
"position": [-3, 3, 0],
"rotation": [0, 0, 0, 1],
"scale": [1, 1, 1],
"properties": {"display_name": "Street Lamp", "catalog_id": "lamp_post_01"}
}
]
"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 []