#include "Player.hpp" #include "AppConfig.hpp" #include "CommonVertexIndex.hpp" #include "ScopeGuard.hpp" #include "Utils.hpp" #include #include // Keep the same number as # of fields in `struct {}` in PlayerKeyBinds constexpr int kPlayerKeyBindCount = 4; // Here be dragons: this treats consecutive fiels as an array, technically UB std::span PlayerKeyBinds::GetKeyArray() { return { &keyLeft, kPlayerKeyBindCount }; } std::span PlayerKeyBinds::GetKeyStatusArray() { return { &pressedLeft, kPlayerKeyBindCount }; } Player::Player(GameWorld* world, int id) : GameObject(KD_Player, world) , mId{ id } { renderObject.SetMaterial(gDefaultMaterial.Get()); renderObject.SetFormat(gVformatStandard.Get(), Tags::IT_16Bit); renderObject.RebuildIfNecessary(); } void Player::Awaken() { LoadFromFile(); } void Player::Resleep() { SaveToFile(); } void Player::Update() { using namespace Tags; if (keybinds.pressedLeft) { } if (keybinds.pressedRight) { } // TODO jump controller // TODO attack controller // TODO set default sprite to get rid of this check if (sprite.GetDefinition()) { int prevFrame = sprite.GetFrame(); sprite.PlayFrame(); int currFrame = sprite.GetFrame(); if (prevFrame != currFrame) { uint16_t indices[6]; Index_U16::Assign(indices, 0); renderObject.GetIndexBuffer()->Upload((const std::byte*)indices, IT_16Bit, std::size(indices)); Vertex_PTC vertices[4]; Vertex_PTC::Assign(vertices, Rect{ GetPos(), sprite.GetDefinition()->GetBoundingBox() }); Vertex_PTC::Assign(vertices, 0.0f); Vertex_PTC::Assign(vertices, RgbaColor(255, 255, 255)); Vertex_PTC::Assign(vertices, sprite.GetFrameSubregion()); renderObject.GetVertexBufferBindings().bindings[0]->Upload((const std::byte*)vertices, sizeof(vertices)); } } } Material* Player::GetMaterial() const { return renderObject.GetMaterial(); } void Player::SetMaterial(Material* material) { renderObject.SetMaterial(material); renderObject.RebuildIfNecessary(); } std::span Player::GetRenderObjects() const { return { &renderObject, 1 }; } void Player::HandleKeyInput(int key, int action) { bool pressed; if (action == GLFW_PRESS) { pressed = true; } else if (action == GLFW_REPEAT) { return; } else /* action == GLFW_RELEASE */ { pressed = false; } for (int i = 0; i < kPlayerKeyBindCount; ++i) { int kbKey = keybinds.GetKeyArray()[i]; bool& kbStatus = keybinds.GetKeyStatusArray()[i]; if (kbKey == key) { kbStatus = pressed; break; } } } #pragma push_macro("PLAYERKEYBINDS_DO_IO") #undef PLAYERKEYBINDS_DO_IO #define PLAYERKEYBINDS_DO_IO(function, fieldPrefix) \ function(file, "left=%d\n", fieldPrefix keybinds.keyLeft); \ function(file, "right=%d\n", fieldPrefix keybinds.keyRight); \ function(file, "jump=%d\n", fieldPrefix keybinds.keyJump); \ function(file, "attack=%d\n", fieldPrefix keybinds.keyAttack); static FILE* OpenPlayerConfigFile(Player* player, Utils::IoMode mode) { char path[512]; snprintf(path, sizeof(path), "%s/player%d.txt", AppConfig::dataDir.c_str(), player->GetId()); return Utils::OpenCstdioFile(path, mode); } bool Player::LoadFromFile() { auto file = OpenPlayerConfigFile(this, Utils::Read); if (!file) return false; DEFER { fclose(file); }; // TODO input validation PLAYERKEYBINDS_DO_IO(fscanf, &); return true; } bool Player::SaveToFile() { auto file = OpenPlayerConfigFile(this, Utils::WriteTruncate); if (!file) return false; DEFER { fclose(file); }; PLAYERKEYBINDS_DO_IO(fprintf, ); return true; } #pragma pop_macro("PLAYERKEYBINDS_DO_IO")