From d2608b48515012135a0e27823123ef5992f075de Mon Sep 17 00:00:00 2001 From: Joey Pollack Date: Tue, 22 Nov 2022 16:00:08 -0500 Subject: [PATCH] Entity component access and manipulation in wren scripts working! --- .../internal_scripts/components.wren | 9 +- .../internal_scripts/world_interface.wren | 6 +- src/scripting/wren_state.cpp | 25 +++++ src/scripting/wren_state.h | 3 +- src/world/world.cpp | 97 +++++++------------ src/world/world.h | 2 +- src/world/world_api.cpp | 76 ++++++++++++++- src/world/world_api.h | 8 ++ 8 files changed, 154 insertions(+), 72 deletions(-) diff --git a/src/scripting/internal_scripts/components.wren b/src/scripting/internal_scripts/components.wren index 1c7e825..6e3a25d 100644 --- a/src/scripting/internal_scripts/components.wren +++ b/src/scripting/internal_scripts/components.wren @@ -10,12 +10,13 @@ foreign class VelocityComponent { // The parameter will be used on the C++ side to set the correct C++ component - construct new(entity_id) { - super.EntityID = entity_id - } + construct new(entity_id) {} // maybe wrap these in non-foreign methods // to abstract pulling data out of slots? - foreign GetVelocity() + foreign GetVelocityX() + foreign GetVelocityY() foreign SetVelocity(x, y) + + } \ No newline at end of file diff --git a/src/scripting/internal_scripts/world_interface.wren b/src/scripting/internal_scripts/world_interface.wren index 3a2c2c6..fc7c505 100644 --- a/src/scripting/internal_scripts/world_interface.wren +++ b/src/scripting/internal_scripts/world_interface.wren @@ -6,6 +6,8 @@ * Description - The main interface for scripts to interact with the game world ******************************************************************************/ +import "Components" for VelocityComponent + // Manages all of the EntityBehaviors class WorldInterface { @@ -46,7 +48,9 @@ class WorldInterface { // API ///////////////////////////////////////////////////////////////////// - //foreign static GetVelocityComponent(entity_id) + static GetVelocityComponent(entity_id) { + return VelocityComponent.new(entity_id) + } } diff --git a/src/scripting/wren_state.cpp b/src/scripting/wren_state.cpp index 2c0ef7e..3c36e79 100644 --- a/src/scripting/wren_state.cpp +++ b/src/scripting/wren_state.cpp @@ -16,6 +16,7 @@ namespace lunarium { std::vector WrenState::mForeignMethods; + std::vector WrenState::mForeignClasses; WrenState::~WrenState() { @@ -36,6 +37,7 @@ namespace lunarium config.writeFn = WrenState::WriteFN; config.errorFn = WrenState::ErrorFN; config.bindForeignMethodFn = WrenState::BindForeignMethodFN; + config.bindForeignClassFn = WrenState::BindForeignClassFN; mpVM = wrenNewVM(&config); @@ -54,6 +56,11 @@ namespace lunarium mForeignMethods.push_back(method_desc); } + void WrenState::RegisterForeignClass(ForeignClassDesc class_desc) + { + mForeignClasses.push_back(class_desc); + } + ///////////////////////////////////////////////////////////////////// // HANDLES ///////////////////////////////////////////////////////////////////// @@ -185,6 +192,7 @@ namespace lunarium { if (FMID == (*iter)) { + Logger::Trace(mLogCat, "Successfully bound foreign method: %s::%s", class_name, signature); return iter->FM; } } @@ -192,4 +200,21 @@ namespace lunarium Logger::Error(mLogCat, "Failed to bind foreign method: %s::%s", class_name, signature); return nullptr; } + + WrenForeignClassMethods WrenState::BindForeignClassFN(WrenVM* vm, const char* module, const char* class_name) + { + ForeignClassDesc FCD = { module, class_name }; + + for (auto iter = mForeignClasses.begin(); iter != mForeignClasses.end(); iter++) + { + if (FCD == (*iter)) + { + Logger::Trace(mLogCat, "Successfully bound foreign class: %s in module %s", class_name, module); + return iter->FCM; + } + } + + Logger::Error(mLogCat, "Could not find foreign class: %s in module %s", class_name, module); + return WrenForeignClassMethods { nullptr, nullptr }; + } } \ No newline at end of file diff --git a/src/scripting/wren_state.h b/src/scripting/wren_state.h index 65b5ffe..fedc9e9 100644 --- a/src/scripting/wren_state.h +++ b/src/scripting/wren_state.h @@ -84,6 +84,7 @@ namespace lunarium u32 GetLogCat() const; void RegisterForeignMethod(ForeignMethodDesc method_desc); + void RegisterForeignClass(ForeignClassDesc class_desc); void RunScript(WrenScript* script); void RunSnippet(std::string name, std::string code); @@ -100,7 +101,7 @@ public: static void WriteFN(WrenVM* vm, const char* text); static void ErrorFN(WrenVM* vm, WrenErrorType type, const char* module, int line, const char* message); static WrenForeignMethodFn BindForeignMethodFN(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature); - static WrenForeignClassMethods BindForeignClass(WrenVM* vm, const char* module, const char* className); + static WrenForeignClassMethods BindForeignClassFN(WrenVM* vm, const char* module, const char* className); diff --git a/src/world/world.cpp b/src/world/world.cpp index 9d16a46..eb71696 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -41,35 +41,9 @@ namespace lunarium { } - - void World::InitScriptState() - { - // mScriptState.Initialize().LogIfFailed(LogCategory::GAME_SYSTEM, "Failed to initialize the world script state"); - - // // Register foreign methods - // mScriptState.RegisterForeignMethod({"WorldInterface", "WorldInterface", true, "GetComponent(_,_)", (WrenForeignMethodFn)&World::GetVelocityComponent}); - - // // Load the world interface script - // mWorldInterface.SetModuleName("WorldInterface"); - // std::string code = File::ReadTextFile("world_interface.wren"); // This will eventually move to internal data - // mWorldInterface.SetScriptCode(code); - - // mScriptState.RunScript(&mWorldInterface); - - // // Get class and method handles - // mWIHandle = mScriptState.GetWrenClassHandle("WorldInterface", "WorldInterface"); - // mWIInitMethod = mScriptState.GetWrenMethodHandle("Init()"); - // mWIDoOnLoadMethod = mScriptState.GetWrenMethodHandle("DoOnLoad()"); - // mWIDoOnUnloadMethod = mScriptState.GetWrenMethodHandle("DoOnUnload()"); - // mWIUpdateMethod = mScriptState.GetWrenMethodHandle("Update(_)"); - - // // Init the interface - // mScriptState.CallWrenMethod(mWIInitMethod, mWIHandle, {}, "WorldInterface.Init()"); - } void World::OnLoad() { - // InitScriptState(); WorldAPI::Initialize(this).LogIfFailed(LogCategory::GAME_SYSTEM, "Failed to initialized the world scripting api"); @@ -90,17 +64,13 @@ namespace lunarium } // Call OnLoad for each registered EntityBehavior class object - //mScriptState.CallWrenMethod(mWIDoOnLoadMethod, mWIHandle, {}, "WorldInterface.DoOnLoad()"); WorldAPI::InvokeEvent(WorldAPI::Event::ON_LOAD); } void World::OnUnload() { - // TODO: Call OnUnLoad for each registered EntityBehavior class object - //mScriptState.CallWrenMethod(mWIDoOnUnloadMethod, mWIHandle, {}, "WorldInterface.DoOnUnload()"); + // Call OnUnLoad for each registered EntityBehavior class object WorldAPI::InvokeEvent(WorldAPI::Event::ON_UNLOAD); - - //mScriptState.Shutdown(); WorldAPI::Shutdown(); } @@ -118,7 +88,6 @@ namespace lunarium { // Update all scripts // Call Update for each registered EntityBehavior class object - //mScriptState.CallWrenMethod(mWIUpdateMethod, mWIHandle, { {WrenParamType::WPT_DOUBLE, (double)dt} }, "WorldInterface.Update(dt)"); WorldAPI::InvokeEvent(WorldAPI::Event::ON_UPDATE, dt); @@ -176,6 +145,10 @@ namespace lunarium mpActiveCamera = pCam; } + ///////////////////////////////////////////////////////////////////// + // ENTITY API + ///////////////////////////////////////////////////////////////////// + entt::registry* World::GetEntityRegistry() { return &mECSRegistry; @@ -245,37 +218,37 @@ namespace lunarium ///////////////////////////////////////////////////////////////////// - void World::DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform) - { - // Draw current entity - Rectangle rect(my_trans.Position.x, my_trans.Position.y, bo_comp.Size.x, bo_comp.Size.y); - Color color(bo_comp.Color.x, bo_comp.Color.y, bo_comp.Color.z, bo_comp.Color.w); - g->DrawQuad(rect, color, nullptr, -my_trans.Rotation.z, Rectangle(-1, -1, -1, -1), current_transform); - - // Apply transform to children's transforms - current_transform *= my_trans.GetTransform(); - - // Iterate and draw children - if (mECSRegistry.all_of(entity)) - { - ChildrenComponent& children_comp = mECSRegistry.get(entity); - for (int i = 0; i < children_comp.Children.size(); i++) - { - Entity* pEnt = GetEntity(children_comp.Children[i]); - entt::entity handle = pEnt->GetEnttHandle(); - - if (pEnt->HasComponent() && pEnt->HasComponent()) - { - TransformComponent& trans_comp = pEnt->GetComponent(); - BlockOutComponent& bo_comp = pEnt->GetComponent(); - - DrawHeirarchy(g, handle, trans_comp, bo_comp, current_transform); - } - - } - } + // void World::DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform) + // { + // // Draw current entity + // Rectangle rect(my_trans.Position.x, my_trans.Position.y, bo_comp.Size.x, bo_comp.Size.y); + // Color color(bo_comp.Color.x, bo_comp.Color.y, bo_comp.Color.z, bo_comp.Color.w); + // g->DrawQuad(rect, color, nullptr, -my_trans.Rotation.z, Rectangle(-1, -1, -1, -1), current_transform); + + // // Apply transform to children's transforms + // current_transform *= my_trans.GetTransform(); + + // // Iterate and draw children + // if (mECSRegistry.all_of(entity)) + // { + // ChildrenComponent& children_comp = mECSRegistry.get(entity); + // for (int i = 0; i < children_comp.Children.size(); i++) + // { + // Entity* pEnt = GetEntity(children_comp.Children[i]); + // entt::entity handle = pEnt->GetEnttHandle(); + + // if (pEnt->HasComponent() && pEnt->HasComponent()) + // { + // TransformComponent& trans_comp = pEnt->GetComponent(); + // BlockOutComponent& bo_comp = pEnt->GetComponent(); + + // DrawHeirarchy(g, handle, trans_comp, bo_comp, current_transform); + // } + + // } + // } - } + // } glm::mat4 World::GetParentTransform(LUUID parent) { diff --git a/src/world/world.h b/src/world/world.h index 5bd66ba..2e96021 100644 --- a/src/world/world.h +++ b/src/world/world.h @@ -134,7 +134,7 @@ namespace lunarium void InitScriptState(); void RenderEditor(lunarium::Renderer2D* pGraphics) const; glm::mat4 GetParentTransform(LUUID parent); - void DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform); + //void DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform); }; } diff --git a/src/world/world_api.cpp b/src/world/world_api.cpp index d0264f5..d21be3c 100644 --- a/src/world/world_api.cpp +++ b/src/world/world_api.cpp @@ -8,6 +8,7 @@ #include "world_api.h" #include "world.h" +#include "entity.h" #include #include @@ -26,16 +27,27 @@ namespace lunarium mScriptState.Initialize().LogIfFailed(LogCategory::GAME_SYSTEM, "Failed to initialize the world script state"); // Register foreign methods - mScriptState.RegisterForeignMethod({"WorldInterface", "WorldInterface", true, "GetComponent(_,_)", (WrenForeignMethodFn)&WorldAPI::GetVelocityComponent}); + //mScriptState.RegisterForeignMethod({"WorldInterface", "WorldInterface", true, "GetComponent(_,_)", (WrenForeignMethodFn)&WorldAPI::GetVelocityComponent}); + + // Register foreign classes + SetupForeignClassVelocityComp(); + + // Load the component script + WrenScript components; + components.SetModuleName("Components"); + std::string code = File::ReadTextFile("components.wren"); // This will eventually move to internal data + components.SetScriptCode(code); + mScriptState.RunScript(&components); // Load the world interface script WrenScript world_interface; world_interface.SetModuleName("WorldInterface"); - std::string code = File::ReadTextFile("world_interface.wren"); // This will eventually move to internal data + code = File::ReadTextFile("world_interface.wren"); // This will eventually move to internal data world_interface.SetScriptCode(code); - mScriptState.RunScript(&world_interface); + + // Get class and method handles mEventHandles.mWIHandle = mScriptState.GetWrenClassHandle("WorldInterface", "WorldInterface"); mEventHandles.mWIInitMethod = mScriptState.GetWrenMethodHandle("Init()"); @@ -94,4 +106,62 @@ namespace lunarium } + + ///////////////////////////////////////////////////////////////////// + // FOREIGN CLASSES + ///////////////////////////////////////////////////////////////////// + + void WorldAPI::SetupForeignClassVelocityComp() + { + mScriptState.RegisterForeignClass({"Components", "VelocityComponent", sizeof(VelocityComponent*), + {(WrenForeignMethodFn)&WorldAPI::VelocityCompAllocate, &WorldAPI::VelocityCompFinalise}}); + + mScriptState.RegisterForeignMethod({"Components", "VelocityComponent", false, "GetVelocityX()",&WorldAPI::GetVelocityXFM}); + mScriptState.RegisterForeignMethod({"Components", "VelocityComponent", false, "GetVelocityY()",(WrenForeignMethodFn)&WorldAPI::GetVelocityYFM}); + mScriptState.RegisterForeignMethod({"Components", "VelocityComponent", false, "SetVelocity(_,_)", (WrenForeignMethodFn)&WorldAPI::SetVelocityFM}); + } + + void WorldAPI::VelocityCompAllocate(WrenVM* vm) + { + VelocityComponent** vcp = (VelocityComponent**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(VelocityComponent*)); + std::string str_entity_id = wrenGetSlotString(vm, 1); + LUUID entity_id = std::stoull(str_entity_id); + Entity* pEnt = mpWorld->GetEntity(entity_id); + if (!pEnt->HasComponent()) + { + Logger::Error(LogCategory::SCRIPTING, "Cannot allocate foreign class VelocityComponent - the entity does not have the component"); + (*vcp) = nullptr; + } + + (*vcp) = &pEnt->GetComponent(); + } + + void WorldAPI::VelocityCompFinalise(void* data) + { + // Nothing to clean up + } + + void WorldAPI::GetVelocityXFM(WrenVM* vm) + { + VelocityComponent** vcp = (VelocityComponent**)wrenGetSlotForeign(vm, 0); + wrenEnsureSlots(vm, 1); + wrenSetSlotDouble(vm, 0, (*vcp)->Velocity.x); + } + + void WorldAPI::GetVelocityYFM(WrenVM* vm) + { + VelocityComponent** vcp = (VelocityComponent**)wrenGetSlotForeign(vm, 0); + wrenEnsureSlots(vm, 1); + wrenSetSlotDouble(vm, 0, (*vcp)->Velocity.y); + } + + void WorldAPI::SetVelocityFM(WrenVM* vm) + { + VelocityComponent** vcp = (VelocityComponent**)wrenGetSlotForeign(vm, 0); + double x = wrenGetSlotDouble(vm, 1); + double y = wrenGetSlotDouble(vm, 2); + + (*vcp)->Velocity.x = x; + (*vcp)->Velocity.y = y; + } } \ No newline at end of file diff --git a/src/world/world_api.h b/src/world/world_api.h index a9d0893..e73ab4b 100644 --- a/src/world/world_api.h +++ b/src/world/world_api.h @@ -48,6 +48,14 @@ namespace lunarium private: // SCRIPTING API static void GetVelocityComponent(WrenVM* vm); + // Foreign classes + static void SetupForeignClassVelocityComp(); + static void VelocityCompAllocate(WrenVM* vm); + static void VelocityCompFinalise(void* data); + static void GetVelocityXFM(WrenVM* vm); + static void GetVelocityYFM(WrenVM* vm); + static void SetVelocityFM(WrenVM* vm); + private: static WrenState mScriptState; static World* mpWorld;