From 30e6b638df77acd2691f90ddef832aa575709293 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:26:09 +0100 Subject: [PATCH 01/27] Python Bindings -fPIC and RTTI is needed for dynamic libraries, it's just put in common flags to prevent a whole recompilation. We could have a CMake flag to create the bindings or not. --- CMakeLists.txt | 44 ++++++- source/bindings/KBindSystem.cc | 68 ++++++++++ source/bindings/KBindSystem.hh | 61 +++++++++ source/bindings/bindings.cc | 210 +++++++++++++++++++++++++++++++ source/game/scene/RaceScene.cc | 2 +- source/game/system/RaceConfig.hh | 2 +- tools/bindings_test.py | 11 ++ 7 files changed, 394 insertions(+), 4 deletions(-) create mode 100644 source/bindings/KBindSystem.cc create mode 100644 source/bindings/KBindSystem.hh create mode 100644 source/bindings/bindings.cc create mode 100644 tools/bindings_test.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ee10587..e9cb1866 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.22) project(Kinoko CXX) # Compiler and flags @@ -8,10 +8,10 @@ set(CMAKE_CXX_EXTENSIONS OFF) # Common flags set(COMMON_CXX_FLAGS + -fPIC -DREVOLUTION -fno-asynchronous-unwind-tables -fno-exceptions - -fno-rtti -fshort-wchar -fstack-protector-strong -Wall @@ -22,14 +22,32 @@ set(COMMON_CXX_FLAGS -Wsuggest-override ) +# Bindings flags +set(BINDINGS_CXX_FLAGS + -DREVOLUTION + -fstack-protector-strong + -Wall + -Werror + -Wextra + -Wno-delete-non-virtual-dtor + -Wno-packed-bitfield-compat + -Wsuggest-override +) + set(RK_INCLUDE_DIRS include source ) + +# +-------------------------------------------+ +# - LIBKINOKO - +# +-------------------------------------------+ + # Source files file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/**/*.cc) list(FILTER SOURCE_FILES EXCLUDE REGEX ".*/host/main\\.cc$") +list(FILTER SOURCE_FILES EXCLUDE REGEX ".*/bindings/.*\\.cc$") add_library(libkinoko ${SOURCE_FILES}) target_include_directories(libkinoko SYSTEM @@ -43,6 +61,28 @@ add_executable(kinoko source/host/main.cc) target_link_libraries(kinoko libkinoko) target_compile_options(kinoko PRIVATE ${COMMON_CXX_FLAGS}) +# +-------------------------------------------+ +# - BINDINGS - +# +-------------------------------------------+ + +# Add dependencies +find_package(Python REQUIRED COMPONENTS Development) +add_subdirectory(extern/nanobind) + +# Add a target +nanobind_add_module(bindings + source/bindings/KBindSystem.cc + source/bindings/bindings.cc +) + +# Link libraries +target_link_libraries(bindings PRIVATE libkinoko Python::Python) +target_compile_options(bindings PRIVATE ${BINDINGS_CXX_FLAGS}) + +# +-------------------------------------------+ +# - TEST CASES - +# +-------------------------------------------+ + # Add a custom target to generate testCases.json set(TEST_JSON ${CMAKE_CURRENT_SOURCE_DIR}/testCases.json) set(TEST_BIN ${CMAKE_CURRENT_BINARY_DIR}/testCases.bin) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc new file mode 100644 index 00000000..6004d510 --- /dev/null +++ b/source/bindings/KBindSystem.cc @@ -0,0 +1,68 @@ +#include "bindings/KBindSystem.hh" +#include "egg/core/ExpHeap.hh" +#include "host/SceneCreatorDynamic.hh" +#include "egg/core/SceneManager.hh" +#include "game/system/KPadController.hh" +#include "game/system/KPadDirector.hh" +#include "game/system/RaceConfig.hh" + +KBindSystem* KBindSystem::s_instance = nullptr; + +KBindSystem::KBindSystem() : m_sceneMgr(nullptr) {} + +KBindSystem::~KBindSystem() { + delete m_sceneMgr; +} + +KBindSystem* KBindSystem::CreateInstance() { + s_instance = new KBindSystem; + return s_instance; +} + +void KBindSystem::DestroyInstance() { + delete s_instance; + s_instance = nullptr; +} + +void KBindSystem::init() { + // Create a new sceneCreator (needed to make RaceScene) + auto *sceneCreator = new Host::SceneCreatorDynamic; + m_sceneMgr = new EGG::SceneManager(sceneCreator); + + // Register a callback to configure RaceConfig once it's created + System::RaceConfig::RegisterInitCallback([this](System::RaceConfig* config, void* /* arg */) { + auto& scenario = config->raceScenario(); + + // Set the scenario + scenario.course = m_course; + scenario.playerCount = m_players.size(); + + for (size_t i = 0; i < m_players.size(); ++i) { + scenario.players[i].character = m_players[i].character; + scenario.players[i].vehicle = m_players[i].vehicle; + scenario.players[i].driftIsAuto = m_players[i].driftIsAuto; + scenario.players[i].type = System::RaceConfig::Player::Type::Local; + } + }, nullptr); + + m_sceneMgr->changeScene(static_cast(Host::SceneId::Root)); +} + +void KBindSystem::step() { + if (m_sceneMgr) { + m_sceneMgr->calc(); + } +} + +System::KPadHostController* KBindSystem::get_host_controller() { + return System::KPadDirector::Instance()->hostController(); +} + +void KBindSystem::set_course(Course course) { + m_course = course; +} + +void KBindSystem::set_player(int slot, Character character, Vehicle vehicle, bool driftIsAuto) { + if (slot < 0) return; + m_players[slot] = { character, vehicle, driftIsAuto }; +} \ No newline at end of file diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh new file mode 100644 index 00000000..de7fa6af --- /dev/null +++ b/source/bindings/KBindSystem.hh @@ -0,0 +1,61 @@ +#pragma once + +#include "egg/core/Disposer.hh" +#include "egg/core/SceneManager.hh" +#include "game/system/KPadController.hh" +#include "game/system/RaceConfig.hh" +#include "Common.hh" + +namespace EGG { + class SceneManager; +} + +class KBindSystem final : public EGG::Disposer { +public: + KBindSystem(); + + /// @brief Initializes the scene manager and starts the root scene + void init(); + + /// @brief Steps the simulation by a frame + void step(); + + /// @brief Sets the course for the race. Must be called before init() + void set_course(Course course); + + /// @brief Configures a racer. Must be called before init() + void set_player(int playerIdx, Character character, Vehicle vehicle, bool driftIsAuto); + + /// @brief Gets the host controller for changing controller state + /// At the moment Kinoko only supports one racer, so this returns the controller for player 0 + /// @return A pointer to the KPadHostController for the local player + System::KPadHostController* get_host_controller(); + + static KBindSystem* CreateInstance(); + + static void DestroyInstance(); + + static KBindSystem* Instance() { + return s_instance; + } + +private: + ~KBindSystem() override; + KBindSystem(const KBindSystem &) = delete; + KBindSystem(KBindSystem &&) = delete; + + // Scenario Settings + // We need to store a copy of them locally to prevent a crash, trying + // to do it via System::RaceConfig::raceScenario() causes a second + // RaceConfig instance when RootScene is created, causing it to segfault. + Course m_course = Course::Luigi_Circuit; + struct PlayerConfig { + Character character; + Vehicle vehicle; + bool driftIsAuto; + }; + std::array m_players; + + static KBindSystem *s_instance; + EGG::SceneManager *m_sceneMgr; +}; \ No newline at end of file diff --git a/source/bindings/bindings.cc b/source/bindings/bindings.cc new file mode 100644 index 00000000..53f72d04 --- /dev/null +++ b/source/bindings/bindings.cc @@ -0,0 +1,210 @@ +#include +#include +#include "bindings/KBindSystem.hh" +#include "game/system/KPadController.hh" +#include "egg/core/ExpHeap.hh" +#include "egg/core/SceneManager.hh" +#include "Common.hh" + +namespace nb = nanobind; +using namespace nb::literals; + +static void InitMemory(); +static void FlushDenormalsToZero(); + +struct KinokoInitializer { + KinokoInitializer() { + FlushDenormalsToZero(); + InitMemory(); + } +}; +static KinokoInitializer s_KinokoInitializer_instance; + +NB_MODULE(bindings, m) { + m.doc() = "Python bindings for Kinoko"; + + nb::enum_(m, "Character") + .value("Mario", Character::Mario) + .value("Baby_Peach", Character::Baby_Peach) + .value("Waluigi", Character::Waluigi) + .value("Bowser", Character::Bowser) + .value("Baby_Daisy", Character::Baby_Daisy) + .value("Dry_Bones", Character::Dry_Bones) + .value("Baby_Mario", Character::Baby_Mario) + .value("Luigi", Character::Luigi) + .value("Peach", Character::Peach) + .value("Yoshi", Character::Yoshi) + .value("Donkey_Kong", Character::Donkey_Kong) + .value("Wario", Character::Wario) + .value("Baby_Luigi", Character::Baby_Luigi) + .value("Toad", Character::Toad) + .value("Koopa_Troopa", Character::Koopa_Troopa) + .value("Daisy", Character::Daisy) + .value("Toadette", Character::Toadette) + .value("Birdo", Character::Birdo) + .value("Diddy_Kong", Character::Diddy_Kong) + .value("King_Boo", Character::King_Boo) + .value("Bowser_Jr", Character::Bowser_Jr) + .value("Dry_Bowser", Character::Dry_Bowser) + .value("Funky_Kong", Character::Funky_Kong) + .value("Rosalina", Character::Rosalina) + .value("Small_Mii_Outfit_A_Male", Character::Small_Mii_Outfit_A_Male) + .value("Small_Mii_Outfit_A_Female", Character::Small_Mii_Outfit_A_Female) + .value("Small_Mii_Outfit_B_Male", Character::Small_Mii_Outfit_B_Male) + .value("Small_Mii_Outfit_B_Female", Character::Small_Mii_Outfit_B_Female) + .value("Small_Mii_Outfit_C_Male", Character::Small_Mii_Outfit_C_Male) + .value("Small_Mii_Outfit_C_Female", Character::Small_Mii_Outfit_C_Female) + .value("Medium_Mii_Outfit_A_Male", Character::Medium_Mii_Outfit_A_Male) + .value("Medium_Mii_Outfit_A_Female", Character::Medium_Mii_Outfit_A_Female) + .value("Medium_Mii_Outfit_B_Male", Character::Medium_Mii_Outfit_B_Male) + .value("Medium_Mii_Outfit_B_Female", Character::Medium_Mii_Outfit_B_Female) + .value("Medium_Mii_Outfit_C_Male", Character::Medium_Mii_Outfit_C_Male) + .value("Medium_Mii_Outfit_C_Female", Character::Medium_Mii_Outfit_C_Female) + .value("Large_Mii_Outfit_A_Male", Character::Large_Mii_Outfit_A_Male) + .value("Large_Mii_Outfit_A_Female", Character::Large_Mii_Outfit_A_Female) + .value("Large_Mii_Outfit_B_Male", Character::Large_Mii_Outfit_B_Male) + .value("Large_Mii_Outfit_B_Female", Character::Large_Mii_Outfit_B_Female) + .value("Large_Mii_Outfit_C_Male", Character::Large_Mii_Outfit_C_Male) + .value("Large_Mii_Outfit_C_Female", Character::Large_Mii_Outfit_C_Female) + .value("Medium_Mii", Character::Medium_Mii) + .value("Small_Mii", Character::Small_Mii) + .value("Large_Mii", Character::Large_Mii) + .value("Max", Character::Max) + .export_values(); + + nb::enum_(m, "Vehicle") + .value("Standard_Kart_S", Vehicle::Standard_Kart_S) + .value("Standard_Kart_M", Vehicle::Standard_Kart_M) + .value("Standard_Kart_L", Vehicle::Standard_Kart_L) + .value("Baby_Booster", Vehicle::Baby_Booster) + .value("Classic_Dragster", Vehicle::Classic_Dragster) + .value("Offroader", Vehicle::Offroader) + .value("Mini_Beast", Vehicle::Mini_Beast) + .value("Wild_Wing", Vehicle::Wild_Wing) + .value("Flame_Flyer", Vehicle::Flame_Flyer) + .value("Cheep_Charger", Vehicle::Cheep_Charger) + .value("Super_Blooper", Vehicle::Super_Blooper) + .value("Piranha_Prowler", Vehicle::Piranha_Prowler) + .value("Tiny_Titan", Vehicle::Tiny_Titan) + .value("Daytripper", Vehicle::Daytripper) + .value("Jetsetter", Vehicle::Jetsetter) + .value("Blue_Falcon", Vehicle::Blue_Falcon) + .value("Sprinter", Vehicle::Sprinter) + .value("Honeycoupe", Vehicle::Honeycoupe) + .value("Standard_Bike_S", Vehicle::Standard_Bike_S) + .value("Standard_Bike_M", Vehicle::Standard_Bike_M) + .value("Standard_Bike_L", Vehicle::Standard_Bike_L) + .value("Bullet_Bike", Vehicle::Bullet_Bike) + .value("Mach_Bike", Vehicle::Mach_Bike) + .value("Flame_Runner", Vehicle::Flame_Runner) + .value("Bit_Bike", Vehicle::Bit_Bike) + .value("Sugarscoot", Vehicle::Sugarscoot) + .value("Wario_Bike", Vehicle::Wario_Bike) + .value("Quacker", Vehicle::Quacker) + .value("Zip_Zip", Vehicle::Zip_Zip) + .value("Shooting_Star", Vehicle::Shooting_Star) + .value("Magikruiser", Vehicle::Magikruiser) + .value("Sneakster", Vehicle::Sneakster) + .value("Spear", Vehicle::Spear) + .value("Jet_Bubble", Vehicle::Jet_Bubble) + .value("Dolphin_Dasher", Vehicle::Dolphin_Dasher) + .value("Phantom", Vehicle::Phantom) + .value("Max", Vehicle::Max) + .export_values(); + + nb::enum_(m, "Course") + .value("Luigi_Circuit", Course::Luigi_Circuit) + .value("Moo_Moo_Meadows", Course::Moo_Moo_Meadows) + .value("Mushroom_Gorge", Course::Mushroom_Gorge) + .value("Toads_Factory", Course::Toads_Factory) + .value("Mario_Circuit", Course::Mario_Circuit) + .value("Coconut_Mall", Course::Coconut_Mall) + .value("DK_Summit", Course::DK_Summit) + .value("Wario_Gold_Mine", Course::Wario_Gold_Mine) + .value("Daisy_Circuit", Course::Daisy_Circuit) + .value("Koopa_Cape", Course::Koopa_Cape) + .value("Maple_Treeway", Course::Maple_Treeway) + .value("Grumble_Volcano", Course::Grumble_Volcano) + .value("Dry_Dry_Ruins", Course::Dry_Dry_Ruins) + .value("Moonview_Highway", Course::Moonview_Highway) + .value("Bowsers_Castle", Course::Bowsers_Castle) + .value("Rainbow_Road", Course::Rainbow_Road) + .value("GCN_Peach_Beach", Course::GCN_Peach_Beach) + .value("DS_Yoshi_Falls", Course::DS_Yoshi_Falls) + .value("SNES_Ghost_Valley_2", Course::SNES_Ghost_Valley_2) + .value("N64_Mario_Raceway", Course::N64_Mario_Raceway) + .value("N64_Sherbet_Land", Course::N64_Sherbet_Land) + .value("GBA_Shy_Guy_Beach", Course::GBA_Shy_Guy_Beach) + .value("DS_Delfino_Square", Course::DS_Delfino_Square) + .value("GCN_Waluigi_Stadium", Course::GCN_Waluigi_Stadium) + .value("DS_Desert_Hills", Course::DS_Desert_Hills) + .value("GBA_Bowser_Castle_3", Course::GBA_Bowser_Castle_3) + .value("N64_DKs_Jungle_Parkway", Course::N64_DKs_Jungle_Parkway) + .value("GCN_Mario_Circuit", Course::GCN_Mario_Circuit) + .value("SNES_Mario_Circuit_3", Course::SNES_Mario_Circuit_3) + .value("DS_Peach_Gardens", Course::DS_Peach_Gardens) + .value("GCN_DK_Mountain", Course::GCN_DK_Mountain) + .value("N64_Bowsers_Castle", Course::N64_Bowsers_Castle) + .export_values(); + + nb::enum_(m, "Trick") + .value("Neutral", System::Trick::None) // None is reserved + .value("Up", System::Trick::Up) + .value("Down", System::Trick::Down) + .value("Left", System::Trick::Left) + .value("Right", System::Trick::Right) + .export_values(); + + nb::class_(m, "KBindSystem") + .def(nb::init<>()) + .def("init", &KBindSystem::init) + .def("step", &KBindSystem::step) + .def("set_course", &KBindSystem::set_course, "course"_a) + .def("set_player", &KBindSystem::set_player, "player_idx"_a, "character"_a, "vehicle"_a, "drift_is_auto"_a) + .def("get_host_controller", &KBindSystem::get_host_controller, nb::rv_policy::reference) + .def_static("create_instance", &KBindSystem::CreateInstance, nb::rv_policy::reference) + .def_static("destroy_instance", &KBindSystem::DestroyInstance) + .def_static("instance", &KBindSystem::Instance, nb::rv_policy::reference); + + nb::class_(m, "KPadHostController") + .def("set_inputs", nb::overload_cast(&System::KPadHostController::setInputs), + "buttons"_a, "stick_x"_a, "stick_y"_a, "trick"_a) + .def("set_inputs_raw_stick", &System::KPadHostController::setInputsRawStick, + "buttons"_a, "stick_x_raw"_a, "stick_y_raw"_a, "trick"_a) + .def("set_inputs_raw_stick_zero_center", &System::KPadHostController::setInputsRawStickZeroCenter, + "buttons"_a, "stick_x_raw"_a, "stick_y_raw"_a, "trick"_a); +} + +#if defined(__arm64__) || defined(__aarch64__) +static void FlushDenormalsToZero() { + uint64_t fpcr; + asm("mrs %0, fpcr" : "=r"(fpcr)); + asm("msr fpcr, %0" ::"r"(fpcr | (1 << 24))); +} +#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) +#include + +static void FlushDenormalsToZero() { + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); +} +#endif + +static void *s_memorySpace = nullptr; +static EGG::Heap *s_rootHeap = nullptr; + +static void InitMemory() { + constexpr size_t MEMORY_SPACE_SIZE = 0x8000000; // Arbitrary number + Abstract::Memory::MEMiHeapHead::OptFlag opt; + opt.setBit(Abstract::Memory::MEMiHeapHead::eOptFlag::ZeroFillAlloc); + +#ifdef BUILD_DEBUG + opt.setBit(Abstract::Memory::MEMiHeapHead::eOptFlag::DebugFillAlloc); +#endif + + s_memorySpace = malloc(MEMORY_SPACE_SIZE); + s_rootHeap = EGG::ExpHeap::create(s_memorySpace, MEMORY_SPACE_SIZE, opt); + s_rootHeap->setName("EGGRoot"); + s_rootHeap->becomeCurrentHeap(); + + EGG::SceneManager::SetRootHeap(s_rootHeap); +} \ No newline at end of file diff --git a/source/game/scene/RaceScene.cc b/source/game/scene/RaceScene.cc index cd8f2b3e..0dc8cbc1 100644 --- a/source/game/scene/RaceScene.cc +++ b/source/game/scene/RaceScene.cc @@ -85,7 +85,7 @@ void RaceScene::initEngines() { Field::ObjectDirector::Instance()->init(); } - m_heap->disableAllocation(); + //m_heap->disableAllocation(); } /// @addr{0x80554E6C} diff --git a/source/game/system/RaceConfig.hh b/source/game/system/RaceConfig.hh index dc019006..e4c16d31 100644 --- a/source/game/system/RaceConfig.hh +++ b/source/game/system/RaceConfig.hh @@ -17,7 +17,7 @@ public: struct Player { public: enum class Type { - Local = 0, // Inputs managed by ML algorithm + Local = 0, // Inputs managed externally Ghost = 3, // Inputs managed by ghost None = 5, }; diff --git a/tools/bindings_test.py b/tools/bindings_test.py new file mode 100644 index 00000000..8f090245 --- /dev/null +++ b/tools/bindings_test.py @@ -0,0 +1,11 @@ +import bindings as kinoko + +k = kinoko.KBindSystem() +k.set_course(kinoko.Course.Mushroom_Gorge) +k.set_player(0, kinoko.Character.Funky_Kong, kinoko.Vehicle.Flame_Runner, False) +k.init() + +controller = k.get_host_controller() +while True: + controller.set_inputs(buttons=1, stick_x=0.0, stick_y=1.0, trick=kinoko.Trick.Neutral) + k.step() \ No newline at end of file From d06533638808c2d4f7f2dde3378519285d1d671b Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:59:44 +0100 Subject: [PATCH 02/27] Clang formatting + vector regression --- source/bindings/KBindSystem.cc | 35 +++++++++++++++++++--------------- source/bindings/KBindSystem.hh | 16 +++++++++------- source/bindings/bindings.cc | 2 ++ source/game/scene/RaceScene.cc | 2 +- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc index 6004d510..8c41f844 100644 --- a/source/bindings/KBindSystem.cc +++ b/source/bindings/KBindSystem.cc @@ -1,4 +1,5 @@ #include "bindings/KBindSystem.hh" + #include "egg/core/ExpHeap.hh" #include "host/SceneCreatorDynamic.hh" #include "egg/core/SceneManager.hh" @@ -26,24 +27,26 @@ void KBindSystem::DestroyInstance() { void KBindSystem::init() { // Create a new sceneCreator (needed to make RaceScene) - auto *sceneCreator = new Host::SceneCreatorDynamic; + auto* sceneCreator = new Host::SceneCreatorDynamic; m_sceneMgr = new EGG::SceneManager(sceneCreator); // Register a callback to configure RaceConfig once it's created - System::RaceConfig::RegisterInitCallback([this](System::RaceConfig* config, void* /* arg */) { - auto& scenario = config->raceScenario(); + System::RaceConfig::RegisterInitCallback( + [this](System::RaceConfig* config, void* /* arg */) { + auto& scenario = config->raceScenario(); - // Set the scenario - scenario.course = m_course; - scenario.playerCount = m_players.size(); + // Set the scenario + scenario.course = m_course; + scenario.playerCount = m_players.size(); - for (size_t i = 0; i < m_players.size(); ++i) { - scenario.players[i].character = m_players[i].character; - scenario.players[i].vehicle = m_players[i].vehicle; - scenario.players[i].driftIsAuto = m_players[i].driftIsAuto; - scenario.players[i].type = System::RaceConfig::Player::Type::Local; - } - }, nullptr); + for (size_t i = 0; i < m_players.size(); ++i) { + scenario.players[i].character = m_players[i].character; + scenario.players[i].vehicle = m_players[i].vehicle; + scenario.players[i].driftIsAuto = m_players[i].driftIsAuto; + scenario.players[i].type = System::RaceConfig::Player::Type::Local; + } + }, + nullptr); m_sceneMgr->changeScene(static_cast(Host::SceneId::Root)); } @@ -63,6 +66,8 @@ void KBindSystem::set_course(Course course) { } void KBindSystem::set_player(int slot, Character character, Vehicle vehicle, bool driftIsAuto) { - if (slot < 0) return; - m_players[slot] = { character, vehicle, driftIsAuto }; + if (slot < 0 || slot > 12) { + return; + } + m_players[slot] = {character, vehicle, driftIsAuto}; } \ No newline at end of file diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index de7fa6af..44bba989 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -1,13 +1,15 @@ #pragma once +#include + +#include "Common.hh" #include "egg/core/Disposer.hh" #include "egg/core/SceneManager.hh" #include "game/system/KPadController.hh" #include "game/system/RaceConfig.hh" -#include "Common.hh" namespace EGG { - class SceneManager; +class SceneManager; } class KBindSystem final : public EGG::Disposer { @@ -41,8 +43,8 @@ public: private: ~KBindSystem() override; - KBindSystem(const KBindSystem &) = delete; - KBindSystem(KBindSystem &&) = delete; + KBindSystem(const KBindSystem&) = delete; + KBindSystem(KBindSystem&&) = delete; // Scenario Settings // We need to store a copy of them locally to prevent a crash, trying @@ -54,8 +56,8 @@ private: Vehicle vehicle; bool driftIsAuto; }; - std::array m_players; + std::vector m_players; - static KBindSystem *s_instance; - EGG::SceneManager *m_sceneMgr; + static KBindSystem* s_instance; + EGG::SceneManager* m_sceneMgr; }; \ No newline at end of file diff --git a/source/bindings/bindings.cc b/source/bindings/bindings.cc index 53f72d04..5eb55216 100644 --- a/source/bindings/bindings.cc +++ b/source/bindings/bindings.cc @@ -20,6 +20,7 @@ struct KinokoInitializer { }; static KinokoInitializer s_KinokoInitializer_instance; +// clang-format off NB_MODULE(bindings, m) { m.doc() = "Python bindings for Kinoko"; @@ -174,6 +175,7 @@ NB_MODULE(bindings, m) { .def("set_inputs_raw_stick_zero_center", &System::KPadHostController::setInputsRawStickZeroCenter, "buttons"_a, "stick_x_raw"_a, "stick_y_raw"_a, "trick"_a); } +// clang-format on #if defined(__arm64__) || defined(__aarch64__) static void FlushDenormalsToZero() { diff --git a/source/game/scene/RaceScene.cc b/source/game/scene/RaceScene.cc index 0dc8cbc1..1d1f1480 100644 --- a/source/game/scene/RaceScene.cc +++ b/source/game/scene/RaceScene.cc @@ -85,7 +85,7 @@ void RaceScene::initEngines() { Field::ObjectDirector::Instance()->init(); } - //m_heap->disableAllocation(); + // m_heap->disableAllocation(); } /// @addr{0x80554E6C} From db5a2466e6bab334530adc403a05524bb990087e Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Fri, 1 Aug 2025 19:48:33 +0100 Subject: [PATCH 03/27] clang-format fix --- source/bindings/KBindSystem.cc | 39 +++++++++++++++++----------------- source/bindings/KBindSystem.hh | 18 ++++++++-------- source/bindings/bindings.cc | 7 +++--- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc index 8c41f844..ca1f3ab7 100644 --- a/source/bindings/KBindSystem.cc +++ b/source/bindings/KBindSystem.cc @@ -1,13 +1,12 @@ #include "bindings/KBindSystem.hh" - #include "egg/core/ExpHeap.hh" -#include "host/SceneCreatorDynamic.hh" #include "egg/core/SceneManager.hh" #include "game/system/KPadController.hh" #include "game/system/KPadDirector.hh" #include "game/system/RaceConfig.hh" +#include "host/SceneCreatorDynamic.hh" -KBindSystem* KBindSystem::s_instance = nullptr; +KBindSystem *KBindSystem::s_instance = nullptr; KBindSystem::KBindSystem() : m_sceneMgr(nullptr) {} @@ -15,7 +14,7 @@ KBindSystem::~KBindSystem() { delete m_sceneMgr; } -KBindSystem* KBindSystem::CreateInstance() { +KBindSystem *KBindSystem::CreateInstance() { s_instance = new KBindSystem; return s_instance; } @@ -27,26 +26,26 @@ void KBindSystem::DestroyInstance() { void KBindSystem::init() { // Create a new sceneCreator (needed to make RaceScene) - auto* sceneCreator = new Host::SceneCreatorDynamic; + auto *sceneCreator = new Host::SceneCreatorDynamic; m_sceneMgr = new EGG::SceneManager(sceneCreator); // Register a callback to configure RaceConfig once it's created System::RaceConfig::RegisterInitCallback( - [this](System::RaceConfig* config, void* /* arg */) { - auto& scenario = config->raceScenario(); + [this](System::RaceConfig *config, void * /* arg */) { + auto &scenario = config->raceScenario(); - // Set the scenario - scenario.course = m_course; - scenario.playerCount = m_players.size(); + // Set the scenario + scenario.course = m_course; + scenario.playerCount = m_players.size(); - for (size_t i = 0; i < m_players.size(); ++i) { - scenario.players[i].character = m_players[i].character; - scenario.players[i].vehicle = m_players[i].vehicle; - scenario.players[i].driftIsAuto = m_players[i].driftIsAuto; - scenario.players[i].type = System::RaceConfig::Player::Type::Local; - } - }, - nullptr); + for (size_t i = 0; i < m_players.size(); ++i) { + scenario.players[i].character = m_players[i].character; + scenario.players[i].vehicle = m_players[i].vehicle; + scenario.players[i].driftIsAuto = m_players[i].driftIsAuto; + scenario.players[i].type = System::RaceConfig::Player::Type::Local; + } + }, + nullptr); m_sceneMgr->changeScene(static_cast(Host::SceneId::Root)); } @@ -57,7 +56,7 @@ void KBindSystem::step() { } } -System::KPadHostController* KBindSystem::get_host_controller() { +System::KPadHostController *KBindSystem::get_host_controller() { return System::KPadDirector::Instance()->hostController(); } @@ -70,4 +69,4 @@ void KBindSystem::set_player(int slot, Character character, Vehicle vehicle, boo return; } m_players[slot] = {character, vehicle, driftIsAuto}; -} \ No newline at end of file +} diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index 44bba989..913e1d12 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -26,25 +26,25 @@ public: void set_course(Course course); /// @brief Configures a racer. Must be called before init() - void set_player(int playerIdx, Character character, Vehicle vehicle, bool driftIsAuto); + void set_player(int slot, Character character, Vehicle vehicle, bool driftIsAuto); /// @brief Gets the host controller for changing controller state /// At the moment Kinoko only supports one racer, so this returns the controller for player 0 /// @return A pointer to the KPadHostController for the local player - System::KPadHostController* get_host_controller(); + System::KPadHostController *get_host_controller(); - static KBindSystem* CreateInstance(); + static KBindSystem *CreateInstance(); static void DestroyInstance(); - static KBindSystem* Instance() { + static KBindSystem *Instance() { return s_instance; } private: ~KBindSystem() override; - KBindSystem(const KBindSystem&) = delete; - KBindSystem(KBindSystem&&) = delete; + KBindSystem(const KBindSystem &) = delete; + KBindSystem(KBindSystem &&) = delete; // Scenario Settings // We need to store a copy of them locally to prevent a crash, trying @@ -58,6 +58,6 @@ private: }; std::vector m_players; - static KBindSystem* s_instance; - EGG::SceneManager* m_sceneMgr; -}; \ No newline at end of file + static KBindSystem *s_instance; + EGG::SceneManager *m_sceneMgr; +}; diff --git a/source/bindings/bindings.cc b/source/bindings/bindings.cc index 5eb55216..5f0c01d6 100644 --- a/source/bindings/bindings.cc +++ b/source/bindings/bindings.cc @@ -1,10 +1,11 @@ #include #include + +#include "Common.hh" #include "bindings/KBindSystem.hh" -#include "game/system/KPadController.hh" #include "egg/core/ExpHeap.hh" #include "egg/core/SceneManager.hh" -#include "Common.hh" +#include "game/system/KPadController.hh" namespace nb = nanobind; using namespace nb::literals; @@ -209,4 +210,4 @@ static void InitMemory() { s_rootHeap->becomeCurrentHeap(); EGG::SceneManager::SetRootHeap(s_rootHeap); -} \ No newline at end of file +} From 6583d3ae2151d2932ba8cb25f53494555bef9108 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Fri, 1 Aug 2025 21:20:24 +0100 Subject: [PATCH 04/27] Update CMakeLists.txt --- CMakeLists.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9cb1866..dd00c68b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,9 +65,16 @@ target_compile_options(kinoko PRIVATE ${COMMON_CXX_FLAGS}) # - BINDINGS - # +-------------------------------------------+ -# Add dependencies +# Include Python find_package(Python REQUIRED COMPONENTS Development) -add_subdirectory(extern/nanobind) + +# Fetch Nanobind +include(FetchContent) +FetchContent_Declare( + nanobind + GIT_REPOSITORY https://github.com/wjakob/nanobind.git +) +FetchContent_MakeAvailable(nanobind) # Add a target nanobind_add_module(bindings @@ -89,7 +96,7 @@ set(TEST_BIN ${CMAKE_CURRENT_BINARY_DIR}/testCases.bin) add_custom_command( OUTPUT ${TEST_BIN} # The file generated by this rule DEPENDS ${TEST_JSON} # Dependency - COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_tests.py ${TEST_JSON} ${TEST_BIN} + COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_tests.py ${TEST_JSON} ${TEST_BIN} COMMENT "Running generate_tests.py to create test cases" ) add_custom_target( From ca97156007b83b33e37905d4fa4a4ec25c7c0345 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:29:18 +0100 Subject: [PATCH 05/27] Update source/bindings/KBindSystem.cc Co-authored-by: Malleo --- source/bindings/KBindSystem.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc index ca1f3ab7..03dc0bc2 100644 --- a/source/bindings/KBindSystem.cc +++ b/source/bindings/KBindSystem.cc @@ -1,11 +1,14 @@ -#include "bindings/KBindSystem.hh" -#include "egg/core/ExpHeap.hh" -#include "egg/core/SceneManager.hh" -#include "game/system/KPadController.hh" -#include "game/system/KPadDirector.hh" -#include "game/system/RaceConfig.hh" +#include "KBindSystem.hh" + #include "host/SceneCreatorDynamic.hh" +#include +#include +#include + +#include +#include + KBindSystem *KBindSystem::s_instance = nullptr; KBindSystem::KBindSystem() : m_sceneMgr(nullptr) {} From 9deecc45b7effa491c11c383ce503f662f3b2716 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:29:44 +0100 Subject: [PATCH 06/27] Update source/bindings/KBindSystem.hh Co-authored-by: Malleo --- source/bindings/KBindSystem.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index 913e1d12..e15fe670 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -26,7 +26,7 @@ public: void set_course(Course course); /// @brief Configures a racer. Must be called before init() - void set_player(int slot, Character character, Vehicle vehicle, bool driftIsAuto); + void SetPlayer(int slot, Character character, Vehicle vehicle, bool driftIsAuto); /// @brief Gets the host controller for changing controller state /// At the moment Kinoko only supports one racer, so this returns the controller for player 0 From b2e0648ba188843a88f4ac47a281af94f8c640b8 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:29:50 +0100 Subject: [PATCH 07/27] Update source/bindings/KBindSystem.cc Co-authored-by: Malleo --- source/bindings/KBindSystem.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc index 03dc0bc2..9ac0d0fb 100644 --- a/source/bindings/KBindSystem.cc +++ b/source/bindings/KBindSystem.cc @@ -18,6 +18,7 @@ KBindSystem::~KBindSystem() { } KBindSystem *KBindSystem::CreateInstance() { + ASSERT(!s_instance); s_instance = new KBindSystem; return s_instance; } From 2899f3819933d017af46c7f63c5ac22652f17dab Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:29:57 +0100 Subject: [PATCH 08/27] Update source/bindings/bindings.cc Co-authored-by: Malleo --- source/bindings/bindings.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/source/bindings/bindings.cc b/source/bindings/bindings.cc index 5f0c01d6..ff0df31e 100644 --- a/source/bindings/bindings.cc +++ b/source/bindings/bindings.cc @@ -1,11 +1,14 @@ -#include -#include - #include "Common.hh" + #include "bindings/KBindSystem.hh" -#include "egg/core/ExpHeap.hh" -#include "egg/core/SceneManager.hh" -#include "game/system/KPadController.hh" + +#include +#include + +#include + +#include +#include namespace nb = nanobind; using namespace nb::literals; From 925f72fa3d6106fb74653aab9fff02bde07e57ac Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:30:04 +0100 Subject: [PATCH 09/27] Update source/bindings/KBindSystem.cc Co-authored-by: Malleo --- source/bindings/KBindSystem.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc index 9ac0d0fb..aaeac07c 100644 --- a/source/bindings/KBindSystem.cc +++ b/source/bindings/KBindSystem.cc @@ -24,6 +24,7 @@ KBindSystem *KBindSystem::CreateInstance() { } void KBindSystem::DestroyInstance() { + ASSERT(s_instance); delete s_instance; s_instance = nullptr; } From cca75aa21b60851ed4b47a5f6c04c2ec37219c57 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:30:31 +0100 Subject: [PATCH 10/27] Update source/bindings/KBindSystem.hh Co-authored-by: Malleo --- source/bindings/KBindSystem.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index e15fe670..784fa556 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -31,7 +31,7 @@ public: /// @brief Gets the host controller for changing controller state /// At the moment Kinoko only supports one racer, so this returns the controller for player 0 /// @return A pointer to the KPadHostController for the local player - System::KPadHostController *get_host_controller(); + [[nodiscard]] static System::KPadHostController *GetHostController(); static KBindSystem *CreateInstance(); From 4b6ca31941dd0b6f9d53e9f060f8fa08f8d93100 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:55:43 +0100 Subject: [PATCH 11/27] Cleanup of scenario settings + method name changes --- source/bindings/KBindSystem.cc | 33 ++++++++++++++------------------- source/bindings/KBindSystem.hh | 19 +++---------------- source/bindings/bindings.cc | 6 +++--- 3 files changed, 20 insertions(+), 38 deletions(-) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc index aaeac07c..83f3ada2 100644 --- a/source/bindings/KBindSystem.cc +++ b/source/bindings/KBindSystem.cc @@ -9,8 +9,6 @@ #include #include -KBindSystem *KBindSystem::s_instance = nullptr; - KBindSystem::KBindSystem() : m_sceneMgr(nullptr) {} KBindSystem::~KBindSystem() { @@ -37,18 +35,7 @@ void KBindSystem::init() { // Register a callback to configure RaceConfig once it's created System::RaceConfig::RegisterInitCallback( [this](System::RaceConfig *config, void * /* arg */) { - auto &scenario = config->raceScenario(); - - // Set the scenario - scenario.course = m_course; - scenario.playerCount = m_players.size(); - - for (size_t i = 0; i < m_players.size(); ++i) { - scenario.players[i].character = m_players[i].character; - scenario.players[i].vehicle = m_players[i].vehicle; - scenario.players[i].driftIsAuto = m_players[i].driftIsAuto; - scenario.players[i].type = System::RaceConfig::Player::Type::Local; - } + config->raceScenario() = m_scenario; }, nullptr); @@ -61,17 +48,25 @@ void KBindSystem::step() { } } -System::KPadHostController *KBindSystem::get_host_controller() { +System::KPadHostController *KBindSystem::GetHostController() { return System::KPadDirector::Instance()->hostController(); } -void KBindSystem::set_course(Course course) { - m_course = course; +void KBindSystem::SetCourse(Course course) { + m_scenario.course = course; } -void KBindSystem::set_player(int slot, Character character, Vehicle vehicle, bool driftIsAuto) { +void KBindSystem::SetPlayer(int slot, Character character, Vehicle vehicle, bool driftIsAuto) { if (slot < 0 || slot > 12) { return; } - m_players[slot] = {character, vehicle, driftIsAuto}; + + m_scenario.players[slot] = {character, vehicle, System::RaceConfig::Player::Type::Local, + driftIsAuto}; + + if (m_scenario.playerCount <= slot) { + m_scenario.playerCount = slot + 1; + } } + +KBindSystem *KBindSystem::s_instance = nullptr; diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index 784fa556..7db4e214 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -1,7 +1,5 @@ #pragma once -#include - #include "Common.hh" #include "egg/core/Disposer.hh" #include "egg/core/SceneManager.hh" @@ -23,7 +21,7 @@ public: void step(); /// @brief Sets the course for the race. Must be called before init() - void set_course(Course course); + void SetCourse(Course course); /// @brief Configures a racer. Must be called before init() void SetPlayer(int slot, Character character, Vehicle vehicle, bool driftIsAuto); @@ -46,18 +44,7 @@ private: KBindSystem(const KBindSystem &) = delete; KBindSystem(KBindSystem &&) = delete; - // Scenario Settings - // We need to store a copy of them locally to prevent a crash, trying - // to do it via System::RaceConfig::raceScenario() causes a second - // RaceConfig instance when RootScene is created, causing it to segfault. - Course m_course = Course::Luigi_Circuit; - struct PlayerConfig { - Character character; - Vehicle vehicle; - bool driftIsAuto; - }; - std::vector m_players; - - static KBindSystem *s_instance; + System::RaceConfig::Scenario m_scenario; EGG::SceneManager *m_sceneMgr; + static KBindSystem *s_instance; }; diff --git a/source/bindings/bindings.cc b/source/bindings/bindings.cc index ff0df31e..aa6d6819 100644 --- a/source/bindings/bindings.cc +++ b/source/bindings/bindings.cc @@ -164,9 +164,9 @@ NB_MODULE(bindings, m) { .def(nb::init<>()) .def("init", &KBindSystem::init) .def("step", &KBindSystem::step) - .def("set_course", &KBindSystem::set_course, "course"_a) - .def("set_player", &KBindSystem::set_player, "player_idx"_a, "character"_a, "vehicle"_a, "drift_is_auto"_a) - .def("get_host_controller", &KBindSystem::get_host_controller, nb::rv_policy::reference) + .def("set_course", &KBindSystem::SetCourse, "course"_a) + .def("set_player", &KBindSystem::SetPlayer, "slot"_a, "character"_a, "vehicle"_a, "drift_is_auto"_a) + .def_static("get_host_controller", &KBindSystem::GetHostController, nb::rv_policy::reference) .def_static("create_instance", &KBindSystem::CreateInstance, nb::rv_policy::reference) .def_static("destroy_instance", &KBindSystem::DestroyInstance) .def_static("instance", &KBindSystem::Instance, nb::rv_policy::reference); From ec1ea616454421f1aa3ea71724832fd9628666e7 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 00:56:59 +0100 Subject: [PATCH 12/27] Update source/bindings/KBindSystem.hh Co-authored-by: Malleo --- source/bindings/KBindSystem.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index 7db4e214..8f8b19e3 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -35,7 +35,7 @@ public: static void DestroyInstance(); - static KBindSystem *Instance() { + [[nodiscard]] static KBindSystem *Instance() { return s_instance; } From 79959390e54354e1bd99b3ca190d1c61b946596c Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 01:32:16 +0100 Subject: [PATCH 13/27] Script bug fix [skip ci] --- source/bindings/KBindSystem.hh | 4 ---- tools/bindings_test.py | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index 7db4e214..21681aba 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -6,10 +6,6 @@ #include "game/system/KPadController.hh" #include "game/system/RaceConfig.hh" -namespace EGG { -class SceneManager; -} - class KBindSystem final : public EGG::Disposer { public: KBindSystem(); diff --git a/tools/bindings_test.py b/tools/bindings_test.py index 8f090245..1e15e244 100644 --- a/tools/bindings_test.py +++ b/tools/bindings_test.py @@ -1,11 +1,14 @@ import bindings as kinoko -k = kinoko.KBindSystem() +k = kinoko.KBindSystem.create_instance() k.set_course(kinoko.Course.Mushroom_Gorge) k.set_player(0, kinoko.Character.Funky_Kong, kinoko.Vehicle.Flame_Runner, False) k.init() controller = k.get_host_controller() -while True: + +for _ in range(1000): controller.set_inputs(buttons=1, stick_x=0.0, stick_y=1.0, trick=kinoko.Trick.Neutral) - k.step() \ No newline at end of file + k.step() + +k.destroy_instance() \ No newline at end of file From b3d6736d4ff5fd8254f3dd15e3be170a4b9537cc Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 13:06:38 +0100 Subject: [PATCH 14/27] Inherit from KSystem instead of EGG::Disposer [skip ci] --- source/bindings/KBindSystem.cc | 2 +- source/bindings/KBindSystem.hh | 15 +++++++-------- source/bindings/bindings.cc | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/source/bindings/KBindSystem.cc b/source/bindings/KBindSystem.cc index 83f3ada2..8a448956 100644 --- a/source/bindings/KBindSystem.cc +++ b/source/bindings/KBindSystem.cc @@ -42,7 +42,7 @@ void KBindSystem::init() { m_sceneMgr->changeScene(static_cast(Host::SceneId::Root)); } -void KBindSystem::step() { +void KBindSystem::calc() { if (m_sceneMgr) { m_sceneMgr->calc(); } diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index 93a828b2..6a3b21c1 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -1,20 +1,20 @@ #pragma once #include "Common.hh" -#include "egg/core/Disposer.hh" +#include "host/KSystem.hh" #include "egg/core/SceneManager.hh" #include "game/system/KPadController.hh" #include "game/system/RaceConfig.hh" -class KBindSystem final : public EGG::Disposer { +class KBindSystem final : public KSystem { public: KBindSystem(); + ~KBindSystem() override; - /// @brief Initializes the scene manager and starts the root scene - void init(); - - /// @brief Steps the simulation by a frame - void step(); + void init() override; + void calc() override; + bool run() override { return true; } + void parseOptions(int /*argc*/, char ** /*argv*/) override {} /// @brief Sets the course for the race. Must be called before init() void SetCourse(Course course); @@ -36,7 +36,6 @@ public: } private: - ~KBindSystem() override; KBindSystem(const KBindSystem &) = delete; KBindSystem(KBindSystem &&) = delete; diff --git a/source/bindings/bindings.cc b/source/bindings/bindings.cc index aa6d6819..d57704e5 100644 --- a/source/bindings/bindings.cc +++ b/source/bindings/bindings.cc @@ -163,7 +163,7 @@ NB_MODULE(bindings, m) { nb::class_(m, "KBindSystem") .def(nb::init<>()) .def("init", &KBindSystem::init) - .def("step", &KBindSystem::step) + .def("calc", &KBindSystem::calc) .def("set_course", &KBindSystem::SetCourse, "course"_a) .def("set_player", &KBindSystem::SetPlayer, "slot"_a, "character"_a, "vehicle"_a, "drift_is_auto"_a) .def_static("get_host_controller", &KBindSystem::GetHostController, nb::rv_policy::reference) From a9e21b309ac29b9dc847e91f76021206ba9547c2 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:43:08 +0100 Subject: [PATCH 15/27] Ninja bindings support --- configure.py | 241 ++++++++++++++++++++++++++------------------------- 1 file changed, 121 insertions(+), 120 deletions(-) diff --git a/configure.py b/configure.py index 3148e8bd..23b72aa4 100755 --- a/configure.py +++ b/configure.py @@ -1,154 +1,155 @@ #!/usr/bin/env python3 -from glob import glob -import io +import glob import os +import re +import io import sys -from tools.generate_tests import generate_tests +import sysconfig +import subprocess +from dataclasses import dataclass, field from vendor.ninja_syntax import Writer +from tools.generate_tests import generate_tests generate_tests() +# Ninja variables and rules out_buf = io.StringIO() n = Writer(out_buf) -file_extension = '' -if sys.platform.startswith('win32'): - file_extension = '.exe' +build_dir = "build" -n.variable('ninja_required_version', '1.3') +n.variable("ninja_required_version", "1.3") +n.variable("builddir", build_dir) +n.variable("outdir", "out") +n.variable("compiler", "g++") n.newline() - -n.variable('builddir', 'build') -n.variable('outdir', 'out') +n.rule("cc", command="$compiler -MD -MT $out -MF $out.d $ccflags -c $in -o $out", depfile="$out.d", deps="gcc", description="CC $out") n.newline() - -n.variable('compiler', 'g++') +n.rule("ld", command="$compiler $ldflags $in -o $out", description="LD $out") +n.newline() +n.rule("ld_shared", command="$compiler -shared $ldflags $in -o $out", description="LD_SHARED $out") n.newline() -common_ccflags = [ - '-DREVOLUTION', - '-fno-asynchronous-unwind-tables', - '-fno-exceptions', - '-fno-rtti', - '-fshort-wchar', - '-fstack-protector-strong', - '-isystem', '.', - '-isystem', 'include', - '-isystem', 'source', - '-isystem', 'vendor', - '-isystem', 'build', - '-std=c++23', - '-Wall', - '-Wdouble-promotion', - '-Werror', - '-Wextra', - '-Wno-delete-non-virtual-dtor', - '-Wno-packed-bitfield-compat', - '-Wsuggest-override', -] +# Download dependancies +deps_path = os.path.join(build_dir, "_deps") +os.makedirs(deps_path, exist_ok=True) +nanobind_path = os.path.join(deps_path, "nanobind") +robin_path = os.path.join(deps_path, "robin-map") -target_cflags = [ - '-O3', +if not os.path.isdir(nanobind_path): + subprocess.run(["git", "clone", "https://github.com/wjakob/nanobind", nanobind_path], check=True) + +if not os.path.isdir(robin_path): + subprocess.run(["git", "clone", "https://github.com/Tessil/robin-map.git", robin_path], check=True) + +python_include_path = sysconfig.get_paths()["include"] +nanobind_src_path = os.path.join(nanobind_path, "src") +nanobind_include_path = os.path.join(nanobind_path, "include") +robin_include_path = os.path.join(robin_path, "include") + +# Flags +common_ccflags = [ + "-DREVOLUTION", + "-fno-asynchronous-unwind-tables", + "-fshort-wchar", + "-fstack-protector-strong", + "-isystem", ".", + "-isystem", "include", + "-isystem", "source", + "-isystem", "vendor", + "-isystem", "build", + "-isystem", python_include_path, + "-isystem", nanobind_include_path, + "-isystem", robin_include_path, + "-Wall", + "-Werror", + "-Wextra", + "-Wno-delete-non-virtual-dtor", + "-Wno-packed-bitfield-compat", + "-Wsuggest-override", + "-std=c++23", + "-fPIC", ] -debug_cflags = [ - '-DBUILD_DEBUG', - '-O0', - '-ggdb', +# Define build types +@dataclass +class Build: + name: str + suffix: str + flags: list[str] + obj_files: dict = field(default_factory=lambda: { + "common": [], + "main": [], + "bindings": [] + }) + +builds = [ + Build(name="target", suffix="", flags=["-O3"]), + Build(name="debug", suffix="D", flags=["-DBUILD_DEBUG", "-O0", "-ggdb"]) ] -common_ldflags = [] +# Compile files +def GetFiles(): + sep = re.escape(os.path.sep) + main_regex = re.compile(rf".*{sep}host{sep}main\.cc$") + bindings_regex = re.compile(rf".*{sep}bindings{sep}.*\.cc$") -n.rule( - 'cc', - command='$compiler -MD -MT $out -MF $out.d $ccflags -c $in -o $out', - depfile='$out.d', - deps='gcc', - description='CC $out', -) -n.newline() + main_files = [] + bindings_files = [] + common_files = [] -n.rule( - 'ld', - command='$compiler $ldflags $in -o $out', - description='LD $out', -) + for file in glob.glob(os.path.join(".", "**", "*.cc"), recursive=True): + if main_regex.search(file): + main_files.append(file) + continue -code_in_files = [file for file in glob('**/*.cc', recursive=True)] + if bindings_regex.search(file): + bindings_files.append(file) + continue -target_code_out_files = [] -debug_code_out_files = [] + common_files.append(file) -for in_file in code_in_files: - _, ext = os.path.splitext(in_file) + bindings_files.append(os.path.join(nanobind_src_path, "nb_combined.cpp")) - target_out_file = os.path.join('$builddir', in_file + '.o') - target_code_out_files.append(target_out_file) + return common_files, main_files, bindings_files - debug_out_file = os.path.join('$builddir', in_file + 'D.o') - debug_code_out_files.append(debug_out_file) +def Compile(files, builds, obj_key): + for in_file in files: + base_name, _ = os.path.splitext(in_file) + for build in builds: + out_file = os.path.join("$builddir", f"{base_name}{build.suffix}.o") + build.obj_files[obj_key].append(out_file) + n.build(out_file, "cc", in_file, variables={"ccflags": " ".join([*common_ccflags, *build.flags])}) - n.build( - target_out_file, - ext[1:], - in_file, - variables={ - 'ccflags': ' '.join([*common_ccflags, *target_cflags]) - } - ) - n.newline() +common_files, main_files, bindings_files = GetFiles() +Compile(common_files, builds, "common") +Compile(main_files, builds, "main") +Compile(bindings_files, builds, "bindings") +n.newline() - n.build( - debug_out_file, - ext[1:], - in_file, - variables={ - 'ccflags': ' '.join([*common_ccflags, *debug_cflags]) - } - ) +# Link files +binary_extension = ".exe" if sys.platform.startswith("win32") else "" +lib_extension = ".pyd" if sys.platform.startswith("win32") else ".so" + +for build in builds: + # libkinoko + exe_name = f"kinoko{build.suffix}{binary_extension}" + exe_path = os.path.join("$outdir", exe_name) + exe_objs = build.obj_files["common"] + build.obj_files["main"] + n.build(exe_path, "ld", exe_objs) + + # bindings + lib_name = f"bindings{build.suffix}{lib_extension}" + lib_path = os.path.join("$outdir", lib_name) + lib_objs = build.obj_files["common"] + build.obj_files["bindings"] + n.build(lib_path, "ld_shared", lib_objs) n.newline() - -n.build( - os.path.join('$outdir', f'kinoko{file_extension}'), - 'ld', - target_code_out_files, - variables={ - 'ldflags': ' '.join([ - *common_ldflags, - ]) - }, -) - -n.build( - os.path.join('$outdir', f'kinokoD{file_extension}'), - 'ld', - debug_code_out_files, - variables={ - 'ldflags': ' '.join([ - *common_ldflags, - ]) - }, -) - -n.variable('configure', 'configure.py') +n.rule("configure", command=f"{sys.executable} configure.py", generator=True) +n.build("build.ninja", "configure", implicit=["configure.py", os.path.join("vendor", "ninja_syntax.py")]) n.newline() -n.rule( - 'configure', - command=f'{sys.executable} $configure', - generator=True, -) -n.build( - 'build.ninja', - 'configure', - implicit=[ - '$configure', - os.path.join('vendor', 'ninja_syntax.py'), - ], -) - -with open('build.ninja', 'w') as out_file: - out_file.write(out_buf.getvalue()) -n.close() +with open("build.ninja", "w") as f: + f.write(out_buf.getvalue()) +n.close() \ No newline at end of file From b998a302996ee19c2b28938bdd258504cca952d6 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:46:36 +0100 Subject: [PATCH 16/27] clang-format changes --- source/bindings/KBindSystem.hh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/bindings/KBindSystem.hh b/source/bindings/KBindSystem.hh index 6a3b21c1..25fb578f 100644 --- a/source/bindings/KBindSystem.hh +++ b/source/bindings/KBindSystem.hh @@ -1,10 +1,10 @@ #pragma once #include "Common.hh" -#include "host/KSystem.hh" #include "egg/core/SceneManager.hh" #include "game/system/KPadController.hh" #include "game/system/RaceConfig.hh" +#include "host/KSystem.hh" class KBindSystem final : public KSystem { public: @@ -13,7 +13,9 @@ public: void init() override; void calc() override; - bool run() override { return true; } + bool run() override { + return true; + } void parseOptions(int /*argc*/, char ** /*argv*/) override {} /// @brief Sets the course for the race. Must be called before init() From 60cc7b9dec64ad1cb3e10d77085cde0a388f3ded Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 16:52:47 +0100 Subject: [PATCH 17/27] Build bug fix + Moved bindings to Host --- CMakeLists.txt | 6 +-- configure.py | 50 +++++++++++++------ source/{bindings => host}/KBindSystem.cc | 0 source/{bindings => host}/KBindSystem.hh | 0 .../bindings.cc => host/KBindings.cc} | 2 +- 5 files changed, 40 insertions(+), 18 deletions(-) rename source/{bindings => host}/KBindSystem.cc (100%) rename source/{bindings => host}/KBindSystem.hh (100%) rename source/{bindings/bindings.cc => host/KBindings.cc} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd00c68b..ff4ff41a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ set(RK_INCLUDE_DIRS # Source files file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/**/*.cc) list(FILTER SOURCE_FILES EXCLUDE REGEX ".*/host/main\\.cc$") -list(FILTER SOURCE_FILES EXCLUDE REGEX ".*/bindings/.*\\.cc$") +list(FILTER SOURCE_FILES EXCLUDE REGEX ".*/host/KBind.*\\.cc$") add_library(libkinoko ${SOURCE_FILES}) target_include_directories(libkinoko SYSTEM @@ -78,8 +78,8 @@ FetchContent_MakeAvailable(nanobind) # Add a target nanobind_add_module(bindings - source/bindings/KBindSystem.cc - source/bindings/bindings.cc + source/host/KBindSystem.cc + source/host/KBindings.cc ) # Link libraries diff --git a/configure.py b/configure.py index 23b72aa4..a143edfa 100755 --- a/configure.py +++ b/configure.py @@ -23,8 +23,10 @@ n.variable("builddir", build_dir) n.variable("outdir", "out") n.variable("compiler", "g++") +n.variable("ar", "ar") n.newline() n.rule("cc", command="$compiler -MD -MT $out -MF $out.d $ccflags -c $in -o $out", depfile="$out.d", deps="gcc", description="CC $out") +n.rule("ar", command="$ar rcs $out $in", description="AR $out") n.newline() n.rule("ld", command="$compiler $ldflags $in -o $out", description="LD $out") n.newline() @@ -52,13 +54,26 @@ common_ccflags = [ "-DREVOLUTION", "-fno-asynchronous-unwind-tables", + "-fno-exceptions", "-fshort-wchar", "-fstack-protector-strong", - "-isystem", ".", "-isystem", "include", "-isystem", "source", - "-isystem", "vendor", - "-isystem", "build", + "-Wall", + "-Werror", + "-Wextra", + "-Wno-delete-non-virtual-dtor", + "-Wno-packed-bitfield-compat", + "-Wsuggest-override", + "-std=c++23", + "-fPIC", +] + +bindings_ccflags = [ + "-DREVOLUTION", + "-fstack-protector-strong", + "-isystem", "include", + "-isystem", "source", "-isystem", python_include_path, "-isystem", nanobind_include_path, "-isystem", robin_include_path, @@ -93,13 +108,13 @@ class Build: def GetFiles(): sep = re.escape(os.path.sep) main_regex = re.compile(rf".*{sep}host{sep}main\.cc$") - bindings_regex = re.compile(rf".*{sep}bindings{sep}.*\.cc$") + bindings_regex = re.compile(rf".*{sep}host{sep}KBind.*\.cc$") main_files = [] bindings_files = [] common_files = [] - for file in glob.glob(os.path.join(".", "**", "*.cc"), recursive=True): + for file in glob.glob(os.path.join("source", "**", "*.cc"), recursive=True): if main_regex.search(file): main_files.append(file) continue @@ -114,18 +129,18 @@ def GetFiles(): return common_files, main_files, bindings_files -def Compile(files, builds, obj_key): +def Compile(files, builds, obj_key, flags): for in_file in files: base_name, _ = os.path.splitext(in_file) for build in builds: out_file = os.path.join("$builddir", f"{base_name}{build.suffix}.o") build.obj_files[obj_key].append(out_file) - n.build(out_file, "cc", in_file, variables={"ccflags": " ".join([*common_ccflags, *build.flags])}) + n.build(out_file, "cc", in_file, variables={"ccflags": " ".join([*flags, *build.flags])}) common_files, main_files, bindings_files = GetFiles() -Compile(common_files, builds, "common") -Compile(main_files, builds, "main") -Compile(bindings_files, builds, "bindings") +Compile(common_files, builds, "common", common_ccflags) +Compile(main_files, builds, "main", common_ccflags) +Compile(bindings_files, builds, "bindings", bindings_ccflags) n.newline() # Link files @@ -134,15 +149,22 @@ def Compile(files, builds, obj_key): for build in builds: # libkinoko + libkinoko_name = f"libkinoko{build.suffix}.a" + libkinoko_path = os.path.join("$builddir", libkinoko_name) + libkinoko_objs = build.obj_files["common"] + n.build(libkinoko_path, "ar", libkinoko_objs) + n.newline() + + # kinoko exe_name = f"kinoko{build.suffix}{binary_extension}" exe_path = os.path.join("$outdir", exe_name) - exe_objs = build.obj_files["common"] + build.obj_files["main"] - n.build(exe_path, "ld", exe_objs) - + exe_obj = build.obj_files["main"] + [libkinoko_path] + n.build(exe_path, "ld", exe_obj) + # bindings lib_name = f"bindings{build.suffix}{lib_extension}" lib_path = os.path.join("$outdir", lib_name) - lib_objs = build.obj_files["common"] + build.obj_files["bindings"] + lib_objs = build.obj_files["bindings"] + [libkinoko_path] n.build(lib_path, "ld_shared", lib_objs) n.newline() diff --git a/source/bindings/KBindSystem.cc b/source/host/KBindSystem.cc similarity index 100% rename from source/bindings/KBindSystem.cc rename to source/host/KBindSystem.cc diff --git a/source/bindings/KBindSystem.hh b/source/host/KBindSystem.hh similarity index 100% rename from source/bindings/KBindSystem.hh rename to source/host/KBindSystem.hh diff --git a/source/bindings/bindings.cc b/source/host/KBindings.cc similarity index 99% rename from source/bindings/bindings.cc rename to source/host/KBindings.cc index d57704e5..06f27f0d 100644 --- a/source/bindings/bindings.cc +++ b/source/host/KBindings.cc @@ -1,6 +1,6 @@ #include "Common.hh" -#include "bindings/KBindSystem.hh" +#include "host/KBindSystem.hh" #include #include From ca6fa297e739ca6ab2689597e08fc327456cfe0f Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sat, 2 Aug 2025 17:57:22 +0100 Subject: [PATCH 18/27] Fix typo in bindings_test.py [skip ci] --- tools/bindings_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bindings_test.py b/tools/bindings_test.py index 1e15e244..69b50314 100644 --- a/tools/bindings_test.py +++ b/tools/bindings_test.py @@ -9,6 +9,6 @@ for _ in range(1000): controller.set_inputs(buttons=1, stick_x=0.0, stick_y=1.0, trick=kinoko.Trick.Neutral) - k.step() + k.calc() k.destroy_instance() \ No newline at end of file From bbda373e7600d5a76bfc0d9e65adc602206f2424 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 12:59:05 +0100 Subject: [PATCH 19/27] Ninja script bug fix + Heap.hh std compliance --- configure.py | 10 +++++++--- source/egg/core/Heap.hh | 12 ++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/configure.py b/configure.py index a143edfa..8fb8d4e1 100755 --- a/configure.py +++ b/configure.py @@ -28,9 +28,9 @@ n.rule("cc", command="$compiler -MD -MT $out -MF $out.d $ccflags -c $in -o $out", depfile="$out.d", deps="gcc", description="CC $out") n.rule("ar", command="$ar rcs $out $in", description="AR $out") n.newline() -n.rule("ld", command="$compiler $ldflags $in -o $out", description="LD $out") +n.rule("ld", command="$compiler $in $ldflags -o $out", description="LD $out") n.newline() -n.rule("ld_shared", command="$compiler -shared $ldflags $in -o $out", description="LD_SHARED $out") +n.rule("ld_shared", command="$compiler -shared $in $ldflags -o $out", description="LD_SHARED $out") n.newline() # Download dependancies @@ -49,6 +49,7 @@ nanobind_src_path = os.path.join(nanobind_path, "src") nanobind_include_path = os.path.join(nanobind_path, "include") robin_include_path = os.path.join(robin_path, "include") +python_lib_path = os.path.join(sysconfig.get_paths()["data"], "libs", f"libpython{sys.version_info.major}.{sys.version_info.minor}.a") # Flags common_ccflags = [ @@ -67,6 +68,7 @@ "-Wsuggest-override", "-std=c++23", "-fPIC", + "-fno-exceptions", ] bindings_ccflags = [ @@ -165,7 +167,9 @@ def Compile(files, builds, obj_key, flags): lib_name = f"bindings{build.suffix}{lib_extension}" lib_path = os.path.join("$outdir", lib_name) lib_objs = build.obj_files["bindings"] + [libkinoko_path] - n.build(lib_path, "ld_shared", lib_objs) + + # Python library + n.build(lib_path, "ld_shared", lib_objs, variables={"ldflags": f"{sysconfig.get_config_var('LDFLAGS')} -L{os.path.dirname(python_lib_path)} -lpython{sys.version_info.major}.{sys.version_info.minor}"}) n.newline() n.rule("configure", command=f"{sys.executable} configure.py", generator=True) diff --git a/source/egg/core/Heap.hh b/source/egg/core/Heap.hh index 25b73de4..41265653 100644 --- a/source/egg/core/Heap.hh +++ b/source/egg/core/Heap.hh @@ -128,11 +128,11 @@ protected: } // namespace EGG -[[nodiscard]] void *operator new(size_t size) noexcept; -[[nodiscard]] void *operator new(size_t size, int align) noexcept; -[[nodiscard]] void *operator new(size_t size, EGG::Heap *heap, int align) noexcept; -[[nodiscard]] void *operator new[](size_t size) noexcept; -[[nodiscard]] void *operator new[](size_t size, int align) noexcept; -[[nodiscard]] void *operator new[](size_t size, EGG::Heap *heap, int align) noexcept; +[[nodiscard]] void *operator new(size_t size); +[[nodiscard]] void *operator new(size_t size, int align); +[[nodiscard]] void *operator new(size_t size, EGG::Heap *heap, int align); +[[nodiscard]] void *operator new[](size_t size); +[[nodiscard]] void *operator new[](size_t size, int align); +[[nodiscard]] void *operator new[](size_t size, EGG::Heap *heap, int align); void operator delete(void *block) noexcept; void operator delete[](void *block) noexcept; From 5680fc09764e0352788fe7806c3a347adee0f347 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 13:22:28 +0100 Subject: [PATCH 20/27] Fix build script for Linux --- configure.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/configure.py b/configure.py index 8fb8d4e1..2468ceab 100755 --- a/configure.py +++ b/configure.py @@ -13,6 +13,8 @@ generate_tests() +ON_WINDOWS = True if sys.platform.startswith("win32") else False + # Ninja variables and rules out_buf = io.StringIO() n = Writer(out_buf) @@ -146,8 +148,8 @@ def Compile(files, builds, obj_key, flags): n.newline() # Link files -binary_extension = ".exe" if sys.platform.startswith("win32") else "" -lib_extension = ".pyd" if sys.platform.startswith("win32") else ".so" +binary_extension = ".exe" if ON_WINDOWS else "" +lib_extension = ".pyd" if ON_WINDOWS else ".so" for build in builds: # libkinoko @@ -169,7 +171,10 @@ def Compile(files, builds, obj_key, flags): lib_objs = build.obj_files["bindings"] + [libkinoko_path] # Python library - n.build(lib_path, "ld_shared", lib_objs, variables={"ldflags": f"{sysconfig.get_config_var('LDFLAGS')} -L{os.path.dirname(python_lib_path)} -lpython{sys.version_info.major}.{sys.version_info.minor}"}) + if ON_WINDOWS: + n.build(lib_path, "ld_shared", lib_objs, variables={"ldflags": f"{sysconfig.get_config_var('LDFLAGS')} -L{os.path.dirname(python_lib_path)} -lpython{sys.version_info.major}.{sys.version_info.minor}"}) + else: + n.build(lib_path, "ld_shared", lib_objs, variables={"ldflags": f"{sysconfig.get_config_var('LDFLAGS')} -L{os.path.dirname(python_lib_path)}"}) n.newline() n.rule("configure", command=f"{sys.executable} configure.py", generator=True) From 8deb1a188d2833f76745ff7ea5098703933bcbd3 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 14:11:34 +0100 Subject: [PATCH 21/27] Add "no-format" flag for bindings --- configure.py | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.py b/configure.py index 2468ceab..a9152fc5 100755 --- a/configure.py +++ b/configure.py @@ -84,6 +84,7 @@ "-Wall", "-Werror", "-Wextra", + "-Wno-format", "-Wno-delete-non-virtual-dtor", "-Wno-packed-bitfield-compat", "-Wsuggest-override", From 934ca6d5611ef90e987dfcca1f16410f07d15cff Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 15:03:29 +0100 Subject: [PATCH 22/27] Variable reordering --- configure.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/configure.py b/configure.py index a9152fc5..f89025c0 100755 --- a/configure.py +++ b/configure.py @@ -37,10 +37,11 @@ # Download dependancies deps_path = os.path.join(build_dir, "_deps") -os.makedirs(deps_path, exist_ok=True) nanobind_path = os.path.join(deps_path, "nanobind") robin_path = os.path.join(deps_path, "robin-map") +os.makedirs(deps_path, exist_ok=True) + if not os.path.isdir(nanobind_path): subprocess.run(["git", "clone", "https://github.com/wjakob/nanobind", nanobind_path], check=True) @@ -48,10 +49,10 @@ subprocess.run(["git", "clone", "https://github.com/Tessil/robin-map.git", robin_path], check=True) python_include_path = sysconfig.get_paths()["include"] -nanobind_src_path = os.path.join(nanobind_path, "src") +python_lib_path = os.path.join(sysconfig.get_paths()["data"], "libs", f"libpython{sys.version_info.major}.{sys.version_info.minor}.a") nanobind_include_path = os.path.join(nanobind_path, "include") +nanobind_src_path = os.path.join(nanobind_path, "src") robin_include_path = os.path.join(robin_path, "include") -python_lib_path = os.path.join(sysconfig.get_paths()["data"], "libs", f"libpython{sys.version_info.major}.{sys.version_info.minor}.a") # Flags common_ccflags = [ From f6298d7f68af8e7aa4c8963dd499811f0bf8a016 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 16:49:15 +0100 Subject: [PATCH 23/27] KartObjectProxy bindings --- source/host/KBindSystem.cc | 4 ++++ source/host/KBindSystem.hh | 13 +++++++++++-- source/host/KBindings.cc | 35 ++++++++++++++++++++++++++++++++--- tools/bindings_test.py | 11 ++++++++++- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/source/host/KBindSystem.cc b/source/host/KBindSystem.cc index 8a448956..1f7c6e09 100644 --- a/source/host/KBindSystem.cc +++ b/source/host/KBindSystem.cc @@ -52,6 +52,10 @@ System::KPadHostController *KBindSystem::GetHostController() { return System::KPadDirector::Instance()->hostController(); } +Kart::KartObjectProxy *KBindSystem::get_kart(int slot) { + return Kart::KartObjectManager::Instance()->object(slot); +} + void KBindSystem::SetCourse(Course course) { m_scenario.course = course; } diff --git a/source/host/KBindSystem.hh b/source/host/KBindSystem.hh index 25fb578f..00a4ccad 100644 --- a/source/host/KBindSystem.hh +++ b/source/host/KBindSystem.hh @@ -1,10 +1,15 @@ #pragma once #include "Common.hh" -#include "egg/core/SceneManager.hh" + +#include "game/kart/KartObjectManager.hh" + #include "game/system/KPadController.hh" #include "game/system/RaceConfig.hh" -#include "host/KSystem.hh" + +#include + +#include class KBindSystem final : public KSystem { public: @@ -29,6 +34,10 @@ public: /// @return A pointer to the KPadHostController for the local player [[nodiscard]] static System::KPadHostController *GetHostController(); + /// @brief Gets the KartObjectProxy instance for a specific slot + /// @return A pointer to the KartObjectInstance for the specified slot + [[nodiscard]] Kart::KartObjectProxy *get_kart(int slot); + static KBindSystem *CreateInstance(); static void DestroyInstance(); diff --git a/source/host/KBindings.cc b/source/host/KBindings.cc index 06f27f0d..be4d8821 100644 --- a/source/host/KBindings.cc +++ b/source/host/KBindings.cc @@ -1,11 +1,15 @@ #include "Common.hh" -#include "host/KBindSystem.hh" +#include "game/system/KPadController.hh" + +#include "game/kart/KartObjectProxy.hh" + +#include #include #include - -#include +#include +#include #include #include @@ -152,6 +156,30 @@ NB_MODULE(bindings, m) { .value("N64_Bowsers_Castle", Course::N64_Bowsers_Castle) .export_values(); + nb::class_(m, "Vector3f") + .def(nb::init()) + .def_rw("x", &EGG::Vector3f::x) + .def_rw("y", &EGG::Vector3f::y) + .def_rw("z", &EGG::Vector3f::z); + + nb::class_(m, "Quatf") + .def(nb::init(), "w"_a, "x"_a, "y"_a, "z"_a) + .def_rw("v", &EGG::Quatf::v) + .def_rw("w", &EGG::Quatf::w); + + nb::class_(m, "KartObjectProxy") + .def("speed", &Kart::KartObjectProxy::speed) + .def("acceleration", &Kart::KartObjectProxy::acceleration) + .def("speedRatio", &Kart::KartObjectProxy::speedRatio) + .def("speedRatioCapped", &Kart::KartObjectProxy::speedRatioCapped) + .def("softSpeedLimit", &Kart::KartObjectProxy::softSpeedLimit) + .def("pos", &Kart::KartObjectProxy::pos, nb::rv_policy::reference_internal) + .def("extVel", &Kart::KartObjectProxy::extVel, nb::rv_policy::reference_internal) + .def("intVel", &Kart::KartObjectProxy::intVel, nb::rv_policy::reference_internal) + .def("velocity", &Kart::KartObjectProxy::velocity, nb::rv_policy::reference_internal) + .def("mainRot", &Kart::KartObjectProxy::mainRot, nb::rv_policy::reference_internal) + .def("fullRot", &Kart::KartObjectProxy::fullRot, nb::rv_policy::reference_internal); + nb::enum_(m, "Trick") .value("Neutral", System::Trick::None) // None is reserved .value("Up", System::Trick::Up) @@ -166,6 +194,7 @@ NB_MODULE(bindings, m) { .def("calc", &KBindSystem::calc) .def("set_course", &KBindSystem::SetCourse, "course"_a) .def("set_player", &KBindSystem::SetPlayer, "slot"_a, "character"_a, "vehicle"_a, "drift_is_auto"_a) + .def("get_kart", &KBindSystem::get_kart, nb::rv_policy::reference) .def_static("get_host_controller", &KBindSystem::GetHostController, nb::rv_policy::reference) .def_static("create_instance", &KBindSystem::CreateInstance, nb::rv_policy::reference) .def_static("destroy_instance", &KBindSystem::DestroyInstance) diff --git a/tools/bindings_test.py b/tools/bindings_test.py index 69b50314..91af22db 100644 --- a/tools/bindings_test.py +++ b/tools/bindings_test.py @@ -6,9 +6,18 @@ k.init() controller = k.get_host_controller() +kart = k.get_kart(0) -for _ in range(1000): +for i in range(1000): controller.set_inputs(buttons=1, stick_x=0.0, stick_y=1.0, trick=kinoko.Trick.Neutral) k.calc() + pos = kart.pos() + speed = kart.speed() + + print(f"Frame {i}:") + print(f"pos: {pos.x:.2f}, {pos.y:.2f}, {pos.z:.2f}") + print(f"speed: {speed:.2f}") + print("------------------------") + k.destroy_instance() \ No newline at end of file From 3d8baa0d526fb878f61f9d0256634f05684e7b42 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 17:07:43 +0100 Subject: [PATCH 24/27] Function rename --- source/host/KBindSystem.cc | 2 +- source/host/KBindSystem.hh | 2 +- source/host/KBindings.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/host/KBindSystem.cc b/source/host/KBindSystem.cc index 1f7c6e09..d76abc3d 100644 --- a/source/host/KBindSystem.cc +++ b/source/host/KBindSystem.cc @@ -52,7 +52,7 @@ System::KPadHostController *KBindSystem::GetHostController() { return System::KPadDirector::Instance()->hostController(); } -Kart::KartObjectProxy *KBindSystem::get_kart(int slot) { +Kart::KartObjectProxy *KBindSystem::GetKart(int slot) { return Kart::KartObjectManager::Instance()->object(slot); } diff --git a/source/host/KBindSystem.hh b/source/host/KBindSystem.hh index 00a4ccad..ac0aac73 100644 --- a/source/host/KBindSystem.hh +++ b/source/host/KBindSystem.hh @@ -36,7 +36,7 @@ public: /// @brief Gets the KartObjectProxy instance for a specific slot /// @return A pointer to the KartObjectInstance for the specified slot - [[nodiscard]] Kart::KartObjectProxy *get_kart(int slot); + [[nodiscard]] Kart::KartObjectProxy *GetKart(int slot); static KBindSystem *CreateInstance(); diff --git a/source/host/KBindings.cc b/source/host/KBindings.cc index be4d8821..07488b5c 100644 --- a/source/host/KBindings.cc +++ b/source/host/KBindings.cc @@ -194,7 +194,7 @@ NB_MODULE(bindings, m) { .def("calc", &KBindSystem::calc) .def("set_course", &KBindSystem::SetCourse, "course"_a) .def("set_player", &KBindSystem::SetPlayer, "slot"_a, "character"_a, "vehicle"_a, "drift_is_auto"_a) - .def("get_kart", &KBindSystem::get_kart, nb::rv_policy::reference) + .def("get_kart", &KBindSystem::GetKart, nb::rv_policy::reference) .def_static("get_host_controller", &KBindSystem::GetHostController, nb::rv_policy::reference) .def_static("create_instance", &KBindSystem::CreateInstance, nb::rv_policy::reference) .def_static("destroy_instance", &KBindSystem::DestroyInstance) From 8f08051d591d9261a531c193fa1eac21ca780f4f Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 22:48:39 +0100 Subject: [PATCH 25/27] Update source/host/KBindings.cc Co-authored-by: Malleo --- source/host/KBindings.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/host/KBindings.cc b/source/host/KBindings.cc index 07488b5c..927282c3 100644 --- a/source/host/KBindings.cc +++ b/source/host/KBindings.cc @@ -2,9 +2,9 @@ #include "game/system/KPadController.hh" -#include "game/kart/KartObjectProxy.hh" +#include "host/KBindSystem.hh" -#include +#include #include #include From b2b5b2a9456f57fd9dee9426a2d14414274d8b58 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 22:54:23 +0100 Subject: [PATCH 26/27] Update configure.py --- configure.py | 76 ++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/configure.py b/configure.py index f89025c0..2bbaef58 100755 --- a/configure.py +++ b/configure.py @@ -56,41 +56,41 @@ # Flags common_ccflags = [ - "-DREVOLUTION", - "-fno-asynchronous-unwind-tables", - "-fno-exceptions", - "-fshort-wchar", - "-fstack-protector-strong", - "-isystem", "include", - "-isystem", "source", - "-Wall", - "-Werror", - "-Wextra", - "-Wno-delete-non-virtual-dtor", - "-Wno-packed-bitfield-compat", - "-Wsuggest-override", - "-std=c++23", - "-fPIC", - "-fno-exceptions", + '-DREVOLUTION', + '-fno-asynchronous-unwind-tables', + '-fno-exceptions', + '-fshort-wchar', + '-fstack-protector-strong', + '-isystem', 'include', + '-isystem', 'source', + '-Wall', + '-Werror', + '-Wextra', + '-Wno-delete-non-virtual-dtor', + '-Wno-packed-bitfield-compat', + '-Wsuggest-override', + '-std=c++23', + '-fPIC', + '-fno-exceptions', ] bindings_ccflags = [ - "-DREVOLUTION", - "-fstack-protector-strong", - "-isystem", "include", - "-isystem", "source", - "-isystem", python_include_path, - "-isystem", nanobind_include_path, - "-isystem", robin_include_path, - "-Wall", - "-Werror", - "-Wextra", - "-Wno-format", - "-Wno-delete-non-virtual-dtor", - "-Wno-packed-bitfield-compat", - "-Wsuggest-override", - "-std=c++23", - "-fPIC", + '-DREVOLUTION', + '-fstack-protector-strong', + '-isystem', 'include', + '-isystem', 'source', + '-isystem', python_include_path, + '-isystem', nanobind_include_path, + '-isystem', robin_include_path, + '-Wall', + '-Werror', + '-Wextra', + '-Wno-format', + '-Wno-delete-non-virtual-dtor', + '-Wno-packed-bitfield-compat', + '-Wsuggest-override', + '-std=c++23', + '-fPIC', ] # Define build types @@ -111,7 +111,7 @@ class Build: ] # Compile files -def GetFiles(): +def get_files(): sep = re.escape(os.path.sep) main_regex = re.compile(rf".*{sep}host{sep}main\.cc$") bindings_regex = re.compile(rf".*{sep}host{sep}KBind.*\.cc$") @@ -135,7 +135,7 @@ def GetFiles(): return common_files, main_files, bindings_files -def Compile(files, builds, obj_key, flags): +def compile(files, builds, obj_key, flags): for in_file in files: base_name, _ = os.path.splitext(in_file) for build in builds: @@ -143,10 +143,10 @@ def Compile(files, builds, obj_key, flags): build.obj_files[obj_key].append(out_file) n.build(out_file, "cc", in_file, variables={"ccflags": " ".join([*flags, *build.flags])}) -common_files, main_files, bindings_files = GetFiles() -Compile(common_files, builds, "common", common_ccflags) -Compile(main_files, builds, "main", common_ccflags) -Compile(bindings_files, builds, "bindings", bindings_ccflags) +common_files, main_files, bindings_files = get_files() +compile(common_files, builds, "common", common_ccflags) +compile(main_files, builds, "main", common_ccflags) +compile(bindings_files, builds, "bindings", bindings_ccflags) n.newline() # Link files From 5acca4c4086aecdb2fd9966545e0ec1a1172a219 Mon Sep 17 00:00:00 2001 From: o2161405 <91959604+o2161405@users.noreply.github.com> Date: Sun, 3 Aug 2025 23:01:01 +0100 Subject: [PATCH 27/27] SetCourse now in header --- source/host/KBindSystem.cc | 4 ---- source/host/KBindSystem.hh | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/source/host/KBindSystem.cc b/source/host/KBindSystem.cc index d76abc3d..6080ec32 100644 --- a/source/host/KBindSystem.cc +++ b/source/host/KBindSystem.cc @@ -56,10 +56,6 @@ Kart::KartObjectProxy *KBindSystem::GetKart(int slot) { return Kart::KartObjectManager::Instance()->object(slot); } -void KBindSystem::SetCourse(Course course) { - m_scenario.course = course; -} - void KBindSystem::SetPlayer(int slot, Character character, Vehicle vehicle, bool driftIsAuto) { if (slot < 0 || slot > 12) { return; diff --git a/source/host/KBindSystem.hh b/source/host/KBindSystem.hh index ac0aac73..af76a1b5 100644 --- a/source/host/KBindSystem.hh +++ b/source/host/KBindSystem.hh @@ -24,7 +24,9 @@ public: void parseOptions(int /*argc*/, char ** /*argv*/) override {} /// @brief Sets the course for the race. Must be called before init() - void SetCourse(Course course); + void SetCourse(Course course) { + m_scenario.course = course; + } /// @brief Configures a racer. Must be called before init() void SetPlayer(int slot, Character character, Vehicle vehicle, bool driftIsAuto);