Skip to content

Commit 0b2cc75

Browse files
authored
first push
1 parent 9c5dbe1 commit 0b2cc75

191 files changed

Lines changed: 151369 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.clang-format

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
Language: Cpp
3+
BasedOnStyle: Google
4+
PointerAlignment: Left
5+
FixNamespaceComments: false
6+
CompactNamespaces: true
7+
ColumnLimit: 100
8+
...

.clangd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CompileFlags:
2+
Add:
3+
[
4+
'-std=c++23'
5+
]

.github/workflows/msvc.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: msvc
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
7+
workflow_dispatch:
8+
9+
jobs:
10+
build:
11+
runs-on: windows-latest
12+
13+
env:
14+
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/cache@v4
19+
id: cache
20+
with:
21+
path: |
22+
${{ github.workspace }}/vcpkg/packages
23+
${{ github.workspace }}/vcpkg/downloads
24+
${{ github.workspace }}/vcpkg/buildtrees
25+
${{ github.workspace }}/build
26+
key: ${{ runner.os }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}
27+
28+
- name: vcpkg setup
29+
run: |
30+
git clone https://github.com/microsoft/vcpkg.git --depth 1 ${{ env.VCPKG_ROOT }}
31+
.\vcpkg\bootstrap-vcpkg.bat -disableMetrics
32+
33+
- name: MSVC config
34+
uses: ilammy/msvc-dev-cmd@v1
35+
36+
- name: CMake config
37+
run: |
38+
cmake --preset release -DCMAKE_TOOLCHAIN_FILE="${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake"
39+
40+
- name: CMake build
41+
run: |
42+
cmake --build build/release
43+
44+
- name: Save artifact
45+
if: github.event_name == 'workflow_dispatch'
46+
uses: actions/upload-artifact@v4
47+
with:
48+
name: upload-artefact
49+
path: build/release/skylua.dll

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/release

CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
cmake_minimum_required(VERSION 3.18)
2+
3+
set(CMAKE_CXX_STANDARD 23)
4+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
5+
set(CMAKE_CXX_FLAGS_RELEASE "/O2 /Ob3 /DNDEBUG")
6+
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
7+
8+
project(skylua VERSION 0.1.0 LANGUAGES CXX)
9+
include(GNUInstallDirs)
10+
11+
find_package(mimalloc CONFIG REQUIRED)
12+
find_package(CommonLibSSE CONFIG REQUIRED)
13+
find_package(PkgConfig REQUIRED)
14+
15+
pkg_check_modules(LuaJIT REQUIRED IMPORTED_TARGET luajit)
16+
find_path(SOL2_INCLUDE_DIRS "sol/abort.hpp")
17+
18+
add_commonlibsse_plugin(${PROJECT_NAME} SOURCES src/plugin.cpp)
19+
target_precompile_headers(${PROJECT_NAME} PRIVATE src/pch.h)
20+
target_include_directories(${PROJECT_NAME} PRIVATE ${SOL2_INCLUDE_DIRS} vendor)
21+
target_link_libraries(${PROJECT_NAME} PRIVATE mimalloc-static PkgConfig::LuaJIT)
22+
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23)

CMakePresets.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"version": 3,
3+
"configurePresets": [
4+
{
5+
"name": "base",
6+
"hidden": true,
7+
"generator": "Ninja",
8+
"binaryDir": "${sourceDir}/build/${presetName}",
9+
"installDir": "${sourceDir}/install/${presetName}",
10+
"architecture": { "value": "x64", "strategy": "external" },
11+
"cacheVariables": {
12+
"CMAKE_CXX_COMPILER": "cl.exe",
13+
"CMAKE_CXX_FLAGS": "/options:strict /Qpar /jumptablerdata /utf-8 /Zc:char8_t- /Zc:inline /std:c++latest /Zc:throwingNew /permissive- /WL /Zc:preprocessor /Zc:__cplusplus /fp:fast /O2 /Ob3 /EHsc /GL /Gw /GR- /MP /W4 -DWIN32_LEAN_AND_MEAN -DNOMINMAX -DUNICODE -D_UNICODE",
14+
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
15+
"VCPKG_TARGET_TRIPLET": "x64-windows-static",
16+
"VCPKG_OVERLAY_TRIPLETS": "${sourceDir}/cmake",
17+
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>",
18+
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
19+
}
20+
},
21+
{
22+
"name": "debug",
23+
"inherits": ["base"],
24+
"displayName": "Debug",
25+
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }
26+
},
27+
{
28+
"name": "release",
29+
"inherits": ["base"],
30+
"displayName": "Release",
31+
"cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
32+
}
33+
]
34+
}

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,22 @@
1-
# skylua
1+
# skylua
2+
3+
skylua glues LuaJIT via sol2 and CommonLibSSE NG to provide an embedded, fast and lightweight scripting runtime for Skyrim
4+
5+
## features
6+
7+
* Lua 5.1 (JIT)
8+
* bitwise support
9+
- hot reload
10+
11+
## example
12+
13+
```lua
14+
function SkyLua.OnTick()
15+
SkyLua.notify("hello world")
16+
end
17+
```
18+
19+
## requirements
20+
21+
- SKSE to load .dll
22+

src/cfg.hpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
#include "fs.hpp"
4+
5+
namespace cfg {
6+
enum class LuaLibs { DEFAULT, FULL };
7+
8+
static constexpr auto cfg_file_name = "skylua.json"sv;
9+
static inline const auto cfg_path =
10+
fs::FindOrCreateDirectory<fs::Destination::RUNTIME>() / cfg_file_name;
11+
12+
struct Config {
13+
spdlog::level::level_enum log_level{spdlog::level::trace};
14+
std::uint64_t tick_rate{1000};
15+
bool enable_hot_reload{true};
16+
LuaLibs lua_libs{LuaLibs::DEFAULT};
17+
};
18+
19+
static const Config* LoadOrDefault(bool force_reload = false) {
20+
static Config config{};
21+
static bool first_load{true};
22+
23+
if (first_load || force_reload) {
24+
auto _res = std::filesystem::exists(cfg_path)
25+
? glz::read_file_json(config, cfg_path.string(), std::string{})
26+
: glz::write_file_json(config, cfg_path.string(), std::string{});
27+
first_load = false;
28+
}
29+
return &config;
30+
}
31+
32+
inline auto LoadLuaLibs(sol::state& lua) {
33+
LoadOrDefault()->lua_libs == LuaLibs::DEFAULT
34+
? lua.open_libraries(sol::lib::bit32, sol::lib::table)
35+
: lua.open_libraries();
36+
}
37+
}
38+
39+
template <>
40+
struct glz::meta<cfg::LuaLibs> {
41+
using enum cfg::LuaLibs;
42+
static constexpr auto value = enumerate(DEFAULT, FULL);
43+
};

src/ecs.hpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#pragma once
2+
3+
#include "entt.hpp"
4+
#include "fs.hpp"
5+
#include "lua.hpp"
6+
7+
namespace ecs {
8+
typedef fs::LuaFile Fd;
9+
typedef std::unique_ptr<lua::ScopedState> State;
10+
typedef sol::protected_function Tick;
11+
12+
inline entt::registry registry;
13+
14+
template <glue::GameEvent>
15+
struct EventHandler {
16+
sol::protected_function handler;
17+
};
18+
19+
[[noreturn]] static void LatentTick() {
20+
static const auto tick_rate = std::chrono::milliseconds(cfg::LoadOrDefault()->tick_rate);
21+
22+
for (;;) {
23+
std::this_thread::sleep_for(tick_rate);
24+
25+
SKSE::GetTaskInterface()->AddTask([] {
26+
auto view = registry.view<const Tick>();
27+
for (auto [_, tick] : view.each()) tick();
28+
});
29+
}
30+
}
31+
32+
inline auto EnableLatentTick() { std::jthread(&LatentTick).detach(); }
33+
34+
inline auto BindEventHandlersToEntity(const entt::entity& ent,
35+
std::unique_ptr<lua::ScopedState>& state) {
36+
magic_enum::enum_for_each<glue::GameEvent>([&](auto val) {
37+
constexpr auto func_name = glue::GetLuaFuncName<val>();
38+
state->logger->trace("Checking handler: {}", func_name);
39+
sol::protected_function func = state->skylua[func_name];
40+
if (func.valid()) {
41+
state->logger->info("Bound {}", func_name);
42+
registry.emplace<EventHandler<val>>(ent, std::move(func));
43+
}
44+
});
45+
}
46+
47+
inline auto AddLuaFileToRegistry(const fs::LuaFile& fd) {
48+
const auto e = registry.create();
49+
auto state = lua::ScopedState::FromPath(fd);
50+
if (auto maybe_tick = state->MaybeGetTick()) {
51+
state->logger->trace("Tick registered for: {}", state->name);
52+
registry.emplace<Tick>(e, maybe_tick.value());
53+
}
54+
BindEventHandlersToEntity(e, state);
55+
registry.emplace<State>(e, std::move(state));
56+
registry.emplace<Fd>(e, fd);
57+
}
58+
59+
inline auto UnbindAllEventHandlersForEntity(const entt::entity& e) {
60+
magic_enum::enum_for_each<glue::GameEvent>([&](auto val) {
61+
if (auto maybe_handler = registry.try_get<EventHandler<val>>(e)) {
62+
maybe_handler->handler.abandon();
63+
}
64+
});
65+
66+
if (auto maybe_tick = registry.try_get<Tick>(e)) {
67+
maybe_tick->abandon();
68+
}
69+
}
70+
71+
inline auto RebuildEntityForPath(const fs::LuaFile& fd) {
72+
for (auto e : registry.view<const Fd>()) {
73+
auto ent_fd = registry.get<const Fd>(e);
74+
if (ent_fd.relative_path_str == fd.relative_path_str) {
75+
UnbindAllEventHandlersForEntity(e);
76+
registry.destroy(e);
77+
AddLuaFileToRegistry(ent_fd);
78+
}
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)