Added Wren scripting with module system 📚
Added Input pressed, released system Added interface button support with wren onclick callback
This commit is contained in:
38
Nuake/src/Scripting/Modules/EngineModule.h
Normal file
38
Nuake/src/Scripting/Modules/EngineModule.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include "wren.h"
|
||||
#include <string>
|
||||
#include <src/Core/Logger.h>
|
||||
#include "ScriptModule.h"
|
||||
#include <iostream>
|
||||
#include <wren.h>
|
||||
|
||||
namespace ScriptAPI
|
||||
{
|
||||
class EngineModule : public ScriptModule
|
||||
{
|
||||
std::string ModuleName = "Engine";
|
||||
std::string WrenAPI = "class Engine { \n"
|
||||
"foreign static Log(msg) \n"
|
||||
"}"
|
||||
"";
|
||||
|
||||
std::string GetModuleName() override
|
||||
{
|
||||
return "Engine";
|
||||
}
|
||||
|
||||
void RegisterModule(WrenVM* vm) override
|
||||
{
|
||||
RegisterMethod("Log(_)", (void*)Log);
|
||||
WrenInterpretResult result = wrenInterpret(vm, "main", WrenAPI.c_str());
|
||||
}
|
||||
|
||||
static void Log(WrenVM* vm)
|
||||
{
|
||||
std::string msg = wrenGetSlotString(vm, 1);
|
||||
Logger::Log(msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
27
Nuake/src/Scripting/Modules/ScriptModule.h
Normal file
27
Nuake/src/Scripting/Modules/ScriptModule.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <map>
|
||||
struct WrenVM;
|
||||
class ScriptModule
|
||||
{
|
||||
private:
|
||||
std::map<std::string, void*> Methods = std::map<std::string, void*>();
|
||||
|
||||
std::string WrenAPI;
|
||||
public:
|
||||
std::string ModuleName;
|
||||
virtual void RegisterModule(WrenVM*) = 0;
|
||||
virtual std::string GetModuleName() = 0;
|
||||
|
||||
void RegisterMethod(const std::string& signature, void* ptr)
|
||||
{
|
||||
Methods[signature] = ptr;
|
||||
}
|
||||
|
||||
void* GetMethodPointer(const std::string& signature)
|
||||
{
|
||||
return Methods[signature];
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
@@ -9,17 +9,7 @@ bool ScriptLoader::RegisterScript(ScriptableEntity* script)
|
||||
|
||||
bool ScriptLoader::LoadModule(const std::string& path)
|
||||
{
|
||||
HMODULE loadedLib = LoadLibraryA(path.c_str());
|
||||
if (!loadedLib) {
|
||||
printf("Failed to load library\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Library loaded\n");
|
||||
|
||||
ScriptModuleRegister* functionPointer = (ScriptModuleRegister*)GetProcAddress(loadedLib, "Register");
|
||||
|
||||
functionPointer();
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "ScriptModule.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "../Scene/Entities/ScriptableEntity.h"
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
class ScriptModule
|
||||
{
|
||||
public:
|
||||
virtual void Register();
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "HelloWorld.h"
|
||||
|
||||
|
||||
|
||||
int ScriptingAPI::HelloWorld(lua_State* L)
|
||||
{
|
||||
|
||||
|
||||
return 1; // Successful
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
struct lua_State;
|
||||
namespace ScriptingAPI
|
||||
{
|
||||
int HelloWorld(lua_State* L);
|
||||
}
|
||||
@@ -1,77 +1,112 @@
|
||||
#include "ScriptingEngine.h"
|
||||
#include <src/Vendors/sol/sol.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "WrenScript.h"
|
||||
#include "../Core/FileSystem.h"
|
||||
#include <src/Scripting/Modules/ScriptModule.h>
|
||||
#include <src/Scripting/Modules/EngineModule.h>
|
||||
WrenVM* ScriptingEngine::m_WrenVM;
|
||||
|
||||
inline void my_panic(sol::optional<std::string> maybe_msg) {
|
||||
std::cerr << "Lua script error detected!" << std::endl;
|
||||
if (maybe_msg) {
|
||||
const std::string& msg = maybe_msg.value();
|
||||
std::cerr << "\terror message: " << msg << std::endl;
|
||||
}
|
||||
|
||||
std::map<std::string, Ref<WrenScript>> ScriptingEngine::m_Scripts;
|
||||
|
||||
std::map<std::string, Ref<ScriptModule>> ScriptingEngine::Modules;
|
||||
|
||||
void errorFn(WrenVM* vm, WrenErrorType errorType,
|
||||
const char* module, const int line,
|
||||
const char* msg)
|
||||
{
|
||||
switch (errorType)
|
||||
{
|
||||
case WREN_ERROR_COMPILE:
|
||||
{
|
||||
printf("[%s line %d] [Error] %s\n", module, line, msg);
|
||||
} break;
|
||||
case WREN_ERROR_STACK_TRACE:
|
||||
{
|
||||
printf("[%s line %d] in %s\n", module, line, msg);
|
||||
} break;
|
||||
case WREN_ERROR_RUNTIME:
|
||||
{
|
||||
printf("[Runtime Error] %s\n", msg);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
sol::state ScriptingEngine::lua = sol::state(sol::c_call<decltype(&my_panic), &my_panic>);
|
||||
|
||||
void writeFn(WrenVM* vm, const char* text) {
|
||||
printf("%s", text);
|
||||
}
|
||||
|
||||
|
||||
WrenLoadModuleResult myLoadModule(WrenVM* vm, const char* name) {
|
||||
WrenLoadModuleResult result = { 0 };
|
||||
std::string str = FileSystem::ReadFile("resources/" + std::string(name) + ".wren", true);
|
||||
char* c = strcpy(new char[str.length() + 1], str.c_str());
|
||||
result.source = c;
|
||||
return result;
|
||||
}
|
||||
|
||||
Ref<WrenScript> ScriptingEngine::RegisterScript(const std::string& path, const std::string& mod)
|
||||
{
|
||||
std::string query = "import \"" + path + "\" for " + mod;
|
||||
wrenInterpret(m_WrenVM, "main", query.c_str());
|
||||
return CreateRef<WrenScript>(path, mod);
|
||||
}
|
||||
|
||||
void ScriptingEngine::RegisterModule(Ref<ScriptModule> scriptModule)
|
||||
{
|
||||
Modules[scriptModule->GetModuleName()] = scriptModule;
|
||||
scriptModule->RegisterModule(m_WrenVM);
|
||||
}
|
||||
|
||||
|
||||
void ScriptingEngine::InitScript(Ref<WrenScript> script)
|
||||
{
|
||||
script->CallInit();
|
||||
}
|
||||
|
||||
void ScriptingEngine::UpdateScript(Ref<WrenScript> script, Timestep timestep)
|
||||
{
|
||||
script->CallUpdate(timestep);
|
||||
}
|
||||
|
||||
void ScriptingEngine::ExitScript(Ref<WrenScript> script)
|
||||
{
|
||||
script->CallExit();
|
||||
}
|
||||
|
||||
void ScriptingEngine::Init()
|
||||
{
|
||||
lua.open_libraries(sol::lib::base, sol::lib::package);
|
||||
m_Scripts = std::map<std::string, Ref<WrenScript>>();
|
||||
WrenConfiguration config;
|
||||
wrenInitConfiguration(&config);
|
||||
|
||||
config.loadModuleFn = &myLoadModule;
|
||||
config.errorFn = &errorFn;
|
||||
config.writeFn = &writeFn;
|
||||
config.bindForeignMethodFn = &bindForeignMethod;
|
||||
m_WrenVM = wrenNewVM(&config);
|
||||
|
||||
Ref<ScriptAPI::EngineModule> engineModule = CreateRef<ScriptAPI::EngineModule>();
|
||||
RegisterModule(engineModule);
|
||||
}
|
||||
|
||||
void ScriptingEngine::RunFile(const std::string& path)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ScriptingEngine::RunCode(const std::string& code)
|
||||
{
|
||||
lua.script(code);
|
||||
bool isfullscreen = lua["config"]["fullscreen"];
|
||||
sol::table config = lua["config"];
|
||||
float x = lua["config"]["resolution"]["x"];
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void ScriptingEngine::UpdateScript(const std::string& path)
|
||||
{
|
||||
std::string fileContent;
|
||||
std::string allFile = "";
|
||||
// Read from the text file
|
||||
std::ifstream MyReadFile("resources/Scripts/test.lua");
|
||||
|
||||
// Use a while loop together with the getline() function to read the file line by line
|
||||
while (getline(MyReadFile, fileContent)) {
|
||||
allFile.append(fileContent);
|
||||
}
|
||||
|
||||
// Close the file
|
||||
MyReadFile.close();
|
||||
|
||||
try {
|
||||
auto bad_code_result = lua.script(allFile);
|
||||
// it did not work
|
||||
if (!bad_code_result.valid())
|
||||
{
|
||||
printf(std::to_string((int)(bad_code_result.status())).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int result = lua["update"]();
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ScriptingEngine::Close()
|
||||
{
|
||||
wrenFreeVM(m_WrenVM);
|
||||
}
|
||||
|
||||
}
|
||||
WrenForeignMethodFn ScriptingEngine::bindForeignMethod(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature)
|
||||
{
|
||||
if (Modules.find(className) != Modules.end())
|
||||
{
|
||||
Ref<ScriptModule> mod = Modules[className];
|
||||
void* ptr = mod->GetMethodPointer(signature);
|
||||
return (WrenForeignMethodFn)ptr;
|
||||
}
|
||||
}
|
||||
|
||||
WrenVM* ScriptingEngine::GetWrenVM()
|
||||
{
|
||||
return m_WrenVM;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,36 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "sol/forward.hpp"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "src/Core/Core.h"
|
||||
#include "src/Vendors/wren/src/include/wren.hpp"
|
||||
#include <src/Core/Timestep.h>
|
||||
|
||||
class WrenScript;
|
||||
class ScriptModule;
|
||||
class ScriptingEngine
|
||||
{
|
||||
private:
|
||||
static sol::state lua;
|
||||
static std::map<std::string, std::string> m_Scripts;
|
||||
|
||||
static WrenVM* m_WrenVM;
|
||||
static std::map<std::string, Ref<WrenScript>> m_Scripts;
|
||||
static std::map<std::string, Ref<ScriptModule>> Modules;
|
||||
public:
|
||||
static Ref<WrenScript> RegisterScript(const std::string& path, const std::string& mod);
|
||||
static void RegisterModule(Ref<ScriptModule> module);
|
||||
static void RegisterMethod(void* method, const std::string& module, const std::string& signature);
|
||||
static void InitScript(Ref<WrenScript> script);
|
||||
static void UpdateScript(Ref<WrenScript> script, Timestep timestep);
|
||||
static void ExitScript(Ref<WrenScript> script);
|
||||
static void Init();
|
||||
|
||||
static void RegisterScript(std::string path);
|
||||
|
||||
static void InitScript(std::string path);
|
||||
static void UpdateScript(std::string path);
|
||||
static void ExitScript(std::string path);
|
||||
|
||||
static void RunFile(const std::string& path);
|
||||
static void UpdateScript(const std::string& path);
|
||||
static void RunCode(const std::string& code);
|
||||
static void Close();
|
||||
|
||||
static WrenForeignMethodFn bindForeignMethod(
|
||||
WrenVM* vm,
|
||||
const char* module,
|
||||
const char* className,
|
||||
bool isStatic,
|
||||
const char* signature);
|
||||
|
||||
static WrenVM* GetWrenVM();
|
||||
};
|
||||
62
Nuake/src/Scripting/WrenScript.cpp
Normal file
62
Nuake/src/Scripting/WrenScript.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "WrenScript.h"
|
||||
#include "../Core/FileSystem.h"
|
||||
#include <src/Vendors/wren/src/include/wren.h>
|
||||
WrenScript::WrenScript(const std::string& path, const std::string& mod)
|
||||
{
|
||||
|
||||
WrenVM* vm = ScriptingEngine::GetWrenVM();
|
||||
|
||||
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenGetVariable(vm, "main", mod.c_str(), 0);
|
||||
|
||||
this->m_Instance = wrenGetSlotHandle(vm, 0);
|
||||
|
||||
this->m_OnInitHandle = wrenMakeCallHandle(vm, "init()");
|
||||
this->m_OnUpdateHandle = wrenMakeCallHandle(vm, "update(_)");
|
||||
this->m_OnExitHandle = wrenMakeCallHandle(vm, "exit()");
|
||||
}
|
||||
|
||||
void WrenScript::CallInit()
|
||||
{
|
||||
WrenVM* vm = ScriptingEngine::GetWrenVM();
|
||||
wrenSetSlotHandle(vm, 0, this->m_Instance);
|
||||
WrenInterpretResult result = wrenCall(vm, this->m_OnInitHandle);
|
||||
}
|
||||
|
||||
void WrenScript::CallUpdate(float timestep)
|
||||
{
|
||||
|
||||
WrenVM* vm = ScriptingEngine::GetWrenVM();
|
||||
wrenEnsureSlots(vm, 2);
|
||||
wrenSetSlotHandle(vm, 0, this->m_Instance);
|
||||
wrenSetSlotDouble(vm, 1, timestep);
|
||||
WrenInterpretResult result = wrenCall(vm, this->m_OnUpdateHandle);
|
||||
}
|
||||
|
||||
void WrenScript::CallExit()
|
||||
{
|
||||
WrenVM* vm = ScriptingEngine::GetWrenVM();
|
||||
wrenSetSlotHandle(vm, 0, this->m_Instance);
|
||||
WrenInterpretResult result = wrenCall(vm, this->m_OnExitHandle);
|
||||
}
|
||||
|
||||
void WrenScript::RegisterMethod(const std::string& signature)
|
||||
{
|
||||
WrenVM* vm = ScriptingEngine::GetWrenVM();
|
||||
WrenHandle* handle = wrenMakeCallHandle(vm, signature.c_str());
|
||||
methods.emplace(signature, handle);
|
||||
}
|
||||
|
||||
void WrenScript::CallMethod(const std::string& signature)
|
||||
{
|
||||
WrenVM* vm = ScriptingEngine::GetWrenVM();
|
||||
|
||||
|
||||
// Not found. maybe try to register it?
|
||||
if (methods.find(signature) == methods.end())
|
||||
return;
|
||||
wrenSetSlotHandle(vm, 0, this->m_Instance);
|
||||
WrenHandle* handle = methods[signature];
|
||||
WrenInterpretResult result = wrenCall(vm, handle);
|
||||
}
|
||||
24
Nuake/src/Scripting/WrenScript.h
Normal file
24
Nuake/src/Scripting/WrenScript.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "ScriptingEngine.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class WrenHandle;
|
||||
class WrenScript
|
||||
{
|
||||
public:
|
||||
std::map <std::string, WrenHandle*> methods;
|
||||
WrenHandle* m_Instance;
|
||||
WrenHandle* m_OnInitHandle;
|
||||
WrenHandle* m_OnUpdateHandle;
|
||||
WrenHandle* m_OnExitHandle;
|
||||
|
||||
WrenScript(const std::string& path, const std::string& mod);
|
||||
|
||||
void CallInit();
|
||||
void CallUpdate(float timestep);
|
||||
void CallExit();
|
||||
|
||||
void RegisterMethod(const std::string& signature);
|
||||
void CallMethod(const std::string& signature);
|
||||
};
|
||||
Reference in New Issue
Block a user