Skip to content

Commit 893bb58

Browse files
authored
Merge pull request #55 from apple1417/master
swap configuration to be toml based
2 parents b5ceb8e + 0c6d28c commit 893bb58

File tree

13 files changed

+121
-43
lines changed

13 files changed

+121
-43
lines changed

Readme.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@ accept arguments into `sys.argv`.
3535

3636
## Initialization Script
3737
If you want to make more permanent mods, you'll want to use the initialization script. By default
38-
this is `__main__.py` in the game's cwd, though you can overwrite this with the
39-
`PYUNREALSDK_INIT_SCRIPT` environment variable. The initialization script is automatically run after
40-
sdk initialization, so you can use it to import other files and generally perform all your setup.
38+
this is `__main__.py` in the game's cwd. The initialization script is automatically run after sdk
39+
initialization, so you can use it to import other files and generally perform all your setup.
40+
41+
You can swap to a different initialization script by using setting `pyunrealsdk.init_script` in the
42+
[unrealsdk configuration file](https://github.com/bl-sdk/unrealsdk/#configuration). If you do this
43+
you may also want to set `pyunrealsdk.pyexec_root`, so that `pyexec` commands work from the same
44+
folder.
4145

4246
## Using SDK bindings
4347
Once you've got code running, you probably want to setup some hooks - the sdk can run callbacks
@@ -87,7 +91,7 @@ To use it:
8791
debugpy.listen(("localhost", 5678), in_process_debug_adapter=True)
8892
```
8993

90-
3. Define the environment variable `PYUNREALSDK_DEBUGPY`.
94+
3. Set `pyunrealsdk.debugpy = True` in the [unrealsdk configuration file](https://github.com/bl-sdk/unrealsdk/#configuration).
9195

9296
4. Attach using remote debugging with the debugger of your choice.
9397

changelog.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@
77

88
[59f474fe](https://github.com/bl-sdk/pyunrealsdk/commit/59f474fe)
99

10+
- The `WeakPointer` constructor can now be called with no args, to create a null pointer.
11+
12+
[59f474fe](https://github.com/bl-sdk/pyunrealsdk/commit/59f474fe)
13+
14+
- As with unrealsdk, reworked the configuration system to no longer rely on environment variables.
15+
All sdk configuration is now also done through the `unrealsdk.toml`.
16+
17+
The full contents of the unrealsdk config are parsed and exposed to Python in `unrealsdk.config`.
18+
19+
[ecde0a83](https://github.com/bl-sdk/pyunrealsdk/commit/ecde0a83)
20+
1021
## v1.4.0
1122

1223
- Fixed weak pointer type hinting to allow for null pointers. This always worked at runtime.

src/pyunrealsdk/base_bindings.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#include "pyunrealsdk/pch.h"
22
#include "pyunrealsdk/base_bindings.h"
3+
#include "pyunrealsdk/logging.h"
34
#include "pyunrealsdk/unreal_bindings/uenum.h"
45
#include "pyunrealsdk/unreal_bindings/wrapped_struct.h"
6+
#include "unrealsdk/config.h"
57
#include "unrealsdk/unreal/classes/uclass.h"
68
#include "unrealsdk/unreal/classes/uenum.h"
79
#include "unrealsdk/unreal/classes/uobject.h"
@@ -85,6 +87,87 @@ UClass* evaluate_class_arg(const std::variant<UClass*, std::wstring>& cls_arg) {
8587
return cls_ptr;
8688
}
8789

90+
/**
91+
* @brief Recursively merges two toml tables.
92+
*
93+
* @param base The base table. Modified in place.
94+
* @param overrides The overrides tables.
95+
*/
96+
void recursive_merge_table(py::dict& base, const py::dict& overrides) {
97+
for (auto [key, value] : overrides) {
98+
if (py::isinstance<py::dict>(value)) {
99+
if (base.contains(key)) {
100+
auto base_value = base[key];
101+
if (py::isinstance<py::dict>(base_value)) {
102+
auto base_dict = base_value.cast<py::dict>();
103+
auto overrides_dict = value.cast<py::dict>();
104+
recursive_merge_table(base_dict, overrides_dict);
105+
continue;
106+
}
107+
}
108+
}
109+
base[key] = value;
110+
}
111+
}
112+
113+
/**
114+
* @brief Creates the config dict, and adds it to the given module.
115+
*
116+
* @param mod The module to add the config dict to.
117+
*/
118+
void create_and_add_config_dict(py::module_& mod) {
119+
// We want to copy the full, merged, unrealsdk config into Python.
120+
// Only a few basic accessors into the config dict are exposed, since we can't safely expose
121+
// the toml objects across dlls.
122+
// Properly converting toml from the C++ side into Python is also a bit awkward, with all the
123+
// different types.
124+
125+
// Instead, to get everything in Python more easily, we'll just load the config files directly
126+
// in Python to begin with.
127+
128+
auto load_config_file = [](const std::filesystem::path&& path) -> py::object {
129+
try {
130+
const py::dict globals{"path"_a = path};
131+
py::exec(
132+
"import tomllib\n"
133+
"with path.open(\"rb\") as file:\n"
134+
" config = tomllib.load(file)\n",
135+
globals);
136+
return globals["config"];
137+
138+
} catch (const std::exception& ex) {
139+
LOG(ERROR, "Failed to load {}", path.string());
140+
logging::log_python_exception(ex);
141+
return py::none{};
142+
}
143+
};
144+
145+
auto base_config = load_config_file(unrealsdk::config::get_base_config_file_path());
146+
auto user_config = load_config_file(unrealsdk::config::get_user_config_file_path());
147+
148+
if (!py::isinstance<py::dict>(base_config)) {
149+
if (py::isinstance<py::dict>(user_config)) {
150+
// Only user config got loaded
151+
mod.attr("config") = user_config;
152+
return;
153+
}
154+
// No config files got loaded, just create a default dict
155+
mod.attr("config") = py::dict{};
156+
return;
157+
}
158+
if (!py::isinstance<py::dict>(user_config)) {
159+
// Only base config got loaded
160+
mod.attr("config") = base_config;
161+
return;
162+
}
163+
164+
// Both configs were loaded, we need to merge them
165+
auto base_dict = base_config.cast<py::dict>();
166+
auto user_dict = user_config.cast<py::dict>();
167+
recursive_merge_table(base_dict, user_dict);
168+
mod.attr("config") = base_dict;
169+
}
170+
88171
} // namespace
89172

90173
void register_base_bindings(py::module_& mod) {
@@ -251,6 +334,8 @@ void register_base_bindings(py::module_& mod) {
251334
"Returns:\n"
252335
" The loaded `Package` object.",
253336
"name"_a, "flags"_a = 0);
337+
338+
create_and_add_config_dict(mod);
254339
}
255340

256341
} // namespace pyunrealsdk

src/pyunrealsdk/commands.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#include "pyunrealsdk/pch.h"
22
#include "pyunrealsdk/commands.h"
33
#include "pyunrealsdk/debugging.h"
4-
#include "pyunrealsdk/env.h"
54
#include "pyunrealsdk/logging.h"
65
#include "unrealsdk/commands.h"
6+
#include "unrealsdk/config.h"
77
#include "unrealsdk/utils.h"
88

99
#ifdef PYUNREALSDK_INTERNAL
@@ -13,7 +13,8 @@ namespace pyunrealsdk::commands {
1313
namespace {
1414

1515
void pyexec_cmd_handler(const wchar_t* line, size_t size, size_t cmd_len) {
16-
static const std::filesystem::path root = env::get(env::PYEXEC_ROOT);
16+
static const std::filesystem::path root =
17+
unrealsdk::config::get_str("pyunrealsdk.pyexec_root").value_or("");
1718

1819
auto file_start = std::find_if_not(line + cmd_len, line + size, &std::iswspace);
1920
const size_t file_len = (line + size) - file_start;

src/pyunrealsdk/debugging.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include "pyunrealsdk/pch.h"
22
#include "pyunrealsdk/debugging.h"
3-
#include "pyunrealsdk/env.h"
43
#include "pyunrealsdk/exports.h"
54
#include "pyunrealsdk/static_py_object.h"
5+
#include "unrealsdk/config.h"
66

77
namespace pyunrealsdk {
88

@@ -32,7 +32,7 @@ PYUNREALSDK_CAPI(void, debug_this_thread) {
3232
auto& debugpy_debug_this_thread =
3333
storage
3434
.call_once_and_store_result([]() -> py::object {
35-
if (env::defined(env::DEBUGPY)) {
35+
if (unrealsdk::config::get_bool("pyunrealsdk.debugpy").value_or(false)) {
3636
try {
3737
return py::module_::import("debugpy").attr("debug_this_thread");
3838
} catch (const py::error_already_set&) {}

src/pyunrealsdk/env.h

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/pyunrealsdk/pch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <pybind11/embed.h>
2626
#include <pybind11/pybind11.h>
2727
#include <pybind11/stl.h>
28+
#include <pybind11/stl/filesystem.h>
2829

2930
// NOLINTNEXTLINE(misc-unused-alias-decls)
3031
namespace py = pybind11;

src/pyunrealsdk/pyunrealsdk.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
#include "pyunrealsdk/pyunrealsdk.h"
33
#include "pyunrealsdk/base_bindings.h"
44
#include "pyunrealsdk/commands.h"
5-
#include "pyunrealsdk/env.h"
65
#include "pyunrealsdk/hooks.h"
76
#include "pyunrealsdk/logging.h"
87
#include "pyunrealsdk/unreal_bindings/bindings.h"
98
#include "pyunrealsdk/version.h"
9+
#include "unrealsdk/config.h"
1010
#include "unrealsdk/unrealsdk.h"
1111
#include "unrealsdk/version.h"
1212

@@ -73,7 +73,8 @@ void init(void) {
7373
try {
7474
// Use a custom globals to make sure we don't contaminate `py`/`pyexec` commands
7575
// This also ensures `__file__` gets redefined properly
76-
py::eval_file(env::get(env::INIT_SCRIPT, env::defaults::INIT_SCRIPT), py::dict{});
76+
py::eval_file(unrealsdk::config::get_str("pyunrealsdk.init_script").value_or("__main__.py"),
77+
py::dict{});
7778
} catch (const std::exception& ex) {
7879
LOG(ERROR, "Error running python initialization script:");
7980
logging::log_python_exception(ex);

src/pyunrealsdk/unreal_bindings/weak_pointer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void register_weak_pointer(py::module_& mod) {
2121
"\n"
2222
"Args:\n"
2323
" obj: The object to create a weak reference to.",
24-
"obj"_a)
24+
"obj"_a = nullptr)
2525
.def(
2626
"__call__",
2727
// Take a mutable reference, since the mutable dereference can do some optimizations

0 commit comments

Comments
 (0)