Added / Updated Lua Bindings

This commit is contained in:
OusmBlueNinja 2024-12-27 21:43:17 -06:00
parent 18791713ab
commit 193dcee7d6
15 changed files with 1229 additions and 288 deletions

72
assets/scripts/backup.lua Normal file
View File

@ -0,0 +1,72 @@
-- script.lua
local itterator = 0
local ticks = 0
local new_rotation = 0
local speed = 50
function OnInit()
-- Log a message with a custom red color
Engine.Log("This is a red message.", {1.0, 0.0, 0.0, 1.0})
-- Log a message with a custom green color
Engine.Log("This is a green message.", {0.0, 1.0, 0.0, 1.0})
-- Log a message with a custom blue color
Engine.Log("This is a blue message.", {0.0, 0.0, 1.0, 1.0})
end
function OnUpdate(deltaTime)
-- Attempt to retrieve the GameObject with the tag "Player"
local player = Engine.GetGameObjectByTag("Player")
if player ~= nil then
-- Successfully retrieved the GameObject
-- Call the GetName method on the GameObject
local transform = player:GetComponent("Transform")
-- Log the player's name with a white color
-- local pos = transform:GetPosition()
-- local x = string.format("%.2f", pos.x)
-- local y = string.format("%.2f", pos.y)
-- local z = string.format("%.2f", pos.z)
-- Engine.Log("Player Pos: (" .. x .. ", " .. y .. ", " .. z .. ")", {1, 1, 1, 1})
--local position = {x = 0.0, y = 2.0, z = -12.0} -- Define the new position
--transform:SetPosition(position) -- Call the SetPosition method
new_rotation = new_rotation + (deltaTime*speed)
if (new_rotation > 720) then
new_rotation = 0
end
local rotation = {x = -180, y = new_rotation, z = new_rotation} -- Define the new position
transform:SetRotation(rotation) -- Call the SetPosition method
-- (Optional) Perform additional operations on the player GameObject
-- For example, you might want to move the player, change properties, etc.
-- player:Move(newPosition)
-- player:SetHealth(100)
else
-- Failed to retrieve the GameObject; it doesn't exist
-- Log an error message with a red color
Engine.Log("Error: Player GameObject not found!", {1, 0, 0, 1})
end
end

View File

@ -1,6 +1,11 @@
-- script.lua
local itterator = 0
local ticks = 0
local new_rotation = 0
local speed = 50
function OnInit()
-- Log a message with a custom red color
Engine.Log("This is a red message.", {1.0, 0.0, 0.0, 1.0})
@ -19,17 +24,44 @@ end
function OnUpdate(deltaTime)
ticks = ticks + 1
local timestep = 5
if itterator >= timestep then
Engine.Log("TPS: ".. (ticks/timestep))
ticks = 0
itterator = 0
end
-- Attempt to retrieve the GameObject with the tag "Player"
local player = Engine.GetGameObjectByTag("Player")
itterator = itterator + deltaTime
if player ~= nil then
-- Successfully retrieved the GameObject
-- Call the GetName method on the GameObject
local transform = player:GetComponent("Transform")
-- Log the player's name with a white color
-- local pos = transform:GetPosition()
-- local x = string.format("%.2f", pos.x)
-- local y = string.format("%.2f", pos.y)
-- local z = string.format("%.2f", pos.z)
-- Engine.Log("Player Pos: (" .. x .. ", " .. y .. ", " .. z .. ")", {1, 1, 1, 1})
--local position = {x = 0.0, y = 2.0, z = -12.0} -- Define the new position
--transform:SetPosition(position) -- Call the SetPosition method
new_rotation = new_rotation + (deltaTime*speed)
if (new_rotation > 720) then
new_rotation = 0
end
local rotation = {x = -180, y = new_rotation, z = new_rotation} -- Define the new position
transform:SetRotation(rotation) -- Call the SetPosition method
-- (Optional) Perform additional operations on the player GameObject
-- For example, you might want to move the player, change properties, etc.
-- player:Move(newPosition)
-- player:SetHealth(100)
end
end

View File

@ -1,6 +1,6 @@
[Window][DockSpace]
Pos=0,0
Size=1920,1177
Size=1280,720
Collapsed=0
[Window][Debug##Default]
@ -9,8 +9,8 @@ Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1543,27
Size=369,1142
Pos=938,27
Size=334,685
Collapsed=0
DockId=0x00000002,0
@ -21,14 +21,14 @@ Collapsed=0
DockId=0x00000003,0
[Window][Performance]
Pos=8,774
Size=364,395
Pos=8,475
Size=364,237
Collapsed=0
DockId=0x00000006,0
[Window][Logger]
Pos=374,799
Size=1167,370
Pos=374,392
Size=562,320
Collapsed=0
DockId=0x00000004,0
@ -40,26 +40,32 @@ DockId=0x00000007,0
[Window][Scene Window]
Pos=8,27
Size=364,745
Size=364,446
Collapsed=0
DockId=0x00000005,0
[Window][Editor]
Pos=374,27
Size=1167,770
Size=562,363
Collapsed=0
DockId=0x00000003,0
[Window][Lua Text Editor]
Pos=374,27
Size=1167,528
Collapsed=0
DockId=0x00000003,1
[Docking][Data]
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1904,1142 Split=X Selected=0xF7365A5A
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1264,685 Split=X Selected=0xF7365A5A
DockNode ID=0x00000009 Parent=0x14621557 SizeRef=364,1142 Split=Y Selected=0x3DC5AC3F
DockNode ID=0x00000005 Parent=0x00000009 SizeRef=364,745 HiddenTabBar=1 Selected=0x3DC5AC3F
DockNode ID=0x00000006 Parent=0x00000009 SizeRef=364,395 HiddenTabBar=1 Selected=0x726D8899
DockNode ID=0x0000000A Parent=0x14621557 SizeRef=1538,1142 Split=X
DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2
DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X
DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1167,1142 Split=Y Selected=0xF7365A5A
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1578,770 CentralNode=1 HiddenTabBar=1 Selected=0xDF0EC458
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1578,370 HiddenTabBar=1 Selected=0x9DD4E196
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=369,1142 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1202,1142 Split=Y Selected=0xF7365A5A
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1578,820 CentralNode=1 Selected=0xDF0EC458
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1578,320 HiddenTabBar=1 Selected=0x9DD4E196
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB

View File

@ -1,112 +1,112 @@
Entities:
- ID: 0
Name: Car
Name: Player
Components:
Transform:
Position: [0, 2.79999995, -12.6000004]
Rotation: [149.699997, -137.899994, -39.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 2
indexCount: 15810
textureID: 1
MeshPath: assets/models/LowPolyFiatUNO.obj
Transform:
Position: [0, 2.79999995, -12.6000004]
Rotation: [149.699997, -137.899994, -39.2999992]
Scale: [1, 1, 1]
- ID: 2
Name: Null Texture Box
Components:
Transform:
Position: [7.80000019, -8.10000038, -20.6000004]
Rotation: [-86.3000031, 0, -66]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 3
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [7.80000019, -8.10000038, -20.6000004]
Rotation: [-86.3000031, 0, -66]
Scale: [1, 1, 1]
- ID: 3
Name: Grass Box Top
Components:
Transform:
Position: [-1.20000005, -3.4000001, -17.7000008]
Rotation: [-23.5, 15.8999996, -59.9000015]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-1.20000005, -3.4000001, -17.7000008]
Rotation: [-23.5, 15.8999996, -59.9000015]
Scale: [1, 1, 1]
- ID: 4
Name: Bark Box
Components:
Transform:
Position: [8.10000038, 0.800000012, -12]
Rotation: [-17.2999992, -16.1000004, -19.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 5
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [8.10000038, 0.800000012, -12]
Rotation: [-17.2999992, -16.1000004, -19.2999992]
Scale: [1, 1, 1]
- ID: 5
Name: Skybox
Components:
Transform:
Position: [0, 0, 43.2000008]
Rotation: [0, 0, 0]
Scale: [100, 100, 100]
Mesh:
vao: 5
indexCount: 36
textureID: 6
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [0, 0, 43.2000008]
Rotation: [0, 0, 0]
Scale: [100, 100, 100]
- ID: 6
Name: Null Texture Box
Components:
Transform:
Position: [-6.5, -6, -18]
Rotation: [15.8000002, -18.2000008, -11.1000004]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 3
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-6.5, -6, -18]
Rotation: [15.8000002, -18.2000008, -11.1000004]
Scale: [1, 1, 1]
- ID: 7
Name: Grass Box Bottom
Components:
Transform:
Position: [6.5999999, 1.79999995, -23.8999996]
Rotation: [-16.1000004, -15.8999996, -35]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [6.5999999, 1.79999995, -23.8999996]
Rotation: [-16.1000004, -15.8999996, -35]
Scale: [1, 1, 1]
- ID: 8
Name: Wood Box
Components:
Transform:
Position: [-7.80000019, 0.200000003, -29.7999992]
Rotation: [22.2999992, -32.7999992, 0]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 1
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-7.80000019, 0.200000003, -29.7999992]
Rotation: [22.2999992, -32.7999992, 0]
Scale: [1, 1, 1]
- ID: 9
Name: Bricks
Components:
Transform:
Position: [5.5, -2.9000001, -19.5]
Rotation: [-41.4000015, -22.6000004, -52.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 2
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [5.5, -2.9000001, -19.5]
Rotation: [-41.4000015, -22.6000004, -52.2999992]
Scale: [1, 1, 1]
- ID: 10
Name: Script Handler
Components:

View File

@ -6,13 +6,10 @@
#include "../Windows/LoggerWindow.h"
extern LoggerWindow *g_LoggerWindow;
GameObject::GameObject(int id, const std::string &name)
: id(id), name(name)
: id(id), name(name)
{
}
@ -21,11 +18,17 @@ int GameObject::GetComponentCount() const
return static_cast<int>(components.size());
}
std::string GameObject::GetName() const
{
return name;
}
void GameObject::AddComponent(const std::shared_ptr<Component> &component)
{
components[component->GetName()] = component;
//std::cout << "Added " << component->GetName() << std::endl;
// std::cout << "Added " << component->GetName() << std::endl;
}
std::shared_ptr<Component> GameObject::GetComponentByName(const std::string &name) const
@ -59,7 +62,6 @@ YAML::Node GameObject::Serialize()
void GameObject::Deserialize(const YAML::Node &node)
{
if (node["ID"])
{
id = node["ID"].as<int>();
@ -74,7 +76,7 @@ void GameObject::Deserialize(const YAML::Node &node)
for (auto it = componentsNode.begin(); it != componentsNode.end(); ++it)
{
std::string compName = it->first.as<std::string>();
YAML::Node compNode = it->second;
@ -100,26 +102,20 @@ void GameObject::Deserialize(const YAML::Node &node)
{
g_LoggerWindow->AddLog("[SceneManager] Failed to load Component: %s", compName.c_str());
DEBUG_PRINT("[SceneManager] Failed to load Component: %s", compName.c_str());
}
// Add deserialization for other components as needed
}
}
}
//}
//else if (compName == MeshComponent::GetStaticName())
// else if (compName == MeshComponent::GetStaticName())
//{
// auto render = std::make_shared<MeshComponent>();
// render->Deserialize(compNode);
// AddComponent(render);
//}
//else if (compName == MeshComponent::GetStaticName())
// else if (compName == MeshComponent::GetStaticName())
//{
// auto render = std::make_shared<MeshComponent>();
// render->Deserialize(compNode);

View File

@ -25,6 +25,8 @@ public:
GameObject(int id, const std::string &name);
std::string GetName() const;
void AddComponent(const std::shared_ptr<Component> &component);
std::shared_ptr<Component> GetComponentByName(const std::string &name) const;

View File

@ -73,7 +73,7 @@ bool ScriptComponent::Initialize()
}
// Initialize LuaManager with the script path
if (!m_LuaManager.init(ScriptPath))
if (!m_LuaManager.Initialize(ScriptPath))
{
DEBUG_PRINT("ScriptComponent: Failed to initialize LuaManager");
return false;
@ -85,5 +85,5 @@ bool ScriptComponent::Initialize()
void ScriptComponent::Update(float deltaTime)
{
// Call the Update method of LuaManager
m_LuaManager.onUpdate(deltaTime);
m_LuaManager.Update(deltaTime);
}

View File

@ -12,6 +12,22 @@ public:
glm::vec3 rotation;
glm::vec3 scale;
glm::vec3 GetPosition() const {
return position;
}
void SetPosition(float x, float y, float z) {
position = { x, y, z };
}
glm::vec3 GetRotation() const {
return rotation;
}
void SetRotation(float x, float y, float z) {
rotation = { x, y, z };
}
TransformComponent();
virtual const std::string& GetName() const override;
static const std::string& GetStaticName();

View File

@ -22,6 +22,11 @@
#include "Windows/InspectorWindow.h"
#include "Windows/SceneWindow.h"
// Create an instance
// In your rendering loop
#include "Engine/ThemeManager.h"
#include "Engine/SceneManager.h"
#include "Engine/LuaAPI.h"
@ -37,6 +42,7 @@ LoggerWindow *g_LoggerWindow;
SceneManager g_SceneManager;
std::vector<std::shared_ptr<GameObject>> g_GameObjects;
int g_GPU_Triangles_drawn_to_screen = 0;
@ -105,10 +111,11 @@ bool MyEngine::Init(int width, int height, const std::string &title)
m_LoggerWindow = std::make_unique<LoggerWindow>();
m_InspectorWindow = std::make_unique<InspectorWindow>();
m_SceneWindow = std::make_unique<SceneWindow>();
m_luaEditor = std::make_unique<LuaEditorWindow>();
g_LoggerWindow = m_LoggerWindow.get();
// Optionally, call 'onInit' Lua function
// Some initial logs
@ -119,7 +126,6 @@ bool MyEngine::Init(int width, int height, const std::string &title)
m_LastTime = glfwGetTime();
DEBUG_PRINT("[OK] Engine Init ");
return true;
}
@ -243,18 +249,18 @@ void MyEngine::Run()
m_InspectorWindow->Show();
if (1)
{
for (auto &Gameobject : g_GameObjects)
{
if (1) {
for (auto& Gameobject : g_GameObjects) {
// Handle Componenets That require Updates
std::shared_ptr<ScriptComponent> script = Gameobject->GetComponent<ScriptComponent>();
if (script){ // Stupid Null Checks
if (script)
{ // Stupid Null Checks
script->Update(frame_delta);
}
}
}
}
@ -268,6 +274,8 @@ void MyEngine::Run()
m_SceneWindow->Show();
//m_luaEditor->Show();
// After rendering
m_PerformanceWindow->UpdatePerformanceStats(-1, g_GPU_Triangles_drawn_to_screen);

View File

@ -8,6 +8,7 @@
#include "Windows/LoggerWindow.h"
#include "Windows/InspectorWindow.h"
#include "Windows/SceneWindow.h"
#include "Windows/LuaEditorWindow.h"
#include "Componenets/GameObject.h"
#include "Componenets/Mesh.h"
@ -18,11 +19,8 @@
#include "Engine/SceneManager.h"
#include "Engine/LuaAPI.h"
#include "TestModel.h"
#include "gcml.h"
// Forward declaration to avoid including GLFW in the header if you prefer
@ -43,7 +41,6 @@ private:
void ShowDockSpace();
private:
GLFWwindow *m_Window = nullptr;
bool m_Running = false;
@ -53,6 +50,7 @@ private:
std::unique_ptr<LoggerWindow> m_LoggerWindow;
std::unique_ptr<InspectorWindow> m_InspectorWindow;
std::unique_ptr<SceneWindow> m_SceneWindow;
std::unique_ptr<LuaEditorWindow> m_luaEditor;
double m_LastFrameTime = 0.0; // Initialize with the current time
double m_TimeAccumulator = 0.0;

View File

@ -1,240 +1,758 @@
// LuaManager.cpp
// LuaAPI.cpp
#include "LuaAPI.h"
#include "LuaMacros.h"
#include "imgui.h"
#include <iostream>
#include "gcml.h"
#include "LuaMacros.h" // Include the macros for binding
#include "gcml.h" // Include gcml.h for DEBUG_PRINT macros
#include "Componenets/Component.h"
#include "Componenets/Transform.h"
#include "Componenets/Mesh.h"
#include "Componenets/ScriptComponent.h"
#include "Componenets/GameObject.h"
#include "Windows/LoggerWindow.h"
#include <yaml-cpp/yaml.h>
#include <cstring>
#include <memory>
#include <vector>
// External LoggerWindow instance for logging
extern LoggerWindow *g_LoggerWindow;
int lua_log_message(lua_State *L);
// External GameObjects list
extern std::vector<std::unique_ptr<GameObject>> g_GameObjects;
LuaManager::LuaManager() : L(nullptr), m_firstCall(false), m_Initialized(false) {}
// Constructor
LuaManager::LuaManager()
: ScriptPath(""), m_LuaState(nullptr), m_LastErrorMessage("")
{
}
// Destructor
LuaManager::~LuaManager()
{
if (L)
if (m_LuaState)
{
lua_close(L);
lua_close(m_LuaState);
m_LuaState = nullptr;
}
}
bool LuaManager::init(const std::string &scriptPath)
// Initialize the LuaManager with the given script path
bool LuaManager::Initialize(const std::string &scriptPath)
{
// Create a new Lua state
L = luaL_newstate();
if (L == nullptr)
if (scriptPath.empty())
{
std::cerr << "Failed to create Lua state.\n";
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: Script path is empty.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
}
else
{
DEBUG_PRINT("LuaManager: Script path is empty.");
}
return false;
}
ScriptPath = scriptPath;
// Create a new Lua state
m_LuaState = luaL_newstate();
if (!m_LuaState)
{
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: Failed to create Lua state.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
}
else
{
DEBUG_PRINT("LuaManager: Failed to create Lua state.");
}
return false;
}
// Open Lua standard libraries
luaL_openlibs(L);
luaL_openlibs(m_LuaState);
// Register all necessary metatables
RegisterAllMetatables();
// Create the Engine table
CREATE_LUA_TABLE(L, Engine);
lua_newtable(m_LuaState);
lua_setglobal(m_LuaState, "Engine");
// Bind the Log function to the Engine table
BIND_LUA_FUNCTION(L, Engine, "Log", lua_log_message);
lua_getglobal(m_LuaState, "Engine");
lua_pushcfunction(m_LuaState, Lua_Engine_Log);
lua_setfield(m_LuaState, -2, "Log");
// Load and execute the Lua script
if (luaL_dofile(L, scriptPath.c_str()) != LUA_OK)
// Bind the GetGameObjectByTag function to the Engine table
lua_pushcfunction(m_LuaState, Lua_Engine_GetGameObjectByTag);
lua_setfield(m_LuaState, -2, "GetGameObjectByTag");
lua_pop(m_LuaState, 1); // Pop the Engine table from the stack
// Execute the Lua script
if (luaL_dofile(m_LuaState, ScriptPath.c_str()) != LUA_OK)
{
g_LoggerWindow->AddLog("%s", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), lua_tostring(L, -1));
DEBUG_PRINT("%s: %s", scriptPath.c_str(), lua_tostring(L, -1));
lua_close(L);
L = nullptr;
return false;
}
m_Initialized = true;
callLuaFunction("OnInit");
return true;
}
bool LuaManager::callLuaFunction(const std::string &funcName)
{
if (!m_Initialized) {
return false;
}
lua_getglobal(L, funcName.c_str());
if (!lua_isfunction(L, -1))
{
std::cerr << "'" << funcName << "' is not a function.\n";
lua_pop(L, 1); // Remove non-function value
return false;
}
// Call the function with 0 arguments and 0 return values
if (lua_pcall(L, 0, 0, 0) != LUA_OK)
{
std::cerr << "Error calling '" << funcName << "': " << lua_tostring(L, -1) << "\n";
lua_pop(L, 1); // Remove error message
return false;
}
return true;
}
bool LuaManager::onUpdate(float deltaTime)
{
if (!m_Initialized) {
return false;
}
// Push the 'OnUpdate' function onto the stack
lua_getglobal(L, "OnUpdate"); // Ensure correct case
if (!lua_isfunction(L, -1))
{
std::cerr << "'OnUpdate' is not a function.\n";
lua_pop(L, 1); // Remove non-function value
return false;
}
// Push the deltaTime argument
lua_pushnumber(L, deltaTime);
m_firstCall = true;
// Call the function with 1 argument and 0 return values
if (lua_pcall(L, 1, 0, 0) != LUA_OK)
{
// Retrieve the error message from Lua
const char *luaError = lua_tostring(L, -1);
const char *luaError = lua_tostring(m_LuaState, -1);
if (luaError)
{
std::string errorMsg(luaError);
// Check if this error message has already been logged
// Prevent duplicate error logs
if (errorMsg != m_LastErrorMessage)
{
// Log the error to the in-game terminal in red
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog(errorMsg.c_str(), ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
std::string formattedError = "LuaManager Error: " + errorMsg;
ImVec4 redColor = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
g_LoggerWindow->AddLog(formattedError.c_str(), std::optional<ImVec4>(redColor));
}
else
{
std::cerr << "LoggerWindow is not initialized.\n";
DEBUG_PRINT("LuaManager Error: %s", errorMsg.c_str());
}
// Update the last error message
m_LastErrorMessage = errorMsg;
}
// Optionally, print to std::cerr once if LoggerWindow is unavailable
if (!g_LoggerWindow)
{
std::cerr << "Error calling 'OnUpdate': " << luaError << "\n";
}
}
else
{
std::cerr << "Unknown error calling 'OnUpdate'.\n";
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: Unknown error executing script.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
}
else
{
DEBUG_PRINT("LuaManager: Unknown error executing script.");
}
}
lua_pop(L, 1); // Remove error message
lua_pop(m_LuaState, 1); // Remove error message from stack
return false;
}
// Reset last error message on successful script execution
m_LastErrorMessage.clear();
// Log successful initialization
DEBUG_PRINT("LuaManager initialized successfully with script: %s", ScriptPath.c_str());
return true;
}
// Update function called every frame
void LuaManager::Update(float deltaTime)
{
if (!m_LuaState)
{
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: Lua state is not initialized.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
}
else
{
DEBUG_PRINT("LuaManager: Lua state is not initialized.");
}
return;
}
// Push the 'OnUpdate' function onto the stack
lua_getglobal(m_LuaState, "OnUpdate");
if (!lua_isfunction(m_LuaState, -1))
{
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: 'OnUpdate' is not a function.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
}
else
{
DEBUG_PRINT("LuaManager: 'OnUpdate' is not a function.");
}
lua_pop(m_LuaState, 1); // Remove non-function value from stack
return;
}
// Push the deltaTime argument
lua_pushnumber(m_LuaState, deltaTime);
// Call the 'OnUpdate' function with 1 argument and 0 return values
if (lua_pcall(m_LuaState, 1, 0, 0) != LUA_OK)
{
const char *luaError = lua_tostring(m_LuaState, -1);
if (luaError)
{
std::string errorMsg(luaError);
// Prevent duplicate error logs
if (errorMsg != m_LastErrorMessage)
{
if (g_LoggerWindow)
{
std::string formattedError = "LuaManager Error in OnUpdate: " + errorMsg;
ImVec4 redColor = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
g_LoggerWindow->AddLog(formattedError.c_str(), std::optional<ImVec4>(redColor));
}
else
{
DEBUG_PRINT("LuaManager Error in OnUpdate: %s", errorMsg.c_str());
}
m_LastErrorMessage = errorMsg;
}
}
else
{
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: Unknown error in OnUpdate.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
}
else
{
DEBUG_PRINT("LuaManager: Unknown error in OnUpdate.");
}
}
lua_pop(m_LuaState, 1); // Remove error message from stack
return;
}
else
{
// Reset the last error message if the call was successful
// Reset last error message on successful call
m_LastErrorMessage.clear();
}
return true;
}
bool LuaManager::onDrawGui()
{
return callLuaFunction("onDrawGui");
}
bool LuaManager::callFunction(const std::string &funcName, int args, int returns)
{
if (!m_Initialized) {
return false;
}
lua_getglobal(L, funcName.c_str());
if (!lua_isfunction(L, -1))
{
std::cerr << "'" << funcName << "' is not a function.\n";
lua_pop(L, 1); // Remove non-function value
return false;
}
// For simplicity, this example doesn't handle arguments and return values.
// You can extend this method to push arguments and retrieve returns as needed.
if (lua_pcall(L, args, returns, 0) != LUA_OK)
{
std::cerr << "Error calling '" << funcName << "': " << lua_tostring(L, -1) << "\n";
lua_pop(L, 1); // Remove error message
return false;
}
return true;
}
// Binding function to log messages from Lua
int lua_log_message(lua_State *L)
int LuaManager::Lua_Engine_Log(lua_State *L)
{
// Check and retrieve the message string
int argc = lua_gettop(L);
if (argc < 1 || !lua_isstring(L, 1))
{
lua_pushstring(L, "Engine.Log expects at least one string argument.");
lua_error(L);
return 0;
}
std::string message = lua_tostring(L, 1);
ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // Default white
// Optional color table
if (argc >= 2 && lua_istable(L, 2))
{
lua_getfield(L, 2, "r");
if (lua_isnumber(L, -1))
color.x = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, 2, "g");
if (lua_isnumber(L, -1))
color.y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, 2, "b");
if (lua_isnumber(L, -1))
color.z = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, 2, "a");
if (lua_isnumber(L, -1))
color.w = lua_tonumber(L, -1);
lua_pop(L, 1);
}
// Log the message
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog(message.c_str(), std::optional<ImVec4>(color));
}
return 0; // No return values
}
// Binding function to retrieve a GameObject by tag from Lua
int LuaManager::Lua_Engine_GetGameObjectByTag(lua_State *L)
{
// Reuse the existing Lua_GetGameObjectByTag function
return Lua_GetGameObjectByTag(L);
}
// Binding function to retrieve a GameObject by tag
int LuaManager::Lua_GetGameObjectByTag(lua_State *L)
{
// Check if the first argument is a string
if (!lua_isstring(L, 1))
{
lua_pushstring(L, "Incorrect argument to 'Engine.Log'. Expected string as first argument.");
lua_error(L);
return 0; // Never reached, lua_error long jumps
lua_pushstring(L, "GetGameObjectByTag expects a string argument.");
lua_error(L); // Raises a Lua error and does not return
return 0; // This line won't be reached
}
const char *message = lua_tostring(L, 1);
// Initialize default color
ImVec4 color(1.0f, 1.0f, 1.0f, 1.0f); // Default white color
std::string tag = lua_tostring(L, 1);
// Check if a second argument (color) is provided
if (lua_gettop(L) >= 2)
// Search for the GameObject with the matching tag
GameObject *foundObject = nullptr;
for (auto &obj : g_GameObjects)
{
if (lua_istable(L, 2))
if (obj->name == tag)
{
// Retrieve color components from the table
lua_pushnumber(L, 1); // Push key 1 (r)
lua_gettable(L, 2);
float r = lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 1.0f;
lua_pop(L, 1);
lua_pushnumber(L, 2); // Push key 2 (g)
lua_gettable(L, 2);
float g = lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 1.0f;
lua_pop(L, 1);
lua_pushnumber(L, 3); // Push key 3 (b)
lua_gettable(L, 2);
float b = lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 1.0f;
lua_pop(L, 1);
lua_pushnumber(L, 4); // Push key 4 (a)
lua_gettable(L, 2);
float a = lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 1.0f;
lua_pop(L, 1);
color = ImVec4(r, g, b, a);
}
else
{
lua_pushstring(L, "Incorrect argument to 'Engine.Log'. Expected table for color.");
lua_error(L);
return 0;
foundObject = obj.get();
break;
}
}
// Ensure LoggerWindow is valid
if (foundObject == nullptr)
{
lua_pushnil(L); // Push nil to the stack if not found
return 1; // Return 1 (nil on Lua stack)
}
g_LoggerWindow->AddLog(message, color);
// Create userdata to hold the GameObject pointer
GameObject **udata = (GameObject **)lua_newuserdata(L, sizeof(GameObject *));
*udata = foundObject;
return 0; // Number of return values
// Set the metatable
luaL_getmetatable(L, "GameObjectMetaTable");
if (!lua_istable(L, -1)) // Check if the metatable was successfully found
{
DEBUG_PRINT("LuaManager: Metatable 'GameObjectMetaTable' not found.");
lua_pop(L, 1); // Remove the invalid metatable from the stack
lua_pushnil(L); // Return nil to indicate failure
return 1; // Return 1 (nil on Lua stack)
}
lua_setmetatable(L, -2); // Set the metatable for the userdata
return 1; // Return the GameObject userdata
}
// Binding function to retrieve a Component by name from a GameObject
int LuaManager::Lua_GameObject_GetComponent(lua_State *L)
{
// Ensure the first argument is a userdata with the correct metatable
GameObject **udata = (GameObject **)luaL_checkudata(L, 1, "GameObjectMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid GameObject.");
lua_error(L);
return 0;
}
// Ensure the second argument is a string representing the component name
if (!lua_isstring(L, 2))
{
lua_pushstring(L, "GetComponent expects a string as the second argument.");
lua_error(L);
return 0;
}
const char *componentNameStr = lua_tostring(L, 2);
// Retrieve the component by name
Component *component = (*udata)->GetComponentByName(componentNameStr).get();
if (component == nullptr)
{
lua_pushnil(L); // Return nil if component not found
return 1;
}
// Determine which metatable to use based on the component type
if (strcmp(componentNameStr, "Transform") == 0)
{
luaL_getmetatable(L, "TransformMetaTable");
}
else if (strcmp(componentNameStr, "Mesh") == 0)
{
luaL_getmetatable(L, "MeshMetaTable");
}
else if (strcmp(componentNameStr, "Script") == 0)
{
luaL_getmetatable(L, "ScriptMetaTable");
}
else
{
lua_pushstring(L, "Unknown ComponentType specified.");
lua_error(L);
return 0;
}
// Check if the metatable was successfully retrieved
std::string metatableName = std::string(componentNameStr) + "MetaTable";
if (!lua_istable(L, -1))
{
DEBUG_PRINT("LuaManager: Metatable '%s' not found.", std::string(metatableName).c_str());
lua_pop(L, 1); // Remove the invalid metatable from the stack
lua_pushnil(L); // Return nil to indicate failure
return 1;
}
// Create userdata for the Component
Component **compUdata = (Component **)lua_newuserdata(L, sizeof(Component *));
*compUdata = component;
// Retrieve and push the metatable onto the stack
luaL_getmetatable(L, std::string(metatableName).c_str());
if (lua_isnil(L, -1))
{
luaL_error(L, "Metatable '%s' not found", std::string(metatableName).c_str());
}
// Set the metatable for the userdata
lua_setmetatable(L, -2);
return 1; // Return the Component userdata
}
// Binding function to retrieve a Component's name
int LuaManager::Lua_Component_GetName(lua_State *L)
{
// Ensure the first argument is a userdata with ComponentMetaTable
Component **udata = (Component **)luaL_checkudata(L, 1, "ComponentMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid Component.");
lua_error(L);
return 0;
}
// Push the name of the Component
lua_pushstring(L, (*udata)->GetName().c_str());
return 1; // Return the name
}
// Binding function to retrieve a TransformComponent's position
int LuaManager::Lua_TransformComponent_GetPosition(lua_State *L)
{
// Ensure the first argument is a userdata with TransformMetaTable
TransformComponent **udata = (TransformComponent **)luaL_checkudata(L, 1, "TransformMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid TransformComponent.");
lua_error(L);
return 0;
}
// Assuming TransformComponent has a GetPosition method returning a glm::vec3
glm::vec3 position = (*udata)->GetPosition(); // Example using glm::vec3
// Push position as a Lua table
lua_newtable(L);
lua_pushnumber(L, position.x);
lua_setfield(L, -2, "x");
lua_pushnumber(L, position.y);
lua_setfield(L, -2, "y");
lua_pushnumber(L, position.z);
lua_setfield(L, -2, "z");
return 1; // Return the position table
}
// Binding function to set a TransformComponent's position
int LuaManager::Lua_TransformComponent_SetPosition(lua_State *L)
{
// Ensure the first argument is a userdata with TransformMetaTable
TransformComponent **udata = (TransformComponent **)luaL_checkudata(L, 1, "TransformMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid TransformComponent.");
lua_error(L);
return 0;
}
// Ensure the second argument is a table with x, y, z
if (!lua_istable(L, 2))
{
lua_pushstring(L, "SetPosition expects a table with x, y, z fields.");
lua_error(L);
return 0;
}
lua_getfield(L, 2, "x");
lua_getfield(L, 2, "y");
lua_getfield(L, 2, "z");
if (!lua_isnumber(L, -3) || !lua_isnumber(L, -2) || !lua_isnumber(L, -1))
{
lua_pushstring(L, "SetPosition expects numerical x, y, z fields.");
lua_error(L);
return 0;
}
float x = lua_tonumber(L, -3);
float y = lua_tonumber(L, -2);
float z = lua_tonumber(L, -1);
lua_pop(L, 3); // Remove x, y, z from stack
(*udata)->SetPosition(x, y, z); // Corrected to match the method signature
return 0; // No return values
}
// Binding function to retrieve a TransformComponent's position
int LuaManager::Lua_TransformComponent_GetRotation(lua_State *L)
{
// Ensure the first argument is a userdata with TransformMetaTable
TransformComponent **udata = (TransformComponent **)luaL_checkudata(L, 1, "TransformMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid TransformComponent.");
lua_error(L);
return 0;
}
// Assuming TransformComponent has a GetPosition method returning a glm::vec3
glm::vec3 rotation = (*udata)->GetRotation(); // Example using glm::vec3
// Push position as a Lua table
lua_newtable(L);
lua_pushnumber(L, rotation.x);
lua_setfield(L, -2, "x");
lua_pushnumber(L, rotation.y);
lua_setfield(L, -2, "y");
lua_pushnumber(L, rotation.z);
lua_setfield(L, -2, "z");
return 1; // Return the position table
}
// Binding function to set a TransformComponent's position
int LuaManager::Lua_TransformComponent_SetRotation(lua_State *L)
{
// Ensure the first argument is a userdata with TransformMetaTable
TransformComponent **udata = (TransformComponent **)luaL_checkudata(L, 1, "TransformMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid TransformComponent.");
lua_error(L);
return 0;
}
// Ensure the second argument is a table with x, y, z
if (!lua_istable(L, 2))
{
lua_pushstring(L, "SetRotation expects a table with x, y, z fields.");
lua_error(L);
return 0;
}
lua_getfield(L, 2, "x");
lua_getfield(L, 2, "y");
lua_getfield(L, 2, "z");
if (!lua_isnumber(L, -3) || !lua_isnumber(L, -2) || !lua_isnumber(L, -1))
{
lua_pushstring(L, "SetRotation expects numerical x, y, z fields.");
lua_error(L);
return 0;
}
float x = lua_tonumber(L, -3);
float y = lua_tonumber(L, -2);
float z = lua_tonumber(L, -1);
lua_pop(L, 3); // Remove x, y, z from stack
(*udata)->SetRotation(x, y, z); // Corrected to match the method signature
return 0; // No return values
}
// Binding function to retrieve a MeshComponent's mesh data
int LuaManager::Lua_MeshComponent_GetMeshData(lua_State *L)
{
// Ensure the first argument is a userdata with MeshComponentMetaTable
MeshComponent **udata = (MeshComponent **)luaL_checkudata(L, 1, "MeshComponentMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid MeshComponent.");
lua_error(L);
return 0;
}
// Example: Push mesh data as a table
// Ensure MeshData is defined appropriately in MeshComponent
GLuint ID = (*udata)->textureID; // Assume MeshData is a struct with relevant fields
lua_newtable(L);
lua_pushnumber(L, ID);
lua_setfield(L, -2, "vertexData");
// lua_pushstring(L, ID.indexData.c_str());
// lua_setfield(L, -2, "indexData");
// Add more mesh data fields as needed
return 1; // Return the mesh data table
}
// Binding function to retrieve a ScriptComponent's script path
int LuaManager::Lua_ScriptComponent_GetScriptPath(lua_State *L)
{
// Ensure the first argument is a userdata with ScriptComponentMetaTable
ScriptComponent **udata = (ScriptComponent **)luaL_checkudata(L, 1, "ScriptComponentMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid ScriptComponent.");
lua_error(L);
return 0;
}
// Push the script path
lua_pushstring(L, (*udata)->ScriptPath.c_str());
return 1; // Return the script path
}
// Binding function to retrieve a GameObject's name
int LuaManager::Lua_GameObject_GetName(lua_State *L)
{
// Ensure the first argument is a userdata with GameObjectMetaTable
GameObject **udata = (GameObject **)luaL_checkudata(L, 1, "GameObjectMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid GameObject.");
lua_error(L);
return 0;
}
// Push the name of the GameObject
lua_pushstring(L, (*udata)->GetName().c_str());
return 1; // Return the name
}
// Function to register all metatables
void LuaManager::RegisterAllMetatables()
{
RegisterComponentMetaTable();
RegisterTransformComponentMetaTable();
RegisterMeshComponentMetaTable();
RegisterScriptComponentMetaTable();
RegisterGameObjectMetatable();
}
// Function to register the base ComponentMetaTable
void LuaManager::RegisterComponentMetaTable()
{
luaL_newmetatable(m_LuaState, "ComponentMetaTable");
// __index
lua_pushstring(m_LuaState, "__index");
lua_newtable(m_LuaState);
// Add methods to the metatable
lua_pushcfunction(m_LuaState, Lua_Component_GetName);
lua_setfield(m_LuaState, -2, "GetName");
// Add more common methods as needed
lua_settable(m_LuaState, -3); // Set __index to the table with methods
lua_pop(m_LuaState, 1); // Pop the metatable
}
// Function to register the TransformMetaTable
void LuaManager::RegisterTransformComponentMetaTable()
{
luaL_newmetatable(m_LuaState, "TransformMetaTable");
// __index
lua_pushstring(m_LuaState, "__index");
lua_newtable(m_LuaState);
// Inherit from ComponentMetaTable
luaL_getmetatable(m_LuaState, "ComponentMetaTable");
lua_setfield(m_LuaState, -2, "__base");
// Add methods specific to TransformComponent
lua_pushcfunction(m_LuaState, Lua_TransformComponent_GetPosition);
lua_setfield(m_LuaState, -2, "GetPosition");
lua_pushcfunction(m_LuaState, Lua_TransformComponent_SetPosition);
lua_setfield(m_LuaState, -2, "SetPosition");
// Add methods specific to TransformComponent
lua_pushcfunction(m_LuaState, Lua_TransformComponent_GetRotation);
lua_setfield(m_LuaState, -2, "GetRotation");
lua_pushcfunction(m_LuaState, Lua_TransformComponent_SetRotation);
lua_setfield(m_LuaState, -2, "SetRotation");
// Add more Transform-specific methods as needed
lua_settable(m_LuaState, -3); // Set __index to the table with methods
lua_pop(m_LuaState, 1); // Pop the metatable
}
// Function to register the MeshComponentMetaTable
void LuaManager::RegisterMeshComponentMetaTable()
{
luaL_newmetatable(m_LuaState, "MeshMetaTable");
// __index
lua_pushstring(m_LuaState, "__index");
lua_newtable(m_LuaState);
// Inherit from ComponentMetaTable
luaL_getmetatable(m_LuaState, "ComponentMetaTable");
lua_setfield(m_LuaState, -2, "__base");
// Add methods specific to MeshComponent
lua_pushcfunction(m_LuaState, Lua_MeshComponent_GetMeshData);
lua_setfield(m_LuaState, -2, "GetMeshData");
// Add more Mesh-specific methods as needed
lua_settable(m_LuaState, -3); // Set __index to the table with methods
lua_pop(m_LuaState, 1); // Pop the metatable
}
// Function to register the ScriptComponentMetaTable
void LuaManager::RegisterScriptComponentMetaTable()
{
luaL_newmetatable(m_LuaState, "ScriptMetaTable");
// __index
lua_pushstring(m_LuaState, "__index");
lua_newtable(m_LuaState);
// Inherit from ComponentMetaTable
luaL_getmetatable(m_LuaState, "ComponentMetaTable");
lua_setfield(m_LuaState, -2, "__base");
// Add methods specific to ScriptComponent
lua_pushcfunction(m_LuaState, Lua_ScriptComponent_GetScriptPath);
lua_setfield(m_LuaState, -2, "GetScriptPath");
// Add more Script-specific methods as needed
lua_settable(m_LuaState, -3); // Set __index to the table with methods
lua_pop(m_LuaState, 1); // Pop the metatable
}
// Function to register the GameObjectMetaTable
void LuaManager::RegisterGameObjectMetatable()
{
luaL_newmetatable(m_LuaState, "GameObjectMetaTable");
// __index
lua_pushstring(m_LuaState, "__index");
lua_newtable(m_LuaState);
// Add methods to the metatable
lua_pushcfunction(m_LuaState, Lua_GameObject_GetName);
lua_setfield(m_LuaState, -2, "GetName");
lua_pushcfunction(m_LuaState, Lua_GameObject_GetComponent);
lua_setfield(m_LuaState, -2, "GetComponent");
// Add more methods as needed
lua_settable(m_LuaState, -3); // Set __index to the table with methods
lua_pop(m_LuaState, 1); // Pop the metatable
}

View File

@ -1,36 +1,98 @@
// LuaAPI.h
#pragma once
#include "lua.hpp"
#include <string>
// Include Lua headers
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
class LuaManager {
// Include standard libraries
#include <string>
#include <optional>
// Forward declarations to avoid circular dependencies
class Component;
class TransformComponent;
class MeshComponent;
class ScriptComponent;
class GameObject;
class LoggerWindow;
// LuaManager class definition
class LuaManager
{
public:
// Constructor
LuaManager();
// Destructor
~LuaManager();
// Initialize the Lua state and load the script
bool init(const std::string& scriptPath);
/**
* @brief Initializes the LuaManager with the specified Lua script.
*
* This function creates a new Lua state, opens standard libraries,
* registers all necessary metatables, binds essential functions to Lua,
* and executes the provided Lua script.
*
* @param scriptPath The file path to the Lua script to execute.
* @return true if initialization is successful; false otherwise.
*/
bool Initialize(const std::string &scriptPath);
// Call the 'onUpdate' function in Lua
bool onUpdate(float deltaTime);
// Call the 'onDrawGui' function in Lua
bool onDrawGui();
// Optionally, call other Lua functions as needed
bool callFunction(const std::string& funcName, int args = 0, int returns = 0);
/**
* @brief Updates the LuaManager each frame.
*
* This function calls the Lua `OnUpdate` function, passing the
* delta time since the last frame. It handles any errors that
* occur during the execution of the Lua function.
*
* @param deltaTime The time elapsed since the last frame.
*/
void Update(float deltaTime);
private:
lua_State* L;
std::string m_LastErrorMessage; // Stores the last error message
// Lua state
std::string ScriptPath;
bool m_firstCall;
lua_State *m_LuaState;
bool m_Initialized;
// Last error message to prevent duplicate logging
std::string m_LastErrorMessage;
void RegisterAllMetatables();
void RegisterComponentMetaTable();
void RegisterTransformComponentMetaTable();
void RegisterMeshComponentMetaTable();
void RegisterScriptComponentMetaTable();
void RegisterGameObjectMetatable();
// Helper function to call a Lua function with no arguments and no return values
// Binding functions for Component
static int Lua_Component_GetName(lua_State *L);
bool callLuaFunction(const std::string& funcName);
// Binding functions for TransformComponent
static int Lua_TransformComponent_GetPosition(lua_State *L);
static int Lua_TransformComponent_SetPosition(lua_State *L);
static int Lua_TransformComponent_GetRotation(lua_State *L);
static int Lua_TransformComponent_SetRotation(lua_State *L);
// Binding functions for MeshComponent
static int Lua_MeshComponent_GetMeshData(lua_State *L);
// Binding functions for ScriptComponent
static int Lua_ScriptComponent_GetScriptPath(lua_State *L);
// Binding functions for GameObject
static int Lua_GameObject_GetName(lua_State *L);
static int Lua_GameObject_GetComponent(lua_State *L);
static int Lua_GetGameObjectByTag(lua_State *L);
// Binding functions for Engine table
static int Lua_Engine_Log(lua_State *L);
static int Lua_Engine_GetGameObjectByTag(lua_State *L);
};

View File

@ -1,7 +1,6 @@
#include "./Componenets/GameObject.h"
#pragma once
#include <vector>
#include "Componenets/GameObject.h"
class SceneManager

View File

@ -0,0 +1,208 @@
#include <vector>
#include "LuaEditorWindow.h"
#include <fstream>
#include <sstream>
#include <unordered_set>
// Lua keywords for highlighting
const std::unordered_set<std::string> luaKeywords = {
"and", "break", "do", "else", "elseif", "end", "false", "for", "function",
"if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true",
"until", "while"
};
bool IsLuaKeyword(const std::string& word) {
return luaKeywords.find(word) != luaKeywords.end();
}
LuaEditorWindow::LuaEditorWindow() {
m_FilePath = "assets/scripts/script.lua";
m_EditorContent.resize(BUFFER_SIZE, '\0'); // Initialize buffer
std::string initialText = "-- Lua Text Editor Example\nprint('Hello, World!')";
std::copy(initialText.begin(), initialText.end(), m_EditorContent.begin());
}
void LuaEditorWindow::Show() {
if (m_EditorContent.empty()) {
ImGui::Text("Editor content not initialized.");
return;
}
ImGui::Begin("Lua Text Editor");
// Toolbar buttons
if (ImGui::Button("Save")) {
if (!m_FilePath.empty()) {
SaveToFile(m_FilePath);
}
}
ImGui::SameLine();
if (ImGui::Button("Load")) {
if (!m_FilePath.empty()) {
LoadFromFile(m_FilePath);
}
}
ImGui::SameLine();
if (ImGui::Button("Clear")) {
Clear();
}
ImGui::Separator();
// Editable text input
float contentHeight = ImGui::GetContentRegionAvail().y;
ImVec2 inputBoxSize(-FLT_MIN, contentHeight);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); // Reduce spacing for overlay
ImGui::BeginChild("##editor_background", inputBoxSize, true, ImGuiWindowFlags_NoScrollbar);
// Syntax highlighting overlay
ImGui::SetCursorPos(ImVec2(0, 0));
std::istringstream stream(GetText());
std::string line;
while (std::getline(stream, line)) {
const char* cursor = line.c_str();
const char* end = cursor + line.size();
std::string inlineText;
while (cursor < end) {
// Handle comments
if (*cursor == '-' && (cursor + 1 < end) && *(cursor + 1) == '-') {
if (!inlineText.empty()) {
ImGui::TextUnformatted(inlineText.c_str());
ImGui::SameLine(0.0f, 0.0f);
inlineText.clear();
}
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); // Gray for comments
ImGui::TextUnformatted(cursor);
ImGui::PopStyleColor();
break;
}
// Handle strings
if (*cursor == '"' || *cursor == '\'') {
char stringDelimiter = *cursor;
if (!inlineText.empty()) {
ImGui::TextUnformatted(inlineText.c_str());
ImGui::SameLine(0.0f, 0.0f);
inlineText.clear();
}
const char* stringStart = cursor++;
while (cursor < end && *cursor != stringDelimiter) {
if (*cursor == '\\' && (cursor + 1 < end) && *(cursor + 1) == stringDelimiter) {
cursor++;
}
cursor++;
}
if (cursor < end) {
cursor++;
}
std::string stringToken(stringStart, cursor);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f)); // Green for strings
ImGui::TextUnformatted(stringToken.c_str());
ImGui::PopStyleColor();
ImGui::SameLine(0.0f, 0.0f);
continue;
}
// Handle keywords
const char* wordStart = cursor;
while (cursor < end && (isalnum(*cursor) || *cursor == '_')) {
cursor++;
}
std::string word(wordStart, cursor);
if (IsLuaKeyword(word)) {
if (!inlineText.empty()) {
ImGui::TextUnformatted(inlineText.c_str());
ImGui::SameLine(0.0f, 0.0f);
inlineText.clear();
}
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.5f, 1.0f, 1.0f)); // Blue for keywords
ImGui::TextUnformatted(word.c_str());
ImGui::PopStyleColor();
ImGui::SameLine(0.0f, 0.0f);
} else {
inlineText += word;
}
// Handle symbols
if (cursor < end && !isalnum(*cursor) && *cursor != '_') {
if (!inlineText.empty()) {
ImGui::TextUnformatted(inlineText.c_str());
ImGui::SameLine(0.0f, 0.0f);
inlineText.clear();
}
ImGui::TextUnformatted(std::string(1, *cursor).c_str());
ImGui::SameLine(0.0f, 0.0f);
cursor++;
}
}
if (!inlineText.empty()) {
ImGui::TextUnformatted(inlineText.c_str());
}
ImGui::NewLine();
}
ImGui::EndChild(); // End background overlay
ImGui::PopStyleVar();
// Editable content area
ImGui::InputTextMultiline("##editor", m_EditorContent.data(), m_EditorContent.size(),
inputBoxSize, ImGuiInputTextFlags_AllowTabInput);
ImGui::End();
}
void LuaEditorWindow::SetText(const std::string& text) {
if (text.size() >= BUFFER_SIZE) {
m_EditorContent.resize(text.size() + 1); // Resize if needed
}
std::copy(text.begin(), text.end(), m_EditorContent.begin());
m_EditorContent[text.size()] = '\0'; // Ensure null termination
}
std::string LuaEditorWindow::GetText() const {
return std::string(m_EditorContent.data());
}
void LuaEditorWindow::Clear() {
std::fill(m_EditorContent.begin(), m_EditorContent.end(), '\0');
}
bool LuaEditorWindow::SaveToFile(const std::string& filePath) {
std::ofstream file(filePath);
if (!file.is_open()) {
return false;
}
file << m_EditorContent.data();
return true;
}
bool LuaEditorWindow::LoadFromFile(const std::string& filePath) {
std::ifstream file(filePath);
if (!file.is_open()) {
return false;
}
std::stringstream buffer;
buffer << file.rdbuf();
SetText(buffer.str());
m_FilePath = filePath;
return true;
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <string>
#include "imgui.h"
class LuaEditorWindow {
public:
LuaEditorWindow();
~LuaEditorWindow() = default;
void Show(); // Renders the Lua editor window
void SetText(const std::string& text); // Sets the editor content
std::string GetText() const; // Gets the editor content
void Clear(); // Clears the editor content
bool LoadFromFile(const std::string& filePath); // Loads content from a file
bool SaveToFile(const std::string& filePath); // Saves content to a file
private:
std::vector<char> m_EditorContent; // Buffer for the editor's content
static constexpr size_t BUFFER_SIZE = 1024 * 16; // 16 KB default size
std::string m_FilePath; // Path to the loaded file
bool m_ScrollToBottom = false; // Flag to auto-scroll to the bottom
};