From 903d270b028b4ab7df5d5875ea0f217ae6c857d9 Mon Sep 17 00:00:00 2001 From: craftablescience Date: Fri, 18 Oct 2024 03:32:37 -0400 Subject: [PATCH 1/8] chore(ext): bump miniz --- ext/miniz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/miniz b/ext/miniz index 1ff82be7d..35528ad76 160000 --- a/ext/miniz +++ b/ext/miniz @@ -1 +1 @@ -Subproject commit 1ff82be7d67f5c2f8b5497f538eea247861e0717 +Subproject commit 35528ad769143b9ed38a95a22d460b963e39f278 From 3cf3268c286298b3124c0cf761b6fb1dc78cf020 Mon Sep 17 00:00:00 2001 From: craftablescience Date: Fri, 18 Oct 2024 03:32:50 -0400 Subject: [PATCH 2/8] chore(gamepp): apply IDE suggestions --- src/gamepp/gamepp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gamepp/gamepp.cpp b/src/gamepp/gamepp.cpp index b44892da9..d07b4aef5 100644 --- a/src/gamepp/gamepp.cpp +++ b/src/gamepp/gamepp.cpp @@ -13,7 +13,7 @@ using namespace sourcepp; #include std::optional GameInstance::find(std::string_view windowNameOverride) { - GameInstance instance; + GameInstance instance{}; if (!windowNameOverride.empty()) { instance.hwnd = FindWindowA(windowNameOverride.data(), nullptr); @@ -34,7 +34,7 @@ std::optional GameInstance::find(std::string_view windowNameOverri std::string GameInstance::getWindowTitle() const { // This should be large enough std::string title(512, '\0'); - if (auto size = GetWindowTextA(reinterpret_cast(this->hwnd), title.data(), title.length())) { + if (auto size = GetWindowTextA(reinterpret_cast(this->hwnd), title.data(), static_cast(title.length()))) { title.resize(size); return title; } From 376346c4e07cce8c2b57ee7bda5df2e61fe67458 Mon Sep 17 00:00:00 2001 From: craftablescience Date: Fri, 18 Oct 2024 03:33:11 -0400 Subject: [PATCH 3/8] chore(vtfpp): remove uint24_t leftover type --- include/sourcepp/math/Integer.h | 114 +------------------------------- include/sourcepp/math/Vector.h | 5 +- src/vtfpp/VTF.cpp | 4 +- 3 files changed, 5 insertions(+), 118 deletions(-) diff --git a/include/sourcepp/math/Integer.h b/include/sourcepp/math/Integer.h index d245fc014..7de6f416e 100644 --- a/include/sourcepp/math/Integer.h +++ b/include/sourcepp/math/Integer.h @@ -15,122 +15,10 @@ using std::uint16_t; using std::uint32_t; using std::uint64_t; -/// 3-byte wide unsigned integer -struct uint24_t { - uint24_t() = default; - - template - constexpr uint24_t(T value) // NOLINT(*-explicit-constructor) - : bytes{ - static_cast((value >> 16) & 0xff), - static_cast((value >> 8) & 0xff), - static_cast( value & 0xff), - } {} - - template - [[nodiscard]] constexpr operator T() const { // NOLINT(*-explicit-constructor) - return static_cast((bytes[0] << 16) | (bytes[1] << 8) | bytes[2]); - } - - template - constexpr uint24_t& operator=(T value) { - *this = {value}; - return *this; - } - - template - [[nodiscard]] constexpr uint24_t operator+(T value) const { - return {uint32_t{*this} + value}; - } - - template - constexpr void operator+=(T value) const { - *this = {uint32_t{*this} + value}; - } - - constexpr uint24_t operator++() { - return *this = {uint32_t{*this} + 1}; - } - - constexpr uint24_t operator++(int) { - uint24_t out{*this}; - *this = {uint32_t{*this} + 1}; - return out; - } - - template - [[nodiscard]] constexpr uint24_t operator-(T value) const { - return {uint32_t{*this} - value}; - } - - template - constexpr void operator-=(T value) const { - return *this = {uint32_t{*this} - value}; - } - - constexpr uint24_t operator--() { - return *this = {uint32_t{*this} - 1}; - } - - constexpr uint24_t operator--(int) { - uint24_t out{*this}; - *this = {uint32_t{*this} - 1}; - return out; - } - - template - [[nodiscard]] constexpr uint24_t operator*(T value) const { - return {uint32_t{*this} * value}; - } - - template - constexpr void operator*=(T value) const { - *this = {uint32_t{*this} * value}; - } - - template - [[nodiscard]] constexpr uint24_t operator/(T value) const { - return {uint32_t{*this} / value}; - } - - template - constexpr void operator/=(T value) const { - *this = {uint32_t{*this} / value}; - } - - template - [[nodiscard]] constexpr uint24_t operator%(T value) const { - return {uint32_t{*this} % value}; - } - - template - constexpr void operator%=(T value) const { - *this = {uint32_t{*this} % value}; - } - - template - [[nodiscard]] constexpr bool operator==(T value) const { - return uint32_t{*this} == value; - } - - template - [[nodiscard]] constexpr auto operator<=>(T value) const { - return uint32_t{*this} <=> value; - } - - [[nodiscard]] constexpr operator bool() const { // NOLINT(*-explicit-constructor) - return static_cast(uint32_t{*this}); - } - - uint8_t bytes[3]; -}; -static_assert(sizeof(uint24_t) == 3, "uint24_t is not 3 bytes wide!"); -static_assert(std::is_trivially_copyable_v, "uint24_t is not a POD type!"); - namespace sourcepp::math { template -concept Arithmetic = std::is_arithmetic_v || std::same_as; +concept Arithmetic = std::is_arithmetic_v; template [[nodiscard]] constexpr T remap(T value, T l1, T h1, T l2, T h2) { diff --git a/include/sourcepp/math/Vector.h b/include/sourcepp/math/Vector.h index b50ad76fd..d4395b81f 100644 --- a/include/sourcepp/math/Vector.h +++ b/include/sourcepp/math/Vector.h @@ -28,7 +28,7 @@ struct Vec { using value_type = P; - [[nodiscard]] consteval uint8_t size() const { + [[nodiscard]] constexpr uint8_t size() const { return S; } @@ -252,7 +252,6 @@ using Vec2i = Vec2i32; using Vec2ui8 = Vec2; using Vec2ui16 = Vec2; -using Vec2ui24 = Vec2; using Vec2ui32 = Vec2; using Vec2ui64 = Vec2; using Vec2ui = Vec2ui32; @@ -272,7 +271,6 @@ using Vec3i = Vec3i32; using Vec3ui8 = Vec3; using Vec3ui16 = Vec3; -using Vec3ui24 = Vec3; using Vec3ui32 = Vec3; using Vec3ui64 = Vec3; using Vec3ui = Vec3ui32; @@ -292,7 +290,6 @@ using Vec4i = Vec4i32; using Vec4ui8 = Vec4; using Vec4ui16 = Vec4; -using Vec4ui24 = Vec4; using Vec4ui32 = Vec4; using Vec4ui64 = Vec4; using Vec4ui = Vec4ui32; diff --git a/src/vtfpp/VTF.cpp b/src/vtfpp/VTF.cpp index f7402f339..6d63c1880 100644 --- a/src/vtfpp/VTF.cpp +++ b/src/vtfpp/VTF.cpp @@ -1192,7 +1192,9 @@ std::vector VTF::bake() const { } writer - .write(0) // padding + .write(0) // padding + .write(0) // padding + .write(0) // padding .write(this->getResources().size() + hasAuxCompression) .write(0); // padding From fcbe9dada0cc803dfaec8c8be617fa54e727798a Mon Sep 17 00:00:00 2001 From: craftablescience Date: Fri, 18 Oct 2024 03:42:56 -0400 Subject: [PATCH 4/8] feat(python): add python wrappers for gamepp, steampp --- CMakeLists.txt | 63 ++++++++++++++------ README.md | 4 +- cmake/AddSourcePPLibrary.cmake | 18 ++++-- docs/index.md | 4 +- lang/python/.gitignore | 3 + lang/python/dist/sourcepp/__init__.py | 5 ++ lang/python/src/gamepp.h | 29 +++++++++ lang/python/src/sourcepp.cpp | 25 ++++++++ lang/python/src/sourcepp.h | 85 +++++++++++++++++++++++++++ lang/python/src/steampp.h | 34 +++++++++++ 10 files changed, 242 insertions(+), 28 deletions(-) create mode 100644 lang/python/.gitignore create mode 100644 lang/python/dist/sourcepp/__init__.py create mode 100644 lang/python/src/gamepp.h create mode 100644 lang/python/src/sourcepp.cpp create mode 100644 lang/python/src/sourcepp.h create mode 100644 lang/python/src/steampp.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b45a38798..7447873a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,13 +26,14 @@ option(SOURCEPP_USE_VCRYPTPP "Build vcryptpp library" ${SOURC option(SOURCEPP_USE_VPKPP "Build vpkpp library" ${SOURCEPP_LIBS_START_ENABLED}) option(SOURCEPP_USE_VTFPP "Build vtfpp library" ${SOURCEPP_LIBS_START_ENABLED}) -option(SOURCEPP_BUILD_BENCHMARKS "Build benchmarks for supported libraries" OFF) -option(SOURCEPP_BUILD_C_WRAPPERS "Build C wrappers for supported libraries" OFF) -option(SOURCEPP_BUILD_WITH_OPENCL "Build with support for GPU compute" OFF) -option(SOURCEPP_BUILD_WITH_TBB "Build with support for std::execution" OFF) -option(SOURCEPP_BUILD_WITH_THREADS "Build with support for threading" ON) -option(SOURCEPP_BUILD_TESTS "Build tests for supported libraries" OFF) -option(SOURCEPP_BUILD_WIN7_COMPAT "Build with Windows 7 compatibility" OFF) +option(SOURCEPP_BUILD_BENCHMARKS "Build benchmarks for supported libraries" OFF) +option(SOURCEPP_BUILD_C_WRAPPERS "Build C wrappers for supported libraries" OFF) +option(SOURCEPP_BUILD_PYTHON_WRAPPERS "Build Python wrappers for supported libraries" OFF) +option(SOURCEPP_BUILD_WITH_OPENCL "Build with support for GPU compute" OFF) +option(SOURCEPP_BUILD_WITH_TBB "Build with support for std::execution" OFF) +option(SOURCEPP_BUILD_WITH_THREADS "Build with support for threading" ON) +option(SOURCEPP_BUILD_TESTS "Build tests for supported libraries" OFF) +option(SOURCEPP_BUILD_WIN7_COMPAT "Build with Windows 7 compatibility" OFF) option(SOURCEPP_LINK_STATIC_MSVC_RUNTIME "Link to static MSVC runtime library" OFF) @@ -73,6 +74,7 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(AddPrettyParser) include(AddSourcePPLibrary) +include(FetchContent) include(IncludeSubdirectory) include(PrintOptions) include(TargetOptimize) @@ -92,10 +94,24 @@ if(SOURCEPP_BUILD_C_WRAPPERS) endif() +# Python bindings, part 1 +if(SOURCEPP_BUILD_PYTHON_WRAPPERS) + set(SOURCEPP_PYTHON_NAME "${PROJECT_NAME}_python") + find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) + FetchContent_Declare( + pybind11 + GIT_REPOSITORY "https://github.com/pybind/pybind11.git" + GIT_TAG "v2.13.6") + FetchContent_MakeAvailable(pybind11) + set(${SOURCEPP_PYTHON_NAME}_SOURCES "") + set(${SOURCEPP_PYTHON_NAME}_DEFINES "") + list(APPEND ${SOURCEPP_PYTHON_NAME}_DEPS pybind11::headers) +endif() + + # Tests, part 1 if(SOURCEPP_BUILD_TESTS) set(SOURCEPP_TEST_NAME "${PROJECT_NAME}_test") - include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY "https://github.com/google/googletest.git" @@ -138,16 +154,16 @@ endif() # Add libraries -add_sourcepp_library(bsppp NO_TEST ) # sourcepp::bsppp -add_sourcepp_library(dmxpp ) # sourcepp::dmxpp -add_sourcepp_library(gamepp ) # sourcepp::gamepp -add_sourcepp_library(kvpp BENCH) # sourcepp::kvpp -add_sourcepp_library(mdlpp ) # sourcepp::mdlpp -add_sourcepp_library(steampp C ) # sourcepp::steampp -add_sourcepp_library(toolpp ) # sourcepp::toolpp -add_sourcepp_library(vcryptpp C CSHARP ) # sourcepp::vcryptpp -add_sourcepp_library(vpkpp C CSHARP NO_TEST ) # sourcepp::vpkpp -add_sourcepp_library(vtfpp BENCH) # sourcepp::vtfpp +add_sourcepp_library(bsppp NO_TEST ) # sourcepp::bsppp +add_sourcepp_library(dmxpp ) # sourcepp::dmxpp +add_sourcepp_library(gamepp PYTHON ) # sourcepp::gamepp +add_sourcepp_library(kvpp BENCH) # sourcepp::kvpp +add_sourcepp_library(mdlpp ) # sourcepp::mdlpp +add_sourcepp_library(steampp C PYTHON ) # sourcepp::steampp +add_sourcepp_library(toolpp ) # sourcepp::toolpp +add_sourcepp_library(vcryptpp C CSHARP ) # sourcepp::vcryptpp +add_sourcepp_library(vpkpp C CSHARP NO_TEST ) # sourcepp::vpkpp +add_sourcepp_library(vtfpp BENCH) # sourcepp::vtfpp # Tests, part 2 @@ -160,9 +176,18 @@ if(SOURCEPP_BUILD_TESTS) endif() +# Python bindings, part 2 +if(SOURCEPP_BUILD_PYTHON_WRAPPERS) + python_add_library(${SOURCEPP_PYTHON_NAME} MODULE "${CMAKE_CURRENT_SOURCE_DIR}/lang/python/src/sourcepp.cpp" ${${SOURCEPP_PYTHON_NAME}_SOURCES} WITH_SOABI) + set_target_properties(${SOURCEPP_PYTHON_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lang/python/dist/sourcepp") + target_compile_definitions(${SOURCEPP_PYTHON_NAME} PRIVATE ${${SOURCEPP_PYTHON_NAME}_DEFINES}) + target_link_libraries(${SOURCEPP_PYTHON_NAME} PRIVATE ${${SOURCEPP_PYTHON_NAME}_DEPS}) +endif() + + # Print options print_options(OPTIONS USE_BSPPP USE_DMXPP USE_GAMEPP USE_KVPP USE_MDLPP USE_STEAMPP USE_TOOLPP USE_VCRYPTPP USE_VPKPP USE_VTFPP - BUILD_BENCHMARKS BUILD_C_WRAPPERS BUILD_WITH_OPENCL BUILD_WITH_TBB BUILD_WITH_THREADS BUILD_TESTS BUILD_WIN7_COMPAT + BUILD_BENCHMARKS BUILD_C_WRAPPERS BUILD_PYTHON_WRAPPERS BUILD_WITH_OPENCL BUILD_WITH_TBB BUILD_WITH_THREADS BUILD_TESTS BUILD_WIN7_COMPAT LINK_STATIC_MSVC_RUNTIME VPKPP_SUPPORT_VPK_V54) diff --git a/README.md b/README.md index de78d5c50..ce07d1343 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one Get Source engine instance window title/position/size ✅ ❌ - + Python @@ -84,7 +84,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one Find Steam install folder ✅ - - C + C
Python diff --git a/cmake/AddSourcePPLibrary.cmake b/cmake/AddSourcePPLibrary.cmake index 18a760ed6..b9f62dfe2 100644 --- a/cmake/AddSourcePPLibrary.cmake +++ b/cmake/AddSourcePPLibrary.cmake @@ -1,7 +1,9 @@ function(add_sourcepp_library TARGET) - cmake_parse_arguments(PARSE_ARGV 1 OPTIONS "C;CSHARP;NO_TEST;BENCH" "" "") + cmake_parse_arguments(PARSE_ARGV 1 OPTIONS "C;CSHARP;PYTHON;NO_TEST;BENCH" "" "") string(TOUPPER ${TARGET} TARGET_UPPER) if(SOURCEPP_USE_${TARGET_UPPER}) + set(PROPAGATE_VARS "") + # Add C++ include("${CMAKE_CURRENT_SOURCE_DIR}/src/${TARGET}/_${TARGET}.cmake") @@ -11,23 +13,29 @@ function(add_sourcepp_library TARGET) endif() # Add C# - if(OPTIONS_CSHARP) + if(SOURCEPP_BUILD_C_WRAPPERS AND OPTIONS_CSHARP) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/sourcepp/Buffer.cs.in" "${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/${TARGET}/Buffer.cs") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/sourcepp/String.cs.in" "${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/${TARGET}/String.cs") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/sourcepp/TARGET.csproj.in" "${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/${TARGET}/${TARGET}.csproj") endif() - set(PROPAGATE_VARS "") + # Add Python + if(SOURCEPP_BUILD_PYTHON_WRAPPERS AND OPTIONS_PYTHON) + list(APPEND ${SOURCEPP_PYTHON_NAME}_DEPS sourcepp::${TARGET}) + list(APPEND ${SOURCEPP_PYTHON_NAME}_DEFINES ${TARGET_UPPER}) + list(APPEND ${SOURCEPP_PYTHON_NAME}_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/lang/python/src/${TARGET}.h") + list(APPEND PROPAGATE_VARS ${SOURCEPP_PYTHON_NAME}_DEPS ${SOURCEPP_PYTHON_NAME}_DEFINES ${SOURCEPP_PYTHON_NAME}_SOURCES) + endif() # Add tests - if(NOT OPTIONS_NO_TEST AND SOURCEPP_BUILD_TESTS) + if(SOURCEPP_BUILD_TESTS AND NOT OPTIONS_NO_TEST) list(APPEND ${SOURCEPP_TEST_NAME}_DEPS sourcepp::${TARGET}) list(APPEND ${SOURCEPP_TEST_NAME}_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/test/${TARGET}.cpp") list(APPEND PROPAGATE_VARS ${SOURCEPP_TEST_NAME}_DEPS ${SOURCEPP_TEST_NAME}_SOURCES) endif() # Add benchmarks - if(OPTIONS_BENCH AND SOURCEPP_BUILD_BENCHMARKS) + if(SOURCEPP_BUILD_BENCHMARKS AND OPTIONS_BENCH) add_executable(${TARGET}_bench "${CMAKE_CURRENT_SOURCE_DIR}/bench/${TARGET}.cpp") target_link_libraries(${TARGET}_bench PUBLIC ${SOURCEPP_BENCH_NAME} sourcepp::${TARGET}) include("${CMAKE_CURRENT_SOURCE_DIR}/bench/${TARGET}.cmake") diff --git a/docs/index.md b/docs/index.md index 8d4ff20e3..d951375c6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -40,7 +40,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one Get Source engine instance window title/position/size ✅ ❌ - + Python Run commands in a Source engine instance remotely @@ -76,7 +76,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one Find Steam install folder ✅ - - C + C
Python Find installed Steam games diff --git a/lang/python/.gitignore b/lang/python/.gitignore new file mode 100644 index 000000000..b45f0c509 --- /dev/null +++ b/lang/python/.gitignore @@ -0,0 +1,3 @@ +# Build Files +dist/sourcepp/* +!dist/sourcepp/__init__.py diff --git a/lang/python/dist/sourcepp/__init__.py b/lang/python/dist/sourcepp/__init__.py new file mode 100644 index 000000000..25185e04b --- /dev/null +++ b/lang/python/dist/sourcepp/__init__.py @@ -0,0 +1,5 @@ +from __future__ import annotations + +from .sourcepp_python import __doc__, __version__, gamepp, sourcepp, steampp + +__all__ = ['__doc__', '__version__', 'gamepp', 'sourcepp', 'steampp'] diff --git a/lang/python/src/gamepp.h b/lang/python/src/gamepp.h new file mode 100644 index 000000000..239e0804c --- /dev/null +++ b/lang/python/src/gamepp.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +namespace py = pybind11; + +#include + +namespace gamepp { + +void register_python(py::module_& m) { + using namespace gamepp; + auto gamepp = m.def_submodule("gamepp"); + + py::class_(gamepp, "GameInstance") + .def_static("find", &GameInstance::find, py::arg("window_name_override") = "") + .def_property_readonly("window_title", &GameInstance::getWindowTitle) + .def_property_readonly("window_pos", &GameInstance::getWindowPos) + .def_property_readonly("window_size", &GameInstance::getWindowSize) + .def("command", &GameInstance::command) + .def("input_begin", &GameInstance::inputBegin) + .def("input_end", &GameInstance::inputEnd) + .def("input_once", &GameInstance::inputOnce) + .def("input_hold", &GameInstance::inputHold) + .def("wait", &GameInstance::wait); +} + +} // namespace gamepp diff --git a/lang/python/src/sourcepp.cpp b/lang/python/src/sourcepp.cpp new file mode 100644 index 000000000..20b954b9e --- /dev/null +++ b/lang/python/src/sourcepp.cpp @@ -0,0 +1,25 @@ +#include "sourcepp.h" + +#ifdef GAMEPP +#include "gamepp.h" +#endif + +#ifdef STEAMPP +#include "steampp.h" +#endif + +PYBIND11_MODULE(sourcepp_python, m) { + m.doc() = "SourcePP: A Python wrapper around several modern C++20 libraries for sanely parsing Valve's formats."; + + m.attr("__version__") = "dev"; + + sourcepp::register_python(m); + +#ifdef GAMEPP + gamepp::register_python(m); +#endif + +#ifdef STEAMPP + steampp::register_python(m); +#endif +} diff --git a/lang/python/src/sourcepp.h b/lang/python/src/sourcepp.h new file mode 100644 index 000000000..eeec1b764 --- /dev/null +++ b/lang/python/src/sourcepp.h @@ -0,0 +1,85 @@ +#pragma once + +#include + +#include +#include +#include + +namespace py = pybind11; + +#include + +namespace sourcepp { + +void register_python(py::module_& m) { + using namespace sourcepp; + auto sourcepp = m.def_submodule("sourcepp"); + + { + auto math = sourcepp.def_submodule("math"); + using namespace math; + + const auto registerVecType = [&math](std::string_view name) { + py::class_(math, name.data(), pybind11::buffer_protocol()) + .def_buffer([](V& v) -> py::buffer_info { + return {v.values.data(), static_cast(v.values.size())}; + }) + .def("__len__", &V::size) + .def("__setitem__", [](V& self, uint8_t index, V::value_type val) { self[index] = val; }) + .def("__getitem__", [](V& self, uint8_t index) { return self[index]; }) + .def_static("zero", &V::zero) + .def("is_zero", &V::isZero); + }; + + registerVecType.operator()("Vec2i8"); + registerVecType.operator()("Vec2i16"); + registerVecType.operator()("Vec2i32"); + registerVecType.operator()("Vec2i64"); + //registerVecType.operator()("Vec2i"); + + registerVecType.operator()("Vec2ui8"); + registerVecType.operator()("Vec2ui16"); + registerVecType.operator()("Vec2ui32"); + registerVecType.operator()("Vec2ui64"); + //registerVecType.operator()("Vec2ui"); + + registerVecType.operator()("Vec2f32"); + registerVecType.operator()("Vec2f64"); + //registerVecType.operator()("Vec2f"); + + registerVecType.operator()("Vec3i8"); + registerVecType.operator()("Vec3i16"); + registerVecType.operator()("Vec3i32"); + registerVecType.operator()("Vec3i64"); + //registerVecType.operator()("Vec3i"); + + registerVecType.operator()("Vec3ui8"); + registerVecType.operator()("Vec3ui16"); + registerVecType.operator()("Vec3ui32"); + registerVecType.operator()("Vec3ui64"); + //registerVecType.operator()("Vec3ui"); + + registerVecType.operator()("Vec3f32"); + registerVecType.operator()("Vec3f64"); + //registerVecType.operator()("Vec3f"); + + registerVecType.operator()("Vec4i8"); + registerVecType.operator()("Vec4i16"); + registerVecType.operator()("Vec4i32"); + registerVecType.operator()("Vec4i64"); + //registerVecType.operator()("Vec4i"); + + registerVecType.operator()("Vec4ui8"); + registerVecType.operator()("Vec4ui16"); + registerVecType.operator()("Vec4ui32"); + registerVecType.operator()("Vec4ui64"); + //registerVecType.operator()("Vec4ui"); + + registerVecType.operator()("Vec4f32"); + registerVecType.operator()("Vec4f64"); + //registerVecType.operator()("Vec4f"); + } +} + +} // namespace sourcepp diff --git a/lang/python/src/steampp.h b/lang/python/src/steampp.h new file mode 100644 index 000000000..02a82f627 --- /dev/null +++ b/lang/python/src/steampp.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +namespace py = pybind11; + +#include + +namespace steampp { + +void register_python(py::module_& m) { + using namespace steampp; + auto steampp = m.def_submodule("steampp"); + + py::class_(steampp, "Steam") + .def(py::init<>()) + .def_property_readonly("install_dir", &Steam::getInstallDir) + .def_property_readonly("library_dirs", &Steam::getLibraryDirs) + .def_property_readonly("sourcemod_dir", &Steam::getSourceModDir) + .def_property_readonly("installed_apps", &Steam::getInstalledApps) + .def("is_app_installed", &Steam::isAppInstalled) + .def("get_app_name", &Steam::getAppName) + .def("get_app_install_dir", &Steam::getAppInstallDir) + .def("get_app_icon_path", &Steam::getAppIconPath) + .def("get_app_logo_path", &Steam::getAppLogoPath) + .def("get_app_box_art_path", &Steam::getAppBoxArtPath) + .def("get_app_store_art_path", &Steam::getAppStoreArtPath) + .def("is_app_using_source_engine", &Steam::isAppUsingSourceEngine) + .def("is_app_using_source_2_engine", &Steam::isAppUsingSource2Engine) + .def_property_readonly("valid", &Steam::operator bool); +} + +} // namespace gamepp From 3e248cd1deb77df28019700f935f2cea14fc724c Mon Sep 17 00:00:00 2001 From: craftablescience Date: Fri, 18 Oct 2024 11:21:17 -0400 Subject: [PATCH 5/8] feat(python): add vcryptpp wrapper --- CMakeLists.txt | 4 +- README.md | 2 +- docs/index.md | 2 +- lang/python/.gitignore | 1 + lang/python/dist/sourcepp/__init__.py | 4 +- lang/python/src/sourcepp.cpp | 16 ++++- lang/python/src/steampp.h | 2 +- lang/python/src/vcryptpp.h | 93 +++++++++++++++++++++++++++ 8 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 lang/python/src/vcryptpp.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7447873a6..5611c6b17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,7 +161,7 @@ add_sourcepp_library(kvpp BENCH) # sourcepp::kvpp add_sourcepp_library(mdlpp ) # sourcepp::mdlpp add_sourcepp_library(steampp C PYTHON ) # sourcepp::steampp add_sourcepp_library(toolpp ) # sourcepp::toolpp -add_sourcepp_library(vcryptpp C CSHARP ) # sourcepp::vcryptpp +add_sourcepp_library(vcryptpp C CSHARP PYTHON ) # sourcepp::vcryptpp add_sourcepp_library(vpkpp C CSHARP NO_TEST ) # sourcepp::vpkpp add_sourcepp_library(vtfpp BENCH) # sourcepp::vtfpp @@ -179,7 +179,7 @@ endif() # Python bindings, part 2 if(SOURCEPP_BUILD_PYTHON_WRAPPERS) python_add_library(${SOURCEPP_PYTHON_NAME} MODULE "${CMAKE_CURRENT_SOURCE_DIR}/lang/python/src/sourcepp.cpp" ${${SOURCEPP_PYTHON_NAME}_SOURCES} WITH_SOABI) - set_target_properties(${SOURCEPP_PYTHON_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lang/python/dist/sourcepp") + set_target_properties(${SOURCEPP_PYTHON_NAME} PROPERTIES PREFIX "_" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lang/python/dist/sourcepp") target_compile_definitions(${SOURCEPP_PYTHON_NAME} PRIVATE ${${SOURCEPP_PYTHON_NAME}_DEFINES}) target_link_libraries(${SOURCEPP_PYTHON_NAME} PRIVATE ${${SOURCEPP_PYTHON_NAME}_DEPS}) endif() diff --git a/README.md b/README.md index ce07d1343..40722cef3 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one VICE encrypted files ✅ ✅ - C
C# + C
C#
Python diff --git a/docs/index.md b/docs/index.md index d951375c6..ef612a425 100644 --- a/docs/index.md +++ b/docs/index.md @@ -107,7 +107,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one VICE encrypted files ✅ ✅ - C
C# + C
C#
Python VFONT encrypted fonts diff --git a/lang/python/.gitignore b/lang/python/.gitignore index b45f0c509..0c986d628 100644 --- a/lang/python/.gitignore +++ b/lang/python/.gitignore @@ -1,3 +1,4 @@ # Build Files +__pycache__/ dist/sourcepp/* !dist/sourcepp/__init__.py diff --git a/lang/python/dist/sourcepp/__init__.py b/lang/python/dist/sourcepp/__init__.py index 25185e04b..8a3f5fdba 100644 --- a/lang/python/dist/sourcepp/__init__.py +++ b/lang/python/dist/sourcepp/__init__.py @@ -1,5 +1,5 @@ from __future__ import annotations -from .sourcepp_python import __doc__, __version__, gamepp, sourcepp, steampp +from ._sourcepp_python import __doc__, __version__, gamepp, sourcepp, steampp, vcryptpp -__all__ = ['__doc__', '__version__', 'gamepp', 'sourcepp', 'steampp'] +__all__ = ['__doc__', '__version__', 'gamepp', 'sourcepp', 'steampp', 'vcryptpp'] diff --git a/lang/python/src/sourcepp.cpp b/lang/python/src/sourcepp.cpp index 20b954b9e..e5e66ae97 100644 --- a/lang/python/src/sourcepp.cpp +++ b/lang/python/src/sourcepp.cpp @@ -8,7 +8,11 @@ #include "steampp.h" #endif -PYBIND11_MODULE(sourcepp_python, m) { +#ifdef VCRYPTPP +#include "vcryptpp.h" +#endif + +PYBIND11_MODULE(_sourcepp_python, m) { m.doc() = "SourcePP: A Python wrapper around several modern C++20 libraries for sanely parsing Valve's formats."; m.attr("__version__") = "dev"; @@ -17,9 +21,19 @@ PYBIND11_MODULE(sourcepp_python, m) { #ifdef GAMEPP gamepp::register_python(m); +#else + m.def_submodule("gamepp"); #endif #ifdef STEAMPP steampp::register_python(m); +#else + m.def_submodule("steampp"); +#endif + +#ifdef VCRYPTPP + vcryptpp::register_python(m); +#else + m.def_submodule("vcryptpp"); #endif } diff --git a/lang/python/src/steampp.h b/lang/python/src/steampp.h index 02a82f627..24e1f8043 100644 --- a/lang/python/src/steampp.h +++ b/lang/python/src/steampp.h @@ -31,4 +31,4 @@ void register_python(py::module_& m) { .def_property_readonly("valid", &Steam::operator bool); } -} // namespace gamepp +} // namespace steampp diff --git a/lang/python/src/vcryptpp.h b/lang/python/src/vcryptpp.h new file mode 100644 index 000000000..fc5fa33b7 --- /dev/null +++ b/lang/python/src/vcryptpp.h @@ -0,0 +1,93 @@ +#pragma once + +#include +#include + +namespace py = pybind11; + +#include + +namespace vcryptpp { + +void register_python(py::module_& m) { + using namespace vcryptpp; + auto vcryptpp = m.def_submodule("vcryptpp"); + + { + auto VFONT = vcryptpp.def_submodule("VFONT"); + using namespace VFONT; + + VFONT.attr("IDENTIFIER") = IDENTIFIER; + + VFONT.attr("MAGIC") = MAGIC; + + VFONT.def("decrypt_bytes", [](const py::bytes& data) -> py::bytes { + const std::string_view dataView{data}; + const auto d = decrypt({reinterpret_cast(dataView.data()), dataView.size()}); + return {reinterpret_cast(d.data()), d.size()}; + }, py::arg("data")); + } + + { + auto VICE = vcryptpp.def_submodule("VICE"); + using namespace VICE; + + { + auto KnownCodes = VICE.def_submodule("KnownCodes"); + using namespace KnownCodes; + + KnownCodes.attr("DEFAULT") = DEFAULT; + KnownCodes.attr("CONTAGION_WEAPONS") = CONTAGION_WEAPONS; + KnownCodes.attr("CONTAGION_SCRIPTS") = CONTAGION_SCRIPTS; + KnownCodes.attr("COUNTER_STRIKE_SOURCE") = COUNTER_STRIKE_SOURCE; + KnownCodes.attr("COUNTER_STRIKE_GLOBAL_OFFENSIVE") = COUNTER_STRIKE_GLOBAL_OFFENSIVE; + KnownCodes.attr("COUNTER_STRIKE_2") = COUNTER_STRIKE_2; + KnownCodes.attr("COUNTER_STRIKE_PROMOD") = COUNTER_STRIKE_PROMOD; + KnownCodes.attr("DAY_OF_DEFEAT_SOURCE") = DAY_OF_DEFEAT_SOURCE; + KnownCodes.attr("DYSTOPIA_1_2") = DYSTOPIA_1_2; + KnownCodes.attr("DYSTOPIA_1_3") = DYSTOPIA_1_3; + KnownCodes.attr("GOLDEN_EYE_SOURCE") = GOLDEN_EYE_SOURCE; + KnownCodes.attr("HALF_LIFE_2_CTF") = HALF_LIFE_2_CTF; + KnownCodes.attr("HALF_LIFE_2_DM") = HALF_LIFE_2_DM; + KnownCodes.attr("INSURGENCY") = INSURGENCY; + KnownCodes.attr("LEFT_4_DEAD_2") = LEFT_4_DEAD_2; + KnownCodes.attr("NO_MORE_ROOM_IN_HELL") = NO_MORE_ROOM_IN_HELL; + KnownCodes.attr("NUCLEAR_DAWN") = NUCLEAR_DAWN; + KnownCodes.attr("TACTICAL_INTERVENTION") = TACTICAL_INTERVENTION; + KnownCodes.attr("TEAM_FORTRESS_2") = TEAM_FORTRESS_2; + KnownCodes.attr("TEAM_FORTRESS_2_ITEMS") = TEAM_FORTRESS_2_ITEMS; + KnownCodes.attr("THE_SHIP") = THE_SHIP; + KnownCodes.attr("ZOMBIE_PANIC_SOURCE") = ZOMBIE_PANIC_SOURCE; + + KnownCodes.attr("EKV_GPU_DEFAULT") = EKV_GPU_DEFAULT; + KnownCodes.attr("EKV_GPU_ALIEN_SWARM") = EKV_GPU_ALIEN_SWARM; + KnownCodes.attr("EKV_GPU_LEFT_4_DEAD_1") = EKV_GPU_LEFT_4_DEAD_1; + KnownCodes.attr("EKV_GPU_LEFT_4_DEAD_2") = EKV_GPU_LEFT_4_DEAD_2; + KnownCodes.attr("EKV_GPU_PORTAL_2") = EKV_GPU_PORTAL_2; + } + + VICE.def("decrypt_bytes", [](const py::bytes& data, std::string_view code = KnownCodes::DEFAULT) -> py::bytes { + const std::string_view dataView{data}; + const auto d = decrypt({reinterpret_cast(dataView.data()), dataView.size()}, code); + return {reinterpret_cast(d.data()), d.size()}; + }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT); + + VICE.def("decrypt_str", [](std::string_view data, std::string_view code = KnownCodes::DEFAULT) -> std::string { + const auto d = decrypt({reinterpret_cast(data.data()), data.size()}, code); + return {reinterpret_cast(d.data()), d.size()}; + }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT); + + VICE.def("encrypt_bytes", [](const py::bytes& data, std::string_view code = KnownCodes::DEFAULT) -> py::bytes { + const std::string_view dataView{data}; + const auto e = encrypt({reinterpret_cast(dataView.data()), dataView.size()}, code); + return {reinterpret_cast(e.data()), e.size()}; + }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT); + + VICE.def("encrypt_str", [](std::string_view data, std::string_view code = KnownCodes::DEFAULT) -> std::string { + const auto e = decrypt({reinterpret_cast(data.data()), data.size()}, code); + return {reinterpret_cast(e.data()), e.size()}; + }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT); + } +} + +} // namespace vcryptpp From 691579d5040eac7b5152ff54e69ddd19202af253 Mon Sep 17 00:00:00 2001 From: craftablescience Date: Wed, 23 Oct 2024 03:16:27 -0400 Subject: [PATCH 6/8] feat(python): add author property --- lang/python/dist/sourcepp/__init__.py | 4 ++-- lang/python/src/sourcepp.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lang/python/dist/sourcepp/__init__.py b/lang/python/dist/sourcepp/__init__.py index 8a3f5fdba..d8f3097c9 100644 --- a/lang/python/dist/sourcepp/__init__.py +++ b/lang/python/dist/sourcepp/__init__.py @@ -1,5 +1,5 @@ from __future__ import annotations -from ._sourcepp_python import __doc__, __version__, gamepp, sourcepp, steampp, vcryptpp +from ._sourcepp_python import __author__, __doc__, __version__, gamepp, sourcepp, steampp, vcryptpp -__all__ = ['__doc__', '__version__', 'gamepp', 'sourcepp', 'steampp', 'vcryptpp'] +__all__ = ['__author__', '__doc__', '__version__', 'gamepp', 'sourcepp', 'steampp', 'vcryptpp'] diff --git a/lang/python/src/sourcepp.cpp b/lang/python/src/sourcepp.cpp index e5e66ae97..353151646 100644 --- a/lang/python/src/sourcepp.cpp +++ b/lang/python/src/sourcepp.cpp @@ -15,6 +15,7 @@ PYBIND11_MODULE(_sourcepp_python, m) { m.doc() = "SourcePP: A Python wrapper around several modern C++20 libraries for sanely parsing Valve's formats."; + m.attr("__author__") = "craftablescience"; m.attr("__version__") = "dev"; sourcepp::register_python(m); From e364f9b7a9195501ead83f393fe7a8588117c29a Mon Sep 17 00:00:00 2001 From: craftablescience Date: Wed, 23 Oct 2024 03:37:40 -0400 Subject: [PATCH 7/8] feat(csharp): create target with dependencies on C libraries --- CMakeLists.txt | 4 ++++ cmake/AddSourcePPLibrary.cmake | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5611c6b17..dac69a2c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ option(SOURCEPP_USE_VTFPP "Build vtfpp library" ${SOURC option(SOURCEPP_BUILD_BENCHMARKS "Build benchmarks for supported libraries" OFF) option(SOURCEPP_BUILD_C_WRAPPERS "Build C wrappers for supported libraries" OFF) +option(SOURCEPP_BUILD_CSHARP_WRAPPERS "Build C# wrappers for supported libraries" OFF) option(SOURCEPP_BUILD_PYTHON_WRAPPERS "Build Python wrappers for supported libraries" OFF) option(SOURCEPP_BUILD_WITH_OPENCL "Build with support for GPU compute" OFF) option(SOURCEPP_BUILD_WITH_TBB "Build with support for std::execution" OFF) @@ -54,6 +55,9 @@ if(SOURCEPP_USE_VPKPP) set(SOURCEPP_USE_KVPP ON CACHE INTERNAL "" FORCE) endif() +if(SOURCEPP_BUILD_CSHARP_WRAPPERS) + set(SOURCEPP_BUILD_C_WRAPPERS ON CACHE INTERNAL "" FORCE) +endif() if(MSVC) # MSVC does not rely on tbb for std::execution policies, so we can force this on set(SOURCEPP_BUILD_WITH_TBB ON CACHE INTERNAL "" FORCE) diff --git a/cmake/AddSourcePPLibrary.cmake b/cmake/AddSourcePPLibrary.cmake index b9f62dfe2..581dfd071 100644 --- a/cmake/AddSourcePPLibrary.cmake +++ b/cmake/AddSourcePPLibrary.cmake @@ -13,10 +13,12 @@ function(add_sourcepp_library TARGET) endif() # Add C# - if(SOURCEPP_BUILD_C_WRAPPERS AND OPTIONS_CSHARP) + if(SOURCEPP_BUILD_CSHARP_WRAPPERS AND OPTIONS_CSHARP) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/sourcepp/Buffer.cs.in" "${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/${TARGET}/Buffer.cs") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/sourcepp/String.cs.in" "${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/${TARGET}/String.cs") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/sourcepp/TARGET.csproj.in" "${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/${TARGET}/${TARGET}.csproj") + add_custom_target(${TARGET}_csharp DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/lang/csharp/src/${TARGET}/${TARGET}.csproj") + add_dependencies(${TARGET}_csharp ${TARGET}c) endif() # Add Python From 85320a7fa8e7c524e4e1135a06e91b4bc5f15f87 Mon Sep 17 00:00:00 2001 From: craftablescience Date: Wed, 23 Oct 2024 04:21:13 -0400 Subject: [PATCH 8/8] fix(toolpp): stop hardcoding string length in bufferstream write calls everywhere --- ext/bufferstream | 2 +- src/toolpp/FGD.cpp | 97 +++++++++++++++++++++++----------------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/ext/bufferstream b/ext/bufferstream index 689c50d56..72da37514 160000 --- a/ext/bufferstream +++ b/ext/bufferstream @@ -1 +1 @@ -Subproject commit 689c50d56a0eefb066209c281eac99599845edb6 +Subproject commit 72da375145d8d0cef590d9fe82e68c27f1d37481 diff --git a/src/toolpp/FGD.cpp b/src/toolpp/FGD.cpp index f9f955ca8..102692bfc 100644 --- a/src/toolpp/FGD.cpp +++ b/src/toolpp/FGD.cpp @@ -11,6 +11,7 @@ #include using namespace sourcepp; +using namespace std::string_view_literals; using namespace toolpp; namespace { @@ -467,11 +468,11 @@ void writeOptionalKeyValueStrings(BufferStream& writer, std::initializer_listwriter - .write("@include \"", 10) + .write("@include \""sv, false) .write(fgdPath, false) - .write("\"\n\n", 3); + .write("\"\n\n"sv, false); return *this; } FGDWriter& FGDWriter::version(int version) { this->writer - .write("@version(", 9) + .write("@version("sv, false) .write(std::to_string(version), false) - .write(")\n\n", 3); + .write(")\n\n"sv, false); return *this; } FGDWriter& FGDWriter::mapSize(math::Vec2i mapSize) { this->writer - .write("@mapsize(", 9) + .write("@mapsize("sv, false) .write(std::to_string(mapSize[0]), false) - .write(", ", 2) + .write(", "sv, false) .write(std::to_string(mapSize[1]), false) - .write(")\n\n", 3); + .write(")\n\n"sv, false); return *this; } FGDWriter& FGDWriter::materialExclusionDirs(const std::vector& dirs) { - this->writer.write("@MaterialExclusion\n[\n", 21); + this->writer.write("@MaterialExclusion\n[\n"sv, false); for (const auto& dir : dirs) { this->writer << '\t' << '\"'; this->writer.write(dir, false); this->writer << '\"' << '\n'; } - this->writer.write("]\n\n", 3); + this->writer.write("]\n\n"sv, false); return *this; } FGDWriter::AutoVisGroupWriter FGDWriter::beginAutoVisGroup(const std::string& parentName) { this->writer - .write("@AutoVisGroup = \"", 17) + .write("@AutoVisGroup = \""sv, false) .write(parentName, false) - .write("\"\n[\n", 4); + .write("\"\n[\n"sv, false); return AutoVisGroupWriter{*this}; } FGDWriter::AutoVisGroupWriter& FGDWriter::AutoVisGroupWriter::visGroup(const std::string& name, const std::vector& entities) { this->parent.writer - .write("\t\"", 2) + .write("\t\""sv, false) .write(name, false) - .write("\"\n\t[\n", 5); + .write("\"\n\t[\n"sv, false); for (const auto& entity : entities) { this->parent.writer - .write("\t\t\"", 3) + .write("\t\t\""sv, false) .write(entity, false) - .write("\"\n", 2); + .write("\"\n"sv, false); } - this->parent.writer.write("\t]\n", 3); + this->parent.writer.write("\t]\n"sv, false); return *this; } FGDWriter& FGDWriter::AutoVisGroupWriter::endAutoVisGroup() const { - this->parent.writer.write("]\n\n", 3); + this->parent.writer.write("]\n\n"sv, false); return this->parent; } @@ -684,20 +685,20 @@ FGDWriter::EntityWriter FGDWriter::beginEntity(const std::string& classType, con } } this->writer - .write("= ", 2) + .write("= "sv, false) .write(name, false) - .write(" :", 2); + .write(" :"sv, false); // Put the description on the same line if it's short if (description.size() < 32) { this->writer - .write(" \"", 2) + .write(" \""sv, false) .write(description, false); } else { this->writer - .write("\n\t\"", 3) + .write("\n\t\""sv, false) .write(description, false); } - this->writer.write("\"\n[\n", 4); + this->writer.write("\"\n[\n"sv, false); return EntityWriter{*this}; } @@ -709,10 +710,10 @@ FGDWriter::EntityWriter& FGDWriter::EntityWriter::keyValue(const std::string& na .write(valueType, false) .write(')'); if (readOnly) { - this->parent.writer.write(" readonly", 9); + this->parent.writer.write(" readonly"sv, false); } if (report) { - this->parent.writer.write(" report", 7); + this->parent.writer.write(" report"sv, false); } ::writeOptionalKeyValueStrings(this->parent.writer, {displayName, valueDefault, description}); this->parent.writer << '\n'; @@ -723,30 +724,30 @@ FGDWriter::EntityWriter::KeyValueChoicesWriter FGDWriter::EntityWriter::beginKey this->parent.writer .write('\t') .write(name, false) - .write("(choices)", 9); + .write("(choices)"sv, false); if (readOnly) { - this->parent.writer.write(" readonly", 9); + this->parent.writer.write(" readonly"sv, false); } if (report) { - this->parent.writer.write(" report", 7); + this->parent.writer.write(" report"sv, false); } ::writeOptionalKeyValueStrings(this->parent.writer, {displayName, valueDefault, description}); - this->parent.writer.write(" =\n\t[\n", 6); + this->parent.writer.write(" =\n\t[\n"sv, false); return KeyValueChoicesWriter{*this}; } FGDWriter::EntityWriter::KeyValueChoicesWriter& FGDWriter::EntityWriter::KeyValueChoicesWriter::choice(const std::string& value, const std::string& displayName) { this->parent.parent.writer - .write("\t\t\"", 3) + .write("\t\t\""sv, false) .write(value, false) - .write("\" : \"", 5) + .write("\" : \""sv, false) .write(displayName, false) - .write("\"\n", 2); + .write("\"\n"sv, false); return *this; } FGDWriter::EntityWriter& FGDWriter::EntityWriter::KeyValueChoicesWriter::endKeyValueChoices() const { - this->parent.parent.writer.write("\t]\n", 3); + this->parent.parent.writer.write("\t]\n"sv, false); return this->parent; } @@ -754,29 +755,29 @@ FGDWriter::EntityWriter::KeyValueFlagsWriter FGDWriter::EntityWriter::beginKeyVa this->parent.writer .write('\t') .write(name, false) - .write("(flags)", 7); + .write("(flags)"sv, false); if (readOnly) { - this->parent.writer.write(" readonly", 9); + this->parent.writer.write(" readonly"sv, false); } if (report) { - this->parent.writer.write(" report", 7); + this->parent.writer.write(" report"sv, false); } ::writeOptionalKeyValueStrings(this->parent.writer, {displayName, description}); - this->parent.writer.write(" =\n\t[\n", 6); + this->parent.writer.write(" =\n\t[\n"sv, false); return KeyValueFlagsWriter{*this}; } FGDWriter::EntityWriter::KeyValueFlagsWriter& FGDWriter::EntityWriter::KeyValueFlagsWriter::flag(uint64_t value, const std::string& displayName, bool enabledByDefault, const std::string& description) { this->parent.parent.writer - .write("\t\t", 2) + .write("\t\t"sv, false) .write(std::to_string(value), false) - .write(" : \"", 4) + .write(" : \""sv, false) .write(displayName, false) - .write("\" : ", 4) + .write("\" : "sv, false) .write(std::to_string(enabledByDefault), false); if (!description.empty()) { this->parent.parent.writer - .write(" : \"", 4) + .write(" : \""sv, false) .write(description, false) .write('\"'); } @@ -785,21 +786,21 @@ FGDWriter::EntityWriter::KeyValueFlagsWriter& FGDWriter::EntityWriter::KeyValueF } FGDWriter::EntityWriter& FGDWriter::EntityWriter::KeyValueFlagsWriter::endKeyValueFlags() const { - this->parent.parent.writer.write("\t]\n", 3); + this->parent.parent.writer.write("\t]\n"sv, false); return this->parent; } FGDWriter::EntityWriter& FGDWriter::EntityWriter::input(const std::string& name, const std::string& valueType, const std::string& description) { this->parent.writer .write('\t') - .write("input ", 6) + .write("input "sv, false) .write(name, false) .write('(') .write(valueType, false) .write(')'); if (!description.empty()) { this->parent.writer - .write(" : \"", 4) + .write(" : \""sv, false) .write(description, false) .write('\"'); } @@ -810,14 +811,14 @@ FGDWriter::EntityWriter& FGDWriter::EntityWriter::input(const std::string& name, FGDWriter::EntityWriter& FGDWriter::EntityWriter::output(const std::string& name, const std::string& valueType, const std::string& description) { this->parent.writer .write('\t') - .write("output ", 7) + .write("output "sv, false) .write(name, false) .write('(') .write(valueType, false) .write(')'); if (!description.empty()) { this->parent.writer - .write(" : \"", 4) + .write(" : \""sv, false) .write(description, false) .write('\"'); } @@ -826,7 +827,7 @@ FGDWriter::EntityWriter& FGDWriter::EntityWriter::output(const std::string& name } FGDWriter& FGDWriter::EntityWriter::endEntity() const { - this->parent.writer.write("]\n\n", 3); + this->parent.writer.write("]\n\n"sv, false); return this->parent; }