<repo_name>mall0c/TileEngine<file_sep>/include/gamelib/core/res/EntityConfigResource.hpp
#ifndef GAMELIB_ENTITYCONFIGRESOURCE_HPP
#define GAMELIB_ENTITYCONFIGRESOURCE_HPP

#include "Resource.hpp"

/*
 * Provides an alternative loader for JsonResource that automatically registers
 * it at EntityFactory.
 */

namespace gamelib
{
    class ResourceManager;

    void registerEntityConfigLoader(ResourceManager& resmgr);

    BaseResourceHandle entityConfigLoader(const std::string& fname, ResourceManager* resmgr);
}

#endif
<file_sep>/src/gamelib/core/res/EntityConfigResource.cpp
#include "gamelib/core/res/EntityConfigResource.hpp"
#include "gamelib/core/res/ResourceManager.hpp"
#include "gamelib/core/ecs/EntityFactory.hpp"
#include "gamelib/json/json-utils.hpp"
#include "gamelib/core/res/JsonResource.hpp"

namespace gamelib
{
    void registerEntityConfigLoader(ResourceManager& resmgr)
    {
        for (auto& i : { "ent", "entity" })
            resmgr.registerFileType(i, entityConfigLoader);
    }

    BaseResourceHandle entityConfigLoader(const std::string& fname, ResourceManager* resmgr)
    {
        auto res = jsonLoader(fname, resmgr).as<JsonResource>();

        if (res->isMember("base"))
        {
            // loadOnce because it will be modified
            auto baseres = resmgr->loadOnce((*res)["base"].asString()).as<JsonResource>();
            mergeJson(*res, &*baseres);
            res = baseres;
        }

        if (res->isMember("children"))
        {
            LOG_ERROR("Can't define children in entity configs -> removing");
            res->removeMember("children");
        }

        auto factory = getSubsystem<EntityFactory>();
        if (factory)
            factory->add(*res);

        return res;
    }
}
<file_sep>/include/gamelib/core/input/InputSystem.hpp
#ifndef GAMELIB_INPUT_SYSTEM_HPP
#define GAMELIB_INPUT_SYSTEM_HPP

#include <SFML/Graphics.hpp>
#include "math/geometry/Vector.hpp"
#include "gamelib/core/Subsystem.hpp"

namespace gamelib
{
    class InputSystem : public Subsystem<InputSystem>
    {
        public:
            ASSIGN_NAMETAG("InputSystem");

            enum ButtonState
            {
                Pressed,
                Released,
                Down,
                None
            };

            struct MouseData
            {
                math::Point2i desktop;
                math::Point2i win;
                math::Point2f world;
                int wheel;
                bool moved;
            };

        public:
            InputSystem();
            InputSystem(const sf::RenderWindow& win);

            auto setWindow(const sf::RenderWindow& win) -> void;

            auto beginFrame()                 -> void;
            auto process(const sf::Event& ev) -> void;

            auto markConsumed(bool keyboard, bool mouse) -> void;
            auto isKeyboardConsumed() const -> bool;
            auto isMouseConsumed() const    -> bool;

            auto isKeyPressed(sf::Keyboard::Key key) const  -> bool;
            auto isKeyReleased(sf::Keyboard::Key key) const -> bool;
            auto isKeyDown(sf::Keyboard::Key key) const     -> bool;

            auto isMousePressed(sf::Mouse::Button btn) const  -> bool;
            auto isMouseReleased(sf::Mouse::Button btn) const -> bool;
            auto isMouseDown(sf::Mouse::Button btn) const     -> bool;

            auto isKey(sf::Keyboard::Key key, ButtonState state) const   -> bool;
            auto isMouse(sf::Mouse::Button btn, ButtonState state) const -> bool;

            auto getKeyState(sf::Keyboard::Key key) const   -> ButtonState;
            auto getMouseState(sf::Mouse::Button btn) const -> ButtonState;

            auto getMouse() const -> const MouseData&;

        private:
            auto _check(bool keyboard, bool mouse) const -> bool;

        private:
            struct StateStruct
            {
                bool keyboard;
                ButtonState state;
                union {
                    sf::Mouse::Button btn;
                    sf::Keyboard::Key key;
                };
            };

        private:
            MouseData _mouse;
            const sf::RenderWindow* _window;
            bool _consumedKeyboard;
            bool _consumedMouse;
            std::vector<StateStruct> _states;
    };
}

#endif
<file_sep>/src/gamelib/core/input/InputSystem.cpp
#include "gamelib/core/input/InputSystem.hpp"
#include "gamelib/utils/conversions.hpp"
#include "imgui.h"

namespace gamelib
{
    InputSystem::InputSystem() :
        _window(nullptr)
    { }

    InputSystem::InputSystem(const sf::RenderWindow& win) :
        _window(&win)
    { }

    void InputSystem::setWindow(const sf::RenderWindow& win)
    {
        _window = &win;
    }

    void InputSystem::beginFrame()
    {
        _states.clear();
        _mouse.wheel = 0;
        _mouse.moved = false;
        _mouse.world = convert(_window->mapPixelToCoords(sf::Mouse::getPosition(*_window))).asPoint();
        _consumedMouse = _consumedKeyboard = false;
    }

    void InputSystem::process(const sf::Event& ev)
    {
        if (ev.type == sf::Event::KeyPressed ||
            ev.type == sf::Event::KeyReleased ||
            ev.type == sf::Event::MouseButtonPressed ||
            ev.type == sf::Event::MouseButtonReleased)
        {
            _states.emplace_back();
            auto& state = _states.back();

            switch (ev.type)
            {
                case sf::Event::KeyPressed:
                    state.keyboard = true;
                    state.key = ev.key.code;
                    state.state = Pressed;
                    break;

                case sf::Event::KeyReleased:
                    state.keyboard = true;
                    state.key = ev.key.code;
                    state.state = Released;
                    break;

                case sf::Event::MouseButtonPressed:
                    state.keyboard = false;
                    state.btn = ev.mouseButton.button;
                    state.state = Pressed;
                    break;

                case sf::Event::MouseButtonReleased:
                    state.keyboard = false;
                    state.btn = ev.mouseButton.button;
                    state.state = Released;
                    break;

                default: break; // removes switch warning
            }
        }
        else
        {
            if (ev.type == sf::Event::MouseMoved)
            {
                auto m = sf::Mouse::getPosition(*_window);
                _mouse.desktop = convert(sf::Mouse::getPosition()).asPoint();
                _mouse.win = convert(m).asPoint();
                _mouse.moved = true;
            }
            else if (ev.type == sf::Event::MouseWheelMoved)
                _mouse.wheel = ev.mouseWheel.delta;
        }
    }


    void InputSystem::markConsumed(bool keyboard, bool mouse)
    {
        if (keyboard)
            _consumedKeyboard = true;
        if (mouse)
            _consumedMouse = true;
    }

    bool InputSystem::isKeyboardConsumed() const
    {
        return _consumedKeyboard || ImGui::GetIO().WantCaptureKeyboard;
    }

    bool InputSystem::isMouseConsumed() const
    {
        return _consumedMouse || ImGui::GetIO().WantCaptureMouse;
    }


    bool InputSystem::isKeyPressed(sf::Keyboard::Key key) const
    {
        return isKey(key, Pressed);
    }

    bool InputSystem::isKeyReleased(sf::Keyboard::Key key) const
    {
        return isKey(key, Released);
    }

    bool InputSystem::isKeyDown(sf::Keyboard::Key key) const
    {
        return isKey(key, Down);
    }


    bool InputSystem::isMousePressed(sf::Mouse::Button btn) const
    {
        return isMouse(btn, Pressed);
    }

    bool InputSystem::isMouseReleased(sf::Mouse::Button btn) const
    {
        return isMouse(btn, Released);
    }

    bool InputSystem::isMouseDown(sf::Mouse::Button btn) const
    {
        return isMouse(btn, Down);
    }

    bool InputSystem::isKey(sf::Keyboard::Key key, ButtonState state) const
    {
        return getKeyState(key) == state;
    }

    bool InputSystem::isMouse(sf::Mouse::Button btn, ButtonState state) const
    {
        return getMouseState(btn) == state;
    }


    InputSystem::ButtonState InputSystem::getKeyState(sf::Keyboard::Key key) const
    {
        if (!_check(true, false))
            return None;

        for (auto& i : _states)
            if (i.keyboard && i.key == key)
                return i.state;

        return sf::Keyboard::isKeyPressed(key) ? Down : None;
    }

    InputSystem::ButtonState InputSystem::getMouseState(sf::Mouse::Button btn) const
    {
        if (!_check(false, true))
            return None;

        for (auto& i : _states)
            if (!i.keyboard && i.btn == btn)
                return i.state;

        return sf::Mouse::isButtonPressed(btn) ? Down : None;
    }

    const InputSystem::MouseData& InputSystem::getMouse() const
    {
        return _mouse;
    }

    bool InputSystem::_check(bool keyboard, bool mouse) const
    {
        if ((keyboard && isKeyboardConsumed()) || (mouse && isMouseConsumed()))
            return false;
        return _window->hasFocus();
    }
}
