From 41626328c966cc477feb0621d75f6d4f1316041a Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sat, 19 Mar 2016 06:42:10 +1100 Subject: [PATCH] Checked out common/* --- common/debugging/makefile | 28 +++ common/debugging/timer.cpp | 45 ++++ common/debugging/timer.hpp | 51 ++++ common/frameworks/network/makefile | 29 +++ common/frameworks/scenes/application.cpp | 188 +++++++++++++++ common/frameworks/scenes/application.hpp | 54 +++++ common/frameworks/scenes/base_scene.cpp | 105 ++++++++ common/frameworks/scenes/base_scene.hpp | 61 +++++ common/frameworks/scenes/example_scene.cpp | 83 +++++++ common/frameworks/scenes/example_scene.hpp | 46 ++++ common/frameworks/scenes/main.cpp | 43 ++++ common/frameworks/scenes/makefile | 56 +++++ common/frameworks/scenes/scene_signal.hpp | 32 +++ common/gameplay/character_defines.hpp | 39 +++ common/gameplay/makefile | 28 +++ common/graphics/button.cpp | 167 +++++++++++++ common/graphics/button.hpp | 68 ++++++ common/graphics/image.cpp | 211 +++++++++++++++++ common/graphics/image.hpp | 73 ++++++ common/graphics/makefile | 28 +++ common/graphics/sprite_sheet.cpp | 186 +++++++++++++++ common/graphics/sprite_sheet.hpp | 70 ++++++ common/graphics/text_box.cpp | 56 +++++ common/graphics/text_box.hpp | 45 ++++ common/graphics/text_line.cpp | 70 ++++++ common/graphics/text_line.hpp | 45 ++++ common/makefile | 28 +++ common/map/makefile | 28 +++ common/map/region.cpp | 82 +++++++ common/map/region.hpp | 62 +++++ common/map/region_api.cpp | 99 ++++++++ common/map/region_api.hpp | 27 +++ common/map/region_pager_api.cpp | 172 ++++++++++++++ common/map/region_pager_api.hpp | 27 +++ common/map/region_pager_base.cpp | 111 +++++++++ common/map/region_pager_base.hpp | 58 +++++ common/map/region_pager_lua.cpp | 208 ++++++++++++++++ common/map/region_pager_lua.hpp | 68 ++++++ common/map/tile_sheet.cpp | 124 ++++++++++ common/map/tile_sheet.hpp | 67 ++++++ common/network/makefile | 29 +++ .../network/packet_types/character_packet.cpp | 80 +++++++ .../network/packet_types/character_packet.hpp | 46 ++++ common/network/packet_types/client_packet.cpp | 40 ++++ common/network/packet_types/client_packet.hpp | 34 +++ common/network/packet_types/makefile | 28 +++ .../network/packet_types/monster_packet.cpp | 70 ++++++ .../network/packet_types/monster_packet.hpp | 43 ++++ common/network/packet_types/region_packet.cpp | 79 ++++++ common/network/packet_types/region_packet.hpp | 45 ++++ .../packet_types/serial_packet_base.cpp | 24 ++ .../packet_types/serial_packet_base.hpp | 36 +++ common/network/packet_types/server_packet.cpp | 42 ++++ common/network/packet_types/server_packet.hpp | 34 +++ common/network/packet_types/text_packet.cpp | 52 ++++ common/network/packet_types/text_packet.hpp | 37 +++ common/network/serial_packet.hpp | 63 +++++ common/network/serial_packet_type.hpp | 184 ++++++++++++++ common/network/serial_utility.cpp | 105 ++++++++ common/network/serial_utility.hpp | 34 +++ common/network/udp_network_utility.cpp | 224 ++++++++++++++++++ common/network/udp_network_utility.hpp | 74 ++++++ common/utilities/bounding_box.hpp | 75 ++++++ common/utilities/config_utility.cpp | 188 +++++++++++++++ common/utilities/config_utility.hpp | 52 ++++ common/utilities/frame_rate.hpp | 50 ++++ common/utilities/ip_operators.cpp | 30 +++ common/utilities/ip_operators.hpp | 28 +++ common/utilities/makefile | 28 +++ common/utilities/singleton.hpp | 60 +++++ common/utilities/vector2.hpp | 111 +++++++++ 71 files changed, 5093 insertions(+) create mode 100644 common/debugging/makefile create mode 100644 common/debugging/timer.cpp create mode 100644 common/debugging/timer.hpp create mode 100644 common/frameworks/network/makefile create mode 100644 common/frameworks/scenes/application.cpp create mode 100644 common/frameworks/scenes/application.hpp create mode 100644 common/frameworks/scenes/base_scene.cpp create mode 100644 common/frameworks/scenes/base_scene.hpp create mode 100644 common/frameworks/scenes/example_scene.cpp create mode 100644 common/frameworks/scenes/example_scene.hpp create mode 100644 common/frameworks/scenes/main.cpp create mode 100644 common/frameworks/scenes/makefile create mode 100644 common/frameworks/scenes/scene_signal.hpp create mode 100644 common/gameplay/character_defines.hpp create mode 100644 common/gameplay/makefile create mode 100644 common/graphics/button.cpp create mode 100644 common/graphics/button.hpp create mode 100644 common/graphics/image.cpp create mode 100644 common/graphics/image.hpp create mode 100644 common/graphics/makefile create mode 100644 common/graphics/sprite_sheet.cpp create mode 100644 common/graphics/sprite_sheet.hpp create mode 100644 common/graphics/text_box.cpp create mode 100644 common/graphics/text_box.hpp create mode 100644 common/graphics/text_line.cpp create mode 100644 common/graphics/text_line.hpp create mode 100644 common/makefile create mode 100644 common/map/makefile create mode 100644 common/map/region.cpp create mode 100644 common/map/region.hpp create mode 100644 common/map/region_api.cpp create mode 100644 common/map/region_api.hpp create mode 100644 common/map/region_pager_api.cpp create mode 100644 common/map/region_pager_api.hpp create mode 100644 common/map/region_pager_base.cpp create mode 100644 common/map/region_pager_base.hpp create mode 100644 common/map/region_pager_lua.cpp create mode 100644 common/map/region_pager_lua.hpp create mode 100644 common/map/tile_sheet.cpp create mode 100644 common/map/tile_sheet.hpp create mode 100644 common/network/makefile create mode 100644 common/network/packet_types/character_packet.cpp create mode 100644 common/network/packet_types/character_packet.hpp create mode 100644 common/network/packet_types/client_packet.cpp create mode 100644 common/network/packet_types/client_packet.hpp create mode 100644 common/network/packet_types/makefile create mode 100644 common/network/packet_types/monster_packet.cpp create mode 100644 common/network/packet_types/monster_packet.hpp create mode 100644 common/network/packet_types/region_packet.cpp create mode 100644 common/network/packet_types/region_packet.hpp create mode 100644 common/network/packet_types/serial_packet_base.cpp create mode 100644 common/network/packet_types/serial_packet_base.hpp create mode 100644 common/network/packet_types/server_packet.cpp create mode 100644 common/network/packet_types/server_packet.hpp create mode 100644 common/network/packet_types/text_packet.cpp create mode 100644 common/network/packet_types/text_packet.hpp create mode 100644 common/network/serial_packet.hpp create mode 100644 common/network/serial_packet_type.hpp create mode 100644 common/network/serial_utility.cpp create mode 100644 common/network/serial_utility.hpp create mode 100644 common/network/udp_network_utility.cpp create mode 100644 common/network/udp_network_utility.hpp create mode 100644 common/utilities/bounding_box.hpp create mode 100644 common/utilities/config_utility.cpp create mode 100644 common/utilities/config_utility.hpp create mode 100644 common/utilities/frame_rate.hpp create mode 100644 common/utilities/ip_operators.cpp create mode 100644 common/utilities/ip_operators.hpp create mode 100644 common/utilities/makefile create mode 100644 common/utilities/singleton.hpp create mode 100644 common/utilities/vector2.hpp diff --git a/common/debugging/makefile b/common/debugging/makefile new file mode 100644 index 0000000..e6bcb85 --- /dev/null +++ b/common/debugging/makefile @@ -0,0 +1,28 @@ +#config +INCLUDES+=. +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/debugging/timer.cpp b/common/debugging/timer.cpp new file mode 100644 index 0000000..b99ee10 --- /dev/null +++ b/common/debugging/timer.cpp @@ -0,0 +1,45 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "timer.hpp" + +Timer::Timer(): start(Timer::Clock::now()) { + // +} + +Timer::Timer(std::string s): name(s), start(Timer::Clock::now()) { + // +} + +void Timer::Start() { + start = Clock::now(); +} + +void Timer::Stop() { + timeSpan = Clock::now() - start; +} + +std::ostream& operator<<(std::ostream& os, Timer& t) { + os << t.GetName() << ": "; + os << std::chrono::duration_cast(t.GetTime()).count(); + os << "us"; + return os; +} diff --git a/common/debugging/timer.hpp b/common/debugging/timer.hpp new file mode 100644 index 0000000..d7e97f3 --- /dev/null +++ b/common/debugging/timer.hpp @@ -0,0 +1,51 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include +#include +#include + +class Timer { +public: + typedef std::chrono::high_resolution_clock Clock; + + Timer(); + Timer(std::string s); + ~Timer() = default; + + void Start(); + void Stop(); + + //accessors and mutators + Clock::duration GetTime() { return timeSpan; } + + std::string SetName(std::string s) { return name = s; } + std::string GetName() { return name; } + +private: + std::string name; + Clock::time_point start; + Clock::duration timeSpan; +}; + +std::ostream& operator<<(std::ostream& os, Timer& t); diff --git a/common/frameworks/network/makefile b/common/frameworks/network/makefile new file mode 100644 index 0000000..3bcac3d --- /dev/null +++ b/common/frameworks/network/makefile @@ -0,0 +1,29 @@ +#config +INCLUDES+=. packet_types ../gameplay ../map ../utilities +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + $(MAKE) -C packet_types + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/frameworks/scenes/application.cpp b/common/frameworks/scenes/application.cpp new file mode 100644 index 0000000..0b68fdd --- /dev/null +++ b/common/frameworks/scenes/application.cpp @@ -0,0 +1,188 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "application.hpp" + +#include +#include +#include + +void Application::Init(int argc, char* argv[]) { + //create and check the window + window = SDL_CreateWindow( + "Example Caption", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + screenWidth, + screenHeight, + SDL_WINDOW_RESIZABLE); + + if (!window) { + std::ostringstream msg; + msg << "Failed to create the window: " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + + //create and check the renderer + renderer = SDL_CreateRenderer(window, -1, 0); + + if (!renderer) { + std::ostringstream msg; + msg << "Failed to create the renderer: " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + + //screen scaling + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); + SDL_RenderSetLogicalSize(renderer, screenWidth, screenHeight); + + //set the hook for the renderer + BaseScene::SetRenderer(renderer); +} + +void Application::Proc() { + //load the first scene + ProcessSceneSignal(SceneSignal::FIRST); + + //fixed frame rate + typedef std::chrono::steady_clock Clock; + + Clock::time_point simTime = Clock::now(); + Clock::time_point realTime; + constexpr std::chrono::duration frameDelay(16); //~60FPS + + //the game loop continues until the scenes signal QUIT + while(activeScene->GetSceneSignal() != SceneSignal::QUIT) { + //switch scenes if necessary + if(activeScene->GetSceneSignal() != SceneSignal::CONTINUE) { + ProcessSceneSignal(activeScene->GetSceneSignal()); + continue; + } + + //update the current time + realTime = Clock::now(); + + //simulate the game or give the machine a break + if (simTime < realTime) { + while(simTime < realTime) { + //call the user defined functions + activeScene->FrameStart(); + ProcessEvents(); + activeScene->Update(); + activeScene->FrameEnd(); + + //step to the next frame + simTime += frameDelay; + } + } + else { + SDL_Delay(1); + } + + SDL_RenderClear(renderer); + activeScene->RenderFrame(renderer); + SDL_RenderPresent(renderer); + } + + //cleanup + ClearScene(); +} + +void Application::Quit() { + //clean up after the program + BaseScene::SetRenderer(nullptr); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); +} + +//------------------------- +//Scene management +//------------------------- + +void Application::ProcessEvents() { + SDL_Event event; + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_QUIT: + activeScene->QuitEvent(); + break; + + case SDL_MOUSEMOTION: + activeScene->MouseMotion(event.motion); + break; + + case SDL_MOUSEBUTTONDOWN: + activeScene->MouseButtonDown(event.button); + break; + + case SDL_MOUSEBUTTONUP: + activeScene->MouseButtonUp(event.button); + break; + + case SDL_MOUSEWHEEL: + activeScene->MouseWheel(event.wheel); + break; + + case SDL_KEYDOWN: + activeScene->KeyDown(event.key); + break; + + case SDL_KEYUP: + activeScene->KeyUp(event.key); + break; + + //TODO: joystick and controller events + + //window events are handled internally + case SDL_WINDOWEVENT: + switch(event.window.event) { + case SDL_WINDOWEVENT_RESIZED: + SDL_RenderSetLogicalSize(renderer, event.window.data1, event.window.data2); + break; + } + break; + } + } +} + +//Add the custom scene headers here +#include "example_scene.hpp" + +void Application::ProcessSceneSignal(SceneSignal signal) { + ClearScene(); + + switch(signal) { + case SceneSignal::FIRST: + case SceneSignal::EXAMPLE_SCENE: + activeScene = new ExampleScene(); + break; + default: { + std::ostringstream msg; + msg << "Failed to recognize the scene signal: " << signal; + throw(std::logic_error(msg.str())); + } + } +} + +void Application::ClearScene() { + delete activeScene; + activeScene = nullptr; +} \ No newline at end of file diff --git a/common/frameworks/scenes/application.hpp b/common/frameworks/scenes/application.hpp new file mode 100644 index 0000000..c927734 --- /dev/null +++ b/common/frameworks/scenes/application.hpp @@ -0,0 +1,54 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "base_scene.hpp" +#include "scene_signal.hpp" + +#include "SDL2/SDL.h" + +//TODO: do something with these +constexpr int screenWidth = 800; +constexpr int screenHeight = 600; + +//DOCS: The Application class handles scene switching, utilizing only one window +class Application { +public: + Application() = default; + ~Application() = default; + + void Init(int argc, char* argv[]); + void Proc(); + void Quit(); + +private: + //scene management + void ProcessEvents(); + void ProcessSceneSignal(SceneSignal); + void ClearScene(); + + BaseScene* activeScene = nullptr; + + //TODO: build a "window" class? + SDL_Window* window = nullptr; + SDL_Renderer* renderer = nullptr; +}; \ No newline at end of file diff --git a/common/frameworks/scenes/base_scene.cpp b/common/frameworks/scenes/base_scene.cpp new file mode 100644 index 0000000..f637710 --- /dev/null +++ b/common/frameworks/scenes/base_scene.cpp @@ -0,0 +1,105 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "base_scene.hpp" + +SDL_Renderer* BaseScene::rendererHandle = nullptr; + +BaseScene::BaseScene() { + //EMPTY +} + +BaseScene::~BaseScene() { + //EMPTY +} + +void BaseScene::RenderFrame(SDL_Renderer* renderer) { + //EMPTY +} + +void BaseScene::SetRenderer(SDL_Renderer* r) { + rendererHandle = r; +} + +SDL_Renderer* BaseScene::GetRenderer() { + return rendererHandle; +} + +void BaseScene::SetSceneSignal(SceneSignal signal) { + sceneSignal = signal; +} + +SceneSignal BaseScene::GetSceneSignal() { + return sceneSignal; +} + +//------------------------- +//frame phases +//------------------------- + +void BaseScene::FrameStart() { + //EMPTY +} + +void BaseScene::Update() { + //EMPTY +} + +void BaseScene::FrameEnd() { + //EMPTY +} + +//------------------------- +//input events +//------------------------- + +void BaseScene::QuitEvent() { + sceneSignal = SceneSignal::QUIT; +} + +void BaseScene::MouseMotion(SDL_MouseMotionEvent const& event) { + //EMPTY +} + +void BaseScene::MouseButtonDown(SDL_MouseButtonEvent const& event) { + //EMPTY +} + +void BaseScene::MouseButtonUp(SDL_MouseButtonEvent const& event) { + //EMPTY +} + +void BaseScene::MouseWheel(SDL_MouseWheelEvent const& event) { + //EMPTY +} + +void BaseScene::KeyDown(SDL_KeyboardEvent const& event) { + //preference as a default + switch(event.keysym.sym) { + case SDLK_ESCAPE: + QuitEvent(); + break; + } +} + +void BaseScene::KeyUp(SDL_KeyboardEvent const& event) { + //EMPTY +} diff --git a/common/frameworks/scenes/base_scene.hpp b/common/frameworks/scenes/base_scene.hpp new file mode 100644 index 0000000..96a4085 --- /dev/null +++ b/common/frameworks/scenes/base_scene.hpp @@ -0,0 +1,61 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "scene_signal.hpp" + +#include "SDL2/SDL.h" + +class BaseScene { +public: + BaseScene(); + virtual ~BaseScene(); + + virtual void RenderFrame(SDL_Renderer*); + static void SetRenderer(SDL_Renderer*); + SceneSignal GetSceneSignal(); + + //frame phases + virtual void FrameStart(); + virtual void Update(); + virtual void FrameEnd(); + + //input events + virtual void QuitEvent(); + virtual void MouseMotion(SDL_MouseMotionEvent const& event); + virtual void MouseButtonDown(SDL_MouseButtonEvent const& event); + virtual void MouseButtonUp(SDL_MouseButtonEvent const& event); + virtual void MouseWheel(SDL_MouseWheelEvent const& event); + virtual void KeyDown(SDL_KeyboardEvent const& event); + virtual void KeyUp(SDL_KeyboardEvent const& event); + + //TODO: joystick and controller events + +protected: + //control + static SDL_Renderer* GetRenderer(); + void SetSceneSignal(SceneSignal); + +private: + static SDL_Renderer* rendererHandle; + SceneSignal sceneSignal = SceneSignal::CONTINUE; +}; \ No newline at end of file diff --git a/common/frameworks/scenes/example_scene.cpp b/common/frameworks/scenes/example_scene.cpp new file mode 100644 index 0000000..33be9ab --- /dev/null +++ b/common/frameworks/scenes/example_scene.cpp @@ -0,0 +1,83 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "example_scene.hpp" + +ExampleScene::ExampleScene() { + // +} + +ExampleScene::~ExampleScene() { + // +} + +//------------------------- +//frame phases +//------------------------- + +void ExampleScene::FrameStart() { + // +} + +void ExampleScene::Update() { + // +} + +void ExampleScene::FrameEnd() { + // +} + +void ExampleScene::RenderFrame(SDL_Renderer* renderer) { + // +} + +//------------------------- +//input events +//------------------------- + +void ExampleScene::MouseMotion(SDL_MouseMotionEvent const& event) { + // +} + +void ExampleScene::MouseButtonDown(SDL_MouseButtonEvent const& event) { + // +} + +void ExampleScene::MouseButtonUp(SDL_MouseButtonEvent const& event) { + // +} + +void ExampleScene::MouseWheel(SDL_MouseWheelEvent const& event) { + // +} + +void ExampleScene::KeyDown(SDL_KeyboardEvent const& event) { + //preference as a default + switch(event.keysym.sym) { + case SDLK_ESCAPE: + QuitEvent(); + break; + } +} + +void ExampleScene::KeyUp(SDL_KeyboardEvent const& event) { + // +} diff --git a/common/frameworks/scenes/example_scene.hpp b/common/frameworks/scenes/example_scene.hpp new file mode 100644 index 0000000..2f18af1 --- /dev/null +++ b/common/frameworks/scenes/example_scene.hpp @@ -0,0 +1,46 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "base_scene.hpp" + +class ExampleScene : public BaseScene { +public: + ExampleScene(); + ~ExampleScene(); + + void RenderFrame(SDL_Renderer* renderer) override; + +private: + //frame phases + void FrameStart() override; + void Update() override; + void FrameEnd() override; + + //input events + void MouseMotion(SDL_MouseMotionEvent const& event) override; + void MouseButtonDown(SDL_MouseButtonEvent const& event) override; + void MouseButtonUp(SDL_MouseButtonEvent const& event) override; + void MouseWheel(SDL_MouseWheelEvent const& event) override; + void KeyDown(SDL_KeyboardEvent const& event) override; + void KeyUp(SDL_KeyboardEvent const& event) override; +}; diff --git a/common/frameworks/scenes/main.cpp b/common/frameworks/scenes/main.cpp new file mode 100644 index 0000000..90f7d67 --- /dev/null +++ b/common/frameworks/scenes/main.cpp @@ -0,0 +1,43 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "application.hpp" + +#include "SDL2/SDL.h" + +#include +#include + +int main(int argc, char** argv) { + std::cout << "Beginning " << argv[0] << std::endl; + try { + Application app; + app.Init(argc, argv); + app.Proc(); + app.Quit(); + } + catch(std::exception& e) { + std::cerr << "Fatal Error: " << e.what() << std::endl; + return 1; + } + std::cout << "Clean exit from " << argv[0] << std::endl; + return 0; +} \ No newline at end of file diff --git a/common/frameworks/scenes/makefile b/common/frameworks/scenes/makefile new file mode 100644 index 0000000..a8f0ea0 --- /dev/null +++ b/common/frameworks/scenes/makefile @@ -0,0 +1,56 @@ +#include directories +INCLUDES+=. + +#libraries +#the order of the $(LIBS) is important, at least for MinGW +LIBS+= +ifeq ($(OS),Windows_NT) + LIBS+=-lmingw32 +endif +LIBS+=-lSDL2main -lSDL2 + +#flags +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) +ifeq ($(shell uname), Linux) + #read data about the current install + CXXFLAGS+=$(shell sdl-config --cflags --static-libs) +endif + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#output +OUTDIR=out +OUT=$(addprefix $(OUTDIR)/,scenes) + +#targets +all: $(OBJ) $(OUT) + $(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +clean: +ifeq ($(OS),Windows_NT) + $(RM) *.o *.a *.exe +else ifeq ($(shell uname), Linux) + find . -type f -name '*.o' -exec rm -f -r -v {} \; + find . -type f -name '*.a' -exec rm -f -r -v {} \; + rm -f -v $(OUT) +endif + +rebuild: clean all diff --git a/common/frameworks/scenes/scene_signal.hpp b/common/frameworks/scenes/scene_signal.hpp new file mode 100644 index 0000000..49e0bcb --- /dev/null +++ b/common/frameworks/scenes/scene_signal.hpp @@ -0,0 +1,32 @@ +/* Copyright: (c) Kayne Ruse 2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +enum SceneSignal { + //reserved members for internal use + QUIT = -1, + CONTINUE = 0, + FIRST = 1, + + //custom scenes + EXAMPLE_SCENE +}; \ No newline at end of file diff --git a/common/gameplay/character_defines.hpp b/common/gameplay/character_defines.hpp new file mode 100644 index 0000000..a975a3e --- /dev/null +++ b/common/gameplay/character_defines.hpp @@ -0,0 +1,39 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include + +//the speeds that the characters move +constexpr double CHARACTER_WALKING_SPEED = 2.24; +constexpr double CHARACTER_WALKING_MOD = 1.0/sqrt(2.0); +constexpr double CHARACTER_WALKING_NEGATIVE_MOD = 1.0 - CHARACTER_WALKING_MOD; + +//the bounds for the character objects, mapped to the default sprites +constexpr int CHARACTER_BOUNDS_X = 0; +constexpr int CHARACTER_BOUNDS_Y = 16; +constexpr int CHARACTER_BOUNDS_WIDTH = 32; +constexpr int CHARACTER_BOUNDS_HEIGHT = 32; + +//the character's sprite format +constexpr int CHARACTER_CELLS_X = 4; +constexpr int CHARACTER_CELLS_Y = 4; diff --git a/common/gameplay/makefile b/common/gameplay/makefile new file mode 100644 index 0000000..e6bcb85 --- /dev/null +++ b/common/gameplay/makefile @@ -0,0 +1,28 @@ +#config +INCLUDES+=. +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/graphics/button.cpp b/common/graphics/button.cpp new file mode 100644 index 0000000..49c8502 --- /dev/null +++ b/common/graphics/button.cpp @@ -0,0 +1,167 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "button.hpp" + +#include + +void Button::DrawTo(SDL_Renderer* renderer) { + image.SetClipY(image.GetClipH() * state); + image.DrawTo(renderer, posX, posY); +} + +void Button::SetBackgroundTexture(SDL_Renderer* renderer, SDL_Texture* texture) { + //copy the given texture + image.Free(); + + //a null texture can simply free the image + if (!texture) { + return; + } + + //get the w & h, & create + int w = 0, h = 0; + SDL_QueryTexture(texture, nullptr, nullptr, &w, &h); + image.Create(renderer, w, h); + + //copy + SDL_SetRenderTarget(renderer, image.GetTexture()); + SDL_RenderCopy(renderer, texture, nullptr, nullptr); + SDL_SetRenderTarget(renderer, nullptr); + + //prune + image.SetClipH(image.GetClipH() / 3); +} + +void Button::SetText(SDL_Renderer* renderer, TTF_Font* font, std::string s, SDL_Color color) { + //make the surface (from SDL_ttf) + SDL_Surface* surf = TTF_RenderText_Solid(font, s.c_str(), color); + if (!surf) { + throw(std::runtime_error("Failed to create a TTF surface")); + } + + //convert to texture + SDL_Texture* text = SDL_CreateTextureFromSurface(renderer, surf); + SDL_FreeSurface(surf); + if (!text) { + throw(std::runtime_error("Failed to create a TTF texture")); + } + + //get the dimensions & rects + int x, y, w, h; + SDL_QueryTexture(text, nullptr, nullptr, &w, &h); + x = (image.GetClipW() - w) / 2; + y = (image.GetClipH() - h) / 2; + SDL_Rect src = {0, 0, w, h}; + SDL_Rect dst; + + //draw the text to the background + SDL_SetRenderTarget(renderer, image.GetTexture()); + + for (int i = 0; i < 3; i++) { + dst = {x, y + image.GetClipH() * i, w, h}; + SDL_RenderCopy(renderer, text, &src, &dst); + } + + SDL_SetRenderTarget(renderer, nullptr); + + //free the texture + SDL_DestroyTexture(text); +} + +void Button::SetX(int x) { + posX = x; +} + +void Button::SetY(int y) { + posY = y; +} + +Button::State Button::MouseMotion(SDL_MouseMotionEvent const& event) { + //if out of bounds, exit + if (!CheckBounds(event.x, event.y)) { + return state = State::IDLE; + } + + //if in bounds, check button + if (event.state & SDL_BUTTON_LMASK && state == State::PRESSED) { + //stay pressed +// state = State::PRESSED; + } + else { + state = State::HOVER; + } + + return state; +} + +Button::State Button::MouseButtonDown(SDL_MouseButtonEvent const& event) { + //if out of bounds, exit + if (!CheckBounds(event.x, event.y)) { + return state = State::IDLE; + } + + //if in bounds, check button + if (event.button == SDL_BUTTON_LEFT) { + return state = State::PRESSED; + } + + //NOTE: if not left button down, ignore + return State::HOVER; +} + +Button::State Button::MouseButtonUp(SDL_MouseButtonEvent const& event) { + //if out of bounds, exit + if (!CheckBounds(event.x, event.y)) { + return state = State::IDLE; + } + + //if not left button up, ignore + if (event.button != SDL_BUTTON_LEFT) { + return state; + } + + //if in bounds and left button up, send release signal + if (state == State::PRESSED) { + state = State::HOVER; + return State::RELEASED; + } + + return state; +} + +void Button::SetState(State s) { + state = s; +} + +Button::State Button::GetState() { + return state; +} + +bool Button::CheckBounds(int x, int y) { + //return if true (x, y) is within bounds, otherwise return false + return !( + x < posX || + y < posY || + x > posX + image.GetClipW() || + y > posY + image.GetClipH() + ); +} \ No newline at end of file diff --git a/common/graphics/button.hpp b/common/graphics/button.hpp new file mode 100644 index 0000000..e4887a8 --- /dev/null +++ b/common/graphics/button.hpp @@ -0,0 +1,68 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "image.hpp" + +#include "SDL2/SDL_ttf.h" + +#include + +constexpr SDL_Color COLOR_WHITE = {255, 255, 255, 255}; +constexpr SDL_Color COLOR_RED = {255, 0, 0, 255}; +constexpr SDL_Color COLOR_ORANGE = {255, 127, 0, 255}; +constexpr SDL_Color COLOR_BLUE = {0, 0, 255, 255}; + +class Button { +public: + enum State { + IDLE = 0, HOVER = 1, PRESSED = 2, RELEASED = 3 + }; + + //methods + Button() = default; + ~Button() = default; + + void DrawTo(SDL_Renderer*); + + //setup + void SetBackgroundTexture(SDL_Renderer*, SDL_Texture*); + void SetText(SDL_Renderer*, TTF_Font*, std::string, SDL_Color); + void SetX(int x); + void SetY(int y); + + //capture input + State MouseMotion(SDL_MouseMotionEvent const&); + State MouseButtonDown(SDL_MouseButtonEvent const&); + State MouseButtonUp(SDL_MouseButtonEvent const&); + + //states + void SetState(State); //TODO: idle, busy or disabled + State GetState(); + +protected: + bool CheckBounds(int x, int y); + + Image image; + int posX = 0, posY = 0; + State state = State::IDLE; +}; diff --git a/common/graphics/image.cpp b/common/graphics/image.cpp new file mode 100644 index 0000000..02f9bf2 --- /dev/null +++ b/common/graphics/image.cpp @@ -0,0 +1,211 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "image.hpp" + +#include "SDL2/SDL_image.h" + +#include +#include + +Image& Image::operator=(Image const& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Copy the other Image's stuff + texture = rhs.texture; + clip = rhs.clip; + local = false; +} + +Image& Image::operator=(Image&& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Steal the other Image's stuff + texture = rhs.texture; + clip = rhs.clip; + local = rhs.local; + + rhs.texture = nullptr; + rhs.clip = {0, 0, 0, 0}; + rhs.local = false; +} + +SDL_Texture* Image::Load(SDL_Renderer* renderer, std::string fname) { + Free(); + + //load the file into a surface + SDL_Surface* surface = IMG_Load(fname.c_str()); + if (!surface) { + std::ostringstream msg; + msg << "Failed to load an image file: " << fname; + msg << "; " << IMG_GetError(); + throw(std::runtime_error(msg.str())); + } + + //create a texture from this surface + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + std::ostringstream msg; + msg << "Failed to convert a newly loaded image file: " << fname; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + + //set the metadata + clip.x = 0; + clip.y = 0; + if (SDL_QueryTexture(texture, nullptr, nullptr, &clip.w, &clip.h)) { + std::ostringstream msg; + msg << "Failed to record metadata for a newly loaded image file: " << fname; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + local = true; + + //free the surface & return + SDL_FreeSurface(surface); + return texture; +} + +SDL_Texture* Image::Create(SDL_Renderer* renderer, Uint16 w, Uint16 h, SDL_Color blank) { + Free(); + + //make the texture + texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_TARGET, + w, h); + + //check + if (!texture) { + std::ostringstream msg; + msg << "Failed to create a texture; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + + //set the metadata + clip.x = 0; + clip.y = 0; + if (SDL_QueryTexture(texture, nullptr, nullptr, &clip.w, &clip.h)) { + std::ostringstream msg; + msg << "Failed to record metadata for a newly created image"; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + local = true; + + //blank (black) texture + SDL_SetRenderTarget(renderer, texture); + SDL_SetRenderDrawColor(renderer, blank.r, blank.g, blank.b, blank.a); + SDL_RenderFillRect(renderer, nullptr); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_SetRenderTarget(renderer, nullptr); + + return texture; +} + +SDL_Texture* Image::CopyTexture(SDL_Renderer* renderer, SDL_Texture* ptr) { + Free(); + int w = 0, h = 0; + + //get the info + SDL_QueryTexture(ptr, nullptr, nullptr, &w, &h); + + //create a texture of (w, h) size (also sets the metadata) + Create(renderer, w, h); + + //copy the argument texture to the local texture + SDL_SetRenderTarget(renderer, texture); + SDL_RenderCopy(renderer, ptr, nullptr, nullptr); + SDL_SetRenderTarget(renderer, nullptr); + + //return the local texture + return texture; +} + +SDL_Texture* Image::SetTexture(SDL_Texture* ptr) { + Free(); + + texture = ptr; + + //set the metadata + clip.x = 0; + clip.y = 0; + if (SDL_QueryTexture(texture, nullptr, nullptr, &clip.w, &clip.h)) { + std::ostringstream msg; + msg << "Failed to record metadata for a newly image image"; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + local = false; + + return texture; +} + +SDL_Texture* Image::GetTexture() const { + return texture; +} + +void Image::Free() { + if (local) { + SDL_DestroyTexture(texture); + local = false; + } + texture = nullptr; + clip = {0, 0, 0, 0}; +} + +void Image::DrawTo(SDL_Renderer* const renderer, Sint16 x, Sint16 y, double scaleX, double scaleY) { + if (!texture) { + throw(std::logic_error("No image texture to draw")); + } + SDL_Rect sclip = clip; + SDL_Rect dclip = {x, y, Uint16(clip.w * scaleX), Uint16(clip.h * scaleY)}; + SDL_RenderCopy(renderer, texture, &sclip, &dclip); +} + +void Image::SetAlpha(Uint8 a) { + if (SDL_SetTextureAlphaMod(texture, a)) { + std::ostringstream msg; + msg << "Failed to set alpha; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } +} + +Uint8 Image::GetAlpha() { + Uint8 ret = 0; + if (SDL_GetTextureAlphaMod(texture, &ret)) { + std::ostringstream msg; + msg << "Failed to get alpha; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + return ret; +} \ No newline at end of file diff --git a/common/graphics/image.hpp b/common/graphics/image.hpp new file mode 100644 index 0000000..f45e0b0 --- /dev/null +++ b/common/graphics/image.hpp @@ -0,0 +1,73 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "SDL2/SDL.h" + +#include + +class Image { +public: + Image() = default; + Image(Image const& rhs) { *this = rhs; } + Image(Image&& rhs) { *this = std::move(rhs); } + Image(SDL_Renderer* r, std::string fname) { Load(r, fname); } + Image(SDL_Renderer* r, Uint16 w, Uint16 h) { Create(r, w, h); } + Image(SDL_Texture* p) { SetTexture(p); } + virtual ~Image() { Free(); } + + Image& operator=(Image const&); + Image& operator=(Image&&); + + SDL_Texture* Load(SDL_Renderer* renderer, std::string fname); + SDL_Texture* Create(SDL_Renderer* renderer, Uint16 w, Uint16 h, SDL_Color blank = {0, 0, 0, 255}); + SDL_Texture* CopyTexture(SDL_Renderer* renderer, SDL_Texture* ptr); + SDL_Texture* SetTexture(SDL_Texture*); + SDL_Texture* GetTexture() const; + virtual void Free(); + + void DrawTo(SDL_Renderer* const, Sint16 x, Sint16 y, double scaleX = 1.0, double scaleY = 1.0); + + void SetAlpha(Uint8 a); + Uint8 GetAlpha(); + + //Clip handlers + SDL_Rect SetClip(SDL_Rect r) { return clip = r; } + SDL_Rect GetClip() const { return clip; } + + Sint16 SetClipX(Sint16 x) { return clip.x = x; } + Sint16 SetClipY(Sint16 y) { return clip.y = y; } + Uint16 SetClipW(Uint16 w) { return clip.w = w; } + Uint16 SetClipH(Uint16 h) { return clip.h = h; } + + Sint16 GetClipX() const { return clip.x; } + Sint16 GetClipY() const { return clip.y; } + Uint16 GetClipW() const { return clip.w; } + Uint16 GetClipH() const { return clip.h; } + + bool GetLocal() const { return local; } + +protected: + SDL_Texture* texture = nullptr; + SDL_Rect clip = {0, 0, 0, 0}; + bool local = false; +}; \ No newline at end of file diff --git a/common/graphics/makefile b/common/graphics/makefile new file mode 100644 index 0000000..e6bcb85 --- /dev/null +++ b/common/graphics/makefile @@ -0,0 +1,28 @@ +#config +INCLUDES+=. +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/graphics/sprite_sheet.cpp b/common/graphics/sprite_sheet.cpp new file mode 100644 index 0000000..3d61f62 --- /dev/null +++ b/common/graphics/sprite_sheet.cpp @@ -0,0 +1,186 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "sprite_sheet.hpp" + +#include +#include + +SpriteSheet& SpriteSheet::operator=(SpriteSheet const& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Copy the other SpriteSheet's stuff + texture = rhs.texture; + clip = rhs.clip; + local = false; + countX = rhs.countX; + countY = rhs.countY; + indexX = rhs.indexX; + indexY = rhs.indexY; + delay = rhs.delay; + tick = rhs.tick; +} + +SpriteSheet& SpriteSheet::operator=(SpriteSheet&& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Steal the other SpriteSheet's stuff + texture = rhs.texture; + clip = rhs.clip; + local = rhs.local; + countX = rhs.countX; + countY = rhs.countY; + indexX = rhs.indexX; + indexY = rhs.indexY; + delay = rhs.delay; + tick = rhs.tick; + + rhs.texture = nullptr; + rhs.clip = {0, 0, 0, 0}; + rhs.local = false; + rhs.countX = 0; + rhs.countY = 0; + rhs.indexX = 0; + rhs.indexY = 0; + rhs.delay = 0.0; + rhs.tick = 0.0; +} + +void SpriteSheet::Update(double delta) { + //if the delay has passed + if (delay && (tick += delta) >= delay) { + //if the index is out of bounds + if (++indexX >= countX) { + indexX = 0; + } + tick = 0; + } + //modify area drawn + clip.x = indexX * clip.w; + clip.y = indexY * clip.h; +} + +SDL_Texture* SpriteSheet::Load(SDL_Renderer* r, std::string fname, Uint16 cx, Uint16 cy) { + //call the base function + Image::Load(r, fname); + + //set the metadata + countX = cx; + countY = cy; + + //assume clip.x and clip.y were set to the size of the texture + //reduce the w & h to the size of one cell + clip.w = clip.w / countX; + clip.h = clip.h / countY; + + indexX = indexY = 0; + delay = tick = 0.0; + + return texture; +} + +SDL_Texture* SpriteSheet::Create(SDL_Renderer* r, Uint16 w, Uint16 h, Uint16 cx, Uint16 cy) { + //call the base function + Image::Create(r, w, h); + + //set the metadata + countX = cx; + countY = cy; + + //assume clip.x and clip.y were set to the size of the texture + //reduce the w & h to the size of one cell + clip.w = clip.w / countX; + clip.h = clip.h / countY; + + indexX = indexY = 0; + delay = tick = 0.0; + + return texture; +} + +SDL_Texture* SpriteSheet::SetTexture(SDL_Texture* ptr, Uint16 cx, Uint16 cy) { + //call the base function + Image::SetTexture(ptr); + + //set the metadata + countX = cx; + countY = cy; + + //assume clip.x and clip.y were set to the size of the texture + //reduce the w & h to the size of one cell + clip.w = clip.w / countX; + clip.h = clip.h / countY; + + indexX = indexY = 0; + delay = tick = 0.0; + + return texture; +} + +void SpriteSheet::Free() { + Image::Free(); + countX = countY = 0; + indexX = indexY = 0; + delay = tick = 0.0; +} + +Uint16 SpriteSheet::SetCountX(Uint16 i) { + indexX = 0; + return countX = i; +} + +Uint16 SpriteSheet::SetCountY(Uint16 i) { + indexY = 0; + return countY = i; +} + +Uint16 SpriteSheet::SetIndexX(Uint16 i) { + if (i > countX) { + std::ostringstream msg; + msg << "Cannot set index 'x' to " << i; + throw(std::out_of_range(msg.str())); + } + return indexX = i; +} + +Uint16 SpriteSheet::SetIndexY(Uint16 i) { + if (i > countY) { + std::ostringstream msg; + msg << "Cannot set index 'y' to " << i; + throw(std::invalid_argument(msg.str())); + } + return indexY = i; +} + +double SpriteSheet::SetDelay(double d) { + tick = 0; + return delay = d; +} \ No newline at end of file diff --git a/common/graphics/sprite_sheet.hpp b/common/graphics/sprite_sheet.hpp new file mode 100644 index 0000000..395cfe3 --- /dev/null +++ b/common/graphics/sprite_sheet.hpp @@ -0,0 +1,70 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "image.hpp" + +class SpriteSheet : public Image { +public: + SpriteSheet() = default; + SpriteSheet(SpriteSheet const& rhs) { *this = rhs; } + SpriteSheet(SpriteSheet&& rhs) { *this = std::move(rhs); } + SpriteSheet(SDL_Renderer* r, std::string fname, Uint16 cx, Uint16 cy) + { Load(r, fname, cx, cy); } + SpriteSheet(SDL_Renderer* r, Uint16 w, Uint16 h, Uint16 cx, Uint16 cy) + { Create(r, w, h, cx, cy); } + SpriteSheet(SDL_Texture* p, Uint16 cx, Uint16 cy) + { SetTexture(p, cx, cy); } + ~SpriteSheet() = default; + + SpriteSheet& operator=(SpriteSheet const&); + SpriteSheet& operator=(SpriteSheet&&); + + void Update(double delta); + + SDL_Texture* Load(SDL_Renderer*, std::string fname, Uint16 cx, Uint16 cy); + SDL_Texture* Create(SDL_Renderer*, Uint16 w, Uint16 h, Uint16 cx, Uint16 cy); + SDL_Texture* SetTexture(SDL_Texture*, Uint16 cx, Uint16 cy); + void Free() override; + + Uint16 SetCountX(Uint16); + Uint16 SetCountY(Uint16); + Uint16 SetIndexX(Uint16); + Uint16 SetIndexY(Uint16); + + Uint16 GetCountX() const { return countX; } + Uint16 GetCountY() const { return countY; } + Uint16 GetIndexX() const { return indexX; } + Uint16 GetIndexY() const { return indexY; } + + double SetDelay(double d); + double GetDelay() const { return delay; } + +private: + Uint16 countX = 0, countY = 0, indexX = 0, indexY = 0; + double delay = 0.0, tick = 0.0; + + //disable access + using Image::Load; + using Image::Create; + using Image::SetTexture; +}; \ No newline at end of file diff --git a/common/graphics/text_box.cpp b/common/graphics/text_box.cpp new file mode 100644 index 0000000..98275aa --- /dev/null +++ b/common/graphics/text_box.cpp @@ -0,0 +1,56 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "text_box.hpp" + +#include + +TextBox::TextBox() { + // +} + +TextBox::~TextBox() { + // +} + +void TextBox::DrawTo(SDL_Renderer* renderer, int posX, int posY, int pointSize) { + for (std::list::iterator it = lineList.begin(); it != lineList.end(); it++) { + it->DrawTo(renderer, posX, posY); + posY += pointSize; + } +} + +void TextBox::PushLine(SDL_Renderer* renderer, TTF_Font* font, std::string str, SDL_Color color) { + lineList.emplace_front(renderer, font, str, color); +} + +void TextBox::PopLine(int num) { + //prevent underflow + num < lineList.size() ? num : lineList.size(); + + for (int i = 0; i < num; ++i) { + lineList.pop_back(); + } +} + +void TextBox::ClearLines() { + lineList.clear(); +} diff --git a/common/graphics/text_box.hpp b/common/graphics/text_box.hpp new file mode 100644 index 0000000..89d90a6 --- /dev/null +++ b/common/graphics/text_box.hpp @@ -0,0 +1,45 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "text_line.hpp" + +#include "SDL2/SDL.h" +#include "SDL2/SDL_ttf.h" + +#include +#include + +class TextBox { +public: + TextBox(); + ~TextBox(); + + void DrawTo(SDL_Renderer*, int posX, int posY, int pointSize); + + void PushLine(SDL_Renderer*, TTF_Font*, std::string, SDL_Color color); + void PopLine(int num = 1); + void ClearLines(); + +private: + std::list lineList; +}; \ No newline at end of file diff --git a/common/graphics/text_line.cpp b/common/graphics/text_line.cpp new file mode 100644 index 0000000..8826e86 --- /dev/null +++ b/common/graphics/text_line.cpp @@ -0,0 +1,70 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "text_line.hpp" + +#include + +SDL_Texture* renderTextTexture(SDL_Renderer* renderer, TTF_Font* font, std::string str, SDL_Color color) { + //make the surface (from SDL_ttf) + SDL_Surface* surface = TTF_RenderText_Solid(font, str.c_str(), color); + if (!surface) { + throw(std::runtime_error("Failed to create a TTF surface")); + } + + //convert to texture + SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); + + //cleanup + SDL_FreeSurface(surface); + + //check + if (!texture) { + throw(std::runtime_error("Failed to create a TTF texture")); + } + + //NOTE: free the texture yourself + return texture; +} + +TextLine::TextLine() { + // +} + +TextLine::~TextLine() { + ClearText(); +} + +void TextLine::DrawTo(SDL_Renderer* renderer, int posX, int posY) { + SDL_Rect dclip = {posX, posY, 0, 0}; + SDL_QueryTexture(texture, nullptr, nullptr, &dclip.w, &dclip.h); + SDL_RenderCopy(renderer, texture, nullptr, &dclip); +} + +void TextLine::SetText(SDL_Renderer* renderer, TTF_Font* font, std::string str, SDL_Color color) { + //just use the above global function + SDL_DestroyTexture(texture); + texture = renderTextTexture(renderer, font, str, color); +} + +void TextLine::ClearText() { + SDL_DestroyTexture(texture); +} \ No newline at end of file diff --git a/common/graphics/text_line.hpp b/common/graphics/text_line.hpp new file mode 100644 index 0000000..4c4c3da --- /dev/null +++ b/common/graphics/text_line.hpp @@ -0,0 +1,45 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "SDL2/SDL.h" +#include "SDL2/SDL_ttf.h" + +#include + +SDL_Texture* renderTextTexture(SDL_Renderer*, TTF_Font*, std::string, SDL_Color color); + +class TextLine { +public: + TextLine(); + TextLine(SDL_Renderer* r, TTF_Font* f, std::string s, SDL_Color c) + { SetText(r, f, s, c); } + virtual ~TextLine(); + + void DrawTo(SDL_Renderer*, int posX, int posY); + + void SetText(SDL_Renderer*, TTF_Font*, std::string, SDL_Color color); + void ClearText(); + +protected: + SDL_Texture* texture = nullptr; +}; \ No newline at end of file diff --git a/common/makefile b/common/makefile new file mode 100644 index 0000000..12d7825 --- /dev/null +++ b/common/makefile @@ -0,0 +1,28 @@ +#output +export OUTDIR=.. +export OUT=$(addprefix $(OUTDIR)/,libcommon.a) + +all: $(OUTDIR) + $(MAKE) -C debugging + $(MAKE) -C gameplay + $(MAKE) -C graphics + $(MAKE) -C map + $(MAKE) -C network + $(MAKE) -C utilities + +debug: export CXXFLAGS+=-g +debug: clean all + +$(OUTDIR): + mkdir $(OUTDIR) + +clean: +ifeq ($(OS),Windows_NT) + $(RM) *.o *.a *.exe +else ifeq ($(shell uname), Linux) + find . -type f -name *.o -exec rm -f -r -v {} \; + find . -type f -name *.a -exec rm -f -r -v {} \; + rm -f -v out/client out/server +endif + +rebuild: clean all diff --git a/common/map/makefile b/common/map/makefile new file mode 100644 index 0000000..7e6b897 --- /dev/null +++ b/common/map/makefile @@ -0,0 +1,28 @@ +#config +INCLUDES+=. ../graphics +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/map/region.cpp b/common/map/region.cpp new file mode 100644 index 0000000..1815d36 --- /dev/null +++ b/common/map/region.cpp @@ -0,0 +1,82 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region.hpp" + +#include +#include +#include + +int snapToBase(int base, int x) { + return floor((double)x / base) * base; +} + +Region::Region(int argX, int argY): x(argX), y(argY) { + if (x != snapToBase(REGION_WIDTH, x) || y != snapToBase(REGION_HEIGHT, y)) { + throw(std::invalid_argument("Region location is off grid")); + } + memset(tiles, 0, REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH*sizeof(type_t)); +} + +Region::Region(Region const& rhs): x(rhs.x), y(rhs.y) { + memcpy(tiles, rhs.tiles, REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH*sizeof(type_t)); + solid = rhs.solid; +} + +Region::type_t Region::SetTile(int x, int y, int z, type_t v) { + if (x < 0 || y < 0 || z < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT || z >= REGION_DEPTH) { + throw(std::out_of_range("Region::SetTile() argument out of range")); + } + return tiles[x][y][z] = v; +} + +Region::type_t Region::GetTile(int x, int y, int z) { + if (x < 0 || y < 0 || z < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT || z >= REGION_DEPTH) { + throw(std::out_of_range("Region::GetTile() argument out of range")); + } + return tiles[x][y][z]; +} + +bool Region::SetSolid(int x, int y, bool b) { + if (x < 0 || y < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT) { + throw(std::out_of_range("Region::SetSolid() argument out of range")); + } + return solid[x * REGION_WIDTH + y] = b; +} + +bool Region::GetSolid(int x, int y) { + if (x < 0 || y < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT) { + throw(std::out_of_range("Region::GetSolid() argument out of range")); + } + return solid[x * REGION_WIDTH + y]; +} + +int Region::GetX() const { + return x; +} + +int Region::GetY() const { + return y; +} + +std::bitset* Region::GetSolidBitset() { + return &solid; +} \ No newline at end of file diff --git a/common/map/region.hpp b/common/map/region.hpp new file mode 100644 index 0000000..da919cb --- /dev/null +++ b/common/map/region.hpp @@ -0,0 +1,62 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include + +//the region's storage format +constexpr int REGION_WIDTH = 20; +constexpr int REGION_HEIGHT = 20; +constexpr int REGION_DEPTH = 3; + +//utility function +int snapToBase(int base, int x); + +class Region { +public: + typedef unsigned char type_t; + + Region() = delete; + Region(int x, int y); + Region(Region const&); + ~Region() = default; + + type_t SetTile(int x, int y, int z, type_t v); + type_t GetTile(int x, int y, int z); + + bool SetSolid(int x, int y, bool b); + bool GetSolid(int x, int y); + + //accessors + int GetX() const; + int GetY() const; + + std::bitset* GetSolidBitset(); +private: + friend class TileSheet; + + const int x; + const int y; + + type_t tiles[REGION_WIDTH][REGION_HEIGHT][REGION_DEPTH]; + std::bitset solid; +}; diff --git a/common/map/region_api.cpp b/common/map/region_api.cpp new file mode 100644 index 0000000..1c0f848 --- /dev/null +++ b/common/map/region_api.cpp @@ -0,0 +1,99 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region_api.hpp" + +#include "region.hpp" + +static int setTile(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + int ret = region->SetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1, lua_tointeger(L, 5)); + lua_pushinteger(L, ret); + return 1; +} + +static int getTile(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + int ret = region->GetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1); + lua_pushinteger(L, ret); + return 1; +} + +static int setSolid(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = region->SetSolid(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_toboolean(L, 4)); + lua_pushboolean(L, ret); + return 1; +} + +static int getSolid(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = region->GetSolid(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1); + lua_pushboolean(L, ret); + return 1; +} + +static int getX(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + lua_pushinteger(L, region->GetX()); + return 1; +} + +static int getY(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + lua_pushinteger(L, region->GetY()); + return 1; +} + +static int getWidth(lua_State* L) { + lua_pushinteger(L, REGION_WIDTH); + return 1; +} + +static int getHeight(lua_State* L) { + lua_pushinteger(L, REGION_HEIGHT); + return 1; +} + +static int getDepth(lua_State* L) { + lua_pushinteger(L, REGION_DEPTH); + return 1; +} + +static const luaL_Reg regionLib[] = { + {"SetTile",setTile}, + {"GetTile",getTile}, + {"SetSolid",setSolid}, + {"GetSolid",getSolid}, + {"GetX",getX}, + {"GetY",getY}, + + //the global macros + {"GetWidth",getWidth}, + {"GetHeight",getHeight}, + {"GetDepth",getDepth}, + {nullptr, nullptr} +}; + +LUAMOD_API int openRegionAPI(lua_State* L) { + luaL_newlib(L, regionLib); + return 1; +} \ No newline at end of file diff --git a/common/map/region_api.hpp b/common/map/region_api.hpp new file mode 100644 index 0000000..e855bcb --- /dev/null +++ b/common/map/region_api.hpp @@ -0,0 +1,27 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "lua.hpp" + +#define TORTUGA_REGION_API "region" +LUAMOD_API int openRegionAPI(lua_State* L); diff --git a/common/map/region_pager_api.cpp b/common/map/region_pager_api.cpp new file mode 100644 index 0000000..fd366db --- /dev/null +++ b/common/map/region_pager_api.cpp @@ -0,0 +1,172 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region_pager_api.hpp" + +#include "region_pager_lua.hpp" +#include "region.hpp" + +//DOCS: These glue functions simply wrap RegionPagerLua's methods +//NOTE: zero indexing is used here, but not in the region API + +static int setTile(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + int ret = pager->SetTile(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5)); + lua_pushinteger(L, ret); + return 1; +} + +static int getTile(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + int ret = pager->GetTile(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4)); + lua_pushinteger(L, ret); + return 1; +} + +static int setSolid(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = pager->SetSolid(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_toboolean(L, 4)); + lua_pushboolean(L, ret); + return 1; +} + +static int getSolid(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = pager->GetSolid(lua_tointeger(L, 2), lua_tointeger(L, 3)); + lua_pushboolean(L, ret); + return 1; +} + +static int getRegion(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + lua_pushlightuserdata(L, region); + return 1; +} + +static int loadRegion(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->LoadRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + lua_pushlightuserdata(L, region); + return 1; +} + +static int saveRegion(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->SaveRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + lua_pushlightuserdata(L, region); + return 1; +} + +static int createRegion(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->CreateRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + lua_pushlightuserdata(L, region); + return 1; +} + +static int unloadRegion(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + + //two argument types: coords & the region itself + switch(lua_type(L, 2)) { + case LUA_TNUMBER: + pager->UnloadIf([&](Region const& region) -> bool { + int x = lua_tointeger(L, 2); + int y = lua_tointeger(L, 3); + return region.GetX() == x && region.GetY() == y; + }); + break; + case LUA_TLIGHTUSERDATA: + pager->UnloadIf([&](Region const& region) -> bool { + return (®ion) == lua_touserdata(L, 2); + }); + break; + } + return 0; +} + +static int setOnLoad(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + luaL_unref(L, LUA_REGISTRYINDEX, pager->GetLoadReference()); + pager->SetLoadReference(luaL_ref(L, LUA_REGISTRYINDEX)); + return 0; +} + +static int setOnSave(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + luaL_unref(L, LUA_REGISTRYINDEX, pager->GetSaveReference()); + pager->SetSaveReference(luaL_ref(L, LUA_REGISTRYINDEX)); + return 0; +} + +static int setOnCreate(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + luaL_unref(L, LUA_REGISTRYINDEX, pager->GetCreateReference()); + pager->SetCreateReference(luaL_ref(L, LUA_REGISTRYINDEX)); + return 0; +} + +static int setOnUnload(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + luaL_unref(L, LUA_REGISTRYINDEX, pager->GetUnloadReference()); + pager->SetUnloadReference(luaL_ref(L, LUA_REGISTRYINDEX)); + return 0; +} + +//debugging +static int containerSize(lua_State* L) { + RegionPagerLua* pager = static_cast(lua_touserdata(L, 1)); + lua_pushinteger(L, pager->GetContainer()->size()); + return 1; +} + +static const luaL_Reg regionPagerLib[] = { + //curry + {"SetTile", setTile}, + {"GetTile", getTile}, + {"SetSolid", setSolid}, + {"GetSolid", getSolid}, + + //access and control + {"GetRegion", getRegion}, + {"LoadRegion", loadRegion}, + {"SaveRegion", saveRegion}, + {"CreateRegion", createRegion}, + {"UnloadRegion", unloadRegion}, + + //triggers + {"SetOnLoad",setOnLoad}, + {"SetOnSave",setOnSave}, + {"SetOnCreate",setOnCreate}, + {"SetOnUnload",setOnUnload}, + + //debugging + {"ContainerSize", containerSize}, + + //sentinel + {nullptr, nullptr} +}; + +LUAMOD_API int openRegionPagerAPI(lua_State* L) { + luaL_newlib(L, regionPagerLib); + return 1; +} \ No newline at end of file diff --git a/common/map/region_pager_api.hpp b/common/map/region_pager_api.hpp new file mode 100644 index 0000000..965b400 --- /dev/null +++ b/common/map/region_pager_api.hpp @@ -0,0 +1,27 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "lua.hpp" + +#define TORTUGA_REGION_PAGER_API "region_pager" +LUAMOD_API int openRegionPagerAPI(lua_State* L); diff --git a/common/map/region_pager_base.cpp b/common/map/region_pager_base.cpp new file mode 100644 index 0000000..49b8118 --- /dev/null +++ b/common/map/region_pager_base.cpp @@ -0,0 +1,111 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region_pager_base.hpp" + +#include +#include + +RegionPagerBase::~RegionPagerBase() { + UnloadAll(); +}; + +Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) { + Region* ptr = GetRegion(x, y); + return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v); +} + +Region::type_t RegionPagerBase::GetTile(int x, int y, int z) { + Region* ptr = FindRegion(x, y); + if (!ptr) { + return 0; + } + return ptr->GetTile(x - ptr->GetX(), y - ptr->GetY(), z); +} + +bool RegionPagerBase::SetSolid(int x, int y, int b) { + Region* ptr = GetRegion(x, y); + return ptr->SetSolid(x - ptr->GetX(), y - ptr->GetY(), b); +} + +bool RegionPagerBase::GetSolid(int x, int y) { + Region* ptr = FindRegion(x, y); + if (!ptr) { + return 0; + } + return ptr->GetSolid(x - ptr->GetX(), y - ptr->GetY()); +} + +Region* RegionPagerBase::GetRegion(int x, int y) { + x = snapToBase(REGION_WIDTH, x); + y = snapToBase(REGION_HEIGHT, y); + + //get the region by various means + Region* ptr = nullptr; + ptr = FindRegion(x, y); + if (ptr) return ptr; + ptr = LoadRegion(x, y); + if (ptr) return ptr; + return CreateRegion(x, y); +} + +Region* RegionPagerBase::FindRegion(int x, int y) { + //find the region + std::list::iterator it = find_if(regionList.begin(), regionList.end(), [x, y](Region& region) -> bool { + return region.GetX() == x && region.GetY() == y; + }); + return it != regionList.end() ? &(*it) : nullptr; +} + +Region* RegionPagerBase::PushRegion(Region* const ptr) { + regionList.push_front(*ptr); + return ®ionList.front(); +} + +Region* RegionPagerBase::LoadRegion(int x, int y) { + //EMPTY, intended for override + return nullptr; +} + +Region* RegionPagerBase::SaveRegion(int x, int y) { + //EMPTY, intended for override + return nullptr; +} + +Region* RegionPagerBase::CreateRegion(int x, int y) { + if (FindRegion(x, y)) { + throw(std::logic_error("Cannot overwrite an existing region")); + } + regionList.emplace_front(x, y); + return ®ionList.front(); +} + +void RegionPagerBase::UnloadIf(std::function fn) { + regionList.remove_if(fn); +} + +void RegionPagerBase::UnloadAll() { + regionList.clear(); +} + +std::list* RegionPagerBase::GetContainer() { + return ®ionList; +} \ No newline at end of file diff --git a/common/map/region_pager_base.hpp b/common/map/region_pager_base.hpp new file mode 100644 index 0000000..a53083d --- /dev/null +++ b/common/map/region_pager_base.hpp @@ -0,0 +1,58 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "region.hpp" + +#include +#include + +class RegionPagerBase { +public: + RegionPagerBase() = default; + virtual ~RegionPagerBase(); + + //tile manipulation + virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v); + virtual Region::type_t GetTile(int x, int y, int z); + + //solid manipulation + virtual bool SetSolid(int x, int y, int b); + virtual bool GetSolid(int x, int y); + + //region manipulation + virtual Region* GetRegion(int x, int y); + virtual Region* FindRegion(int x, int y); + virtual Region* PushRegion(Region* const); + + virtual Region* LoadRegion(int x, int y); + virtual Region* SaveRegion(int x, int y); + virtual Region* CreateRegion(int x, int y); + + virtual void UnloadIf(std::function fn); + virtual void UnloadAll(); + + //accessors & mutators + std::list* GetContainer(); +protected: + std::list regionList; +}; diff --git a/common/map/region_pager_lua.cpp b/common/map/region_pager_lua.cpp new file mode 100644 index 0000000..66771c9 --- /dev/null +++ b/common/map/region_pager_lua.cpp @@ -0,0 +1,208 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region_pager_lua.hpp" + +#include + +RegionPagerLua::~RegionPagerLua() { + //unload all regions + UnloadAll(); + //clear any stored functions + luaL_unref(lua, LUA_REGISTRYINDEX, loadRef); + luaL_unref(lua, LUA_REGISTRYINDEX, saveRef); + luaL_unref(lua, LUA_REGISTRYINDEX, createRef); + luaL_unref(lua, LUA_REGISTRYINDEX, unloadRef); +} + +//return the loaded region, or nullptr on failure +Region* RegionPagerLua::LoadRegion(int x, int y) { + //get the pager's function from the registry + lua_rawgeti(lua, LUA_REGISTRYINDEX, loadRef); + + //check if this function is available + if (lua_isnil(lua, -1)) { + lua_pop(lua, 1); + //signal that there is no load function + return nullptr; + } + + //something to work on + Region tmpRegion(x, y); + lua_pushlightuserdata(lua, &tmpRegion); + + //call the funtion, 1 arg, 1 return + if (lua_pcall(lua, 1, 1, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) )); + } + + //check the return value, success or failure + if (lua_isboolean(lua, -1) && lua_toboolean(lua, -1)) { + lua_pop(lua, 1); + //push and return the loaded region + regionList.push_front(tmpRegion); + return ®ionList.front(); + } + else { + lua_pop(lua, 1); + //signal a failure + return nullptr; + } +} + +//NOTE: this return value seems strange; could replace it with a boolean +//return the saved region, or nullptr on failure +Region* RegionPagerLua::SaveRegion(int x, int y) { + //get the pager's function from the registry + lua_rawgeti(lua, LUA_REGISTRYINDEX, saveRef); + + //check if this function is available + if (lua_isnil(lua, -1)) { + lua_pop(lua, 1); + //signal that the region wasn't saved + return nullptr; + } + + //find the specified region + Region* ptr = FindRegion(x, y); + if (!ptr) { + lua_pop(lua, 1); + //signal that there is no save function + return nullptr; + } + lua_pushlightuserdata(lua, ptr); + + //call the function, 1 arg, 1 return + if (lua_pcall(lua, 1, 1, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) )); + } + + //check the return value, success or failure + if (lua_isboolean(lua, -1) && lua_toboolean(lua, -1)) { + lua_pop(lua, 1); + //return the specified region that was saved + return ptr; + } + else { + lua_pop(lua, 1); + //signal a failure + return nullptr; + } +} + +//DOCS: since this method is the last ditch call from GetRegion, it must return a valid region object, even if the create function hasn't been set. +//return a new region, throwing an error on failure +Region* RegionPagerLua::CreateRegion(int x, int y) { + if (FindRegion(x, y)) { + throw(std::logic_error("Cannot overwrite an existing region")); + } + + //get the pager's function from the registry + lua_rawgeti(lua, LUA_REGISTRYINDEX, createRef); + + //check if this function is available + if (lua_isnil(lua, -1)) { + lua_pop(lua, 1); + //return an empty region object + regionList.emplace_front(x, y); + return ®ionList.front(); + } + + //something to work on + Region tmpRegion(x, y); + lua_pushlightuserdata(lua, &tmpRegion); + + //call the function, 1 arg, 0 return + if (lua_pcall(lua, 1, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) )); + } + + //return the new region + regionList.push_front(tmpRegion); + return ®ionList.front(); +} + +//no return +void RegionPagerLua::UnloadIf(std::function fn) { + //get the pager's function from the registry + lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef); + + //check if this function is available + if (lua_isnil(lua, -1)) { + lua_pop(lua, 1); + //remove the regions anyway + regionList.remove_if(fn); + return; + } + + //run each region through this lambda + regionList.remove_if([&](Region& region) -> bool { + if (fn(region)) { + + //push a copy of the function onto the stack with the region + lua_pushvalue(lua, -1); + lua_pushlightuserdata(lua, static_cast(®ion)); + + //call the function, 1 arg, 0 return + if (lua_pcall(lua, 1, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) )); + } + + //signal to the container + return true; + } + //signal to the container + return false; + }); + + //pop the base copy of the function + lua_pop(lua, 1); +} + +void RegionPagerLua::UnloadAll() { + //get the pager's function from the registry + lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef); + + //check if this function is available + if (lua_isnil(lua, -1)) { + lua_pop(lua, 1); + //remove the regions anyway + regionList.clear(); + return; + } + + for (auto& it : regionList) { + //push a copy of the function onto the stack with the region + lua_pushvalue(lua, -1); + lua_pushlightuserdata(lua, &it); + + //call the function, 1 arg, 0 return + if (lua_pcall(lua, 1, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) )); + } + } + + //pop the base copy of the function + lua_pop(lua, 1); + + //remove from memory + regionList.clear(); +} \ No newline at end of file diff --git a/common/map/region_pager_lua.hpp b/common/map/region_pager_lua.hpp new file mode 100644 index 0000000..bf2c039 --- /dev/null +++ b/common/map/region_pager_lua.hpp @@ -0,0 +1,68 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "region_pager_base.hpp" + +#include "lua.hpp" + +#include +#include + +//DOCS: set the lua hook before use + +class RegionPagerLua : public RegionPagerBase { +public: + RegionPagerLua() = default; + ~RegionPagerLua(); + + //region manipulation + Region* LoadRegion(int x, int y) override; + Region* SaveRegion(int x, int y) override; + Region* CreateRegion(int x, int y) override; + + void UnloadIf(std::function fn) override; + void UnloadAll() override; + + //accessors & mutators + lua_State* SetLuaState(lua_State* L) { return lua = L; } + lua_State* GetLuaState() { return lua; } + + //utilities for the API + int SetLoadReference(int i) { return loadRef = i; } + int SetSaveReference(int i) { return saveRef = i; } + int SetCreateReference(int i) { return createRef = i; } + int SetUnloadReference(int i) { return unloadRef = i; } + + int GetLoadReference() { return loadRef; } + int GetSaveReference() { return saveRef; } + int GetCreateReference() { return createRef; } + int GetUnloadReference() { return unloadRef; } + +protected: + lua_State* lua = nullptr; + + int loadRef = LUA_NOREF; + int saveRef = LUA_NOREF; + int createRef = LUA_NOREF; + int unloadRef = LUA_NOREF; +}; diff --git a/common/map/tile_sheet.cpp b/common/map/tile_sheet.cpp new file mode 100644 index 0000000..bd18d0a --- /dev/null +++ b/common/map/tile_sheet.cpp @@ -0,0 +1,124 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "tile_sheet.hpp" + +#include + +TileSheet& TileSheet::operator=(TileSheet const& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Copy the other TileSheet's stuff + texture = rhs.texture; + clip = rhs.clip; + local = false; + countX = rhs.countX; + countY = rhs.countY; +} + +TileSheet& TileSheet::operator=(TileSheet&& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Copy the other TileSheet's stuff + texture = rhs.texture; + clip = rhs.clip; + local = false; + countX = rhs.countX; + countY = rhs.countY; + + rhs.texture = nullptr; + rhs.clip = {0, 0, 0, 0}; + rhs.local = false; + rhs.countX = 0; + rhs.countY = 0; +} + +void TileSheet::Load(SDL_Renderer* renderer, std::string fname, int tileWidth, int tileHeight) { + Image::Load(renderer, fname); + countX = clip.w / tileWidth; + countY = clip.h / tileHeight; + clip.w = tileWidth; + clip.h = tileHeight; +} + +SDL_Texture* TileSheet::SetTexture(SDL_Texture* ptr, int tileWidth, int tileHeight) { + Image::SetTexture(ptr); + countX = clip.w / tileWidth; + countY = clip.h / tileHeight; + clip.w = tileWidth; + clip.h = tileHeight; +} + +void TileSheet::Free() { + Image::Free(); + countX = countY = 0; +} + +void TileSheet::DrawLayerTo(SDL_Renderer* const renderer, Region* const region, int layer, int camX, int camY, double scaleX, double scaleY) { + //TODO: (2) empty +} + +void TileSheet::DrawRegionTo(SDL_Renderer* const renderer, Region* const region, int camX, int camY, double scaleX, double scaleY) { + //NOTE: TileSheet is a friend class of Region + //reimplementing DrawTo() to improve performance (less indirection) + if (!texture) { + throw(std::logic_error("No image texture to draw")); + } + + //the local variables + SDL_Rect sclip = {0, 0, clip.w, clip.h}; + SDL_Rect dclip = {0, 0, Uint16(clip.w * scaleX), Uint16(clip.h * scaleY)}; + Region::type_t tile = 0; + + //for each tile + for (register int i = 0; i < REGION_WIDTH; ++i) { + for (register int j = 0; j < REGION_HEIGHT; ++j) { + for (register int k = 0; k < REGION_DEPTH; ++k) { + //get the value to skip expensive lookups + tile = region->tiles[i][j][k]; + + //0 is invisible + if (tile == 0) continue; + + //set the sclip + sclip.x = (tile-1) % countX * clip.h; + sclip.y = (tile-1) / countX * clip.w; + + //set the dclip + dclip.x = ((region->x + i) * clip.w - camX) * scaleX; + dclip.y = ((region->y + j) * clip.h - camY) * scaleY; + + //draw + SDL_RenderCopy(renderer, texture, &sclip, &dclip); + } + } + } +} diff --git a/common/map/tile_sheet.hpp b/common/map/tile_sheet.hpp new file mode 100644 index 0000000..74affdf --- /dev/null +++ b/common/map/tile_sheet.hpp @@ -0,0 +1,67 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "region.hpp" + +#include "image.hpp" + +#include + +class TileSheet : public Image { +public: + TileSheet() = default; + TileSheet(TileSheet const& rhs) { *this = rhs; } + TileSheet(TileSheet&& rhs) { *this = std::move(rhs); } + TileSheet(SDL_Renderer* r, std::string fn, int tw, int th) { Load(r, fn, tw, th); } + TileSheet(SDL_Texture* p, int tw, int th) { SetTexture(p, tw, th); } + ~TileSheet() = default; + + TileSheet& operator=(TileSheet const&); + TileSheet& operator=(TileSheet&&); + + void Load(SDL_Renderer*, std::string fname, int tileWidth, int tileHeight); + SDL_Texture* SetTexture(SDL_Texture*, int tileWidth, int tileHeight); + void Free() override; + + void DrawLayerTo(SDL_Renderer* const renderer, Region* const region, int layer, int camX, int camY, double scaleX = 1.0, double scaleY = 1.0); + void DrawRegionTo(SDL_Renderer* const renderer, Region* const region, int camX, int camY, double scaleX = 1.0, double scaleY = 1.0); + + //accessors + //DOCS: Reuse Image::clip for tile sizes + int GetCountX() { return countX; } + int GetCountY() { return countY; } + int GetTileW() { return clip.w; } + int GetTileH() { return clip.h; } + +protected: + int countX = 0, countY = 0; + + using Image::Load; + using Image::Create; + using Image::SetTexture; + using Image::SetClip; + using Image::SetClipX; + using Image::SetClipY; + using Image::SetClipW; + using Image::SetClipH; +}; diff --git a/common/network/makefile b/common/network/makefile new file mode 100644 index 0000000..3bcac3d --- /dev/null +++ b/common/network/makefile @@ -0,0 +1,29 @@ +#config +INCLUDES+=. packet_types ../gameplay ../map ../utilities +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + $(MAKE) -C packet_types + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/network/packet_types/character_packet.cpp b/common/network/packet_types/character_packet.cpp new file mode 100644 index 0000000..7906230 --- /dev/null +++ b/common/network/packet_types/character_packet.cpp @@ -0,0 +1,80 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "character_packet.hpp" + +#include "serial_utility.hpp" + +void serializeCharacter(void* buffer, CharacterPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the character + serialCopy(&buffer, &packet->characterIndex, sizeof(int)); + serialCopy(&buffer, packet->handle, PACKET_STRING_SIZE); + serialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE); + + //the owner + serialCopy(&buffer, &packet->accountIndex, sizeof(int)); + + //location + serialCopy(&buffer, &packet->roomIndex, sizeof(int)); + + serialCopy(&buffer, &packet->origin.x, sizeof(double)); + serialCopy(&buffer, &packet->origin.y, sizeof(double)); + + serialCopy(&buffer, &packet->motion.x, sizeof(double)); + serialCopy(&buffer, &packet->motion.y, sizeof(double)); + + serialCopy(&buffer, &packet->bounds.x, sizeof(int)); + serialCopy(&buffer, &packet->bounds.y, sizeof(int)); + serialCopy(&buffer, &packet->bounds.w, sizeof(int)); + serialCopy(&buffer, &packet->bounds.h, sizeof(int)); + + //gameplay components: equipment, items, buffs, debuffs... +} + +void deserializeCharacter(void* buffer, CharacterPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the character + deserialCopy(&buffer, &packet->characterIndex, sizeof(int)); + deserialCopy(&buffer, packet->handle, PACKET_STRING_SIZE); + deserialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE); + + //the owner + deserialCopy(&buffer, &packet->accountIndex, sizeof(int)); + + //location + deserialCopy(&buffer, &packet->roomIndex, sizeof(int)); + + deserialCopy(&buffer, &packet->origin.x, sizeof(double)); + deserialCopy(&buffer, &packet->origin.y, sizeof(double)); + + deserialCopy(&buffer, &packet->motion.x, sizeof(double)); + deserialCopy(&buffer, &packet->motion.y, sizeof(double)); + + deserialCopy(&buffer, &packet->bounds.x, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.y, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.w, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.h, sizeof(int)); + + //gameplay components: equipment, items, buffs, debuffs... +} diff --git a/common/network/packet_types/character_packet.hpp b/common/network/packet_types/character_packet.hpp new file mode 100644 index 0000000..fb3b0bb --- /dev/null +++ b/common/network/packet_types/character_packet.hpp @@ -0,0 +1,46 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" + +#include "bounding_box.hpp" +#include "vector2.hpp" + +struct CharacterPacket : SerialPacketBase { + //identify the character + int characterIndex; + char handle[PACKET_STRING_SIZE]; + char avatar[PACKET_STRING_SIZE]; + + //the owner + int accountIndex; + + //location + int roomIndex; + Vector2 origin; + Vector2 motion; + BoundingBox bounds; +}; + +void serializeCharacter(void* buffer, CharacterPacket* packet); +void deserializeCharacter(void* buffer, CharacterPacket* packet); diff --git a/common/network/packet_types/client_packet.cpp b/common/network/packet_types/client_packet.cpp new file mode 100644 index 0000000..a0c6617 --- /dev/null +++ b/common/network/packet_types/client_packet.cpp @@ -0,0 +1,40 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "client_packet.hpp" + +#include "serial_utility.hpp" + +void serializeClient(void* buffer, ClientPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + serialCopy(&buffer, &packet->clientIndex, sizeof(int)); + serialCopy(&buffer, &packet->accountIndex, sizeof(int)); + serialCopy(&buffer, packet->username, PACKET_STRING_SIZE); +} + +void deserializeClient(void* buffer, ClientPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + deserialCopy(&buffer, &packet->clientIndex, sizeof(int)); + deserialCopy(&buffer, &packet->accountIndex, sizeof(int)); + deserialCopy(&buffer, packet->username, PACKET_STRING_SIZE); +} diff --git a/common/network/packet_types/client_packet.hpp b/common/network/packet_types/client_packet.hpp new file mode 100644 index 0000000..ec5ea5a --- /dev/null +++ b/common/network/packet_types/client_packet.hpp @@ -0,0 +1,34 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" + +struct ClientPacket : SerialPacketBase { + int clientIndex; + int accountIndex; + char username[PACKET_STRING_SIZE]; + //TODO: (3) password, auth token +}; + +void serializeClient(void* buffer, ClientPacket* packet); +void deserializeClient(void* buffer, ClientPacket* packet); diff --git a/common/network/packet_types/makefile b/common/network/packet_types/makefile new file mode 100644 index 0000000..e6aff0a --- /dev/null +++ b/common/network/packet_types/makefile @@ -0,0 +1,28 @@ +#config +INCLUDES+=. .. ../../gameplay ../../map ../../utilities +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs ../$(OUT) $(OBJ) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/network/packet_types/monster_packet.cpp b/common/network/packet_types/monster_packet.cpp new file mode 100644 index 0000000..c365207 --- /dev/null +++ b/common/network/packet_types/monster_packet.cpp @@ -0,0 +1,70 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "monster_packet.hpp" + +#include "serial_utility.hpp" + +void serializeMonster(void* buffer, MonsterPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the monster + serialCopy(&buffer, &packet->monsterIndex, sizeof(int)); + serialCopy(&buffer, packet->handle, PACKET_STRING_SIZE); + serialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE); + + //bounds + serialCopy(&buffer, &packet->bounds.x, sizeof(int)); + serialCopy(&buffer, &packet->bounds.y, sizeof(int)); + serialCopy(&buffer, &packet->bounds.w, sizeof(int)); + serialCopy(&buffer, &packet->bounds.h, sizeof(int)); + + + //location + serialCopy(&buffer, &packet->roomIndex, sizeof(int)); + serialCopy(&buffer, &packet->origin.x, sizeof(double)); + serialCopy(&buffer, &packet->origin.y, sizeof(double)); + serialCopy(&buffer, &packet->motion.x, sizeof(double)); + serialCopy(&buffer, &packet->motion.y, sizeof(double)); +} + +void deserializeMonster(void* buffer, MonsterPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the monster + deserialCopy(&buffer, &packet->monsterIndex, sizeof(int)); + deserialCopy(&buffer, packet->handle, PACKET_STRING_SIZE); + deserialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE); + + //bounds + deserialCopy(&buffer, &packet->bounds.x, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.y, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.w, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.h, sizeof(int)); + + + //location + deserialCopy(&buffer, &packet->roomIndex, sizeof(int)); + deserialCopy(&buffer, &packet->origin.x, sizeof(double)); + deserialCopy(&buffer, &packet->origin.y, sizeof(double)); + deserialCopy(&buffer, &packet->motion.x, sizeof(double)); + deserialCopy(&buffer, &packet->motion.y, sizeof(double)); +} diff --git a/common/network/packet_types/monster_packet.hpp b/common/network/packet_types/monster_packet.hpp new file mode 100644 index 0000000..3a4cc37 --- /dev/null +++ b/common/network/packet_types/monster_packet.hpp @@ -0,0 +1,43 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" + +#include "bounding_box.hpp" +#include "vector2.hpp" + +struct MonsterPacket : SerialPacketBase { + //identify the monster + int monsterIndex; + char handle[PACKET_STRING_SIZE]; + char avatar[PACKET_STRING_SIZE]; + BoundingBox bounds; + + //location + int roomIndex; + Vector2 origin; + Vector2 motion; +}; + +void serializeMonster(void* buffer, MonsterPacket* packet); +void deserializeMonster(void* buffer, MonsterPacket* packet); diff --git a/common/network/packet_types/region_packet.cpp b/common/network/packet_types/region_packet.cpp new file mode 100644 index 0000000..4ac1471 --- /dev/null +++ b/common/network/packet_types/region_packet.cpp @@ -0,0 +1,79 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region_packet.hpp" + +#include "serial_utility.hpp" + +void serializeRegion(void* buffer, RegionPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //format + serialCopy(&buffer, &packet->roomIndex, sizeof(int)); + serialCopy(&buffer, &packet->x, sizeof(int)); + serialCopy(&buffer, &packet->y, sizeof(int)); + + if (packet->type != SerialPacketType::REGION_CONTENT) { + return; + } + + //tiles + for (int i = 0; i < REGION_WIDTH; i++) { + for (int j = 0; j < REGION_HEIGHT; j++) { + for (int k = 0; k < REGION_DEPTH; k++) { + *reinterpret_cast(buffer) = packet->region->GetTile(i, j, k); + buffer = reinterpret_cast(buffer) + sizeof(Region::type_t); + } + } + } + + //solids + serialCopy(&buffer, packet->region->GetSolidBitset(), REGION_SOLID_FOOTPRINT); +} + +void deserializeRegion(void* buffer, RegionPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //format + deserialCopy(&buffer, &packet->roomIndex, sizeof(int)); + deserialCopy(&buffer, &packet->x, sizeof(int)); + deserialCopy(&buffer, &packet->y, sizeof(int)); + + if (packet->type != SerialPacketType::REGION_CONTENT) { + return; + } + + //an object to work on + packet->region = new Region(packet->x, packet->y); + + //tiles + for (int i = 0; i < REGION_WIDTH; i++) { + for (int j = 0; j < REGION_HEIGHT; j++) { + for (int k = 0; k < REGION_DEPTH; k++) { + packet->region->SetTile(i, j, k, *reinterpret_cast(buffer)); + buffer = reinterpret_cast(buffer) + sizeof(Region::type_t); + } + } + } + + //solids + deserialCopy(&buffer, packet->region->GetSolidBitset(), REGION_SOLID_FOOTPRINT); +} \ No newline at end of file diff --git a/common/network/packet_types/region_packet.hpp b/common/network/packet_types/region_packet.hpp new file mode 100644 index 0000000..01588c7 --- /dev/null +++ b/common/network/packet_types/region_packet.hpp @@ -0,0 +1,45 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" + +#include "region.hpp" + +#include + +//define the memory footprint for the region's members +constexpr int REGION_TILE_FOOTPRINT = sizeof(Region::type_t) * REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH; +constexpr int REGION_SOLID_FOOTPRINT = ceil(REGION_WIDTH * REGION_HEIGHT / 8.0); +constexpr int REGION_METADATA_FOOTPRINT = sizeof(int) * 3; + +struct RegionPacket : SerialPacketBase { + //location/identify the region + int roomIndex; + int x, y; + + //the data + Region* region; +}; + +void serializeRegion(void* buffer, RegionPacket* packet); +void deserializeRegion(void* buffer, RegionPacket* packet); diff --git a/common/network/packet_types/serial_packet_base.cpp b/common/network/packet_types/serial_packet_base.cpp new file mode 100644 index 0000000..d90b868 --- /dev/null +++ b/common/network/packet_types/serial_packet_base.cpp @@ -0,0 +1,24 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial_packet_base.hpp" + +//sanity check \ No newline at end of file diff --git a/common/network/packet_types/serial_packet_base.hpp b/common/network/packet_types/serial_packet_base.hpp new file mode 100644 index 0000000..a2eafff --- /dev/null +++ b/common/network/packet_types/serial_packet_base.hpp @@ -0,0 +1,36 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_type.hpp" + +#include "SDL2/SDL_net.h" + +constexpr int PACKET_STRING_SIZE = 100; + +struct SerialPacketBase { + //members + SerialPacketType type; + IPaddress srcAddress; + + virtual ~SerialPacketBase() {}; +}; diff --git a/common/network/packet_types/server_packet.cpp b/common/network/packet_types/server_packet.cpp new file mode 100644 index 0000000..eefefbe --- /dev/null +++ b/common/network/packet_types/server_packet.cpp @@ -0,0 +1,42 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "server_packet.hpp" + +#include "serial_utility.hpp" + +void serializeServer(void* buffer, ServerPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the server + serialCopy(&buffer, &packet->version, sizeof(int)); + serialCopy(&buffer, packet->name, PACKET_STRING_SIZE); + serialCopy(&buffer, &packet->playerCount, sizeof(int)); +} + +void deserializeServer(void* buffer, ServerPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the server + deserialCopy(&buffer, &packet->version, sizeof(int)); + deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE); + deserialCopy(&buffer, &packet->playerCount, sizeof(int)); +} diff --git a/common/network/packet_types/server_packet.hpp b/common/network/packet_types/server_packet.hpp new file mode 100644 index 0000000..6c6b1b5 --- /dev/null +++ b/common/network/packet_types/server_packet.hpp @@ -0,0 +1,34 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" + +struct ServerPacket : SerialPacketBase { + //identify the server + char name[PACKET_STRING_SIZE]; + int playerCount; + int version; +}; + +void serializeServer(void* buffer, ServerPacket* packet); +void deserializeServer(void* buffer, ServerPacket* packet); diff --git a/common/network/packet_types/text_packet.cpp b/common/network/packet_types/text_packet.cpp new file mode 100644 index 0000000..2ec8ce2 --- /dev/null +++ b/common/network/packet_types/text_packet.cpp @@ -0,0 +1,52 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "text_packet.hpp" + +#include "serial_utility.hpp" + +void serializeText(void* buffer, TextPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //content + serialCopy(&buffer, packet->name, PACKET_STRING_SIZE); + serialCopy(&buffer, packet->text, PACKET_STRING_SIZE); + + //location + serialCopy(&buffer, &packet->roomIndex, sizeof(int)); + serialCopy(&buffer, &packet->origin.x, sizeof(double)); + serialCopy(&buffer, &packet->origin.y, sizeof(double)); + serialCopy(&buffer, &packet->range, sizeof(int)); +} + +void deserializeText(void* buffer, TextPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //content + deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE); + deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE); + + //location + deserialCopy(&buffer, &packet->roomIndex, sizeof(int)); + deserialCopy(&buffer, &packet->origin.x, sizeof(double)); + deserialCopy(&buffer, &packet->origin.y, sizeof(double)); + deserialCopy(&buffer, &packet->range, sizeof(int)); +} \ No newline at end of file diff --git a/common/network/packet_types/text_packet.hpp b/common/network/packet_types/text_packet.hpp new file mode 100644 index 0000000..434ee86 --- /dev/null +++ b/common/network/packet_types/text_packet.hpp @@ -0,0 +1,37 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" + +#include "vector2.hpp" + +struct TextPacket : SerialPacketBase { + char name[PACKET_STRING_SIZE]; + char text[PACKET_STRING_SIZE]; + int roomIndex; + Vector2 origin; + int range; +}; + +void serializeText(void* buffer, TextPacket* packet); +void deserializeText(void* buffer, TextPacket* packet); diff --git a/common/network/serial_packet.hpp b/common/network/serial_packet.hpp new file mode 100644 index 0000000..4bf1d8a --- /dev/null +++ b/common/network/serial_packet.hpp @@ -0,0 +1,63 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" +#include "character_packet.hpp" +#include "client_packet.hpp" +#include "monster_packet.hpp" +#include "region_packet.hpp" +#include "server_packet.hpp" +#include "text_packet.hpp" + +//SerialPacketBase is defined in serial_packet_base.hpp +typedef SerialPacketBase SerialPacket; + +//DOCS: NETWORK_VERSION is used to discern compatible servers and clients +constexpr int NETWORK_VERSION = 20160316; + +union MaxPacket { + CharacterPacket a; + ClientPacket b; + MonsterPacket c; + RegionPacket d; + ServerPacket e; + TextPacket f; +}; + +constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket); + +/* DOCS: PACKET_BUFFER_SIZE is the memory required to store serialized data + * DOCS: SerialPacketType::REGION_CONTENT is currently the largest packet type + * Serialized RegionPacket structure: + * SerialPacketType + * room index (int) + * X & Y position (int) + * tile data (3 layers) + * solid data (bitset) +*/ + +constexpr int PACKET_BUFFER_SIZE = + sizeof(SerialPacketType) + + REGION_METADATA_FOOTPRINT + + REGION_TILE_FOOTPRINT + + REGION_SOLID_FOOTPRINT; diff --git a/common/network/serial_packet_type.hpp b/common/network/serial_packet_type.hpp new file mode 100644 index 0000000..349d964 --- /dev/null +++ b/common/network/serial_packet_type.hpp @@ -0,0 +1,184 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +/* DOCS: The headers indicate what packet type is used for each message + * different messages under the same header will carry different amounts of + * valid data, but it will still be carried in that packet's format. + * FORMAT_* is for internal use, deviding the different format bounds. +*/ + +enum class SerialPacketType { + //default: there is something wrong + NONE, + + //------------------------- + //ServerPacket + // name, player count, version + //------------------------- + + FORMAT_SERVER, + + //heartbeat + PING, + PONG, + + //Used for finding available servers + BROADCAST_REQUEST, + BROADCAST_RESPONSE, + + FORMAT_END_SERVER, + + //------------------------- + //ClientPacket + // client index, account index, username + //------------------------- + + FORMAT_CLIENT, + + //Connecting to a server as a client + JOIN_REQUEST, + JOIN_RESPONSE, + + //disconnect from the server + DISCONNECT_REQUEST, + DISCONNECT_RESPONSE, + ADMIN_DISCONNECT_FORCED, + + //load the account + LOGIN_REQUEST, + LOGIN_RESPONSE, + + //unload the account + LOGOUT_REQUEST, + LOGOUT_RESPONSE, + + //shut down the server + ADMIN_SHUTDOWN_REQUEST, + + FORMAT_END_CLIENT, + + //------------------------- + //RegionPacket + // room index, x, y, raw data + //------------------------- + + FORMAT_REGION, + + //map data + REGION_REQUEST, + REGION_CONTENT, + + FORMAT_END_REGION, + + //------------------------- + //CharacterPacket + // character index, + // handle, avatar, + // account index (owner), + // room index, origin, motion + //------------------------- + + FORMAT_CHARACTER, + + //full data update + CHARACTER_UPDATE, + + //character management + CHARACTER_CREATE, + CHARACTER_DELETE, + CHARACTER_LOAD, + CHARACTER_UNLOAD, + + //find out info from the server + QUERY_CHARACTER_EXISTS, + QUERY_CHARACTER_STATS, + QUERY_CHARACTER_LOCATION, + + //actions taken + CHARACTER_MOVEMENT, + CHARACTER_ATTACK, + CHARACTER_DAMAGE, + + //admin control +// ADMIN_SET_CHARACTER_ORIGIN, + + FORMAT_END_CHARACTER, + + //------------------------- + //MonsterPacket + // monster index, + // handle, avatar + // bounds + // room index, origin, motion + //------------------------- + + FORMAT_MONSTER, + + //full data update + MONSTER_UPDATE, + + //character management + MONSTER_CREATE, + MONSTER_DELETE, + + //find out info from the server + QUERY_MONSTER_EXISTS, + QUERY_MONSTER_STATS, + QUERY_MONSTER_LOCATION, + + //actions taken + MONSTER_MOVEMENT, + MONSTER_ATTACK, + MONSTER_DAMAGE, + + FORMAT_END_MONSTER, + + //------------------------- + //TextPacket + // name, text + //------------------------- + + FORMAT_TEXT, + + //general speech + TEXT_BROADCAST, + TEXT_SPEECH, + TEXT_WHISPER, + + //rejection/error messages + JOIN_REJECTION, + LOGIN_REJECTION, + REGION_REJECTION, + CHARACTER_REJECTION, + MONSTER_REJECTION, + SHUTDOWN_REJECTION, + QUERY_REJECTION, + + FORMAT_END_TEXT, + + //------------------------- + //not used + //------------------------- + + LAST +}; diff --git a/common/network/serial_utility.cpp b/common/network/serial_utility.cpp new file mode 100644 index 0000000..d002891 --- /dev/null +++ b/common/network/serial_utility.cpp @@ -0,0 +1,105 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial_utility.hpp" + +//packet types +#include "character_packet.hpp" +#include "client_packet.hpp" +#include "monster_packet.hpp" +#include "region_packet.hpp" +#include "server_packet.hpp" +#include "text_packet.hpp" + +#include + +//macros +#define BOUNDS(type, lower, upper) ((type) > (lower) && (type) < (upper)) + +//raw memory copy +void serialCopy(void** buffer, void* data, int size) { + memcpy(*buffer, data, size); + *buffer = reinterpret_cast(*buffer) + size; +} + +void deserialCopy(void** buffer, void* data, int size) { + memcpy(data, *buffer, size); + *buffer = reinterpret_cast(*buffer) + size; +} + +//DOCS: The server and client MUST use the correct packet types + +//main switch functions +void serializePacket(void* buffer, SerialPacketBase* packet) { + if (BOUNDS(packet->type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) { + serializeServer(buffer, static_cast(packet)); + } + + if (BOUNDS(packet->type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) { + serializeClient(buffer, static_cast(packet)); + } + + if (BOUNDS(packet->type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) { + serializeRegion(buffer, static_cast(packet)); + } + + if (BOUNDS(packet->type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) { + serializeCharacter(buffer, static_cast(packet)); + } + + if (BOUNDS(packet->type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) { + serializeMonster(buffer, static_cast(packet)); + } + + if (BOUNDS(packet->type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) { + serializeText(buffer, static_cast(packet)); + } +} + +void deserializePacket(void* buffer, SerialPacketBase* packet) { + //find the type, so that you can actually deserialize the packet! + SerialPacketType type; + memcpy(&type, buffer, sizeof(SerialPacketType)); + + if (BOUNDS(type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) { + deserializeServer(buffer, static_cast(packet)); + } + + if (BOUNDS(type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) { + deserializeClient(buffer, static_cast(packet)); + } + + if (BOUNDS(type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) { + deserializeRegion(buffer, static_cast(packet)); + } + + if (BOUNDS(type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) { + deserializeCharacter(buffer, static_cast(packet)); + } + + if (BOUNDS(type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) { + deserializeMonster(buffer, static_cast(packet)); + } + + if (BOUNDS(type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) { + deserializeText(buffer, static_cast(packet)); + } +} \ No newline at end of file diff --git a/common/network/serial_utility.hpp b/common/network/serial_utility.hpp new file mode 100644 index 0000000..125379d --- /dev/null +++ b/common/network/serial_utility.hpp @@ -0,0 +1,34 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "serial_packet_base.hpp" + +#include + +//raw memory copy +void serialCopy(void** buffer, void* data, int size); +void deserialCopy(void** buffer, void* data, int size); + +//primary functions +void serializePacket(void* buffer, SerialPacketBase* packet); +void deserializePacket(void* buffer, SerialPacketBase* packet); diff --git a/common/network/udp_network_utility.cpp b/common/network/udp_network_utility.cpp new file mode 100644 index 0000000..ec8733f --- /dev/null +++ b/common/network/udp_network_utility.cpp @@ -0,0 +1,224 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "udp_network_utility.hpp" + +#include "serial_packet.hpp" +#include "serial_utility.hpp" + +#include + +//DOCS: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network +//NOTE: don't confuse SerialPacketBase with UDPpacket + +void UDPNetworkUtility::Open(int port) { + socket = SDLNet_UDP_Open(port); + packet = SDLNet_AllocPacket(PACKET_BUFFER_SIZE); + if (!socket || !packet) { + Close(); + throw(std::runtime_error("Failed to open UDPNetworkUtility")); + } +} + +void UDPNetworkUtility::Close() { + SDLNet_UDP_Close(socket); + SDLNet_FreePacket(packet); + socket = nullptr; + packet = nullptr; +} + +//------------------------- +//bind to a channel +//------------------------- + +int UDPNetworkUtility::Bind(const char* ip, int port, int channel) { + IPaddress add; + if (SDLNet_ResolveHost(&add, ip, port) == -1) { + throw(std::runtime_error("Failed to resolve a host")); + } + + return Bind(add, channel); +} + +int UDPNetworkUtility::Bind(IPaddress add, int channel) { + int ret = SDLNet_UDP_Bind(socket, channel, &add); + + if (ret < 0) { + throw(std::runtime_error("Failed to bind to a channel")); + } + + return ret; +} + +void UDPNetworkUtility::Unbind(int channel) { + SDLNet_UDP_Unbind(socket, channel); +} + +//------------------------- +//send a buffer +//------------------------- + +int UDPNetworkUtility::SendTo(const char* ip, int port, void* data, int len) { + IPaddress add; + if (SDLNet_ResolveHost(&add, ip, port) == -1) { + throw(std::runtime_error("Failed to resolve a host")); + } + + SendTo(add, data, len); +} + +int UDPNetworkUtility::SendTo(IPaddress add, void* data, int len) { + if (len > packet->maxlen) { + throw(std::runtime_error("The buffer is to large for the UDPpacket")); + } + memset(packet->data, 0, packet->maxlen); + memcpy(packet->data, data, len); + packet->len = len; + packet->address = add; + + int ret = SDLNet_UDP_Send(socket, -1, packet); + + if (ret <= 0) { + throw(std::runtime_error("Failed to send a packet")); + } + + return ret; +} + +int UDPNetworkUtility::SendTo(int channel, void* data, int len) { + if (len > packet->maxlen) { + throw(std::runtime_error("The buffer is to large for the UDPpacket")); + } + memset(packet->data, 0, packet->maxlen); + memcpy(packet->data, data, len); + packet->len = len; + + int ret = SDLNet_UDP_Send(socket, channel, packet); + + if (ret <= 0) { + throw(std::runtime_error("Failed to send a packet")); + } + + return ret; +} + +int UDPNetworkUtility::SendToAllChannels(void* data, int len) { + if (len > packet->maxlen) { + throw(std::runtime_error("The buffer is to large for the UDPpacket")); + } + memset(packet->data, 0, packet->maxlen); + memcpy(packet->data, data, len); + packet->len = len; + + int sent = 0; + + //send to all bound channels + for (int i = 0; i < SDLNET_MAX_UDPCHANNELS; i++) { + if (SDLNet_UDP_GetPeerAddress(socket, i)) { + sent += SDLNet_UDP_Send(socket, i, packet); + } + } + + return sent; +} + +int UDPNetworkUtility::Receive() { + memset(packet->data, 0, packet->maxlen); + int ret = SDLNet_UDP_Recv(socket, packet); + + if (ret < 0) { + throw(std::runtime_error("Unknown network error occured")); + } + + return ret; +} + +//------------------------- +//send a SerialPacketBase +//------------------------- + +int UDPNetworkUtility::SendTo(const char* ip, int port, SerialPacketBase* serialPacket) { + IPaddress add; + if (SDLNet_ResolveHost(&add, ip, port) == -1) { + throw(std::runtime_error("Failed to resolve a host")); + } + + SendTo(add, serialPacket); +} + +int UDPNetworkUtility::SendTo(IPaddress add, SerialPacketBase* serialPacket) { + memset(packet->data, 0, packet->maxlen); + serializePacket(packet->data, serialPacket); + packet->len = PACKET_BUFFER_SIZE; + packet->address = add; + + int ret = SDLNet_UDP_Send(socket, -1, packet); + + if (ret <= 0) { + throw(std::runtime_error("Failed to send a packet")); + } + + return ret; +} + +int UDPNetworkUtility::SendTo(int channel, SerialPacketBase* serialPacket) { + memset(packet->data, 0, packet->maxlen); + serializePacket(packet->data, serialPacket); + packet->len = PACKET_BUFFER_SIZE; + + int ret = SDLNet_UDP_Send(socket, channel, packet); + + if (ret <= 0) { + throw(std::runtime_error("Failed to send a packet")); + } + + return ret; +} + +int UDPNetworkUtility::SendToAllChannels(SerialPacketBase* serialPacket) { + memset(packet->data, 0, packet->maxlen); + serializePacket(packet->data, serialPacket); + packet->len = PACKET_BUFFER_SIZE; + + int sent = 0; + + //send to all bound channels + for (int i = 0; i < SDLNET_MAX_UDPCHANNELS; i++) { + if (SDLNet_UDP_GetPeerAddress(socket, i)) { + sent += SDLNet_UDP_Send(socket, i, packet); + } + } + + return sent; +} + +int UDPNetworkUtility::Receive(SerialPacketBase* serialPacket) { + memset(packet->data, 0, packet->maxlen); + int ret = SDLNet_UDP_Recv(socket, packet); + deserializePacket(packet->data, serialPacket); + serialPacket->srcAddress = packet->address; + + if (ret < 0) { + throw(std::runtime_error("Unknown network error occured")); + } + + return ret; +} \ No newline at end of file diff --git a/common/network/udp_network_utility.hpp b/common/network/udp_network_utility.hpp new file mode 100644 index 0000000..6c48ac3 --- /dev/null +++ b/common/network/udp_network_utility.hpp @@ -0,0 +1,74 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +//common +#include "serial_packet_base.hpp" +#include "singleton.hpp" + +//APIs +#include "SDL2/SDL_net.h" + +class UDPNetworkUtility : public Singleton { +public: + void Open(int port); + void Close(); + + //bind to a channel + int Bind(const char* ip, int port, int channel = -1); + int Bind(IPaddress add, int channel = -1); + void Unbind(int channel); + + IPaddress* GetIPAddress(int channel) { + return SDLNet_UDP_GetPeerAddress(socket, channel); + } + + //send a buffer + int SendTo(const char* ip, int port, void* data, int len); + int SendTo(IPaddress add, void* data, int len); + int SendTo(int channel, void* data, int len); + int SendToAllChannels(void* data, int len); + int Receive(); + + //send a SerialPacketBase + int SendTo(const char* ip, int port, SerialPacketBase* serialPacket); + int SendTo(IPaddress add, SerialPacketBase* serialPacket); + int SendTo(int channel, SerialPacketBase* serialPacket); + int SendToAllChannels(SerialPacketBase* serialPacket); + int Receive(SerialPacketBase* serialPacket); + + //accessors + UDPpacket* GetPacket() const { + return packet; + } + UDPsocket GetSocket() const { + return socket; + } +private: + friend Singleton; + + UDPNetworkUtility() = default; + ~UDPNetworkUtility() = default; + + UDPsocket socket = nullptr; + UDPpacket* packet = nullptr; +}; diff --git a/common/utilities/bounding_box.hpp b/common/utilities/bounding_box.hpp new file mode 100644 index 0000000..eba974d --- /dev/null +++ b/common/utilities/bounding_box.hpp @@ -0,0 +1,75 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include +#include + +class BoundingBox { +public: + //This is explicitly a POD + int x, y; + int w, h; + + BoundingBox() = default; + BoundingBox(int i, int j): x(i), y(j), w(0), h(0) {}; + BoundingBox(int i, int j, int k, int l): x(i), y(j), w(k), h(l) {}; + ~BoundingBox() = default; + BoundingBox& operator=(BoundingBox const&) = default; + + int Size() { + return std::max(w*h,0); + } + + bool CheckOverlap(BoundingBox rhs) { + return !( + x >= rhs.x + rhs.w || + y >= rhs.y + rhs.h || + rhs.x >= x + w || + rhs.y >= y + h); + } + + BoundingBox CalcOverlap(BoundingBox rhs) { + if (!CheckOverlap(rhs)) { + return {0, 0, 0, 0}; + } + BoundingBox ret; + ret.x = std::max(x, rhs.x); + ret.y = std::max(y, rhs.y); + ret.w = std::min(x+w, rhs.x+rhs.w) - ret.x; + ret.h = std::min(y+h, rhs.y+rhs.h) - ret.y; + return ret; + } +}; + +//This is explicitly a POD +static_assert(std::is_pod::value, "BoundingBox is not a POD"); + +#include "vector2.hpp" + +//operators +inline BoundingBox operator+(BoundingBox b, Vector2 v) { + return {b.x + (int)v.x, b.y + (int)v.y, b.w, b.h}; +} +inline BoundingBox operator+(Vector2 v, BoundingBox b) { + return b + v; +} diff --git a/common/utilities/config_utility.cpp b/common/utilities/config_utility.cpp new file mode 100644 index 0000000..3161501 --- /dev/null +++ b/common/utilities/config_utility.cpp @@ -0,0 +1,188 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "config_utility.hpp" + +#include +#include +#include +#include +#include + +void ConfigUtility::Load(std::string fname, bool skipMissingFile, int argc, char* argv[]) { + //clear the stored configuration + configMap.clear(); + + //use the default file + if (argc < 2) { + configMap = Read(fname, skipMissingFile); + return; + } + + //some variables to use + table_t redirectedFile; + table_t cmdLineParams; + char key[256], val[256]; + bool redirectUsed = false; + + //reading from the command line + for (int i = 1; i < argc; ++i) { + //read from a specified config file + if (!strncmp(argv[i], "-config=", 8)) { + //older specified files take precedence + table_t tmp = Read(argv[i] + 8, skipMissingFile); + redirectedFile.insert(tmp.begin(), tmp.end()); + redirectUsed = true; + continue; + } + + //set some specific values + if (!strncmp(argv[i], "-", 1)) { + //wipe the variables + memset(key, 0, 256); + memset(key, 0, 256); + + //read the key-value pair + if (sscanf(argv[i], "-%[^=]=%[^\\0]", key, val) != 2) { + std::ostringstream os; + os << "Failed to read a command line config argument (expected -%s=%s):" << std::endl; + os << "\targv[" << i << "]: " << argv[i] << std::endl; + os << "\tkey: " << key << std::endl; + os << "\tval: " << val << std::endl; + throw(std::runtime_error( os.str() )); + } + cmdLineParams[key] = val; + } + } + + //finally, construct the final config table + if (!redirectUsed) { + redirectedFile = Read(fname, skipMissingFile); + } + configMap.insert(cmdLineParams.begin(), cmdLineParams.end()); + configMap.insert(redirectedFile.begin(), redirectedFile.end()); +} + +ConfigUtility::table_t ConfigUtility::Read(std::string fname, bool skipMissingFile) { + //read in and return this file's data + table_t retTable; + std::ifstream is(fname); + + if (!is.is_open()) { + if (skipMissingFile) { + return {}; //empty table + } + std::ostringstream os; + os << "Failed to open a config file: " << fname; + throw(std::runtime_error( os.str() )); + } + + std::string key, val; + + while(true) { //forever + //eat whitespace + while(isspace(is.peek())) { + is.ignore(); + } + + //end of file + if (is.eof()) { + break; + } + + //skip comment lines + if (is.peek() == '#') { + while(is.peek() != '\n' && !is.eof()) { + is.ignore(); + } + continue; + } + + //read in the pair + getline(is, key,'='); + getline(is, val); + + //eat the whitespace at the start & end + while(key.size() && isspace( *key.begin() )) { + key.erase(0, 1); + } + while(val.size() && isspace( *val.begin() )) { + val.erase(0, 1); + } + + while(key.size() && isspace( *(key.end()-1) )) { + key.erase(key.end() - 1); + } + while(val.size() && isspace( *(val.end()-1) )) { + val.erase(val.end() - 1); + } + + //disallow empty/wiped pairs + if (key.size() == 0 || val.size() == 0) { + continue; + } + + //save the pair + retTable[key] = val; + } + + is.close(); + + //load in any subordinate config files + if (retTable.find("config.next") != retTable.end()) { + table_t subTable = Read(retTable["config.next"], skipMissingFile); + retTable.insert(subTable.begin(), subTable.end()); + } + + return retTable; +} + +//------------------------- +//Convert to a type +//------------------------- + +std::string& ConfigUtility::String(std::string s) { + return configMap[s]; +} + +int ConfigUtility::Integer(std::string s) { + table_t::iterator it = configMap.find(s); + if (it == configMap.end()) { + return 0; + } + return atoi(it->second.c_str()); +} + +double ConfigUtility::Double(std::string s) { + table_t::iterator it = configMap.find(s); + if (it == configMap.end()) { + return 0.0; + } + return atof(it->second.c_str()); +} + +bool ConfigUtility::Boolean(std::string s) { + table_t::iterator it = configMap.find(s); + if (it == configMap.end()) { + return false; + } + return it->second == "true"; +} diff --git a/common/utilities/config_utility.hpp b/common/utilities/config_utility.hpp new file mode 100644 index 0000000..cc4f2ea --- /dev/null +++ b/common/utilities/config_utility.hpp @@ -0,0 +1,52 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "singleton.hpp" + +#include +#include + +class ConfigUtility: public Singleton { +public: + void Load(std::string fname, bool skipMissingFile = false, int argc = 0, char* argv[] = nullptr); + + //convert to a type + std::string& String(std::string); + int Integer(std::string); + double Double(std::string); + bool Boolean(std::string); + + //shorthand + inline std::string& operator[](std::string s) { return configMap[s]; } + inline int Int(std::string s) { return Integer(s); } + inline bool Bool(std::string s) { return Boolean(s); } + +private: + typedef std::map table_t; + + friend Singleton; + + table_t Read(std::string fname, bool skipMissingFile); + + table_t configMap; +}; diff --git a/common/utilities/frame_rate.hpp b/common/utilities/frame_rate.hpp new file mode 100644 index 0000000..31970db --- /dev/null +++ b/common/utilities/frame_rate.hpp @@ -0,0 +1,50 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include + +class FrameRate { +public: + typedef std::chrono::high_resolution_clock Clock; + + FrameRate() = default; + + //DOCS: for usage purposes, this returns -1 unless a new framerate value is set + int Calculate() { + frameCount++; + if (Clock::now() - tick >= std::chrono::duration(1)) { + lastFrameRate = frameCount; + frameCount = 0; + tick = Clock::now(); + return lastFrameRate; + } + return -1; + } + + int GetFrameRate() { return lastFrameRate; } + +private: + int frameCount = 0; + int lastFrameRate = 0; + Clock::time_point tick = Clock::now(); +}; diff --git a/common/utilities/ip_operators.cpp b/common/utilities/ip_operators.cpp new file mode 100644 index 0000000..fe3ba48 --- /dev/null +++ b/common/utilities/ip_operators.cpp @@ -0,0 +1,30 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "ip_operators.hpp" + +bool operator==(IPaddress lhs, IPaddress rhs) { + return lhs.host == rhs.host && lhs.port == rhs.port; +} + +bool operator!=(IPaddress lhs, IPaddress rhs) { + return !(lhs == rhs); +} \ No newline at end of file diff --git a/common/utilities/ip_operators.hpp b/common/utilities/ip_operators.hpp new file mode 100644 index 0000000..a3d5b62 --- /dev/null +++ b/common/utilities/ip_operators.hpp @@ -0,0 +1,28 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "SDL2/SDL_net.h" + +//these should've come standard +bool operator==(IPaddress lhs, IPaddress rhs); +bool operator!=(IPaddress lhs, IPaddress rhs); diff --git a/common/utilities/makefile b/common/utilities/makefile new file mode 100644 index 0000000..e6bcb85 --- /dev/null +++ b/common/utilities/makefile @@ -0,0 +1,28 @@ +#config +INCLUDES+=. +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< diff --git a/common/utilities/singleton.hpp b/common/utilities/singleton.hpp new file mode 100644 index 0000000..cba191a --- /dev/null +++ b/common/utilities/singleton.hpp @@ -0,0 +1,60 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include + +template +class Singleton { +public: + static T& GetSingleton() { + if (!ptr) { + throw(std::logic_error("This singleton has not been created")); + } + return *ptr; + } + static void CreateSingleton() { + if (ptr) { + throw(std::logic_error("This singleton has already been created")); + } + ptr = new T(); + } + static void DeleteSingleton() { + if (!ptr) { + throw(std::logic_error("A non-existant singleton cannot be deleted")); + } + delete ptr; + ptr = nullptr; + } + +protected: + Singleton() = default; + Singleton(Singleton const&) = default; + Singleton(Singleton&&) = default; + ~Singleton() = default; + +private: + static T* ptr; +}; + +template +T* Singleton::ptr = nullptr; diff --git a/common/utilities/vector2.hpp b/common/utilities/vector2.hpp new file mode 100644 index 0000000..4441c3e --- /dev/null +++ b/common/utilities/vector2.hpp @@ -0,0 +1,111 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include +#include +#include + +class Vector2 { +public: + double x, y; + + Vector2() = default; + Vector2(double i, double j): x(i), y(j) {}; + ~Vector2() = default; + Vector2& operator=(Vector2 const&) = default; + + double Length() const { + return sqrt(x*x+y*y); + } + double SquaredLength() const { + return x*x+y*y; + } + void Normalize() { + double l = Length(); + if (l == 0) + throw(std::domain_error("Divide by zero")); + x /= l; + y /= l; + } + + //Arithmetic operators + Vector2 operator+(Vector2 v) const { + Vector2 ret; + ret.x = x + v.x; + ret.y = y + v.y; + return ret; + } + Vector2 operator-(Vector2 v) const { + Vector2 ret; + ret.x = x - v.x; + ret.y = y - v.y; + return ret; + } + Vector2 operator*(Vector2 v) const { + Vector2 ret; + ret.x = x * v.x; + ret.y = y * v.y; + return ret; + } + Vector2 operator*(double d) const { + Vector2 ret; + ret.x = x * d; + ret.y = y * d; + return ret; + } + + Vector2 operator/(Vector2 v) { + if (!v.x || !v.y) + throw(std::domain_error("Divide by zero")); + Vector2 ret; + ret.x = x / v.x; + ret.y = y / v.y; + return ret; + } + Vector2 operator/(double d) { + if (!d) + throw(std::domain_error("Divide by zero")); + Vector2 ret; + ret.x = x / d; + ret.y = y / d; + return ret; + } + + //unary operators + Vector2 operator-() { return {-x, -y}; } + + //comparison operators + bool operator==(Vector2 v) { return (x == v.x && y == v.y); } + bool operator!=(Vector2 v) { return (x != v.x || y != v.y); } + + //member templates (curry the above operators) + template Vector2 operator+=(T t) { return *this = *this + t; } + template Vector2 operator-=(T t) { return *this = *this - t; } + template Vector2 operator*=(T t) { return *this = *this * t; } + template Vector2 operator/=(T t) { return *this = *this / t; } + template bool operator==(T t) { return (x == t && y == t); } + template bool operator!=(T t) { return (x != t || y != t); } +}; + +//This is explicitly a POD +static_assert(std::is_pod::value, "Vector2 is not a POD");