AeThex-Engine-Core/engine/modules/aethex_templates/template_manager.cpp
mrpiglr 190b6b2eab
Some checks are pending
Build AeThex Engine / build-windows (push) Waiting to run
Build AeThex Engine / build-linux (push) Waiting to run
Build AeThex Engine / build-macos (push) Waiting to run
Build AeThex Engine / create-release (push) Blocked by required conditions
Deploy Docsify Documentation / build (push) Waiting to run
Deploy Docsify Documentation / deploy (push) Blocked by required conditions
chore: sync local changes to Forgejo
2026-03-13 00:37:06 -07:00

720 lines
24 KiB
C++

/**************************************************************************/
/* template_manager.cpp */
/**************************************************************************/
/* This file is part of: */
/* AETHEX ENGINE */
/* https://aethex.foundation */
/**************************************************************************/
/* Copyright (c) 2026-present AeThex Labs. */
/**************************************************************************/
#include "template_manager.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/os/os.h"
#include "core/variant/typed_array.h"
const String AeThexTemplateManager::TEMPLATES_API_URL = "https://api.aethex.dev/templates/v1";
const String AeThexTemplateManager::TEMPLATES_CACHE_PATH = "user://aethex_templates/";
AeThexTemplateManager *AeThexTemplateManager::singleton = nullptr;
void AeThexTemplateManager::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_all_templates"), &AeThexTemplateManager::get_all_templates);
ClassDB::bind_method(D_METHOD("get_builtin_templates"), &AeThexTemplateManager::get_builtin_templates);
ClassDB::bind_method(D_METHOD("get_downloaded_templates"), &AeThexTemplateManager::get_downloaded_templates);
ClassDB::bind_method(D_METHOD("get_online_templates"), &AeThexTemplateManager::get_online_templates);
ClassDB::bind_method(D_METHOD("get_template_by_id", "id"), &AeThexTemplateManager::get_template_by_id);
ClassDB::bind_method(D_METHOD("get_templates_by_category", "category"), &AeThexTemplateManager::get_templates_by_category);
ClassDB::bind_method(D_METHOD("get_templates_by_platform", "platform"), &AeThexTemplateManager::get_templates_by_platform);
ClassDB::bind_method(D_METHOD("get_templates_by_difficulty", "difficulty"), &AeThexTemplateManager::get_templates_by_difficulty);
ClassDB::bind_method(D_METHOD("search_templates", "query"), &AeThexTemplateManager::search_templates);
ClassDB::bind_method(D_METHOD("fetch_online_templates"), &AeThexTemplateManager::fetch_online_templates);
ClassDB::bind_method(D_METHOD("download_template", "template_id"), &AeThexTemplateManager::download_template);
ClassDB::bind_method(D_METHOD("is_template_downloaded", "template_id"), &AeThexTemplateManager::is_template_downloaded);
ClassDB::bind_method(D_METHOD("create_project_from_template", "template", "project_path", "variables"), &AeThexTemplateManager::create_project_from_template);
ClassDB::bind_method(D_METHOD("process_template_string", "template", "variables"), &AeThexTemplateManager::process_template_string);
ADD_SIGNAL(MethodInfo("templates_fetched", PropertyInfo(Variant::ARRAY, "templates")));
ADD_SIGNAL(MethodInfo("template_downloaded", PropertyInfo(Variant::STRING, "template_id")));
ADD_SIGNAL(MethodInfo("template_download_failed", PropertyInfo(Variant::STRING, "template_id"), PropertyInfo(Variant::STRING, "error")));
ADD_SIGNAL(MethodInfo("project_created", PropertyInfo(Variant::STRING, "project_path")));
ADD_SIGNAL(MethodInfo("project_creation_failed", PropertyInfo(Variant::STRING, "error")));
}
AeThexTemplateManager *AeThexTemplateManager::get_singleton() {
return singleton;
}
AeThexTemplateManager::AeThexTemplateManager() {
singleton = this;
_init_builtin_templates();
_load_downloaded_templates();
}
AeThexTemplateManager::~AeThexTemplateManager() {
if (http_client) {
memdelete(http_client);
}
singleton = nullptr;
}
void AeThexTemplateManager::_init_builtin_templates() {
builtin_templates.push_back(AeThexBuiltinTemplates::create_empty_project());
builtin_templates.push_back(AeThexBuiltinTemplates::create_2d_platformer());
builtin_templates.push_back(AeThexBuiltinTemplates::create_3d_fps());
builtin_templates.push_back(AeThexBuiltinTemplates::create_rpg_starter());
builtin_templates.push_back(AeThexBuiltinTemplates::create_multiplayer_game());
builtin_templates.push_back(AeThexBuiltinTemplates::create_roblox_experience());
builtin_templates.push_back(AeThexBuiltinTemplates::create_uefn_island());
builtin_templates.push_back(AeThexBuiltinTemplates::create_unity_mobile());
builtin_templates.push_back(AeThexBuiltinTemplates::create_web_game());
builtin_templates.push_back(AeThexBuiltinTemplates::create_crossplatform_game());
}
void AeThexTemplateManager::_load_downloaded_templates() {
Ref<DirAccess> dir = DirAccess::open(TEMPLATES_CACHE_PATH);
if (dir.is_null()) {
return;
}
dir->list_dir_begin();
String file_name = dir->get_next();
while (!file_name.is_empty()) {
if (file_name.ends_with(".aethex_template")) {
Ref<FileAccess> f = FileAccess::open(TEMPLATES_CACHE_PATH + file_name, FileAccess::READ);
if (f.is_valid()) {
String json_str = f->get_as_text();
JSON json;
if (json.parse(json_str) == OK) {
Ref<AeThexTemplate> tmpl = AeThexTemplate::from_json(json.get_data());
tmpl->set_is_downloaded(true);
tmpl->set_local_path(TEMPLATES_CACHE_PATH + file_name);
downloaded_templates.push_back(tmpl);
}
}
}
file_name = dir->get_next();
}
}
void AeThexTemplateManager::_cache_template(const Ref<AeThexTemplate> &p_template) {
Ref<DirAccess> dir = DirAccess::open("user://");
if (dir.is_valid()) {
dir->make_dir_recursive(TEMPLATES_CACHE_PATH.substr(7)); // Remove "user://"
}
String file_path = TEMPLATES_CACHE_PATH + p_template->get_id() + ".aethex_template";
Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::WRITE);
if (f.is_valid()) {
f->store_string(JSON::stringify(p_template->to_json(), "\t"));
}
}
TypedArray<AeThexTemplate> AeThexTemplateManager::get_all_templates() const {
TypedArray<AeThexTemplate> all;
for (const Ref<AeThexTemplate> &t : builtin_templates) all.push_back(t);
for (const Ref<AeThexTemplate> &t : downloaded_templates) all.push_back(t);
for (const Ref<AeThexTemplate> &t : online_templates) all.push_back(t);
return all;
}
TypedArray<AeThexTemplate> AeThexTemplateManager::get_builtin_templates() const {
TypedArray<AeThexTemplate> result;
for (const Ref<AeThexTemplate> &t : builtin_templates) result.push_back(t);
return result;
}
TypedArray<AeThexTemplate> AeThexTemplateManager::get_downloaded_templates() const {
TypedArray<AeThexTemplate> result;
for (const Ref<AeThexTemplate> &t : downloaded_templates) result.push_back(t);
return result;
}
TypedArray<AeThexTemplate> AeThexTemplateManager::get_online_templates() const {
TypedArray<AeThexTemplate> result;
for (const Ref<AeThexTemplate> &t : online_templates) result.push_back(t);
return result;
}
Ref<AeThexTemplate> AeThexTemplateManager::get_template_by_id(const String &p_id) const {
for (const Ref<AeThexTemplate> &tmpl : builtin_templates) {
if (tmpl->get_id() == p_id) return tmpl;
}
for (const Ref<AeThexTemplate> &tmpl : downloaded_templates) {
if (tmpl->get_id() == p_id) return tmpl;
}
for (const Ref<AeThexTemplate> &tmpl : online_templates) {
if (tmpl->get_id() == p_id) return tmpl;
}
return Ref<AeThexTemplate>();
}
TypedArray<AeThexTemplate> AeThexTemplateManager::get_templates_by_category(AeThexTemplate::TemplateCategory p_category) const {
TypedArray<AeThexTemplate> result;
for (const Ref<AeThexTemplate> &tmpl : builtin_templates) {
if (tmpl->get_category() == p_category) result.push_back(tmpl);
}
for (const Ref<AeThexTemplate> &tmpl : downloaded_templates) {
if (tmpl->get_category() == p_category) result.push_back(tmpl);
}
for (const Ref<AeThexTemplate> &tmpl : online_templates) {
if (tmpl->get_category() == p_category) result.push_back(tmpl);
}
return result;
}
TypedArray<AeThexTemplate> AeThexTemplateManager::get_templates_by_platform(AeThexTemplate::TargetPlatform p_platform) const {
TypedArray<AeThexTemplate> result;
for (const Ref<AeThexTemplate> &tmpl : builtin_templates) {
if (tmpl->supports_platform(p_platform)) result.push_back(tmpl);
}
for (const Ref<AeThexTemplate> &tmpl : downloaded_templates) {
if (tmpl->supports_platform(p_platform)) result.push_back(tmpl);
}
for (const Ref<AeThexTemplate> &tmpl : online_templates) {
if (tmpl->supports_platform(p_platform)) result.push_back(tmpl);
}
return result;
}
TypedArray<AeThexTemplate> AeThexTemplateManager::get_templates_by_difficulty(AeThexTemplate::Difficulty p_difficulty) const {
TypedArray<AeThexTemplate> result;
for (const Ref<AeThexTemplate> &tmpl : builtin_templates) {
if (tmpl->get_difficulty() == p_difficulty) result.push_back(tmpl);
}
for (const Ref<AeThexTemplate> &tmpl : downloaded_templates) {
if (tmpl->get_difficulty() == p_difficulty) result.push_back(tmpl);
}
for (const Ref<AeThexTemplate> &tmpl : online_templates) {
if (tmpl->get_difficulty() == p_difficulty) result.push_back(tmpl);
}
return result;
}
TypedArray<AeThexTemplate> AeThexTemplateManager::search_templates(const String &p_query) const {
TypedArray<AeThexTemplate> result;
String query_lower = p_query.to_lower();
Vector<Ref<AeThexTemplate>> all;
all.append_array(builtin_templates);
all.append_array(downloaded_templates);
all.append_array(online_templates);
for (const Ref<AeThexTemplate> &tmpl : all) {
if (tmpl->get_template_name().to_lower().contains(query_lower) ||
tmpl->get_description().to_lower().contains(query_lower)) {
result.push_back(tmpl);
continue;
}
// Check tags
for (const String &tag : tmpl->get_tags()) {
if (tag.to_lower().contains(query_lower)) {
result.push_back(tmpl);
break;
}
}
}
return result;
}
void AeThexTemplateManager::fetch_online_templates() {
// Would make HTTP request to TEMPLATES_API_URL
// For now, emit empty signal
is_fetching = true;
// ... HTTP request logic ...
}
void AeThexTemplateManager::download_template(const String &p_template_id) {
Ref<AeThexTemplate> tmpl = get_template_by_id(p_template_id);
if (tmpl.is_null()) {
emit_signal("template_download_failed", p_template_id, "Template not found");
return;
}
// Would download template package
// For now, just cache the metadata
_cache_template(tmpl);
emit_signal("template_downloaded", p_template_id);
}
bool AeThexTemplateManager::is_template_downloaded(const String &p_template_id) const {
for (const Ref<AeThexTemplate> &tmpl : downloaded_templates) {
if (tmpl->get_id() == p_template_id) {
return true;
}
}
// Builtin templates are always "downloaded"
for (const Ref<AeThexTemplate> &tmpl : builtin_templates) {
if (tmpl->get_id() == p_template_id) {
return true;
}
}
return false;
}
Error AeThexTemplateManager::create_project_from_template(const Ref<AeThexTemplate> &p_template,
const String &p_project_path,
const Dictionary &p_variables) {
if (p_template.is_null()) {
emit_signal("project_creation_failed", "Invalid template");
return ERR_INVALID_PARAMETER;
}
// Create project directory
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error err = dir->make_dir_recursive(p_project_path);
if (err != OK) {
emit_signal("project_creation_failed", "Failed to create project directory");
return err;
}
// Process file structure
Dictionary file_structure = p_template->get_file_structure();
Array keys = file_structure.keys();
for (int i = 0; i < keys.size(); i++) {
String rel_path = keys[i];
String content = file_structure[rel_path];
// Process template variables
content = process_template_string(content, p_variables);
rel_path = process_template_string(rel_path, p_variables);
String full_path = p_project_path.path_join(rel_path);
// Create subdirectories if needed
String dir_path = full_path.get_base_dir();
dir->make_dir_recursive(dir_path);
// Write file
Ref<FileAccess> f = FileAccess::open(full_path, FileAccess::WRITE);
if (f.is_valid()) {
f->store_string(content);
} else {
WARN_PRINT("Failed to create file: " + full_path);
}
}
// Create project.aethex file with AeThex configuration
String project_file = p_project_path.path_join("project.aethex");
if (!FileAccess::exists(project_file)) {
String project_name = p_variables.get("project_name", "New AeThex Project");
String project_content = _create_project_godot(project_name, p_template);
Ref<FileAccess> f = FileAccess::open(project_file, FileAccess::WRITE);
if (f.is_valid()) {
f->store_string(project_content);
}
}
emit_signal("project_created", p_project_path);
return OK;
}
String AeThexTemplateManager::process_template_string(const String &p_template, const Dictionary &p_variables) {
String result = p_template;
Array keys = p_variables.keys();
for (int i = 0; i < keys.size(); i++) {
String key = keys[i];
String value = p_variables[key];
// Replace {{variable}} patterns
result = result.replace("{{" + key + "}}", value);
// Replace ${variable} patterns
result = result.replace("${" + key + "}", value);
// Replace %variable% patterns
result = result.replace("%" + key + "%", value);
}
return result;
}
String AeThexTemplateManager::_create_project_godot(const String &p_name, const Ref<AeThexTemplate> &p_template) {
String content;
content += "; Engine configuration file.\n";
content += "; Generated by AeThex Engine Template System\n\n";
content += "[application]\n\n";
content += "config/name=\"" + p_name + "\"\n";
content += "config/description=\"Created with AeThex Engine\"\n";
content += "config/icon=\"res://icon.svg\"\n\n";
content += "[aethex]\n\n";
content += "template/id=\"" + p_template->get_id() + "\"\n";
content += "template/version=\"" + p_template->get_version() + "\"\n";
// Add platform targets
uint32_t platforms = p_template->get_platforms();
PackedStringArray platform_names;
if (platforms & AeThexTemplate::PLATFORM_ROBLOX) platform_names.push_back("roblox");
if (platforms & AeThexTemplate::PLATFORM_UEFN) platform_names.push_back("uefn");
if (platforms & AeThexTemplate::PLATFORM_UNITY) platform_names.push_back("unity");
if (platforms & AeThexTemplate::PLATFORM_WEB) platform_names.push_back("web");
if (platforms & AeThexTemplate::PLATFORM_AETHEX) platform_names.push_back("aethex");
content += "export/targets=[";
for (int i = 0; i < platform_names.size(); i++) {
if (i > 0) content += ", ";
content += "\"" + platform_names[i] + "\"";
}
content += "]\n\n";
content += "[rendering]\n\n";
content += "renderer/rendering_method=\"forward_plus\"\n";
return content;
}
// ===========================================================
// Built-in Template Factory Functions
// ===========================================================
namespace AeThexBuiltinTemplates {
Ref<AeThexTemplate> create_empty_project() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_empty");
t->set_template_name("Empty Project");
t->set_description("A minimal project with just the essentials. Perfect for starting from scratch.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_ALL);
t->set_difficulty(AeThexTemplate::DIFFICULTY_BEGINNER);
t->set_is_builtin(true);
PackedStringArray tags;
tags.push_back("empty");
tags.push_back("starter");
tags.push_back("minimal");
t->set_tags(tags);
Dictionary files;
files["main.aethex"] = R"(// AeThex Main Script
// Your cross-platform game starts here!
reality Game {
journey start() {
reveal("Hello from AeThex!")
}
}
)";
files["icon.svg"] = R"(<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"128\" height=\"128\"><rect width=\"128\" height=\"128\" fill=\"#478cbf\"/></svg>)";
t->set_file_structure(files);
return t;
}
Ref<AeThexTemplate> create_2d_platformer() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_2d_platformer");
t->set_template_name("2D Platformer");
t->set_description("Classic 2D platformer with player movement, jumping, and basic level design.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_ALL);
t->set_difficulty(AeThexTemplate::DIFFICULTY_BEGINNER);
t->set_is_builtin(true);
PackedStringArray tags;
tags.push_back("2d");
tags.push_back("platformer");
tags.push_back("sidescroller");
t->set_tags(tags);
PackedStringArray features;
features.push_back("Player movement & jumping");
features.push_back("Tilemap-based levels");
features.push_back("Collectibles");
features.push_back("Basic enemies");
t->set_features(features);
Dictionary files;
files["player.aethex"] = R"(// Player Controller - Cross-platform
reality Player {
beacon position: Vector2 = (0, 0)
beacon velocity: Vector2 = (0, 0)
beacon speed: Number = 300
beacon jump_force: Number = -600
beacon gravity: Number = 1200
beacon is_grounded: Boolean = false
journey update(delta: Number) {
// Horizontal movement
artifact move_dir = get_input_axis("move_left", "move_right")
velocity.x = move_dir * speed
// Gravity
velocity.y += gravity * delta
// Jump
if is_grounded and is_action_pressed("jump") {
velocity.y = jump_force
}
// Apply movement
sync across {
position += velocity * delta
}
}
}
)";
files["level.aethex"] = R"(// Level Controller
reality Level {
beacon player: Player
beacon collectibles: Array = []
beacon score: Number = 0
journey start() {
player = spawn(Player, (100, 300))
setup_tilemap()
}
journey on_collectible_picked(item) {
score += item.value
notify("score_changed", score)
}
}
)";
t->set_file_structure(files);
return t;
}
Ref<AeThexTemplate> create_3d_fps() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_3d_fps");
t->set_template_name("3D First Person");
t->set_description("First-person 3D template with mouselook, movement, and basic shooting mechanics.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_AETHEX | AeThexTemplate::PLATFORM_UEFN | AeThexTemplate::PLATFORM_UNITY);
t->set_difficulty(AeThexTemplate::DIFFICULTY_INTERMEDIATE);
t->set_is_builtin(true);
PackedStringArray tags;
tags.push_back("3d");
tags.push_back("fps");
tags.push_back("shooter");
t->set_tags(tags);
return t;
}
Ref<AeThexTemplate> create_rpg_starter() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_rpg_starter");
t->set_template_name("RPG Starter Kit");
t->set_description("Complete RPG foundation with inventory, dialogue, and combat systems.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_ALL);
t->set_difficulty(AeThexTemplate::DIFFICULTY_ADVANCED);
t->set_is_builtin(true);
return t;
}
Ref<AeThexTemplate> create_multiplayer_game() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_multiplayer");
t->set_template_name("Multiplayer Game");
t->set_description("Network-enabled game template with lobby, matchmaking, and sync.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_ALL);
t->set_difficulty(AeThexTemplate::DIFFICULTY_ADVANCED);
t->set_is_builtin(true);
return t;
}
Ref<AeThexTemplate> create_roblox_experience() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_roblox_experience");
t->set_template_name("Roblox Experience");
t->set_description("Template optimized for Roblox with AeThex-to-Luau compilation.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_ROBLOX | AeThexTemplate::PLATFORM_AETHEX);
t->set_difficulty(AeThexTemplate::DIFFICULTY_BEGINNER);
t->set_is_builtin(true);
Dictionary files;
files["game.aethex"] = R"(// Roblox Experience - AeThex Script
// Compiles to Luau for Roblox deployment
reality RobloxGame {
beacon players: Array = []
beacon game_started: Boolean = false
journey on_player_join(player) {
players.add(player)
reveal("Welcome, " + player.name + "!")
if players.length >= 2 and not game_started {
start_game()
}
}
journey start_game() {
game_started = true
notify("game_started")
// Cross-platform compatible!
sync across {
reveal("Game starting!")
}
}
}
)";
t->set_file_structure(files);
return t;
}
Ref<AeThexTemplate> create_uefn_island() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_uefn_island");
t->set_template_name("UEFN Island");
t->set_description("Fortnite Creative island template with AeThex-to-Verse compilation.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_UEFN | AeThexTemplate::PLATFORM_AETHEX);
t->set_difficulty(AeThexTemplate::DIFFICULTY_BEGINNER);
t->set_is_builtin(true);
return t;
}
Ref<AeThexTemplate> create_unity_mobile() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_unity_mobile");
t->set_template_name("Unity Mobile");
t->set_description("Mobile game template targeting Unity export with touch controls.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_UNITY | AeThexTemplate::PLATFORM_AETHEX);
t->set_difficulty(AeThexTemplate::DIFFICULTY_INTERMEDIATE);
t->set_is_builtin(true);
return t;
}
Ref<AeThexTemplate> create_web_game() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_web_game");
t->set_template_name("Web Game");
t->set_description("Browser-based game with HTML5 export and JavaScript compilation.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_WEB | AeThexTemplate::PLATFORM_AETHEX);
t->set_difficulty(AeThexTemplate::DIFFICULTY_BEGINNER);
t->set_is_builtin(true);
return t;
}
Ref<AeThexTemplate> create_crossplatform_game() {
Ref<AeThexTemplate> t;
t.instantiate();
t->set_id("builtin_crossplatform");
t->set_template_name("Cross-Platform Game");
t->set_description("Ultimate template supporting ALL platforms: Roblox, UEFN, Unity, and Web.");
t->set_author("AeThex Labs");
t->set_version("1.0.0");
t->set_category(AeThexTemplate::CATEGORY_GAME);
t->set_platforms(AeThexTemplate::PLATFORM_ALL);
t->set_difficulty(AeThexTemplate::DIFFICULTY_INTERMEDIATE);
t->set_is_builtin(true);
PackedStringArray features;
features.push_back("Write once, deploy everywhere");
features.push_back("Platform-specific optimizations");
features.push_back("Unified networking layer");
features.push_back("Asset pipeline for all platforms");
t->set_features(features);
Dictionary files;
files["main.aethex"] = R"(// Cross-Platform AeThex Game
// This code runs on Roblox, UEFN, Unity, Web, and native AeThex!
reality CrossPlatformGame {
beacon score: Number = 0
beacon player_name: String = "Player"
journey start() {
reveal("Welcome to Cross-Platform Gaming!")
reveal("Running on: " + get_platform())
setup_game()
}
journey setup_game() {
// Platform-agnostic game logic
sync across {
spawn_player()
load_level(1)
}
}
journey add_score(points: Number) {
score += points
notify("score_updated", score)
// Sync across all platforms and clients
sync across {
update_leaderboard(player_name, score)
}
}
}
)";
files["player.aethex"] = R"(// Universal Player Controller
reality Player {
beacon health: Number = 100
beacon position: Vector3 = (0, 0, 0)
journey take_damage(amount: Number) {
health -= amount
if health <= 0 {
on_death()
}
}
journey on_death() {
notify("player_died")
respawn()
}
}
)";
t->set_file_structure(files);
return t;
}
} // namespace AeThexBuiltinTemplates