mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-22 13:30:06 +00:00
Added base lua manager
- CMakeLists.txt, Makefile, and appveyor now use luajit - lua/LuaManager.[ch]pp has been added which includes a basic script loader & thread scheduler - SCRIPTSDIR has been added to settings.[ch]pp, this specifies what directory lua scripts should be loaded from - Makefile has been updated to include lua/LuaManager.[ch]pp
This commit is contained in:
parent
6f59001be1
commit
43aa4eaeb8
@ -44,6 +44,7 @@ add_executable(openfusion ${SOURCES})
|
|||||||
set_target_properties(openfusion PROPERTIES OUTPUT_NAME ${BIN_NAME})
|
set_target_properties(openfusion PROPERTIES OUTPUT_NAME ${BIN_NAME})
|
||||||
|
|
||||||
target_link_libraries(openfusion sqlite3)
|
target_link_libraries(openfusion sqlite3)
|
||||||
|
target_link_libraries(openfusion lua51)
|
||||||
|
|
||||||
# Makes it so config, tdata, etc. get picked up when starting via the debugger in VS
|
# Makes it so config, tdata, etc. get picked up when starting via the debugger in VS
|
||||||
set_property(TARGET openfusion PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
set_property(TARGET openfusion PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||||
|
6
Makefile
6
Makefile
@ -6,7 +6,7 @@ CXX=clang++
|
|||||||
# If compiling with ASAN, invoke like this: $ LSAN_OPTIONS=suppressions=suppr.txt bin/fusion
|
# If compiling with ASAN, invoke like this: $ LSAN_OPTIONS=suppressions=suppr.txt bin/fusion
|
||||||
CFLAGS=-O3 #-g3 -fsanitize=address
|
CFLAGS=-O3 #-g3 -fsanitize=address
|
||||||
CXXFLAGS=-Wall -Wno-unknown-pragmas -std=c++17 -O2 -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) -DGIT_VERSION=\"$(GIT_VERSION)\" -I./src -I./vendor #-g3 -fsanitize=address
|
CXXFLAGS=-Wall -Wno-unknown-pragmas -std=c++17 -O2 -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) -DGIT_VERSION=\"$(GIT_VERSION)\" -I./src -I./vendor #-g3 -fsanitize=address
|
||||||
LDFLAGS=-lpthread -lsqlite3 #-g3 -fsanitize=address
|
LDFLAGS=-lpthread -lsqlite3 -lluajit-5.1 -lstdc++fs #-g3 -fsanitize=address
|
||||||
# specifies the name of our exectuable
|
# specifies the name of our exectuable
|
||||||
SERVER=bin/fusion
|
SERVER=bin/fusion
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ WIN_CC=x86_64-w64-mingw32-gcc
|
|||||||
WIN_CXX=x86_64-w64-mingw32-g++
|
WIN_CXX=x86_64-w64-mingw32-g++
|
||||||
WIN_CFLAGS=-O3 #-g3 -fsanitize=address
|
WIN_CFLAGS=-O3 #-g3 -fsanitize=address
|
||||||
WIN_CXXFLAGS=-D_WIN32_WINNT=0x0601 -Wall -Wno-unknown-pragmas -std=c++17 -O3 -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) -DGIT_VERSION=\"$(GIT_VERSION)\" -I./src -I./vendor #-g3 -fsanitize=address
|
WIN_CXXFLAGS=-D_WIN32_WINNT=0x0601 -Wall -Wno-unknown-pragmas -std=c++17 -O3 -DPROTOCOL_VERSION=$(PROTOCOL_VERSION) -DGIT_VERSION=\"$(GIT_VERSION)\" -I./src -I./vendor #-g3 -fsanitize=address
|
||||||
WIN_LDFLAGS=-static -lws2_32 -lwsock32 -lsqlite3 #-g3 -fsanitize=address
|
WIN_LDFLAGS=-static -lws2_32 -lwsock32 -lsqlite3 -lluajit-5.1 -lstdc++fs #-g3 -fsanitize=address
|
||||||
WIN_SERVER=bin/winfusion.exe
|
WIN_SERVER=bin/winfusion.exe
|
||||||
|
|
||||||
# C code; currently exclusively from vendored libraries
|
# C code; currently exclusively from vendored libraries
|
||||||
@ -43,6 +43,7 @@ CXXSRC=\
|
|||||||
src/servers/CNLoginServer.cpp\
|
src/servers/CNLoginServer.cpp\
|
||||||
src/servers/CNShardServer.cpp\
|
src/servers/CNShardServer.cpp\
|
||||||
src/servers/Monitor.cpp\
|
src/servers/Monitor.cpp\
|
||||||
|
src/lua/LuaManager.cpp\
|
||||||
src/db/init.cpp\
|
src/db/init.cpp\
|
||||||
src/db/login.cpp\
|
src/db/login.cpp\
|
||||||
src/db/shard.cpp\
|
src/db/shard.cpp\
|
||||||
@ -86,6 +87,7 @@ CXXHDR=\
|
|||||||
src/servers/CNLoginServer.hpp\
|
src/servers/CNLoginServer.hpp\
|
||||||
src/servers/CNShardServer.hpp\
|
src/servers/CNShardServer.hpp\
|
||||||
src/servers/Monitor.hpp\
|
src/servers/Monitor.hpp\
|
||||||
|
src/lua/LuaManager.hpp\
|
||||||
src/db/Database.hpp\
|
src/db/Database.hpp\
|
||||||
src/db/internal.hpp\
|
src/db/internal.hpp\
|
||||||
vendor/bcrypt/BCrypt.hpp\
|
vendor/bcrypt/BCrypt.hpp\
|
||||||
|
@ -18,6 +18,8 @@ for:
|
|||||||
matrix:
|
matrix:
|
||||||
only:
|
only:
|
||||||
- image: GCP-Linux-Ubuntu2004
|
- image: GCP-Linux-Ubuntu2004
|
||||||
|
install:
|
||||||
|
- sh: sudo apt install libluajit-5.1-dev -y
|
||||||
build_script:
|
build_script:
|
||||||
- ps: |
|
- ps: |
|
||||||
$versions = "104", "728", "1013"
|
$versions = "104", "728", "1013"
|
||||||
@ -48,6 +50,7 @@ for:
|
|||||||
- image: GCP-Windows-VS2019
|
- image: GCP-Windows-VS2019
|
||||||
install:
|
install:
|
||||||
- cmd: vcpkg install sqlite3:x64-windows
|
- cmd: vcpkg install sqlite3:x64-windows
|
||||||
|
- cmd: vcpkg install luajit:x64-windows
|
||||||
- cmd: vcpkg integrate install
|
- cmd: vcpkg integrate install
|
||||||
build_script:
|
build_script:
|
||||||
- ps: |
|
- ps: |
|
||||||
|
3
scripts/test.lua
Normal file
3
scripts/test.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
print("Hello world!")
|
||||||
|
wait(2)
|
||||||
|
print("Hello world ~2 seconds later!")
|
156
src/lua/LuaManager.cpp
Normal file
156
src/lua/LuaManager.cpp
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#include "lua/LuaManager.hpp"
|
||||||
|
|
||||||
|
#include "servers/CNShardServer.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
time_t getTime();
|
||||||
|
class Script;
|
||||||
|
|
||||||
|
// our "main" state, holds our environment
|
||||||
|
lua_State *LuaManager::global;
|
||||||
|
std::map<lua_State*, Script*> activeScripts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Basically each script is treated as a coroutine, when wait() is called it gets yielded and is pushed onto the scheduler queue to be resumed.
|
||||||
|
*/
|
||||||
|
class Script {
|
||||||
|
private:
|
||||||
|
lua_State *thread;
|
||||||
|
lRegistry threadRef; // we'll need to unref this when closing this state
|
||||||
|
|
||||||
|
public:
|
||||||
|
Script(std::string source) {
|
||||||
|
// make the thread & register it in the registry
|
||||||
|
thread = lua_newthread(LuaManager::global);
|
||||||
|
threadRef = luaL_ref(LuaManager::global, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
// add this script to the map
|
||||||
|
activeScripts[thread] = this;
|
||||||
|
|
||||||
|
// compile & run the script, if it error'd, print the error
|
||||||
|
int _retCode;
|
||||||
|
if (luaL_loadfile(thread, source.c_str()) || ((_retCode = lua_resume(thread, 0)) != 0 && (_retCode != LUA_YIELD))) {
|
||||||
|
std::cout << "[LUA ERROR]: " << lua_tostring(thread, -1) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unregister all of our events from the wrappers
|
||||||
|
~Script() {
|
||||||
|
LuaManager::clearState(thread);
|
||||||
|
|
||||||
|
// remove it from the global registry
|
||||||
|
luaL_unref(LuaManager::global, LUA_REGISTRYINDEX, threadRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// c++ moment....
|
||||||
|
lua_State* getState() {
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scheduledThread {
|
||||||
|
lRegistry ref; // ref that should be unref'd before resuming
|
||||||
|
time_t time;
|
||||||
|
};
|
||||||
|
std::map<lua_State*, scheduledThread> scheduleQueue;
|
||||||
|
|
||||||
|
// pauses the script for x seconds
|
||||||
|
int OF_wait(lua_State *state) {
|
||||||
|
double seconds = luaL_checknumber(state, 1);
|
||||||
|
|
||||||
|
// register the thread in the global registry so we don't get GC'd
|
||||||
|
lua_pushthread(state);
|
||||||
|
lRegistry ref = luaL_ref(state, LUA_REGISTRYINDEX); // threads decentant of a global state all share the global registry
|
||||||
|
|
||||||
|
// yield the state and push the state onto our scheduler queue
|
||||||
|
scheduleQueue[state] = {ref, (int)(seconds*1000) + getTime()};
|
||||||
|
return lua_yield(state, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void luaScheduler(CNServer *serv, time_t currtime) {
|
||||||
|
for (auto iter = scheduleQueue.begin(); iter != scheduleQueue.end();) {
|
||||||
|
time_t event = (*iter).second.time;
|
||||||
|
lRegistry ref = (*iter).second.ref;
|
||||||
|
lua_State *thread = (*iter).first;
|
||||||
|
// is it time to run the event?
|
||||||
|
if (event <= currtime) {
|
||||||
|
// remove from the scheduler queue
|
||||||
|
scheduleQueue.erase(iter++);
|
||||||
|
|
||||||
|
// unregister the thread
|
||||||
|
luaL_unref(thread, LUA_REGISTRYINDEX, ref);
|
||||||
|
|
||||||
|
// resume the state, (wait() returns the delta time since call)
|
||||||
|
lua_pushnumber(thread, ((double)currtime - event)/10);
|
||||||
|
|
||||||
|
int err = lua_resume(thread, 1);
|
||||||
|
if (err != 0 && err != LUA_YIELD) // if it returned LUA_YIELD, wait() was just called again, not an error!
|
||||||
|
LuaManager::printError(lua_tostring(thread, -1));
|
||||||
|
} else // go to the next iteration
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::printError(std::string err) {
|
||||||
|
std::cerr << "[LUA ERR]: " << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::init() {
|
||||||
|
// allocate our state
|
||||||
|
global = luaL_newstate();
|
||||||
|
|
||||||
|
// open lua's base libraries (excluding the IO for now)
|
||||||
|
luaopen_base(global);
|
||||||
|
luaopen_table(global);
|
||||||
|
luaopen_string(global);
|
||||||
|
luaopen_math(global);
|
||||||
|
luaopen_debug(global);
|
||||||
|
|
||||||
|
// add wait()
|
||||||
|
lua_register(global, "wait", OF_wait);
|
||||||
|
|
||||||
|
activeScripts = std::map<lua_State*, Script*>();
|
||||||
|
|
||||||
|
REGISTER_SHARD_TIMER(luaScheduler, 200);
|
||||||
|
|
||||||
|
// load our scripts
|
||||||
|
loadScripts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::runScript(std::string filename) {
|
||||||
|
new Script(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::stopScripts() {
|
||||||
|
// clear the scheduler queue
|
||||||
|
scheduleQueue.clear();
|
||||||
|
|
||||||
|
// free all the scripts, they'll take care of everything for us :)
|
||||||
|
for (auto as : activeScripts) {
|
||||||
|
delete as.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally clear the map
|
||||||
|
activeScripts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::loadScripts() {
|
||||||
|
if (!std::filesystem::exists(settings::SCRIPTSDIR)) {
|
||||||
|
std::cout << "[WARN] scripts directory \"" << settings::SCRIPTSDIR << "\" doesn't exist!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each file in the scripts director, load the script
|
||||||
|
std::filesystem::path dir(settings::SCRIPTSDIR);
|
||||||
|
for (auto &d : std::filesystem::directory_iterator(dir)) {
|
||||||
|
if (d.path().extension().u8string() == ".lua")
|
||||||
|
runScript(d.path().u8string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::clearState(lua_State *state) {
|
||||||
|
// TODO
|
||||||
|
}
|
26
src/lua/LuaManager.hpp
Normal file
26
src/lua/LuaManager.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/CNProtocol.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <luajit/lua.hpp>
|
||||||
|
#else
|
||||||
|
#include <luajit-2.1/lua.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int lRegistry;
|
||||||
|
|
||||||
|
namespace LuaManager {
|
||||||
|
extern lua_State *global;
|
||||||
|
void init();
|
||||||
|
void printError(std::string err);
|
||||||
|
|
||||||
|
// runs the script in the passed file
|
||||||
|
void runScript(std::string filename);
|
||||||
|
void stopScripts();
|
||||||
|
void loadScripts();
|
||||||
|
|
||||||
|
// unregisters the events tied to this state with all wrappers
|
||||||
|
void clearState(lua_State *state);
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include "servers/CNLoginServer.hpp"
|
#include "servers/CNLoginServer.hpp"
|
||||||
#include "servers/CNShardServer.hpp"
|
#include "servers/CNShardServer.hpp"
|
||||||
|
#include "lua/LuaManager.hpp"
|
||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
#include "PlayerMovement.hpp"
|
#include "PlayerMovement.hpp"
|
||||||
#include "BuiltinCommands.hpp"
|
#include "BuiltinCommands.hpp"
|
||||||
@ -120,6 +121,7 @@ int main() {
|
|||||||
Racing::init();
|
Racing::init();
|
||||||
Database::open();
|
Database::open();
|
||||||
Trading::init();
|
Trading::init();
|
||||||
|
LuaManager::init();
|
||||||
|
|
||||||
switch (settings::EVENTMODE) {
|
switch (settings::EVENTMODE) {
|
||||||
case 0: break; // no event
|
case 0: break; // no event
|
||||||
|
@ -35,6 +35,7 @@ int settings::SPAWN_ANGLE = 130;
|
|||||||
std::string settings::DBPATH = "database.db";
|
std::string settings::DBPATH = "database.db";
|
||||||
std::string settings::TDATADIR = "tdata/";
|
std::string settings::TDATADIR = "tdata/";
|
||||||
std::string settings::PATCHDIR = "tdata/patch/";
|
std::string settings::PATCHDIR = "tdata/patch/";
|
||||||
|
std::string settings::SCRIPTSDIR = "scripts";
|
||||||
|
|
||||||
std::string settings::NPCJSON = "NPCs.json";
|
std::string settings::NPCJSON = "NPCs.json";
|
||||||
std::string settings::MOBJSON = "mobs.json";
|
std::string settings::MOBJSON = "mobs.json";
|
||||||
|
@ -27,6 +27,7 @@ namespace settings {
|
|||||||
extern std::string PATCHDIR;
|
extern std::string PATCHDIR;
|
||||||
extern std::string ENABLEDPATCHES;
|
extern std::string ENABLEDPATCHES;
|
||||||
extern std::string TDATADIR;
|
extern std::string TDATADIR;
|
||||||
|
extern std::string SCRIPTSDIR;
|
||||||
extern int EVENTMODE;
|
extern int EVENTMODE;
|
||||||
extern bool MONITORENABLED;
|
extern bool MONITORENABLED;
|
||||||
extern int MONITORPORT;
|
extern int MONITORPORT;
|
||||||
|
Loading…
Reference in New Issue
Block a user