Skip to content

Commit 11a28c0

Browse files
committed
Begin adding Lua scripting
1 parent c054016 commit 11a28c0

File tree

15 files changed

+30590
-6
lines changed

15 files changed

+30590
-6
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ General
1111
* Added Dear ImGui support for debug UI's
1212
* Replaced the normal .pak archives with .gpak (NEW!!!!!!!!!)
1313

14+
Scripting
15+
=========
16+
* Added Lua scripting support
17+
1418
AppBase
1519
===========
1620
* Replaced the Windows API input parsing with SDL3 events.

CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ FetchContent_Declare(
141141
GIT_TAG main
142142
)
143143

144+
FetchContent_Declare(
145+
Lua
146+
GIT_REPOSITORY https://github.com/walterschell/Lua
147+
GIT_TAG master
148+
)
149+
144150
# the most hackiest hacks i've ever done
145151
if(APPLE)
146152
find_library(OPENAL_LIBRARY OpenAL REQUIRED)
@@ -206,7 +212,7 @@ FetchContent_Declare(
206212
GIT_TAG master
207213
)
208214

209-
FetchContent_MakeAvailable(SDL3 SDL3_TTF miniaudio ogg vorbis curl zlib discordrpc glm)
215+
FetchContent_MakeAvailable(SDL3 SDL3_TTF miniaudio ogg vorbis curl zlib discordrpc glm Lua)
210216

211217
add_subdirectory(external/misc EXCLUDE_FROM_ALL)
212218
add_subdirectory(PopLib)

PopLib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC
157157
zlibstatic
158158
glm
159159
misc
160+
lua_static
160161
${OPENMPT_LIBRARIES}
161162
)
162163

PopLib/appbase.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "math/mtrand.hpp"
1515
#include "readwrite/modval.hpp"
1616
#include "debug/sehcatcher.hpp"
17+
#include "scripting/scripting_base.hpp"
1718
#ifdef _WIN32
1819
#include <direct.h>
1920
#else
@@ -219,6 +220,8 @@ AppBase::AppBase()
219220
mWindowAspect.Set(4, 3);
220221
mIsWideWindow = false;
221222

223+
m_pScriptingBase = nullptr;
224+
222225
int i;
223226

224227
using underlying = std::underlying_type_t<CursorType>;
@@ -1385,6 +1388,9 @@ void AppBase::ShutdownHook()
13851388

13861389
void AppBase::Shutdown()
13871390
{
1391+
if (m_pScriptingBase)
1392+
m_pScriptingBase->Shutdown();
1393+
13881394
if ((mPrimaryThreadId != 0) && (SDL_GetCurrentThreadID() != mPrimaryThreadId))
13891395
{
13901396
mLoadingFailed = true;
@@ -2243,6 +2249,12 @@ void AppBase::MakeWindow()
22432249
}
22442250
}
22452251

2252+
if (!m_pScriptingBase)
2253+
{
2254+
m_pScriptingBase = new ScriptingBase();
2255+
m_pScriptingBase->Initialize();
2256+
}
2257+
22462258
int aResult = InitInterface();
22472259

22482260
bool isActive = mActive;
@@ -3377,6 +3389,10 @@ void AppBase::Init()
33773389

33783390
InitHook();
33793391

3392+
// ok, i assume here
3393+
m_pScriptingBase->SetScriptFolder("scripts/");
3394+
m_pScriptingBase->ExecuteFolder("");
3395+
33803396
mInitialized = true;
33813397
}
33823398

PopLib/appbase.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <SDL3/SDL.h>
1818
#include <SDL3_ttf/SDL_ttf.h>
1919

20+
class ScriptingBase;
21+
2022
/**
2123
* @brief registry types, but json
2224
*/
@@ -409,6 +411,9 @@ class AppBase : public ButtonListener, public DialogListener
409411
/// @brief true if widescreen window
410412
bool mIsWideWindow;
411413

414+
/// @brief Scripting interface
415+
ScriptingBase* m_pScriptingBase;
416+
412417
/// @brief the number of loading thread tasks
413418
int mNumLoadingThreadTasks;
414419
/// @brief the number of completed loading thread tasks

PopLib/math/rect.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#include "common.hpp"
77
#include "point.hpp"
8-
8+
#include <algorithm>
99
#include <list>
1010

1111
#ifndef _WIN32
@@ -56,10 +56,10 @@ template <class _T> class TRect
5656

5757
TRect<_T> Union(const TRect<_T> &theTRect)
5858
{
59-
_T x1 = min(mX, theTRect.mX);
60-
_T x2 = max(mX + mWidth, theTRect.mX + theTRect.mWidth);
61-
_T y1 = min(mY, theTRect.mY);
62-
_T y2 = max(mY + mHeight, theTRect.mY + theTRect.mHeight);
59+
_T x1 = std::min(mX, theTRect.mX);
60+
_T x2 = std::max(mX + mWidth, theTRect.mX + theTRect.mWidth);
61+
_T y1 = std::min(mY, theTRect.mY);
62+
_T y2 = std::max(mY + mHeight, theTRect.mY + theTRect.mHeight);
6363
return TRect<_T>(x1, y1, x2 - x1, y2 - y1);
6464
}
6565

PopLib/scripting/lua/lpoplib.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "lpoplib.hpp"
2+
3+
void pop_openlibs(sol::state &lua)
4+
{
5+
open_rect(lua);
6+
}

PopLib/scripting/lua/lpoplib.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef LPOPLIB_HPP
2+
#define LPOPLIB_HPP
3+
4+
#pragma once
5+
6+
#include <sol/sol.hpp>
7+
#include "../scripting_base.hpp"
8+
9+
void(open_rect)(sol::state_view lua);
10+
11+
void(pop_openlibs)(sol::state &lua);
12+
13+
#endif

PopLib/scripting/lua/lrect.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include "lpoplib.hpp"
2+
#include "math/rect.hpp"
3+
4+
using namespace PopLib;
5+
6+
void open_rect(sol::state_view lua)
7+
{
8+
sol::table poplib;
9+
if (lua["PopLib"].valid() && lua["PopLib"].get_type() == sol::type::table)
10+
{
11+
poplib = lua["PopLib"];
12+
}
13+
else
14+
{
15+
poplib = lua.create_table();
16+
lua["PopLib"] = poplib;
17+
}
18+
19+
poplib.new_usertype<PopLib::Rect>(
20+
"Rect",
21+
sol::constructors<PopLib::Rect(), PopLib::Rect(int, int, int, int), PopLib::Rect(const PopLib::Rect &)>(), "mX",
22+
&PopLib::Rect::mX, "mY", &PopLib::Rect::mY, "mWidth", &PopLib::Rect::mWidth, "mHeight", &PopLib::Rect::mHeight,
23+
24+
"Intersects", &PopLib::Rect::Intersects, "Intersection", &PopLib::Rect::Intersection, "Union",
25+
static_cast<PopLib::Rect (PopLib::Rect::*)(const PopLib::Rect &)>(&PopLib::Rect::Union), "Contains",
26+
sol::overload(static_cast<bool (PopLib::Rect::*)(int, int) const>(&PopLib::Rect::Contains),
27+
static_cast<bool (PopLib::Rect::*)(const PopLib::TPoint<int> &) const>(&PopLib::Rect::Contains)),
28+
"Offset",
29+
sol::overload(static_cast<void (PopLib::Rect::*)(int, int)>(&PopLib::Rect::Offset),
30+
static_cast<void (PopLib::Rect::*)(const PopLib::TPoint<int> &)>(&PopLib::Rect::Offset)),
31+
"Inflate", &PopLib::Rect::Inflate, sol::meta_function::to_string,
32+
[](const PopLib::Rect &r) {
33+
return "Rect(" + std::to_string(r.mX) + "," + std::to_string(r.mY) + "," + std::to_string(r.mWidth) + "," +
34+
std::to_string(r.mHeight) + ")";
35+
},
36+
sol::meta_function::equal_to, &PopLib::Rect::operator==);
37+
38+
poplib.new_usertype<PopLib::FRect>(
39+
"FRect",
40+
sol::constructors<PopLib::FRect(), PopLib::FRect(double, double, double, double),
41+
PopLib::FRect(const PopLib::FRect &)>(),
42+
"mX", &PopLib::FRect::mX, "mY", &PopLib::FRect::mY, "mWidth", &PopLib::FRect::mWidth, "mHeight",
43+
&PopLib::FRect::mHeight,
44+
45+
"Intersects", &PopLib::FRect::Intersects, "Intersection", &PopLib::FRect::Intersection, "Union",
46+
static_cast<PopLib::FRect (PopLib::FRect::*)(const PopLib::FRect &)>(&PopLib::FRect::Union), "Contains",
47+
sol::overload(
48+
static_cast<bool (PopLib::FRect::*)(double, double) const>(&PopLib::FRect::Contains),
49+
static_cast<bool (PopLib::FRect::*)(const PopLib::TPoint<double> &) const>(&PopLib::FRect::Contains)),
50+
"Offset",
51+
sol::overload(static_cast<void (PopLib::FRect::*)(double, double)>(&PopLib::FRect::Offset),
52+
static_cast<void (PopLib::FRect::*)(const PopLib::TPoint<double> &)>(&PopLib::FRect::Offset)),
53+
"Inflate", &PopLib::FRect::Inflate, sol::meta_function::to_string,
54+
[](const PopLib::FRect &r) {
55+
return "FRect(" + std::to_string(r.mX) + "," + std::to_string(r.mY) + "," + std::to_string(r.mWidth) + "," +
56+
std::to_string(r.mHeight) + ")";
57+
},
58+
sol::meta_function::equal_to, &PopLib::FRect::operator==);
59+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#include "scripting_base.hpp"
2+
#include "debug/log.hpp"
3+
#include "lua/lpoplib.hpp"
4+
#include <filesystem>
5+
6+
using namespace PopLib;
7+
8+
bool ScriptingBase::Initialize()
9+
{
10+
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::os, sol::lib::string, sol::lib::math,
11+
sol::lib::table);
12+
13+
LOG_INFO("Lua scripting initialized");
14+
15+
pop_openlibs(lua);
16+
17+
// replace print
18+
lua["print"] = [](sol::variadic_args va) {
19+
std::string combined;
20+
bool first = true;
21+
for (auto v : va)
22+
{
23+
if (!first)
24+
combined += "\t";
25+
first = false;
26+
27+
if (v.is<std::string>())
28+
{
29+
combined += v.as<std::string>();
30+
}
31+
else if (v.is<bool>())
32+
{
33+
combined += (v.as<bool>() ? "true" : "false");
34+
}
35+
else if (v.is<double>())
36+
{
37+
combined += std::to_string(v.as<double>());
38+
}
39+
else if (v.is<int>())
40+
{
41+
combined += std::to_string(v.as<int>());
42+
}
43+
else
44+
{
45+
combined += "<non-printable>";
46+
}
47+
}
48+
LOG_INFO(combined.c_str());
49+
};
50+
51+
return true;
52+
}
53+
54+
void ScriptingBase::Shutdown()
55+
{
56+
lua.collect_garbage();
57+
LOG_INFO("Lua scripting shut down");
58+
}
59+
60+
bool ScriptingBase::ExecuteFile(const PopString &fileName)
61+
{
62+
std::filesystem::path fullPath = std::filesystem::path(scriptFolder) / fileName;
63+
64+
if (!std::filesystem::exists(fullPath))
65+
{
66+
LOG_ERROR("Lua file not found: %s", fullPath.c_str());
67+
return false;
68+
}
69+
70+
auto result = lua.safe_script_file(
71+
fullPath.string(), [](lua_State * /*L*/, sol::protected_function_result pfr) -> sol::protected_function_result {
72+
if (!pfr.valid())
73+
{
74+
sol::error err = pfr;
75+
LOG_ERROR("Lua execution error: %s", err.what());
76+
}
77+
return pfr;
78+
});
79+
80+
if (!result.valid())
81+
{
82+
sol::error err = result;
83+
LOG_ERROR("Failed to execute file '%s': %s", fullPath.string().c_str(), err.what());
84+
return false;
85+
}
86+
87+
LOG_INFO("Executed Lua file: %s", fullPath.string().c_str());
88+
return true;
89+
}
90+
91+
bool ScriptingBase::ExecuteString(const PopString &code)
92+
{
93+
auto result = lua.safe_script(
94+
std::string(code), [](lua_State * /*L*/, sol::protected_function_result pfr) -> sol::protected_function_result {
95+
if (!pfr.valid())
96+
{
97+
sol::error err = pfr;
98+
LOG_ERROR("Lua execution error: %s", err.what());
99+
}
100+
return pfr;
101+
});
102+
103+
if (!result.valid())
104+
{
105+
sol::error err = result;
106+
LOG_ERROR("Failed to execute Lua string: %s", err.what());
107+
return false;
108+
}
109+
110+
return true;
111+
}
112+
113+
bool ScriptingBase::ExecuteFolder(const PopString &folderPath)
114+
{
115+
std::filesystem::path fullPath = folderPath.empty() ? scriptFolder : folderPath;
116+
117+
if (!std::filesystem::exists(fullPath) || !std::filesystem::is_directory(fullPath))
118+
{
119+
LOG_ERROR("Lua folder not found: %s", fullPath.string().c_str());
120+
return false;
121+
}
122+
123+
for (auto &entry : std::filesystem::directory_iterator(fullPath))
124+
{
125+
if (entry.is_regular_file() && entry.path().extension() == ".lua")
126+
{
127+
LOG_INFO("Executing Lua file: %s", entry.path().string().c_str());
128+
if (!ExecuteFile(entry.path().filename().string()))
129+
{
130+
LOG_ERROR("Failed to execute Lua file: %s", entry.path().string().c_str());
131+
return false;
132+
}
133+
}
134+
}
135+
136+
return true;
137+
}

0 commit comments

Comments
 (0)