201 lines
5.1 KiB
GDScript
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 []
|