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
720 lines
24 KiB
C++
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
|