Advertisement

Script instance in other script

Started by February 25, 2025 09:58 AM
0 comments, last by Svenvh 5 hours, 8 minutes ago

Hi, I'm trying to recreate a Unity-like scripting system using Angelscript. I have an ECS and each entity can hold scripts. Each script has a start, update, and end. These function get called from the C++ side for updating.

Right now, I can access the default components I made in C++ (like transform). But what would be even better is if I could access a script instance from within a different script. Without knowing whats inside the script beforehand on the C++ side. For example:

class Player {


    float health;


    Player(GameEntity e) {
    }


    void OnStart() {
    }


    void OnUpdate(float dt) {
    }


    void OnEnd() {
    }


    void TakeDamage(float hp){
        health -= hp;
    }


}

Then in a different script:

class Manager {


    GameEntity player;


    Manager(GameEntity e) {
    }


    void OnStart() {
    }


    void OnUpdate(float dt) {
        player.GetScript("Player").TakeDamage(10);
        //or
        player.GetPlayerScript().TakeDamage(10);
    }


    void OnEnd() {
    }


}

Would this be possible?

For more context. This is currently the way I initialize the scripts:

void kudzu::Script::InitializeScript(const std::string& scriptName, const std::string& className, const std::string& source)
{
   path = scriptName;
   m_className = className;
   m_source = source;
   asIScriptEngine* engine = kudzu::Engine.scripting_engine().get_engine();
   if (!engine)
   {
       kudzu::Log::Error("ScriptResource: engine is null");
       return;
   }
   CScriptBuilder builder;
   int r;
   r = builder.StartNewModule(engine, scriptName.c_str());
   assert(r >= 0);
   r = builder.AddSectionFromMemory(scriptName.c_str(), source.c_str());
   if (r < 0)
   {
       kudzu::Log::Error("AddSectionFromMemory failed");
       return;
   }
   r = builder.BuildModule();
   if (r < 0)
   {
       kudzu::Log::Error("BuildModule failed");
       return;
   }
   m_module = engine->GetModule(scriptName.c_str());
   if (!m_module)
   {
       kudzu::Log::Error("Failed to create module for script: {}", scriptName);
       return;
   }
   m_scriptType = m_module->GetTypeInfoByName(className.c_str());
   if (!m_scriptType)
   {
       kudzu::Log::Error("Could not find class '{}' in script.", className);
   }
   int typeId = m_scriptType->GetTypeId();
   int propertyCount = m_scriptType->GetPropertyCount();
   for (int i = 0; i < propertyCount; i++)
   {
       const char* propName;
       int propTypeId;
       r = m_scriptType->GetProperty(i, &propName, &propTypeId);
       if (r < 0)
       {
           kudzu::Log::Error("Failed to get property info");
           continue;
       }
       std::vector<std::string> metadata = builder.GetMetadataForTypeProperty(typeId, i);
       for (auto& md : metadata)
       {
           std::string typeDecl = engine->GetTypeDeclaration(propTypeId);
           auto info = PropertyInfo(i, propName, propTypeId, typeDecl);
           if (md == "editable")
           {
               kudzu::Log::Info("Found editable property: {}", propName);
               m_editableProperties.push_back(info);
           }
           if (md == "serialize")
           {
               kudzu::Log::Info("Found serialize property: {}", propName);
               m_serializableProperties.push_back(info);
           }
       }
   }
}
kudzu::Script::~Script() {}
std::shared_ptr<kudzu::ScriptInstance> kudzu::Script::CreateInstance(const entt::entity entity, const bool addToList)
{
   if (!m_scriptType)
   {
       Log::Error("Failed creating script instance. Script type is null");
       return nullptr;
   }
   bool isValid = IsValid();
   asIScriptEngine* engine = kudzu::Engine.scripting_engine().get_engine();
   // get constructor
   auto decl = m_className + "@ " + m_className + "(GameEntity)";
   asIScriptFunction* factory = m_scriptType->GetFactoryByDecl(decl.c_str());
   if (!factory)
   {
       Log::Error("Failed creating script instance. No factory found for script type {}", m_scriptType->GetName());
       isValid = false;
   }
   asIScriptContext* ctx = engine->CreateContext();
   int r = ctx->Prepare(factory);
   if (r < 0)
   {
       Log::Error("Failed creating script instance. Failed to prepare factory for script type {}", m_scriptType->GetName());
       ctx->Release();
       isValid = false;
   }
   GameEntity* gameEntity = new GameEntity(entity);
   ctx->SetArgObject(0, gameEntity);
   r = ctx->Execute();
   if (r != asEXECUTION_FINISHED)
   {
       Log::Error("Failed creating script instance. Factory execution didn't finish properly");
       ctx->Release();
       isValid = false;
   }
   auto** retAddress = reinterpret_cast<asIScriptObject**>(ctx->GetAddressOfReturnValue());
   asIScriptObject* obj = (retAddress ? *retAddress : nullptr);
   if (obj)
   {
       obj->AddRef();
   }
   ctx->Release();
   auto instance = std::make_shared<ScriptInstance>();
   instance->instance = obj;
   instance->onStart = m_scriptType->GetMethodByName("OnStart");
   instance->onUpdate = m_scriptType->GetMethodByName("OnUpdate");
   instance->onEnd = m_scriptType->GetMethodByName("OnEnd");
   instance->initialized = false;
   instance->entity = entity;
   instance->valid = isValid;
   if (addToList)
   {
       m_instances.push_back(instance);
   }
   return instance;
}

Any help or suggestions would be greatly appreciated!

Advertisement