800 lines
21 KiB
C++
800 lines
21 KiB
C++
/**************************************************************************/
|
|
/* aethex_script.cpp */
|
|
/**************************************************************************/
|
|
/* This file is part of: */
|
|
/* AETHEX ENGINE */
|
|
/* https://aethex.foundation */
|
|
/**************************************************************************/
|
|
/* Copyright (c) 2026-present AeThex Labs. */
|
|
/* Based on AETHEX ENGINE, MIT License. */
|
|
/**************************************************************************/
|
|
|
|
#include "aethex_script.h"
|
|
|
|
#include "aethex_tokenizer.h"
|
|
#include "aethex_parser.h"
|
|
#include "aethex_compiler.h"
|
|
|
|
#include "core/config/project_settings.h"
|
|
#include "core/io/file_access.h"
|
|
#include "core/math/math_defs.h"
|
|
|
|
// ============================================================================
|
|
// AeThexScriptLanguage
|
|
// ============================================================================
|
|
|
|
AeThexScriptLanguage *AeThexScriptLanguage::singleton = nullptr;
|
|
|
|
AeThexScriptLanguage::AeThexScriptLanguage() {
|
|
ERR_FAIL_COND(singleton);
|
|
singleton = this;
|
|
}
|
|
|
|
AeThexScriptLanguage::~AeThexScriptLanguage() {
|
|
singleton = nullptr;
|
|
}
|
|
|
|
void AeThexScriptLanguage::init() {
|
|
// Register built-in constants
|
|
global_constants["PI"] = Math::PI;
|
|
global_constants["TAU"] = Math::TAU;
|
|
global_constants["INF"] = INFINITY;
|
|
global_constants["NAN"] = NAN;
|
|
|
|
print_line("AeThex Language initialized - Write once, deploy everywhere!");
|
|
}
|
|
|
|
void AeThexScriptLanguage::finish() {
|
|
global_constants.clear();
|
|
}
|
|
|
|
Vector<String> AeThexScriptLanguage::get_reserved_words() const {
|
|
Vector<String> words;
|
|
// AeThex keywords
|
|
static const char *keywords[] = {
|
|
// Core constructs
|
|
"reality", // Module/namespace declaration
|
|
"journey", // Cross-platform function
|
|
"portal", // Import/export
|
|
"beacon", // Event/signal
|
|
"artifact", // Class/object
|
|
"essence", // Interface/trait
|
|
"chronicle", // Enum
|
|
|
|
// Control flow
|
|
"when", // If/condition
|
|
"otherwise", // Else
|
|
"traverse", // For loop
|
|
"while", // While loop
|
|
"break",
|
|
"continue",
|
|
"return",
|
|
"yield",
|
|
|
|
// Data
|
|
"let", // Variable
|
|
"const", // Constant
|
|
"mut", // Mutable
|
|
"new", // Instance creation
|
|
|
|
// Platform-specific
|
|
"platform", // Platform declaration
|
|
"sync", // Cross-platform sync
|
|
"async", // Async operation
|
|
"await", // Await async
|
|
|
|
// Actions
|
|
"notify", // Output/print
|
|
"reveal", // Return/expose
|
|
"summon", // Create/spawn
|
|
"banish", // Destroy/remove
|
|
|
|
// Compliance (built-in)
|
|
"Passport", // Auth identity
|
|
"Shield", // Data protection
|
|
"Consent", // COPPA/GDPR
|
|
|
|
// Literals
|
|
"true",
|
|
"false",
|
|
"null",
|
|
"self",
|
|
"super",
|
|
|
|
nullptr
|
|
};
|
|
|
|
const char **w = keywords;
|
|
while (*w) {
|
|
words.push_back(*w);
|
|
w++;
|
|
}
|
|
return words;
|
|
}
|
|
|
|
bool AeThexScriptLanguage::is_control_flow_keyword(const String &p_keyword) const {
|
|
return p_keyword == "when" || p_keyword == "otherwise" || p_keyword == "traverse" ||
|
|
p_keyword == "while" || p_keyword == "break" || p_keyword == "continue" ||
|
|
p_keyword == "return" || p_keyword == "yield";
|
|
}
|
|
|
|
Vector<String> AeThexScriptLanguage::get_comment_delimiters() const {
|
|
Vector<String> delimiters;
|
|
delimiters.push_back("# "); // Single line comment
|
|
delimiters.push_back("/* */"); // Block comment
|
|
return delimiters;
|
|
}
|
|
|
|
Vector<String> AeThexScriptLanguage::get_doc_comment_delimiters() const {
|
|
Vector<String> delimiters;
|
|
delimiters.push_back("## "); // Doc comment
|
|
return delimiters;
|
|
}
|
|
|
|
Vector<String> AeThexScriptLanguage::get_string_delimiters() const {
|
|
Vector<String> delimiters;
|
|
delimiters.push_back("\" \"");
|
|
delimiters.push_back("' '");
|
|
delimiters.push_back("` `"); // Template strings
|
|
return delimiters;
|
|
}
|
|
|
|
Ref<Script> AeThexScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const {
|
|
Ref<AeThexScript> script;
|
|
script.instantiate();
|
|
|
|
String template_code = p_template;
|
|
if (template_code.is_empty()) {
|
|
template_code = R"(# AeThex Script
|
|
# Write once, deploy to Roblox, UEFN, Unity, and Web
|
|
|
|
reality %CLASS% {
|
|
platforms: [roblox, uefn, web]
|
|
extends: %BASE%
|
|
}
|
|
|
|
journey _ready() {
|
|
platform: all
|
|
notify "Hello from AeThex!"
|
|
}
|
|
|
|
journey _process(delta) {
|
|
platform: all
|
|
# Your game logic here
|
|
}
|
|
)";
|
|
}
|
|
|
|
template_code = template_code.replace("%CLASS%", p_class_name);
|
|
template_code = template_code.replace("%BASE%", p_base_class_name);
|
|
script->set_source_code(template_code);
|
|
|
|
return script;
|
|
}
|
|
|
|
Vector<ScriptLanguage::ScriptTemplate> AeThexScriptLanguage::get_built_in_templates(const StringName &p_object) {
|
|
Vector<ScriptTemplate> templates;
|
|
|
|
// Basic template
|
|
ScriptTemplate basic;
|
|
basic.inherit = "Node";
|
|
basic.name = "AeThex Basic";
|
|
basic.description = "Basic AeThex script with cross-platform support";
|
|
basic.content = R"(# %CLASS_NAME%
|
|
reality %CLASS_NAME% {
|
|
platforms: [roblox, uefn, web]
|
|
extends: %BASE_CLASS_NAME%
|
|
}
|
|
|
|
journey _ready() {
|
|
platform: all
|
|
notify "%CLASS_NAME% ready!"
|
|
}
|
|
)";
|
|
templates.push_back(basic);
|
|
|
|
// Player controller
|
|
ScriptTemplate player;
|
|
player.inherit = "CharacterBody3D";
|
|
player.name = "AeThex Player Controller";
|
|
player.description = "Cross-platform player movement";
|
|
player.content = R"(# %CLASS_NAME%
|
|
# Cross-platform player controller
|
|
|
|
reality %CLASS_NAME% {
|
|
platforms: [roblox, uefn, web]
|
|
extends: %BASE_CLASS_NAME%
|
|
}
|
|
|
|
let speed = 5.0
|
|
let jump_velocity = 4.5
|
|
let gravity = 9.8
|
|
|
|
journey _process(delta) {
|
|
platform: all
|
|
|
|
let velocity = self.velocity
|
|
|
|
# Apply gravity
|
|
when not self.is_on_floor() {
|
|
velocity.y = velocity.y - gravity * delta
|
|
}
|
|
|
|
# Handle jump
|
|
when Input.is_action_just_pressed("jump") and self.is_on_floor() {
|
|
velocity.y = jump_velocity
|
|
}
|
|
|
|
# Get input direction
|
|
let input_dir = Input.get_vector("left", "right", "forward", "backward")
|
|
let direction = (self.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
|
|
|
when direction {
|
|
velocity.x = direction.x * speed
|
|
velocity.z = direction.z * speed
|
|
} otherwise {
|
|
velocity.x = move_toward(velocity.x, 0, speed)
|
|
velocity.z = move_toward(velocity.z, 0, speed)
|
|
}
|
|
|
|
self.velocity = velocity
|
|
self.move_and_slide()
|
|
}
|
|
)";
|
|
templates.push_back(player);
|
|
|
|
// Multiplayer sync
|
|
ScriptTemplate multiplayer;
|
|
multiplayer.inherit = "Node";
|
|
multiplayer.name = "AeThex Multiplayer";
|
|
multiplayer.description = "Cross-platform multiplayer sync";
|
|
multiplayer.content = R"(# %CLASS_NAME%
|
|
# Cross-platform multiplayer with automatic sync
|
|
|
|
reality %CLASS_NAME% {
|
|
platforms: [roblox, uefn, web]
|
|
extends: %BASE_CLASS_NAME%
|
|
}
|
|
|
|
let player_data = {}
|
|
|
|
journey OnPlayerJoin(player) {
|
|
platform: all
|
|
|
|
let passport = new Passport(player.id)
|
|
|
|
when passport.verify() {
|
|
player_data[player.id] = {
|
|
"name": player.name,
|
|
"score": 0,
|
|
"inventory": []
|
|
}
|
|
|
|
sync player_data[player.id] across [roblox, uefn, web]
|
|
notify player.name + " joined the game!"
|
|
}
|
|
}
|
|
|
|
journey UpdateScore(player_id, points) {
|
|
platform: all
|
|
|
|
when player_data.has(player_id) {
|
|
player_data[player_id].score += points
|
|
sync player_data[player_id].score across all
|
|
}
|
|
}
|
|
|
|
beacon ScoreChanged(player_id, new_score)
|
|
)";
|
|
templates.push_back(multiplayer);
|
|
|
|
return templates;
|
|
}
|
|
|
|
bool AeThexScriptLanguage::validate(const String &p_script, const String &p_path,
|
|
List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors,
|
|
List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const {
|
|
|
|
// TODO: Implement full validation with AeThexParser
|
|
// For now, basic syntax checking
|
|
|
|
if (p_script.is_empty()) {
|
|
return true;
|
|
}
|
|
|
|
// Check for required reality block
|
|
if (!p_script.contains("reality ")) {
|
|
if (r_errors) {
|
|
ScriptError err;
|
|
err.line = 1;
|
|
err.column = 1;
|
|
err.message = "AeThex scripts must have a 'reality' block declaration";
|
|
r_errors->push_back(err);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int AeThexScriptLanguage::find_function(const String &p_function, const String &p_code) const {
|
|
// Find function in code - search for "journey function_name"
|
|
String search = "journey " + p_function;
|
|
int pos = p_code.find(search);
|
|
if (pos == -1) {
|
|
return -1;
|
|
}
|
|
// Count newlines to get line number
|
|
int line = 1;
|
|
for (int i = 0; i < pos; i++) {
|
|
if (p_code[i] == '\n') {
|
|
line++;
|
|
}
|
|
}
|
|
return line;
|
|
}
|
|
|
|
String AeThexScriptLanguage::make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const {
|
|
String args_str;
|
|
for (int i = 0; i < p_args.size(); i++) {
|
|
if (i > 0) {
|
|
args_str += ", ";
|
|
}
|
|
args_str += p_args[i];
|
|
}
|
|
return "journey " + p_name + "(" + args_str + ") {\n platform: all\n # TODO: Implement\n}\n";
|
|
}
|
|
|
|
String AeThexScriptLanguage::debug_get_error() const {
|
|
return String();
|
|
}
|
|
|
|
int AeThexScriptLanguage::debug_get_stack_level_count() const {
|
|
return 0;
|
|
}
|
|
|
|
int AeThexScriptLanguage::debug_get_stack_level_line(int p_level) const {
|
|
return 0;
|
|
}
|
|
|
|
String AeThexScriptLanguage::debug_get_stack_level_function(int p_level) const {
|
|
return String();
|
|
}
|
|
|
|
String AeThexScriptLanguage::debug_get_stack_level_source(int p_level) const {
|
|
return String();
|
|
}
|
|
|
|
void AeThexScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
|
|
}
|
|
|
|
void AeThexScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
|
|
}
|
|
|
|
void AeThexScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
|
|
}
|
|
|
|
String AeThexScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
|
|
return String();
|
|
}
|
|
|
|
void AeThexScriptLanguage::frame() {
|
|
// Called every frame
|
|
}
|
|
|
|
void AeThexScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
|
|
global_constants[p_variable] = p_value;
|
|
}
|
|
|
|
void AeThexScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
|
|
p_extensions->push_back("aethex");
|
|
}
|
|
|
|
bool AeThexScriptLanguage::handles_global_class_type(const String &p_type) const {
|
|
return p_type == "AeThexScript";
|
|
}
|
|
|
|
String AeThexScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path, bool *r_is_abstract, bool *r_is_tool) const {
|
|
if (!p_path.ends_with(".aethex")) {
|
|
return String();
|
|
}
|
|
|
|
// Parse the file to extract class name from reality block
|
|
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
|
|
if (f.is_null()) {
|
|
return String();
|
|
}
|
|
|
|
String source = f->get_as_text();
|
|
|
|
// Simple regex-like extraction of reality ClassName
|
|
int reality_pos = source.find("reality ");
|
|
if (reality_pos != -1) {
|
|
int name_start = reality_pos + 8;
|
|
int name_end = source.find_char(' ', name_start);
|
|
if (name_end == -1) {
|
|
name_end = source.find_char('{', name_start);
|
|
}
|
|
if (name_end != -1) {
|
|
return source.substr(name_start, name_end - name_start).strip_edges();
|
|
}
|
|
}
|
|
|
|
return String();
|
|
}
|
|
|
|
String AeThexScriptLanguage::export_to_target(const String &p_source, ExportTarget p_target) const {
|
|
// Use the AeThex compiler to cross-compile
|
|
// This integrates with the standalone AeThex-Lang compiler
|
|
|
|
// Parse the source first
|
|
AeThexTokenizer tokenizer;
|
|
tokenizer.tokenize(p_source);
|
|
|
|
AeThexParser parser;
|
|
parser.parse(tokenizer.get_tokens());
|
|
|
|
if (!parser.get_errors().is_empty()) {
|
|
return "// Compilation error: " + parser.get_errors()[0].message;
|
|
}
|
|
|
|
const AeThexParser::ASTNode *root = parser.get_root();
|
|
|
|
AeThexCompiler compiler;
|
|
|
|
switch (p_target) {
|
|
case EXPORT_ROBLOX:
|
|
return compiler.export_to_luau(root);
|
|
case EXPORT_UEFN:
|
|
return compiler.export_to_verse(root);
|
|
case EXPORT_UNITY:
|
|
return compiler.export_to_csharp(root);
|
|
case EXPORT_WEB:
|
|
return compiler.export_to_javascript(root);
|
|
case EXPORT_ENGINE:
|
|
default:
|
|
return p_source; // Native execution
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// AeThexScript
|
|
// ============================================================================
|
|
|
|
void AeThexScript::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("export_to_lua"), &AeThexScript::export_to_lua);
|
|
ClassDB::bind_method(D_METHOD("export_to_verse"), &AeThexScript::export_to_verse);
|
|
ClassDB::bind_method(D_METHOD("export_to_csharp"), &AeThexScript::export_to_csharp);
|
|
ClassDB::bind_method(D_METHOD("export_to_javascript"), &AeThexScript::export_to_javascript);
|
|
}
|
|
|
|
AeThexScript::AeThexScript() {
|
|
}
|
|
|
|
AeThexScript::~AeThexScript() {
|
|
}
|
|
|
|
bool AeThexScript::can_instantiate() const {
|
|
return valid;
|
|
}
|
|
|
|
Ref<Script> AeThexScript::get_base_script() const {
|
|
return Ref<Script>();
|
|
}
|
|
|
|
StringName AeThexScript::get_global_name() const {
|
|
return StringName();
|
|
}
|
|
|
|
bool AeThexScript::inherits_script(const Ref<Script> &p_script) const {
|
|
return false;
|
|
}
|
|
|
|
StringName AeThexScript::get_instance_base_type() const {
|
|
return StringName("Node");
|
|
}
|
|
|
|
ScriptInstance *AeThexScript::instance_create(Object *p_this) {
|
|
AeThexScriptInstance *instance = memnew(AeThexScriptInstance);
|
|
instance->set_owner(p_this);
|
|
instance->set_script(Ref<AeThexScript>(this));
|
|
return instance;
|
|
}
|
|
|
|
PlaceHolderScriptInstance *AeThexScript::placeholder_instance_create(Object *p_this) {
|
|
return nullptr;
|
|
}
|
|
|
|
bool AeThexScript::instance_has(const Object *p_this) const {
|
|
return false;
|
|
}
|
|
|
|
bool AeThexScript::has_source_code() const {
|
|
return !source_code.is_empty();
|
|
}
|
|
|
|
String AeThexScript::get_source_code() const {
|
|
return source_code;
|
|
}
|
|
|
|
void AeThexScript::set_source_code(const String &p_code) {
|
|
source_code = p_code;
|
|
}
|
|
|
|
Error AeThexScript::reload(bool p_keep_state) {
|
|
// Parse and compile the source
|
|
valid = false;
|
|
functions.clear();
|
|
constants.clear();
|
|
target_platforms.clear();
|
|
|
|
if (source_code.is_empty()) {
|
|
return OK;
|
|
}
|
|
|
|
// TODO: Full parsing with AeThexParser
|
|
// For now, basic validation
|
|
|
|
// Extract platforms from reality block
|
|
int platforms_pos = source_code.find("platforms:");
|
|
if (platforms_pos != -1) {
|
|
int start = source_code.find("[", platforms_pos);
|
|
int end = source_code.find("]", start);
|
|
if (start != -1 && end != -1) {
|
|
String platforms_str = source_code.substr(start + 1, end - start - 1);
|
|
Vector<String> platforms = platforms_str.split(",");
|
|
for (const String &p : platforms) {
|
|
target_platforms.insert(p.strip_edges());
|
|
}
|
|
}
|
|
}
|
|
|
|
valid = true;
|
|
return OK;
|
|
}
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
Vector<DocData::ClassDoc> AeThexScript::get_documentation() const {
|
|
return Vector<DocData::ClassDoc>();
|
|
}
|
|
|
|
String AeThexScript::get_class_icon_path() const {
|
|
return "res://addons/aethex/icons/aethex_script.svg";
|
|
}
|
|
|
|
PropertyInfo AeThexScript::get_class_category() const {
|
|
return PropertyInfo(Variant::STRING, "AeThex");
|
|
}
|
|
#endif
|
|
|
|
bool AeThexScript::has_method(const StringName &p_method) const {
|
|
for (const CompiledFunction &f : functions) {
|
|
if (f.name == p_method) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
MethodInfo AeThexScript::get_method_info(const StringName &p_method) const {
|
|
for (const CompiledFunction &f : functions) {
|
|
if (f.name == p_method) {
|
|
MethodInfo mi;
|
|
mi.name = f.name;
|
|
for (const String ¶m : f.parameters) {
|
|
mi.arguments.push_back(PropertyInfo(Variant::NIL, param));
|
|
}
|
|
return mi;
|
|
}
|
|
}
|
|
return MethodInfo();
|
|
}
|
|
|
|
ScriptLanguage *AeThexScript::get_language() const {
|
|
return AeThexScriptLanguage::get_singleton();
|
|
}
|
|
|
|
const Variant AeThexScript::get_rpc_config() const {
|
|
return Dictionary();
|
|
}
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
StringName AeThexScript::get_doc_class_name() const {
|
|
return StringName();
|
|
}
|
|
#endif
|
|
|
|
bool AeThexScript::has_script_signal(const StringName &p_signal) const {
|
|
return false;
|
|
}
|
|
|
|
void AeThexScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
|
|
}
|
|
|
|
bool AeThexScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
|
|
return false;
|
|
}
|
|
|
|
void AeThexScript::update_exports() {
|
|
}
|
|
|
|
void AeThexScript::get_script_method_list(List<MethodInfo> *p_list) const {
|
|
for (const CompiledFunction &f : functions) {
|
|
MethodInfo mi;
|
|
mi.name = f.name;
|
|
p_list->push_back(mi);
|
|
}
|
|
}
|
|
|
|
void AeThexScript::get_script_property_list(List<PropertyInfo> *p_list) const {
|
|
}
|
|
|
|
int AeThexScript::get_member_line(const StringName &p_member) const {
|
|
return -1;
|
|
}
|
|
|
|
void AeThexScript::get_constants(HashMap<StringName, Variant> *p_constants) {
|
|
for (const KeyValue<StringName, Variant> &E : constants) {
|
|
p_constants->insert(E.key, E.value);
|
|
}
|
|
}
|
|
|
|
void AeThexScript::get_members(HashSet<StringName> *p_members) {
|
|
}
|
|
|
|
// Cross-platform export methods
|
|
String AeThexScript::export_to_lua() const {
|
|
return AeThexScriptLanguage::get_singleton()->export_to_target(source_code, AeThexScriptLanguage::EXPORT_ROBLOX);
|
|
}
|
|
|
|
String AeThexScript::export_to_verse() const {
|
|
return AeThexScriptLanguage::get_singleton()->export_to_target(source_code, AeThexScriptLanguage::EXPORT_UEFN);
|
|
}
|
|
|
|
String AeThexScript::export_to_csharp() const {
|
|
return AeThexScriptLanguage::get_singleton()->export_to_target(source_code, AeThexScriptLanguage::EXPORT_UNITY);
|
|
}
|
|
|
|
String AeThexScript::export_to_javascript() const {
|
|
return AeThexScriptLanguage::get_singleton()->export_to_target(source_code, AeThexScriptLanguage::EXPORT_WEB);
|
|
}
|
|
|
|
// ============================================================================
|
|
// AeThexScriptInstance
|
|
// ============================================================================
|
|
|
|
AeThexScriptInstance::AeThexScriptInstance() {
|
|
}
|
|
|
|
AeThexScriptInstance::~AeThexScriptInstance() {
|
|
}
|
|
|
|
bool AeThexScriptInstance::set(const StringName &p_name, const Variant &p_value) {
|
|
members[p_name] = p_value;
|
|
return true;
|
|
}
|
|
|
|
bool AeThexScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
|
|
if (members.has(p_name)) {
|
|
r_ret = members[p_name];
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void AeThexScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
|
|
}
|
|
|
|
Variant::Type AeThexScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
|
|
return Variant::NIL;
|
|
}
|
|
|
|
void AeThexScriptInstance::validate_property(PropertyInfo &p_property) const {
|
|
}
|
|
|
|
bool AeThexScriptInstance::property_can_revert(const StringName &p_name) const {
|
|
return false;
|
|
}
|
|
|
|
bool AeThexScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
|
|
return false;
|
|
}
|
|
|
|
void AeThexScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
|
|
if (script.is_valid()) {
|
|
script->get_script_method_list(p_list);
|
|
}
|
|
}
|
|
|
|
bool AeThexScriptInstance::has_method(const StringName &p_method) const {
|
|
if (script.is_valid()) {
|
|
return script->has_method(p_method);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Variant AeThexScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
|
// TODO: Implement AeThex VM execution
|
|
r_error.error = Callable::CallError::CALL_OK;
|
|
return Variant();
|
|
}
|
|
|
|
void AeThexScriptInstance::notification(int p_notification, bool p_reversed) {
|
|
}
|
|
|
|
Ref<Script> AeThexScriptInstance::get_script() const {
|
|
return script;
|
|
}
|
|
|
|
ScriptLanguage *AeThexScriptInstance::get_language() {
|
|
return AeThexScriptLanguage::get_singleton();
|
|
}
|
|
|
|
// ============================================================================
|
|
// Resource Format Loader/Saver
|
|
// ============================================================================
|
|
|
|
Ref<Resource> ResourceFormatLoaderAeThexScript::load(const String &p_path, const String &p_original_path,
|
|
Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
|
|
|
Ref<AeThexScript> script;
|
|
script.instantiate();
|
|
|
|
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
|
|
if (f.is_null()) {
|
|
if (r_error) {
|
|
*r_error = ERR_CANT_OPEN;
|
|
}
|
|
return Ref<Resource>();
|
|
}
|
|
|
|
String source = f->get_as_text();
|
|
script->set_source_code(source);
|
|
script->reload();
|
|
|
|
if (r_error) {
|
|
*r_error = OK;
|
|
}
|
|
|
|
return script;
|
|
}
|
|
|
|
void ResourceFormatLoaderAeThexScript::get_recognized_extensions(List<String> *p_extensions) const {
|
|
p_extensions->push_back("aethex");
|
|
}
|
|
|
|
bool ResourceFormatLoaderAeThexScript::handles_type(const String &p_type) const {
|
|
return p_type == "Script" || p_type == "AeThexScript";
|
|
}
|
|
|
|
String ResourceFormatLoaderAeThexScript::get_resource_type(const String &p_path) const {
|
|
if (p_path.get_extension().to_lower() == "aethex") {
|
|
return "AeThexScript";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
Error ResourceFormatSaverAeThexScript::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
|
|
Ref<AeThexScript> script = p_resource;
|
|
if (script.is_null()) {
|
|
return ERR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
|
|
if (f.is_null()) {
|
|
return ERR_CANT_OPEN;
|
|
}
|
|
|
|
f->store_string(script->get_source_code());
|
|
return OK;
|
|
}
|
|
|
|
void ResourceFormatSaverAeThexScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
|
|
if (Object::cast_to<AeThexScript>(*p_resource)) {
|
|
p_extensions->push_back("aethex");
|
|
}
|
|
}
|
|
|
|
bool ResourceFormatSaverAeThexScript::recognize(const Ref<Resource> &p_resource) const {
|
|
return Object::cast_to<AeThexScript>(*p_resource) != nullptr;
|
|
}
|