From c3a0b6cf1dc66e3a8f5e42ba3372a6d665458343 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 18 Feb 2017 01:46:50 +0100 Subject: [PATCH 01/24] Added tubes logic and epic tubepong The tube demo runs a simple curses based pong, that shall demonstrate the functionality where and why a prediction interface is built. --- libopenage/CMakeLists.txt | 5 +- libopenage/tubes/.gitignore | 31 +++ libopenage/tubes/CMakeLists.txt | 19 ++ libopenage/tubes/README.md | 7 + libopenage/tubes/base.cpp | 9 + libopenage/tubes/base.h | 222 ++++++++++++++++++ libopenage/tubes/container_iterator.cpp | 9 + libopenage/tubes/container_iterator.h | 93 ++++++++ libopenage/tubes/demo/CMakeLists.txt | 19 ++ libopenage/tubes/demo/aicontroller.cpp | 28 +++ libopenage/tubes/demo/aicontroller.h | 21 ++ libopenage/tubes/demo/gamestate.h | 58 +++++ libopenage/tubes/demo/gui.cpp | 149 ++++++++++++ libopenage/tubes/demo/gui.h | 23 ++ libopenage/tubes/demo/main.cpp | 92 ++++++++ libopenage/tubes/demo/physics.cpp | 136 +++++++++++ libopenage/tubes/demo/physics.h | 19 ++ libopenage/tubes/demo/vertex.h | 226 +++++++++++++++++++ libopenage/tubes/event.cpp | 8 + libopenage/tubes/event.h | 8 + libopenage/tubes/eventlist.cpp | 8 + libopenage/tubes/eventlist.h | 8 + libopenage/tubes/filter_iterator.cpp | 8 + libopenage/tubes/filter_iterator.h | 112 +++++++++ libopenage/tubes/object.cpp | 9 + libopenage/tubes/object.h | 14 ++ libopenage/tubes/objectlist.h | 8 + libopenage/tubes/simple_continuous.cpp | 9 + libopenage/tubes/simple_continuous.h | 60 +++++ libopenage/tubes/simple_discrete.cpp | 8 + libopenage/tubes/simple_discrete.h | 35 +++ libopenage/tubes/simple_type.cpp | 9 + libopenage/tubes/simple_type.h | 81 +++++++ libopenage/tubes/test/CMakeLists.txt | 11 + libopenage/tubes/test/test.h | 0 libopenage/tubes/test/test_container.cpp | 188 +++++++++++++++ libopenage/tubes/test/test_serialization.cpp | 16 ++ libopenage/tubes/test/test_tube_types.cpp | 16 ++ libopenage/tubes/tube.cpp | 9 + libopenage/tubes/tube.h | 10 + libopenage/tubes/unordered_map.cpp | 9 + libopenage/tubes/unordered_map.h | 112 +++++++++ openage/testing/testlist.py | 12 +- 43 files changed, 1928 insertions(+), 6 deletions(-) create mode 100644 libopenage/tubes/.gitignore create mode 100644 libopenage/tubes/CMakeLists.txt create mode 100644 libopenage/tubes/README.md create mode 100644 libopenage/tubes/base.cpp create mode 100644 libopenage/tubes/base.h create mode 100644 libopenage/tubes/container_iterator.cpp create mode 100644 libopenage/tubes/container_iterator.h create mode 100644 libopenage/tubes/demo/CMakeLists.txt create mode 100644 libopenage/tubes/demo/aicontroller.cpp create mode 100644 libopenage/tubes/demo/aicontroller.h create mode 100644 libopenage/tubes/demo/gamestate.h create mode 100644 libopenage/tubes/demo/gui.cpp create mode 100644 libopenage/tubes/demo/gui.h create mode 100644 libopenage/tubes/demo/main.cpp create mode 100644 libopenage/tubes/demo/physics.cpp create mode 100644 libopenage/tubes/demo/physics.h create mode 100644 libopenage/tubes/demo/vertex.h create mode 100644 libopenage/tubes/event.cpp create mode 100644 libopenage/tubes/event.h create mode 100644 libopenage/tubes/eventlist.cpp create mode 100644 libopenage/tubes/eventlist.h create mode 100644 libopenage/tubes/filter_iterator.cpp create mode 100644 libopenage/tubes/filter_iterator.h create mode 100644 libopenage/tubes/object.cpp create mode 100644 libopenage/tubes/object.h create mode 100644 libopenage/tubes/objectlist.h create mode 100644 libopenage/tubes/simple_continuous.cpp create mode 100644 libopenage/tubes/simple_continuous.h create mode 100644 libopenage/tubes/simple_discrete.cpp create mode 100644 libopenage/tubes/simple_discrete.h create mode 100644 libopenage/tubes/simple_type.cpp create mode 100644 libopenage/tubes/simple_type.h create mode 100644 libopenage/tubes/test/CMakeLists.txt create mode 100644 libopenage/tubes/test/test.h create mode 100644 libopenage/tubes/test/test_container.cpp create mode 100644 libopenage/tubes/test/test_serialization.cpp create mode 100644 libopenage/tubes/test/test_tube_types.cpp create mode 100644 libopenage/tubes/tube.cpp create mode 100644 libopenage/tubes/tube.h create mode 100644 libopenage/tubes/unordered_map.cpp create mode 100644 libopenage/tubes/unordered_map.h diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index de5ad13240..c87a1a9842 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -33,12 +33,12 @@ add_subdirectory("console") add_subdirectory("coord") add_subdirectory("cvar") add_subdirectory("datastructure") -add_subdirectory("gui") add_subdirectory("error") add_subdirectory("gamestate") +add_subdirectory("gui") add_subdirectory("input") -add_subdirectory("log") add_subdirectory("job") +add_subdirectory("log") add_subdirectory("pathfinding") add_subdirectory("pyinterface") add_subdirectory("renderer") @@ -46,6 +46,7 @@ add_subdirectory("rng") add_subdirectory("shader") add_subdirectory("terrain") add_subdirectory("testing") +add_subdirectory("tubes") add_subdirectory("unit") add_subdirectory("util") diff --git a/libopenage/tubes/.gitignore b/libopenage/tubes/.gitignore new file mode 100644 index 0000000000..5ae0e4943c --- /dev/null +++ b/libopenage/tubes/.gitignore @@ -0,0 +1,31 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +*build* diff --git a/libopenage/tubes/CMakeLists.txt b/libopenage/tubes/CMakeLists.txt new file mode 100644 index 0000000000..101abc31e0 --- /dev/null +++ b/libopenage/tubes/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_library(tube STATIC + base.cpp + container_iterator.cpp + event.cpp + eventlist.cpp + filter_iterator.cpp + object.cpp + simple_continuous.cpp + simple_discrete.cpp + simple_type.cpp + tube.cpp + unordered_map.cpp +) + +set_property(TARGET tube PROPERTY CXX_STANDARD 11) + +add_subdirectory(test) +add_subdirectory(demo) diff --git a/libopenage/tubes/README.md b/libopenage/tubes/README.md new file mode 100644 index 0000000000..bbe5e178c6 --- /dev/null +++ b/libopenage/tubes/README.md @@ -0,0 +1,7 @@ +# tubepong + +An experiment how one can work with tubes and predictionmagic in a stateless physical game engine. + +This is a Pong-like game build on top of tubes. + + diff --git a/libopenage/tubes/base.cpp b/libopenage/tubes/base.cpp new file mode 100644 index 0000000000..162b76c4ad --- /dev/null +++ b/libopenage/tubes/base.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "base.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/base.h b/libopenage/tubes/base.h new file mode 100644 index 0000000000..fa6395c240 --- /dev/null +++ b/libopenage/tubes/base.h @@ -0,0 +1,222 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +#include +#include +#include + +namespace openage { +namespace tube { + +template +class tubeelement; + +/** + * A timely ordered list with several management functions + * + * This class manages different time-based management functions for the double- + * linked list approach that lies underneath. It contains a double-linked list + * to be accessed via a non-accurate timing functionality, this means, that for + * getting a value, not the exact timestamp has to be known, it will always return + * the one closest, less or equal to the requested one. + **/ +template +class tubebase { + tubeelement<_T> *begin = nullptr; + tubeelement<_T> *end = nullptr; + + // TODO create a pool where it might be possible to draw memory from +public: + tubebase(); + + ~tubebase(); + + // Get the last element with e->time <= time + tubeelement<_T> *last(const tube_time_t &time, tubeelement<_T>* hint=nullptr) const; + + // Create a new element and insert it into the tree + tubeelement<_T> *create(const tube_time_t &, const _T& value); + + // Insert a newly ekement into the tree, that has not yet been inserted. + void insert(tubeelement<_T> *, tubeelement<_T> *hint = nullptr); + + // Erase the whole list after this element until the end. + void erase_after(tubeelement<_T> *last_valid); + + // Remove the tubeelement from its container + void erase(tubeelement<_T> *e); +}; + +/** + * A element of the double-linked list tubebase + */ +template +class tubeelement { +friend class tubebase<_T>; +public: + tubeelement *next = nullptr; + tubeelement *prev = nullptr; +private: + // These folks are for tubebase only! + tubeelement(const tube_time_t &time) : + time(time) + {} + + // Contruct it from time and value + tubeelement(const tube_time_t &time, const _T &value) : + time(time), + value(value) + {} + +public: + const tube_time_t time = 0; + _T value = _T(); +}; + + +template +tubebase<_T>::tubebase() { + //Create a default element at -Inf, that can always be dereferenced - so there will by definition never be + //a element that cannot be dereferenced + create(-std::numeric_limits::infinity(), _T()); +} + +template +tubebase<_T>::~tubebase() { + erase_after(begin); + delete(begin); +} + +/** + * Select the element that directly preceedes the given timestamp. + * + * Without a hint, start to iterate at the beginning of the buffer, and return + * the element last element before e->time > time. + * This method returns nullptr, if begin->time > time. + **/ +template +tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hint) const { + tubeelement<_T> *e = hint ? hint : begin; + + if (e == nullptr) { + //throw Error(ERR << "Empty container list!"); + return e; + } + + if (begin->time > time){ + // This will never happen due to the begin->time == -Inf magic! + assert(false); + return nullptr; + } + + // Search in the queue + if (time > e->time) { // the searched element is supposed to be AFTER the hint + // perform the search via ->next + while (e->next != nullptr && time >= e->next->time) { + e = e->next; + } + // e is now one of two options: + // 1. e == end: The last element of the queue was smaller than `time` + // 2. e != end: There was a element with `e->time` > `time` + } else { + // the searched element is supposed to be BEFORE the hint + // perform the search via ->prev + while (e->prev != nullptr && time < e->time) { + e = e->prev; + } + // e is now one of two options: + // 1. e == begin: The time was before every element in the queue + // 2. e != begin: There was an element with `e->time` > `time` + } + + return e; +} + +/** + * Create and insert a new element into this tube + */ +template +tubeelement<_T> *tubebase<_T>::create(const tube_time_t &time, const _T& value) { + // TODO this has to be managed by a memory pool! + auto e = new tubeelement<_T>(time, value); + insert(e); + return e; +} + +/** + * Determine where to insert, and update all references + */ +template +void tubebase<_T>::insert(tubeelement<_T> *e, tubeelement<_T> *hint) { + // There are no elements in the list right now. + if (begin == nullptr) { + begin = e; + end = e; + return; + } + + tubeelement<_T>* at = last(e->time, hint); + + // if "last" cannot point at a location, so there was no element _before_ + // the newly inserted + if (at == nullptr) { + begin->prev = e; + e->next = begin; + begin = e; + } else if (at->next == nullptr || end == at) { + // if next is nullptr, then it has to be at the end, so update the end + at->next = e; + e->prev = at; + end = e; + } else { + // the list is not empty, it is not at the beginning, it is not at the end: + // it has to be in the middle! so we can perform a normal insert + e->next = at->next; + e->prev = at; + at->next->prev = e; + at->next = e; + } +} + + +/** + * Go from the end to the last_valid element, and call erase on all of them + */ +template +void tubebase<_T>::erase_after(tubeelement<_T> *last_valid) { + tubeelement<_T> *e = end; + //Delete from the end to last_valid + while (e != nullptr && e != last_valid) { + tubeelement<_T> *prev = e->prev; + erase(e); + e = prev; + } +} + +/** + * Delete the element from the list and call delete on it. + */ +template +void tubebase<_T>::erase(tubeelement<_T> *e) { + if (e == nullptr) return; + if (begin == e) { + begin = e->next; + } + if (end == e) { + end = e->prev; + } + + if (e->next != nullptr) { + e->next->prev = e->prev; + } + if (e->prev != nullptr) { + e->prev->next = e->next; + } + + delete e; // TODO Memory management magic! +} + +}} // openage::tube diff --git a/libopenage/tubes/container_iterator.cpp b/libopenage/tubes/container_iterator.cpp new file mode 100644 index 0000000000..9d3bbe25b3 --- /dev/null +++ b/libopenage/tubes/container_iterator.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "container_iterator.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/container_iterator.h b/libopenage/tubes/container_iterator.h new file mode 100644 index 0000000000..79955ee72a --- /dev/null +++ b/libopenage/tubes/container_iterator.h @@ -0,0 +1,93 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +#include + +namespace openage { +namespace tube { + +template +class timed_iterator : public std::iterator< std::bidirectional_iterator_tag, _Ty > +{ + typename container::const_iterator base; + int64_t from, to; + time_translator_f time_translator; + +public: + timed_iterator(typename container::const_iterator base, int64_t from, int64_t to, const time_translator_f& time_translator) + : base(base) + , from(from) + , to(to) + , time_translator(time_translator) + {} + + timed_iterator(const timed_iterator &rhs) + : base(rhs.base) + , from(rhs.from) + , to(rhs.to) + , time_translator(rhs.time_translator) + {} + + timed_iterator &operator =(const timed_iterator &rhs) + { + this->base = rhs.base; + this->from = rhs.from; + this->to = rhs.to; + this->time_translator = rhs.time_translator; + return *this; + } + + timed_iterator &operator ++() + { + ++base; + return *this; + } + + //We only want to Iterate forward - so maybe delete this? + timed_iterator &operator --() + { + --base; + return *this; + } + + const _Ty &operator *() const + { + return *base; + } + + const _Ty *operator ->() const + { + return &**base; + } + + tube_time_t time() { + return time_translator(**base); + } + + bool operator ==(const timed_iterator<_Ty, container, time_translator_f> &rhs) const + { + return base == rhs.base; + } + + bool operator !=(const timed_iterator<_Ty, container, time_translator_f> &rhs) const + { + return base != rhs.base; + } + + bool valid() + { + return time() < to; + } + + operator bool() + { + return valid(); + } +}; + +}} // openage::tube diff --git a/libopenage/tubes/demo/CMakeLists.txt b/libopenage/tubes/demo/CMakeLists.txt new file mode 100644 index 0000000000..ea05b607e4 --- /dev/null +++ b/libopenage/tubes/demo/CMakeLists.txt @@ -0,0 +1,19 @@ +set(CURSES_NEED_NCURSES TRUE) +find_package(Curses) + +IF (${CURSES_FOUND}) + + include_directories(${CURSES_INCLUDE_DIR}) + link_libraries (tube ${CURSES_LIBRARIES}) + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -pedantic -Wall -Wextra") + add_executable (tubepong + main.cpp + physics.cpp + gui.cpp + aicontroller.cpp + ) + + set_property(TARGET tubepong PROPERTY CXX_STANDARD 14) +ENDIF() + diff --git a/libopenage/tubes/demo/aicontroller.cpp b/libopenage/tubes/demo/aicontroller.cpp new file mode 100644 index 0000000000..3071a274f7 --- /dev/null +++ b/libopenage/tubes/demo/aicontroller.cpp @@ -0,0 +1,28 @@ +#include "aicontroller.h" + +namespace openage { +namespace tubepong { + +std::vector &AIInput::getInputs( + const PongPlayer &player, + const PongBall &ball, + const tube::tube_time_t &now) { + this->event_cache.clear(); + + auto position = player.position.get(now); + + // Yes i know, there is /3 used - instead of the logical /2 - this is to + // create a small safety boundary of 1/3 for enhanced fancyness + + // Ball is below position + if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { + event_cache.push_back(event(player.id, event::DOWN)); + } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { + // Ball is above position + event_cache.push_back(event(player.id, event::UP)); + } + + return this->event_cache; +} + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/aicontroller.h b/libopenage/tubes/demo/aicontroller.h new file mode 100644 index 0000000000..d00abbed29 --- /dev/null +++ b/libopenage/tubes/demo/aicontroller.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "gamestate.h" + +namespace openage { +namespace tubepong { + +class AIInput { +public: + std::vector &getInputs( + const PongPlayer &player, + const PongBall &ball, + const tube::tube_time_t &now); + +private: + std::vector event_cache; +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/gamestate.h b/libopenage/tubes/demo/gamestate.h new file mode 100644 index 0000000000..7f85c87837 --- /dev/null +++ b/libopenage/tubes/demo/gamestate.h @@ -0,0 +1,58 @@ +#pragma once + + +#include "../simple_continuous.h" +#include "../simple_discrete.h" +#include "../object.h" +#include "vertex.h" + +namespace openage { +namespace tubepong { + +struct event { + int player; + enum state_e { + UP, DOWN, START, IDLE, LOST + } state; + event(int id, state_e s) : player(id), state(s) {} + event() : player(0), state(IDLE) {} +}; + +class PongPlayer : public tube::TubeObject { +public: + PongPlayer() { + speed.set_drop(0, 1); + position.set_drop(0, 0.5); + lives.set_drop(0, 1); + state.set_drop(0, event(0, event::IDLE)); + size.set_drop(0, 0.1); + y = 0; + id = 0; + } + + tube::SimpleDiscrete speed; + tube::SimpleContinuous position; + tube::SimpleDiscrete lives; + tube::SimpleDiscrete state; + tube::SimpleDiscrete size; + float y; + int id; +}; + +class PongBall : public tube::TubeObject { +public: + tube::SimpleDiscrete> speed; + tube::SimpleContinuous> position; +}; + +class PongState { +public: + PongPlayer p1; + PongPlayer p2; + + PongBall ball; + + util::vertex<2, float> resolution; +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.cpp b/libopenage/tubes/demo/gui.cpp new file mode 100644 index 0000000000..6c605bd1e3 --- /dev/null +++ b/libopenage/tubes/demo/gui.cpp @@ -0,0 +1,149 @@ +#include "gui.h" + +#include +#include + +namespace openage { +namespace tubepong { + +std::vector &Gui::getInputs(const PongPlayer &player) { + input_cache.clear(); + event evnt; + evnt.player = player.id; + evnt.state = event::IDLE; + timeout(0); + int c = getch(); + //mvprintw(0,1, "IN: %i", c); + switch (c) { + case KEY_DOWN: + evnt.state = event::DOWN; + input_cache.push_back(evnt); + mvprintw(1,1, "DOWN"); + break; + case KEY_UP: + evnt.state = event::UP; + input_cache.push_back(evnt); + mvprintw(1,1, "UP"); + break; + case ' ': + evnt.state = event::START; + break; + default: + break; + } + + return input_cache; +} + +enum { + COLOR_PLAYER1 = 1, + COLOR_PLAYER2 = 2, + COLOR_BALL = 3, + COLOR_DEBUG = 4, + + COLOR_0 = 5, + COLOR_1 = 6, + COLOR_2 = 7, + COLOR_3 = 8, + COLOR_4 = 9, +}; + +Gui::Gui() { + initscr(); + start_color(); + init_pair(COLOR_PLAYER1, COLOR_BLUE,COLOR_BLUE); + init_pair(COLOR_PLAYER2, COLOR_RED,COLOR_RED); + init_pair(COLOR_BALL , COLOR_BLUE,COLOR_WHITE); + init_pair(COLOR_DEBUG , COLOR_WHITE,COLOR_BLACK); + init_pair(COLOR_0, COLOR_RED ,COLOR_BLACK); + init_pair(COLOR_1, COLOR_GREEN ,COLOR_BLACK); + + keypad(stdscr,true); + noecho(); + curs_set(0); +// getmaxyx(stdscr,state.resolution[1], state.resolution[0]); + + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw(4,5," oooooooooo "); + mvprintw(5,5," 888 888 ooooooo ooooooo oooooooo8 "); + mvprintw(6,5," 888oooo88 888 888 888 888 888 88o "); + mvprintw(7,5," 888 888 888 888 888 888oo888o "); + mvprintw(8,5," o888o 88ooo88 o888o o888o 88 888 "); + mvprintw(9,5," 888ooo888 "); + attroff(COLOR_PAIR(COLOR_DEBUG)); + + getch(); +} + +void Gui::draw(PongState &state, const tube::tube_time_t &now) { + erase(); +// clear(); +//Print Score + attron(COLOR_PAIR(COLOR_DEBUG)); + getmaxyx(stdscr, state.resolution[1], state.resolution[0]); + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw(2, state.resolution[0]/2-5, "P1 %i | P2 %i", + state.p1.lives(now), + state.p2.lives(now)); + + mvvline(0, state.resolution[0]/2, ACS_VLINE, state.resolution[1]); + mvprintw(0, 1, "NOW: %f", now); + mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); + mvprintw(2, 1, "P1: %f, %f, %i", state.p1.position(now), state.p1.y, state.p1.state(now).state); + mvprintw(3, 1, "P2: %f, %f, %i", state.p2.position(now), state.p2.y, state.p2.state(now).state); + for (int i = 0; i < 1000; i += 100) { + mvprintw(4 + i / 100, 1, "BALL in %03i: %f | %f; SPEED: %f | %f", + i, + state.ball.position(now + i)[0], + state.ball.position(now + i)[1], + state.ball.speed(now + i)[0], + state.ball.speed(now + i)[1]); + } + + attroff(COLOR_PAIR(COLOR_DEBUG)); + + attron(COLOR_PAIR(COLOR_PLAYER1)); + for(int i=-state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { + mvprintw(state.p1.position(now)+i, + state.p1.y,"|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER1)); + + attron(COLOR_PAIR(COLOR_PLAYER2)); + for(int i=-state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { + mvprintw(state.p2.position(now)+i, + state.p2.y,"|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER2)); + + for (int i = 0; i < 9999; ++i) { + draw_ball(state.ball.position(now + i * 50), i); + } + +/*attron(COLOR_PAIR(COLOR_BALL)); + mvprintw(state.ball.position(now)[1], + state.ball.position(now)[0], + "o"); +*/ + attroff(COLOR_PAIR(COLOR_BALL)); + refresh(); +} + +void Gui::draw_ball(util::vertex<2, float> pos, int idx) { + switch(idx) { + case 0: + attron(COLOR_PAIR(COLOR_0)); + break; + default: + case 1: + attron(COLOR_PAIR(COLOR_1)); + break; + } + + mvprintw((int)(pos[1]), + (int)(pos[0]), + "\xfe"); + standend(); +} + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.h b/libopenage/tubes/demo/gui.h new file mode 100644 index 0000000000..31d50b8b11 --- /dev/null +++ b/libopenage/tubes/demo/gui.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "gamestate.h" + +namespace openage { +namespace tubepong { + + +class Gui { + +public: + Gui(); + std::vector &getInputs(const PongPlayer &player); + void draw(PongState &state, const tube::tube_time_t &now); + void draw_ball(util::vertex<2, float> ball, int idx); + +private: + std::vector input_cache; +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/main.cpp b/libopenage/tubes/demo/main.cpp new file mode 100644 index 0000000000..3dff3136df --- /dev/null +++ b/libopenage/tubes/demo/main.cpp @@ -0,0 +1,92 @@ +#include + +#include + +#include + +#include "gamestate.h" +#include "physics.h" +#include "gui.h" +#include "aicontroller.h" + +using namespace openage; + +typedef std::chrono::high_resolution_clock Clock; + +int main() { + // Restart forever + tubepong::Gui gui; + tubepong::Physics phys; + tubepong::AIInput ai; + bool running = true; + + while (running) { + tubepong::PongState state; + tube::tube_time_t now = 1; + + + state.p1.lives.set_drop(now, 3); + state.p1.id = 0; + state.p1.size.set_drop(now, 4); + state.p2.lives.set_drop(now, 3); + state.p2.id = 1; + state.p2.size.set_drop(now, 4); + + auto init_speed = vertex2f( + ((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, + 0.01f * (rand() % 100) / 70.f); + + gui.draw(state, now); //update gui related parameters + + state.ball.speed.set_drop(now, init_speed); + state.ball.position.set_drop(now, state.resolution * 0.5); + state.p1.position.set_drop(now, state.resolution[1] / 2); + state.p2.position.set_drop(now, state.resolution[1] / 2); + + gui.draw(state, now); //initial drawing with corrected ball + + auto loop_start = Clock::now(); +// std::cout << "1" << std::endl; + now += 1; + std::cout << "p1: " << state.p1.lives.get(now) << " p2 " << state.p2.lives.get(now) << std::endl; + + + while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { +#ifdef HUMAN + phys.processInput( + state, + state.p1, + gui.getInputs(state.p1), + now + ); +#else + phys.processInput( + state, + state.p1, + ai.getInputs(state.p1, state.ball, now), + now + ); +#endif + phys.processInput( + state, + state.p2, + ai.getInputs(state.p2, state.ball, now), + now + ); + + + state.p1.y = 0; + state.p2.y = state.resolution[0]-1; + + phys.update(state, now); + +// std::cout << now << std::endl; + gui.draw(state, now); + usleep(10000); + + // double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); + now += 10; //dt; + loop_start = Clock::now(); + } + } +} diff --git a/libopenage/tubes/demo/physics.cpp b/libopenage/tubes/demo/physics.cpp new file mode 100644 index 0000000000..9ff1b4b6dc --- /dev/null +++ b/libopenage/tubes/demo/physics.cpp @@ -0,0 +1,136 @@ +#include "physics.h" + +#include + +#include + +namespace openage { +namespace tubepong { + +const float extrapolating_time = 100.0f; +const int init_recursion_limit = 50; + +void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const tube::tube_time_t &now) { + for (auto evnt : events) { + //Process only if the future has changed + if (player.state.get(now).state != evnt.state) { + player.state.set_drop(now, evnt); + + switch(evnt.state) { + case event::UP: + case event::DOWN: { + if (evnt.state == event::UP) { + player.speed.set_drop(now, -2); + } else if (evnt.state == event::DOWN) { + player.speed.set_drop(now, 2); + } + player.speed.set_drop(now + extrapolating_time, 0); + + float new_pos = player.position.get(now) + + (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); + if (new_pos < 0) + new_pos = 0; + if (new_pos > state.resolution[1]) + new_pos = state.resolution[1]; + + player.position.set_drop(now+extrapolating_time, new_pos); + evnt.state = event::IDLE; + player.state.set_drop(now + extrapolating_time, evnt); + break; + } + case event::IDLE: + player.position.set_drop(now+extrapolating_time, + player.position.get(now)); + break; + case event::START: + if (player.state.get(now).state == event::LOST) { + state.ball.position.set_drop(now, state.resolution * 0.5); + } + update_ball(state, now, init_recursion_limit); + break; + default: + break; + } + } + } +} + +void Physics::update(PongState &state, const tube::tube_time_t &now) { + + + auto pos = state.ball.position.get(now); + //Handle panel p1 + if (pos[0] <= 1 + && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 + && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 + && state.ball.speed.get(now)[0] < 0) { + //Ball hit the paddel in this frame + auto s = state.ball.speed.get(now); + s[0] *= -1.0; + state.ball.speed.set_drop(now, s); + state.ball.position.set_drop(now, pos); // this line can handle the future! + + update_ball(state, now, init_recursion_limit); + } else if (pos[0] >= state.resolution[0] - 1 + && pos[1] > state.p2.position.get(now) - state.p2.size.get(now) / 2 + && pos[1] < state.p2.position.get(now) + state.p2.size.get(now) / 2 + && state.ball.speed.get(now)[0] > 0) { + //Ball hit the paddel in this frame + auto s = state.ball.speed.get(now); + s[0] *= -1.0; + state.ball.speed.set_drop(now, s); + state.ball.position.set_drop(now, pos); // this line can handle the future! + + update_ball(state, now, init_recursion_limit); + } else if (state.ball.position.needs_update(now)) { + update_ball(state, now, init_recursion_limit); + } + + // Game loose condition + if (pos[0] < 0) { + state.p1.lives.set_drop(now, state.p1.lives.get(now) - 1); + state.p1.state.set_drop(now, event(state.p1.id, event::LOST)); + } + if (pos[0] > state.resolution[0]) { + state.p2.lives.set_drop(now, state.p2.lives.get(now) - 1); + state.p2.state.set_drop(now, event(state.p2.id, event::LOST)); + } + +} + + +void Physics::update_ball(PongState &state, const tube::tube_time_t &now, int recursion_limit) { + //calculate the ball takes to hit a wall. + auto speed = state.ball.speed.get(now); + auto pos = state.ball.position.get(now); + + float ty = 0; + //char mode = ' '; + if (speed [1] > 0) { + ty = (state.resolution[1] - pos[1]) / speed[1]; + //mode = 'v'; + } else if (speed[1] < 0) { + ty = pos[1] / -speed[1]; + //mode = '^'; + } + +/* mvprintw(20 - recursion_limit, 1, "R %i: %c TY %f | pos: %f | %f speed %f | %f res %i | %i", + init_recursion_limit - recursion_limit, mode, + ty, + pos[0], pos[1], + speed[0], speed[1], + state.resolution[0], state.resolution[1] + ); +*/ + if (ty > 0) { + auto hit_pos = pos + speed * ty; + state.ball.position.set_drop(now + ty, hit_pos); + speed[1] *= -1; + state.ball.speed.set_drop(now + ty, speed); + if (recursion_limit > 1) { + update_ball(state, now + ty, recursion_limit - 1); + } + } +} + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/physics.h b/libopenage/tubes/demo/physics.h new file mode 100644 index 0000000000..8a8798bde9 --- /dev/null +++ b/libopenage/tubes/demo/physics.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "gamestate.h" +#include "../tube.h" + +namespace openage { +namespace tubepong { + +class Physics { +public: + void processInput(PongState &, PongPlayer &, std::vector &events, const tube::tube_time_t &now); + void update(PongState &, const tube::tube_time_t &); +protected: + void update_ball(PongState &, const tube::tube_time_t &, int recursion_limit); +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/vertex.h b/libopenage/tubes/demo/vertex.h new file mode 100644 index 0000000000..3e42238598 --- /dev/null +++ b/libopenage/tubes/demo/vertex.h @@ -0,0 +1,226 @@ +#ifndef VERTEX_H +#define VERTEX_H + +#include +#include +#include +#include +#include + +namespace util { + /** + * N-Dimensional vertex of basetype B. + * is used in GFX, world, every POINT can be converted to evth. + * + * Speciality about this version: + * You cannot have a dimension > 4 with a vertex(a,b,c) ctor! + * + * Version 1.4 ( 30. December 2012 ) + * (c) Johannes Walcher, all rights reserved + * NOT COMPATIBLE WITH VERSIONS < 1.0!! + */ + template + class vertex { + private: + _T f[_DIM]; + public: + vertex() { + memset(f, 0, _DIM*sizeof(_T)); + }; + + vertex(_T s[_DIM]) { + memcpy(f, s, _DIM*sizeof(_T)); + }; + + vertex(const vertex<_DIM, _T> &s) { + memcpy(f, s.f, _DIM*sizeof(_T)); + }; + + /** + * Now this can be used as vertex(_T, _T, _T) + */ + //Initialising the first 4 ctors + vertex(_T fst) { + f[0] = fst; + } + vertex(_T fst, _T snd) { + + if (_DIM < 2) { + printf("vertex has too few dimensions"); + throw std::exception(); + } + f[0] = fst; + f[1] = snd; + } + vertex(_T fst, _T snd, _T trd) { + if (_DIM < 3) { + printf("vertex has too few dimensions"); + throw std::exception(); + } + f[0] = fst; + f[1] = snd; + f[2] = trd; + } + vertex(_T arg1, _T arg2, _T arg3, _T arg4) { + if (_DIM < 4) { + printf("vertex has too few dimensions"); + throw std::exception(); + } + f[0] = arg1; + f[1] = arg2; + f[2] = arg3; + f[4] = arg4; + } + + template + vertex<_DIM, _T> &operator=(const vertex<_DIM, _Rhs_Type> &rhs) + { + for (int i= 0; i < _DIM; i++) { + f[i] = (_T)rhs[i]; + } + return *this; + } + + /* + vertex (_T first, ...) + { + f[0] = first; + int n = _DIM; + if (_DIM > 1) { + va_list params; // Zugriffshandle für Parameter + va_start(params, n); // Zugriff vorbereiten + for (int i = 1; i <_DIM; ++i) { + f[i] = va_arg(params, _T); + } + va_end(params); + } + }; + */ + float length() const { + _T sum = 0; + for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; + return sqrt((float)sum); + } + + double d_length() const { + double sum = 0; + for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; + return sqrt((double)sum); + } + + + void normalize() { + float l = length(); + for (int i = 0; i < _DIM; ++i) + f[i] = (_T)(f[i]/l); + } + + _T at(unsigned int p) const { + if (p < _DIM) return f[p]; + else { + printf("Vertex index out of bounds"); + throw std::exception(); + } + } + + operator vertex<_DIM+1, _T>() + { + vertex<_DIM+1, _T> v; + memcpy(&v[0], f, _DIM*sizeof(_T)); + v[_DIM] = 0; + return v; + } + + _T operator[](unsigned int p) const{ + return f[p]; + } + + _T& operator[](unsigned int p) { + return f[p]; + } + + bool operator == (const vertex<_DIM, _T>& s) const { + for (int i = 0; i < _DIM; ++i) { + if (f[i] != s.f[i]) + return false; + } + return true; + }; + + bool operator < (const vertex<_DIM, _T>& s) const { + for (int i = 0; i < _DIM; ++i) { + if (f[i] >= s.f[i]) + return false; + } + return true; + }; + + vertex<_DIM, _T> operator+ (const vertex<_DIM, _T>& rhs) const { + vertex<_DIM, _T> v(*this); + v += rhs; + return v; + }; + + vertex<_DIM, _T>& operator+= (const vertex<_DIM, _T>& s) { + for (int i = 0; i < _DIM; ++i) + f[i] += s.f[i]; + return *this; + }; + + vertex<_DIM, _T> operator- (const vertex<_DIM, _T>& rhs) const { + vertex<_DIM, _T> v(*this); + v -= rhs; + return v; + }; + + vertex<_DIM, _T>& operator-= (const vertex<_DIM, _T>& s) { + for (int i = 0; i < _DIM; ++i) + f[i] -= s.f[i]; + return *this; + }; + + template + vertex<_DIM, _T> operator* (const _RHS &d) const { + vertex<_DIM, _T> r; + for (int i = 0; i < _DIM; ++i) + r[i] = _T(f[i] * d); + return r; + } + + template + operator vertex<_DIM, _RHS> () { + vertex<_DIM, _RHS> r; + for (int i = 0; i < _DIM; ++i) + r[i] = _RHS(f[i]); + return r; + } + + _T dot(const vertex<_DIM, _T> &v) const { + _T r = _T(); + for (int i = 0; i < _DIM; i++) { + r += f[i] * v.f[i]; + } + return r; + } + + vertex<_DIM, _T> cross(const vertex<_DIM, _T> &rhs) const { + vertex<_DIM, _T> v; + + v[0] = f[1]*rhs[2] - f[2]*rhs[1]; + v[1] = f[2]*rhs[0] - f[0]*rhs[2]; + v[2] = f[0]*rhs[1] - f[1]*rhs[0]; + + return v; + } + + }; +} + +typedef util::vertex<2, int> vertex2i; +typedef util::vertex<3, int> vertex3i; +typedef util::vertex<2, float> vertex2f; +typedef util::vertex<3, double> vertex3d; +typedef util::vertex<3, float> vertex3f; + +#endif + diff --git a/libopenage/tubes/event.cpp b/libopenage/tubes/event.cpp new file mode 100644 index 0000000000..30ee97e83b --- /dev/null +++ b/libopenage/tubes/event.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "event.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/event.h b/libopenage/tubes/event.h new file mode 100644 index 0000000000..2be20e6b2a --- /dev/null +++ b/libopenage/tubes/event.h @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/eventlist.cpp b/libopenage/tubes/eventlist.cpp new file mode 100644 index 0000000000..e0e67ddf62 --- /dev/null +++ b/libopenage/tubes/eventlist.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "eventlist.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/eventlist.h b/libopenage/tubes/eventlist.h new file mode 100644 index 0000000000..2be20e6b2a --- /dev/null +++ b/libopenage/tubes/eventlist.h @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.cpp b/libopenage/tubes/filter_iterator.cpp new file mode 100644 index 0000000000..790dec54b1 --- /dev/null +++ b/libopenage/tubes/filter_iterator.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "filter_iterator.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.h b/libopenage/tubes/filter_iterator.h new file mode 100644 index 0000000000..5e385a758c --- /dev/null +++ b/libopenage/tubes/filter_iterator.h @@ -0,0 +1,112 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include + +#include "tube.h" + +namespace openage { +namespace tube { + +template +class tube_iterator{ +public: + virtual val_t &value() = 0; + virtual bool valid() = 0; +}; + +template +class tube_filter_iterator : + public std::iterator< std::bidirectional_iterator_tag, std::pair >, + public tube_iterator +{ +protected: +// typename container_t::const_iterator base; + typename container_t::iterator base; + + tube_time_t now; + +public: + tube_filter_iterator(const typename container_t::const_iterator &base, const tube_time_t &now) + : base(base) + , now(now) + {} + + tube_filter_iterator(const tube_filter_iterator &rhs) + : base(rhs.base) + , now(rhs.now) + {} + + tube_filter_iterator &operator =(const tube_filter_iterator &rhs) + { + this->base = rhs.base; + this->now = rhs.now; + return *this; + } + + tube_filter_iterator &operator ++() + { + do { + ++base; + } while (base->second.alive > time && base->second.dead < time); + + return *this; + } + + //We only want to Iterate forward - so maybe delete this? + //timed_iterator &operator --() + //{ + // --base; + // return *this; + //} + + std::pair &operator *() const + { + return *base; + } + + std::pair *operator ->() const + { + return &**this; + } + + virtual bool operator ==(const tube_filter_iterator &rhs) const + { + return rhs.now == std::numeric_limits::infinity() + && base == rhs.base; + } + + virtual bool operator !=(const tube_filter_iterator &rhs) const + { + return rhs.now != std::numeric_limits::infinity() + && base != rhs.base; + } + + virtual bool valid() + { + return base->second.alive > now; + } + + operator bool() + { + return valid(); + } +}; + +template +class tube_filter_end_iterator : public tube_filter_iterator { +public: + tube_filter_end_iterator(const typename container_t::const_iterator &base) + : tube_filter_iterator(base, std::numeric_limits::infinity()) + {} + + virtual bool valid() { + return false; + } +}; + +}} // openage::tube diff --git a/libopenage/tubes/object.cpp b/libopenage/tubes/object.cpp new file mode 100644 index 0000000000..14a167cb59 --- /dev/null +++ b/libopenage/tubes/object.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "object.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/object.h b/libopenage/tubes/object.h new file mode 100644 index 0000000000..40f5566a72 --- /dev/null +++ b/libopenage/tubes/object.h @@ -0,0 +1,14 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +namespace openage { +namespace tube { + +class TubeObject { +public: +}; + +}} // openage::tube diff --git a/libopenage/tubes/objectlist.h b/libopenage/tubes/objectlist.h new file mode 100644 index 0000000000..2be20e6b2a --- /dev/null +++ b/libopenage/tubes/objectlist.h @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/simple_continuous.cpp b/libopenage/tubes/simple_continuous.cpp new file mode 100644 index 0000000000..1bbbe6452c --- /dev/null +++ b/libopenage/tubes/simple_continuous.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "simple_continuous.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/simple_continuous.h b/libopenage/tubes/simple_continuous.h new file mode 100644 index 0000000000..bf1a1ed9d8 --- /dev/null +++ b/libopenage/tubes/simple_continuous.h @@ -0,0 +1,60 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "simple_type.h" + +namespace openage { +namespace tube { + +template +class SimpleContinuous : public SimpleType<_T> { + mutable tube_time_t diff_time; + mutable tube_time_t offset; + +public: + void set_now(const tube_time_t &t) const override; + + _T get() const override; + _T get(const tube_time_t &) const override; + +public: +}; + +template +void SimpleContinuous<_T>::set_now(const tube_time_t &t) const { + SimpleType<_T>::set_now(t); + if (this->e_now == nullptr) { // TODO This Sucks! + diff_time = 0; + offset = 1; + } else { + if (this->e_now->next != nullptr) { + diff_time = this->e_now->next->time - this->e_now->time; + } else { + diff_time = 0; + } + offset = t - this->e_now->time; + } +} + +template +_T SimpleContinuous<_T>::get() const { + double elapsed_frac = (double)offset / (double)diff_time ; + if (this->e_now == nullptr) { //TODO This Sucks! + return _T(); + } else if (this->e_now->next == nullptr || offset == 0) { + return this->e_now->value; //If we cannot interpolate, treat as standing still (?) + } else { + return this->e_now->value + (this->e_now->next->value - this->e_now->value) * elapsed_frac; + } +} + +template +_T SimpleContinuous<_T>::get(const tube_time_t &time) const { + this->set_now(time); + return get(); +} + + +}} // openage::tube + diff --git a/libopenage/tubes/simple_discrete.cpp b/libopenage/tubes/simple_discrete.cpp new file mode 100644 index 0000000000..3b39b4ec99 --- /dev/null +++ b/libopenage/tubes/simple_discrete.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "simple_discrete.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/simple_discrete.h b/libopenage/tubes/simple_discrete.h new file mode 100644 index 0000000000..91406cdcfe --- /dev/null +++ b/libopenage/tubes/simple_discrete.h @@ -0,0 +1,35 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "simple_type.h" + +namespace openage { +namespace tube { + +template +class SimpleDiscrete : public SimpleType<_T> { +public: + + _T get() const override; + _T get(const tube_time_t &) const override; +public: +}; + +template +_T SimpleDiscrete<_T>::get() const { + if (this->e_now == nullptr) { // TODO THIS SUCKS! + return _T(); + } else { + return this->e_now->value; + } +} + +template +_T SimpleDiscrete<_T>::get(const tube_time_t &time) const { + this->set_now(time); + return this->get(); +} + +}} // openage::tube + diff --git a/libopenage/tubes/simple_type.cpp b/libopenage/tubes/simple_type.cpp new file mode 100644 index 0000000000..1d845a6b3f --- /dev/null +++ b/libopenage/tubes/simple_type.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "simple_type.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/simple_type.h b/libopenage/tubes/simple_type.h new file mode 100644 index 0000000000..348ba2b97f --- /dev/null +++ b/libopenage/tubes/simple_type.h @@ -0,0 +1,81 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "base.h" + +namespace openage { +namespace tube { + +template +class SimpleType { +protected: + tubebase<_T> container; + mutable tubeelement<_T> *e_now; + mutable tube_time_t now; + +public: + SimpleType(); + + // Reader mode + virtual void set_now(const tube_time_t &t) const; + + virtual _T get() const = 0; + virtual _T get(const tube_time_t &t) const; + + virtual _T operator ()() const { + return std::move(get()); + } + + virtual _T operator ()(const tube_time_t &now) { + return std::move(get(now)); + } + + virtual bool needs_update(const tube_time_t &at); +public: + // Inserter mode + void set_drop(const tube_time_t &at, const _T &value); + void set_insert(const tube_time_t &at, const _T &value); +}; + +template +SimpleType<_T>::SimpleType() : + e_now(nullptr), + now() +{} + +template +void SimpleType<_T>::set_now(const tube_time_t &t) const { + now = t; + e_now = container.last(t, e_now); +} + +template +_T SimpleType<_T>::get(const tube_time_t &t) const { + set_now(t); + return get(); +} + +template +void SimpleType<_T>::set_drop(const tube_time_t &at, const _T &value) { + container.erase_after(container.last(at, e_now)); + container.create(at, value); +} + +template +void SimpleType<_T>::set_insert(const tube_time_t &at, const _T &value) { + container.create(at, value); +} + +template +bool SimpleType<_T>::needs_update(const tube_time_t &at) { + auto e = container.last(at, e_now); //TODO take container.end as a hint? + if (e->time > at || e->next == nullptr || e->next->time > at) { + return true; + } else { + return false; + } +} + +}} // openage::tube + diff --git a/libopenage/tubes/test/CMakeLists.txt b/libopenage/tubes/test/CMakeLists.txt new file mode 100644 index 0000000000..f1bbbca333 --- /dev/null +++ b/libopenage/tubes/test/CMakeLists.txt @@ -0,0 +1,11 @@ +link_libraries(tube) + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") + +add_sources(libopenage + test_container.cpp + test_tube_types.cpp + test_serialization.cpp +) + diff --git a/libopenage/tubes/test/test.h b/libopenage/tubes/test/test.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libopenage/tubes/test/test_container.cpp b/libopenage/tubes/test/test_container.cpp new file mode 100644 index 0000000000..49586d705b --- /dev/null +++ b/libopenage/tubes/test/test_container.cpp @@ -0,0 +1,188 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "../../testing/testing.h" +#include "../base.h" +#include "../container_iterator.h" +#include "../tube.h" +#include "../simple_continuous.h" +#include "../simple_discrete.h" + +namespace openage { +namespace tube { +namespace tests { + +class test_tube_element { +public: + test_tube_element(tube_time_t t, int32_t data) : + time(t), + data(data) + {} + + tube_time_t time; + int32_t data; +}; + +tube_time_t timer (const test_tube_element &t) { + return t.time; +} + +void container() { + // Check the base container type + { + tubebase c; + auto p0 = c.create(0, 0); + auto p1 = c.create(1, 1); + auto p2 = c.create(10, 2); + + // last function tests without hints + TESTEQUALS(c.last(0)->value, 0); + TESTEQUALS(c.last(1)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5)->value, 1); + TESTEQUALS(c.last(10)->value, 2); + TESTEQUALS(c.last(47)->value, 2); + + // last() with hints. Yes this can make a difference. we want to be + // absolutely shure! + // hint p1 + TESTEQUALS(c.last(0, p0)->value, 0); + TESTEQUALS(c.last(1, p0)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p0)->value, 1); + TESTEQUALS(c.last(10, p0)->value, 2); + TESTEQUALS(c.last(47, p0)->value, 2); + + TESTEQUALS(c.last(0, p1)->value, 0); + TESTEQUALS(c.last(1, p1)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p1)->value, 1); + TESTEQUALS(c.last(10, p1)->value, 2); + TESTEQUALS(c.last(47, p1)->value, 2); + + TESTEQUALS(c.last(0, p2)->value, 0); + TESTEQUALS(c.last(1, p2)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p2)->value, 1); + TESTEQUALS(c.last(10, p2)->value, 2); + TESTEQUALS(c.last(47, p2)->value, 2); + + // Now test the basic erase() function + c.erase(c.last(1)); + + TESTEQUALS(c.last(1)->value, 0); + TESTEQUALS(c.last(5)->value, 0); + TESTEQUALS(c.last(47)->value, 2); + + c.erase_after(c.last(99)); // we dont want to have the element itself erased! + TESTEQUALS(c.last(47)->value, 2); + + c.erase_after(c.last(5)); // now since 10 > 5, element with value 2 has to be gone + TESTEQUALS(c.last(47)->value, 0); + } + + // Check the Simple Continuous type + { + SimpleContinuous c; + c.set_insert(0, 0); + c.set_insert(10, 1); + + c.set_now(0); + TESTEQUALS(c.get(), 0); + + c.set_now(1); + TESTEQUALS_FLOAT(c.get(), 0.1, 1e-7); + } + + { + SimpleContinuous c; + c.set_insert(0, 0); + c.set_insert(10, 10); + + c.set_now(0); + TESTEQUALS(c.get(), 0); + + c.set_now(1); + TESTEQUALS(c.get(), 1); + } + //Check the discrete type + { + SimpleDiscrete c; + c.set_insert(0, 0); + c.set_insert(10, 10); + + c.set_now(0); + TESTEQUALS(c.get(), 0); + + c.set_now(1); + TESTEQUALS(c.get(), 0); + + c.set_now(11); + TESTEQUALS(c.get(), 10); + } + + //check set_drop + { + SimpleDiscrete c; + c.set_insert(0, 0); + c.set_insert(1, 1); + c.set_insert(3, 3); + + c.set_now(3); + TESTEQUALS(c.get(), 3); + + c.set_drop(2, 10); + c.set_now(3); + TESTEQUALS(c.get(), 10); + } + + // Iterate tests +/* { + Container container(timer); + + container.insert(std::make_shared(test_tube_element(10, 0))); + container.insert(std::make_shared(test_tube_element(20, 1))); + + // Iterate over everything with boundaries + { + auto it = container.iterate(0, 30); + TESTEQUALS(it.valid(), true); + + TESTEQUALS(it->data, 0); + ++it; + TESTEQUALS(it.valid(), true); + + TESTEQUALS(it->data, 1); + ++it; + TESTEQUALS(it.valid(), false); + + } + + // Iterate only over the first, with boundaries + { + auto it = container.iterate(0, 15); + TESTEQUALS(it.valid(), true); + TESTEQUALS(it->data, 0); + ++it; + TESTEQUALS(it.valid(), false); + } + + // Iterate only over the first, without boundaries + { + auto it = container.iterate(10, 11); + TESTEQUALS(it.valid(), true); + TESTEQUALS(it->data, 0); + ++it; + TESTEQUALS(it.valid(), false); + } + + // Iterate out of boundaries + { + auto it = container.iterate(100, 200); + TESTEQUALS(it.valid(), false); + } + } + + // Some fucked up insert and read stuff, create all the bugs. + { + // TODO have more ideas to fuck up our data structures + }*/ +} + + +}}} // openage::tube::tests diff --git a/libopenage/tubes/test/test_serialization.cpp b/libopenage/tubes/test/test_serialization.cpp new file mode 100644 index 0000000000..a33e2a7aee --- /dev/null +++ b/libopenage/tubes/test/test_serialization.cpp @@ -0,0 +1,16 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "test.h" + +#include "../../testing/testing.h" + +namespace openage { +namespace tube { +namespace tests { + +void serialization() { + +} + +}}} // openage::tube::tests + diff --git a/libopenage/tubes/test/test_tube_types.cpp b/libopenage/tubes/test/test_tube_types.cpp new file mode 100644 index 0000000000..c5e4a098d0 --- /dev/null +++ b/libopenage/tubes/test/test_tube_types.cpp @@ -0,0 +1,16 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "test.h" + + +#include "../../testing/testing.h" + +namespace openage { +namespace tube { +namespace tests { + +void tube_types() { + +} + +}}} // openage::tube::tests diff --git a/libopenage/tubes/tube.cpp b/libopenage/tubes/tube.cpp new file mode 100644 index 0000000000..378783bb1b --- /dev/null +++ b/libopenage/tubes/tube.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "tube.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/tube.h b/libopenage/tubes/tube.h new file mode 100644 index 0000000000..0061659228 --- /dev/null +++ b/libopenage/tubes/tube.h @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +typedef float tube_time_t; + +}} // openage::tube diff --git a/libopenage/tubes/unordered_map.cpp b/libopenage/tubes/unordered_map.cpp new file mode 100644 index 0000000000..58b6227d2f --- /dev/null +++ b/libopenage/tubes/unordered_map.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "unordered_map.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/unordered_map.h b/libopenage/tubes/unordered_map.h new file mode 100644 index 0000000000..830cb21309 --- /dev/null +++ b/libopenage/tubes/unordered_map.h @@ -0,0 +1,112 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "base.h" +#include "tube.h" +#include "filter_iterator.h" + +namespace openage { +namespace tube { + +template +class UnorderedTubeMap { + struct map_element { + key_t key; + tubebase value; + tube_time_t alive; + tube_time_t dead; + }; + std::unordered_map container; + +public: + val_t &operator()(const tube_time_t&, const key_t &); + val_t &at(const tube_time_t &, const key_t &); + + tube_filter_iterator begin(const tube_time_t &); + + tube_filter_iterator end(const tube_time_t &); + + tube_iterator insert(const tube_time_t &, const key_t &, const val_t &); + tube_iterator insert(const tube_iterator &at, const key_t &, const val_t &); + + void birth(const key_t &, const tube_time_t &); + void birth(const tube_iterator &, const tube_time_t &); + + void kill(const key_t &, const tube_time_t &); + void kill(const tube_iterator &, const tube_time_t &); + + void is_alive(const key_t &, const tube_time_t &); + void is_alive(const tube_iterator &, const tube_time_t &); + + void clean(const tube_time_t &); // remove all dead elements +}; + +template +val_t &UnorderedTubeMap::operator()(const tube_time_t &, const key_t &) { + +} + +template +val_t &UnorderedTubeMap::at(const tube_time_t &, const key_t &) { + +} + +template +tube_filter_iterator> UnorderedTubeMap::begin(const tube_time_t &) { + +} + +template +tube_filter_iterator> UnorderedTubeMap::end(const tube_time_t &) { + +} + +template +tube_iterator UnorderedTubeMap::insert(const tube_time_t &, const key_t &, const val_t &) { + +} + +template +tube_iterator UnorderedTubeMap::insert(const tube_iterator &at, const key_t &, const val_t &) { + +} + +template +void UnorderedTubeMap::birth(const key_t &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::birth(const tube_iterator &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::kill(const key_t &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::kill(const tube_iterator &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::is_alive(const key_t &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::is_alive(const tube_iterator &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::clean(const tube_time_t &) { + +} + +}} // openage::tube diff --git a/openage/testing/testlist.py b/openage/testing/testlist.py index 2f230b38ff..0a77f9b12a 100644 --- a/openage/testing/testlist.py +++ b/openage/testing/testlist.py @@ -70,22 +70,26 @@ def tests_cpp(): yield "openage::coord::tests::coord" yield "openage::datastructure::tests::constexpr_map" yield "openage::datastructure::tests::pairing_heap" + yield "openage::input::tests::parse_event_string", "keybinds parsing" + yield "openage::input::tests::parse_event_string", "keybinds parsing" yield "openage::job::tests::test_job_manager" yield "openage::path::tests::path_node", "pathfinding" - yield "openage::pyinterface::tests::pyobject" yield "openage::pyinterface::tests::err_py_to_cpp" + yield "openage::pyinterface::tests::pyobject" yield "openage::renderer::tests::font" yield "openage::renderer::tests::font_manager" yield "openage::rng::tests::run" + yield "openage::tube::tests::container" + yield "openage::tube::tests::serialization" + yield "openage::tube::tests::tube_types" + yield "openage::util::tests::array_conversion" yield "openage::util::tests::constinit_vector" yield "openage::util::tests::enum_" yield "openage::util::tests::init" yield "openage::util::tests::matrix" yield "openage::util::tests::quaternion" - yield "openage::util::tests::vector" yield "openage::util::tests::siphash" - yield "openage::util::tests::array_conversion" - yield "openage::input::tests::parse_event_string", "keybinds parsing" + yield "openage::util::tests::vector" def demos_cpp(): From 41b2f93900e47cd5bf19a0a6bf9ab3fbd6942745 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 18 Feb 2017 04:14:49 +0100 Subject: [PATCH 02/24] Fixed includes and some whitespaces --- doc/building.md | 1 + libopenage/CMakeLists.txt | 4 + libopenage/tubes/CMakeLists.txt | 4 +- libopenage/tubes/README.md | 2 - libopenage/tubes/base.cpp | 1 - libopenage/tubes/base.h | 20 +- libopenage/tubes/container_iterator.cpp | 1 - libopenage/tubes/demo/CMakeLists.txt | 25 +- libopenage/tubes/demo/aicontroller.cpp | 8 +- libopenage/tubes/demo/aicontroller.h | 2 + libopenage/tubes/demo/gamestate.h | 10 +- libopenage/tubes/demo/gui.cpp | 144 ++++++------ libopenage/tubes/demo/gui.h | 4 +- libopenage/tubes/demo/main.cpp | 28 +-- libopenage/tubes/demo/physics.cpp | 108 ++++----- libopenage/tubes/demo/physics.h | 2 + libopenage/tubes/demo/vertex.h | 226 ------------------- libopenage/tubes/object.cpp | 1 - libopenage/tubes/simple_continuous.cpp | 1 - libopenage/tubes/simple_continuous.h | 5 +- libopenage/tubes/simple_discrete.h | 1 - libopenage/tubes/simple_type.cpp | 1 - libopenage/tubes/simple_type.h | 3 +- libopenage/tubes/test/CMakeLists.txt | 1 - libopenage/tubes/test/test.h | 0 libopenage/tubes/test/test_serialization.cpp | 5 +- libopenage/tubes/test/test_tube_types.cpp | 4 - libopenage/tubes/tube.cpp | 1 - libopenage/tubes/unordered_map.cpp | 1 - openage/testing/testlist.py | 2 + 30 files changed, 195 insertions(+), 421 deletions(-) delete mode 100644 libopenage/tubes/demo/vertex.h delete mode 100644 libopenage/tubes/test/test.h diff --git a/doc/building.md b/doc/building.md index 130109a8d6..e695c97976 100644 --- a/doc/building.md +++ b/doc/building.md @@ -30,6 +30,7 @@ Dependency list: CRA python >=3.4 C cython >=0.25 C cmake >=3.1.0 + CR ncurses A numpy A python imaging library (PIL) -> pillow CR opengl >=2.1 diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index c87a1a9842..a10361e236 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -103,6 +103,9 @@ find_package(Opusfile REQUIRED) find_package(Epoxy REQUIRED) find_package(HarfBuzz 1.0.0 REQUIRED) +set(CURSES_NEED_NCURSES TRUE) +find_package(Curses REQUIRED) + set(QT_VERSION_REQ "5.5") find_package(Qt5Core ${QT_VERSION_REQ} REQUIRED) find_package(Qt5Quick ${QT_VERSION_REQ} REQUIRED) @@ -191,6 +194,7 @@ target_link_libraries(libopenage ${RT_LIB} ${OGG_LIB} ${EXECINFO_LIB} + ${CURSES_LIBRARIES} # TODO: change to PUBLIC (or, alternatively, remove all keywords # of this type) when qt cmake scripts change declarations of the # IMPORTED libraries to GLOBAL. diff --git a/libopenage/tubes/CMakeLists.txt b/libopenage/tubes/CMakeLists.txt index 101abc31e0..1dd290e5bf 100644 --- a/libopenage/tubes/CMakeLists.txt +++ b/libopenage/tubes/CMakeLists.txt @@ -1,5 +1,5 @@ -add_library(tube STATIC +add_sources(libopenage base.cpp container_iterator.cpp event.cpp @@ -13,7 +13,5 @@ add_library(tube STATIC unordered_map.cpp ) -set_property(TARGET tube PROPERTY CXX_STANDARD 11) - add_subdirectory(test) add_subdirectory(demo) diff --git a/libopenage/tubes/README.md b/libopenage/tubes/README.md index bbe5e178c6..6c721e0ed7 100644 --- a/libopenage/tubes/README.md +++ b/libopenage/tubes/README.md @@ -3,5 +3,3 @@ An experiment how one can work with tubes and predictionmagic in a stateless physical game engine. This is a Pong-like game build on top of tubes. - - diff --git a/libopenage/tubes/base.cpp b/libopenage/tubes/base.cpp index 162b76c4ad..bf036928d8 100644 --- a/libopenage/tubes/base.cpp +++ b/libopenage/tubes/base.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/base.h b/libopenage/tubes/base.h index fa6395c240..234d566581 100644 --- a/libopenage/tubes/base.h +++ b/libopenage/tubes/base.h @@ -51,25 +51,25 @@ class tubebase { }; /** - * A element of the double-linked list tubebase + >* A element of the double-linked list tubebase */ template class tubeelement { -friend class tubebase<_T>; + friend class tubebase<_T>; public: tubeelement *next = nullptr; tubeelement *prev = nullptr; private: // These folks are for tubebase only! - tubeelement(const tube_time_t &time) : - time(time) - {} + tubeelement(const tube_time_t &time) + : + time(time) {} // Contruct it from time and value tubeelement(const tube_time_t &time, const _T &value) : time(time), value(value) - {} + {} public: const tube_time_t time = 0; @@ -106,7 +106,7 @@ tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hi return e; } - if (begin->time > time){ + if (begin->time > time) { // This will never happen due to the begin->time == -Inf magic! assert(false); return nullptr; @@ -127,7 +127,7 @@ tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hi while (e->prev != nullptr && time < e->time) { e = e->prev; } - // e is now one of two options: + // e is now one of two options: // 1. e == begin: The time was before every element in the queue // 2. e != begin: There was an element with `e->time` > `time` } @@ -196,7 +196,7 @@ void tubebase<_T>::erase_after(tubeelement<_T> *last_valid) { } } -/** +/** * Delete the element from the list and call delete on it. */ template @@ -215,7 +215,7 @@ void tubebase<_T>::erase(tubeelement<_T> *e) { if (e->prev != nullptr) { e->prev->next = e->next; } - + delete e; // TODO Memory management magic! } diff --git a/libopenage/tubes/container_iterator.cpp b/libopenage/tubes/container_iterator.cpp index 9d3bbe25b3..a53a97b94c 100644 --- a/libopenage/tubes/container_iterator.cpp +++ b/libopenage/tubes/container_iterator.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/demo/CMakeLists.txt b/libopenage/tubes/demo/CMakeLists.txt index ea05b607e4..e46acf1aa5 100644 --- a/libopenage/tubes/demo/CMakeLists.txt +++ b/libopenage/tubes/demo/CMakeLists.txt @@ -1,19 +1,6 @@ -set(CURSES_NEED_NCURSES TRUE) -find_package(Curses) - -IF (${CURSES_FOUND}) - - include_directories(${CURSES_INCLUDE_DIR}) - link_libraries (tube ${CURSES_LIBRARIES}) - - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -pedantic -Wall -Wextra") - add_executable (tubepong - main.cpp - physics.cpp - gui.cpp - aicontroller.cpp - ) - - set_property(TARGET tubepong PROPERTY CXX_STANDARD 14) -ENDIF() - +add_sources (libopenage + main.cpp + physics.cpp + gui.cpp + aicontroller.cpp +) diff --git a/libopenage/tubes/demo/aicontroller.cpp b/libopenage/tubes/demo/aicontroller.cpp index 3071a274f7..b58e36b860 100644 --- a/libopenage/tubes/demo/aicontroller.cpp +++ b/libopenage/tubes/demo/aicontroller.cpp @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #include "aicontroller.h" namespace openage { @@ -8,12 +10,12 @@ std::vector &AIInput::getInputs( const PongBall &ball, const tube::tube_time_t &now) { this->event_cache.clear(); - + auto position = player.position.get(now); - // Yes i know, there is /3 used - instead of the logical /2 - this is to + // Yes i know, there is /3 used - instead of the logical /2 - this is to // create a small safety boundary of 1/3 for enhanced fancyness - + // Ball is below position if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { event_cache.push_back(event(player.id, event::DOWN)); diff --git a/libopenage/tubes/demo/aicontroller.h b/libopenage/tubes/demo/aicontroller.h index d00abbed29..1a8c67100a 100644 --- a/libopenage/tubes/demo/aicontroller.h +++ b/libopenage/tubes/demo/aicontroller.h @@ -1,3 +1,5 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + #pragma once #include diff --git a/libopenage/tubes/demo/gamestate.h b/libopenage/tubes/demo/gamestate.h index 7f85c87837..8cc646ed4c 100644 --- a/libopenage/tubes/demo/gamestate.h +++ b/libopenage/tubes/demo/gamestate.h @@ -1,10 +1,12 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #pragma once #include "../simple_continuous.h" #include "../simple_discrete.h" #include "../object.h" -#include "vertex.h" +#include "../../util/vector.h" namespace openage { namespace tubepong { @@ -41,8 +43,8 @@ class PongPlayer : public tube::TubeObject { class PongBall : public tube::TubeObject { public: - tube::SimpleDiscrete> speed; - tube::SimpleContinuous> position; + tube::SimpleDiscrete> speed; + tube::SimpleContinuous> position; }; class PongState { @@ -52,7 +54,7 @@ class PongState { PongBall ball; - util::vertex<2, float> resolution; + util::Vector<2> resolution; }; }} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.cpp b/libopenage/tubes/demo/gui.cpp index 6c605bd1e3..941b2db7d0 100644 --- a/libopenage/tubes/demo/gui.cpp +++ b/libopenage/tubes/demo/gui.cpp @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #include "gui.h" #include @@ -10,26 +12,26 @@ std::vector &Gui::getInputs(const PongPlayer &player) { input_cache.clear(); event evnt; evnt.player = player.id; - evnt.state = event::IDLE; + evnt.state = event::IDLE; timeout(0); int c = getch(); - //mvprintw(0,1, "IN: %i", c); + // mvprintw(0,1, "IN: %i", c); switch (c) { case KEY_DOWN: evnt.state = event::DOWN; input_cache.push_back(evnt); - mvprintw(1,1, "DOWN"); + mvprintw(1, 1, "DOWN"); break; case KEY_UP: evnt.state = event::UP; input_cache.push_back(evnt); - mvprintw(1,1, "UP"); - break; - case ' ': - evnt.state = event::START; - break; - default: + mvprintw(1, 1, "UP"); break; + case ' ': evnt.state = event::START; break; + case 27: // esc or alt + endwin(); + exit(0); + default: break; } return input_cache; @@ -38,8 +40,8 @@ std::vector &Gui::getInputs(const PongPlayer &player) { enum { COLOR_PLAYER1 = 1, COLOR_PLAYER2 = 2, - COLOR_BALL = 3, - COLOR_DEBUG = 4, + COLOR_BALL = 3, + COLOR_DEBUG = 4, COLOR_0 = 5, COLOR_1 = 6, @@ -51,25 +53,31 @@ enum { Gui::Gui() { initscr(); start_color(); - init_pair(COLOR_PLAYER1, COLOR_BLUE,COLOR_BLUE); - init_pair(COLOR_PLAYER2, COLOR_RED,COLOR_RED); - init_pair(COLOR_BALL , COLOR_BLUE,COLOR_WHITE); - init_pair(COLOR_DEBUG , COLOR_WHITE,COLOR_BLACK); - init_pair(COLOR_0, COLOR_RED ,COLOR_BLACK); - init_pair(COLOR_1, COLOR_GREEN ,COLOR_BLACK); - - keypad(stdscr,true); + init_pair(COLOR_PLAYER1, COLOR_BLUE, COLOR_BLUE); + init_pair(COLOR_PLAYER2, COLOR_RED, COLOR_RED); + init_pair(COLOR_BALL, COLOR_BLUE, COLOR_WHITE); + init_pair(COLOR_DEBUG, COLOR_WHITE, COLOR_BLACK); + init_pair(COLOR_0, COLOR_RED, COLOR_BLACK); + init_pair(COLOR_1, COLOR_GREEN, COLOR_BLACK); + + keypad(stdscr, true); noecho(); curs_set(0); -// getmaxyx(stdscr,state.resolution[1], state.resolution[0]); + // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw(4,5," oooooooooo "); - mvprintw(5,5," 888 888 ooooooo ooooooo oooooooo8 "); - mvprintw(6,5," 888oooo88 888 888 888 888 888 88o "); - mvprintw(7,5," 888 888 888 888 888 888oo888o "); - mvprintw(8,5," o888o 88ooo88 o888o o888o 88 888 "); - mvprintw(9,5," 888ooo888 "); + mvprintw( + 4, 5, " oooooooooo "); + mvprintw( + 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); + mvprintw( + 6, 5, " 888oooo88 888 888 888 888 888 88o "); + mvprintw( + 7, 5, " 888 888 888 888 888 888oo888o "); + mvprintw( + 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); + mvprintw( + 9, 5, " 888ooo888 "); attroff(COLOR_PAIR(COLOR_DEBUG)); getch(); @@ -77,42 +85,54 @@ Gui::Gui() { void Gui::draw(PongState &state, const tube::tube_time_t &now) { erase(); -// clear(); -//Print Score + // clear(); + // Print Score attron(COLOR_PAIR(COLOR_DEBUG)); getmaxyx(stdscr, state.resolution[1], state.resolution[0]); attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw(2, state.resolution[0]/2-5, "P1 %i | P2 %i", - state.p1.lives(now), - state.p2.lives(now)); + mvprintw(2, + state.resolution[0] / 2 - 5, + "P1 %i | P2 %i", + state.p1.lives(now), + state.p2.lives(now)); - mvvline(0, state.resolution[0]/2, ACS_VLINE, state.resolution[1]); + mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); mvprintw(0, 1, "NOW: %f", now); mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); - mvprintw(2, 1, "P1: %f, %f, %i", state.p1.position(now), state.p1.y, state.p1.state(now).state); - mvprintw(3, 1, "P2: %f, %f, %i", state.p2.position(now), state.p2.y, state.p2.state(now).state); + mvprintw(2, + 1, + "P1: %f, %f, %i", + state.p1.position(now), + state.p1.y, + state.p1.state(now).state); + mvprintw(3, + 1, + "P2: %f, %f, %i", + state.p2.position(now), + state.p2.y, + state.p2.state(now).state); for (int i = 0; i < 1000; i += 100) { - mvprintw(4 + i / 100, 1, "BALL in %03i: %f | %f; SPEED: %f | %f", - i, - state.ball.position(now + i)[0], - state.ball.position(now + i)[1], - state.ball.speed(now + i)[0], - state.ball.speed(now + i)[1]); + mvprintw(4 + i / 100, + 1, + "BALL in %03i: %f | %f; SPEED: %f | %f", + i, + state.ball.position(now + i)[0], + state.ball.position(now + i)[1], + state.ball.speed(now + i)[0], + state.ball.speed(now + i)[1]); } - + mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); attroff(COLOR_PAIR(COLOR_DEBUG)); attron(COLOR_PAIR(COLOR_PLAYER1)); - for(int i=-state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { - mvprintw(state.p1.position(now)+i, - state.p1.y,"|"); + for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { + mvprintw(state.p1.position(now) + i, state.p1.y, "|"); } attroff(COLOR_PAIR(COLOR_PLAYER1)); attron(COLOR_PAIR(COLOR_PLAYER2)); - for(int i=-state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { - mvprintw(state.p2.position(now)+i, - state.p2.y,"|"); + for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { + mvprintw(state.p2.position(now) + i, state.p2.y, "|"); } attroff(COLOR_PAIR(COLOR_PLAYER2)); @@ -120,30 +140,24 @@ void Gui::draw(PongState &state, const tube::tube_time_t &now) { draw_ball(state.ball.position(now + i * 50), i); } -/*attron(COLOR_PAIR(COLOR_BALL)); - mvprintw(state.ball.position(now)[1], - state.ball.position(now)[0], - "o"); -*/ + /*attron(COLOR_PAIR(COLOR_BALL)); + mvprintw(state.ball.position(now)[1], + state.ball.position(now)[0], + "o"); + */ attroff(COLOR_PAIR(COLOR_BALL)); refresh(); } -void Gui::draw_ball(util::vertex<2, float> pos, int idx) { - switch(idx) { - case 0: - attron(COLOR_PAIR(COLOR_0)); - break; +void Gui::draw_ball(util::Vector<2> pos, int idx) { + switch (idx) { + case 0: attron(COLOR_PAIR(COLOR_0)); break; default: - case 1: - attron(COLOR_PAIR(COLOR_1)); - break; + case 1: attron(COLOR_PAIR(COLOR_1)); break; } - mvprintw((int)(pos[1]), - (int)(pos[0]), - "\xfe"); + mvprintw((int)(pos[1]), (int)(pos[0]), "X"); standend(); } - -}} // openage::tubepong +} +} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.h b/libopenage/tubes/demo/gui.h index 31d50b8b11..f8d2142ff2 100644 --- a/libopenage/tubes/demo/gui.h +++ b/libopenage/tubes/demo/gui.h @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #pragma once #include @@ -14,7 +16,7 @@ class Gui { Gui(); std::vector &getInputs(const PongPlayer &player); void draw(PongState &state, const tube::tube_time_t &now); - void draw_ball(util::vertex<2, float> ball, int idx); + void draw_ball(util::Vector<2> ball, int idx); private: std::vector input_cache; diff --git a/libopenage/tubes/demo/main.cpp b/libopenage/tubes/demo/main.cpp index 3dff3136df..902b247e51 100644 --- a/libopenage/tubes/demo/main.cpp +++ b/libopenage/tubes/demo/main.cpp @@ -1,6 +1,6 @@ -#include +// Copyright 2015-2017 the openage authors. See copying.md for legal info. -#include +#include #include @@ -9,11 +9,12 @@ #include "gui.h" #include "aicontroller.h" -using namespace openage; - typedef std::chrono::high_resolution_clock Clock; -int main() { +namespace openage { +namespace tubepong { + +int demo() { // Restart forever tubepong::Gui gui; tubepong::Physics phys; @@ -24,7 +25,6 @@ int main() { tubepong::PongState state; tube::tube_time_t now = 1; - state.p1.lives.set_drop(now, 3); state.p1.id = 0; state.p1.size.set_drop(now, 4); @@ -32,7 +32,7 @@ int main() { state.p2.id = 1; state.p2.size.set_drop(now, 4); - auto init_speed = vertex2f( + auto init_speed = util::Vector<2>( ((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, 0.01f * (rand() % 100) / 70.f); @@ -46,7 +46,6 @@ int main() { gui.draw(state, now); //initial drawing with corrected ball auto loop_start = Clock::now(); -// std::cout << "1" << std::endl; now += 1; std::cout << "p1: " << state.p1.lives.get(now) << " p2 " << state.p2.lives.get(now) << std::endl; @@ -60,6 +59,7 @@ int main() { now ); #else + gui.getInputs(state.p1); phys.processInput( state, state.p1, @@ -74,19 +74,21 @@ int main() { now ); - state.p1.y = 0; state.p2.y = state.resolution[0]-1; phys.update(state, now); -// std::cout << now << std::endl; gui.draw(state, now); - usleep(10000); + usleep(40000); - // double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); - now += 10; //dt; + double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); + now += dt; + // now += 40; loop_start = Clock::now(); } } + return 0; } + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/physics.cpp b/libopenage/tubes/demo/physics.cpp index 9ff1b4b6dc..a91ef7ac70 100644 --- a/libopenage/tubes/demo/physics.cpp +++ b/libopenage/tubes/demo/physics.cpp @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #include "physics.h" #include @@ -11,63 +13,63 @@ const float extrapolating_time = 100.0f; const int init_recursion_limit = 50; void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const tube::tube_time_t &now) { - for (auto evnt : events) { - //Process only if the future has changed - if (player.state.get(now).state != evnt.state) { - player.state.set_drop(now, evnt); - - switch(evnt.state) { - case event::UP: - case event::DOWN: { - if (evnt.state == event::UP) { - player.speed.set_drop(now, -2); - } else if (evnt.state == event::DOWN) { - player.speed.set_drop(now, 2); + for (auto evnt : events) { + //Process only if the future has changed + if (player.state.get(now).state != evnt.state) { + player.state.set_drop(now, evnt); + + switch(evnt.state) { + case event::UP: + case event::DOWN: { + if (evnt.state == event::UP) { + player.speed.set_drop(now, -2); + } else if (evnt.state == event::DOWN) { + player.speed.set_drop(now, 2); + } + player.speed.set_drop(now + extrapolating_time, 0); + + float new_pos = player.position.get(now) + + (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); + if (new_pos < 0) + new_pos = 0; + if (new_pos > state.resolution[1]) + new_pos = state.resolution[1]; + + player.position.set_drop(now+extrapolating_time, new_pos); + evnt.state = event::IDLE; + player.state.set_drop(now + extrapolating_time, evnt); + break; } - player.speed.set_drop(now + extrapolating_time, 0); - - float new_pos = player.position.get(now) + - (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); - if (new_pos < 0) - new_pos = 0; - if (new_pos > state.resolution[1]) - new_pos = state.resolution[1]; - - player.position.set_drop(now+extrapolating_time, new_pos); - evnt.state = event::IDLE; - player.state.set_drop(now + extrapolating_time, evnt); - break; - } - case event::IDLE: - player.position.set_drop(now+extrapolating_time, - player.position.get(now)); - break; - case event::START: - if (player.state.get(now).state == event::LOST) { - state.ball.position.set_drop(now, state.resolution * 0.5); + case event::IDLE: + player.position.set_drop(now+extrapolating_time, + player.position.get(now)); + break; + case event::START: + if (player.state.get(now).state == event::LOST) { + state.ball.position.set_drop(now, state.resolution * 0.5); + } + update_ball(state, now, init_recursion_limit); + break; + default: + break; } - update_ball(state, now, init_recursion_limit); - break; - default: - break; } } } -} -void Physics::update(PongState &state, const tube::tube_time_t &now) { + void Physics::update(PongState &state, const tube::tube_time_t &now) { - auto pos = state.ball.position.get(now); - //Handle panel p1 - if (pos[0] <= 1 - && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 - && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 - && state.ball.speed.get(now)[0] < 0) { - //Ball hit the paddel in this frame - auto s = state.ball.speed.get(now); - s[0] *= -1.0; - state.ball.speed.set_drop(now, s); + auto pos = state.ball.position.get(now); + //Handle panel p1 + if (pos[0] <= 1 + && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 + && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 + && state.ball.speed.get(now)[0] < 0) { + //Ball hit the paddel in this frame + auto s = state.ball.speed.get(now); + s[0] *= -1.0; + state.ball.speed.set_drop(now, s); state.ball.position.set_drop(now, pos); // this line can handle the future! update_ball(state, now, init_recursion_limit); @@ -85,7 +87,7 @@ void Physics::update(PongState &state, const tube::tube_time_t &now) { } else if (state.ball.position.needs_update(now)) { update_ball(state, now, init_recursion_limit); } - + // Game loose condition if (pos[0] < 0) { state.p1.lives.set_drop(now, state.p1.lives.get(now) - 1); @@ -95,7 +97,7 @@ void Physics::update(PongState &state, const tube::tube_time_t &now) { state.p2.lives.set_drop(now, state.p2.lives.get(now) - 1); state.p2.state.set_drop(now, event(state.p2.id, event::LOST)); } - + } @@ -103,14 +105,14 @@ void Physics::update_ball(PongState &state, const tube::tube_time_t &now, int re //calculate the ball takes to hit a wall. auto speed = state.ball.speed.get(now); auto pos = state.ball.position.get(now); - + float ty = 0; //char mode = ' '; if (speed [1] > 0) { ty = (state.resolution[1] - pos[1]) / speed[1]; //mode = 'v'; } else if (speed[1] < 0) { - ty = pos[1] / -speed[1]; + ty = pos[1] / -speed[1]; //mode = '^'; } diff --git a/libopenage/tubes/demo/physics.h b/libopenage/tubes/demo/physics.h index 8a8798bde9..02a3a72a82 100644 --- a/libopenage/tubes/demo/physics.h +++ b/libopenage/tubes/demo/physics.h @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #pragma once #include diff --git a/libopenage/tubes/demo/vertex.h b/libopenage/tubes/demo/vertex.h deleted file mode 100644 index 3e42238598..0000000000 --- a/libopenage/tubes/demo/vertex.h +++ /dev/null @@ -1,226 +0,0 @@ -#ifndef VERTEX_H -#define VERTEX_H - -#include -#include -#include -#include -#include - -namespace util { - /** - * N-Dimensional vertex of basetype B. - * is used in GFX, world, every POINT can be converted to evth. - * - * Speciality about this version: - * You cannot have a dimension > 4 with a vertex(a,b,c) ctor! - * - * Version 1.4 ( 30. December 2012 ) - * (c) Johannes Walcher, all rights reserved - * NOT COMPATIBLE WITH VERSIONS < 1.0!! - */ - template - class vertex { - private: - _T f[_DIM]; - public: - vertex() { - memset(f, 0, _DIM*sizeof(_T)); - }; - - vertex(_T s[_DIM]) { - memcpy(f, s, _DIM*sizeof(_T)); - }; - - vertex(const vertex<_DIM, _T> &s) { - memcpy(f, s.f, _DIM*sizeof(_T)); - }; - - /** - * Now this can be used as vertex(_T, _T, _T) - */ - //Initialising the first 4 ctors - vertex(_T fst) { - f[0] = fst; - } - vertex(_T fst, _T snd) { - - if (_DIM < 2) { - printf("vertex has too few dimensions"); - throw std::exception(); - } - f[0] = fst; - f[1] = snd; - } - vertex(_T fst, _T snd, _T trd) { - if (_DIM < 3) { - printf("vertex has too few dimensions"); - throw std::exception(); - } - f[0] = fst; - f[1] = snd; - f[2] = trd; - } - vertex(_T arg1, _T arg2, _T arg3, _T arg4) { - if (_DIM < 4) { - printf("vertex has too few dimensions"); - throw std::exception(); - } - f[0] = arg1; - f[1] = arg2; - f[2] = arg3; - f[4] = arg4; - } - - template - vertex<_DIM, _T> &operator=(const vertex<_DIM, _Rhs_Type> &rhs) - { - for (int i= 0; i < _DIM; i++) { - f[i] = (_T)rhs[i]; - } - return *this; - } - - /* - vertex (_T first, ...) - { - f[0] = first; - int n = _DIM; - if (_DIM > 1) { - va_list params; // Zugriffshandle für Parameter - va_start(params, n); // Zugriff vorbereiten - for (int i = 1; i <_DIM; ++i) { - f[i] = va_arg(params, _T); - } - va_end(params); - } - }; - */ - float length() const { - _T sum = 0; - for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; - return sqrt((float)sum); - } - - double d_length() const { - double sum = 0; - for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; - return sqrt((double)sum); - } - - - void normalize() { - float l = length(); - for (int i = 0; i < _DIM; ++i) - f[i] = (_T)(f[i]/l); - } - - _T at(unsigned int p) const { - if (p < _DIM) return f[p]; - else { - printf("Vertex index out of bounds"); - throw std::exception(); - } - } - - operator vertex<_DIM+1, _T>() - { - vertex<_DIM+1, _T> v; - memcpy(&v[0], f, _DIM*sizeof(_T)); - v[_DIM] = 0; - return v; - } - - _T operator[](unsigned int p) const{ - return f[p]; - } - - _T& operator[](unsigned int p) { - return f[p]; - } - - bool operator == (const vertex<_DIM, _T>& s) const { - for (int i = 0; i < _DIM; ++i) { - if (f[i] != s.f[i]) - return false; - } - return true; - }; - - bool operator < (const vertex<_DIM, _T>& s) const { - for (int i = 0; i < _DIM; ++i) { - if (f[i] >= s.f[i]) - return false; - } - return true; - }; - - vertex<_DIM, _T> operator+ (const vertex<_DIM, _T>& rhs) const { - vertex<_DIM, _T> v(*this); - v += rhs; - return v; - }; - - vertex<_DIM, _T>& operator+= (const vertex<_DIM, _T>& s) { - for (int i = 0; i < _DIM; ++i) - f[i] += s.f[i]; - return *this; - }; - - vertex<_DIM, _T> operator- (const vertex<_DIM, _T>& rhs) const { - vertex<_DIM, _T> v(*this); - v -= rhs; - return v; - }; - - vertex<_DIM, _T>& operator-= (const vertex<_DIM, _T>& s) { - for (int i = 0; i < _DIM; ++i) - f[i] -= s.f[i]; - return *this; - }; - - template - vertex<_DIM, _T> operator* (const _RHS &d) const { - vertex<_DIM, _T> r; - for (int i = 0; i < _DIM; ++i) - r[i] = _T(f[i] * d); - return r; - } - - template - operator vertex<_DIM, _RHS> () { - vertex<_DIM, _RHS> r; - for (int i = 0; i < _DIM; ++i) - r[i] = _RHS(f[i]); - return r; - } - - _T dot(const vertex<_DIM, _T> &v) const { - _T r = _T(); - for (int i = 0; i < _DIM; i++) { - r += f[i] * v.f[i]; - } - return r; - } - - vertex<_DIM, _T> cross(const vertex<_DIM, _T> &rhs) const { - vertex<_DIM, _T> v; - - v[0] = f[1]*rhs[2] - f[2]*rhs[1]; - v[1] = f[2]*rhs[0] - f[0]*rhs[2]; - v[2] = f[0]*rhs[1] - f[1]*rhs[0]; - - return v; - } - - }; -} - -typedef util::vertex<2, int> vertex2i; -typedef util::vertex<3, int> vertex3i; -typedef util::vertex<2, float> vertex2f; -typedef util::vertex<3, double> vertex3d; -typedef util::vertex<3, float> vertex3f; - -#endif - diff --git a/libopenage/tubes/object.cpp b/libopenage/tubes/object.cpp index 14a167cb59..93a463df50 100644 --- a/libopenage/tubes/object.cpp +++ b/libopenage/tubes/object.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/simple_continuous.cpp b/libopenage/tubes/simple_continuous.cpp index 1bbbe6452c..c54324a4a5 100644 --- a/libopenage/tubes/simple_continuous.cpp +++ b/libopenage/tubes/simple_continuous.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/simple_continuous.h b/libopenage/tubes/simple_continuous.h index bf1a1ed9d8..ed125254dd 100644 --- a/libopenage/tubes/simple_continuous.h +++ b/libopenage/tubes/simple_continuous.h @@ -39,11 +39,11 @@ void SimpleContinuous<_T>::set_now(const tube_time_t &t) const { template _T SimpleContinuous<_T>::get() const { - double elapsed_frac = (double)offset / (double)diff_time ; + double elapsed_frac = (double)offset / (double)diff_time; if (this->e_now == nullptr) { //TODO This Sucks! return _T(); } else if (this->e_now->next == nullptr || offset == 0) { - return this->e_now->value; //If we cannot interpolate, treat as standing still (?) + return this->e_now->value; //If we cannot interpolate, treat as standing still (?) } else { return this->e_now->value + (this->e_now->next->value - this->e_now->value) * elapsed_frac; } @@ -57,4 +57,3 @@ _T SimpleContinuous<_T>::get(const tube_time_t &time) const { }} // openage::tube - diff --git a/libopenage/tubes/simple_discrete.h b/libopenage/tubes/simple_discrete.h index 91406cdcfe..968e13fed5 100644 --- a/libopenage/tubes/simple_discrete.h +++ b/libopenage/tubes/simple_discrete.h @@ -32,4 +32,3 @@ _T SimpleDiscrete<_T>::get(const tube_time_t &time) const { } }} // openage::tube - diff --git a/libopenage/tubes/simple_type.cpp b/libopenage/tubes/simple_type.cpp index 1d845a6b3f..918d89f759 100644 --- a/libopenage/tubes/simple_type.cpp +++ b/libopenage/tubes/simple_type.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/simple_type.h b/libopenage/tubes/simple_type.h index 348ba2b97f..2f8f37d840 100644 --- a/libopenage/tubes/simple_type.h +++ b/libopenage/tubes/simple_type.h @@ -15,7 +15,7 @@ class SimpleType { mutable tube_time_t now; public: - SimpleType(); + SimpleType(); // Reader mode virtual void set_now(const tube_time_t &t) const; @@ -78,4 +78,3 @@ bool SimpleType<_T>::needs_update(const tube_time_t &at) { } }} // openage::tube - diff --git a/libopenage/tubes/test/CMakeLists.txt b/libopenage/tubes/test/CMakeLists.txt index f1bbbca333..6e340d6393 100644 --- a/libopenage/tubes/test/CMakeLists.txt +++ b/libopenage/tubes/test/CMakeLists.txt @@ -8,4 +8,3 @@ add_sources(libopenage test_tube_types.cpp test_serialization.cpp ) - diff --git a/libopenage/tubes/test/test.h b/libopenage/tubes/test/test.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libopenage/tubes/test/test_serialization.cpp b/libopenage/tubes/test/test_serialization.cpp index a33e2a7aee..af8dd046c7 100644 --- a/libopenage/tubes/test/test_serialization.cpp +++ b/libopenage/tubes/test/test_serialization.cpp @@ -1,7 +1,5 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "test.h" - #include "../../testing/testing.h" namespace openage { @@ -9,8 +7,7 @@ namespace tube { namespace tests { void serialization() { - + } }}} // openage::tube::tests - diff --git a/libopenage/tubes/test/test_tube_types.cpp b/libopenage/tubes/test/test_tube_types.cpp index c5e4a098d0..aafa1c21ae 100644 --- a/libopenage/tubes/test/test_tube_types.cpp +++ b/libopenage/tubes/test/test_tube_types.cpp @@ -1,8 +1,5 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "test.h" - - #include "../../testing/testing.h" namespace openage { @@ -10,7 +7,6 @@ namespace tube { namespace tests { void tube_types() { - } }}} // openage::tube::tests diff --git a/libopenage/tubes/tube.cpp b/libopenage/tubes/tube.cpp index 378783bb1b..4462daac9c 100644 --- a/libopenage/tubes/tube.cpp +++ b/libopenage/tubes/tube.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/unordered_map.cpp b/libopenage/tubes/unordered_map.cpp index 58b6227d2f..c336fedff8 100644 --- a/libopenage/tubes/unordered_map.cpp +++ b/libopenage/tubes/unordered_map.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/openage/testing/testlist.py b/openage/testing/testlist.py index 0a77f9b12a..0e8cb22734 100644 --- a/openage/testing/testlist.py +++ b/openage/testing/testlist.py @@ -109,6 +109,8 @@ def demos_cpp(): "translates a Python exception to C++") yield ("openage::pyinterface::tests::pyobject_demo", "a tiny interactive interpreter using PyObjectRef") + yield ("openage::tubepong::demo", + "a pong game implemented in curves") def benchmark_cpp(): From cfe6580e43b1619248a7dacdc1ad3621c46dd596 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 18 Feb 2017 04:22:09 +0100 Subject: [PATCH 03/24] Added ncurses to ubuntu installation --- doc/build_instructions/ubuntu_16.04.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build_instructions/ubuntu_16.04.md b/doc/build_instructions/ubuntu_16.04.md index ceb5972cfa..8a9bcbf7d4 100644 --- a/doc/build_instructions/ubuntu_16.04.md +++ b/doc/build_instructions/ubuntu_16.04.md @@ -1,5 +1,5 @@ # Prerequisite steps for Ubuntu users (Ubuntu 16.04) - `sudo apt-get update` - - `sudo apt-get install cmake libfreetype6-dev python3-dev python3-pip libepoxy-dev libsdl2-dev libsdl2-image-dev libopusfile-dev libfontconfig1-dev libharfbuzz-dev libpng-dev opus-tools python3-pil python3-numpy python3-pygments qtdeclarative5-dev qml-module-qtquick-controls` + - `sudo apt-get install cmake libfreetype6-dev python3-dev python3-pip libepoxy-dev libsdl2-dev libsdl2-image-dev libopusfile-dev libfontconfig1-dev libharfbuzz-dev libpng-dev libncurses5-dev opus-tools python3-pil python3-numpy python3-pygments qtdeclarative5-dev qml-module-qtquick-controls` - `pip3 install cython` From 0b006b04be3a7274dbdd6794c182cf23c4ebf6e6 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 15 Apr 2017 01:14:10 +0200 Subject: [PATCH 04/24] Tubes: Refactoring, Map and Types --- libopenage/CMakeLists.txt | 2 +- libopenage/{tubes => tube}/.gitignore | 0 libopenage/tube/CMakeLists.txt | 16 ++ libopenage/tube/datatypes.md | 58 +++++ .../{tubes => tube}/demo/CMakeLists.txt | 0 .../{tubes => tube}/demo/aicontroller.cpp | 0 .../{tubes => tube}/demo/aicontroller.h | 0 libopenage/{tubes => tube}/demo/gamestate.h | 21 +- libopenage/{tubes => tube}/demo/gui.cpp | 12 +- libopenage/{tubes => tube}/demo/gui.h | 0 libopenage/{tubes => tube}/demo/main.cpp | 49 ++-- libopenage/{tubes => tube}/demo/physics.cpp | 0 libopenage/{tubes => tube}/demo/physics.h | 0 .../keyframe_container.cpp} | 2 +- libopenage/tube/keyframe_container.h | 199 ++++++++++++++++ libopenage/tube/map_filter_iterator.h | 123 ++++++++++ .../{tubes => tube}/test/CMakeLists.txt | 0 libopenage/tube/test/test_container.cpp | 154 ++++++++++++ .../test/test_serialization.cpp | 0 libopenage/tube/test/test_tube_types.cpp | 124 ++++++++++ libopenage/{tubes => tube}/tube.cpp | 0 libopenage/tube/tube.h | 25 ++ libopenage/tube/tube_container_iterator.cpp | 8 + libopenage/tube/tube_container_iterator.h | 89 +++++++ .../tube_continuous.cpp} | 2 +- libopenage/tube/tube_continuous.h | 45 ++++ .../object.cpp => tube/tube_discrete.cpp} | 2 +- libopenage/tube/tube_discrete.h | 23 ++ .../{tubes/event.cpp => tube/tube_event.cpp} | 2 +- .../{tubes/event.h => tube/tube_event.h} | 0 .../{tubes/base.cpp => tube/tube_object.cpp} | 2 +- .../{tubes/object.h => tube/tube_object.h} | 0 libopenage/tube/tube_objectlist.cpp | 8 + .../eventlist.h => tube/tube_objectlist.h} | 0 .../eventlist.cpp => tube/tube_queue.cpp} | 2 +- libopenage/tube/tube_queue.h | 30 +++ libopenage/tube/unordered_map.h | 214 +++++++++++++++++ libopenage/tube/value_container.cpp | 8 + libopenage/tube/value_container.h | 55 +++++ libopenage/tubes/CMakeLists.txt | 17 -- libopenage/tubes/README.md | 5 - libopenage/tubes/base.h | 222 ------------------ libopenage/tubes/container_iterator.h | 93 -------- libopenage/tubes/filter_iterator.h | 112 --------- libopenage/tubes/objectlist.h | 8 - libopenage/tubes/simple_continuous.cpp | 8 - libopenage/tubes/simple_continuous.h | 59 ----- libopenage/tubes/simple_discrete.cpp | 8 - libopenage/tubes/simple_discrete.h | 34 --- libopenage/tubes/simple_type.cpp | 8 - libopenage/tubes/simple_type.h | 80 ------- libopenage/tubes/test/test_container.cpp | 188 --------------- libopenage/tubes/test/test_tube_types.cpp | 12 - libopenage/tubes/tube.h | 10 - libopenage/tubes/unordered_map.cpp | 8 - libopenage/tubes/unordered_map.h | 112 --------- openage/testing/main.py | 11 +- 57 files changed, 1230 insertions(+), 1040 deletions(-) rename libopenage/{tubes => tube}/.gitignore (100%) create mode 100644 libopenage/tube/CMakeLists.txt create mode 100644 libopenage/tube/datatypes.md rename libopenage/{tubes => tube}/demo/CMakeLists.txt (100%) rename libopenage/{tubes => tube}/demo/aicontroller.cpp (100%) rename libopenage/{tubes => tube}/demo/aicontroller.h (100%) rename libopenage/{tubes => tube}/demo/gamestate.h (68%) rename libopenage/{tubes => tube}/demo/gui.cpp (88%) rename libopenage/{tubes => tube}/demo/gui.h (100%) rename libopenage/{tubes => tube}/demo/main.cpp (63%) rename libopenage/{tubes => tube}/demo/physics.cpp (100%) rename libopenage/{tubes => tube}/demo/physics.h (100%) rename libopenage/{tubes/container_iterator.cpp => tube/keyframe_container.cpp} (80%) create mode 100644 libopenage/tube/keyframe_container.h create mode 100644 libopenage/tube/map_filter_iterator.h rename libopenage/{tubes => tube}/test/CMakeLists.txt (100%) create mode 100644 libopenage/tube/test/test_container.cpp rename libopenage/{tubes => tube}/test/test_serialization.cpp (100%) create mode 100644 libopenage/tube/test/test_tube_types.cpp rename libopenage/{tubes => tube}/tube.cpp (100%) create mode 100644 libopenage/tube/tube.h create mode 100644 libopenage/tube/tube_container_iterator.cpp create mode 100644 libopenage/tube/tube_container_iterator.h rename libopenage/{tubes/filter_iterator.cpp => tube/tube_continuous.cpp} (82%) create mode 100644 libopenage/tube/tube_continuous.h rename libopenage/{tubes/object.cpp => tube/tube_discrete.cpp} (83%) create mode 100644 libopenage/tube/tube_discrete.h rename libopenage/{tubes/event.cpp => tube/tube_event.cpp} (84%) rename libopenage/{tubes/event.h => tube/tube_event.h} (100%) rename libopenage/{tubes/base.cpp => tube/tube_object.cpp} (84%) rename libopenage/{tubes/object.h => tube/tube_object.h} (100%) create mode 100644 libopenage/tube/tube_objectlist.cpp rename libopenage/{tubes/eventlist.h => tube/tube_objectlist.h} (100%) rename libopenage/{tubes/eventlist.cpp => tube/tube_queue.cpp} (84%) create mode 100644 libopenage/tube/tube_queue.h create mode 100644 libopenage/tube/unordered_map.h create mode 100644 libopenage/tube/value_container.cpp create mode 100644 libopenage/tube/value_container.h delete mode 100644 libopenage/tubes/CMakeLists.txt delete mode 100644 libopenage/tubes/README.md delete mode 100644 libopenage/tubes/base.h delete mode 100644 libopenage/tubes/container_iterator.h delete mode 100644 libopenage/tubes/filter_iterator.h delete mode 100644 libopenage/tubes/objectlist.h delete mode 100644 libopenage/tubes/simple_continuous.cpp delete mode 100644 libopenage/tubes/simple_continuous.h delete mode 100644 libopenage/tubes/simple_discrete.cpp delete mode 100644 libopenage/tubes/simple_discrete.h delete mode 100644 libopenage/tubes/simple_type.cpp delete mode 100644 libopenage/tubes/simple_type.h delete mode 100644 libopenage/tubes/test/test_container.cpp delete mode 100644 libopenage/tubes/test/test_tube_types.cpp delete mode 100644 libopenage/tubes/tube.h delete mode 100644 libopenage/tubes/unordered_map.cpp delete mode 100644 libopenage/tubes/unordered_map.h diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index a10361e236..d418e8bd3d 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -46,7 +46,7 @@ add_subdirectory("rng") add_subdirectory("shader") add_subdirectory("terrain") add_subdirectory("testing") -add_subdirectory("tubes") +add_subdirectory("tube") add_subdirectory("unit") add_subdirectory("util") diff --git a/libopenage/tubes/.gitignore b/libopenage/tube/.gitignore similarity index 100% rename from libopenage/tubes/.gitignore rename to libopenage/tube/.gitignore diff --git a/libopenage/tube/CMakeLists.txt b/libopenage/tube/CMakeLists.txt new file mode 100644 index 0000000000..c29c76712d --- /dev/null +++ b/libopenage/tube/CMakeLists.txt @@ -0,0 +1,16 @@ + +add_sources(libopenage + keyframe_container.cpp + #tube_container_iterator.cpp + tube_event.cpp + tube_queue.cpp + tube_object.cpp + tube_objectlist.cpp + tube_continuous.cpp + tube_discrete.cpp + tube.cpp + value_container.cpp +) + +add_subdirectory(test) +add_subdirectory(demo) diff --git a/libopenage/tube/datatypes.md b/libopenage/tube/datatypes.md new file mode 100644 index 0000000000..fdc215c391 --- /dev/null +++ b/libopenage/tube/datatypes.md @@ -0,0 +1,58 @@ +TUBE DATATYPES +================= + +This document describes the datatypes that should be available within the tubes library. +They consists of simple, single dimensinal types and list types. + +This document is intended for brainstorming on needed datatypes. + +Simple Types +------------ + +Simple types only have one distinct value at a specific point in time. + +Discrete Interpolation +---------------------- + +"Step function" style values. These types adopt the new value exactly at the point in time changed. +They are useful for example for values like unit capacity, hitpoints, resource count, ... + +Linear Interpolation +-------------------- + +Linear connections between two points. These types have to overload the operators + and *, since these +are used to interpolate between t\_n and t\_n+1. These values change consistently over time, if t\_n+1 exists. +These are useful for example for unit position, building progress, ... + +Nyan Values +-------------- + +This container keeps track of nyan objects over time and their respective properties. + +Container Types +=============== + +Container types hold lists of items at any given time. They store a creation and a deletion timestamp for each item, and offer iteration logic to traverse the active elements in the container. + +Map Container +------------- + +The map container stores items based on an unique identifier mapped to an item. It keeps track of the existence of the item. No guaranteed order of items within this container is given (similar to std::unordered_map). +This container is useful for example for unit lists ... + +Set Container +---------------- + +The set container stores items, just as a normal array would. It keeps track of the existence of the items, but does not guarentee any particular ordering (similar to std::unordered_set). +This Container is useful for any non-indexed data structures, for example projectiles. + +Queue Container +--------------- + +The queue container represents a random access queue while keeping the ordering of the queue. +It is usually used for pushing in the back and popping at the front (FIFO-Stlye) but offers random access insertion and deletion as well. +This container is useful for example for action queues and buildung queues. + +TUBE FILES +============ + diff --git a/libopenage/tubes/demo/CMakeLists.txt b/libopenage/tube/demo/CMakeLists.txt similarity index 100% rename from libopenage/tubes/demo/CMakeLists.txt rename to libopenage/tube/demo/CMakeLists.txt diff --git a/libopenage/tubes/demo/aicontroller.cpp b/libopenage/tube/demo/aicontroller.cpp similarity index 100% rename from libopenage/tubes/demo/aicontroller.cpp rename to libopenage/tube/demo/aicontroller.cpp diff --git a/libopenage/tubes/demo/aicontroller.h b/libopenage/tube/demo/aicontroller.h similarity index 100% rename from libopenage/tubes/demo/aicontroller.h rename to libopenage/tube/demo/aicontroller.h diff --git a/libopenage/tubes/demo/gamestate.h b/libopenage/tube/demo/gamestate.h similarity index 68% rename from libopenage/tubes/demo/gamestate.h rename to libopenage/tube/demo/gamestate.h index 8cc646ed4c..3ae0674f84 100644 --- a/libopenage/tubes/demo/gamestate.h +++ b/libopenage/tube/demo/gamestate.h @@ -2,10 +2,9 @@ #pragma once - -#include "../simple_continuous.h" -#include "../simple_discrete.h" -#include "../object.h" +#include "../tube_continuous.h" +#include "../tube_discrete.h" +#include "../tube_object.h" #include "../../util/vector.h" namespace openage { @@ -32,19 +31,19 @@ class PongPlayer : public tube::TubeObject { id = 0; } - tube::SimpleDiscrete speed; - tube::SimpleContinuous position; - tube::SimpleDiscrete lives; - tube::SimpleDiscrete state; - tube::SimpleDiscrete size; + tube::Discrete speed; + tube::Continuous position; + tube::Discrete lives; + tube::Discrete state; + tube::Discrete size; float y; int id; }; class PongBall : public tube::TubeObject { public: - tube::SimpleDiscrete> speed; - tube::SimpleContinuous> position; + tube::Discrete> speed; + tube::Continuous> position; }; class PongState { diff --git a/libopenage/tubes/demo/gui.cpp b/libopenage/tube/demo/gui.cpp similarity index 88% rename from libopenage/tubes/demo/gui.cpp rename to libopenage/tube/demo/gui.cpp index 941b2db7d0..604ea91c10 100644 --- a/libopenage/tubes/demo/gui.cpp +++ b/libopenage/tube/demo/gui.cpp @@ -67,17 +67,17 @@ Gui::Gui() { attron(COLOR_PAIR(COLOR_DEBUG)); mvprintw( - 4, 5, " oooooooooo "); + 4, 5, " oooooooooo "); mvprintw( - 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); + 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); mvprintw( - 6, 5, " 888oooo88 888 888 888 888 888 88o "); + 6, 5, " 888oooo88 888 888 888 888 888 88o "); mvprintw( - 7, 5, " 888 888 888 888 888 888oo888o "); + 7, 5, " 888 888 888 888 888 888oo888o "); mvprintw( - 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); + 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); mvprintw( - 9, 5, " 888ooo888 "); + 9, 5, " 888ooo888 "); attroff(COLOR_PAIR(COLOR_DEBUG)); getch(); diff --git a/libopenage/tubes/demo/gui.h b/libopenage/tube/demo/gui.h similarity index 100% rename from libopenage/tubes/demo/gui.h rename to libopenage/tube/demo/gui.h diff --git a/libopenage/tubes/demo/main.cpp b/libopenage/tube/demo/main.cpp similarity index 63% rename from libopenage/tubes/demo/main.cpp rename to libopenage/tube/demo/main.cpp index 902b247e51..d5ad18a910 100644 --- a/libopenage/tubes/demo/main.cpp +++ b/libopenage/tube/demo/main.cpp @@ -4,10 +4,10 @@ #include +#include "aicontroller.h" #include "gamestate.h" -#include "physics.h" #include "gui.h" -#include "aicontroller.h" +#include "physics.h" typedef std::chrono::high_resolution_clock Clock; @@ -32,63 +32,52 @@ int demo() { state.p2.id = 1; state.p2.size.set_drop(now, 4); - auto init_speed = util::Vector<2>( - ((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, - 0.01f * (rand() % 100) / 70.f); + auto init_speed = + util::Vector<2>(((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, + 0.01f * (rand() % 100) / 70.f); - gui.draw(state, now); //update gui related parameters + gui.draw(state, now); // update gui related parameters state.ball.speed.set_drop(now, init_speed); state.ball.position.set_drop(now, state.resolution * 0.5); state.p1.position.set_drop(now, state.resolution[1] / 2); state.p2.position.set_drop(now, state.resolution[1] / 2); - gui.draw(state, now); //initial drawing with corrected ball + gui.draw(state, now); // initial drawing with corrected ball auto loop_start = Clock::now(); now += 1; - std::cout << "p1: " << state.p1.lives.get(now) << " p2 " << state.p2.lives.get(now) << std::endl; - + std::cout << "p1: " << state.p1.lives.get(now) << " p2 " + << state.p2.lives.get(now) << std::endl; while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { #ifdef HUMAN - phys.processInput( - state, - state.p1, - gui.getInputs(state.p1), - now - ); + phys.processInput(state, state.p1, gui.getInputs(state.p1), now); #else gui.getInputs(state.p1); phys.processInput( - state, - state.p1, - ai.getInputs(state.p1, state.ball, now), - now - ); + state, state.p1, ai.getInputs(state.p1, state.ball, now), now); #endif phys.processInput( - state, - state.p2, - ai.getInputs(state.p2, state.ball, now), - now - ); + state, state.p2, ai.getInputs(state.p2, state.ball, now), now); state.p1.y = 0; - state.p2.y = state.resolution[0]-1; + state.p2.y = state.resolution[0] - 1; phys.update(state, now); gui.draw(state, now); usleep(40000); - double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); + double dt = std::chrono::duration_cast( + (Clock::now() - loop_start)) + .count(); now += dt; - // now += 40; + // now += 40; loop_start = Clock::now(); } } return 0; } - -}} // openage::tubepong +} +} // openage::tubepong diff --git a/libopenage/tubes/demo/physics.cpp b/libopenage/tube/demo/physics.cpp similarity index 100% rename from libopenage/tubes/demo/physics.cpp rename to libopenage/tube/demo/physics.cpp diff --git a/libopenage/tubes/demo/physics.h b/libopenage/tube/demo/physics.h similarity index 100% rename from libopenage/tubes/demo/physics.h rename to libopenage/tube/demo/physics.h diff --git a/libopenage/tubes/container_iterator.cpp b/libopenage/tube/keyframe_container.cpp similarity index 80% rename from libopenage/tubes/container_iterator.cpp rename to libopenage/tube/keyframe_container.cpp index a53a97b94c..9620527dcb 100644 --- a/libopenage/tubes/container_iterator.cpp +++ b/libopenage/tube/keyframe_container.cpp @@ -1,6 +1,6 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "container_iterator.h" +#include "keyframe_container.h" namespace openage { namespace tube { diff --git a/libopenage/tube/keyframe_container.h b/libopenage/tube/keyframe_container.h new file mode 100644 index 0000000000..5928575dfa --- /dev/null +++ b/libopenage/tube/keyframe_container.h @@ -0,0 +1,199 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +#include "../error/error.h" + +#include +#include +#include +#include + +namespace openage { +namespace tube { + +/** + * A timely ordered list with several management functions + * + * This class manages different time-based management functions for the double- + * linked list approach that lies underneath. It contains a double-linked list + * to be accessed via a non-accurate timing functionality, this means, that for + * getting a value, not the exact timestamp has to be known, it will always return + * the one closest, less or equal to the requested one. + **/ +template +class KeyframeContainer { +public: + /** + * A element of the double-linked list KeyframeContainer + */ + class Keyframe { + public: + Keyframe(const tube_time_t &time) : + time(time) {} + + // Contruct it from time and value + Keyframe(const tube_time_t &time, const _T &value) : + time(time), + value(value) {} + + const tube_time_t time = 0; + _T value = _T(); + }; + + typedef std::list tubecontainer; + typedef typename tubecontainer::const_iterator KeyframeIterator; + KeyframeContainer(); + ~KeyframeContainer(); + + // Get the last element with e->time <= time + KeyframeIterator last(const tube_time_t &time, const KeyframeIterator & hint) const; + KeyframeIterator last(const tube_time_t &time) const { + return this->last(time, this->container.begin()); + } + + /** + * Insert a new element without a hint. + * + * This function is recommended for use, whenever possible, keep a hint to insert + * the data. + */ + KeyframeIterator insert(const Keyframe &value) { + return this->insert(value, this->container.begin()); + } + + /** + * Insert a new element. The hint shall give an approximate location, where the + * inserter will start to look for a insertion point. If a good hint is given, the + * runtime of this function will not be affected by the current history size. + */ + KeyframeIterator insert(const Keyframe &value, const KeyframeIterator &hint); + + /** + * Create and insert a new element without submitting a hint. + * The use of this function is discouraged, use it only, if your really do not + * have the possibility to get a hint + */ + KeyframeIterator insert(const tube_time_t &time, const _T&value) { + return this->insert(Keyframe(time, value), this->container.begin()); + } + /** + * Create and insert a new element. The hint gives an approximate location. + */ + KeyframeIterator insert(const tube_time_t &time, const _T&value, const KeyframeIterator &hint) { + return this->insert(Keyframe(time, value), hint); + } + + /** + * Erase all elements that come after this last valid element. + */ + KeyframeIterator erase_after(KeyframeIterator last_valid); + + /** + * Erase a single element from the tube. + */ + KeyframeIterator erase(KeyframeIterator ); + + KeyframeIterator begin() const { + return container.begin(); + } + + KeyframeIterator end() const { + return container.end(); + } + + void __attribute__ ((noinline)) dump() { + for (auto e : container) { + std::cout << "Element: time: " << e.time << " v: " << e.value << std::endl; + } + } +private: + tubecontainer container; +}; + + +template +KeyframeContainer<_T>::KeyframeContainer() { + //Create a default element at -Inf, that can always be dereferenced - so there will by definition never be + //a element that cannot be dereferenced + this->container.push_back(Keyframe(-std::numeric_limits::infinity(), _T())); +} + +template +KeyframeContainer<_T>::~KeyframeContainer() { +} + +/** + * Select the element that directly preceedes the given timestamp. + * + * Without a hint, start to iterate at the beginning of the buffer, and return + * the element last element before e->time > time. + * This method returns nullptr, if begin->time > time. + **/ +template +typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::last(const tube_time_t &time, const KeyframeIterator &hint) const { + KeyframeIterator e = (hint == this->container.end()) ? this->container.begin() : hint; + + if (this->container.front().time > time) { + // This will never happen due to the container.front->time == -Inf magic! + throw new Error(ERR << "rupture in spacetime detected, tube container is broken"); + } + + // Search in the queue + if (time > e->time) { // the searched element is supposed to be AFTER the hint + // perform the search via ->next + while (e != this->container.end() && time >= e->time) { + e++; + } + e--; + // e is now one of two options: + // 1. e == end: The last element of the queue was smaller than `time` + // 2. e != end: There was a element with `e->time` > `time` + + } else if (time < e->time) { + // the searched element is supposed to be BEFORE the hint + // perform the search via ->prev + while (e != this->container.begin() && time < e->time) { + e--; + } + // e is now one of two options: + // 1. e == begin: The time was before every element in the queue + // 2. e != begin: There was an element with `e->time` > `time` + + } else { + // perform <= search - and return e, whose time is == time. + } + + return e; +} + +/** + * Determine where to insert based on time, and insert + */ +template +typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::insert(const KeyframeContainer<_T>::Keyframe &e, const KeyframeContainer<_T>::KeyframeIterator &hint) { + KeyframeIterator at = this->last(e.time, hint); + at ++; + return this->container.insert(at, e); +} + +/** + * Go from the end to the last_valid element, and call erase on all of them + */ +template +typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::erase_after(KeyframeContainer<_T>::KeyframeIterator last_valid) { + //Delete from the end to (excluded) last_valid + return this->container.erase(++last_valid, container.end()); +} + +/** + * Delete the element from the list and call delete on it. + */ +template +typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::erase(KeyframeContainer<_T>::KeyframeIterator e) { + return this->container.erase(e); +} + +}} // openage::tube diff --git a/libopenage/tube/map_filter_iterator.h b/libopenage/tube/map_filter_iterator.h new file mode 100644 index 0000000000..49753a0598 --- /dev/null +++ b/libopenage/tube/map_filter_iterator.h @@ -0,0 +1,123 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include + +#include "tube.h" + +namespace openage { +namespace tube { + +template +class TubeIterator { +public: + virtual val_t &value() = 0; +}; + +template +bool valid(const _T &, const tube_time_t &at); + +template +using _valid_function_t = bool (*)(const _T&, const tube_time_t &); + +template valid_f = valid > +class TubeMapFilterIterator : + virtual public std::iterator, + public TubeIterator +{ +protected: + //typedef typename std::iterator iterator_t; + typedef typename container_t::iterator iterator_t; + iterator_t base; + iterator_t container_end; + + tube_time_t from; + tube_time_t to; + tube_time_t now; + +public: + TubeMapFilterIterator(const iterator_t &base, + const iterator_t &container_end, + const tube_time_t &from, + const tube_time_t &to) : + base{base}, + container_end{container_end}, + from{from}, + to{to}, + now{from} {} + + TubeMapFilterIterator(const TubeMapFilterIterator &rhs) : + base{rhs.base}, + container_end{rhs.container_end}, + from{rhs.from}, + to{rhs.to}, + now{rhs.now} {} + + TubeMapFilterIterator &operator =(const TubeMapFilterIterator &rhs) { + this->base = rhs.base; + this->container_end = rhs.container_end; + this->from = rhs.from; + this->to = rhs.to; + return *this; + } + + TubeMapFilterIterator &operator ++() { + do { + ++this->base; + } while (this->base != this->container_end && + (existent_from(this->base->second.value) < from || + existent_until(this->base->second.value) > to)); + return *this; + } + + //We only want to Iterate forward - so maybe delete this? + //timed_iterator &operator --() + //{ + // --base; + // return *this; + //} + + val_t &operator *() const { + return this->base->second.value; + } + + val_t *operator ->() const { + return &**this; + } + + virtual bool operator ==(const TubeMapFilterIterator &rhs) const { + return rhs.now != std::numeric_limits::infinity() + || this->base == rhs.base; + } + + virtual bool operator !=(const TubeMapFilterIterator &rhs) const { + return rhs.now == std::numeric_limits::infinity() + || this->base != rhs.base; + } + + virtual bool valid(const tube_time_t &time) { + return valid_f(base->second.value, time); + } + + val_t &value() override { + return this->base->second.value; + } + + const key_t &key() { + return this->base->first; + } +}; + +template +bool valid(const _T &t, + const tube_time_t& time) { + return existent_from(t) <= time && existent_until(t) > time; +} + + +}} // openage::tube diff --git a/libopenage/tubes/test/CMakeLists.txt b/libopenage/tube/test/CMakeLists.txt similarity index 100% rename from libopenage/tubes/test/CMakeLists.txt rename to libopenage/tube/test/CMakeLists.txt diff --git a/libopenage/tube/test/test_container.cpp b/libopenage/tube/test/test_container.cpp new file mode 100644 index 0000000000..c2918b560f --- /dev/null +++ b/libopenage/tube/test/test_container.cpp @@ -0,0 +1,154 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "../../testing/testing.h" +#include "../unordered_map.h" +#include "../tube.h" +#include "../tube_continuous.h" +#include "../tube_discrete.h" + +#include + +namespace openage { +namespace tube { +namespace tests { + +struct map_test_element { + volatile int value; + tube_time_t birth, death; + + map_test_element(int v, tube_time_t b, tube_time_t d) : + value(v), + birth(b), + death(d) {} + + tube_time_t existent_from () const { + return this->birth; + } + tube_time_t existent_until () const { + return this->death; + } + + bool operator != (int rhs) { + return this->value != rhs; + } + +}; + +std::ostream &operator << (std::ostream &o, const map_test_element &e) { + o << e.value; + return o; +} + +template +void dump(const std::map &map) { + for (auto i : map) { + std::cout << i.first << ": " << i.second << std::endl; + } +} + +void test_map() { + UnorderedMap map; + map.insert(0, map_test_element(0, 0, 10)); + map.insert(5, map_test_element(1, 5, 10)); + map.insert(200, map_test_element(2, 100, 200)); + + // Basic tests test lookup in the middle of the range. + { + auto t = map.at(2, 0); //At timestamp 2 element 0 + TESTEQUALS(t.first, true); + TESTEQUALS(t.second.value(), 0); + t = map.at(20, 5); + TESTEQUALS(t.first, false); + } + { + auto t = map.at(7, 5); + TESTEQUALS(t.first, true); + TESTEQUALS(t.second.value(), 1); + t = map.at(20, 5); + TESTEQUALS(t.first, false); + t = map.at(2, 5); + TESTEQUALS(t.first, false); + } + { + auto t = map.at(150, 200); + TESTEQUALS(t.first, true); + TESTEQUALS(t.second.value(), 2); + t = map.at(500, 200); + TESTEQUALS(t.first, false); + t = map.at(5, 200); + TESTEQUALS(t.first, false); + } + // test 2.0: test at the boundaries + { + auto t = map.at(0, 0); + TESTEQUALS(t.first, true); + TESTEQUALS(t.second.value(), 0); + t = map.at(10, 0); + TESTEQUALS(t.first, false); + } + { + auto t = map.at(5, 5); + TESTEQUALS(t.first, true); + TESTEQUALS(t.second.value(), 1); + t = map.at(10, 5); + TESTEQUALS(t.first, false); + } + { + auto t = map.at(100, 200); + TESTEQUALS(t.first, true); + TESTEQUALS(t.second.value(), 2); + t = map.at(200, 200); + TESTEQUALS(t.first, false); + } + // Test 3.0 Iterations + { + // Iteration tests + std::map reference; + reference[0] = 0; + reference[5] = 1; + reference[200] = 2; + for (auto it = map.begin(0); it != map.end(); ++it) { // Get all + auto ri = reference.find(it.key()); + if (ri != reference.end()) { + reference.erase(ri); + } + } + TESTEQUALS(reference.empty(), true); + + reference[5] = 5; + for (auto it = map.begin(1); it != map.end(90); ++it) { + auto ri = reference.find(it.key()); + if (ri != reference.end()) { + reference.erase(ri); + } + } + TESTEQUALS(reference.empty(), true); + + reference[5] = 5; + for (auto it = map.between(1,90); it != map.end(); ++it) { + auto ri = reference.find(it.key()); + if (ri != reference.end()) { + reference.erase(ri); + } + } + TESTEQUALS(reference.empty(), true); + } +} + +void test_list() { + +} + +void test_queue() { + +} + + +void container() { + test_map(); + test_list(); + test_queue(); +} + + +}}} // openage::tube::tests diff --git a/libopenage/tubes/test/test_serialization.cpp b/libopenage/tube/test/test_serialization.cpp similarity index 100% rename from libopenage/tubes/test/test_serialization.cpp rename to libopenage/tube/test/test_serialization.cpp diff --git a/libopenage/tube/test/test_tube_types.cpp b/libopenage/tube/test/test_tube_types.cpp new file mode 100644 index 0000000000..7b0c2acbb9 --- /dev/null +++ b/libopenage/tube/test/test_tube_types.cpp @@ -0,0 +1,124 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "../../testing/testing.h" +#include "../keyframe_container.h" +#include "../tube.h" +#include "../tube_continuous.h" +#include "../tube_discrete.h" + + +namespace openage { +namespace tube { +namespace tests { + +void tube_types() { + // Check the base container type + { + KeyframeContainer c; + auto p0 = c.insert(0, 0); + auto p1 = c.insert(1, 1); + auto p2 = c.insert(10, 2); + + // last function tests without hints + TESTEQUALS(c.last(0)->value, 0); + TESTEQUALS(c.last(1)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5)->value, 1); + TESTEQUALS(c.last(10)->value, 2); + TESTEQUALS(c.last(47)->value, 2); + + // last() with hints. Yes this can make a difference. we want to be + // absolutely shure! + // hint p1 + TESTEQUALS(c.last(0, p0)->value, 0); + TESTEQUALS(c.last(1, p0)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p0)->value, 1); + TESTEQUALS(c.last(10, p0)->value, 2); + TESTEQUALS(c.last(47, p0)->value, 2); + + TESTEQUALS(c.last(0, p1)->value, 0); + TESTEQUALS(c.last(1, p1)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p1)->value, 1); + TESTEQUALS(c.last(10, p1)->value, 2); + TESTEQUALS(c.last(47, p1)->value, 2); + + TESTEQUALS(c.last(0, p2)->value, 0); + TESTEQUALS(c.last(1, p2)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p2)->value, 1); + TESTEQUALS(c.last(10, p2)->value, 2); + TESTEQUALS(c.last(47, p2)->value, 2); + + // Now test the basic erase() function + c.erase(c.last(1)); + + TESTEQUALS(c.last(1)->value, 0); + TESTEQUALS(c.last(5)->value, 0); + TESTEQUALS(c.last(47)->value, 2); + + c.erase_after(c.last(99)); // we dont want to have the element itself erased! + TESTEQUALS(c.last(47)->value, 2); + + c.erase_after(c.last(5)); // now since 10 > 5, element with value 2 has to be gone + TESTEQUALS(c.last(47)->value, 0); + } + + // Check the Simple Continuous type + { + Continuous c; + c.set_insert(0, 0); + c.set_insert(10, 1); + + TESTEQUALS(c.get(0), 0); + + TESTEQUALS_FLOAT(c.get(1), 0.1, 1e-7); + } + + { + Continuous c; + c.set_insert(0, 0); + c.set_insert(20, 20); + + TESTEQUALS(c.get(0), 0); + TESTEQUALS(c.get(1), 1); + TESTEQUALS(c.get(7), 7); + + c.set_drop(10, 10); + TESTEQUALS(c.get(0), 0); + TESTEQUALS(c.get(1), 1); + TESTEQUALS(c.get(7), 7); + } + //Check the discrete type + { + Discrete c; + c.set_insert(0, 0); + c.set_insert(10, 10); + + TESTEQUALS(c.get(0), 0); + TESTEQUALS(c.get(1), 0); + TESTEQUALS(c.get(11), 10); + + Discrete complex; + + complex.set_insert(0, "Test 0"); + complex.set_insert(10, "Test 10"); + + TESTEQUALS(complex.get(0), "Test 0"); + TESTEQUALS(complex.get(1), "Test 0"); + TESTEQUALS(complex.get(11), "Test 10"); + + } + + //check set_drop + { + Discrete c; + c.set_insert(0, 0); + c.set_insert(1, 1); + c.set_insert(3, 3); + + TESTEQUALS(c.get(3), 3); + + c.set_drop(2, 10); + TESTEQUALS(c.get(3), 10); + } +} + +}}} // openage::tube::tests diff --git a/libopenage/tubes/tube.cpp b/libopenage/tube/tube.cpp similarity index 100% rename from libopenage/tubes/tube.cpp rename to libopenage/tube/tube.cpp diff --git a/libopenage/tube/tube.h b/libopenage/tube/tube.h new file mode 100644 index 0000000000..b25723621a --- /dev/null +++ b/libopenage/tube/tube.h @@ -0,0 +1,25 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +typedef float tube_time_t; + +template +tube_time_t time(const _T &t) { + return t.time(); +} + +template +tube_time_t existent_from (const _T &t) { + return t.existent_from(); +} + +template +tube_time_t existent_until (const _T &t) { + return t.existent_until(); +} + +}} // openage::tube diff --git a/libopenage/tube/tube_container_iterator.cpp b/libopenage/tube/tube_container_iterator.cpp new file mode 100644 index 0000000000..b1d1b98164 --- /dev/null +++ b/libopenage/tube/tube_container_iterator.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "tube_container_iterator.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tube/tube_container_iterator.h b/libopenage/tube/tube_container_iterator.h new file mode 100644 index 0000000000..cc88233a53 --- /dev/null +++ b/libopenage/tube/tube_container_iterator.h @@ -0,0 +1,89 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +#include + +namespace openage { +namespace tube { + +template +class timed_iterator : public std::iterator< std::bidirectional_iterator_tag, _Ty > +{ +public: + timed_iterator(typename container::const_iterator base, + tube_time_t reference_time) : + base(base), + now(reference_time) {} + + timed_iterator(const timed_iterator &rhs) : + base(rhs.base), + now(rhs.now) {} + + timed_iterator &operator = (const timed_iterator &rhs) { + this->base = rhs.base; + this->now = rhs.now; + return *this; + } + + timed_iterator operator ++() { + ++base; + return *this; + } + + timed_iterator operator ++(int) { + auto tmp = *this; + ++base; + return tmp; + } + + timed_iterator operator --() { + --base; + return *this; + } + + timed_iterator operator --(int) { + auto tmp = *this; + ++base; + return tmp; + } + + const _Ty &operator *() const { + return *base; + } + + const _Ty *operator ->() const { + return &**base; + } + + tube_time_t time() { + return (*this)->time; + } + + bool operator ==(const timed_iterator<_Ty, container> &rhs) const { + return base == rhs.base; + } + + bool operator !=(const timed_iterator<_Ty, container> &rhs) const { + return base != rhs.base; + } + + bool valid() { + return time() < to; + } + + operator bool() { + return valid(); + } + +protected: + typename container_iterator base; + tube_time_t now; + +}; + +}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.cpp b/libopenage/tube/tube_continuous.cpp similarity index 82% rename from libopenage/tubes/filter_iterator.cpp rename to libopenage/tube/tube_continuous.cpp index 790dec54b1..d61b30475a 100644 --- a/libopenage/tubes/filter_iterator.cpp +++ b/libopenage/tube/tube_continuous.cpp @@ -1,6 +1,6 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "filter_iterator.h" +#include "tube_continuous.h" namespace openage { namespace tube { diff --git a/libopenage/tube/tube_continuous.h b/libopenage/tube/tube_continuous.h new file mode 100644 index 0000000000..c73b7fbb6c --- /dev/null +++ b/libopenage/tube/tube_continuous.h @@ -0,0 +1,45 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "value_container.h" + +#include "../log/log.h" + +namespace openage { +namespace tube { + +template +class Continuous : public ValueContainer<_T> { +public: + _T get(const tube_time_t &) const override; +}; + +template +_T Continuous<_T>::get(const tube_time_t &time) const { + auto e = this->container.last(time, this->last_element); + this->last_element = e; + auto nxt = e; + ++nxt; + + double diff_time = 0; + double offset = time - e->time; + // If we do not have a next (buffer underrun!!) we assign values + if (nxt == this->container.end()) { + log::log(WARN << "Continuous buffer underrun. This might be bad! Assuming constant."); + } else { + diff_time = nxt->time - e->time; + } + + if (nxt == this->container.end() // We do not have next - this is bad + || offset == 0 // we do not have an offset - this is performance + || diff_time == 0) { // we do not have diff - this is division-by-zero-error + return e->value; + } else { + // Fraction between time(now) and time(next) that has elapsed + double elapsed_frac = (double)offset / (double)diff_time; + return e->value + (nxt->value - e->value) * elapsed_frac; + } +} + +}} // openage::tube diff --git a/libopenage/tubes/object.cpp b/libopenage/tube/tube_discrete.cpp similarity index 83% rename from libopenage/tubes/object.cpp rename to libopenage/tube/tube_discrete.cpp index 93a463df50..20cb14dadc 100644 --- a/libopenage/tubes/object.cpp +++ b/libopenage/tube/tube_discrete.cpp @@ -1,6 +1,6 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "object.h" +#include "tube_discrete.h" namespace openage { namespace tube { diff --git a/libopenage/tube/tube_discrete.h b/libopenage/tube/tube_discrete.h new file mode 100644 index 0000000000..fda9f420d5 --- /dev/null +++ b/libopenage/tube/tube_discrete.h @@ -0,0 +1,23 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "value_container.h" + +namespace openage { +namespace tube { + +template +class Discrete : public ValueContainer<_T> { +public: + _T get(const tube_time_t &) const override; +}; + +template +_T Discrete<_T>::get(const tube_time_t &time) const { + auto e = this->container.last(time, this->last_element); + this->last_element = e; // TODO if Cacheing? + return e->value; +} + +}} // openage::tube diff --git a/libopenage/tubes/event.cpp b/libopenage/tube/tube_event.cpp similarity index 84% rename from libopenage/tubes/event.cpp rename to libopenage/tube/tube_event.cpp index 30ee97e83b..c6e585d25a 100644 --- a/libopenage/tubes/event.cpp +++ b/libopenage/tube/tube_event.cpp @@ -1,6 +1,6 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "event.h" +#include "tube_event.h" namespace openage { namespace tube { diff --git a/libopenage/tubes/event.h b/libopenage/tube/tube_event.h similarity index 100% rename from libopenage/tubes/event.h rename to libopenage/tube/tube_event.h diff --git a/libopenage/tubes/base.cpp b/libopenage/tube/tube_object.cpp similarity index 84% rename from libopenage/tubes/base.cpp rename to libopenage/tube/tube_object.cpp index bf036928d8..46c07a74d3 100644 --- a/libopenage/tubes/base.cpp +++ b/libopenage/tube/tube_object.cpp @@ -1,6 +1,6 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "base.h" +#include "tube_object.h" namespace openage { namespace tube { diff --git a/libopenage/tubes/object.h b/libopenage/tube/tube_object.h similarity index 100% rename from libopenage/tubes/object.h rename to libopenage/tube/tube_object.h diff --git a/libopenage/tube/tube_objectlist.cpp b/libopenage/tube/tube_objectlist.cpp new file mode 100644 index 0000000000..b7d52005a9 --- /dev/null +++ b/libopenage/tube/tube_objectlist.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "tube_objectlist.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/eventlist.h b/libopenage/tube/tube_objectlist.h similarity index 100% rename from libopenage/tubes/eventlist.h rename to libopenage/tube/tube_objectlist.h diff --git a/libopenage/tubes/eventlist.cpp b/libopenage/tube/tube_queue.cpp similarity index 84% rename from libopenage/tubes/eventlist.cpp rename to libopenage/tube/tube_queue.cpp index e0e67ddf62..80285e5c2f 100644 --- a/libopenage/tubes/eventlist.cpp +++ b/libopenage/tube/tube_queue.cpp @@ -1,6 +1,6 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "eventlist.h" +#include "tube_queue.h" namespace openage { namespace tube { diff --git a/libopenage/tube/tube_queue.h b/libopenage/tube/tube_queue.h new file mode 100644 index 0000000000..13dab6700e --- /dev/null +++ b/libopenage/tube/tube_queue.h @@ -0,0 +1,30 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + + +#include "tube.h" +// #include "tube_filter_iterator.h" + +#include + +namespace openage { +namespace tube { + +template +class Queue { +public: + // Reading Access + const _T &front(const tube_time_t &) const; +// TODO define the TubeQueueIterator +// tube_filter_iterator<_T, Queue> begin(const tube_time_t &); +// tube_filter_iterator<_T, Queue> end(const tube_time_t &); + + // Modifying access + void pop(const tube_time_t &); + +private: + std::deque<_T> container; +}; + +}} // openage::tube diff --git a/libopenage/tube/unordered_map.h b/libopenage/tube/unordered_map.h new file mode 100644 index 0000000000..ca53ae0d55 --- /dev/null +++ b/libopenage/tube/unordered_map.h @@ -0,0 +1,214 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "tube.h" +#include "map_filter_iterator.h" + +namespace openage { +namespace tube { + +template +class UnorderedMap { + struct map_element { + val_t value; + tube_time_t alive; + tube_time_t dead; + map_element (val_t v, const tube_time_t &a, const tube_time_t &d) + : value(v), + alive(a), + dead(d) {} + }; + std::unordered_map container; + +public: + // Using does not work with templates + typedef typename std::unordered_map::iterator iterator; +// TODO return an std::optional here. + std::pair> operator()(const tube_time_t&, const key_t &); +// TODO return an std::optional here. + std::pair> at(const tube_time_t &, const key_t &); + + TubeMapFilterIterator begin(const tube_time_t &e = std::numeric_limits::infinity()); + TubeMapFilterIterator end(const tube_time_t &e = std::numeric_limits::infinity()); + + + TubeMapFilterIterator insert(const key_t &, const val_t &); + TubeMapFilterIterator insert(const tube_time_t &birth, const key_t &, const val_t &); + TubeMapFilterIterator insert(const tube_time_t &birth, const tube_time_t &death, const key_t &key, const val_t &value); + + TubeMapFilterIterator between(const tube_time_t &start, const tube_time_t &to); + + void birth(const tube_time_t &, const key_t &); + void birth(const tube_time_t &, const TubeMapFilterIterator &); + + void kill(const tube_time_t &, const key_t &); + void kill(const tube_time_t &, const TubeMapFilterIterator &); + + bool is_alive(const tube_time_t &, const key_t &); + bool is_alive(const tube_time_t &, const TubeMapFilterIterator &); + + void clean(const tube_time_t &); // remove all dead elements before that point in time + + void __attribute__((noinline)) dump() { + for (auto i : container) { + std::cout << "Element: " << i.second.value << std::endl;; + } + } +}; + +template +std::pair>> +UnorderedMap::operator()(const tube_time_t &time, + const key_t &key) { + return this->at(time, key); +} + +template +std::pair>> +UnorderedMap::at(const tube_time_t & time, + const key_t & key) { + auto e = this->container.find(key); + if (e != this->container.end() && e->second.alive <= time && e->second.dead >time) { + return std::make_pair( + true, + TubeMapFilterIterator>( + e, + this->container.end(), + time, + std::numeric_limits::infinity())); + } else { + return std::make_pair( + false, + this->end(time)); + } +} + +template +TubeMapFilterIterator> +UnorderedMap::begin(const tube_time_t &time) { + return TubeMapFilterIterator>( + this->container.begin(), + this->container.end(), + time, + std::numeric_limits::infinity()); +} + +template +TubeMapFilterIterator> +UnorderedMap::end(const tube_time_t &time) { + return TubeMapFilterIterator>( + this->container.end(), + this->container.end(), + -std::numeric_limits::infinity(), + time); +} + +template +TubeMapFilterIterator> +UnorderedMap::between(const tube_time_t &from, const tube_time_t &to) { + auto it = TubeMapFilterIterator>( + this->container.begin(), + this->container.end(), + from, + to); + + if (!it.valid(from)) { + ++it; + } + return it; +} + +template +TubeMapFilterIterator> +UnorderedMap::insert(const key_t &key, + const val_t &value) { + return this->insert( + existent_from(value), + existent_until(value), + key, + value); +} + +template +TubeMapFilterIterator> +UnorderedMap::insert(const tube_time_t &alive, + const key_t &key, + const val_t &value) { + return this->insert( + alive, + std::numeric_limits::infinity(), + key, + value); +} + +template +TubeMapFilterIterator> +UnorderedMap::insert(const tube_time_t &alive, + const tube_time_t &dead, + const key_t &key, + const val_t &value) { + map_element e(value, alive, dead); + auto it = this->container.insert(std::make_pair(key, e)); + return TubeMapFilterIterator>( + it.first, + this->container.end(), + alive, + dead); +} + +template +void UnorderedMap::birth(const tube_time_t &time, + const key_t &key) { + auto it = this->container.find(key); + if (it != this->container.end()) { + it->second.alive = time; + } +} + +template +void UnorderedMap::birth(const tube_time_t &time, + const TubeMapFilterIterator &it) { + it->second.alive = time; +} + +template +void UnorderedMap::kill(const tube_time_t &time, + const key_t &key) { + auto it = this->container.find(key); + if (it != this->container.end()) { + it->second.dead = time; + } +} + +template +void UnorderedMap::kill(const tube_time_t &time, + const TubeMapFilterIterator &it) { + it->second.dead = time; +} + +template +bool UnorderedMap::is_alive(const tube_time_t &time, + const key_t &key) { + auto it = this->container.find(key); + if (it != this->container.end()) { + return valid_f(it->second.value, time); + } +} + +template +bool UnorderedMap::is_alive(const tube_time_t &time, + const TubeMapFilterIterator &it) { + return valid_f(it->second.value, time); +} + +template +void UnorderedMap::clean(const tube_time_t &) { + // TODO save everything to a file and be happy. +} + +}} // openage::tube diff --git a/libopenage/tube/value_container.cpp b/libopenage/tube/value_container.cpp new file mode 100644 index 0000000000..a973ab73f1 --- /dev/null +++ b/libopenage/tube/value_container.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "value_container.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tube/value_container.h b/libopenage/tube/value_container.h new file mode 100644 index 0000000000..cd9ba28a0c --- /dev/null +++ b/libopenage/tube/value_container.h @@ -0,0 +1,55 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "keyframe_container.h" + +namespace openage { +namespace tube { + +template +class ValueContainer { +public: + ValueContainer() : + last_element{container.begin()} {} + + virtual _T get(const tube_time_t &t) const=0; + + virtual _T operator ()(const tube_time_t &now) { + return get(now); + } + + virtual bool needs_update(const tube_time_t &at); +public: + // Inserter mode + virtual void set_drop(const tube_time_t &at, const _T &value); + virtual void set_insert(const tube_time_t &at, const _T &value); + +protected: + KeyframeContainer<_T> container; + mutable typename KeyframeContainer<_T>::KeyframeIterator last_element; +}; + +template +void ValueContainer<_T>::set_drop(const tube_time_t &at, const _T &value) { + auto hint = this->container.erase_after(this->container.last(at, this->last_element)); + container.insert(at, value, hint); + last_element = hint; +} + +template +void ValueContainer<_T>::set_insert(const tube_time_t &at, const _T &value) { + this->container.insert(at, value, this->last_element); +} + +template +bool ValueContainer<_T>::needs_update(const tube_time_t &at) { + auto e = this->container.last(at, this->container.end()); + if (e->time > at || ++e == this->container.end() || e->time > at) { + return true; + } else { + return false; + } +} + +}} // openage::tube diff --git a/libopenage/tubes/CMakeLists.txt b/libopenage/tubes/CMakeLists.txt deleted file mode 100644 index 1dd290e5bf..0000000000 --- a/libopenage/tubes/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ - -add_sources(libopenage - base.cpp - container_iterator.cpp - event.cpp - eventlist.cpp - filter_iterator.cpp - object.cpp - simple_continuous.cpp - simple_discrete.cpp - simple_type.cpp - tube.cpp - unordered_map.cpp -) - -add_subdirectory(test) -add_subdirectory(demo) diff --git a/libopenage/tubes/README.md b/libopenage/tubes/README.md deleted file mode 100644 index 6c721e0ed7..0000000000 --- a/libopenage/tubes/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# tubepong - -An experiment how one can work with tubes and predictionmagic in a stateless physical game engine. - -This is a Pong-like game build on top of tubes. diff --git a/libopenage/tubes/base.h b/libopenage/tubes/base.h deleted file mode 100644 index 234d566581..0000000000 --- a/libopenage/tubes/base.h +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "tube.h" - -#include -#include -#include - -namespace openage { -namespace tube { - -template -class tubeelement; - -/** - * A timely ordered list with several management functions - * - * This class manages different time-based management functions for the double- - * linked list approach that lies underneath. It contains a double-linked list - * to be accessed via a non-accurate timing functionality, this means, that for - * getting a value, not the exact timestamp has to be known, it will always return - * the one closest, less or equal to the requested one. - **/ -template -class tubebase { - tubeelement<_T> *begin = nullptr; - tubeelement<_T> *end = nullptr; - - // TODO create a pool where it might be possible to draw memory from -public: - tubebase(); - - ~tubebase(); - - // Get the last element with e->time <= time - tubeelement<_T> *last(const tube_time_t &time, tubeelement<_T>* hint=nullptr) const; - - // Create a new element and insert it into the tree - tubeelement<_T> *create(const tube_time_t &, const _T& value); - - // Insert a newly ekement into the tree, that has not yet been inserted. - void insert(tubeelement<_T> *, tubeelement<_T> *hint = nullptr); - - // Erase the whole list after this element until the end. - void erase_after(tubeelement<_T> *last_valid); - - // Remove the tubeelement from its container - void erase(tubeelement<_T> *e); -}; - -/** - >* A element of the double-linked list tubebase - */ -template -class tubeelement { - friend class tubebase<_T>; -public: - tubeelement *next = nullptr; - tubeelement *prev = nullptr; -private: - // These folks are for tubebase only! - tubeelement(const tube_time_t &time) - : - time(time) {} - - // Contruct it from time and value - tubeelement(const tube_time_t &time, const _T &value) : - time(time), - value(value) - {} - -public: - const tube_time_t time = 0; - _T value = _T(); -}; - - -template -tubebase<_T>::tubebase() { - //Create a default element at -Inf, that can always be dereferenced - so there will by definition never be - //a element that cannot be dereferenced - create(-std::numeric_limits::infinity(), _T()); -} - -template -tubebase<_T>::~tubebase() { - erase_after(begin); - delete(begin); -} - -/** - * Select the element that directly preceedes the given timestamp. - * - * Without a hint, start to iterate at the beginning of the buffer, and return - * the element last element before e->time > time. - * This method returns nullptr, if begin->time > time. - **/ -template -tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hint) const { - tubeelement<_T> *e = hint ? hint : begin; - - if (e == nullptr) { - //throw Error(ERR << "Empty container list!"); - return e; - } - - if (begin->time > time) { - // This will never happen due to the begin->time == -Inf magic! - assert(false); - return nullptr; - } - - // Search in the queue - if (time > e->time) { // the searched element is supposed to be AFTER the hint - // perform the search via ->next - while (e->next != nullptr && time >= e->next->time) { - e = e->next; - } - // e is now one of two options: - // 1. e == end: The last element of the queue was smaller than `time` - // 2. e != end: There was a element with `e->time` > `time` - } else { - // the searched element is supposed to be BEFORE the hint - // perform the search via ->prev - while (e->prev != nullptr && time < e->time) { - e = e->prev; - } - // e is now one of two options: - // 1. e == begin: The time was before every element in the queue - // 2. e != begin: There was an element with `e->time` > `time` - } - - return e; -} - -/** - * Create and insert a new element into this tube - */ -template -tubeelement<_T> *tubebase<_T>::create(const tube_time_t &time, const _T& value) { - // TODO this has to be managed by a memory pool! - auto e = new tubeelement<_T>(time, value); - insert(e); - return e; -} - -/** - * Determine where to insert, and update all references - */ -template -void tubebase<_T>::insert(tubeelement<_T> *e, tubeelement<_T> *hint) { - // There are no elements in the list right now. - if (begin == nullptr) { - begin = e; - end = e; - return; - } - - tubeelement<_T>* at = last(e->time, hint); - - // if "last" cannot point at a location, so there was no element _before_ - // the newly inserted - if (at == nullptr) { - begin->prev = e; - e->next = begin; - begin = e; - } else if (at->next == nullptr || end == at) { - // if next is nullptr, then it has to be at the end, so update the end - at->next = e; - e->prev = at; - end = e; - } else { - // the list is not empty, it is not at the beginning, it is not at the end: - // it has to be in the middle! so we can perform a normal insert - e->next = at->next; - e->prev = at; - at->next->prev = e; - at->next = e; - } -} - - -/** - * Go from the end to the last_valid element, and call erase on all of them - */ -template -void tubebase<_T>::erase_after(tubeelement<_T> *last_valid) { - tubeelement<_T> *e = end; - //Delete from the end to last_valid - while (e != nullptr && e != last_valid) { - tubeelement<_T> *prev = e->prev; - erase(e); - e = prev; - } -} - -/** - * Delete the element from the list and call delete on it. - */ -template -void tubebase<_T>::erase(tubeelement<_T> *e) { - if (e == nullptr) return; - if (begin == e) { - begin = e->next; - } - if (end == e) { - end = e->prev; - } - - if (e->next != nullptr) { - e->next->prev = e->prev; - } - if (e->prev != nullptr) { - e->prev->next = e->next; - } - - delete e; // TODO Memory management magic! -} - -}} // openage::tube diff --git a/libopenage/tubes/container_iterator.h b/libopenage/tubes/container_iterator.h deleted file mode 100644 index 79955ee72a..0000000000 --- a/libopenage/tubes/container_iterator.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "tube.h" - -#include - -namespace openage { -namespace tube { - -template -class timed_iterator : public std::iterator< std::bidirectional_iterator_tag, _Ty > -{ - typename container::const_iterator base; - int64_t from, to; - time_translator_f time_translator; - -public: - timed_iterator(typename container::const_iterator base, int64_t from, int64_t to, const time_translator_f& time_translator) - : base(base) - , from(from) - , to(to) - , time_translator(time_translator) - {} - - timed_iterator(const timed_iterator &rhs) - : base(rhs.base) - , from(rhs.from) - , to(rhs.to) - , time_translator(rhs.time_translator) - {} - - timed_iterator &operator =(const timed_iterator &rhs) - { - this->base = rhs.base; - this->from = rhs.from; - this->to = rhs.to; - this->time_translator = rhs.time_translator; - return *this; - } - - timed_iterator &operator ++() - { - ++base; - return *this; - } - - //We only want to Iterate forward - so maybe delete this? - timed_iterator &operator --() - { - --base; - return *this; - } - - const _Ty &operator *() const - { - return *base; - } - - const _Ty *operator ->() const - { - return &**base; - } - - tube_time_t time() { - return time_translator(**base); - } - - bool operator ==(const timed_iterator<_Ty, container, time_translator_f> &rhs) const - { - return base == rhs.base; - } - - bool operator !=(const timed_iterator<_Ty, container, time_translator_f> &rhs) const - { - return base != rhs.base; - } - - bool valid() - { - return time() < to; - } - - operator bool() - { - return valid(); - } -}; - -}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.h b/libopenage/tubes/filter_iterator.h deleted file mode 100644 index 5e385a758c..0000000000 --- a/libopenage/tubes/filter_iterator.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "tube.h" - -namespace openage { -namespace tube { - -template -class tube_iterator{ -public: - virtual val_t &value() = 0; - virtual bool valid() = 0; -}; - -template -class tube_filter_iterator : - public std::iterator< std::bidirectional_iterator_tag, std::pair >, - public tube_iterator -{ -protected: -// typename container_t::const_iterator base; - typename container_t::iterator base; - - tube_time_t now; - -public: - tube_filter_iterator(const typename container_t::const_iterator &base, const tube_time_t &now) - : base(base) - , now(now) - {} - - tube_filter_iterator(const tube_filter_iterator &rhs) - : base(rhs.base) - , now(rhs.now) - {} - - tube_filter_iterator &operator =(const tube_filter_iterator &rhs) - { - this->base = rhs.base; - this->now = rhs.now; - return *this; - } - - tube_filter_iterator &operator ++() - { - do { - ++base; - } while (base->second.alive > time && base->second.dead < time); - - return *this; - } - - //We only want to Iterate forward - so maybe delete this? - //timed_iterator &operator --() - //{ - // --base; - // return *this; - //} - - std::pair &operator *() const - { - return *base; - } - - std::pair *operator ->() const - { - return &**this; - } - - virtual bool operator ==(const tube_filter_iterator &rhs) const - { - return rhs.now == std::numeric_limits::infinity() - && base == rhs.base; - } - - virtual bool operator !=(const tube_filter_iterator &rhs) const - { - return rhs.now != std::numeric_limits::infinity() - && base != rhs.base; - } - - virtual bool valid() - { - return base->second.alive > now; - } - - operator bool() - { - return valid(); - } -}; - -template -class tube_filter_end_iterator : public tube_filter_iterator { -public: - tube_filter_end_iterator(const typename container_t::const_iterator &base) - : tube_filter_iterator(base, std::numeric_limits::infinity()) - {} - - virtual bool valid() { - return false; - } -}; - -}} // openage::tube diff --git a/libopenage/tubes/objectlist.h b/libopenage/tubes/objectlist.h deleted file mode 100644 index 2be20e6b2a..0000000000 --- a/libopenage/tubes/objectlist.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_continuous.cpp b/libopenage/tubes/simple_continuous.cpp deleted file mode 100644 index c54324a4a5..0000000000 --- a/libopenage/tubes/simple_continuous.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "simple_continuous.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_continuous.h b/libopenage/tubes/simple_continuous.h deleted file mode 100644 index ed125254dd..0000000000 --- a/libopenage/tubes/simple_continuous.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "simple_type.h" - -namespace openage { -namespace tube { - -template -class SimpleContinuous : public SimpleType<_T> { - mutable tube_time_t diff_time; - mutable tube_time_t offset; - -public: - void set_now(const tube_time_t &t) const override; - - _T get() const override; - _T get(const tube_time_t &) const override; - -public: -}; - -template -void SimpleContinuous<_T>::set_now(const tube_time_t &t) const { - SimpleType<_T>::set_now(t); - if (this->e_now == nullptr) { // TODO This Sucks! - diff_time = 0; - offset = 1; - } else { - if (this->e_now->next != nullptr) { - diff_time = this->e_now->next->time - this->e_now->time; - } else { - diff_time = 0; - } - offset = t - this->e_now->time; - } -} - -template -_T SimpleContinuous<_T>::get() const { - double elapsed_frac = (double)offset / (double)diff_time; - if (this->e_now == nullptr) { //TODO This Sucks! - return _T(); - } else if (this->e_now->next == nullptr || offset == 0) { - return this->e_now->value; //If we cannot interpolate, treat as standing still (?) - } else { - return this->e_now->value + (this->e_now->next->value - this->e_now->value) * elapsed_frac; - } -} - -template -_T SimpleContinuous<_T>::get(const tube_time_t &time) const { - this->set_now(time); - return get(); -} - - -}} // openage::tube diff --git a/libopenage/tubes/simple_discrete.cpp b/libopenage/tubes/simple_discrete.cpp deleted file mode 100644 index 3b39b4ec99..0000000000 --- a/libopenage/tubes/simple_discrete.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "simple_discrete.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_discrete.h b/libopenage/tubes/simple_discrete.h deleted file mode 100644 index 968e13fed5..0000000000 --- a/libopenage/tubes/simple_discrete.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "simple_type.h" - -namespace openage { -namespace tube { - -template -class SimpleDiscrete : public SimpleType<_T> { -public: - - _T get() const override; - _T get(const tube_time_t &) const override; -public: -}; - -template -_T SimpleDiscrete<_T>::get() const { - if (this->e_now == nullptr) { // TODO THIS SUCKS! - return _T(); - } else { - return this->e_now->value; - } -} - -template -_T SimpleDiscrete<_T>::get(const tube_time_t &time) const { - this->set_now(time); - return this->get(); -} - -}} // openage::tube diff --git a/libopenage/tubes/simple_type.cpp b/libopenage/tubes/simple_type.cpp deleted file mode 100644 index 918d89f759..0000000000 --- a/libopenage/tubes/simple_type.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "simple_type.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_type.h b/libopenage/tubes/simple_type.h deleted file mode 100644 index 2f8f37d840..0000000000 --- a/libopenage/tubes/simple_type.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "base.h" - -namespace openage { -namespace tube { - -template -class SimpleType { -protected: - tubebase<_T> container; - mutable tubeelement<_T> *e_now; - mutable tube_time_t now; - -public: - SimpleType(); - - // Reader mode - virtual void set_now(const tube_time_t &t) const; - - virtual _T get() const = 0; - virtual _T get(const tube_time_t &t) const; - - virtual _T operator ()() const { - return std::move(get()); - } - - virtual _T operator ()(const tube_time_t &now) { - return std::move(get(now)); - } - - virtual bool needs_update(const tube_time_t &at); -public: - // Inserter mode - void set_drop(const tube_time_t &at, const _T &value); - void set_insert(const tube_time_t &at, const _T &value); -}; - -template -SimpleType<_T>::SimpleType() : - e_now(nullptr), - now() -{} - -template -void SimpleType<_T>::set_now(const tube_time_t &t) const { - now = t; - e_now = container.last(t, e_now); -} - -template -_T SimpleType<_T>::get(const tube_time_t &t) const { - set_now(t); - return get(); -} - -template -void SimpleType<_T>::set_drop(const tube_time_t &at, const _T &value) { - container.erase_after(container.last(at, e_now)); - container.create(at, value); -} - -template -void SimpleType<_T>::set_insert(const tube_time_t &at, const _T &value) { - container.create(at, value); -} - -template -bool SimpleType<_T>::needs_update(const tube_time_t &at) { - auto e = container.last(at, e_now); //TODO take container.end as a hint? - if (e->time > at || e->next == nullptr || e->next->time > at) { - return true; - } else { - return false; - } -} - -}} // openage::tube diff --git a/libopenage/tubes/test/test_container.cpp b/libopenage/tubes/test/test_container.cpp deleted file mode 100644 index 49586d705b..0000000000 --- a/libopenage/tubes/test/test_container.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "../../testing/testing.h" -#include "../base.h" -#include "../container_iterator.h" -#include "../tube.h" -#include "../simple_continuous.h" -#include "../simple_discrete.h" - -namespace openage { -namespace tube { -namespace tests { - -class test_tube_element { -public: - test_tube_element(tube_time_t t, int32_t data) : - time(t), - data(data) - {} - - tube_time_t time; - int32_t data; -}; - -tube_time_t timer (const test_tube_element &t) { - return t.time; -} - -void container() { - // Check the base container type - { - tubebase c; - auto p0 = c.create(0, 0); - auto p1 = c.create(1, 1); - auto p2 = c.create(10, 2); - - // last function tests without hints - TESTEQUALS(c.last(0)->value, 0); - TESTEQUALS(c.last(1)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5)->value, 1); - TESTEQUALS(c.last(10)->value, 2); - TESTEQUALS(c.last(47)->value, 2); - - // last() with hints. Yes this can make a difference. we want to be - // absolutely shure! - // hint p1 - TESTEQUALS(c.last(0, p0)->value, 0); - TESTEQUALS(c.last(1, p0)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5, p0)->value, 1); - TESTEQUALS(c.last(10, p0)->value, 2); - TESTEQUALS(c.last(47, p0)->value, 2); - - TESTEQUALS(c.last(0, p1)->value, 0); - TESTEQUALS(c.last(1, p1)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5, p1)->value, 1); - TESTEQUALS(c.last(10, p1)->value, 2); - TESTEQUALS(c.last(47, p1)->value, 2); - - TESTEQUALS(c.last(0, p2)->value, 0); - TESTEQUALS(c.last(1, p2)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5, p2)->value, 1); - TESTEQUALS(c.last(10, p2)->value, 2); - TESTEQUALS(c.last(47, p2)->value, 2); - - // Now test the basic erase() function - c.erase(c.last(1)); - - TESTEQUALS(c.last(1)->value, 0); - TESTEQUALS(c.last(5)->value, 0); - TESTEQUALS(c.last(47)->value, 2); - - c.erase_after(c.last(99)); // we dont want to have the element itself erased! - TESTEQUALS(c.last(47)->value, 2); - - c.erase_after(c.last(5)); // now since 10 > 5, element with value 2 has to be gone - TESTEQUALS(c.last(47)->value, 0); - } - - // Check the Simple Continuous type - { - SimpleContinuous c; - c.set_insert(0, 0); - c.set_insert(10, 1); - - c.set_now(0); - TESTEQUALS(c.get(), 0); - - c.set_now(1); - TESTEQUALS_FLOAT(c.get(), 0.1, 1e-7); - } - - { - SimpleContinuous c; - c.set_insert(0, 0); - c.set_insert(10, 10); - - c.set_now(0); - TESTEQUALS(c.get(), 0); - - c.set_now(1); - TESTEQUALS(c.get(), 1); - } - //Check the discrete type - { - SimpleDiscrete c; - c.set_insert(0, 0); - c.set_insert(10, 10); - - c.set_now(0); - TESTEQUALS(c.get(), 0); - - c.set_now(1); - TESTEQUALS(c.get(), 0); - - c.set_now(11); - TESTEQUALS(c.get(), 10); - } - - //check set_drop - { - SimpleDiscrete c; - c.set_insert(0, 0); - c.set_insert(1, 1); - c.set_insert(3, 3); - - c.set_now(3); - TESTEQUALS(c.get(), 3); - - c.set_drop(2, 10); - c.set_now(3); - TESTEQUALS(c.get(), 10); - } - - // Iterate tests -/* { - Container container(timer); - - container.insert(std::make_shared(test_tube_element(10, 0))); - container.insert(std::make_shared(test_tube_element(20, 1))); - - // Iterate over everything with boundaries - { - auto it = container.iterate(0, 30); - TESTEQUALS(it.valid(), true); - - TESTEQUALS(it->data, 0); - ++it; - TESTEQUALS(it.valid(), true); - - TESTEQUALS(it->data, 1); - ++it; - TESTEQUALS(it.valid(), false); - - } - - // Iterate only over the first, with boundaries - { - auto it = container.iterate(0, 15); - TESTEQUALS(it.valid(), true); - TESTEQUALS(it->data, 0); - ++it; - TESTEQUALS(it.valid(), false); - } - - // Iterate only over the first, without boundaries - { - auto it = container.iterate(10, 11); - TESTEQUALS(it.valid(), true); - TESTEQUALS(it->data, 0); - ++it; - TESTEQUALS(it.valid(), false); - } - - // Iterate out of boundaries - { - auto it = container.iterate(100, 200); - TESTEQUALS(it.valid(), false); - } - } - - // Some fucked up insert and read stuff, create all the bugs. - { - // TODO have more ideas to fuck up our data structures - }*/ -} - - -}}} // openage::tube::tests diff --git a/libopenage/tubes/test/test_tube_types.cpp b/libopenage/tubes/test/test_tube_types.cpp deleted file mode 100644 index aafa1c21ae..0000000000 --- a/libopenage/tubes/test/test_tube_types.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "../../testing/testing.h" - -namespace openage { -namespace tube { -namespace tests { - -void tube_types() { -} - -}}} // openage::tube::tests diff --git a/libopenage/tubes/tube.h b/libopenage/tubes/tube.h deleted file mode 100644 index 0061659228..0000000000 --- a/libopenage/tubes/tube.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { -namespace tube { - -typedef float tube_time_t; - -}} // openage::tube diff --git a/libopenage/tubes/unordered_map.cpp b/libopenage/tubes/unordered_map.cpp deleted file mode 100644 index c336fedff8..0000000000 --- a/libopenage/tubes/unordered_map.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "unordered_map.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/unordered_map.h b/libopenage/tubes/unordered_map.h deleted file mode 100644 index 830cb21309..0000000000 --- a/libopenage/tubes/unordered_map.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "base.h" -#include "tube.h" -#include "filter_iterator.h" - -namespace openage { -namespace tube { - -template -class UnorderedTubeMap { - struct map_element { - key_t key; - tubebase value; - tube_time_t alive; - tube_time_t dead; - }; - std::unordered_map container; - -public: - val_t &operator()(const tube_time_t&, const key_t &); - val_t &at(const tube_time_t &, const key_t &); - - tube_filter_iterator begin(const tube_time_t &); - - tube_filter_iterator end(const tube_time_t &); - - tube_iterator insert(const tube_time_t &, const key_t &, const val_t &); - tube_iterator insert(const tube_iterator &at, const key_t &, const val_t &); - - void birth(const key_t &, const tube_time_t &); - void birth(const tube_iterator &, const tube_time_t &); - - void kill(const key_t &, const tube_time_t &); - void kill(const tube_iterator &, const tube_time_t &); - - void is_alive(const key_t &, const tube_time_t &); - void is_alive(const tube_iterator &, const tube_time_t &); - - void clean(const tube_time_t &); // remove all dead elements -}; - -template -val_t &UnorderedTubeMap::operator()(const tube_time_t &, const key_t &) { - -} - -template -val_t &UnorderedTubeMap::at(const tube_time_t &, const key_t &) { - -} - -template -tube_filter_iterator> UnorderedTubeMap::begin(const tube_time_t &) { - -} - -template -tube_filter_iterator> UnorderedTubeMap::end(const tube_time_t &) { - -} - -template -tube_iterator UnorderedTubeMap::insert(const tube_time_t &, const key_t &, const val_t &) { - -} - -template -tube_iterator UnorderedTubeMap::insert(const tube_iterator &at, const key_t &, const val_t &) { - -} - -template -void UnorderedTubeMap::birth(const key_t &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::birth(const tube_iterator &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::kill(const key_t &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::kill(const tube_iterator &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::is_alive(const key_t &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::is_alive(const tube_iterator &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::clean(const tube_time_t &) { - -} - -}} // openage::tube diff --git a/openage/testing/main.py b/openage/testing/main.py index 2837e3426e..15bd204a7b 100644 --- a/openage/testing/main.py +++ b/openage/testing/main.py @@ -90,8 +90,15 @@ def process_args(args, error): if (test, 'test') not in test_list: # If the test was not found explicit in the testlist, try to find # all prefixed tests and run them instead. - matched = [elem[0] for elem in test_list - if elem[0].startswith(test) and elem[1] == "test"] + matched = False + for candidate_name, candidate_type in test_list: + if candidate_name.startswith(test) and candidate_type == "test": + matched = True + args.test.append(candidate_name) + if not matched: + error("no such test: " + test) + if matched: + args.test.remove(test) if matched: args.test.extend(matched) From 238e85e48a4448bebfdb24626611288317dd1b06 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sun, 16 Apr 2017 23:20:43 +0200 Subject: [PATCH 05/24] Tube: Added queue, fixed some ugly pylint stuff --- libopenage/tube/datatypes.md | 3 +- libopenage/tube/map_filter_iterator.h | 32 +------- libopenage/tube/queue_filter_iterator.h | 100 ++++++++++++++++++++++ libopenage/tube/test/test_container.cpp | 58 +++++++++++++ libopenage/tube/tube.h | 20 +++++ libopenage/tube/tube_queue.h | 105 ++++++++++++++++++++++-- openage/cabextract/cab.py | 4 +- openage/testing/main.py | 1 + 8 files changed, 283 insertions(+), 40 deletions(-) create mode 100644 libopenage/tube/queue_filter_iterator.h diff --git a/libopenage/tube/datatypes.md b/libopenage/tube/datatypes.md index fdc215c391..feade3a0d4 100644 --- a/libopenage/tube/datatypes.md +++ b/libopenage/tube/datatypes.md @@ -43,7 +43,7 @@ This container is useful for example for unit lists ... Set Container ---------------- -The set container stores items, just as a normal array would. It keeps track of the existence of the items, but does not guarentee any particular ordering (similar to std::unordered_set). +The set container stores items, just as a normal array would. It keeps track of the existence of the items, but does not guarentee any particular ordering (similar to std::unordered_set). This Container is useful for any non-indexed data structures, for example projectiles. Queue Container @@ -55,4 +55,3 @@ This container is useful for example for action queues and buildung queues. TUBE FILES ============ - diff --git a/libopenage/tube/map_filter_iterator.h b/libopenage/tube/map_filter_iterator.h index 49753a0598..139253d306 100644 --- a/libopenage/tube/map_filter_iterator.h +++ b/libopenage/tube/map_filter_iterator.h @@ -10,18 +10,6 @@ namespace openage { namespace tube { -template -class TubeIterator { -public: - virtual val_t &value() = 0; -}; - -template -bool valid(const _T &, const tube_time_t &at); - -template -using _valid_function_t = bool (*)(const _T&, const tube_time_t &); - template base = rhs.base; @@ -91,13 +76,11 @@ class TubeMapFilterIterator : } virtual bool operator ==(const TubeMapFilterIterator &rhs) const { - return rhs.now != std::numeric_limits::infinity() - || this->base == rhs.base; + return this->base == rhs.base; } virtual bool operator !=(const TubeMapFilterIterator &rhs) const { - return rhs.now == std::numeric_limits::infinity() - || this->base != rhs.base; + return this->base != rhs.base; } virtual bool valid(const tube_time_t &time) { @@ -113,11 +96,4 @@ class TubeMapFilterIterator : } }; -template -bool valid(const _T &t, - const tube_time_t& time) { - return existent_from(t) <= time && existent_until(t) > time; -} - - }} // openage::tube diff --git a/libopenage/tube/queue_filter_iterator.h b/libopenage/tube/queue_filter_iterator.h new file mode 100644 index 0000000000..f2b047eaae --- /dev/null +++ b/libopenage/tube/queue_filter_iterator.h @@ -0,0 +1,100 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include + +#include "tube.h" + +namespace openage { +namespace tube { + +template +class Queue; + +template +class TubeQueueFilterIterator : + virtual public std::iterator, + public TubeIterator +{ + friend class Queue; +protected: + typedef typename container_t::iterator iterator_t; + iterator_t base; + iterator_t container_end; + + tube_time_t from; + tube_time_t to; + +public: + TubeQueueFilterIterator(const iterator_t &base, + const iterator_t &container_end, + const tube_time_t &from, + const tube_time_t &to) : + base{base}, + container_end{container_end}, + from{from}, + to{to} {} + + TubeQueueFilterIterator(const TubeQueueFilterIterator &rhs) : + base{rhs.base}, + container_end{rhs.container_end}, + from{rhs.from}, + to{rhs.to} {} + + TubeQueueFilterIterator &operator =(const TubeQueueFilterIterator &rhs) { + this->base = rhs.base; + this->container_end = rhs.container_end; + this->from = rhs.from; + this->to = rhs.to; + return *this; + } + + TubeQueueFilterIterator &operator ++() { + do { + ++this->base; + } while (this->base != this->container_end && + (this->base->time() < from || + this->base->time() > to)); + return *this; + } + + //We only want to Iterate forward - so maybe delete this? + //timed_iterator &operator --() + //{ + // --base; + // return *this; + //} + + val_t &operator *() const { + return this->base->value; + } + + val_t *operator ->() const { + return &**this; + } + + virtual bool operator ==(const TubeQueueFilterIterator &rhs) const { + return this->base == rhs.base; + } + + virtual bool operator !=(const TubeQueueFilterIterator &rhs) const { + return this->base != rhs.base; + } + + virtual bool valid() const { + + if (this->base != this->container_end) { + return this->base->time() >= from && this->base->time() < to; + } + return false; + } + + val_t &value() override { + return this->base->value; + } +}; + +}} // openage::tube diff --git a/libopenage/tube/test/test_container.cpp b/libopenage/tube/test/test_container.cpp index c2918b560f..e5b5aca0c6 100644 --- a/libopenage/tube/test/test_container.cpp +++ b/libopenage/tube/test/test_container.cpp @@ -5,8 +5,10 @@ #include "../tube.h" #include "../tube_continuous.h" #include "../tube_discrete.h" +#include "../tube_queue.h" #include +#include namespace openage { namespace tube { @@ -140,6 +142,62 @@ void test_list() { } void test_queue() { + Queue q; + q.insert(0, 1); + q.insert(2, 2); + q.insert(4, 3); + q.insert(10, 4); + q.dump(); + TESTEQUALS(*q.begin(0), 1); + TESTEQUALS(*q.begin(1), 1); + TESTEQUALS(*q.begin(2), 2); + TESTEQUALS(*q.begin(3), 2); + TESTEQUALS(*q.begin(4), 3); + TESTEQUALS(*q.begin(5), 3); + TESTEQUALS(*q.begin(10), 4); + TESTEQUALS(*q.begin(12), 4); + TESTEQUALS(*q.begin(100000), 4); + + { + std::set reference = {1,2,3}; + for (auto it = q.between(0,6); it != q.end(); ++it) { + auto ri = reference.find(it.value()); + if (ri != reference.end()) { + reference.erase(ri); + } + } + TESTEQUALS(reference.empty(), true); + } + { + std::set reference = {2,3,4}; + for (auto it = q.between(1,40); it != q.end(); ++it) { + auto ri = reference.find(it.value()); + if (ri != reference.end()) { + reference.erase(ri); + } + } + TESTEQUALS(reference.empty(), true); + } + { + std::set reference = {}; + for (auto it = q.between(30,40); it != q.end(); ++it) { + auto ri = reference.find(it.value()); + if (ri != reference.end()) { + reference.erase(ri); + } + } + TESTEQUALS(reference.empty(), true); + } + { + std::set reference = {1,2,3,4}; + for (auto it = q.between(0,40); it != q.end(); ++it) { + auto ri = reference.find(it.value()); + if (ri != reference.end()) { + reference.erase(ri); + } + } + TESTEQUALS(reference.empty(), true); + } } diff --git a/libopenage/tube/tube.h b/libopenage/tube/tube.h index b25723621a..71089b2446 100644 --- a/libopenage/tube/tube.h +++ b/libopenage/tube/tube.h @@ -22,4 +22,24 @@ tube_time_t existent_until (const _T &t) { return t.existent_until(); } +template +class TubeIterator { +public: + virtual val_t &value() = 0; +}; + +template +bool valid(const _T &, const tube_time_t &at); + +template +using _valid_function_t = bool (*)(const _T&, const tube_time_t &); + +template +bool valid(const _T &t, + const tube_time_t& time) { + return existent_from(t) <= time && existent_until(t) > time; +} + + + }} // openage::tube diff --git a/libopenage/tube/tube_queue.h b/libopenage/tube/tube_queue.h index 13dab6700e..0b007db82f 100644 --- a/libopenage/tube/tube_queue.h +++ b/libopenage/tube/tube_queue.h @@ -4,27 +4,118 @@ #include "tube.h" -// #include "tube_filter_iterator.h" +#include "queue_filter_iterator.h" #include +#include namespace openage { namespace tube { template class Queue { + struct queue_wrapper { + tube_time_t _time; + _T value; + + queue_wrapper(const tube_time_t &time, const _T &value) : + _time{time}, + value{value} {} + + tube_time_t time() { + return _time; + } + }; public: + typedef typename std::deque container_t; + typedef typename container_t::iterator iterator; // Reading Access - const _T &front(const tube_time_t &) const; -// TODO define the TubeQueueIterator -// tube_filter_iterator<_T, Queue> begin(const tube_time_t &); -// tube_filter_iterator<_T, Queue> end(const tube_time_t &); + const _T &front(const tube_time_t &) const { + return container.front(); + } // Modifying access - void pop(const tube_time_t &); + TubeQueueFilterIterator<_T, Queue<_T>> begin( + const tube_time_t &t = -std::numeric_limits::infinity()) + { + return TubeQueueFilterIterator<_T, Queue<_T>>( + container.begin(), + container.end(), + t, + std::numeric_limits::infinity()); + } + + TubeQueueFilterIterator<_T, Queue<_T>> end( + const tube_time_t &t = std::numeric_limits::infinity()) + { + return TubeQueueFilterIterator<_T, Queue<_T>>(container.end(), + container.end(), + t, + std::numeric_limits::infinity()); + } + + TubeQueueFilterIterator<_T, Queue<_T>> between( + const tube_time_t &begin = std::numeric_limits::infinity(), + const tube_time_t &end = std::numeric_limits::infinity()) + { + auto it = TubeQueueFilterIterator<_T, Queue<_T>>( + container.begin(), + container.end(), + begin, + end); + if (!it.valid()) { + ++it; + } + return it; + } + + TubeQueueFilterIterator<_T, Queue<_T>> erase(const TubeQueueFilterIterator<_T, Queue<_T>> &t) { + auto it = container.erase(t.base); + auto ct = TubeQueueFilterIterator<_T, Queue<_T>>( + it, + container.end(), + t.from, + t.to); + + if (!ct.valid(t.from)) { + ++ct; + } + return ct; + } + + TubeQueueFilterIterator<_T, Queue<_T>> insert(const tube_time_t & time, const _T &e) { + iterator insertion_point = this->container.end(); + for (auto it = this->container.begin(); it != this->container.end(); ++it) { + if (time < it->time()) { + insertion_point = this->container + .insert(it, queue_wrapper(time, e)); + break; + } + } + if (insertion_point == this->container.end()) { + insertion_point = this->container.insert(this->container.end(), + queue_wrapper(time, e)); + } + + auto ct = TubeQueueFilterIterator<_T, Queue<_T>>( + insertion_point, + container.end(), + time, std::numeric_limits::infinity()); + + if (!ct.valid()) { + ++ct; + } + return ct; + } + + void __attribute__((noinline)) dump() { + for (auto i : container) { + std::cout << i.value << " at " << i.time() << std::endl; + } + } private: - std::deque<_T> container; + container_t container; }; }} // openage::tube diff --git a/openage/cabextract/cab.py b/openage/cabextract/cab.py index fa2f3500f5..22a9e2c551 100644 --- a/openage/cabextract/cab.py +++ b/openage/cabextract/cab.py @@ -336,9 +336,7 @@ def read_folder_headers(self, cab): compressed_data_stream, window_bits=window_bits, reset_interval=0) - - folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) - + folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) # pylint: disable=redefined-variable-type,locally-enabled else: raise Exception("Unknown compression type %d" % compression_type) diff --git a/openage/testing/main.py b/openage/testing/main.py index 15bd204a7b..4fdb54bb0b 100644 --- a/openage/testing/main.py +++ b/openage/testing/main.py @@ -49,6 +49,7 @@ def init_subparser(cli): cli.add_argument("test", nargs='*', help="run this test") +# pylint: disable=too-many-branches def process_args(args, error): """ Processes the given args, detecting errors. """ if not (args.run_all_tests or args.demo or args.test or args.benchmark): From c6b7cff5bee473de1cf9f9f6a604a7ae92a9866c Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Mon, 17 Apr 2017 18:44:43 +0200 Subject: [PATCH 06/24] Tubes: Fixed tests for queue --- libopenage/tube/test/test_container.cpp | 12 ++++++------ libopenage/tube/tube_queue.h | 16 +++++++++++----- openage/cabextract/cab.py | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/libopenage/tube/test/test_container.cpp b/libopenage/tube/test/test_container.cpp index e5b5aca0c6..02d7df32d5 100644 --- a/libopenage/tube/test/test_container.cpp +++ b/libopenage/tube/test/test_container.cpp @@ -147,16 +147,16 @@ void test_queue() { q.insert(2, 2); q.insert(4, 3); q.insert(10, 4); - q.dump(); + q.insert(100001, 5); TESTEQUALS(*q.begin(0), 1); - TESTEQUALS(*q.begin(1), 1); + TESTEQUALS(*q.begin(1), 2); TESTEQUALS(*q.begin(2), 2); - TESTEQUALS(*q.begin(3), 2); + TESTEQUALS(*q.begin(3), 3); TESTEQUALS(*q.begin(4), 3); - TESTEQUALS(*q.begin(5), 3); + TESTEQUALS(*q.begin(5), 4); TESTEQUALS(*q.begin(10), 4); - TESTEQUALS(*q.begin(12), 4); - TESTEQUALS(*q.begin(100000), 4); + TESTEQUALS(*q.begin(12), 5); + TESTEQUALS(*q.begin(100000), 5); { std::set reference = {1,2,3}; diff --git a/libopenage/tube/tube_queue.h b/libopenage/tube/tube_queue.h index 0b007db82f..49416eb955 100644 --- a/libopenage/tube/tube_queue.h +++ b/libopenage/tube/tube_queue.h @@ -38,11 +38,17 @@ class Queue { TubeQueueFilterIterator<_T, Queue<_T>> begin( const tube_time_t &t = -std::numeric_limits::infinity()) { - return TubeQueueFilterIterator<_T, Queue<_T>>( - container.begin(), - container.end(), - t, - std::numeric_limits::infinity()); + for (auto it = this->container.begin(); it != this->container.end(); ++it) { + if (it->time() >= t) { + return TubeQueueFilterIterator<_T, Queue<_T>>( + it, + container.end(), + t, + std::numeric_limits::infinity()); + } + } + + return this->end(t); } TubeQueueFilterIterator<_T, Queue<_T>> end( diff --git a/openage/cabextract/cab.py b/openage/cabextract/cab.py index 22a9e2c551..bb078f554f 100644 --- a/openage/cabextract/cab.py +++ b/openage/cabextract/cab.py @@ -336,7 +336,7 @@ def read_folder_headers(self, cab): compressed_data_stream, window_bits=window_bits, reset_interval=0) - folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) # pylint: disable=redefined-variable-type,locally-enabled + folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) else: raise Exception("Unknown compression type %d" % compression_type) From 6994d21335efd20b77dff281ff8432feb2a17cb7 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 18 Feb 2017 01:46:50 +0100 Subject: [PATCH 07/24] Added tubes logic and epic tubepong The tube demo runs a simple curses based pong, that shall demonstrate the functionality where and why a prediction interface is built. --- libopenage/CMakeLists.txt | 2 +- libopenage/tubes/.gitignore | 31 +++ libopenage/tubes/CMakeLists.txt | 19 ++ libopenage/tubes/README.md | 7 + libopenage/tubes/base.cpp | 9 + libopenage/tubes/base.h | 222 ++++++++++++++++++ libopenage/tubes/container_iterator.cpp | 9 + libopenage/tubes/container_iterator.h | 93 ++++++++ libopenage/tubes/demo/CMakeLists.txt | 19 ++ libopenage/tubes/demo/aicontroller.cpp | 28 +++ libopenage/tubes/demo/aicontroller.h | 21 ++ libopenage/tubes/demo/gamestate.h | 58 +++++ libopenage/tubes/demo/gui.cpp | 149 ++++++++++++ libopenage/tubes/demo/gui.h | 23 ++ libopenage/tubes/demo/main.cpp | 92 ++++++++ libopenage/tubes/demo/physics.cpp | 136 +++++++++++ libopenage/tubes/demo/physics.h | 19 ++ libopenage/tubes/demo/vertex.h | 226 +++++++++++++++++++ libopenage/tubes/event.cpp | 8 + libopenage/tubes/event.h | 8 + libopenage/tubes/eventlist.cpp | 8 + libopenage/tubes/eventlist.h | 8 + libopenage/tubes/filter_iterator.cpp | 8 + libopenage/tubes/filter_iterator.h | 112 +++++++++ libopenage/tubes/object.cpp | 9 + libopenage/tubes/object.h | 14 ++ libopenage/tubes/objectlist.h | 8 + libopenage/tubes/simple_continuous.cpp | 9 + libopenage/tubes/simple_continuous.h | 60 +++++ libopenage/tubes/simple_discrete.cpp | 8 + libopenage/tubes/simple_discrete.h | 35 +++ libopenage/tubes/simple_type.cpp | 9 + libopenage/tubes/simple_type.h | 81 +++++++ libopenage/tubes/test/CMakeLists.txt | 11 + libopenage/tubes/test/test.h | 0 libopenage/tubes/test/test_container.cpp | 188 +++++++++++++++ libopenage/tubes/test/test_serialization.cpp | 16 ++ libopenage/tubes/test/test_tube_types.cpp | 16 ++ libopenage/tubes/tube.cpp | 9 + libopenage/tubes/tube.h | 10 + libopenage/tubes/unordered_map.cpp | 9 + libopenage/tubes/unordered_map.h | 112 +++++++++ 42 files changed, 1918 insertions(+), 1 deletion(-) create mode 100644 libopenage/tubes/.gitignore create mode 100644 libopenage/tubes/CMakeLists.txt create mode 100644 libopenage/tubes/README.md create mode 100644 libopenage/tubes/base.cpp create mode 100644 libopenage/tubes/base.h create mode 100644 libopenage/tubes/container_iterator.cpp create mode 100644 libopenage/tubes/container_iterator.h create mode 100644 libopenage/tubes/demo/CMakeLists.txt create mode 100644 libopenage/tubes/demo/aicontroller.cpp create mode 100644 libopenage/tubes/demo/aicontroller.h create mode 100644 libopenage/tubes/demo/gamestate.h create mode 100644 libopenage/tubes/demo/gui.cpp create mode 100644 libopenage/tubes/demo/gui.h create mode 100644 libopenage/tubes/demo/main.cpp create mode 100644 libopenage/tubes/demo/physics.cpp create mode 100644 libopenage/tubes/demo/physics.h create mode 100644 libopenage/tubes/demo/vertex.h create mode 100644 libopenage/tubes/event.cpp create mode 100644 libopenage/tubes/event.h create mode 100644 libopenage/tubes/eventlist.cpp create mode 100644 libopenage/tubes/eventlist.h create mode 100644 libopenage/tubes/filter_iterator.cpp create mode 100644 libopenage/tubes/filter_iterator.h create mode 100644 libopenage/tubes/object.cpp create mode 100644 libopenage/tubes/object.h create mode 100644 libopenage/tubes/objectlist.h create mode 100644 libopenage/tubes/simple_continuous.cpp create mode 100644 libopenage/tubes/simple_continuous.h create mode 100644 libopenage/tubes/simple_discrete.cpp create mode 100644 libopenage/tubes/simple_discrete.h create mode 100644 libopenage/tubes/simple_type.cpp create mode 100644 libopenage/tubes/simple_type.h create mode 100644 libopenage/tubes/test/CMakeLists.txt create mode 100644 libopenage/tubes/test/test.h create mode 100644 libopenage/tubes/test/test_container.cpp create mode 100644 libopenage/tubes/test/test_serialization.cpp create mode 100644 libopenage/tubes/test/test_tube_types.cpp create mode 100644 libopenage/tubes/tube.cpp create mode 100644 libopenage/tubes/tube.h create mode 100644 libopenage/tubes/unordered_map.cpp create mode 100644 libopenage/tubes/unordered_map.h diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index d418e8bd3d..a10361e236 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -46,7 +46,7 @@ add_subdirectory("rng") add_subdirectory("shader") add_subdirectory("terrain") add_subdirectory("testing") -add_subdirectory("tube") +add_subdirectory("tubes") add_subdirectory("unit") add_subdirectory("util") diff --git a/libopenage/tubes/.gitignore b/libopenage/tubes/.gitignore new file mode 100644 index 0000000000..5ae0e4943c --- /dev/null +++ b/libopenage/tubes/.gitignore @@ -0,0 +1,31 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +*build* diff --git a/libopenage/tubes/CMakeLists.txt b/libopenage/tubes/CMakeLists.txt new file mode 100644 index 0000000000..101abc31e0 --- /dev/null +++ b/libopenage/tubes/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_library(tube STATIC + base.cpp + container_iterator.cpp + event.cpp + eventlist.cpp + filter_iterator.cpp + object.cpp + simple_continuous.cpp + simple_discrete.cpp + simple_type.cpp + tube.cpp + unordered_map.cpp +) + +set_property(TARGET tube PROPERTY CXX_STANDARD 11) + +add_subdirectory(test) +add_subdirectory(demo) diff --git a/libopenage/tubes/README.md b/libopenage/tubes/README.md new file mode 100644 index 0000000000..bbe5e178c6 --- /dev/null +++ b/libopenage/tubes/README.md @@ -0,0 +1,7 @@ +# tubepong + +An experiment how one can work with tubes and predictionmagic in a stateless physical game engine. + +This is a Pong-like game build on top of tubes. + + diff --git a/libopenage/tubes/base.cpp b/libopenage/tubes/base.cpp new file mode 100644 index 0000000000..162b76c4ad --- /dev/null +++ b/libopenage/tubes/base.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "base.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/base.h b/libopenage/tubes/base.h new file mode 100644 index 0000000000..fa6395c240 --- /dev/null +++ b/libopenage/tubes/base.h @@ -0,0 +1,222 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +#include +#include +#include + +namespace openage { +namespace tube { + +template +class tubeelement; + +/** + * A timely ordered list with several management functions + * + * This class manages different time-based management functions for the double- + * linked list approach that lies underneath. It contains a double-linked list + * to be accessed via a non-accurate timing functionality, this means, that for + * getting a value, not the exact timestamp has to be known, it will always return + * the one closest, less or equal to the requested one. + **/ +template +class tubebase { + tubeelement<_T> *begin = nullptr; + tubeelement<_T> *end = nullptr; + + // TODO create a pool where it might be possible to draw memory from +public: + tubebase(); + + ~tubebase(); + + // Get the last element with e->time <= time + tubeelement<_T> *last(const tube_time_t &time, tubeelement<_T>* hint=nullptr) const; + + // Create a new element and insert it into the tree + tubeelement<_T> *create(const tube_time_t &, const _T& value); + + // Insert a newly ekement into the tree, that has not yet been inserted. + void insert(tubeelement<_T> *, tubeelement<_T> *hint = nullptr); + + // Erase the whole list after this element until the end. + void erase_after(tubeelement<_T> *last_valid); + + // Remove the tubeelement from its container + void erase(tubeelement<_T> *e); +}; + +/** + * A element of the double-linked list tubebase + */ +template +class tubeelement { +friend class tubebase<_T>; +public: + tubeelement *next = nullptr; + tubeelement *prev = nullptr; +private: + // These folks are for tubebase only! + tubeelement(const tube_time_t &time) : + time(time) + {} + + // Contruct it from time and value + tubeelement(const tube_time_t &time, const _T &value) : + time(time), + value(value) + {} + +public: + const tube_time_t time = 0; + _T value = _T(); +}; + + +template +tubebase<_T>::tubebase() { + //Create a default element at -Inf, that can always be dereferenced - so there will by definition never be + //a element that cannot be dereferenced + create(-std::numeric_limits::infinity(), _T()); +} + +template +tubebase<_T>::~tubebase() { + erase_after(begin); + delete(begin); +} + +/** + * Select the element that directly preceedes the given timestamp. + * + * Without a hint, start to iterate at the beginning of the buffer, and return + * the element last element before e->time > time. + * This method returns nullptr, if begin->time > time. + **/ +template +tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hint) const { + tubeelement<_T> *e = hint ? hint : begin; + + if (e == nullptr) { + //throw Error(ERR << "Empty container list!"); + return e; + } + + if (begin->time > time){ + // This will never happen due to the begin->time == -Inf magic! + assert(false); + return nullptr; + } + + // Search in the queue + if (time > e->time) { // the searched element is supposed to be AFTER the hint + // perform the search via ->next + while (e->next != nullptr && time >= e->next->time) { + e = e->next; + } + // e is now one of two options: + // 1. e == end: The last element of the queue was smaller than `time` + // 2. e != end: There was a element with `e->time` > `time` + } else { + // the searched element is supposed to be BEFORE the hint + // perform the search via ->prev + while (e->prev != nullptr && time < e->time) { + e = e->prev; + } + // e is now one of two options: + // 1. e == begin: The time was before every element in the queue + // 2. e != begin: There was an element with `e->time` > `time` + } + + return e; +} + +/** + * Create and insert a new element into this tube + */ +template +tubeelement<_T> *tubebase<_T>::create(const tube_time_t &time, const _T& value) { + // TODO this has to be managed by a memory pool! + auto e = new tubeelement<_T>(time, value); + insert(e); + return e; +} + +/** + * Determine where to insert, and update all references + */ +template +void tubebase<_T>::insert(tubeelement<_T> *e, tubeelement<_T> *hint) { + // There are no elements in the list right now. + if (begin == nullptr) { + begin = e; + end = e; + return; + } + + tubeelement<_T>* at = last(e->time, hint); + + // if "last" cannot point at a location, so there was no element _before_ + // the newly inserted + if (at == nullptr) { + begin->prev = e; + e->next = begin; + begin = e; + } else if (at->next == nullptr || end == at) { + // if next is nullptr, then it has to be at the end, so update the end + at->next = e; + e->prev = at; + end = e; + } else { + // the list is not empty, it is not at the beginning, it is not at the end: + // it has to be in the middle! so we can perform a normal insert + e->next = at->next; + e->prev = at; + at->next->prev = e; + at->next = e; + } +} + + +/** + * Go from the end to the last_valid element, and call erase on all of them + */ +template +void tubebase<_T>::erase_after(tubeelement<_T> *last_valid) { + tubeelement<_T> *e = end; + //Delete from the end to last_valid + while (e != nullptr && e != last_valid) { + tubeelement<_T> *prev = e->prev; + erase(e); + e = prev; + } +} + +/** + * Delete the element from the list and call delete on it. + */ +template +void tubebase<_T>::erase(tubeelement<_T> *e) { + if (e == nullptr) return; + if (begin == e) { + begin = e->next; + } + if (end == e) { + end = e->prev; + } + + if (e->next != nullptr) { + e->next->prev = e->prev; + } + if (e->prev != nullptr) { + e->prev->next = e->next; + } + + delete e; // TODO Memory management magic! +} + +}} // openage::tube diff --git a/libopenage/tubes/container_iterator.cpp b/libopenage/tubes/container_iterator.cpp new file mode 100644 index 0000000000..9d3bbe25b3 --- /dev/null +++ b/libopenage/tubes/container_iterator.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "container_iterator.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/container_iterator.h b/libopenage/tubes/container_iterator.h new file mode 100644 index 0000000000..79955ee72a --- /dev/null +++ b/libopenage/tubes/container_iterator.h @@ -0,0 +1,93 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +#include + +namespace openage { +namespace tube { + +template +class timed_iterator : public std::iterator< std::bidirectional_iterator_tag, _Ty > +{ + typename container::const_iterator base; + int64_t from, to; + time_translator_f time_translator; + +public: + timed_iterator(typename container::const_iterator base, int64_t from, int64_t to, const time_translator_f& time_translator) + : base(base) + , from(from) + , to(to) + , time_translator(time_translator) + {} + + timed_iterator(const timed_iterator &rhs) + : base(rhs.base) + , from(rhs.from) + , to(rhs.to) + , time_translator(rhs.time_translator) + {} + + timed_iterator &operator =(const timed_iterator &rhs) + { + this->base = rhs.base; + this->from = rhs.from; + this->to = rhs.to; + this->time_translator = rhs.time_translator; + return *this; + } + + timed_iterator &operator ++() + { + ++base; + return *this; + } + + //We only want to Iterate forward - so maybe delete this? + timed_iterator &operator --() + { + --base; + return *this; + } + + const _Ty &operator *() const + { + return *base; + } + + const _Ty *operator ->() const + { + return &**base; + } + + tube_time_t time() { + return time_translator(**base); + } + + bool operator ==(const timed_iterator<_Ty, container, time_translator_f> &rhs) const + { + return base == rhs.base; + } + + bool operator !=(const timed_iterator<_Ty, container, time_translator_f> &rhs) const + { + return base != rhs.base; + } + + bool valid() + { + return time() < to; + } + + operator bool() + { + return valid(); + } +}; + +}} // openage::tube diff --git a/libopenage/tubes/demo/CMakeLists.txt b/libopenage/tubes/demo/CMakeLists.txt new file mode 100644 index 0000000000..ea05b607e4 --- /dev/null +++ b/libopenage/tubes/demo/CMakeLists.txt @@ -0,0 +1,19 @@ +set(CURSES_NEED_NCURSES TRUE) +find_package(Curses) + +IF (${CURSES_FOUND}) + + include_directories(${CURSES_INCLUDE_DIR}) + link_libraries (tube ${CURSES_LIBRARIES}) + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -pedantic -Wall -Wextra") + add_executable (tubepong + main.cpp + physics.cpp + gui.cpp + aicontroller.cpp + ) + + set_property(TARGET tubepong PROPERTY CXX_STANDARD 14) +ENDIF() + diff --git a/libopenage/tubes/demo/aicontroller.cpp b/libopenage/tubes/demo/aicontroller.cpp new file mode 100644 index 0000000000..3071a274f7 --- /dev/null +++ b/libopenage/tubes/demo/aicontroller.cpp @@ -0,0 +1,28 @@ +#include "aicontroller.h" + +namespace openage { +namespace tubepong { + +std::vector &AIInput::getInputs( + const PongPlayer &player, + const PongBall &ball, + const tube::tube_time_t &now) { + this->event_cache.clear(); + + auto position = player.position.get(now); + + // Yes i know, there is /3 used - instead of the logical /2 - this is to + // create a small safety boundary of 1/3 for enhanced fancyness + + // Ball is below position + if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { + event_cache.push_back(event(player.id, event::DOWN)); + } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { + // Ball is above position + event_cache.push_back(event(player.id, event::UP)); + } + + return this->event_cache; +} + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/aicontroller.h b/libopenage/tubes/demo/aicontroller.h new file mode 100644 index 0000000000..d00abbed29 --- /dev/null +++ b/libopenage/tubes/demo/aicontroller.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "gamestate.h" + +namespace openage { +namespace tubepong { + +class AIInput { +public: + std::vector &getInputs( + const PongPlayer &player, + const PongBall &ball, + const tube::tube_time_t &now); + +private: + std::vector event_cache; +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/gamestate.h b/libopenage/tubes/demo/gamestate.h new file mode 100644 index 0000000000..7f85c87837 --- /dev/null +++ b/libopenage/tubes/demo/gamestate.h @@ -0,0 +1,58 @@ +#pragma once + + +#include "../simple_continuous.h" +#include "../simple_discrete.h" +#include "../object.h" +#include "vertex.h" + +namespace openage { +namespace tubepong { + +struct event { + int player; + enum state_e { + UP, DOWN, START, IDLE, LOST + } state; + event(int id, state_e s) : player(id), state(s) {} + event() : player(0), state(IDLE) {} +}; + +class PongPlayer : public tube::TubeObject { +public: + PongPlayer() { + speed.set_drop(0, 1); + position.set_drop(0, 0.5); + lives.set_drop(0, 1); + state.set_drop(0, event(0, event::IDLE)); + size.set_drop(0, 0.1); + y = 0; + id = 0; + } + + tube::SimpleDiscrete speed; + tube::SimpleContinuous position; + tube::SimpleDiscrete lives; + tube::SimpleDiscrete state; + tube::SimpleDiscrete size; + float y; + int id; +}; + +class PongBall : public tube::TubeObject { +public: + tube::SimpleDiscrete> speed; + tube::SimpleContinuous> position; +}; + +class PongState { +public: + PongPlayer p1; + PongPlayer p2; + + PongBall ball; + + util::vertex<2, float> resolution; +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.cpp b/libopenage/tubes/demo/gui.cpp new file mode 100644 index 0000000000..6c605bd1e3 --- /dev/null +++ b/libopenage/tubes/demo/gui.cpp @@ -0,0 +1,149 @@ +#include "gui.h" + +#include +#include + +namespace openage { +namespace tubepong { + +std::vector &Gui::getInputs(const PongPlayer &player) { + input_cache.clear(); + event evnt; + evnt.player = player.id; + evnt.state = event::IDLE; + timeout(0); + int c = getch(); + //mvprintw(0,1, "IN: %i", c); + switch (c) { + case KEY_DOWN: + evnt.state = event::DOWN; + input_cache.push_back(evnt); + mvprintw(1,1, "DOWN"); + break; + case KEY_UP: + evnt.state = event::UP; + input_cache.push_back(evnt); + mvprintw(1,1, "UP"); + break; + case ' ': + evnt.state = event::START; + break; + default: + break; + } + + return input_cache; +} + +enum { + COLOR_PLAYER1 = 1, + COLOR_PLAYER2 = 2, + COLOR_BALL = 3, + COLOR_DEBUG = 4, + + COLOR_0 = 5, + COLOR_1 = 6, + COLOR_2 = 7, + COLOR_3 = 8, + COLOR_4 = 9, +}; + +Gui::Gui() { + initscr(); + start_color(); + init_pair(COLOR_PLAYER1, COLOR_BLUE,COLOR_BLUE); + init_pair(COLOR_PLAYER2, COLOR_RED,COLOR_RED); + init_pair(COLOR_BALL , COLOR_BLUE,COLOR_WHITE); + init_pair(COLOR_DEBUG , COLOR_WHITE,COLOR_BLACK); + init_pair(COLOR_0, COLOR_RED ,COLOR_BLACK); + init_pair(COLOR_1, COLOR_GREEN ,COLOR_BLACK); + + keypad(stdscr,true); + noecho(); + curs_set(0); +// getmaxyx(stdscr,state.resolution[1], state.resolution[0]); + + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw(4,5," oooooooooo "); + mvprintw(5,5," 888 888 ooooooo ooooooo oooooooo8 "); + mvprintw(6,5," 888oooo88 888 888 888 888 888 88o "); + mvprintw(7,5," 888 888 888 888 888 888oo888o "); + mvprintw(8,5," o888o 88ooo88 o888o o888o 88 888 "); + mvprintw(9,5," 888ooo888 "); + attroff(COLOR_PAIR(COLOR_DEBUG)); + + getch(); +} + +void Gui::draw(PongState &state, const tube::tube_time_t &now) { + erase(); +// clear(); +//Print Score + attron(COLOR_PAIR(COLOR_DEBUG)); + getmaxyx(stdscr, state.resolution[1], state.resolution[0]); + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw(2, state.resolution[0]/2-5, "P1 %i | P2 %i", + state.p1.lives(now), + state.p2.lives(now)); + + mvvline(0, state.resolution[0]/2, ACS_VLINE, state.resolution[1]); + mvprintw(0, 1, "NOW: %f", now); + mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); + mvprintw(2, 1, "P1: %f, %f, %i", state.p1.position(now), state.p1.y, state.p1.state(now).state); + mvprintw(3, 1, "P2: %f, %f, %i", state.p2.position(now), state.p2.y, state.p2.state(now).state); + for (int i = 0; i < 1000; i += 100) { + mvprintw(4 + i / 100, 1, "BALL in %03i: %f | %f; SPEED: %f | %f", + i, + state.ball.position(now + i)[0], + state.ball.position(now + i)[1], + state.ball.speed(now + i)[0], + state.ball.speed(now + i)[1]); + } + + attroff(COLOR_PAIR(COLOR_DEBUG)); + + attron(COLOR_PAIR(COLOR_PLAYER1)); + for(int i=-state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { + mvprintw(state.p1.position(now)+i, + state.p1.y,"|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER1)); + + attron(COLOR_PAIR(COLOR_PLAYER2)); + for(int i=-state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { + mvprintw(state.p2.position(now)+i, + state.p2.y,"|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER2)); + + for (int i = 0; i < 9999; ++i) { + draw_ball(state.ball.position(now + i * 50), i); + } + +/*attron(COLOR_PAIR(COLOR_BALL)); + mvprintw(state.ball.position(now)[1], + state.ball.position(now)[0], + "o"); +*/ + attroff(COLOR_PAIR(COLOR_BALL)); + refresh(); +} + +void Gui::draw_ball(util::vertex<2, float> pos, int idx) { + switch(idx) { + case 0: + attron(COLOR_PAIR(COLOR_0)); + break; + default: + case 1: + attron(COLOR_PAIR(COLOR_1)); + break; + } + + mvprintw((int)(pos[1]), + (int)(pos[0]), + "\xfe"); + standend(); +} + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.h b/libopenage/tubes/demo/gui.h new file mode 100644 index 0000000000..31d50b8b11 --- /dev/null +++ b/libopenage/tubes/demo/gui.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "gamestate.h" + +namespace openage { +namespace tubepong { + + +class Gui { + +public: + Gui(); + std::vector &getInputs(const PongPlayer &player); + void draw(PongState &state, const tube::tube_time_t &now); + void draw_ball(util::vertex<2, float> ball, int idx); + +private: + std::vector input_cache; +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/main.cpp b/libopenage/tubes/demo/main.cpp new file mode 100644 index 0000000000..3dff3136df --- /dev/null +++ b/libopenage/tubes/demo/main.cpp @@ -0,0 +1,92 @@ +#include + +#include + +#include + +#include "gamestate.h" +#include "physics.h" +#include "gui.h" +#include "aicontroller.h" + +using namespace openage; + +typedef std::chrono::high_resolution_clock Clock; + +int main() { + // Restart forever + tubepong::Gui gui; + tubepong::Physics phys; + tubepong::AIInput ai; + bool running = true; + + while (running) { + tubepong::PongState state; + tube::tube_time_t now = 1; + + + state.p1.lives.set_drop(now, 3); + state.p1.id = 0; + state.p1.size.set_drop(now, 4); + state.p2.lives.set_drop(now, 3); + state.p2.id = 1; + state.p2.size.set_drop(now, 4); + + auto init_speed = vertex2f( + ((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, + 0.01f * (rand() % 100) / 70.f); + + gui.draw(state, now); //update gui related parameters + + state.ball.speed.set_drop(now, init_speed); + state.ball.position.set_drop(now, state.resolution * 0.5); + state.p1.position.set_drop(now, state.resolution[1] / 2); + state.p2.position.set_drop(now, state.resolution[1] / 2); + + gui.draw(state, now); //initial drawing with corrected ball + + auto loop_start = Clock::now(); +// std::cout << "1" << std::endl; + now += 1; + std::cout << "p1: " << state.p1.lives.get(now) << " p2 " << state.p2.lives.get(now) << std::endl; + + + while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { +#ifdef HUMAN + phys.processInput( + state, + state.p1, + gui.getInputs(state.p1), + now + ); +#else + phys.processInput( + state, + state.p1, + ai.getInputs(state.p1, state.ball, now), + now + ); +#endif + phys.processInput( + state, + state.p2, + ai.getInputs(state.p2, state.ball, now), + now + ); + + + state.p1.y = 0; + state.p2.y = state.resolution[0]-1; + + phys.update(state, now); + +// std::cout << now << std::endl; + gui.draw(state, now); + usleep(10000); + + // double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); + now += 10; //dt; + loop_start = Clock::now(); + } + } +} diff --git a/libopenage/tubes/demo/physics.cpp b/libopenage/tubes/demo/physics.cpp new file mode 100644 index 0000000000..9ff1b4b6dc --- /dev/null +++ b/libopenage/tubes/demo/physics.cpp @@ -0,0 +1,136 @@ +#include "physics.h" + +#include + +#include + +namespace openage { +namespace tubepong { + +const float extrapolating_time = 100.0f; +const int init_recursion_limit = 50; + +void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const tube::tube_time_t &now) { + for (auto evnt : events) { + //Process only if the future has changed + if (player.state.get(now).state != evnt.state) { + player.state.set_drop(now, evnt); + + switch(evnt.state) { + case event::UP: + case event::DOWN: { + if (evnt.state == event::UP) { + player.speed.set_drop(now, -2); + } else if (evnt.state == event::DOWN) { + player.speed.set_drop(now, 2); + } + player.speed.set_drop(now + extrapolating_time, 0); + + float new_pos = player.position.get(now) + + (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); + if (new_pos < 0) + new_pos = 0; + if (new_pos > state.resolution[1]) + new_pos = state.resolution[1]; + + player.position.set_drop(now+extrapolating_time, new_pos); + evnt.state = event::IDLE; + player.state.set_drop(now + extrapolating_time, evnt); + break; + } + case event::IDLE: + player.position.set_drop(now+extrapolating_time, + player.position.get(now)); + break; + case event::START: + if (player.state.get(now).state == event::LOST) { + state.ball.position.set_drop(now, state.resolution * 0.5); + } + update_ball(state, now, init_recursion_limit); + break; + default: + break; + } + } + } +} + +void Physics::update(PongState &state, const tube::tube_time_t &now) { + + + auto pos = state.ball.position.get(now); + //Handle panel p1 + if (pos[0] <= 1 + && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 + && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 + && state.ball.speed.get(now)[0] < 0) { + //Ball hit the paddel in this frame + auto s = state.ball.speed.get(now); + s[0] *= -1.0; + state.ball.speed.set_drop(now, s); + state.ball.position.set_drop(now, pos); // this line can handle the future! + + update_ball(state, now, init_recursion_limit); + } else if (pos[0] >= state.resolution[0] - 1 + && pos[1] > state.p2.position.get(now) - state.p2.size.get(now) / 2 + && pos[1] < state.p2.position.get(now) + state.p2.size.get(now) / 2 + && state.ball.speed.get(now)[0] > 0) { + //Ball hit the paddel in this frame + auto s = state.ball.speed.get(now); + s[0] *= -1.0; + state.ball.speed.set_drop(now, s); + state.ball.position.set_drop(now, pos); // this line can handle the future! + + update_ball(state, now, init_recursion_limit); + } else if (state.ball.position.needs_update(now)) { + update_ball(state, now, init_recursion_limit); + } + + // Game loose condition + if (pos[0] < 0) { + state.p1.lives.set_drop(now, state.p1.lives.get(now) - 1); + state.p1.state.set_drop(now, event(state.p1.id, event::LOST)); + } + if (pos[0] > state.resolution[0]) { + state.p2.lives.set_drop(now, state.p2.lives.get(now) - 1); + state.p2.state.set_drop(now, event(state.p2.id, event::LOST)); + } + +} + + +void Physics::update_ball(PongState &state, const tube::tube_time_t &now, int recursion_limit) { + //calculate the ball takes to hit a wall. + auto speed = state.ball.speed.get(now); + auto pos = state.ball.position.get(now); + + float ty = 0; + //char mode = ' '; + if (speed [1] > 0) { + ty = (state.resolution[1] - pos[1]) / speed[1]; + //mode = 'v'; + } else if (speed[1] < 0) { + ty = pos[1] / -speed[1]; + //mode = '^'; + } + +/* mvprintw(20 - recursion_limit, 1, "R %i: %c TY %f | pos: %f | %f speed %f | %f res %i | %i", + init_recursion_limit - recursion_limit, mode, + ty, + pos[0], pos[1], + speed[0], speed[1], + state.resolution[0], state.resolution[1] + ); +*/ + if (ty > 0) { + auto hit_pos = pos + speed * ty; + state.ball.position.set_drop(now + ty, hit_pos); + speed[1] *= -1; + state.ball.speed.set_drop(now + ty, speed); + if (recursion_limit > 1) { + update_ball(state, now + ty, recursion_limit - 1); + } + } +} + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/physics.h b/libopenage/tubes/demo/physics.h new file mode 100644 index 0000000000..8a8798bde9 --- /dev/null +++ b/libopenage/tubes/demo/physics.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "gamestate.h" +#include "../tube.h" + +namespace openage { +namespace tubepong { + +class Physics { +public: + void processInput(PongState &, PongPlayer &, std::vector &events, const tube::tube_time_t &now); + void update(PongState &, const tube::tube_time_t &); +protected: + void update_ball(PongState &, const tube::tube_time_t &, int recursion_limit); +}; + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/vertex.h b/libopenage/tubes/demo/vertex.h new file mode 100644 index 0000000000..3e42238598 --- /dev/null +++ b/libopenage/tubes/demo/vertex.h @@ -0,0 +1,226 @@ +#ifndef VERTEX_H +#define VERTEX_H + +#include +#include +#include +#include +#include + +namespace util { + /** + * N-Dimensional vertex of basetype B. + * is used in GFX, world, every POINT can be converted to evth. + * + * Speciality about this version: + * You cannot have a dimension > 4 with a vertex(a,b,c) ctor! + * + * Version 1.4 ( 30. December 2012 ) + * (c) Johannes Walcher, all rights reserved + * NOT COMPATIBLE WITH VERSIONS < 1.0!! + */ + template + class vertex { + private: + _T f[_DIM]; + public: + vertex() { + memset(f, 0, _DIM*sizeof(_T)); + }; + + vertex(_T s[_DIM]) { + memcpy(f, s, _DIM*sizeof(_T)); + }; + + vertex(const vertex<_DIM, _T> &s) { + memcpy(f, s.f, _DIM*sizeof(_T)); + }; + + /** + * Now this can be used as vertex(_T, _T, _T) + */ + //Initialising the first 4 ctors + vertex(_T fst) { + f[0] = fst; + } + vertex(_T fst, _T snd) { + + if (_DIM < 2) { + printf("vertex has too few dimensions"); + throw std::exception(); + } + f[0] = fst; + f[1] = snd; + } + vertex(_T fst, _T snd, _T trd) { + if (_DIM < 3) { + printf("vertex has too few dimensions"); + throw std::exception(); + } + f[0] = fst; + f[1] = snd; + f[2] = trd; + } + vertex(_T arg1, _T arg2, _T arg3, _T arg4) { + if (_DIM < 4) { + printf("vertex has too few dimensions"); + throw std::exception(); + } + f[0] = arg1; + f[1] = arg2; + f[2] = arg3; + f[4] = arg4; + } + + template + vertex<_DIM, _T> &operator=(const vertex<_DIM, _Rhs_Type> &rhs) + { + for (int i= 0; i < _DIM; i++) { + f[i] = (_T)rhs[i]; + } + return *this; + } + + /* + vertex (_T first, ...) + { + f[0] = first; + int n = _DIM; + if (_DIM > 1) { + va_list params; // Zugriffshandle für Parameter + va_start(params, n); // Zugriff vorbereiten + for (int i = 1; i <_DIM; ++i) { + f[i] = va_arg(params, _T); + } + va_end(params); + } + }; + */ + float length() const { + _T sum = 0; + for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; + return sqrt((float)sum); + } + + double d_length() const { + double sum = 0; + for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; + return sqrt((double)sum); + } + + + void normalize() { + float l = length(); + for (int i = 0; i < _DIM; ++i) + f[i] = (_T)(f[i]/l); + } + + _T at(unsigned int p) const { + if (p < _DIM) return f[p]; + else { + printf("Vertex index out of bounds"); + throw std::exception(); + } + } + + operator vertex<_DIM+1, _T>() + { + vertex<_DIM+1, _T> v; + memcpy(&v[0], f, _DIM*sizeof(_T)); + v[_DIM] = 0; + return v; + } + + _T operator[](unsigned int p) const{ + return f[p]; + } + + _T& operator[](unsigned int p) { + return f[p]; + } + + bool operator == (const vertex<_DIM, _T>& s) const { + for (int i = 0; i < _DIM; ++i) { + if (f[i] != s.f[i]) + return false; + } + return true; + }; + + bool operator < (const vertex<_DIM, _T>& s) const { + for (int i = 0; i < _DIM; ++i) { + if (f[i] >= s.f[i]) + return false; + } + return true; + }; + + vertex<_DIM, _T> operator+ (const vertex<_DIM, _T>& rhs) const { + vertex<_DIM, _T> v(*this); + v += rhs; + return v; + }; + + vertex<_DIM, _T>& operator+= (const vertex<_DIM, _T>& s) { + for (int i = 0; i < _DIM; ++i) + f[i] += s.f[i]; + return *this; + }; + + vertex<_DIM, _T> operator- (const vertex<_DIM, _T>& rhs) const { + vertex<_DIM, _T> v(*this); + v -= rhs; + return v; + }; + + vertex<_DIM, _T>& operator-= (const vertex<_DIM, _T>& s) { + for (int i = 0; i < _DIM; ++i) + f[i] -= s.f[i]; + return *this; + }; + + template + vertex<_DIM, _T> operator* (const _RHS &d) const { + vertex<_DIM, _T> r; + for (int i = 0; i < _DIM; ++i) + r[i] = _T(f[i] * d); + return r; + } + + template + operator vertex<_DIM, _RHS> () { + vertex<_DIM, _RHS> r; + for (int i = 0; i < _DIM; ++i) + r[i] = _RHS(f[i]); + return r; + } + + _T dot(const vertex<_DIM, _T> &v) const { + _T r = _T(); + for (int i = 0; i < _DIM; i++) { + r += f[i] * v.f[i]; + } + return r; + } + + vertex<_DIM, _T> cross(const vertex<_DIM, _T> &rhs) const { + vertex<_DIM, _T> v; + + v[0] = f[1]*rhs[2] - f[2]*rhs[1]; + v[1] = f[2]*rhs[0] - f[0]*rhs[2]; + v[2] = f[0]*rhs[1] - f[1]*rhs[0]; + + return v; + } + + }; +} + +typedef util::vertex<2, int> vertex2i; +typedef util::vertex<3, int> vertex3i; +typedef util::vertex<2, float> vertex2f; +typedef util::vertex<3, double> vertex3d; +typedef util::vertex<3, float> vertex3f; + +#endif + diff --git a/libopenage/tubes/event.cpp b/libopenage/tubes/event.cpp new file mode 100644 index 0000000000..30ee97e83b --- /dev/null +++ b/libopenage/tubes/event.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "event.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/event.h b/libopenage/tubes/event.h new file mode 100644 index 0000000000..2be20e6b2a --- /dev/null +++ b/libopenage/tubes/event.h @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/eventlist.cpp b/libopenage/tubes/eventlist.cpp new file mode 100644 index 0000000000..e0e67ddf62 --- /dev/null +++ b/libopenage/tubes/eventlist.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "eventlist.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/eventlist.h b/libopenage/tubes/eventlist.h new file mode 100644 index 0000000000..2be20e6b2a --- /dev/null +++ b/libopenage/tubes/eventlist.h @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.cpp b/libopenage/tubes/filter_iterator.cpp new file mode 100644 index 0000000000..790dec54b1 --- /dev/null +++ b/libopenage/tubes/filter_iterator.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "filter_iterator.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.h b/libopenage/tubes/filter_iterator.h new file mode 100644 index 0000000000..5e385a758c --- /dev/null +++ b/libopenage/tubes/filter_iterator.h @@ -0,0 +1,112 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include + +#include "tube.h" + +namespace openage { +namespace tube { + +template +class tube_iterator{ +public: + virtual val_t &value() = 0; + virtual bool valid() = 0; +}; + +template +class tube_filter_iterator : + public std::iterator< std::bidirectional_iterator_tag, std::pair >, + public tube_iterator +{ +protected: +// typename container_t::const_iterator base; + typename container_t::iterator base; + + tube_time_t now; + +public: + tube_filter_iterator(const typename container_t::const_iterator &base, const tube_time_t &now) + : base(base) + , now(now) + {} + + tube_filter_iterator(const tube_filter_iterator &rhs) + : base(rhs.base) + , now(rhs.now) + {} + + tube_filter_iterator &operator =(const tube_filter_iterator &rhs) + { + this->base = rhs.base; + this->now = rhs.now; + return *this; + } + + tube_filter_iterator &operator ++() + { + do { + ++base; + } while (base->second.alive > time && base->second.dead < time); + + return *this; + } + + //We only want to Iterate forward - so maybe delete this? + //timed_iterator &operator --() + //{ + // --base; + // return *this; + //} + + std::pair &operator *() const + { + return *base; + } + + std::pair *operator ->() const + { + return &**this; + } + + virtual bool operator ==(const tube_filter_iterator &rhs) const + { + return rhs.now == std::numeric_limits::infinity() + && base == rhs.base; + } + + virtual bool operator !=(const tube_filter_iterator &rhs) const + { + return rhs.now != std::numeric_limits::infinity() + && base != rhs.base; + } + + virtual bool valid() + { + return base->second.alive > now; + } + + operator bool() + { + return valid(); + } +}; + +template +class tube_filter_end_iterator : public tube_filter_iterator { +public: + tube_filter_end_iterator(const typename container_t::const_iterator &base) + : tube_filter_iterator(base, std::numeric_limits::infinity()) + {} + + virtual bool valid() { + return false; + } +}; + +}} // openage::tube diff --git a/libopenage/tubes/object.cpp b/libopenage/tubes/object.cpp new file mode 100644 index 0000000000..14a167cb59 --- /dev/null +++ b/libopenage/tubes/object.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "object.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/object.h b/libopenage/tubes/object.h new file mode 100644 index 0000000000..40f5566a72 --- /dev/null +++ b/libopenage/tubes/object.h @@ -0,0 +1,14 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +namespace openage { +namespace tube { + +class TubeObject { +public: +}; + +}} // openage::tube diff --git a/libopenage/tubes/objectlist.h b/libopenage/tubes/objectlist.h new file mode 100644 index 0000000000..2be20e6b2a --- /dev/null +++ b/libopenage/tubes/objectlist.h @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/simple_continuous.cpp b/libopenage/tubes/simple_continuous.cpp new file mode 100644 index 0000000000..1bbbe6452c --- /dev/null +++ b/libopenage/tubes/simple_continuous.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "simple_continuous.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/simple_continuous.h b/libopenage/tubes/simple_continuous.h new file mode 100644 index 0000000000..bf1a1ed9d8 --- /dev/null +++ b/libopenage/tubes/simple_continuous.h @@ -0,0 +1,60 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "simple_type.h" + +namespace openage { +namespace tube { + +template +class SimpleContinuous : public SimpleType<_T> { + mutable tube_time_t diff_time; + mutable tube_time_t offset; + +public: + void set_now(const tube_time_t &t) const override; + + _T get() const override; + _T get(const tube_time_t &) const override; + +public: +}; + +template +void SimpleContinuous<_T>::set_now(const tube_time_t &t) const { + SimpleType<_T>::set_now(t); + if (this->e_now == nullptr) { // TODO This Sucks! + diff_time = 0; + offset = 1; + } else { + if (this->e_now->next != nullptr) { + diff_time = this->e_now->next->time - this->e_now->time; + } else { + diff_time = 0; + } + offset = t - this->e_now->time; + } +} + +template +_T SimpleContinuous<_T>::get() const { + double elapsed_frac = (double)offset / (double)diff_time ; + if (this->e_now == nullptr) { //TODO This Sucks! + return _T(); + } else if (this->e_now->next == nullptr || offset == 0) { + return this->e_now->value; //If we cannot interpolate, treat as standing still (?) + } else { + return this->e_now->value + (this->e_now->next->value - this->e_now->value) * elapsed_frac; + } +} + +template +_T SimpleContinuous<_T>::get(const tube_time_t &time) const { + this->set_now(time); + return get(); +} + + +}} // openage::tube + diff --git a/libopenage/tubes/simple_discrete.cpp b/libopenage/tubes/simple_discrete.cpp new file mode 100644 index 0000000000..3b39b4ec99 --- /dev/null +++ b/libopenage/tubes/simple_discrete.cpp @@ -0,0 +1,8 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "simple_discrete.h" + +namespace openage { +namespace tube { + +}} // openage::tube diff --git a/libopenage/tubes/simple_discrete.h b/libopenage/tubes/simple_discrete.h new file mode 100644 index 0000000000..91406cdcfe --- /dev/null +++ b/libopenage/tubes/simple_discrete.h @@ -0,0 +1,35 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "simple_type.h" + +namespace openage { +namespace tube { + +template +class SimpleDiscrete : public SimpleType<_T> { +public: + + _T get() const override; + _T get(const tube_time_t &) const override; +public: +}; + +template +_T SimpleDiscrete<_T>::get() const { + if (this->e_now == nullptr) { // TODO THIS SUCKS! + return _T(); + } else { + return this->e_now->value; + } +} + +template +_T SimpleDiscrete<_T>::get(const tube_time_t &time) const { + this->set_now(time); + return this->get(); +} + +}} // openage::tube + diff --git a/libopenage/tubes/simple_type.cpp b/libopenage/tubes/simple_type.cpp new file mode 100644 index 0000000000..1d845a6b3f --- /dev/null +++ b/libopenage/tubes/simple_type.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "simple_type.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/simple_type.h b/libopenage/tubes/simple_type.h new file mode 100644 index 0000000000..348ba2b97f --- /dev/null +++ b/libopenage/tubes/simple_type.h @@ -0,0 +1,81 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "base.h" + +namespace openage { +namespace tube { + +template +class SimpleType { +protected: + tubebase<_T> container; + mutable tubeelement<_T> *e_now; + mutable tube_time_t now; + +public: + SimpleType(); + + // Reader mode + virtual void set_now(const tube_time_t &t) const; + + virtual _T get() const = 0; + virtual _T get(const tube_time_t &t) const; + + virtual _T operator ()() const { + return std::move(get()); + } + + virtual _T operator ()(const tube_time_t &now) { + return std::move(get(now)); + } + + virtual bool needs_update(const tube_time_t &at); +public: + // Inserter mode + void set_drop(const tube_time_t &at, const _T &value); + void set_insert(const tube_time_t &at, const _T &value); +}; + +template +SimpleType<_T>::SimpleType() : + e_now(nullptr), + now() +{} + +template +void SimpleType<_T>::set_now(const tube_time_t &t) const { + now = t; + e_now = container.last(t, e_now); +} + +template +_T SimpleType<_T>::get(const tube_time_t &t) const { + set_now(t); + return get(); +} + +template +void SimpleType<_T>::set_drop(const tube_time_t &at, const _T &value) { + container.erase_after(container.last(at, e_now)); + container.create(at, value); +} + +template +void SimpleType<_T>::set_insert(const tube_time_t &at, const _T &value) { + container.create(at, value); +} + +template +bool SimpleType<_T>::needs_update(const tube_time_t &at) { + auto e = container.last(at, e_now); //TODO take container.end as a hint? + if (e->time > at || e->next == nullptr || e->next->time > at) { + return true; + } else { + return false; + } +} + +}} // openage::tube + diff --git a/libopenage/tubes/test/CMakeLists.txt b/libopenage/tubes/test/CMakeLists.txt new file mode 100644 index 0000000000..f1bbbca333 --- /dev/null +++ b/libopenage/tubes/test/CMakeLists.txt @@ -0,0 +1,11 @@ +link_libraries(tube) + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") + +add_sources(libopenage + test_container.cpp + test_tube_types.cpp + test_serialization.cpp +) + diff --git a/libopenage/tubes/test/test.h b/libopenage/tubes/test/test.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libopenage/tubes/test/test_container.cpp b/libopenage/tubes/test/test_container.cpp new file mode 100644 index 0000000000..49586d705b --- /dev/null +++ b/libopenage/tubes/test/test_container.cpp @@ -0,0 +1,188 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "../../testing/testing.h" +#include "../base.h" +#include "../container_iterator.h" +#include "../tube.h" +#include "../simple_continuous.h" +#include "../simple_discrete.h" + +namespace openage { +namespace tube { +namespace tests { + +class test_tube_element { +public: + test_tube_element(tube_time_t t, int32_t data) : + time(t), + data(data) + {} + + tube_time_t time; + int32_t data; +}; + +tube_time_t timer (const test_tube_element &t) { + return t.time; +} + +void container() { + // Check the base container type + { + tubebase c; + auto p0 = c.create(0, 0); + auto p1 = c.create(1, 1); + auto p2 = c.create(10, 2); + + // last function tests without hints + TESTEQUALS(c.last(0)->value, 0); + TESTEQUALS(c.last(1)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5)->value, 1); + TESTEQUALS(c.last(10)->value, 2); + TESTEQUALS(c.last(47)->value, 2); + + // last() with hints. Yes this can make a difference. we want to be + // absolutely shure! + // hint p1 + TESTEQUALS(c.last(0, p0)->value, 0); + TESTEQUALS(c.last(1, p0)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p0)->value, 1); + TESTEQUALS(c.last(10, p0)->value, 2); + TESTEQUALS(c.last(47, p0)->value, 2); + + TESTEQUALS(c.last(0, p1)->value, 0); + TESTEQUALS(c.last(1, p1)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p1)->value, 1); + TESTEQUALS(c.last(10, p1)->value, 2); + TESTEQUALS(c.last(47, p1)->value, 2); + + TESTEQUALS(c.last(0, p2)->value, 0); + TESTEQUALS(c.last(1, p2)->value, 1); //last shall give >= not only > ! + TESTEQUALS(c.last(5, p2)->value, 1); + TESTEQUALS(c.last(10, p2)->value, 2); + TESTEQUALS(c.last(47, p2)->value, 2); + + // Now test the basic erase() function + c.erase(c.last(1)); + + TESTEQUALS(c.last(1)->value, 0); + TESTEQUALS(c.last(5)->value, 0); + TESTEQUALS(c.last(47)->value, 2); + + c.erase_after(c.last(99)); // we dont want to have the element itself erased! + TESTEQUALS(c.last(47)->value, 2); + + c.erase_after(c.last(5)); // now since 10 > 5, element with value 2 has to be gone + TESTEQUALS(c.last(47)->value, 0); + } + + // Check the Simple Continuous type + { + SimpleContinuous c; + c.set_insert(0, 0); + c.set_insert(10, 1); + + c.set_now(0); + TESTEQUALS(c.get(), 0); + + c.set_now(1); + TESTEQUALS_FLOAT(c.get(), 0.1, 1e-7); + } + + { + SimpleContinuous c; + c.set_insert(0, 0); + c.set_insert(10, 10); + + c.set_now(0); + TESTEQUALS(c.get(), 0); + + c.set_now(1); + TESTEQUALS(c.get(), 1); + } + //Check the discrete type + { + SimpleDiscrete c; + c.set_insert(0, 0); + c.set_insert(10, 10); + + c.set_now(0); + TESTEQUALS(c.get(), 0); + + c.set_now(1); + TESTEQUALS(c.get(), 0); + + c.set_now(11); + TESTEQUALS(c.get(), 10); + } + + //check set_drop + { + SimpleDiscrete c; + c.set_insert(0, 0); + c.set_insert(1, 1); + c.set_insert(3, 3); + + c.set_now(3); + TESTEQUALS(c.get(), 3); + + c.set_drop(2, 10); + c.set_now(3); + TESTEQUALS(c.get(), 10); + } + + // Iterate tests +/* { + Container container(timer); + + container.insert(std::make_shared(test_tube_element(10, 0))); + container.insert(std::make_shared(test_tube_element(20, 1))); + + // Iterate over everything with boundaries + { + auto it = container.iterate(0, 30); + TESTEQUALS(it.valid(), true); + + TESTEQUALS(it->data, 0); + ++it; + TESTEQUALS(it.valid(), true); + + TESTEQUALS(it->data, 1); + ++it; + TESTEQUALS(it.valid(), false); + + } + + // Iterate only over the first, with boundaries + { + auto it = container.iterate(0, 15); + TESTEQUALS(it.valid(), true); + TESTEQUALS(it->data, 0); + ++it; + TESTEQUALS(it.valid(), false); + } + + // Iterate only over the first, without boundaries + { + auto it = container.iterate(10, 11); + TESTEQUALS(it.valid(), true); + TESTEQUALS(it->data, 0); + ++it; + TESTEQUALS(it.valid(), false); + } + + // Iterate out of boundaries + { + auto it = container.iterate(100, 200); + TESTEQUALS(it.valid(), false); + } + } + + // Some fucked up insert and read stuff, create all the bugs. + { + // TODO have more ideas to fuck up our data structures + }*/ +} + + +}}} // openage::tube::tests diff --git a/libopenage/tubes/test/test_serialization.cpp b/libopenage/tubes/test/test_serialization.cpp new file mode 100644 index 0000000000..a33e2a7aee --- /dev/null +++ b/libopenage/tubes/test/test_serialization.cpp @@ -0,0 +1,16 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "test.h" + +#include "../../testing/testing.h" + +namespace openage { +namespace tube { +namespace tests { + +void serialization() { + +} + +}}} // openage::tube::tests + diff --git a/libopenage/tubes/test/test_tube_types.cpp b/libopenage/tubes/test/test_tube_types.cpp new file mode 100644 index 0000000000..c5e4a098d0 --- /dev/null +++ b/libopenage/tubes/test/test_tube_types.cpp @@ -0,0 +1,16 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "test.h" + + +#include "../../testing/testing.h" + +namespace openage { +namespace tube { +namespace tests { + +void tube_types() { + +} + +}}} // openage::tube::tests diff --git a/libopenage/tubes/tube.cpp b/libopenage/tubes/tube.cpp new file mode 100644 index 0000000000..378783bb1b --- /dev/null +++ b/libopenage/tubes/tube.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "tube.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/tube.h b/libopenage/tubes/tube.h new file mode 100644 index 0000000000..0061659228 --- /dev/null +++ b/libopenage/tubes/tube.h @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace tube { + +typedef float tube_time_t; + +}} // openage::tube diff --git a/libopenage/tubes/unordered_map.cpp b/libopenage/tubes/unordered_map.cpp new file mode 100644 index 0000000000..58b6227d2f --- /dev/null +++ b/libopenage/tubes/unordered_map.cpp @@ -0,0 +1,9 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "unordered_map.h" + +namespace openage { +namespace tube { + +}} // openage::tube + diff --git a/libopenage/tubes/unordered_map.h b/libopenage/tubes/unordered_map.h new file mode 100644 index 0000000000..830cb21309 --- /dev/null +++ b/libopenage/tubes/unordered_map.h @@ -0,0 +1,112 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "base.h" +#include "tube.h" +#include "filter_iterator.h" + +namespace openage { +namespace tube { + +template +class UnorderedTubeMap { + struct map_element { + key_t key; + tubebase value; + tube_time_t alive; + tube_time_t dead; + }; + std::unordered_map container; + +public: + val_t &operator()(const tube_time_t&, const key_t &); + val_t &at(const tube_time_t &, const key_t &); + + tube_filter_iterator begin(const tube_time_t &); + + tube_filter_iterator end(const tube_time_t &); + + tube_iterator insert(const tube_time_t &, const key_t &, const val_t &); + tube_iterator insert(const tube_iterator &at, const key_t &, const val_t &); + + void birth(const key_t &, const tube_time_t &); + void birth(const tube_iterator &, const tube_time_t &); + + void kill(const key_t &, const tube_time_t &); + void kill(const tube_iterator &, const tube_time_t &); + + void is_alive(const key_t &, const tube_time_t &); + void is_alive(const tube_iterator &, const tube_time_t &); + + void clean(const tube_time_t &); // remove all dead elements +}; + +template +val_t &UnorderedTubeMap::operator()(const tube_time_t &, const key_t &) { + +} + +template +val_t &UnorderedTubeMap::at(const tube_time_t &, const key_t &) { + +} + +template +tube_filter_iterator> UnorderedTubeMap::begin(const tube_time_t &) { + +} + +template +tube_filter_iterator> UnorderedTubeMap::end(const tube_time_t &) { + +} + +template +tube_iterator UnorderedTubeMap::insert(const tube_time_t &, const key_t &, const val_t &) { + +} + +template +tube_iterator UnorderedTubeMap::insert(const tube_iterator &at, const key_t &, const val_t &) { + +} + +template +void UnorderedTubeMap::birth(const key_t &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::birth(const tube_iterator &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::kill(const key_t &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::kill(const tube_iterator &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::is_alive(const key_t &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::is_alive(const tube_iterator &, const tube_time_t &) { + +} + +template +void UnorderedTubeMap::clean(const tube_time_t &) { + +} + +}} // openage::tube From b2f7199e7adeb9a0f44b046fd28ca76f94567a18 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 18 Feb 2017 04:14:49 +0100 Subject: [PATCH 08/24] Fixed includes and some whitespaces --- libopenage/tubes/CMakeLists.txt | 4 +- libopenage/tubes/README.md | 2 - libopenage/tubes/base.cpp | 1 - libopenage/tubes/base.h | 20 +- libopenage/tubes/container_iterator.cpp | 1 - libopenage/tubes/demo/CMakeLists.txt | 25 +- libopenage/tubes/demo/aicontroller.cpp | 8 +- libopenage/tubes/demo/aicontroller.h | 2 + libopenage/tubes/demo/gamestate.h | 10 +- libopenage/tubes/demo/gui.cpp | 144 ++++++------ libopenage/tubes/demo/gui.h | 4 +- libopenage/tubes/demo/main.cpp | 28 +-- libopenage/tubes/demo/physics.cpp | 108 ++++----- libopenage/tubes/demo/physics.h | 2 + libopenage/tubes/demo/vertex.h | 226 ------------------- libopenage/tubes/object.cpp | 1 - libopenage/tubes/simple_continuous.cpp | 1 - libopenage/tubes/simple_continuous.h | 5 +- libopenage/tubes/simple_discrete.h | 1 - libopenage/tubes/simple_type.cpp | 1 - libopenage/tubes/simple_type.h | 3 +- libopenage/tubes/test/CMakeLists.txt | 1 - libopenage/tubes/test/test.h | 0 libopenage/tubes/test/test_serialization.cpp | 5 +- libopenage/tubes/test/test_tube_types.cpp | 4 - libopenage/tubes/tube.cpp | 1 - libopenage/tubes/unordered_map.cpp | 1 - 27 files changed, 188 insertions(+), 421 deletions(-) delete mode 100644 libopenage/tubes/demo/vertex.h delete mode 100644 libopenage/tubes/test/test.h diff --git a/libopenage/tubes/CMakeLists.txt b/libopenage/tubes/CMakeLists.txt index 101abc31e0..1dd290e5bf 100644 --- a/libopenage/tubes/CMakeLists.txt +++ b/libopenage/tubes/CMakeLists.txt @@ -1,5 +1,5 @@ -add_library(tube STATIC +add_sources(libopenage base.cpp container_iterator.cpp event.cpp @@ -13,7 +13,5 @@ add_library(tube STATIC unordered_map.cpp ) -set_property(TARGET tube PROPERTY CXX_STANDARD 11) - add_subdirectory(test) add_subdirectory(demo) diff --git a/libopenage/tubes/README.md b/libopenage/tubes/README.md index bbe5e178c6..6c721e0ed7 100644 --- a/libopenage/tubes/README.md +++ b/libopenage/tubes/README.md @@ -3,5 +3,3 @@ An experiment how one can work with tubes and predictionmagic in a stateless physical game engine. This is a Pong-like game build on top of tubes. - - diff --git a/libopenage/tubes/base.cpp b/libopenage/tubes/base.cpp index 162b76c4ad..bf036928d8 100644 --- a/libopenage/tubes/base.cpp +++ b/libopenage/tubes/base.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/base.h b/libopenage/tubes/base.h index fa6395c240..234d566581 100644 --- a/libopenage/tubes/base.h +++ b/libopenage/tubes/base.h @@ -51,25 +51,25 @@ class tubebase { }; /** - * A element of the double-linked list tubebase + >* A element of the double-linked list tubebase */ template class tubeelement { -friend class tubebase<_T>; + friend class tubebase<_T>; public: tubeelement *next = nullptr; tubeelement *prev = nullptr; private: // These folks are for tubebase only! - tubeelement(const tube_time_t &time) : - time(time) - {} + tubeelement(const tube_time_t &time) + : + time(time) {} // Contruct it from time and value tubeelement(const tube_time_t &time, const _T &value) : time(time), value(value) - {} + {} public: const tube_time_t time = 0; @@ -106,7 +106,7 @@ tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hi return e; } - if (begin->time > time){ + if (begin->time > time) { // This will never happen due to the begin->time == -Inf magic! assert(false); return nullptr; @@ -127,7 +127,7 @@ tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hi while (e->prev != nullptr && time < e->time) { e = e->prev; } - // e is now one of two options: + // e is now one of two options: // 1. e == begin: The time was before every element in the queue // 2. e != begin: There was an element with `e->time` > `time` } @@ -196,7 +196,7 @@ void tubebase<_T>::erase_after(tubeelement<_T> *last_valid) { } } -/** +/** * Delete the element from the list and call delete on it. */ template @@ -215,7 +215,7 @@ void tubebase<_T>::erase(tubeelement<_T> *e) { if (e->prev != nullptr) { e->prev->next = e->next; } - + delete e; // TODO Memory management magic! } diff --git a/libopenage/tubes/container_iterator.cpp b/libopenage/tubes/container_iterator.cpp index 9d3bbe25b3..a53a97b94c 100644 --- a/libopenage/tubes/container_iterator.cpp +++ b/libopenage/tubes/container_iterator.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/demo/CMakeLists.txt b/libopenage/tubes/demo/CMakeLists.txt index ea05b607e4..e46acf1aa5 100644 --- a/libopenage/tubes/demo/CMakeLists.txt +++ b/libopenage/tubes/demo/CMakeLists.txt @@ -1,19 +1,6 @@ -set(CURSES_NEED_NCURSES TRUE) -find_package(Curses) - -IF (${CURSES_FOUND}) - - include_directories(${CURSES_INCLUDE_DIR}) - link_libraries (tube ${CURSES_LIBRARIES}) - - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -pedantic -Wall -Wextra") - add_executable (tubepong - main.cpp - physics.cpp - gui.cpp - aicontroller.cpp - ) - - set_property(TARGET tubepong PROPERTY CXX_STANDARD 14) -ENDIF() - +add_sources (libopenage + main.cpp + physics.cpp + gui.cpp + aicontroller.cpp +) diff --git a/libopenage/tubes/demo/aicontroller.cpp b/libopenage/tubes/demo/aicontroller.cpp index 3071a274f7..b58e36b860 100644 --- a/libopenage/tubes/demo/aicontroller.cpp +++ b/libopenage/tubes/demo/aicontroller.cpp @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #include "aicontroller.h" namespace openage { @@ -8,12 +10,12 @@ std::vector &AIInput::getInputs( const PongBall &ball, const tube::tube_time_t &now) { this->event_cache.clear(); - + auto position = player.position.get(now); - // Yes i know, there is /3 used - instead of the logical /2 - this is to + // Yes i know, there is /3 used - instead of the logical /2 - this is to // create a small safety boundary of 1/3 for enhanced fancyness - + // Ball is below position if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { event_cache.push_back(event(player.id, event::DOWN)); diff --git a/libopenage/tubes/demo/aicontroller.h b/libopenage/tubes/demo/aicontroller.h index d00abbed29..1a8c67100a 100644 --- a/libopenage/tubes/demo/aicontroller.h +++ b/libopenage/tubes/demo/aicontroller.h @@ -1,3 +1,5 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + #pragma once #include diff --git a/libopenage/tubes/demo/gamestate.h b/libopenage/tubes/demo/gamestate.h index 7f85c87837..8cc646ed4c 100644 --- a/libopenage/tubes/demo/gamestate.h +++ b/libopenage/tubes/demo/gamestate.h @@ -1,10 +1,12 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #pragma once #include "../simple_continuous.h" #include "../simple_discrete.h" #include "../object.h" -#include "vertex.h" +#include "../../util/vector.h" namespace openage { namespace tubepong { @@ -41,8 +43,8 @@ class PongPlayer : public tube::TubeObject { class PongBall : public tube::TubeObject { public: - tube::SimpleDiscrete> speed; - tube::SimpleContinuous> position; + tube::SimpleDiscrete> speed; + tube::SimpleContinuous> position; }; class PongState { @@ -52,7 +54,7 @@ class PongState { PongBall ball; - util::vertex<2, float> resolution; + util::Vector<2> resolution; }; }} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.cpp b/libopenage/tubes/demo/gui.cpp index 6c605bd1e3..941b2db7d0 100644 --- a/libopenage/tubes/demo/gui.cpp +++ b/libopenage/tubes/demo/gui.cpp @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #include "gui.h" #include @@ -10,26 +12,26 @@ std::vector &Gui::getInputs(const PongPlayer &player) { input_cache.clear(); event evnt; evnt.player = player.id; - evnt.state = event::IDLE; + evnt.state = event::IDLE; timeout(0); int c = getch(); - //mvprintw(0,1, "IN: %i", c); + // mvprintw(0,1, "IN: %i", c); switch (c) { case KEY_DOWN: evnt.state = event::DOWN; input_cache.push_back(evnt); - mvprintw(1,1, "DOWN"); + mvprintw(1, 1, "DOWN"); break; case KEY_UP: evnt.state = event::UP; input_cache.push_back(evnt); - mvprintw(1,1, "UP"); - break; - case ' ': - evnt.state = event::START; - break; - default: + mvprintw(1, 1, "UP"); break; + case ' ': evnt.state = event::START; break; + case 27: // esc or alt + endwin(); + exit(0); + default: break; } return input_cache; @@ -38,8 +40,8 @@ std::vector &Gui::getInputs(const PongPlayer &player) { enum { COLOR_PLAYER1 = 1, COLOR_PLAYER2 = 2, - COLOR_BALL = 3, - COLOR_DEBUG = 4, + COLOR_BALL = 3, + COLOR_DEBUG = 4, COLOR_0 = 5, COLOR_1 = 6, @@ -51,25 +53,31 @@ enum { Gui::Gui() { initscr(); start_color(); - init_pair(COLOR_PLAYER1, COLOR_BLUE,COLOR_BLUE); - init_pair(COLOR_PLAYER2, COLOR_RED,COLOR_RED); - init_pair(COLOR_BALL , COLOR_BLUE,COLOR_WHITE); - init_pair(COLOR_DEBUG , COLOR_WHITE,COLOR_BLACK); - init_pair(COLOR_0, COLOR_RED ,COLOR_BLACK); - init_pair(COLOR_1, COLOR_GREEN ,COLOR_BLACK); - - keypad(stdscr,true); + init_pair(COLOR_PLAYER1, COLOR_BLUE, COLOR_BLUE); + init_pair(COLOR_PLAYER2, COLOR_RED, COLOR_RED); + init_pair(COLOR_BALL, COLOR_BLUE, COLOR_WHITE); + init_pair(COLOR_DEBUG, COLOR_WHITE, COLOR_BLACK); + init_pair(COLOR_0, COLOR_RED, COLOR_BLACK); + init_pair(COLOR_1, COLOR_GREEN, COLOR_BLACK); + + keypad(stdscr, true); noecho(); curs_set(0); -// getmaxyx(stdscr,state.resolution[1], state.resolution[0]); + // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw(4,5," oooooooooo "); - mvprintw(5,5," 888 888 ooooooo ooooooo oooooooo8 "); - mvprintw(6,5," 888oooo88 888 888 888 888 888 88o "); - mvprintw(7,5," 888 888 888 888 888 888oo888o "); - mvprintw(8,5," o888o 88ooo88 o888o o888o 88 888 "); - mvprintw(9,5," 888ooo888 "); + mvprintw( + 4, 5, " oooooooooo "); + mvprintw( + 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); + mvprintw( + 6, 5, " 888oooo88 888 888 888 888 888 88o "); + mvprintw( + 7, 5, " 888 888 888 888 888 888oo888o "); + mvprintw( + 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); + mvprintw( + 9, 5, " 888ooo888 "); attroff(COLOR_PAIR(COLOR_DEBUG)); getch(); @@ -77,42 +85,54 @@ Gui::Gui() { void Gui::draw(PongState &state, const tube::tube_time_t &now) { erase(); -// clear(); -//Print Score + // clear(); + // Print Score attron(COLOR_PAIR(COLOR_DEBUG)); getmaxyx(stdscr, state.resolution[1], state.resolution[0]); attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw(2, state.resolution[0]/2-5, "P1 %i | P2 %i", - state.p1.lives(now), - state.p2.lives(now)); + mvprintw(2, + state.resolution[0] / 2 - 5, + "P1 %i | P2 %i", + state.p1.lives(now), + state.p2.lives(now)); - mvvline(0, state.resolution[0]/2, ACS_VLINE, state.resolution[1]); + mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); mvprintw(0, 1, "NOW: %f", now); mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); - mvprintw(2, 1, "P1: %f, %f, %i", state.p1.position(now), state.p1.y, state.p1.state(now).state); - mvprintw(3, 1, "P2: %f, %f, %i", state.p2.position(now), state.p2.y, state.p2.state(now).state); + mvprintw(2, + 1, + "P1: %f, %f, %i", + state.p1.position(now), + state.p1.y, + state.p1.state(now).state); + mvprintw(3, + 1, + "P2: %f, %f, %i", + state.p2.position(now), + state.p2.y, + state.p2.state(now).state); for (int i = 0; i < 1000; i += 100) { - mvprintw(4 + i / 100, 1, "BALL in %03i: %f | %f; SPEED: %f | %f", - i, - state.ball.position(now + i)[0], - state.ball.position(now + i)[1], - state.ball.speed(now + i)[0], - state.ball.speed(now + i)[1]); + mvprintw(4 + i / 100, + 1, + "BALL in %03i: %f | %f; SPEED: %f | %f", + i, + state.ball.position(now + i)[0], + state.ball.position(now + i)[1], + state.ball.speed(now + i)[0], + state.ball.speed(now + i)[1]); } - + mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); attroff(COLOR_PAIR(COLOR_DEBUG)); attron(COLOR_PAIR(COLOR_PLAYER1)); - for(int i=-state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { - mvprintw(state.p1.position(now)+i, - state.p1.y,"|"); + for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { + mvprintw(state.p1.position(now) + i, state.p1.y, "|"); } attroff(COLOR_PAIR(COLOR_PLAYER1)); attron(COLOR_PAIR(COLOR_PLAYER2)); - for(int i=-state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { - mvprintw(state.p2.position(now)+i, - state.p2.y,"|"); + for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { + mvprintw(state.p2.position(now) + i, state.p2.y, "|"); } attroff(COLOR_PAIR(COLOR_PLAYER2)); @@ -120,30 +140,24 @@ void Gui::draw(PongState &state, const tube::tube_time_t &now) { draw_ball(state.ball.position(now + i * 50), i); } -/*attron(COLOR_PAIR(COLOR_BALL)); - mvprintw(state.ball.position(now)[1], - state.ball.position(now)[0], - "o"); -*/ + /*attron(COLOR_PAIR(COLOR_BALL)); + mvprintw(state.ball.position(now)[1], + state.ball.position(now)[0], + "o"); + */ attroff(COLOR_PAIR(COLOR_BALL)); refresh(); } -void Gui::draw_ball(util::vertex<2, float> pos, int idx) { - switch(idx) { - case 0: - attron(COLOR_PAIR(COLOR_0)); - break; +void Gui::draw_ball(util::Vector<2> pos, int idx) { + switch (idx) { + case 0: attron(COLOR_PAIR(COLOR_0)); break; default: - case 1: - attron(COLOR_PAIR(COLOR_1)); - break; + case 1: attron(COLOR_PAIR(COLOR_1)); break; } - mvprintw((int)(pos[1]), - (int)(pos[0]), - "\xfe"); + mvprintw((int)(pos[1]), (int)(pos[0]), "X"); standend(); } - -}} // openage::tubepong +} +} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.h b/libopenage/tubes/demo/gui.h index 31d50b8b11..f8d2142ff2 100644 --- a/libopenage/tubes/demo/gui.h +++ b/libopenage/tubes/demo/gui.h @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #pragma once #include @@ -14,7 +16,7 @@ class Gui { Gui(); std::vector &getInputs(const PongPlayer &player); void draw(PongState &state, const tube::tube_time_t &now); - void draw_ball(util::vertex<2, float> ball, int idx); + void draw_ball(util::Vector<2> ball, int idx); private: std::vector input_cache; diff --git a/libopenage/tubes/demo/main.cpp b/libopenage/tubes/demo/main.cpp index 3dff3136df..902b247e51 100644 --- a/libopenage/tubes/demo/main.cpp +++ b/libopenage/tubes/demo/main.cpp @@ -1,6 +1,6 @@ -#include +// Copyright 2015-2017 the openage authors. See copying.md for legal info. -#include +#include #include @@ -9,11 +9,12 @@ #include "gui.h" #include "aicontroller.h" -using namespace openage; - typedef std::chrono::high_resolution_clock Clock; -int main() { +namespace openage { +namespace tubepong { + +int demo() { // Restart forever tubepong::Gui gui; tubepong::Physics phys; @@ -24,7 +25,6 @@ int main() { tubepong::PongState state; tube::tube_time_t now = 1; - state.p1.lives.set_drop(now, 3); state.p1.id = 0; state.p1.size.set_drop(now, 4); @@ -32,7 +32,7 @@ int main() { state.p2.id = 1; state.p2.size.set_drop(now, 4); - auto init_speed = vertex2f( + auto init_speed = util::Vector<2>( ((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, 0.01f * (rand() % 100) / 70.f); @@ -46,7 +46,6 @@ int main() { gui.draw(state, now); //initial drawing with corrected ball auto loop_start = Clock::now(); -// std::cout << "1" << std::endl; now += 1; std::cout << "p1: " << state.p1.lives.get(now) << " p2 " << state.p2.lives.get(now) << std::endl; @@ -60,6 +59,7 @@ int main() { now ); #else + gui.getInputs(state.p1); phys.processInput( state, state.p1, @@ -74,19 +74,21 @@ int main() { now ); - state.p1.y = 0; state.p2.y = state.resolution[0]-1; phys.update(state, now); -// std::cout << now << std::endl; gui.draw(state, now); - usleep(10000); + usleep(40000); - // double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); - now += 10; //dt; + double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); + now += dt; + // now += 40; loop_start = Clock::now(); } } + return 0; } + +}} // openage::tubepong diff --git a/libopenage/tubes/demo/physics.cpp b/libopenage/tubes/demo/physics.cpp index 9ff1b4b6dc..a91ef7ac70 100644 --- a/libopenage/tubes/demo/physics.cpp +++ b/libopenage/tubes/demo/physics.cpp @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #include "physics.h" #include @@ -11,63 +13,63 @@ const float extrapolating_time = 100.0f; const int init_recursion_limit = 50; void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const tube::tube_time_t &now) { - for (auto evnt : events) { - //Process only if the future has changed - if (player.state.get(now).state != evnt.state) { - player.state.set_drop(now, evnt); - - switch(evnt.state) { - case event::UP: - case event::DOWN: { - if (evnt.state == event::UP) { - player.speed.set_drop(now, -2); - } else if (evnt.state == event::DOWN) { - player.speed.set_drop(now, 2); + for (auto evnt : events) { + //Process only if the future has changed + if (player.state.get(now).state != evnt.state) { + player.state.set_drop(now, evnt); + + switch(evnt.state) { + case event::UP: + case event::DOWN: { + if (evnt.state == event::UP) { + player.speed.set_drop(now, -2); + } else if (evnt.state == event::DOWN) { + player.speed.set_drop(now, 2); + } + player.speed.set_drop(now + extrapolating_time, 0); + + float new_pos = player.position.get(now) + + (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); + if (new_pos < 0) + new_pos = 0; + if (new_pos > state.resolution[1]) + new_pos = state.resolution[1]; + + player.position.set_drop(now+extrapolating_time, new_pos); + evnt.state = event::IDLE; + player.state.set_drop(now + extrapolating_time, evnt); + break; } - player.speed.set_drop(now + extrapolating_time, 0); - - float new_pos = player.position.get(now) + - (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); - if (new_pos < 0) - new_pos = 0; - if (new_pos > state.resolution[1]) - new_pos = state.resolution[1]; - - player.position.set_drop(now+extrapolating_time, new_pos); - evnt.state = event::IDLE; - player.state.set_drop(now + extrapolating_time, evnt); - break; - } - case event::IDLE: - player.position.set_drop(now+extrapolating_time, - player.position.get(now)); - break; - case event::START: - if (player.state.get(now).state == event::LOST) { - state.ball.position.set_drop(now, state.resolution * 0.5); + case event::IDLE: + player.position.set_drop(now+extrapolating_time, + player.position.get(now)); + break; + case event::START: + if (player.state.get(now).state == event::LOST) { + state.ball.position.set_drop(now, state.resolution * 0.5); + } + update_ball(state, now, init_recursion_limit); + break; + default: + break; } - update_ball(state, now, init_recursion_limit); - break; - default: - break; } } } -} -void Physics::update(PongState &state, const tube::tube_time_t &now) { + void Physics::update(PongState &state, const tube::tube_time_t &now) { - auto pos = state.ball.position.get(now); - //Handle panel p1 - if (pos[0] <= 1 - && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 - && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 - && state.ball.speed.get(now)[0] < 0) { - //Ball hit the paddel in this frame - auto s = state.ball.speed.get(now); - s[0] *= -1.0; - state.ball.speed.set_drop(now, s); + auto pos = state.ball.position.get(now); + //Handle panel p1 + if (pos[0] <= 1 + && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 + && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 + && state.ball.speed.get(now)[0] < 0) { + //Ball hit the paddel in this frame + auto s = state.ball.speed.get(now); + s[0] *= -1.0; + state.ball.speed.set_drop(now, s); state.ball.position.set_drop(now, pos); // this line can handle the future! update_ball(state, now, init_recursion_limit); @@ -85,7 +87,7 @@ void Physics::update(PongState &state, const tube::tube_time_t &now) { } else if (state.ball.position.needs_update(now)) { update_ball(state, now, init_recursion_limit); } - + // Game loose condition if (pos[0] < 0) { state.p1.lives.set_drop(now, state.p1.lives.get(now) - 1); @@ -95,7 +97,7 @@ void Physics::update(PongState &state, const tube::tube_time_t &now) { state.p2.lives.set_drop(now, state.p2.lives.get(now) - 1); state.p2.state.set_drop(now, event(state.p2.id, event::LOST)); } - + } @@ -103,14 +105,14 @@ void Physics::update_ball(PongState &state, const tube::tube_time_t &now, int re //calculate the ball takes to hit a wall. auto speed = state.ball.speed.get(now); auto pos = state.ball.position.get(now); - + float ty = 0; //char mode = ' '; if (speed [1] > 0) { ty = (state.resolution[1] - pos[1]) / speed[1]; //mode = 'v'; } else if (speed[1] < 0) { - ty = pos[1] / -speed[1]; + ty = pos[1] / -speed[1]; //mode = '^'; } diff --git a/libopenage/tubes/demo/physics.h b/libopenage/tubes/demo/physics.h index 8a8798bde9..02a3a72a82 100644 --- a/libopenage/tubes/demo/physics.h +++ b/libopenage/tubes/demo/physics.h @@ -1,3 +1,5 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + #pragma once #include diff --git a/libopenage/tubes/demo/vertex.h b/libopenage/tubes/demo/vertex.h deleted file mode 100644 index 3e42238598..0000000000 --- a/libopenage/tubes/demo/vertex.h +++ /dev/null @@ -1,226 +0,0 @@ -#ifndef VERTEX_H -#define VERTEX_H - -#include -#include -#include -#include -#include - -namespace util { - /** - * N-Dimensional vertex of basetype B. - * is used in GFX, world, every POINT can be converted to evth. - * - * Speciality about this version: - * You cannot have a dimension > 4 with a vertex(a,b,c) ctor! - * - * Version 1.4 ( 30. December 2012 ) - * (c) Johannes Walcher, all rights reserved - * NOT COMPATIBLE WITH VERSIONS < 1.0!! - */ - template - class vertex { - private: - _T f[_DIM]; - public: - vertex() { - memset(f, 0, _DIM*sizeof(_T)); - }; - - vertex(_T s[_DIM]) { - memcpy(f, s, _DIM*sizeof(_T)); - }; - - vertex(const vertex<_DIM, _T> &s) { - memcpy(f, s.f, _DIM*sizeof(_T)); - }; - - /** - * Now this can be used as vertex(_T, _T, _T) - */ - //Initialising the first 4 ctors - vertex(_T fst) { - f[0] = fst; - } - vertex(_T fst, _T snd) { - - if (_DIM < 2) { - printf("vertex has too few dimensions"); - throw std::exception(); - } - f[0] = fst; - f[1] = snd; - } - vertex(_T fst, _T snd, _T trd) { - if (_DIM < 3) { - printf("vertex has too few dimensions"); - throw std::exception(); - } - f[0] = fst; - f[1] = snd; - f[2] = trd; - } - vertex(_T arg1, _T arg2, _T arg3, _T arg4) { - if (_DIM < 4) { - printf("vertex has too few dimensions"); - throw std::exception(); - } - f[0] = arg1; - f[1] = arg2; - f[2] = arg3; - f[4] = arg4; - } - - template - vertex<_DIM, _T> &operator=(const vertex<_DIM, _Rhs_Type> &rhs) - { - for (int i= 0; i < _DIM; i++) { - f[i] = (_T)rhs[i]; - } - return *this; - } - - /* - vertex (_T first, ...) - { - f[0] = first; - int n = _DIM; - if (_DIM > 1) { - va_list params; // Zugriffshandle für Parameter - va_start(params, n); // Zugriff vorbereiten - for (int i = 1; i <_DIM; ++i) { - f[i] = va_arg(params, _T); - } - va_end(params); - } - }; - */ - float length() const { - _T sum = 0; - for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; - return sqrt((float)sum); - } - - double d_length() const { - double sum = 0; - for (int i = 0; i < _DIM; ++i) sum += f[i] * f[i]; - return sqrt((double)sum); - } - - - void normalize() { - float l = length(); - for (int i = 0; i < _DIM; ++i) - f[i] = (_T)(f[i]/l); - } - - _T at(unsigned int p) const { - if (p < _DIM) return f[p]; - else { - printf("Vertex index out of bounds"); - throw std::exception(); - } - } - - operator vertex<_DIM+1, _T>() - { - vertex<_DIM+1, _T> v; - memcpy(&v[0], f, _DIM*sizeof(_T)); - v[_DIM] = 0; - return v; - } - - _T operator[](unsigned int p) const{ - return f[p]; - } - - _T& operator[](unsigned int p) { - return f[p]; - } - - bool operator == (const vertex<_DIM, _T>& s) const { - for (int i = 0; i < _DIM; ++i) { - if (f[i] != s.f[i]) - return false; - } - return true; - }; - - bool operator < (const vertex<_DIM, _T>& s) const { - for (int i = 0; i < _DIM; ++i) { - if (f[i] >= s.f[i]) - return false; - } - return true; - }; - - vertex<_DIM, _T> operator+ (const vertex<_DIM, _T>& rhs) const { - vertex<_DIM, _T> v(*this); - v += rhs; - return v; - }; - - vertex<_DIM, _T>& operator+= (const vertex<_DIM, _T>& s) { - for (int i = 0; i < _DIM; ++i) - f[i] += s.f[i]; - return *this; - }; - - vertex<_DIM, _T> operator- (const vertex<_DIM, _T>& rhs) const { - vertex<_DIM, _T> v(*this); - v -= rhs; - return v; - }; - - vertex<_DIM, _T>& operator-= (const vertex<_DIM, _T>& s) { - for (int i = 0; i < _DIM; ++i) - f[i] -= s.f[i]; - return *this; - }; - - template - vertex<_DIM, _T> operator* (const _RHS &d) const { - vertex<_DIM, _T> r; - for (int i = 0; i < _DIM; ++i) - r[i] = _T(f[i] * d); - return r; - } - - template - operator vertex<_DIM, _RHS> () { - vertex<_DIM, _RHS> r; - for (int i = 0; i < _DIM; ++i) - r[i] = _RHS(f[i]); - return r; - } - - _T dot(const vertex<_DIM, _T> &v) const { - _T r = _T(); - for (int i = 0; i < _DIM; i++) { - r += f[i] * v.f[i]; - } - return r; - } - - vertex<_DIM, _T> cross(const vertex<_DIM, _T> &rhs) const { - vertex<_DIM, _T> v; - - v[0] = f[1]*rhs[2] - f[2]*rhs[1]; - v[1] = f[2]*rhs[0] - f[0]*rhs[2]; - v[2] = f[0]*rhs[1] - f[1]*rhs[0]; - - return v; - } - - }; -} - -typedef util::vertex<2, int> vertex2i; -typedef util::vertex<3, int> vertex3i; -typedef util::vertex<2, float> vertex2f; -typedef util::vertex<3, double> vertex3d; -typedef util::vertex<3, float> vertex3f; - -#endif - diff --git a/libopenage/tubes/object.cpp b/libopenage/tubes/object.cpp index 14a167cb59..93a463df50 100644 --- a/libopenage/tubes/object.cpp +++ b/libopenage/tubes/object.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/simple_continuous.cpp b/libopenage/tubes/simple_continuous.cpp index 1bbbe6452c..c54324a4a5 100644 --- a/libopenage/tubes/simple_continuous.cpp +++ b/libopenage/tubes/simple_continuous.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/simple_continuous.h b/libopenage/tubes/simple_continuous.h index bf1a1ed9d8..ed125254dd 100644 --- a/libopenage/tubes/simple_continuous.h +++ b/libopenage/tubes/simple_continuous.h @@ -39,11 +39,11 @@ void SimpleContinuous<_T>::set_now(const tube_time_t &t) const { template _T SimpleContinuous<_T>::get() const { - double elapsed_frac = (double)offset / (double)diff_time ; + double elapsed_frac = (double)offset / (double)diff_time; if (this->e_now == nullptr) { //TODO This Sucks! return _T(); } else if (this->e_now->next == nullptr || offset == 0) { - return this->e_now->value; //If we cannot interpolate, treat as standing still (?) + return this->e_now->value; //If we cannot interpolate, treat as standing still (?) } else { return this->e_now->value + (this->e_now->next->value - this->e_now->value) * elapsed_frac; } @@ -57,4 +57,3 @@ _T SimpleContinuous<_T>::get(const tube_time_t &time) const { }} // openage::tube - diff --git a/libopenage/tubes/simple_discrete.h b/libopenage/tubes/simple_discrete.h index 91406cdcfe..968e13fed5 100644 --- a/libopenage/tubes/simple_discrete.h +++ b/libopenage/tubes/simple_discrete.h @@ -32,4 +32,3 @@ _T SimpleDiscrete<_T>::get(const tube_time_t &time) const { } }} // openage::tube - diff --git a/libopenage/tubes/simple_type.cpp b/libopenage/tubes/simple_type.cpp index 1d845a6b3f..918d89f759 100644 --- a/libopenage/tubes/simple_type.cpp +++ b/libopenage/tubes/simple_type.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/simple_type.h b/libopenage/tubes/simple_type.h index 348ba2b97f..2f8f37d840 100644 --- a/libopenage/tubes/simple_type.h +++ b/libopenage/tubes/simple_type.h @@ -15,7 +15,7 @@ class SimpleType { mutable tube_time_t now; public: - SimpleType(); + SimpleType(); // Reader mode virtual void set_now(const tube_time_t &t) const; @@ -78,4 +78,3 @@ bool SimpleType<_T>::needs_update(const tube_time_t &at) { } }} // openage::tube - diff --git a/libopenage/tubes/test/CMakeLists.txt b/libopenage/tubes/test/CMakeLists.txt index f1bbbca333..6e340d6393 100644 --- a/libopenage/tubes/test/CMakeLists.txt +++ b/libopenage/tubes/test/CMakeLists.txt @@ -8,4 +8,3 @@ add_sources(libopenage test_tube_types.cpp test_serialization.cpp ) - diff --git a/libopenage/tubes/test/test.h b/libopenage/tubes/test/test.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libopenage/tubes/test/test_serialization.cpp b/libopenage/tubes/test/test_serialization.cpp index a33e2a7aee..af8dd046c7 100644 --- a/libopenage/tubes/test/test_serialization.cpp +++ b/libopenage/tubes/test/test_serialization.cpp @@ -1,7 +1,5 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "test.h" - #include "../../testing/testing.h" namespace openage { @@ -9,8 +7,7 @@ namespace tube { namespace tests { void serialization() { - + } }}} // openage::tube::tests - diff --git a/libopenage/tubes/test/test_tube_types.cpp b/libopenage/tubes/test/test_tube_types.cpp index c5e4a098d0..aafa1c21ae 100644 --- a/libopenage/tubes/test/test_tube_types.cpp +++ b/libopenage/tubes/test/test_tube_types.cpp @@ -1,8 +1,5 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "test.h" - - #include "../../testing/testing.h" namespace openage { @@ -10,7 +7,6 @@ namespace tube { namespace tests { void tube_types() { - } }}} // openage::tube::tests diff --git a/libopenage/tubes/tube.cpp b/libopenage/tubes/tube.cpp index 378783bb1b..4462daac9c 100644 --- a/libopenage/tubes/tube.cpp +++ b/libopenage/tubes/tube.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - diff --git a/libopenage/tubes/unordered_map.cpp b/libopenage/tubes/unordered_map.cpp index 58b6227d2f..c336fedff8 100644 --- a/libopenage/tubes/unordered_map.cpp +++ b/libopenage/tubes/unordered_map.cpp @@ -6,4 +6,3 @@ namespace openage { namespace tube { }} // openage::tube - From 6f52e4fd0f63631f2cd961716bb934bef742d87c Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 18 Feb 2017 04:22:09 +0100 Subject: [PATCH 09/24] Added ncurses to ubuntu installation --- doc/build_instructions/ubuntu_16.04.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build_instructions/ubuntu_16.04.md b/doc/build_instructions/ubuntu_16.04.md index 8a9bcbf7d4..31ef091ced 100644 --- a/doc/build_instructions/ubuntu_16.04.md +++ b/doc/build_instructions/ubuntu_16.04.md @@ -1,5 +1,5 @@ # Prerequisite steps for Ubuntu users (Ubuntu 16.04) - `sudo apt-get update` - - `sudo apt-get install cmake libfreetype6-dev python3-dev python3-pip libepoxy-dev libsdl2-dev libsdl2-image-dev libopusfile-dev libfontconfig1-dev libharfbuzz-dev libpng-dev libncurses5-dev opus-tools python3-pil python3-numpy python3-pygments qtdeclarative5-dev qml-module-qtquick-controls` + - `sudo apt-get install cmake libfreetype6-dev python3-dev python3-pip libepoxy-dev libsdl2-dev libsdl2-image-dev libopusfile-dev libfontconfig1-dev libharfbuzz-dev libncurses5-dev opus-tools python3-pil python3-numpy python3-pygments qtdeclarative5-dev qml-module-qtquick-controls` - `pip3 install cython` From 4598ff6b798fbb33644540f0843bcea2e66f4ac8 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 15 Apr 2017 01:14:10 +0200 Subject: [PATCH 10/24] Tubes: Refactoring, Map and Types --- libopenage/CMakeLists.txt | 2 +- libopenage/tube/datatypes.md | 2 + libopenage/tube/map_filter_iterator.h | 24 +- libopenage/tube/tube.h | 20 -- libopenage/tubes/.gitignore | 31 --- libopenage/tubes/CMakeLists.txt | 17 -- libopenage/tubes/README.md | 5 - libopenage/tubes/base.cpp | 8 - libopenage/tubes/base.h | 222 ------------------- libopenage/tubes/container_iterator.cpp | 8 - libopenage/tubes/container_iterator.h | 93 -------- libopenage/tubes/demo/CMakeLists.txt | 6 - libopenage/tubes/demo/aicontroller.cpp | 30 --- libopenage/tubes/demo/aicontroller.h | 23 -- libopenage/tubes/demo/gamestate.h | 60 ----- libopenage/tubes/demo/gui.cpp | 163 -------------- libopenage/tubes/demo/gui.h | 25 --- libopenage/tubes/demo/main.cpp | 94 -------- libopenage/tubes/demo/physics.cpp | 138 ------------ libopenage/tubes/demo/physics.h | 21 -- libopenage/tubes/event.cpp | 8 - libopenage/tubes/event.h | 8 - libopenage/tubes/eventlist.cpp | 8 - libopenage/tubes/eventlist.h | 8 - libopenage/tubes/filter_iterator.cpp | 8 - libopenage/tubes/filter_iterator.h | 112 ---------- libopenage/tubes/object.cpp | 8 - libopenage/tubes/object.h | 14 -- libopenage/tubes/objectlist.h | 8 - libopenage/tubes/simple_continuous.cpp | 8 - libopenage/tubes/simple_continuous.h | 59 ----- libopenage/tubes/simple_discrete.cpp | 8 - libopenage/tubes/simple_discrete.h | 34 --- libopenage/tubes/simple_type.cpp | 8 - libopenage/tubes/simple_type.h | 80 ------- libopenage/tubes/test/CMakeLists.txt | 10 - libopenage/tubes/test/test_container.cpp | 188 ---------------- libopenage/tubes/test/test_serialization.cpp | 13 -- libopenage/tubes/test/test_tube_types.cpp | 12 - libopenage/tubes/tube.cpp | 8 - libopenage/tubes/tube.h | 10 - libopenage/tubes/unordered_map.cpp | 8 - libopenage/tubes/unordered_map.h | 112 ---------- 43 files changed, 26 insertions(+), 1706 deletions(-) delete mode 100644 libopenage/tubes/.gitignore delete mode 100644 libopenage/tubes/CMakeLists.txt delete mode 100644 libopenage/tubes/README.md delete mode 100644 libopenage/tubes/base.cpp delete mode 100644 libopenage/tubes/base.h delete mode 100644 libopenage/tubes/container_iterator.cpp delete mode 100644 libopenage/tubes/container_iterator.h delete mode 100644 libopenage/tubes/demo/CMakeLists.txt delete mode 100644 libopenage/tubes/demo/aicontroller.cpp delete mode 100644 libopenage/tubes/demo/aicontroller.h delete mode 100644 libopenage/tubes/demo/gamestate.h delete mode 100644 libopenage/tubes/demo/gui.cpp delete mode 100644 libopenage/tubes/demo/gui.h delete mode 100644 libopenage/tubes/demo/main.cpp delete mode 100644 libopenage/tubes/demo/physics.cpp delete mode 100644 libopenage/tubes/demo/physics.h delete mode 100644 libopenage/tubes/event.cpp delete mode 100644 libopenage/tubes/event.h delete mode 100644 libopenage/tubes/eventlist.cpp delete mode 100644 libopenage/tubes/eventlist.h delete mode 100644 libopenage/tubes/filter_iterator.cpp delete mode 100644 libopenage/tubes/filter_iterator.h delete mode 100644 libopenage/tubes/object.cpp delete mode 100644 libopenage/tubes/object.h delete mode 100644 libopenage/tubes/objectlist.h delete mode 100644 libopenage/tubes/simple_continuous.cpp delete mode 100644 libopenage/tubes/simple_continuous.h delete mode 100644 libopenage/tubes/simple_discrete.cpp delete mode 100644 libopenage/tubes/simple_discrete.h delete mode 100644 libopenage/tubes/simple_type.cpp delete mode 100644 libopenage/tubes/simple_type.h delete mode 100644 libopenage/tubes/test/CMakeLists.txt delete mode 100644 libopenage/tubes/test/test_container.cpp delete mode 100644 libopenage/tubes/test/test_serialization.cpp delete mode 100644 libopenage/tubes/test/test_tube_types.cpp delete mode 100644 libopenage/tubes/tube.cpp delete mode 100644 libopenage/tubes/tube.h delete mode 100644 libopenage/tubes/unordered_map.cpp delete mode 100644 libopenage/tubes/unordered_map.h diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index a10361e236..d418e8bd3d 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -46,7 +46,7 @@ add_subdirectory("rng") add_subdirectory("shader") add_subdirectory("terrain") add_subdirectory("testing") -add_subdirectory("tubes") +add_subdirectory("tube") add_subdirectory("unit") add_subdirectory("util") diff --git a/libopenage/tube/datatypes.md b/libopenage/tube/datatypes.md index feade3a0d4..06ea533bb6 100644 --- a/libopenage/tube/datatypes.md +++ b/libopenage/tube/datatypes.md @@ -44,6 +44,7 @@ Set Container ---------------- The set container stores items, just as a normal array would. It keeps track of the existence of the items, but does not guarentee any particular ordering (similar to std::unordered_set). +======= This Container is useful for any non-indexed data structures, for example projectiles. Queue Container @@ -55,3 +56,4 @@ This container is useful for example for action queues and buildung queues. TUBE FILES ============ + diff --git a/libopenage/tube/map_filter_iterator.h b/libopenage/tube/map_filter_iterator.h index 139253d306..6a6bb0a896 100644 --- a/libopenage/tube/map_filter_iterator.h +++ b/libopenage/tube/map_filter_iterator.h @@ -10,6 +10,18 @@ namespace openage { namespace tube { +template +class TubeIterator { +public: + virtual val_t &value() = 0; +}; + +template +bool valid(const _T &, const tube_time_t &at); + +template +using _valid_function_t = bool (*)(const _T&, const tube_time_t &); + template base = rhs.base; @@ -96,4 +111,11 @@ class TubeMapFilterIterator : } }; +template +bool valid(const _T &t, + const tube_time_t& time) { + return existent_from(t) <= time && existent_until(t) > time; +} + + }} // openage::tube diff --git a/libopenage/tube/tube.h b/libopenage/tube/tube.h index 71089b2446..b25723621a 100644 --- a/libopenage/tube/tube.h +++ b/libopenage/tube/tube.h @@ -22,24 +22,4 @@ tube_time_t existent_until (const _T &t) { return t.existent_until(); } -template -class TubeIterator { -public: - virtual val_t &value() = 0; -}; - -template -bool valid(const _T &, const tube_time_t &at); - -template -using _valid_function_t = bool (*)(const _T&, const tube_time_t &); - -template -bool valid(const _T &t, - const tube_time_t& time) { - return existent_from(t) <= time && existent_until(t) > time; -} - - - }} // openage::tube diff --git a/libopenage/tubes/.gitignore b/libopenage/tubes/.gitignore deleted file mode 100644 index 5ae0e4943c..0000000000 --- a/libopenage/tubes/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -*build* diff --git a/libopenage/tubes/CMakeLists.txt b/libopenage/tubes/CMakeLists.txt deleted file mode 100644 index 1dd290e5bf..0000000000 --- a/libopenage/tubes/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ - -add_sources(libopenage - base.cpp - container_iterator.cpp - event.cpp - eventlist.cpp - filter_iterator.cpp - object.cpp - simple_continuous.cpp - simple_discrete.cpp - simple_type.cpp - tube.cpp - unordered_map.cpp -) - -add_subdirectory(test) -add_subdirectory(demo) diff --git a/libopenage/tubes/README.md b/libopenage/tubes/README.md deleted file mode 100644 index 6c721e0ed7..0000000000 --- a/libopenage/tubes/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# tubepong - -An experiment how one can work with tubes and predictionmagic in a stateless physical game engine. - -This is a Pong-like game build on top of tubes. diff --git a/libopenage/tubes/base.cpp b/libopenage/tubes/base.cpp deleted file mode 100644 index bf036928d8..0000000000 --- a/libopenage/tubes/base.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "base.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/base.h b/libopenage/tubes/base.h deleted file mode 100644 index 234d566581..0000000000 --- a/libopenage/tubes/base.h +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "tube.h" - -#include -#include -#include - -namespace openage { -namespace tube { - -template -class tubeelement; - -/** - * A timely ordered list with several management functions - * - * This class manages different time-based management functions for the double- - * linked list approach that lies underneath. It contains a double-linked list - * to be accessed via a non-accurate timing functionality, this means, that for - * getting a value, not the exact timestamp has to be known, it will always return - * the one closest, less or equal to the requested one. - **/ -template -class tubebase { - tubeelement<_T> *begin = nullptr; - tubeelement<_T> *end = nullptr; - - // TODO create a pool where it might be possible to draw memory from -public: - tubebase(); - - ~tubebase(); - - // Get the last element with e->time <= time - tubeelement<_T> *last(const tube_time_t &time, tubeelement<_T>* hint=nullptr) const; - - // Create a new element and insert it into the tree - tubeelement<_T> *create(const tube_time_t &, const _T& value); - - // Insert a newly ekement into the tree, that has not yet been inserted. - void insert(tubeelement<_T> *, tubeelement<_T> *hint = nullptr); - - // Erase the whole list after this element until the end. - void erase_after(tubeelement<_T> *last_valid); - - // Remove the tubeelement from its container - void erase(tubeelement<_T> *e); -}; - -/** - >* A element of the double-linked list tubebase - */ -template -class tubeelement { - friend class tubebase<_T>; -public: - tubeelement *next = nullptr; - tubeelement *prev = nullptr; -private: - // These folks are for tubebase only! - tubeelement(const tube_time_t &time) - : - time(time) {} - - // Contruct it from time and value - tubeelement(const tube_time_t &time, const _T &value) : - time(time), - value(value) - {} - -public: - const tube_time_t time = 0; - _T value = _T(); -}; - - -template -tubebase<_T>::tubebase() { - //Create a default element at -Inf, that can always be dereferenced - so there will by definition never be - //a element that cannot be dereferenced - create(-std::numeric_limits::infinity(), _T()); -} - -template -tubebase<_T>::~tubebase() { - erase_after(begin); - delete(begin); -} - -/** - * Select the element that directly preceedes the given timestamp. - * - * Without a hint, start to iterate at the beginning of the buffer, and return - * the element last element before e->time > time. - * This method returns nullptr, if begin->time > time. - **/ -template -tubeelement<_T> *tubebase<_T>::last(const tube_time_t &time, tubeelement<_T> *hint) const { - tubeelement<_T> *e = hint ? hint : begin; - - if (e == nullptr) { - //throw Error(ERR << "Empty container list!"); - return e; - } - - if (begin->time > time) { - // This will never happen due to the begin->time == -Inf magic! - assert(false); - return nullptr; - } - - // Search in the queue - if (time > e->time) { // the searched element is supposed to be AFTER the hint - // perform the search via ->next - while (e->next != nullptr && time >= e->next->time) { - e = e->next; - } - // e is now one of two options: - // 1. e == end: The last element of the queue was smaller than `time` - // 2. e != end: There was a element with `e->time` > `time` - } else { - // the searched element is supposed to be BEFORE the hint - // perform the search via ->prev - while (e->prev != nullptr && time < e->time) { - e = e->prev; - } - // e is now one of two options: - // 1. e == begin: The time was before every element in the queue - // 2. e != begin: There was an element with `e->time` > `time` - } - - return e; -} - -/** - * Create and insert a new element into this tube - */ -template -tubeelement<_T> *tubebase<_T>::create(const tube_time_t &time, const _T& value) { - // TODO this has to be managed by a memory pool! - auto e = new tubeelement<_T>(time, value); - insert(e); - return e; -} - -/** - * Determine where to insert, and update all references - */ -template -void tubebase<_T>::insert(tubeelement<_T> *e, tubeelement<_T> *hint) { - // There are no elements in the list right now. - if (begin == nullptr) { - begin = e; - end = e; - return; - } - - tubeelement<_T>* at = last(e->time, hint); - - // if "last" cannot point at a location, so there was no element _before_ - // the newly inserted - if (at == nullptr) { - begin->prev = e; - e->next = begin; - begin = e; - } else if (at->next == nullptr || end == at) { - // if next is nullptr, then it has to be at the end, so update the end - at->next = e; - e->prev = at; - end = e; - } else { - // the list is not empty, it is not at the beginning, it is not at the end: - // it has to be in the middle! so we can perform a normal insert - e->next = at->next; - e->prev = at; - at->next->prev = e; - at->next = e; - } -} - - -/** - * Go from the end to the last_valid element, and call erase on all of them - */ -template -void tubebase<_T>::erase_after(tubeelement<_T> *last_valid) { - tubeelement<_T> *e = end; - //Delete from the end to last_valid - while (e != nullptr && e != last_valid) { - tubeelement<_T> *prev = e->prev; - erase(e); - e = prev; - } -} - -/** - * Delete the element from the list and call delete on it. - */ -template -void tubebase<_T>::erase(tubeelement<_T> *e) { - if (e == nullptr) return; - if (begin == e) { - begin = e->next; - } - if (end == e) { - end = e->prev; - } - - if (e->next != nullptr) { - e->next->prev = e->prev; - } - if (e->prev != nullptr) { - e->prev->next = e->next; - } - - delete e; // TODO Memory management magic! -} - -}} // openage::tube diff --git a/libopenage/tubes/container_iterator.cpp b/libopenage/tubes/container_iterator.cpp deleted file mode 100644 index a53a97b94c..0000000000 --- a/libopenage/tubes/container_iterator.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "container_iterator.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/container_iterator.h b/libopenage/tubes/container_iterator.h deleted file mode 100644 index 79955ee72a..0000000000 --- a/libopenage/tubes/container_iterator.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "tube.h" - -#include - -namespace openage { -namespace tube { - -template -class timed_iterator : public std::iterator< std::bidirectional_iterator_tag, _Ty > -{ - typename container::const_iterator base; - int64_t from, to; - time_translator_f time_translator; - -public: - timed_iterator(typename container::const_iterator base, int64_t from, int64_t to, const time_translator_f& time_translator) - : base(base) - , from(from) - , to(to) - , time_translator(time_translator) - {} - - timed_iterator(const timed_iterator &rhs) - : base(rhs.base) - , from(rhs.from) - , to(rhs.to) - , time_translator(rhs.time_translator) - {} - - timed_iterator &operator =(const timed_iterator &rhs) - { - this->base = rhs.base; - this->from = rhs.from; - this->to = rhs.to; - this->time_translator = rhs.time_translator; - return *this; - } - - timed_iterator &operator ++() - { - ++base; - return *this; - } - - //We only want to Iterate forward - so maybe delete this? - timed_iterator &operator --() - { - --base; - return *this; - } - - const _Ty &operator *() const - { - return *base; - } - - const _Ty *operator ->() const - { - return &**base; - } - - tube_time_t time() { - return time_translator(**base); - } - - bool operator ==(const timed_iterator<_Ty, container, time_translator_f> &rhs) const - { - return base == rhs.base; - } - - bool operator !=(const timed_iterator<_Ty, container, time_translator_f> &rhs) const - { - return base != rhs.base; - } - - bool valid() - { - return time() < to; - } - - operator bool() - { - return valid(); - } -}; - -}} // openage::tube diff --git a/libopenage/tubes/demo/CMakeLists.txt b/libopenage/tubes/demo/CMakeLists.txt deleted file mode 100644 index e46acf1aa5..0000000000 --- a/libopenage/tubes/demo/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -add_sources (libopenage - main.cpp - physics.cpp - gui.cpp - aicontroller.cpp -) diff --git a/libopenage/tubes/demo/aicontroller.cpp b/libopenage/tubes/demo/aicontroller.cpp deleted file mode 100644 index b58e36b860..0000000000 --- a/libopenage/tubes/demo/aicontroller.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "aicontroller.h" - -namespace openage { -namespace tubepong { - -std::vector &AIInput::getInputs( - const PongPlayer &player, - const PongBall &ball, - const tube::tube_time_t &now) { - this->event_cache.clear(); - - auto position = player.position.get(now); - - // Yes i know, there is /3 used - instead of the logical /2 - this is to - // create a small safety boundary of 1/3 for enhanced fancyness - - // Ball is below position - if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { - event_cache.push_back(event(player.id, event::DOWN)); - } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { - // Ball is above position - event_cache.push_back(event(player.id, event::UP)); - } - - return this->event_cache; -} - -}} // openage::tubepong diff --git a/libopenage/tubes/demo/aicontroller.h b/libopenage/tubes/demo/aicontroller.h deleted file mode 100644 index 1a8c67100a..0000000000 --- a/libopenage/tubes/demo/aicontroller.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gamestate.h" - -namespace openage { -namespace tubepong { - -class AIInput { -public: - std::vector &getInputs( - const PongPlayer &player, - const PongBall &ball, - const tube::tube_time_t &now); - -private: - std::vector event_cache; -}; - -}} // openage::tubepong diff --git a/libopenage/tubes/demo/gamestate.h b/libopenage/tubes/demo/gamestate.h deleted file mode 100644 index 8cc646ed4c..0000000000 --- a/libopenage/tubes/demo/gamestate.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - - -#include "../simple_continuous.h" -#include "../simple_discrete.h" -#include "../object.h" -#include "../../util/vector.h" - -namespace openage { -namespace tubepong { - -struct event { - int player; - enum state_e { - UP, DOWN, START, IDLE, LOST - } state; - event(int id, state_e s) : player(id), state(s) {} - event() : player(0), state(IDLE) {} -}; - -class PongPlayer : public tube::TubeObject { -public: - PongPlayer() { - speed.set_drop(0, 1); - position.set_drop(0, 0.5); - lives.set_drop(0, 1); - state.set_drop(0, event(0, event::IDLE)); - size.set_drop(0, 0.1); - y = 0; - id = 0; - } - - tube::SimpleDiscrete speed; - tube::SimpleContinuous position; - tube::SimpleDiscrete lives; - tube::SimpleDiscrete state; - tube::SimpleDiscrete size; - float y; - int id; -}; - -class PongBall : public tube::TubeObject { -public: - tube::SimpleDiscrete> speed; - tube::SimpleContinuous> position; -}; - -class PongState { -public: - PongPlayer p1; - PongPlayer p2; - - PongBall ball; - - util::Vector<2> resolution; -}; - -}} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.cpp b/libopenage/tubes/demo/gui.cpp deleted file mode 100644 index 941b2db7d0..0000000000 --- a/libopenage/tubes/demo/gui.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "gui.h" - -#include -#include - -namespace openage { -namespace tubepong { - -std::vector &Gui::getInputs(const PongPlayer &player) { - input_cache.clear(); - event evnt; - evnt.player = player.id; - evnt.state = event::IDLE; - timeout(0); - int c = getch(); - // mvprintw(0,1, "IN: %i", c); - switch (c) { - case KEY_DOWN: - evnt.state = event::DOWN; - input_cache.push_back(evnt); - mvprintw(1, 1, "DOWN"); - break; - case KEY_UP: - evnt.state = event::UP; - input_cache.push_back(evnt); - mvprintw(1, 1, "UP"); - break; - case ' ': evnt.state = event::START; break; - case 27: // esc or alt - endwin(); - exit(0); - default: break; - } - - return input_cache; -} - -enum { - COLOR_PLAYER1 = 1, - COLOR_PLAYER2 = 2, - COLOR_BALL = 3, - COLOR_DEBUG = 4, - - COLOR_0 = 5, - COLOR_1 = 6, - COLOR_2 = 7, - COLOR_3 = 8, - COLOR_4 = 9, -}; - -Gui::Gui() { - initscr(); - start_color(); - init_pair(COLOR_PLAYER1, COLOR_BLUE, COLOR_BLUE); - init_pair(COLOR_PLAYER2, COLOR_RED, COLOR_RED); - init_pair(COLOR_BALL, COLOR_BLUE, COLOR_WHITE); - init_pair(COLOR_DEBUG, COLOR_WHITE, COLOR_BLACK); - init_pair(COLOR_0, COLOR_RED, COLOR_BLACK); - init_pair(COLOR_1, COLOR_GREEN, COLOR_BLACK); - - keypad(stdscr, true); - noecho(); - curs_set(0); - // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); - - attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw( - 4, 5, " oooooooooo "); - mvprintw( - 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); - mvprintw( - 6, 5, " 888oooo88 888 888 888 888 888 88o "); - mvprintw( - 7, 5, " 888 888 888 888 888 888oo888o "); - mvprintw( - 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); - mvprintw( - 9, 5, " 888ooo888 "); - attroff(COLOR_PAIR(COLOR_DEBUG)); - - getch(); -} - -void Gui::draw(PongState &state, const tube::tube_time_t &now) { - erase(); - // clear(); - // Print Score - attron(COLOR_PAIR(COLOR_DEBUG)); - getmaxyx(stdscr, state.resolution[1], state.resolution[0]); - attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw(2, - state.resolution[0] / 2 - 5, - "P1 %i | P2 %i", - state.p1.lives(now), - state.p2.lives(now)); - - mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); - mvprintw(0, 1, "NOW: %f", now); - mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); - mvprintw(2, - 1, - "P1: %f, %f, %i", - state.p1.position(now), - state.p1.y, - state.p1.state(now).state); - mvprintw(3, - 1, - "P2: %f, %f, %i", - state.p2.position(now), - state.p2.y, - state.p2.state(now).state); - for (int i = 0; i < 1000; i += 100) { - mvprintw(4 + i / 100, - 1, - "BALL in %03i: %f | %f; SPEED: %f | %f", - i, - state.ball.position(now + i)[0], - state.ball.position(now + i)[1], - state.ball.speed(now + i)[0], - state.ball.speed(now + i)[1]); - } - mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); - attroff(COLOR_PAIR(COLOR_DEBUG)); - - attron(COLOR_PAIR(COLOR_PLAYER1)); - for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { - mvprintw(state.p1.position(now) + i, state.p1.y, "|"); - } - attroff(COLOR_PAIR(COLOR_PLAYER1)); - - attron(COLOR_PAIR(COLOR_PLAYER2)); - for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { - mvprintw(state.p2.position(now) + i, state.p2.y, "|"); - } - attroff(COLOR_PAIR(COLOR_PLAYER2)); - - for (int i = 0; i < 9999; ++i) { - draw_ball(state.ball.position(now + i * 50), i); - } - - /*attron(COLOR_PAIR(COLOR_BALL)); - mvprintw(state.ball.position(now)[1], - state.ball.position(now)[0], - "o"); - */ - attroff(COLOR_PAIR(COLOR_BALL)); - refresh(); -} - -void Gui::draw_ball(util::Vector<2> pos, int idx) { - switch (idx) { - case 0: attron(COLOR_PAIR(COLOR_0)); break; - default: - case 1: attron(COLOR_PAIR(COLOR_1)); break; - } - - mvprintw((int)(pos[1]), (int)(pos[0]), "X"); - standend(); -} -} -} // openage::tubepong diff --git a/libopenage/tubes/demo/gui.h b/libopenage/tubes/demo/gui.h deleted file mode 100644 index f8d2142ff2..0000000000 --- a/libopenage/tubes/demo/gui.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gamestate.h" - -namespace openage { -namespace tubepong { - - -class Gui { - -public: - Gui(); - std::vector &getInputs(const PongPlayer &player); - void draw(PongState &state, const tube::tube_time_t &now); - void draw_ball(util::Vector<2> ball, int idx); - -private: - std::vector input_cache; -}; - -}} // openage::tubepong diff --git a/libopenage/tubes/demo/main.cpp b/libopenage/tubes/demo/main.cpp deleted file mode 100644 index 902b247e51..0000000000 --- a/libopenage/tubes/demo/main.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include - -#include - -#include "gamestate.h" -#include "physics.h" -#include "gui.h" -#include "aicontroller.h" - -typedef std::chrono::high_resolution_clock Clock; - -namespace openage { -namespace tubepong { - -int demo() { - // Restart forever - tubepong::Gui gui; - tubepong::Physics phys; - tubepong::AIInput ai; - bool running = true; - - while (running) { - tubepong::PongState state; - tube::tube_time_t now = 1; - - state.p1.lives.set_drop(now, 3); - state.p1.id = 0; - state.p1.size.set_drop(now, 4); - state.p2.lives.set_drop(now, 3); - state.p2.id = 1; - state.p2.size.set_drop(now, 4); - - auto init_speed = util::Vector<2>( - ((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, - 0.01f * (rand() % 100) / 70.f); - - gui.draw(state, now); //update gui related parameters - - state.ball.speed.set_drop(now, init_speed); - state.ball.position.set_drop(now, state.resolution * 0.5); - state.p1.position.set_drop(now, state.resolution[1] / 2); - state.p2.position.set_drop(now, state.resolution[1] / 2); - - gui.draw(state, now); //initial drawing with corrected ball - - auto loop_start = Clock::now(); - now += 1; - std::cout << "p1: " << state.p1.lives.get(now) << " p2 " << state.p2.lives.get(now) << std::endl; - - - while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { -#ifdef HUMAN - phys.processInput( - state, - state.p1, - gui.getInputs(state.p1), - now - ); -#else - gui.getInputs(state.p1); - phys.processInput( - state, - state.p1, - ai.getInputs(state.p1, state.ball, now), - now - ); -#endif - phys.processInput( - state, - state.p2, - ai.getInputs(state.p2, state.ball, now), - now - ); - - state.p1.y = 0; - state.p2.y = state.resolution[0]-1; - - phys.update(state, now); - - gui.draw(state, now); - usleep(40000); - - double dt = std::chrono::duration_cast((Clock::now() - loop_start)).count(); - now += dt; - // now += 40; - loop_start = Clock::now(); - } - } - return 0; -} - -}} // openage::tubepong diff --git a/libopenage/tubes/demo/physics.cpp b/libopenage/tubes/demo/physics.cpp deleted file mode 100644 index a91ef7ac70..0000000000 --- a/libopenage/tubes/demo/physics.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "physics.h" - -#include - -#include - -namespace openage { -namespace tubepong { - -const float extrapolating_time = 100.0f; -const int init_recursion_limit = 50; - -void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const tube::tube_time_t &now) { - for (auto evnt : events) { - //Process only if the future has changed - if (player.state.get(now).state != evnt.state) { - player.state.set_drop(now, evnt); - - switch(evnt.state) { - case event::UP: - case event::DOWN: { - if (evnt.state == event::UP) { - player.speed.set_drop(now, -2); - } else if (evnt.state == event::DOWN) { - player.speed.set_drop(now, 2); - } - player.speed.set_drop(now + extrapolating_time, 0); - - float new_pos = player.position.get(now) + - (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); - if (new_pos < 0) - new_pos = 0; - if (new_pos > state.resolution[1]) - new_pos = state.resolution[1]; - - player.position.set_drop(now+extrapolating_time, new_pos); - evnt.state = event::IDLE; - player.state.set_drop(now + extrapolating_time, evnt); - break; - } - case event::IDLE: - player.position.set_drop(now+extrapolating_time, - player.position.get(now)); - break; - case event::START: - if (player.state.get(now).state == event::LOST) { - state.ball.position.set_drop(now, state.resolution * 0.5); - } - update_ball(state, now, init_recursion_limit); - break; - default: - break; - } - } - } - } - - void Physics::update(PongState &state, const tube::tube_time_t &now) { - - - auto pos = state.ball.position.get(now); - //Handle panel p1 - if (pos[0] <= 1 - && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 - && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 - && state.ball.speed.get(now)[0] < 0) { - //Ball hit the paddel in this frame - auto s = state.ball.speed.get(now); - s[0] *= -1.0; - state.ball.speed.set_drop(now, s); - state.ball.position.set_drop(now, pos); // this line can handle the future! - - update_ball(state, now, init_recursion_limit); - } else if (pos[0] >= state.resolution[0] - 1 - && pos[1] > state.p2.position.get(now) - state.p2.size.get(now) / 2 - && pos[1] < state.p2.position.get(now) + state.p2.size.get(now) / 2 - && state.ball.speed.get(now)[0] > 0) { - //Ball hit the paddel in this frame - auto s = state.ball.speed.get(now); - s[0] *= -1.0; - state.ball.speed.set_drop(now, s); - state.ball.position.set_drop(now, pos); // this line can handle the future! - - update_ball(state, now, init_recursion_limit); - } else if (state.ball.position.needs_update(now)) { - update_ball(state, now, init_recursion_limit); - } - - // Game loose condition - if (pos[0] < 0) { - state.p1.lives.set_drop(now, state.p1.lives.get(now) - 1); - state.p1.state.set_drop(now, event(state.p1.id, event::LOST)); - } - if (pos[0] > state.resolution[0]) { - state.p2.lives.set_drop(now, state.p2.lives.get(now) - 1); - state.p2.state.set_drop(now, event(state.p2.id, event::LOST)); - } - -} - - -void Physics::update_ball(PongState &state, const tube::tube_time_t &now, int recursion_limit) { - //calculate the ball takes to hit a wall. - auto speed = state.ball.speed.get(now); - auto pos = state.ball.position.get(now); - - float ty = 0; - //char mode = ' '; - if (speed [1] > 0) { - ty = (state.resolution[1] - pos[1]) / speed[1]; - //mode = 'v'; - } else if (speed[1] < 0) { - ty = pos[1] / -speed[1]; - //mode = '^'; - } - -/* mvprintw(20 - recursion_limit, 1, "R %i: %c TY %f | pos: %f | %f speed %f | %f res %i | %i", - init_recursion_limit - recursion_limit, mode, - ty, - pos[0], pos[1], - speed[0], speed[1], - state.resolution[0], state.resolution[1] - ); -*/ - if (ty > 0) { - auto hit_pos = pos + speed * ty; - state.ball.position.set_drop(now + ty, hit_pos); - speed[1] *= -1; - state.ball.speed.set_drop(now + ty, speed); - if (recursion_limit > 1) { - update_ball(state, now + ty, recursion_limit - 1); - } - } -} - -}} // openage::tubepong diff --git a/libopenage/tubes/demo/physics.h b/libopenage/tubes/demo/physics.h deleted file mode 100644 index 02a3a72a82..0000000000 --- a/libopenage/tubes/demo/physics.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gamestate.h" -#include "../tube.h" - -namespace openage { -namespace tubepong { - -class Physics { -public: - void processInput(PongState &, PongPlayer &, std::vector &events, const tube::tube_time_t &now); - void update(PongState &, const tube::tube_time_t &); -protected: - void update_ball(PongState &, const tube::tube_time_t &, int recursion_limit); -}; - -}} // openage::tubepong diff --git a/libopenage/tubes/event.cpp b/libopenage/tubes/event.cpp deleted file mode 100644 index 30ee97e83b..0000000000 --- a/libopenage/tubes/event.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "event.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/event.h b/libopenage/tubes/event.h deleted file mode 100644 index 2be20e6b2a..0000000000 --- a/libopenage/tubes/event.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/eventlist.cpp b/libopenage/tubes/eventlist.cpp deleted file mode 100644 index e0e67ddf62..0000000000 --- a/libopenage/tubes/eventlist.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "eventlist.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/eventlist.h b/libopenage/tubes/eventlist.h deleted file mode 100644 index 2be20e6b2a..0000000000 --- a/libopenage/tubes/eventlist.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.cpp b/libopenage/tubes/filter_iterator.cpp deleted file mode 100644 index 790dec54b1..0000000000 --- a/libopenage/tubes/filter_iterator.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "filter_iterator.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/filter_iterator.h b/libopenage/tubes/filter_iterator.h deleted file mode 100644 index 5e385a758c..0000000000 --- a/libopenage/tubes/filter_iterator.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "tube.h" - -namespace openage { -namespace tube { - -template -class tube_iterator{ -public: - virtual val_t &value() = 0; - virtual bool valid() = 0; -}; - -template -class tube_filter_iterator : - public std::iterator< std::bidirectional_iterator_tag, std::pair >, - public tube_iterator -{ -protected: -// typename container_t::const_iterator base; - typename container_t::iterator base; - - tube_time_t now; - -public: - tube_filter_iterator(const typename container_t::const_iterator &base, const tube_time_t &now) - : base(base) - , now(now) - {} - - tube_filter_iterator(const tube_filter_iterator &rhs) - : base(rhs.base) - , now(rhs.now) - {} - - tube_filter_iterator &operator =(const tube_filter_iterator &rhs) - { - this->base = rhs.base; - this->now = rhs.now; - return *this; - } - - tube_filter_iterator &operator ++() - { - do { - ++base; - } while (base->second.alive > time && base->second.dead < time); - - return *this; - } - - //We only want to Iterate forward - so maybe delete this? - //timed_iterator &operator --() - //{ - // --base; - // return *this; - //} - - std::pair &operator *() const - { - return *base; - } - - std::pair *operator ->() const - { - return &**this; - } - - virtual bool operator ==(const tube_filter_iterator &rhs) const - { - return rhs.now == std::numeric_limits::infinity() - && base == rhs.base; - } - - virtual bool operator !=(const tube_filter_iterator &rhs) const - { - return rhs.now != std::numeric_limits::infinity() - && base != rhs.base; - } - - virtual bool valid() - { - return base->second.alive > now; - } - - operator bool() - { - return valid(); - } -}; - -template -class tube_filter_end_iterator : public tube_filter_iterator { -public: - tube_filter_end_iterator(const typename container_t::const_iterator &base) - : tube_filter_iterator(base, std::numeric_limits::infinity()) - {} - - virtual bool valid() { - return false; - } -}; - -}} // openage::tube diff --git a/libopenage/tubes/object.cpp b/libopenage/tubes/object.cpp deleted file mode 100644 index 93a463df50..0000000000 --- a/libopenage/tubes/object.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "object.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/object.h b/libopenage/tubes/object.h deleted file mode 100644 index 40f5566a72..0000000000 --- a/libopenage/tubes/object.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "tube.h" - -namespace openage { -namespace tube { - -class TubeObject { -public: -}; - -}} // openage::tube diff --git a/libopenage/tubes/objectlist.h b/libopenage/tubes/objectlist.h deleted file mode 100644 index 2be20e6b2a..0000000000 --- a/libopenage/tubes/objectlist.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_continuous.cpp b/libopenage/tubes/simple_continuous.cpp deleted file mode 100644 index c54324a4a5..0000000000 --- a/libopenage/tubes/simple_continuous.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "simple_continuous.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_continuous.h b/libopenage/tubes/simple_continuous.h deleted file mode 100644 index ed125254dd..0000000000 --- a/libopenage/tubes/simple_continuous.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "simple_type.h" - -namespace openage { -namespace tube { - -template -class SimpleContinuous : public SimpleType<_T> { - mutable tube_time_t diff_time; - mutable tube_time_t offset; - -public: - void set_now(const tube_time_t &t) const override; - - _T get() const override; - _T get(const tube_time_t &) const override; - -public: -}; - -template -void SimpleContinuous<_T>::set_now(const tube_time_t &t) const { - SimpleType<_T>::set_now(t); - if (this->e_now == nullptr) { // TODO This Sucks! - diff_time = 0; - offset = 1; - } else { - if (this->e_now->next != nullptr) { - diff_time = this->e_now->next->time - this->e_now->time; - } else { - diff_time = 0; - } - offset = t - this->e_now->time; - } -} - -template -_T SimpleContinuous<_T>::get() const { - double elapsed_frac = (double)offset / (double)diff_time; - if (this->e_now == nullptr) { //TODO This Sucks! - return _T(); - } else if (this->e_now->next == nullptr || offset == 0) { - return this->e_now->value; //If we cannot interpolate, treat as standing still (?) - } else { - return this->e_now->value + (this->e_now->next->value - this->e_now->value) * elapsed_frac; - } -} - -template -_T SimpleContinuous<_T>::get(const tube_time_t &time) const { - this->set_now(time); - return get(); -} - - -}} // openage::tube diff --git a/libopenage/tubes/simple_discrete.cpp b/libopenage/tubes/simple_discrete.cpp deleted file mode 100644 index 3b39b4ec99..0000000000 --- a/libopenage/tubes/simple_discrete.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "simple_discrete.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_discrete.h b/libopenage/tubes/simple_discrete.h deleted file mode 100644 index 968e13fed5..0000000000 --- a/libopenage/tubes/simple_discrete.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "simple_type.h" - -namespace openage { -namespace tube { - -template -class SimpleDiscrete : public SimpleType<_T> { -public: - - _T get() const override; - _T get(const tube_time_t &) const override; -public: -}; - -template -_T SimpleDiscrete<_T>::get() const { - if (this->e_now == nullptr) { // TODO THIS SUCKS! - return _T(); - } else { - return this->e_now->value; - } -} - -template -_T SimpleDiscrete<_T>::get(const tube_time_t &time) const { - this->set_now(time); - return this->get(); -} - -}} // openage::tube diff --git a/libopenage/tubes/simple_type.cpp b/libopenage/tubes/simple_type.cpp deleted file mode 100644 index 918d89f759..0000000000 --- a/libopenage/tubes/simple_type.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "simple_type.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/simple_type.h b/libopenage/tubes/simple_type.h deleted file mode 100644 index 2f8f37d840..0000000000 --- a/libopenage/tubes/simple_type.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "base.h" - -namespace openage { -namespace tube { - -template -class SimpleType { -protected: - tubebase<_T> container; - mutable tubeelement<_T> *e_now; - mutable tube_time_t now; - -public: - SimpleType(); - - // Reader mode - virtual void set_now(const tube_time_t &t) const; - - virtual _T get() const = 0; - virtual _T get(const tube_time_t &t) const; - - virtual _T operator ()() const { - return std::move(get()); - } - - virtual _T operator ()(const tube_time_t &now) { - return std::move(get(now)); - } - - virtual bool needs_update(const tube_time_t &at); -public: - // Inserter mode - void set_drop(const tube_time_t &at, const _T &value); - void set_insert(const tube_time_t &at, const _T &value); -}; - -template -SimpleType<_T>::SimpleType() : - e_now(nullptr), - now() -{} - -template -void SimpleType<_T>::set_now(const tube_time_t &t) const { - now = t; - e_now = container.last(t, e_now); -} - -template -_T SimpleType<_T>::get(const tube_time_t &t) const { - set_now(t); - return get(); -} - -template -void SimpleType<_T>::set_drop(const tube_time_t &at, const _T &value) { - container.erase_after(container.last(at, e_now)); - container.create(at, value); -} - -template -void SimpleType<_T>::set_insert(const tube_time_t &at, const _T &value) { - container.create(at, value); -} - -template -bool SimpleType<_T>::needs_update(const tube_time_t &at) { - auto e = container.last(at, e_now); //TODO take container.end as a hint? - if (e->time > at || e->next == nullptr || e->next->time > at) { - return true; - } else { - return false; - } -} - -}} // openage::tube diff --git a/libopenage/tubes/test/CMakeLists.txt b/libopenage/tubes/test/CMakeLists.txt deleted file mode 100644 index 6e340d6393..0000000000 --- a/libopenage/tubes/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -link_libraries(tube) - -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") - -add_sources(libopenage - test_container.cpp - test_tube_types.cpp - test_serialization.cpp -) diff --git a/libopenage/tubes/test/test_container.cpp b/libopenage/tubes/test/test_container.cpp deleted file mode 100644 index 49586d705b..0000000000 --- a/libopenage/tubes/test/test_container.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "../../testing/testing.h" -#include "../base.h" -#include "../container_iterator.h" -#include "../tube.h" -#include "../simple_continuous.h" -#include "../simple_discrete.h" - -namespace openage { -namespace tube { -namespace tests { - -class test_tube_element { -public: - test_tube_element(tube_time_t t, int32_t data) : - time(t), - data(data) - {} - - tube_time_t time; - int32_t data; -}; - -tube_time_t timer (const test_tube_element &t) { - return t.time; -} - -void container() { - // Check the base container type - { - tubebase c; - auto p0 = c.create(0, 0); - auto p1 = c.create(1, 1); - auto p2 = c.create(10, 2); - - // last function tests without hints - TESTEQUALS(c.last(0)->value, 0); - TESTEQUALS(c.last(1)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5)->value, 1); - TESTEQUALS(c.last(10)->value, 2); - TESTEQUALS(c.last(47)->value, 2); - - // last() with hints. Yes this can make a difference. we want to be - // absolutely shure! - // hint p1 - TESTEQUALS(c.last(0, p0)->value, 0); - TESTEQUALS(c.last(1, p0)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5, p0)->value, 1); - TESTEQUALS(c.last(10, p0)->value, 2); - TESTEQUALS(c.last(47, p0)->value, 2); - - TESTEQUALS(c.last(0, p1)->value, 0); - TESTEQUALS(c.last(1, p1)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5, p1)->value, 1); - TESTEQUALS(c.last(10, p1)->value, 2); - TESTEQUALS(c.last(47, p1)->value, 2); - - TESTEQUALS(c.last(0, p2)->value, 0); - TESTEQUALS(c.last(1, p2)->value, 1); //last shall give >= not only > ! - TESTEQUALS(c.last(5, p2)->value, 1); - TESTEQUALS(c.last(10, p2)->value, 2); - TESTEQUALS(c.last(47, p2)->value, 2); - - // Now test the basic erase() function - c.erase(c.last(1)); - - TESTEQUALS(c.last(1)->value, 0); - TESTEQUALS(c.last(5)->value, 0); - TESTEQUALS(c.last(47)->value, 2); - - c.erase_after(c.last(99)); // we dont want to have the element itself erased! - TESTEQUALS(c.last(47)->value, 2); - - c.erase_after(c.last(5)); // now since 10 > 5, element with value 2 has to be gone - TESTEQUALS(c.last(47)->value, 0); - } - - // Check the Simple Continuous type - { - SimpleContinuous c; - c.set_insert(0, 0); - c.set_insert(10, 1); - - c.set_now(0); - TESTEQUALS(c.get(), 0); - - c.set_now(1); - TESTEQUALS_FLOAT(c.get(), 0.1, 1e-7); - } - - { - SimpleContinuous c; - c.set_insert(0, 0); - c.set_insert(10, 10); - - c.set_now(0); - TESTEQUALS(c.get(), 0); - - c.set_now(1); - TESTEQUALS(c.get(), 1); - } - //Check the discrete type - { - SimpleDiscrete c; - c.set_insert(0, 0); - c.set_insert(10, 10); - - c.set_now(0); - TESTEQUALS(c.get(), 0); - - c.set_now(1); - TESTEQUALS(c.get(), 0); - - c.set_now(11); - TESTEQUALS(c.get(), 10); - } - - //check set_drop - { - SimpleDiscrete c; - c.set_insert(0, 0); - c.set_insert(1, 1); - c.set_insert(3, 3); - - c.set_now(3); - TESTEQUALS(c.get(), 3); - - c.set_drop(2, 10); - c.set_now(3); - TESTEQUALS(c.get(), 10); - } - - // Iterate tests -/* { - Container container(timer); - - container.insert(std::make_shared(test_tube_element(10, 0))); - container.insert(std::make_shared(test_tube_element(20, 1))); - - // Iterate over everything with boundaries - { - auto it = container.iterate(0, 30); - TESTEQUALS(it.valid(), true); - - TESTEQUALS(it->data, 0); - ++it; - TESTEQUALS(it.valid(), true); - - TESTEQUALS(it->data, 1); - ++it; - TESTEQUALS(it.valid(), false); - - } - - // Iterate only over the first, with boundaries - { - auto it = container.iterate(0, 15); - TESTEQUALS(it.valid(), true); - TESTEQUALS(it->data, 0); - ++it; - TESTEQUALS(it.valid(), false); - } - - // Iterate only over the first, without boundaries - { - auto it = container.iterate(10, 11); - TESTEQUALS(it.valid(), true); - TESTEQUALS(it->data, 0); - ++it; - TESTEQUALS(it.valid(), false); - } - - // Iterate out of boundaries - { - auto it = container.iterate(100, 200); - TESTEQUALS(it.valid(), false); - } - } - - // Some fucked up insert and read stuff, create all the bugs. - { - // TODO have more ideas to fuck up our data structures - }*/ -} - - -}}} // openage::tube::tests diff --git a/libopenage/tubes/test/test_serialization.cpp b/libopenage/tubes/test/test_serialization.cpp deleted file mode 100644 index af8dd046c7..0000000000 --- a/libopenage/tubes/test/test_serialization.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "../../testing/testing.h" - -namespace openage { -namespace tube { -namespace tests { - -void serialization() { - -} - -}}} // openage::tube::tests diff --git a/libopenage/tubes/test/test_tube_types.cpp b/libopenage/tubes/test/test_tube_types.cpp deleted file mode 100644 index aafa1c21ae..0000000000 --- a/libopenage/tubes/test/test_tube_types.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "../../testing/testing.h" - -namespace openage { -namespace tube { -namespace tests { - -void tube_types() { -} - -}}} // openage::tube::tests diff --git a/libopenage/tubes/tube.cpp b/libopenage/tubes/tube.cpp deleted file mode 100644 index 4462daac9c..0000000000 --- a/libopenage/tubes/tube.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "tube.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/tube.h b/libopenage/tubes/tube.h deleted file mode 100644 index 0061659228..0000000000 --- a/libopenage/tubes/tube.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { -namespace tube { - -typedef float tube_time_t; - -}} // openage::tube diff --git a/libopenage/tubes/unordered_map.cpp b/libopenage/tubes/unordered_map.cpp deleted file mode 100644 index c336fedff8..0000000000 --- a/libopenage/tubes/unordered_map.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "unordered_map.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tubes/unordered_map.h b/libopenage/tubes/unordered_map.h deleted file mode 100644 index 830cb21309..0000000000 --- a/libopenage/tubes/unordered_map.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "base.h" -#include "tube.h" -#include "filter_iterator.h" - -namespace openage { -namespace tube { - -template -class UnorderedTubeMap { - struct map_element { - key_t key; - tubebase value; - tube_time_t alive; - tube_time_t dead; - }; - std::unordered_map container; - -public: - val_t &operator()(const tube_time_t&, const key_t &); - val_t &at(const tube_time_t &, const key_t &); - - tube_filter_iterator begin(const tube_time_t &); - - tube_filter_iterator end(const tube_time_t &); - - tube_iterator insert(const tube_time_t &, const key_t &, const val_t &); - tube_iterator insert(const tube_iterator &at, const key_t &, const val_t &); - - void birth(const key_t &, const tube_time_t &); - void birth(const tube_iterator &, const tube_time_t &); - - void kill(const key_t &, const tube_time_t &); - void kill(const tube_iterator &, const tube_time_t &); - - void is_alive(const key_t &, const tube_time_t &); - void is_alive(const tube_iterator &, const tube_time_t &); - - void clean(const tube_time_t &); // remove all dead elements -}; - -template -val_t &UnorderedTubeMap::operator()(const tube_time_t &, const key_t &) { - -} - -template -val_t &UnorderedTubeMap::at(const tube_time_t &, const key_t &) { - -} - -template -tube_filter_iterator> UnorderedTubeMap::begin(const tube_time_t &) { - -} - -template -tube_filter_iterator> UnorderedTubeMap::end(const tube_time_t &) { - -} - -template -tube_iterator UnorderedTubeMap::insert(const tube_time_t &, const key_t &, const val_t &) { - -} - -template -tube_iterator UnorderedTubeMap::insert(const tube_iterator &at, const key_t &, const val_t &) { - -} - -template -void UnorderedTubeMap::birth(const key_t &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::birth(const tube_iterator &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::kill(const key_t &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::kill(const tube_iterator &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::is_alive(const key_t &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::is_alive(const tube_iterator &, const tube_time_t &) { - -} - -template -void UnorderedTubeMap::clean(const tube_time_t &) { - -} - -}} // openage::tube From 0e43190e72753ab154ae466fb2f673fc0401889b Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sun, 16 Apr 2017 23:20:43 +0200 Subject: [PATCH 11/24] Tube: Added queue, fixed some ugly pylint stuff --- libopenage/tube/datatypes.md | 2 -- libopenage/tube/map_filter_iterator.h | 24 +----------------------- libopenage/tube/test/test_container.cpp | 12 ++++++------ libopenage/tube/tube.h | 20 ++++++++++++++++++++ openage/cabextract/cab.py | 2 +- 5 files changed, 28 insertions(+), 32 deletions(-) diff --git a/libopenage/tube/datatypes.md b/libopenage/tube/datatypes.md index 06ea533bb6..feade3a0d4 100644 --- a/libopenage/tube/datatypes.md +++ b/libopenage/tube/datatypes.md @@ -44,7 +44,6 @@ Set Container ---------------- The set container stores items, just as a normal array would. It keeps track of the existence of the items, but does not guarentee any particular ordering (similar to std::unordered_set). -======= This Container is useful for any non-indexed data structures, for example projectiles. Queue Container @@ -56,4 +55,3 @@ This container is useful for example for action queues and buildung queues. TUBE FILES ============ - diff --git a/libopenage/tube/map_filter_iterator.h b/libopenage/tube/map_filter_iterator.h index 6a6bb0a896..139253d306 100644 --- a/libopenage/tube/map_filter_iterator.h +++ b/libopenage/tube/map_filter_iterator.h @@ -10,18 +10,6 @@ namespace openage { namespace tube { -template -class TubeIterator { -public: - virtual val_t &value() = 0; -}; - -template -bool valid(const _T &, const tube_time_t &at); - -template -using _valid_function_t = bool (*)(const _T&, const tube_time_t &); - template base = rhs.base; @@ -111,11 +96,4 @@ class TubeMapFilterIterator : } }; -template -bool valid(const _T &t, - const tube_time_t& time) { - return existent_from(t) <= time && existent_until(t) > time; -} - - }} // openage::tube diff --git a/libopenage/tube/test/test_container.cpp b/libopenage/tube/test/test_container.cpp index 02d7df32d5..e5b5aca0c6 100644 --- a/libopenage/tube/test/test_container.cpp +++ b/libopenage/tube/test/test_container.cpp @@ -147,16 +147,16 @@ void test_queue() { q.insert(2, 2); q.insert(4, 3); q.insert(10, 4); - q.insert(100001, 5); + q.dump(); TESTEQUALS(*q.begin(0), 1); - TESTEQUALS(*q.begin(1), 2); + TESTEQUALS(*q.begin(1), 1); TESTEQUALS(*q.begin(2), 2); - TESTEQUALS(*q.begin(3), 3); + TESTEQUALS(*q.begin(3), 2); TESTEQUALS(*q.begin(4), 3); - TESTEQUALS(*q.begin(5), 4); + TESTEQUALS(*q.begin(5), 3); TESTEQUALS(*q.begin(10), 4); - TESTEQUALS(*q.begin(12), 5); - TESTEQUALS(*q.begin(100000), 5); + TESTEQUALS(*q.begin(12), 4); + TESTEQUALS(*q.begin(100000), 4); { std::set reference = {1,2,3}; diff --git a/libopenage/tube/tube.h b/libopenage/tube/tube.h index b25723621a..71089b2446 100644 --- a/libopenage/tube/tube.h +++ b/libopenage/tube/tube.h @@ -22,4 +22,24 @@ tube_time_t existent_until (const _T &t) { return t.existent_until(); } +template +class TubeIterator { +public: + virtual val_t &value() = 0; +}; + +template +bool valid(const _T &, const tube_time_t &at); + +template +using _valid_function_t = bool (*)(const _T&, const tube_time_t &); + +template +bool valid(const _T &t, + const tube_time_t& time) { + return existent_from(t) <= time && existent_until(t) > time; +} + + + }} // openage::tube diff --git a/openage/cabextract/cab.py b/openage/cabextract/cab.py index bb078f554f..22a9e2c551 100644 --- a/openage/cabextract/cab.py +++ b/openage/cabextract/cab.py @@ -336,7 +336,7 @@ def read_folder_headers(self, cab): compressed_data_stream, window_bits=window_bits, reset_interval=0) - folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) + folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) # pylint: disable=redefined-variable-type,locally-enabled else: raise Exception("Unknown compression type %d" % compression_type) From 1f63378b30cc2d128bb7f161e8f9e370b01545ad Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Mon, 17 Apr 2017 18:44:43 +0200 Subject: [PATCH 12/24] Tubes: Fixed tests for queue --- libopenage/tube/test/test_container.cpp | 12 ++++++------ openage/cabextract/cab.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libopenage/tube/test/test_container.cpp b/libopenage/tube/test/test_container.cpp index e5b5aca0c6..02d7df32d5 100644 --- a/libopenage/tube/test/test_container.cpp +++ b/libopenage/tube/test/test_container.cpp @@ -147,16 +147,16 @@ void test_queue() { q.insert(2, 2); q.insert(4, 3); q.insert(10, 4); - q.dump(); + q.insert(100001, 5); TESTEQUALS(*q.begin(0), 1); - TESTEQUALS(*q.begin(1), 1); + TESTEQUALS(*q.begin(1), 2); TESTEQUALS(*q.begin(2), 2); - TESTEQUALS(*q.begin(3), 2); + TESTEQUALS(*q.begin(3), 3); TESTEQUALS(*q.begin(4), 3); - TESTEQUALS(*q.begin(5), 3); + TESTEQUALS(*q.begin(5), 4); TESTEQUALS(*q.begin(10), 4); - TESTEQUALS(*q.begin(12), 4); - TESTEQUALS(*q.begin(100000), 4); + TESTEQUALS(*q.begin(12), 5); + TESTEQUALS(*q.begin(100000), 5); { std::set reference = {1,2,3}; diff --git a/openage/cabextract/cab.py b/openage/cabextract/cab.py index 22a9e2c551..bb078f554f 100644 --- a/openage/cabextract/cab.py +++ b/openage/cabextract/cab.py @@ -336,7 +336,7 @@ def read_folder_headers(self, cab): compressed_data_stream, window_bits=window_bits, reset_interval=0) - folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) # pylint: disable=redefined-variable-type,locally-enabled + folder.plain_stream = StreamSeekBuffer(unseekable_plain_stream) else: raise Exception("Unknown compression type %d" % compression_type) From 841b7f911a8ca377132db288e1254f90785baf41 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Tue, 18 Apr 2017 18:20:04 +0200 Subject: [PATCH 13/24] Tubes: added tube_iterator, documentationw --- libopenage/tube/keyframe_container.h | 87 +++++++++++++---- libopenage/tube/map_filter_iterator.h | 95 ++++++------------- libopenage/tube/queue_filter_iterator.h | 85 ++++------------- libopenage/tube/tube.h | 20 ---- libopenage/tube/tube_iterator.h | 90 ++++++++++++++++++ .../tube/{unordered_map.h => tube_map.h} | 21 +--- 6 files changed, 208 insertions(+), 190 deletions(-) create mode 100644 libopenage/tube/tube_iterator.h rename libopenage/tube/{unordered_map.h => tube_map.h} (89%) diff --git a/libopenage/tube/keyframe_container.h b/libopenage/tube/keyframe_container.h index 5928575dfa..f332775f9f 100644 --- a/libopenage/tube/keyframe_container.h +++ b/libopenage/tube/keyframe_container.h @@ -17,39 +17,75 @@ namespace tube { /** * A timely ordered list with several management functions * - * This class manages different time-based management functions for the double- - * linked list approach that lies underneath. It contains a double-linked list - * to be accessed via a non-accurate timing functionality, this means, that for - * getting a value, not the exact timestamp has to be known, it will always return - * the one closest, less or equal to the requested one. + * This class manages different time-based management functions for list + * approach that lies underneath. It contains list to be accessed via a + * non-accurate timing functionality, this means, that for getting a value, not + * the exact timestamp has to be known, it will always return the one closest, + * less or equal to the requested one. **/ template class KeyframeContainer { public: /** - * A element of the double-linked list KeyframeContainer + * A element of the tubecontainer. This is especially used to keep track of + * the value-timing. */ class Keyframe { public: + /** + * New default object at time -INF. + */ + Keyframe() {} + + /** + * New, default-constructed element at the given time + */ Keyframe(const tube_time_t &time) : - time(time) {} + time{time} {} - // Contruct it from time and value + /** + * New element fron time and value + */ Keyframe(const tube_time_t &time, const _T &value) : - time(time), - value(value) {} + time{time}, + value{value} {} - const tube_time_t time = 0; + const tube_time_t time = std::numeric_limits::infinity(); _T value = _T(); }; + /** + * The underlaying container type. + * + * The most important property of this container is the iterator validity on + * insert and remove. + */ typedef std::list tubecontainer; + + /** + * The iterator type to access elements in the container + */ typedef typename tubecontainer::const_iterator KeyframeIterator; + + /** default c'tor **/ KeyframeContainer(); ~KeyframeContainer(); - // Get the last element with e->time <= time - KeyframeIterator last(const tube_time_t &time, const KeyframeIterator & hint) const; + /** + * Get the last element with e->time <= time, given a hint where to + * start the search. + */ + KeyframeIterator last(const tube_time_t &time, + const KeyframeIterator & hint) const; + + /** + * Get the last element with e->time <= time, without a hint where to start + * searching. + * + * The usage of this method is discouraged - except if there is absolutely + * no chance for you to have a hint (or the container is known to be nearly + * empty) + */ KeyframeIterator last(const tube_time_t &time) const { return this->last(time, this->container.begin()); } @@ -57,17 +93,18 @@ class KeyframeContainer { /** * Insert a new element without a hint. * - * This function is recommended for use, whenever possible, keep a hint to insert - * the data. + * This function is not recommended for use, whenever possible, keep a hint + * to insert the data. */ KeyframeIterator insert(const Keyframe &value) { return this->insert(value, this->container.begin()); } /** - * Insert a new element. The hint shall give an approximate location, where the - * inserter will start to look for a insertion point. If a good hint is given, the - * runtime of this function will not be affected by the current history size. + * Insert a new element. The hint shall give an approximate location, where + * the inserter will start to look for a insertion point. If a good hint is + * given, the runtime of this function will not be affected by the current + * history size. */ KeyframeIterator insert(const Keyframe &value, const KeyframeIterator &hint); @@ -79,6 +116,7 @@ class KeyframeContainer { KeyframeIterator insert(const tube_time_t &time, const _T&value) { return this->insert(Keyframe(time, value), this->container.begin()); } + /** * Create and insert a new element. The hint gives an approximate location. */ @@ -96,20 +134,32 @@ class KeyframeContainer { */ KeyframeIterator erase(KeyframeIterator ); + /** + * Obtain an iterator to the first value with the smallest timestamp. + */ KeyframeIterator begin() const { return container.begin(); } + /** + * Obtain an iterator to the position after the last value. + */ KeyframeIterator end() const { return container.end(); } + /** + * Debugging method to be used from gcc to understand bugs better. + */ void __attribute__ ((noinline)) dump() { for (auto e : container) { std::cout << "Element: time: " << e.time << " v: " << e.value << std::endl; } } private: + /** + * The data store. + */ tubecontainer container; }; @@ -123,6 +173,7 @@ KeyframeContainer<_T>::KeyframeContainer() { template KeyframeContainer<_T>::~KeyframeContainer() { + // We rely on std::list to destroy all elements. } /** diff --git a/libopenage/tube/map_filter_iterator.h b/libopenage/tube/map_filter_iterator.h index 139253d306..0db9838435 100644 --- a/libopenage/tube/map_filter_iterator.h +++ b/libopenage/tube/map_filter_iterator.h @@ -6,94 +6,59 @@ #include #include "tube.h" +#include "tube_iterator.h" namespace openage { namespace tube { +/** + * A filtering operator to iterate over all elements of a map whose elements + * exist for a certain livespan. The range where to iterate is given at + * construction. + * + * It depends on key_t and val_t as map-parameters, container_t is the container + * to operate on and the function valid_f, that checks if an element is alive. + */ template valid_f = valid > + class container_t> class TubeMapFilterIterator : - virtual public std::iterator, - public TubeIterator + public TubeIterator { -protected: - //typedef typename std::iterator iterator_t; +public: typedef typename container_t::iterator iterator_t; - iterator_t base; - iterator_t container_end; - - tube_time_t from; - tube_time_t to; -public: + /** + * Construct the iterator from its boundary conditions: time and container + */ TubeMapFilterIterator(const iterator_t &base, const iterator_t &container_end, const tube_time_t &from, const tube_time_t &to) : - base{base}, - container_end{container_end}, - from{from}, - to{to} {} - - TubeMapFilterIterator(const TubeMapFilterIterator &rhs) : - base{rhs.base}, - container_end{rhs.container_end}, - from{rhs.from}, - to{rhs.to} {} - - TubeMapFilterIterator &operator =(const TubeMapFilterIterator &rhs) { - this->base = rhs.base; - this->container_end = rhs.container_end; - this->from = rhs.from; - this->to = rhs.to; - return *this; - } - - TubeMapFilterIterator &operator ++() { - do { - ++this->base; - } while (this->base != this->container_end && - (existent_from(this->base->second.value) < from || - existent_until(this->base->second.value) > to)); - return *this; - } - - //We only want to Iterate forward - so maybe delete this? - //timed_iterator &operator --() - //{ - // --base; - // return *this; - //} - - val_t &operator *() const { - return this->base->second.value; - } - - val_t *operator ->() const { - return &**this; - } - - virtual bool operator ==(const TubeMapFilterIterator &rhs) const { - return this->base == rhs.base; - } + TubeIterator(base, container_end, from, to) {} - virtual bool operator !=(const TubeMapFilterIterator &rhs) const { - return this->base != rhs.base; + virtual bool valid() const override { + return this->base->second.alive >= this->from && + this->base->second.dead < this->to; } - virtual bool valid(const tube_time_t &time) { - return valid_f(base->second.value, time); - } - - val_t &value() override { + /** + * Get the value behind the iterator. + * Nicer way of accessing it beside operator *. + */ + val_t &value() const override { return this->base->second.value; } + /** + * Get the key pointed to by this iterator. + */ const key_t &key() { return this->base->first; } + +protected: + }; }} // openage::tube diff --git a/libopenage/tube/queue_filter_iterator.h b/libopenage/tube/queue_filter_iterator.h index f2b047eaae..7d137d8254 100644 --- a/libopenage/tube/queue_filter_iterator.h +++ b/libopenage/tube/queue_filter_iterator.h @@ -6,93 +6,44 @@ #include #include "tube.h" +#include "tube_iterator.h" namespace openage { namespace tube { -template -class Queue; - +/** + * A filtering operator to iterate over all elements of a queue whose elements + * exist at exactly one point of time, the range where to iterate is given at + * construction. + * + * It depends on val_t as its value type, container_t is the container + * to operate on and the function valid_f, that checks if an element is alive. + */ template class TubeQueueFilterIterator : - virtual public std::iterator, - public TubeIterator + public TubeIterator { - friend class Queue; -protected: +public: typedef typename container_t::iterator iterator_t; - iterator_t base; - iterator_t container_end; - - tube_time_t from; - tube_time_t to; -public: + /** + * Construct the iterator from its boundary conditions: time and container + */ TubeQueueFilterIterator(const iterator_t &base, const iterator_t &container_end, const tube_time_t &from, const tube_time_t &to) : - base{base}, - container_end{container_end}, - from{from}, - to{to} {} - - TubeQueueFilterIterator(const TubeQueueFilterIterator &rhs) : - base{rhs.base}, - container_end{rhs.container_end}, - from{rhs.from}, - to{rhs.to} {} - - TubeQueueFilterIterator &operator =(const TubeQueueFilterIterator &rhs) { - this->base = rhs.base; - this->container_end = rhs.container_end; - this->from = rhs.from; - this->to = rhs.to; - return *this; - } - - TubeQueueFilterIterator &operator ++() { - do { - ++this->base; - } while (this->base != this->container_end && - (this->base->time() < from || - this->base->time() > to)); - return *this; - } - - //We only want to Iterate forward - so maybe delete this? - //timed_iterator &operator --() - //{ - // --base; - // return *this; - //} - - val_t &operator *() const { - return this->base->value; - } - - val_t *operator ->() const { - return &**this; - } - - virtual bool operator ==(const TubeQueueFilterIterator &rhs) const { - return this->base == rhs.base; - } - - virtual bool operator !=(const TubeQueueFilterIterator &rhs) const { - return this->base != rhs.base; - } - - virtual bool valid() const { + TubeIterator{base, container_end, from, to} {} + virtual bool valid() const override { if (this->base != this->container_end) { - return this->base->time() >= from && this->base->time() < to; + return this->base->time() >= this->from && this->base->time() < this->to; } return false; } - val_t &value() override { + val_t &value() const override { return this->base->value; } }; diff --git a/libopenage/tube/tube.h b/libopenage/tube/tube.h index 71089b2446..b25723621a 100644 --- a/libopenage/tube/tube.h +++ b/libopenage/tube/tube.h @@ -22,24 +22,4 @@ tube_time_t existent_until (const _T &t) { return t.existent_until(); } -template -class TubeIterator { -public: - virtual val_t &value() = 0; -}; - -template -bool valid(const _T &, const tube_time_t &at); - -template -using _valid_function_t = bool (*)(const _T&, const tube_time_t &); - -template -bool valid(const _T &t, - const tube_time_t& time) { - return existent_from(t) <= time && existent_until(t) > time; -} - - - }} // openage::tube diff --git a/libopenage/tube/tube_iterator.h b/libopenage/tube/tube_iterator.h new file mode 100644 index 0000000000..3a75551b5c --- /dev/null +++ b/libopenage/tube/tube_iterator.h @@ -0,0 +1,90 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "tube.h" + +namespace openage { +namespace tube { + +template +class TubeIterator : + public std::iterator +{ +public: + virtual val_t &value() const = 0; + virtual bool valid() const = 0; + + TubeIterator(const TubeIterator &rhs) : + base{rhs.base}, + container_end{rhs.container_end}, + from{rhs.from}, + to{rhs.to} {} + + TubeIterator &operator =(const TubeIterator &rhs) { + this->base = rhs.base; + this->container_end = rhs.container_end; + this->from = rhs.from; + this->to = rhs.to; + return *this; + } + + virtual val_t &operator *() const { + return this->value(); + } + + virtual val_t *operator ->() const { + return &this->value(); + } + + /** + * For equalness only the base iterator will be testet - not the timespans + * this is defined in. + */ + virtual bool operator ==(const TubeIterator &rhs) const { + return this->base == rhs.base; + } + + /** + * For unequalness only the base iterator will be testet - not the timespans + * this is defined in. + */ + virtual bool operator !=(const TubeIterator &rhs) const { + return this->base != rhs.base; + } + + /** + * Advance to the next valid element. + */ + virtual TubeIterator &operator ++() { + do { + ++this->base; + } while (this->base != this->container_end && !this->valid()); + return *this; + } + +protected: + TubeIterator (const iterator_t &base, + const iterator_t &container_end, + const tube_time_t &from, + const tube_time_t &to) : + base{base}, + container_end{container_end}, + from{from}, + to{to} {} + +protected: + /// The iterator this is currently referring to. + iterator_t base; + /// The iterator to the containers end. + iterator_t container_end; + + /// The time, from where this iterator started to iterate. + tube_time_t from; + /// The time, to where this iterator will iterate. + tube_time_t to; +}; + +}} // openage::tube diff --git a/libopenage/tube/unordered_map.h b/libopenage/tube/tube_map.h similarity index 89% rename from libopenage/tube/unordered_map.h rename to libopenage/tube/tube_map.h index ca53ae0d55..b2895ec0a2 100644 --- a/libopenage/tube/unordered_map.h +++ b/libopenage/tube/tube_map.h @@ -47,9 +47,6 @@ class UnorderedMap { void kill(const tube_time_t &, const key_t &); void kill(const tube_time_t &, const TubeMapFilterIterator &); - bool is_alive(const tube_time_t &, const key_t &); - bool is_alive(const tube_time_t &, const TubeMapFilterIterator &); - void clean(const tube_time_t &); // remove all dead elements before that point in time void __attribute__((noinline)) dump() { @@ -115,7 +112,7 @@ UnorderedMap::between(const tube_time_t &from, const tube_time_t & from, to); - if (!it.valid(from)) { + if (!it.valid()) { ++it; } return it; @@ -190,22 +187,6 @@ void UnorderedMap::kill(const tube_time_t &time, it->second.dead = time; } -template -bool UnorderedMap::is_alive(const tube_time_t &time, - const key_t &key) { - auto it = this->container.find(key); - if (it != this->container.end()) { - return valid_f(it->second.value, time); - } -} - -template -bool UnorderedMap::is_alive(const tube_time_t &time, - const TubeMapFilterIterator &it) { - return valid_f(it->second.value, time); -} - template void UnorderedMap::clean(const tube_time_t &) { // TODO save everything to a file and be happy. From 3991df521df751fb5b9cda9a9fe2707e3c82e87b Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Thu, 20 Apr 2017 14:55:02 +0200 Subject: [PATCH 14/24] Tubes: refactoring and documentation --- libopenage/tube/test/test_container.cpp | 24 ++++--------- libopenage/tube/tube.h | 4 +-- libopenage/tube/tube_map.h | 46 +++++++++++++------------ 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/libopenage/tube/test/test_container.cpp b/libopenage/tube/test/test_container.cpp index 02d7df32d5..9b2df07b45 100644 --- a/libopenage/tube/test/test_container.cpp +++ b/libopenage/tube/test/test_container.cpp @@ -1,11 +1,11 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "../../testing/testing.h" -#include "../unordered_map.h" #include "../tube.h" #include "../tube_continuous.h" #include "../tube_discrete.h" #include "../tube_queue.h" +#include "../tube_map.h" #include #include @@ -16,19 +16,9 @@ namespace tests { struct map_test_element { volatile int value; - tube_time_t birth, death; - map_test_element(int v, tube_time_t b, tube_time_t d) : - value(v), - birth(b), - death(d) {} - - tube_time_t existent_from () const { - return this->birth; - } - tube_time_t existent_until () const { - return this->death; - } + map_test_element(int v) : + value(v) {} bool operator != (int rhs) { return this->value != rhs; @@ -49,10 +39,10 @@ void dump(const std::map &map) { } void test_map() { - UnorderedMap map; - map.insert(0, map_test_element(0, 0, 10)); - map.insert(5, map_test_element(1, 5, 10)); - map.insert(200, map_test_element(2, 100, 200)); + UnorderedMap map; + map.insert(0, 10, 0, 0); + map.insert(5, 10, 5, 1); + map.insert(100, 200, 200, 2); // Basic tests test lookup in the middle of the range. { diff --git a/libopenage/tube/tube.h b/libopenage/tube/tube.h index b25723621a..bb00bacb23 100644 --- a/libopenage/tube/tube.h +++ b/libopenage/tube/tube.h @@ -6,7 +6,7 @@ namespace openage { namespace tube { typedef float tube_time_t; - +/* template tube_time_t time(const _T &t) { return t.time(); @@ -21,5 +21,5 @@ template tube_time_t existent_until (const _T &t) { return t.existent_until(); } - +*/ }} // openage::tube diff --git a/libopenage/tube/tube_map.h b/libopenage/tube/tube_map.h index b2895ec0a2..52922967c0 100644 --- a/libopenage/tube/tube_map.h +++ b/libopenage/tube/tube_map.h @@ -26,28 +26,41 @@ class UnorderedMap { public: // Using does not work with templates typedef typename std::unordered_map::iterator iterator; + // TODO return an std::optional here. - std::pair> operator()(const tube_time_t&, const key_t &); + std::pair> + operator()(const tube_time_t&, const key_t &); + // TODO return an std::optional here. - std::pair> at(const tube_time_t &, const key_t &); + std::pair> + at(const tube_time_t &, const key_t &); + + TubeMapFilterIterator + begin(const tube_time_t &e = std::numeric_limits::infinity()); - TubeMapFilterIterator begin(const tube_time_t &e = std::numeric_limits::infinity()); - TubeMapFilterIterator end(const tube_time_t &e = std::numeric_limits::infinity()); + TubeMapFilterIterator + end(const tube_time_t &e = std::numeric_limits::infinity()); - TubeMapFilterIterator insert(const key_t &, const val_t &); - TubeMapFilterIterator insert(const tube_time_t &birth, const key_t &, const val_t &); - TubeMapFilterIterator insert(const tube_time_t &birth, const tube_time_t &death, const key_t &key, const val_t &value); + TubeMapFilterIterator + insert(const tube_time_t &birth, const key_t &, const val_t &); - TubeMapFilterIterator between(const tube_time_t &start, const tube_time_t &to); + TubeMapFilterIterator + insert(const tube_time_t &birth, const tube_time_t &death, const key_t &key, const val_t &value); + + TubeMapFilterIterator + between(const tube_time_t &start, const tube_time_t &to); void birth(const tube_time_t &, const key_t &); - void birth(const tube_time_t &, const TubeMapFilterIterator &); + void birth(const tube_time_t &, + const TubeMapFilterIterator &); void kill(const tube_time_t &, const key_t &); - void kill(const tube_time_t &, const TubeMapFilterIterator &); + void kill(const tube_time_t &, + const TubeMapFilterIterator &); - void clean(const tube_time_t &); // remove all dead elements before that point in time + // remove all dead elements before that point in time + void clean(const tube_time_t &); void __attribute__((noinline)) dump() { for (auto i : container) { @@ -118,17 +131,6 @@ UnorderedMap::between(const tube_time_t &from, const tube_time_t & return it; } -template -TubeMapFilterIterator> -UnorderedMap::insert(const key_t &key, - const val_t &value) { - return this->insert( - existent_from(value), - existent_until(value), - key, - value); -} - template TubeMapFilterIterator> UnorderedMap::insert(const tube_time_t &alive, From a1a1c63528c9205e8b7d6a19b2338402025cf7cb Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Fri, 28 Apr 2017 17:14:34 +0200 Subject: [PATCH 15/24] Whitespace and cleanup --- libopenage/tube/CMakeLists.txt | 1 - libopenage/tube/demo/physics.cpp | 100 ++++++++++---------- libopenage/tube/tube_container_iterator.cpp | 8 -- libopenage/tube/tube_container_iterator.h | 89 ----------------- 4 files changed, 49 insertions(+), 149 deletions(-) delete mode 100644 libopenage/tube/tube_container_iterator.cpp delete mode 100644 libopenage/tube/tube_container_iterator.h diff --git a/libopenage/tube/CMakeLists.txt b/libopenage/tube/CMakeLists.txt index c29c76712d..50e8800e91 100644 --- a/libopenage/tube/CMakeLists.txt +++ b/libopenage/tube/CMakeLists.txt @@ -1,7 +1,6 @@ add_sources(libopenage keyframe_container.cpp - #tube_container_iterator.cpp tube_event.cpp tube_queue.cpp tube_object.cpp diff --git a/libopenage/tube/demo/physics.cpp b/libopenage/tube/demo/physics.cpp index a91ef7ac70..3ccab7a70d 100644 --- a/libopenage/tube/demo/physics.cpp +++ b/libopenage/tube/demo/physics.cpp @@ -13,63 +13,61 @@ const float extrapolating_time = 100.0f; const int init_recursion_limit = 50; void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const tube::tube_time_t &now) { - for (auto evnt : events) { - //Process only if the future has changed - if (player.state.get(now).state != evnt.state) { - player.state.set_drop(now, evnt); - - switch(evnt.state) { - case event::UP: - case event::DOWN: { - if (evnt.state == event::UP) { - player.speed.set_drop(now, -2); - } else if (evnt.state == event::DOWN) { - player.speed.set_drop(now, 2); - } - player.speed.set_drop(now + extrapolating_time, 0); - - float new_pos = player.position.get(now) + - (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); - if (new_pos < 0) - new_pos = 0; - if (new_pos > state.resolution[1]) - new_pos = state.resolution[1]; - - player.position.set_drop(now+extrapolating_time, new_pos); - evnt.state = event::IDLE; - player.state.set_drop(now + extrapolating_time, evnt); - break; + for (auto evnt : events) { + //Process only if the future has changed + if (player.state.get(now).state != evnt.state) { + player.state.set_drop(now, evnt); + + switch(evnt.state) { + case event::UP: + case event::DOWN: { + if (evnt.state == event::UP) { + player.speed.set_drop(now, -2); + } else if (evnt.state == event::DOWN) { + player.speed.set_drop(now, 2); } - case event::IDLE: - player.position.set_drop(now+extrapolating_time, - player.position.get(now)); - break; - case event::START: - if (player.state.get(now).state == event::LOST) { - state.ball.position.set_drop(now, state.resolution * 0.5); - } - update_ball(state, now, init_recursion_limit); - break; - default: - break; + player.speed.set_drop(now + extrapolating_time, 0); + + float new_pos = player.position.get(now) + + (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); + if (new_pos < 0) + new_pos = 0; + if (new_pos > state.resolution[1]) + new_pos = state.resolution[1]; + + player.position.set_drop(now+extrapolating_time, new_pos); + evnt.state = event::IDLE; + player.state.set_drop(now + extrapolating_time, evnt); + break; + } + case event::IDLE: + player.position.set_drop(now+extrapolating_time, + player.position.get(now)); + break; + case event::START: + if (player.state.get(now).state == event::LOST) { + state.ball.position.set_drop(now, state.resolution * 0.5); } + update_ball(state, now, init_recursion_limit); + break; + default: + break; } } } +} - void Physics::update(PongState &state, const tube::tube_time_t &now) { - - - auto pos = state.ball.position.get(now); - //Handle panel p1 - if (pos[0] <= 1 - && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 - && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 - && state.ball.speed.get(now)[0] < 0) { - //Ball hit the paddel in this frame - auto s = state.ball.speed.get(now); - s[0] *= -1.0; - state.ball.speed.set_drop(now, s); +void Physics::update(PongState &state, const tube::tube_time_t &now) { + auto pos = state.ball.position.get(now); + //Handle panel p1 + if (pos[0] <= 1 + && pos[1] > state.p1.position.get(now) - state.p1.size.get(now) / 2 + && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 + && state.ball.speed.get(now)[0] < 0) { + //Ball hit the paddel in this frame + auto s = state.ball.speed.get(now); + s[0] *= -1.0; + state.ball.speed.set_drop(now, s); state.ball.position.set_drop(now, pos); // this line can handle the future! update_ball(state, now, init_recursion_limit); diff --git a/libopenage/tube/tube_container_iterator.cpp b/libopenage/tube/tube_container_iterator.cpp deleted file mode 100644 index b1d1b98164..0000000000 --- a/libopenage/tube/tube_container_iterator.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "tube_container_iterator.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tube/tube_container_iterator.h b/libopenage/tube/tube_container_iterator.h deleted file mode 100644 index cc88233a53..0000000000 --- a/libopenage/tube/tube_container_iterator.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "tube.h" - -#include - -namespace openage { -namespace tube { - -template -class timed_iterator : public std::iterator< std::bidirectional_iterator_tag, _Ty > -{ -public: - timed_iterator(typename container::const_iterator base, - tube_time_t reference_time) : - base(base), - now(reference_time) {} - - timed_iterator(const timed_iterator &rhs) : - base(rhs.base), - now(rhs.now) {} - - timed_iterator &operator = (const timed_iterator &rhs) { - this->base = rhs.base; - this->now = rhs.now; - return *this; - } - - timed_iterator operator ++() { - ++base; - return *this; - } - - timed_iterator operator ++(int) { - auto tmp = *this; - ++base; - return tmp; - } - - timed_iterator operator --() { - --base; - return *this; - } - - timed_iterator operator --(int) { - auto tmp = *this; - ++base; - return tmp; - } - - const _Ty &operator *() const { - return *base; - } - - const _Ty *operator ->() const { - return &**base; - } - - tube_time_t time() { - return (*this)->time; - } - - bool operator ==(const timed_iterator<_Ty, container> &rhs) const { - return base == rhs.base; - } - - bool operator !=(const timed_iterator<_Ty, container> &rhs) const { - return base != rhs.base; - } - - bool valid() { - return time() < to; - } - - operator bool() { - return valid(); - } - -protected: - typename container_iterator base; - tube_time_t now; - -}; - -}} // openage::tube From e2a1ebe360f54242d385d76fb8210696e3e0398d Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Fri, 12 May 2017 22:04:08 +0200 Subject: [PATCH 16/24] tubes: added a few more accessors --- libopenage/tube/tube_queue.h | 2 +- libopenage/tube/value_container.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libopenage/tube/tube_queue.h b/libopenage/tube/tube_queue.h index 49416eb955..aef458fa43 100644 --- a/libopenage/tube/tube_queue.h +++ b/libopenage/tube/tube_queue.h @@ -75,7 +75,7 @@ class Queue { return it; } - TubeQueueFilterIterator<_T, Queue<_T>> erase(const TubeQueueFilterIterator<_T, Queue<_T>> &t) { + TubeQueueFilterIterator<_T, Queue<_T>> erase(const TubeIterator<_T, Queue<_T>> &t) { auto it = container.erase(t.base); auto ct = TubeQueueFilterIterator<_T, Queue<_T>>( it, diff --git a/libopenage/tube/value_container.h b/libopenage/tube/value_container.h index cd9ba28a0c..87e36eb867 100644 --- a/libopenage/tube/value_container.h +++ b/libopenage/tube/value_container.h @@ -20,6 +20,9 @@ class ValueContainer { } virtual bool needs_update(const tube_time_t &at); + + virtual std::pair frame(const tube_time_t &) const; + virtual std::pair next_frame(const tube_time_t &) const; public: // Inserter mode virtual void set_drop(const tube_time_t &at, const _T &value); @@ -42,6 +45,19 @@ void ValueContainer<_T>::set_insert(const tube_time_t &at, const _T &value) { this->container.insert(at, value, this->last_element); } +template +std::pair ValueContainer<_T>::frame(const tube_time_t &time) const { + auto e = this->container.last(time, this->container.end()); + return std::make_pair(e->time, e->value); +} + +template +std::pair ValueContainer<_T>::next_frame(const tube_time_t &time) const { + auto e = this->container.last(time, this->container.end()); + e ++; + return std::make_pair(e->time, e->value); +} + template bool ValueContainer<_T>::needs_update(const tube_time_t &at) { auto e = this->container.last(at, this->container.end()); From a21e99ac686ff48266fd77d744384d1b491cdd6f Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Fri, 19 May 2017 20:12:05 +0200 Subject: [PATCH 17/24] curves: renamed tubes to curves --- libopenage/CMakeLists.txt | 2 +- libopenage/curve/CMakeLists.txt | 12 ++ .../tube_object.cpp => curve/continuous.cpp} | 6 +- .../tube_continuous.h => curve/continuous.h} | 10 +- .../{tube/tube_event.h => curve/curve.cpp} | 6 +- libopenage/{tube/tube.h => curve/curve.h} | 12 +- libopenage/{tube => curve}/datatypes.md | 0 .../{tube => curve}/demo/CMakeLists.txt | 0 .../{tube => curve}/demo/aicontroller.cpp | 6 +- .../{tube => curve}/demo/aicontroller.h | 6 +- libopenage/{tube => curve}/demo/gamestate.h | 29 ++- libopenage/{tube => curve}/demo/gui.cpp | 6 +- libopenage/{tube => curve}/demo/gui.h | 6 +- libopenage/{tube => curve}/demo/main.cpp | 14 +- libopenage/{tube => curve}/demo/physics.cpp | 10 +- libopenage/{tube => curve}/demo/physics.h | 12 +- .../tube_event.cpp => curve/discrete.cpp} | 6 +- .../tube_discrete.h => curve/discrete.h} | 10 +- .../internal}/keyframe_container.cpp | 4 +- .../internal}/keyframe_container.h | 38 ++-- .../internal}/value_container.cpp | 4 +- .../internal}/value_container.h | 28 +-- .../tube_iterator.h => curve/iterator.h} | 28 +-- libopenage/curve/map.h | 197 ++++++++++++++++++ .../{tube => curve}/map_filter_iterator.h | 20 +- .../tube_objectlist.h => curve/queue.cpp} | 6 +- .../{tube/tube_queue.h => curve/queue.h} | 48 ++--- .../{tube => curve}/queue_filter_iterator.h | 20 +- libopenage/curve/test/CMakeLists.txt | 7 + .../{tube => curve}/test/test_container.cpp | 14 +- .../test/test_curve_types.cpp} | 14 +- .../test/test_serialization.cpp | 4 +- libopenage/tube/.gitignore | 31 --- libopenage/tube/CMakeLists.txt | 15 -- libopenage/tube/test/CMakeLists.txt | 10 - libopenage/tube/tube.cpp | 8 - libopenage/tube/tube_continuous.cpp | 8 - libopenage/tube/tube_discrete.cpp | 8 - libopenage/tube/tube_map.h | 197 ------------------ libopenage/tube/tube_object.h | 14 -- libopenage/tube/tube_objectlist.cpp | 8 - libopenage/tube/tube_queue.cpp | 8 - openage/testing/testlist.py | 8 +- 43 files changed, 404 insertions(+), 496 deletions(-) create mode 100644 libopenage/curve/CMakeLists.txt rename libopenage/{tube/tube_object.cpp => curve/continuous.cpp} (60%) rename libopenage/{tube/tube_continuous.h => curve/continuous.h} (85%) rename libopenage/{tube/tube_event.h => curve/curve.cpp} (62%) rename libopenage/{tube/tube.h => curve/curve.h} (57%) rename libopenage/{tube => curve}/datatypes.md (100%) rename libopenage/{tube => curve}/demo/CMakeLists.txt (100%) rename libopenage/{tube => curve}/demo/aicontroller.cpp (90%) rename libopenage/{tube => curve}/demo/aicontroller.h (79%) rename libopenage/{tube => curve}/demo/gamestate.h (53%) rename libopenage/{tube => curve}/demo/gui.cpp (97%) rename libopenage/{tube => curve}/demo/gui.h (75%) rename libopenage/{tube => curve}/demo/main.cpp (91%) rename libopenage/{tube => curve}/demo/physics.cpp (93%) rename libopenage/{tube => curve}/demo/physics.h (50%) rename libopenage/{tube/tube_event.cpp => curve/discrete.cpp} (61%) rename libopenage/{tube/tube_discrete.h => curve/discrete.h} (65%) rename libopenage/{tube => curve/internal}/keyframe_container.cpp (76%) rename libopenage/{tube => curve/internal}/keyframe_container.h (85%) rename libopenage/{tube => curve/internal}/value_container.cpp (76%) rename libopenage/{tube => curve/internal}/value_container.h (55%) rename libopenage/{tube/tube_iterator.h => curve/iterator.h} (74%) create mode 100644 libopenage/curve/map.h rename libopenage/{tube => curve}/map_filter_iterator.h (76%) rename libopenage/{tube/tube_objectlist.h => curve/queue.cpp} (62%) rename libopenage/{tube/tube_queue.h => curve/queue.h} (58%) rename libopenage/{tube => curve}/queue_filter_iterator.h (72%) create mode 100644 libopenage/curve/test/CMakeLists.txt rename libopenage/{tube => curve}/test/test_container.cpp (95%) rename libopenage/{tube/test/test_tube_types.cpp => curve/test/test_curve_types.cpp} (93%) rename libopenage/{tube => curve}/test/test_serialization.cpp (79%) delete mode 100644 libopenage/tube/.gitignore delete mode 100644 libopenage/tube/CMakeLists.txt delete mode 100644 libopenage/tube/test/CMakeLists.txt delete mode 100644 libopenage/tube/tube.cpp delete mode 100644 libopenage/tube/tube_continuous.cpp delete mode 100644 libopenage/tube/tube_discrete.cpp delete mode 100644 libopenage/tube/tube_map.h delete mode 100644 libopenage/tube/tube_object.h delete mode 100644 libopenage/tube/tube_objectlist.cpp delete mode 100644 libopenage/tube/tube_queue.cpp diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index d418e8bd3d..a6dd40084d 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -31,6 +31,7 @@ pxdgen( add_subdirectory("audio") add_subdirectory("console") add_subdirectory("coord") +add_subdirectory("curve") add_subdirectory("cvar") add_subdirectory("datastructure") add_subdirectory("error") @@ -46,7 +47,6 @@ add_subdirectory("rng") add_subdirectory("shader") add_subdirectory("terrain") add_subdirectory("testing") -add_subdirectory("tube") add_subdirectory("unit") add_subdirectory("util") diff --git a/libopenage/curve/CMakeLists.txt b/libopenage/curve/CMakeLists.txt new file mode 100644 index 0000000000..f03dc732cc --- /dev/null +++ b/libopenage/curve/CMakeLists.txt @@ -0,0 +1,12 @@ + +add_sources(libopenage + internal/keyframe_container.cpp + internal/value_container.cpp + queue.cpp + continuous.cpp + discrete.cpp + curve.cpp +) + +add_subdirectory(test) +add_subdirectory(demo) diff --git a/libopenage/tube/tube_object.cpp b/libopenage/curve/continuous.cpp similarity index 60% rename from libopenage/tube/tube_object.cpp rename to libopenage/curve/continuous.cpp index 46c07a74d3..c5ed0b67f0 100644 --- a/libopenage/tube/tube_object.cpp +++ b/libopenage/curve/continuous.cpp @@ -1,8 +1,8 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "tube_object.h" +#include "continuous.h" namespace openage { -namespace tube { +namespace curve { -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/tube_continuous.h b/libopenage/curve/continuous.h similarity index 85% rename from libopenage/tube/tube_continuous.h rename to libopenage/curve/continuous.h index c73b7fbb6c..1c55b503bb 100644 --- a/libopenage/tube/tube_continuous.h +++ b/libopenage/curve/continuous.h @@ -2,21 +2,21 @@ #pragma once -#include "value_container.h" +#include "internal/value_container.h" #include "../log/log.h" namespace openage { -namespace tube { +namespace curve { template class Continuous : public ValueContainer<_T> { public: - _T get(const tube_time_t &) const override; + _T get(const curve_time_t &) const override; }; template -_T Continuous<_T>::get(const tube_time_t &time) const { +_T Continuous<_T>::get(const curve_time_t &time) const { auto e = this->container.last(time, this->last_element); this->last_element = e; auto nxt = e; @@ -42,4 +42,4 @@ _T Continuous<_T>::get(const tube_time_t &time) const { } } -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/tube_event.h b/libopenage/curve/curve.cpp similarity index 62% rename from libopenage/tube/tube_event.h rename to libopenage/curve/curve.cpp index 2be20e6b2a..7283022848 100644 --- a/libopenage/tube/tube_event.h +++ b/libopenage/curve/curve.cpp @@ -1,8 +1,8 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#pragma once +#include "curve.h" namespace openage { -namespace tube { +namespace curve { -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/tube.h b/libopenage/curve/curve.h similarity index 57% rename from libopenage/tube/tube.h rename to libopenage/curve/curve.h index bb00bacb23..b8bcca666b 100644 --- a/libopenage/tube/tube.h +++ b/libopenage/curve/curve.h @@ -3,23 +3,23 @@ #pragma once namespace openage { -namespace tube { +namespace curve { -typedef float tube_time_t; +typedef float curve_time_t; /* template -tube_time_t time(const _T &t) { +curve_time_t time(const _T &t) { return t.time(); } template -tube_time_t existent_from (const _T &t) { +curve_time_t existent_from (const _T &t) { return t.existent_from(); } template -tube_time_t existent_until (const _T &t) { +curve_time_t existent_until (const _T &t) { return t.existent_until(); } */ -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/datatypes.md b/libopenage/curve/datatypes.md similarity index 100% rename from libopenage/tube/datatypes.md rename to libopenage/curve/datatypes.md diff --git a/libopenage/tube/demo/CMakeLists.txt b/libopenage/curve/demo/CMakeLists.txt similarity index 100% rename from libopenage/tube/demo/CMakeLists.txt rename to libopenage/curve/demo/CMakeLists.txt diff --git a/libopenage/tube/demo/aicontroller.cpp b/libopenage/curve/demo/aicontroller.cpp similarity index 90% rename from libopenage/tube/demo/aicontroller.cpp rename to libopenage/curve/demo/aicontroller.cpp index b58e36b860..47ef8c0092 100644 --- a/libopenage/tube/demo/aicontroller.cpp +++ b/libopenage/curve/demo/aicontroller.cpp @@ -3,12 +3,12 @@ #include "aicontroller.h" namespace openage { -namespace tubepong { +namespace curvepong { std::vector &AIInput::getInputs( const PongPlayer &player, const PongBall &ball, - const tube::tube_time_t &now) { + const curve::curve_time_t &now) { this->event_cache.clear(); auto position = player.position.get(now); @@ -27,4 +27,4 @@ std::vector &AIInput::getInputs( return this->event_cache; } -}} // openage::tubepong +}} // openage::curvepong diff --git a/libopenage/tube/demo/aicontroller.h b/libopenage/curve/demo/aicontroller.h similarity index 79% rename from libopenage/tube/demo/aicontroller.h rename to libopenage/curve/demo/aicontroller.h index 1a8c67100a..d87c455be1 100644 --- a/libopenage/tube/demo/aicontroller.h +++ b/libopenage/curve/demo/aicontroller.h @@ -7,17 +7,17 @@ #include "gamestate.h" namespace openage { -namespace tubepong { +namespace curvepong { class AIInput { public: std::vector &getInputs( const PongPlayer &player, const PongBall &ball, - const tube::tube_time_t &now); + const curve::curve_time_t &now); private: std::vector event_cache; }; -}} // openage::tubepong +}} // openage::curvepong diff --git a/libopenage/tube/demo/gamestate.h b/libopenage/curve/demo/gamestate.h similarity index 53% rename from libopenage/tube/demo/gamestate.h rename to libopenage/curve/demo/gamestate.h index 3ae0674f84..ce2c4a742c 100644 --- a/libopenage/tube/demo/gamestate.h +++ b/libopenage/curve/demo/gamestate.h @@ -1,14 +1,13 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2017-2017 the openage authors. See copying.md for legal info. #pragma once -#include "../tube_continuous.h" -#include "../tube_discrete.h" -#include "../tube_object.h" +#include "../continuous.h" +#include "../discrete.h" #include "../../util/vector.h" namespace openage { -namespace tubepong { +namespace curvepong { struct event { int player; @@ -19,7 +18,7 @@ struct event { event() : player(0), state(IDLE) {} }; -class PongPlayer : public tube::TubeObject { +class PongPlayer { public: PongPlayer() { speed.set_drop(0, 1); @@ -31,19 +30,19 @@ class PongPlayer : public tube::TubeObject { id = 0; } - tube::Discrete speed; - tube::Continuous position; - tube::Discrete lives; - tube::Discrete state; - tube::Discrete size; + curve::Discrete speed; + curve::Continuous position; + curve::Discrete lives; + curve::Discrete state; + curve::Discrete size; float y; int id; }; -class PongBall : public tube::TubeObject { +class PongBall { public: - tube::Discrete> speed; - tube::Continuous> position; + curve::Discrete> speed; + curve::Continuous> position; }; class PongState { @@ -56,4 +55,4 @@ class PongState { util::Vector<2> resolution; }; -}} // openage::tubepong +}} // openage::curvepong diff --git a/libopenage/tube/demo/gui.cpp b/libopenage/curve/demo/gui.cpp similarity index 97% rename from libopenage/tube/demo/gui.cpp rename to libopenage/curve/demo/gui.cpp index 604ea91c10..f99ab4c18a 100644 --- a/libopenage/tube/demo/gui.cpp +++ b/libopenage/curve/demo/gui.cpp @@ -6,7 +6,7 @@ #include namespace openage { -namespace tubepong { +namespace curvepong { std::vector &Gui::getInputs(const PongPlayer &player) { input_cache.clear(); @@ -83,7 +83,7 @@ Gui::Gui() { getch(); } -void Gui::draw(PongState &state, const tube::tube_time_t &now) { +void Gui::draw(PongState &state, const curve::curve_time_t &now) { erase(); // clear(); // Print Score @@ -160,4 +160,4 @@ void Gui::draw_ball(util::Vector<2> pos, int idx) { standend(); } } -} // openage::tubepong +} // openage::curvepong diff --git a/libopenage/tube/demo/gui.h b/libopenage/curve/demo/gui.h similarity index 75% rename from libopenage/tube/demo/gui.h rename to libopenage/curve/demo/gui.h index f8d2142ff2..d04662324d 100644 --- a/libopenage/tube/demo/gui.h +++ b/libopenage/curve/demo/gui.h @@ -7,7 +7,7 @@ #include "gamestate.h" namespace openage { -namespace tubepong { +namespace curvepong { class Gui { @@ -15,11 +15,11 @@ class Gui { public: Gui(); std::vector &getInputs(const PongPlayer &player); - void draw(PongState &state, const tube::tube_time_t &now); + void draw(PongState &state, const curve::curve_time_t &now); void draw_ball(util::Vector<2> ball, int idx); private: std::vector input_cache; }; -}} // openage::tubepong +}} // openage::curvepong diff --git a/libopenage/tube/demo/main.cpp b/libopenage/curve/demo/main.cpp similarity index 91% rename from libopenage/tube/demo/main.cpp rename to libopenage/curve/demo/main.cpp index d5ad18a910..c7f67efe52 100644 --- a/libopenage/tube/demo/main.cpp +++ b/libopenage/curve/demo/main.cpp @@ -12,18 +12,18 @@ typedef std::chrono::high_resolution_clock Clock; namespace openage { -namespace tubepong { +namespace curvepong { int demo() { // Restart forever - tubepong::Gui gui; - tubepong::Physics phys; - tubepong::AIInput ai; + curvepong::Gui gui; + curvepong::Physics phys; + curvepong::AIInput ai; bool running = true; while (running) { - tubepong::PongState state; - tube::tube_time_t now = 1; + curvepong::PongState state; + curve::curve_time_t now = 1; state.p1.lives.set_drop(now, 3); state.p1.id = 0; @@ -80,4 +80,4 @@ int demo() { return 0; } } -} // openage::tubepong +} // openage::curvepong diff --git a/libopenage/tube/demo/physics.cpp b/libopenage/curve/demo/physics.cpp similarity index 93% rename from libopenage/tube/demo/physics.cpp rename to libopenage/curve/demo/physics.cpp index 3ccab7a70d..d069c59cfe 100644 --- a/libopenage/tube/demo/physics.cpp +++ b/libopenage/curve/demo/physics.cpp @@ -7,12 +7,12 @@ #include namespace openage { -namespace tubepong { +namespace curvepong { const float extrapolating_time = 100.0f; const int init_recursion_limit = 50; -void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const tube::tube_time_t &now) { +void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const curve::curve_time_t &now) { for (auto evnt : events) { //Process only if the future has changed if (player.state.get(now).state != evnt.state) { @@ -57,7 +57,7 @@ void Physics::processInput(PongState &state, PongPlayer &player, std::vector #include "gamestate.h" -#include "../tube.h" +#include "../curve.h" namespace openage { -namespace tubepong { +namespace curvepong { class Physics { public: - void processInput(PongState &, PongPlayer &, std::vector &events, const tube::tube_time_t &now); - void update(PongState &, const tube::tube_time_t &); + void processInput(PongState &, PongPlayer &, std::vector &events, const curve::curve_time_t &now); + void update(PongState &, const curve::curve_time_t &); protected: - void update_ball(PongState &, const tube::tube_time_t &, int recursion_limit); + void update_ball(PongState &, const curve::curve_time_t &, int recursion_limit); }; -}} // openage::tubepong +}} // openage::curvepong diff --git a/libopenage/tube/tube_event.cpp b/libopenage/curve/discrete.cpp similarity index 61% rename from libopenage/tube/tube_event.cpp rename to libopenage/curve/discrete.cpp index c6e585d25a..b233479b67 100644 --- a/libopenage/tube/tube_event.cpp +++ b/libopenage/curve/discrete.cpp @@ -1,8 +1,8 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#include "tube_event.h" +#include "discrete.h" namespace openage { -namespace tube { +namespace curve { -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/tube_discrete.h b/libopenage/curve/discrete.h similarity index 65% rename from libopenage/tube/tube_discrete.h rename to libopenage/curve/discrete.h index fda9f420d5..a95343eeba 100644 --- a/libopenage/tube/tube_discrete.h +++ b/libopenage/curve/discrete.h @@ -2,22 +2,22 @@ #pragma once -#include "value_container.h" +#include "internal/value_container.h" namespace openage { -namespace tube { +namespace curve { template class Discrete : public ValueContainer<_T> { public: - _T get(const tube_time_t &) const override; + _T get(const curve_time_t &) const override; }; template -_T Discrete<_T>::get(const tube_time_t &time) const { +_T Discrete<_T>::get(const curve_time_t &time) const { auto e = this->container.last(time, this->last_element); this->last_element = e; // TODO if Cacheing? return e->value; } -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/keyframe_container.cpp b/libopenage/curve/internal/keyframe_container.cpp similarity index 76% rename from libopenage/tube/keyframe_container.cpp rename to libopenage/curve/internal/keyframe_container.cpp index 9620527dcb..ee3da68353 100644 --- a/libopenage/tube/keyframe_container.cpp +++ b/libopenage/curve/internal/keyframe_container.cpp @@ -3,6 +3,6 @@ #include "keyframe_container.h" namespace openage { -namespace tube { +namespace curve { -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/keyframe_container.h b/libopenage/curve/internal/keyframe_container.h similarity index 85% rename from libopenage/tube/keyframe_container.h rename to libopenage/curve/internal/keyframe_container.h index f332775f9f..f5fbfd456f 100644 --- a/libopenage/tube/keyframe_container.h +++ b/libopenage/curve/internal/keyframe_container.h @@ -2,9 +2,9 @@ #pragma once -#include "tube.h" +#include "../curve.h" -#include "../error/error.h" +#include "../../error/error.h" #include #include @@ -12,7 +12,7 @@ #include namespace openage { -namespace tube { +namespace curve { /** * A timely ordered list with several management functions @@ -27,7 +27,7 @@ template class KeyframeContainer { public: /** - * A element of the tubecontainer. This is especially used to keep track of + * A element of the curvecontainer. This is especially used to keep track of * the value-timing. */ class Keyframe { @@ -40,17 +40,17 @@ class KeyframeContainer { /** * New, default-constructed element at the given time */ - Keyframe(const tube_time_t &time) : + Keyframe(const curve_time_t &time) : time{time} {} /** * New element fron time and value */ - Keyframe(const tube_time_t &time, const _T &value) : + Keyframe(const curve_time_t &time, const _T &value) : time{time}, value{value} {} - const tube_time_t time = std::numeric_limits::infinity(); + const curve_time_t time = std::numeric_limits::infinity(); _T value = _T(); }; @@ -60,12 +60,12 @@ class KeyframeContainer { * The most important property of this container is the iterator validity on * insert and remove. */ - typedef std::list tubecontainer; + typedef std::list curvecontainer; /** * The iterator type to access elements in the container */ - typedef typename tubecontainer::const_iterator KeyframeIterator; + typedef typename curvecontainer::const_iterator KeyframeIterator; /** default c'tor **/ KeyframeContainer(); @@ -75,7 +75,7 @@ class KeyframeContainer { * Get the last element with e->time <= time, given a hint where to * start the search. */ - KeyframeIterator last(const tube_time_t &time, + KeyframeIterator last(const curve_time_t &time, const KeyframeIterator & hint) const; /** @@ -86,7 +86,7 @@ class KeyframeContainer { * no chance for you to have a hint (or the container is known to be nearly * empty) */ - KeyframeIterator last(const tube_time_t &time) const { + KeyframeIterator last(const curve_time_t &time) const { return this->last(time, this->container.begin()); } @@ -113,14 +113,14 @@ class KeyframeContainer { * The use of this function is discouraged, use it only, if your really do not * have the possibility to get a hint */ - KeyframeIterator insert(const tube_time_t &time, const _T&value) { + KeyframeIterator insert(const curve_time_t &time, const _T&value) { return this->insert(Keyframe(time, value), this->container.begin()); } /** * Create and insert a new element. The hint gives an approximate location. */ - KeyframeIterator insert(const tube_time_t &time, const _T&value, const KeyframeIterator &hint) { + KeyframeIterator insert(const curve_time_t &time, const _T&value, const KeyframeIterator &hint) { return this->insert(Keyframe(time, value), hint); } @@ -130,7 +130,7 @@ class KeyframeContainer { KeyframeIterator erase_after(KeyframeIterator last_valid); /** - * Erase a single element from the tube. + * Erase a single element from the curve. */ KeyframeIterator erase(KeyframeIterator ); @@ -160,7 +160,7 @@ class KeyframeContainer { /** * The data store. */ - tubecontainer container; + curvecontainer container; }; @@ -168,7 +168,7 @@ template KeyframeContainer<_T>::KeyframeContainer() { //Create a default element at -Inf, that can always be dereferenced - so there will by definition never be //a element that cannot be dereferenced - this->container.push_back(Keyframe(-std::numeric_limits::infinity(), _T())); + this->container.push_back(Keyframe(-std::numeric_limits::infinity(), _T())); } template @@ -184,12 +184,12 @@ KeyframeContainer<_T>::~KeyframeContainer() { * This method returns nullptr, if begin->time > time. **/ template -typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::last(const tube_time_t &time, const KeyframeIterator &hint) const { +typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::last(const curve_time_t &time, const KeyframeIterator &hint) const { KeyframeIterator e = (hint == this->container.end()) ? this->container.begin() : hint; if (this->container.front().time > time) { // This will never happen due to the container.front->time == -Inf magic! - throw new Error(ERR << "rupture in spacetime detected, tube container is broken"); + throw new Error(ERR << "rupture in spacetime detected, curve container is broken"); } // Search in the queue @@ -247,4 +247,4 @@ typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::erase(Ke return this->container.erase(e); } -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/value_container.cpp b/libopenage/curve/internal/value_container.cpp similarity index 76% rename from libopenage/tube/value_container.cpp rename to libopenage/curve/internal/value_container.cpp index a973ab73f1..c1d39ae291 100644 --- a/libopenage/tube/value_container.cpp +++ b/libopenage/curve/internal/value_container.cpp @@ -3,6 +3,6 @@ #include "value_container.h" namespace openage { -namespace tube { +namespace curve { -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/value_container.h b/libopenage/curve/internal/value_container.h similarity index 55% rename from libopenage/tube/value_container.h rename to libopenage/curve/internal/value_container.h index 87e36eb867..27d911e5f7 100644 --- a/libopenage/tube/value_container.h +++ b/libopenage/curve/internal/value_container.h @@ -5,7 +5,7 @@ #include "keyframe_container.h" namespace openage { -namespace tube { +namespace curve { template class ValueContainer { @@ -13,20 +13,20 @@ class ValueContainer { ValueContainer() : last_element{container.begin()} {} - virtual _T get(const tube_time_t &t) const=0; + virtual _T get(const curve_time_t &t) const=0; - virtual _T operator ()(const tube_time_t &now) { + virtual _T operator ()(const curve_time_t &now) { return get(now); } - virtual bool needs_update(const tube_time_t &at); + virtual bool needs_update(const curve_time_t &at); - virtual std::pair frame(const tube_time_t &) const; - virtual std::pair next_frame(const tube_time_t &) const; + virtual std::pair frame(const curve_time_t &) const; + virtual std::pair next_frame(const curve_time_t &) const; public: // Inserter mode - virtual void set_drop(const tube_time_t &at, const _T &value); - virtual void set_insert(const tube_time_t &at, const _T &value); + virtual void set_drop(const curve_time_t &at, const _T &value); + virtual void set_insert(const curve_time_t &at, const _T &value); protected: KeyframeContainer<_T> container; @@ -34,32 +34,32 @@ class ValueContainer { }; template -void ValueContainer<_T>::set_drop(const tube_time_t &at, const _T &value) { +void ValueContainer<_T>::set_drop(const curve_time_t &at, const _T &value) { auto hint = this->container.erase_after(this->container.last(at, this->last_element)); container.insert(at, value, hint); last_element = hint; } template -void ValueContainer<_T>::set_insert(const tube_time_t &at, const _T &value) { +void ValueContainer<_T>::set_insert(const curve_time_t &at, const _T &value) { this->container.insert(at, value, this->last_element); } template -std::pair ValueContainer<_T>::frame(const tube_time_t &time) const { +std::pair ValueContainer<_T>::frame(const curve_time_t &time) const { auto e = this->container.last(time, this->container.end()); return std::make_pair(e->time, e->value); } template -std::pair ValueContainer<_T>::next_frame(const tube_time_t &time) const { +std::pair ValueContainer<_T>::next_frame(const curve_time_t &time) const { auto e = this->container.last(time, this->container.end()); e ++; return std::make_pair(e->time, e->value); } template -bool ValueContainer<_T>::needs_update(const tube_time_t &at) { +bool ValueContainer<_T>::needs_update(const curve_time_t &at) { auto e = this->container.last(at, this->container.end()); if (e->time > at || ++e == this->container.end() || e->time > at) { return true; @@ -68,4 +68,4 @@ bool ValueContainer<_T>::needs_update(const tube_time_t &at) { } } -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/tube_iterator.h b/libopenage/curve/iterator.h similarity index 74% rename from libopenage/tube/tube_iterator.h rename to libopenage/curve/iterator.h index 3a75551b5c..c1af8e282e 100644 --- a/libopenage/tube/tube_iterator.h +++ b/libopenage/curve/iterator.h @@ -2,28 +2,28 @@ #pragma once -#include "tube.h" +#include "curve.h" namespace openage { -namespace tube { +namespace curve { template -class TubeIterator : +class CurveIterator : public std::iterator { public: virtual val_t &value() const = 0; virtual bool valid() const = 0; - TubeIterator(const TubeIterator &rhs) : + CurveIterator(const CurveIterator &rhs) : base{rhs.base}, container_end{rhs.container_end}, from{rhs.from}, to{rhs.to} {} - TubeIterator &operator =(const TubeIterator &rhs) { + CurveIterator &operator =(const CurveIterator &rhs) { this->base = rhs.base; this->container_end = rhs.container_end; this->from = rhs.from; @@ -43,7 +43,7 @@ class TubeIterator : * For equalness only the base iterator will be testet - not the timespans * this is defined in. */ - virtual bool operator ==(const TubeIterator &rhs) const { + virtual bool operator ==(const CurveIterator &rhs) const { return this->base == rhs.base; } @@ -51,14 +51,14 @@ class TubeIterator : * For unequalness only the base iterator will be testet - not the timespans * this is defined in. */ - virtual bool operator !=(const TubeIterator &rhs) const { + virtual bool operator !=(const CurveIterator &rhs) const { return this->base != rhs.base; } /** * Advance to the next valid element. */ - virtual TubeIterator &operator ++() { + virtual CurveIterator &operator ++() { do { ++this->base; } while (this->base != this->container_end && !this->valid()); @@ -66,10 +66,10 @@ class TubeIterator : } protected: - TubeIterator (const iterator_t &base, + CurveIterator (const iterator_t &base, const iterator_t &container_end, - const tube_time_t &from, - const tube_time_t &to) : + const curve_time_t &from, + const curve_time_t &to) : base{base}, container_end{container_end}, from{from}, @@ -82,9 +82,9 @@ class TubeIterator : iterator_t container_end; /// The time, from where this iterator started to iterate. - tube_time_t from; + curve_time_t from; /// The time, to where this iterator will iterate. - tube_time_t to; + curve_time_t to; }; -}} // openage::tube +}} // openage::curve diff --git a/libopenage/curve/map.h b/libopenage/curve/map.h new file mode 100644 index 0000000000..b178e68068 --- /dev/null +++ b/libopenage/curve/map.h @@ -0,0 +1,197 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "curve.h" +#include "map_filter_iterator.h" + +namespace openage { +namespace curve { + +template +class UnorderedMap { + struct map_element { + val_t value; + curve_time_t alive; + curve_time_t dead; + map_element (val_t v, const curve_time_t &a, const curve_time_t &d) + : value(v), + alive(a), + dead(d) {} + }; + std::unordered_map container; + +public: + // Using does not work with templates + typedef typename std::unordered_map::iterator iterator; + +// TODO return an std::optional here. + std::pair> + operator()(const curve_time_t&, const key_t &); + +// TODO return an std::optional here. + std::pair> + at(const curve_time_t &, const key_t &); + + MapFilterIterator + begin(const curve_time_t &e = std::numeric_limits::infinity()); + + MapFilterIterator + end(const curve_time_t &e = std::numeric_limits::infinity()); + + + MapFilterIterator + insert(const curve_time_t &birth, const key_t &, const val_t &); + + MapFilterIterator + insert(const curve_time_t &birth, const curve_time_t &death, const key_t &key, const val_t &value); + + MapFilterIterator + between(const curve_time_t &start, const curve_time_t &to); + + void birth(const curve_time_t &, const key_t &); + void birth(const curve_time_t &, + const MapFilterIterator &); + + void kill(const curve_time_t &, const key_t &); + void kill(const curve_time_t &, + const MapFilterIterator &); + + // remove all dead elements before that point in time + void clean(const curve_time_t &); + + void __attribute__((noinline)) dump() { + for (auto i : container) { + std::cout << "Element: " << i.second.value << std::endl;; + } + } +}; + +template +std::pair>> +UnorderedMap::operator()(const curve_time_t &time, + const key_t &key) { + return this->at(time, key); +} + +template +std::pair>> +UnorderedMap::at(const curve_time_t & time, + const key_t & key) { + auto e = this->container.find(key); + if (e != this->container.end() && e->second.alive <= time && e->second.dead >time) { + return std::make_pair( + true, + MapFilterIterator>( + e, + this->container.end(), + time, + std::numeric_limits::infinity())); + } else { + return std::make_pair( + false, + this->end(time)); + } +} + +template +MapFilterIterator> +UnorderedMap::begin(const curve_time_t &time) { + return MapFilterIterator>( + this->container.begin(), + this->container.end(), + time, + std::numeric_limits::infinity()); +} + +template +MapFilterIterator> +UnorderedMap::end(const curve_time_t &time) { + return MapFilterIterator>( + this->container.end(), + this->container.end(), + -std::numeric_limits::infinity(), + time); +} + +template +MapFilterIterator> +UnorderedMap::between(const curve_time_t &from, const curve_time_t &to) { + auto it = MapFilterIterator>( + this->container.begin(), + this->container.end(), + from, + to); + + if (!it.valid()) { + ++it; + } + return it; +} + +template +MapFilterIterator> +UnorderedMap::insert(const curve_time_t &alive, + const key_t &key, + const val_t &value) { + return this->insert( + alive, + std::numeric_limits::infinity(), + key, + value); +} + +template +MapFilterIterator> +UnorderedMap::insert(const curve_time_t &alive, + const curve_time_t &dead, + const key_t &key, + const val_t &value) { + map_element e(value, alive, dead); + auto it = this->container.insert(std::make_pair(key, e)); + return MapFilterIterator>( + it.first, + this->container.end(), + alive, + dead); +} + +template +void UnorderedMap::birth(const curve_time_t &time, + const key_t &key) { + auto it = this->container.find(key); + if (it != this->container.end()) { + it->second.alive = time; + } +} + +template +void UnorderedMap::birth(const curve_time_t &time, + const MapFilterIterator &it) { + it->second.alive = time; +} + +template +void UnorderedMap::kill(const curve_time_t &time, + const key_t &key) { + auto it = this->container.find(key); + if (it != this->container.end()) { + it->second.dead = time; + } +} + +template +void UnorderedMap::kill(const curve_time_t &time, + const MapFilterIterator &it) { + it->second.dead = time; +} + +template +void UnorderedMap::clean(const curve_time_t &) { + // TODO save everything to a file and be happy. +} + +}} // openage::curve diff --git a/libopenage/tube/map_filter_iterator.h b/libopenage/curve/map_filter_iterator.h similarity index 76% rename from libopenage/tube/map_filter_iterator.h rename to libopenage/curve/map_filter_iterator.h index 0db9838435..cbb6cdadcd 100644 --- a/libopenage/tube/map_filter_iterator.h +++ b/libopenage/curve/map_filter_iterator.h @@ -5,11 +5,11 @@ #include #include -#include "tube.h" -#include "tube_iterator.h" +#include "curve.h" +#include "iterator.h" namespace openage { -namespace tube { +namespace curve { /** * A filtering operator to iterate over all elements of a map whose elements @@ -22,8 +22,8 @@ namespace tube { template -class TubeMapFilterIterator : - public TubeIterator +class MapFilterIterator : + public CurveIterator { public: typedef typename container_t::iterator iterator_t; @@ -31,11 +31,11 @@ class TubeMapFilterIterator : /** * Construct the iterator from its boundary conditions: time and container */ - TubeMapFilterIterator(const iterator_t &base, + MapFilterIterator(const iterator_t &base, const iterator_t &container_end, - const tube_time_t &from, - const tube_time_t &to) : - TubeIterator(base, container_end, from, to) {} + const curve_time_t &from, + const curve_time_t &to) : + CurveIterator(base, container_end, from, to) {} virtual bool valid() const override { return this->base->second.alive >= this->from && @@ -61,4 +61,4 @@ class TubeMapFilterIterator : }; -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/tube_objectlist.h b/libopenage/curve/queue.cpp similarity index 62% rename from libopenage/tube/tube_objectlist.h rename to libopenage/curve/queue.cpp index 2be20e6b2a..ead1a50d67 100644 --- a/libopenage/tube/tube_objectlist.h +++ b/libopenage/curve/queue.cpp @@ -1,8 +1,8 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -#pragma once +#include "queue.h" namespace openage { -namespace tube { +namespace curve { -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/tube_queue.h b/libopenage/curve/queue.h similarity index 58% rename from libopenage/tube/tube_queue.h rename to libopenage/curve/queue.h index aef458fa43..3ef197c1ef 100644 --- a/libopenage/tube/tube_queue.h +++ b/libopenage/curve/queue.h @@ -3,26 +3,26 @@ #pragma once -#include "tube.h" +#include "curve.h" #include "queue_filter_iterator.h" #include #include namespace openage { -namespace tube { +namespace curve { template class Queue { struct queue_wrapper { - tube_time_t _time; + curve_time_t _time; _T value; - queue_wrapper(const tube_time_t &time, const _T &value) : + queue_wrapper(const curve_time_t &time, const _T &value) : _time{time}, value{value} {} - tube_time_t time() { + curve_time_t time() { return _time; } }; @@ -30,41 +30,41 @@ class Queue { typedef typename std::deque container_t; typedef typename container_t::iterator iterator; // Reading Access - const _T &front(const tube_time_t &) const { + const _T &front(const curve_time_t &) const { return container.front(); } // Modifying access - TubeQueueFilterIterator<_T, Queue<_T>> begin( - const tube_time_t &t = -std::numeric_limits::infinity()) + QueueFilterIterator<_T, Queue<_T>> begin( + const curve_time_t &t = -std::numeric_limits::infinity()) { for (auto it = this->container.begin(); it != this->container.end(); ++it) { if (it->time() >= t) { - return TubeQueueFilterIterator<_T, Queue<_T>>( + return QueueFilterIterator<_T, Queue<_T>>( it, container.end(), t, - std::numeric_limits::infinity()); + std::numeric_limits::infinity()); } } return this->end(t); } - TubeQueueFilterIterator<_T, Queue<_T>> end( - const tube_time_t &t = std::numeric_limits::infinity()) + QueueFilterIterator<_T, Queue<_T>> end( + const curve_time_t &t = std::numeric_limits::infinity()) { - return TubeQueueFilterIterator<_T, Queue<_T>>(container.end(), + return QueueFilterIterator<_T, Queue<_T>>(container.end(), container.end(), t, - std::numeric_limits::infinity()); + std::numeric_limits::infinity()); } - TubeQueueFilterIterator<_T, Queue<_T>> between( - const tube_time_t &begin = std::numeric_limits::infinity(), - const tube_time_t &end = std::numeric_limits::infinity()) + QueueFilterIterator<_T, Queue<_T>> between( + const curve_time_t &begin = std::numeric_limits::infinity(), + const curve_time_t &end = std::numeric_limits::infinity()) { - auto it = TubeQueueFilterIterator<_T, Queue<_T>>( + auto it = QueueFilterIterator<_T, Queue<_T>>( container.begin(), container.end(), begin, @@ -75,9 +75,9 @@ class Queue { return it; } - TubeQueueFilterIterator<_T, Queue<_T>> erase(const TubeIterator<_T, Queue<_T>> &t) { + QueueFilterIterator<_T, Queue<_T>> erase(const CurveIterator<_T, Queue<_T>> &t) { auto it = container.erase(t.base); - auto ct = TubeQueueFilterIterator<_T, Queue<_T>>( + auto ct = QueueFilterIterator<_T, Queue<_T>>( it, container.end(), t.from, @@ -89,7 +89,7 @@ class Queue { return ct; } - TubeQueueFilterIterator<_T, Queue<_T>> insert(const tube_time_t & time, const _T &e) { + QueueFilterIterator<_T, Queue<_T>> insert(const curve_time_t & time, const _T &e) { iterator insertion_point = this->container.end(); for (auto it = this->container.begin(); it != this->container.end(); ++it) { if (time < it->time()) { @@ -103,10 +103,10 @@ class Queue { queue_wrapper(time, e)); } - auto ct = TubeQueueFilterIterator<_T, Queue<_T>>( + auto ct = QueueFilterIterator<_T, Queue<_T>>( insertion_point, container.end(), - time, std::numeric_limits::infinity()); + time, std::numeric_limits::infinity()); if (!ct.valid()) { ++ct; @@ -124,4 +124,4 @@ class Queue { container_t container; }; -}} // openage::tube +}} // openage::curve diff --git a/libopenage/tube/queue_filter_iterator.h b/libopenage/curve/queue_filter_iterator.h similarity index 72% rename from libopenage/tube/queue_filter_iterator.h rename to libopenage/curve/queue_filter_iterator.h index 7d137d8254..0313a95a9d 100644 --- a/libopenage/tube/queue_filter_iterator.h +++ b/libopenage/curve/queue_filter_iterator.h @@ -5,11 +5,11 @@ #include #include -#include "tube.h" -#include "tube_iterator.h" +#include "curve.h" +#include "iterator.h" namespace openage { -namespace tube { +namespace curve { /** * A filtering operator to iterate over all elements of a queue whose elements @@ -21,8 +21,8 @@ namespace tube { */ template -class TubeQueueFilterIterator : - public TubeIterator +class QueueFilterIterator : + public CurveIterator { public: typedef typename container_t::iterator iterator_t; @@ -30,11 +30,11 @@ class TubeQueueFilterIterator : /** * Construct the iterator from its boundary conditions: time and container */ - TubeQueueFilterIterator(const iterator_t &base, + QueueFilterIterator(const iterator_t &base, const iterator_t &container_end, - const tube_time_t &from, - const tube_time_t &to) : - TubeIterator{base, container_end, from, to} {} + const curve_time_t &from, + const curve_time_t &to) : + CurveIterator{base, container_end, from, to} {} virtual bool valid() const override { if (this->base != this->container_end) { @@ -48,4 +48,4 @@ class TubeQueueFilterIterator : } }; -}} // openage::tube +}} // openage::curve diff --git a/libopenage/curve/test/CMakeLists.txt b/libopenage/curve/test/CMakeLists.txt new file mode 100644 index 0000000000..2902fec2b7 --- /dev/null +++ b/libopenage/curve/test/CMakeLists.txt @@ -0,0 +1,7 @@ +link_libraries(tube) + +add_sources(libopenage + test_container.cpp + test_curve_types.cpp + test_serialization.cpp +) diff --git a/libopenage/tube/test/test_container.cpp b/libopenage/curve/test/test_container.cpp similarity index 95% rename from libopenage/tube/test/test_container.cpp rename to libopenage/curve/test/test_container.cpp index 9b2df07b45..2f954766bd 100644 --- a/libopenage/tube/test/test_container.cpp +++ b/libopenage/curve/test/test_container.cpp @@ -1,17 +1,17 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "../../testing/testing.h" -#include "../tube.h" -#include "../tube_continuous.h" -#include "../tube_discrete.h" -#include "../tube_queue.h" -#include "../tube_map.h" +#include "../curve.h" +#include "../continuous.h" +#include "../discrete.h" +#include "../queue.h" +#include "../map.h" #include #include namespace openage { -namespace tube { +namespace curve { namespace tests { struct map_test_element { @@ -199,4 +199,4 @@ void container() { } -}}} // openage::tube::tests +}}} // openage::curve::tests diff --git a/libopenage/tube/test/test_tube_types.cpp b/libopenage/curve/test/test_curve_types.cpp similarity index 93% rename from libopenage/tube/test/test_tube_types.cpp rename to libopenage/curve/test/test_curve_types.cpp index 7b0c2acbb9..989dee9ceb 100644 --- a/libopenage/tube/test/test_tube_types.cpp +++ b/libopenage/curve/test/test_curve_types.cpp @@ -1,17 +1,17 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "../../testing/testing.h" -#include "../keyframe_container.h" -#include "../tube.h" -#include "../tube_continuous.h" -#include "../tube_discrete.h" +#include "../internal/keyframe_container.h" +#include "../curve.h" +#include "../continuous.h" +#include "../discrete.h" namespace openage { -namespace tube { +namespace curve { namespace tests { -void tube_types() { +void curve_types() { // Check the base container type { KeyframeContainer c; @@ -121,4 +121,4 @@ void tube_types() { } } -}}} // openage::tube::tests +}}} // openage::curve::tests diff --git a/libopenage/tube/test/test_serialization.cpp b/libopenage/curve/test/test_serialization.cpp similarity index 79% rename from libopenage/tube/test/test_serialization.cpp rename to libopenage/curve/test/test_serialization.cpp index af8dd046c7..f446cb1f7f 100644 --- a/libopenage/tube/test/test_serialization.cpp +++ b/libopenage/curve/test/test_serialization.cpp @@ -3,11 +3,11 @@ #include "../../testing/testing.h" namespace openage { -namespace tube { +namespace curve { namespace tests { void serialization() { } -}}} // openage::tube::tests +}}} // openage::curve::tests diff --git a/libopenage/tube/.gitignore b/libopenage/tube/.gitignore deleted file mode 100644 index 5ae0e4943c..0000000000 --- a/libopenage/tube/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -*build* diff --git a/libopenage/tube/CMakeLists.txt b/libopenage/tube/CMakeLists.txt deleted file mode 100644 index 50e8800e91..0000000000 --- a/libopenage/tube/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ - -add_sources(libopenage - keyframe_container.cpp - tube_event.cpp - tube_queue.cpp - tube_object.cpp - tube_objectlist.cpp - tube_continuous.cpp - tube_discrete.cpp - tube.cpp - value_container.cpp -) - -add_subdirectory(test) -add_subdirectory(demo) diff --git a/libopenage/tube/test/CMakeLists.txt b/libopenage/tube/test/CMakeLists.txt deleted file mode 100644 index 6e340d6393..0000000000 --- a/libopenage/tube/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -link_libraries(tube) - -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") - -add_sources(libopenage - test_container.cpp - test_tube_types.cpp - test_serialization.cpp -) diff --git a/libopenage/tube/tube.cpp b/libopenage/tube/tube.cpp deleted file mode 100644 index 4462daac9c..0000000000 --- a/libopenage/tube/tube.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "tube.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tube/tube_continuous.cpp b/libopenage/tube/tube_continuous.cpp deleted file mode 100644 index d61b30475a..0000000000 --- a/libopenage/tube/tube_continuous.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "tube_continuous.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tube/tube_discrete.cpp b/libopenage/tube/tube_discrete.cpp deleted file mode 100644 index 20cb14dadc..0000000000 --- a/libopenage/tube/tube_discrete.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "tube_discrete.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tube/tube_map.h b/libopenage/tube/tube_map.h deleted file mode 100644 index 52922967c0..0000000000 --- a/libopenage/tube/tube_map.h +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "tube.h" -#include "map_filter_iterator.h" - -namespace openage { -namespace tube { - -template -class UnorderedMap { - struct map_element { - val_t value; - tube_time_t alive; - tube_time_t dead; - map_element (val_t v, const tube_time_t &a, const tube_time_t &d) - : value(v), - alive(a), - dead(d) {} - }; - std::unordered_map container; - -public: - // Using does not work with templates - typedef typename std::unordered_map::iterator iterator; - -// TODO return an std::optional here. - std::pair> - operator()(const tube_time_t&, const key_t &); - -// TODO return an std::optional here. - std::pair> - at(const tube_time_t &, const key_t &); - - TubeMapFilterIterator - begin(const tube_time_t &e = std::numeric_limits::infinity()); - - TubeMapFilterIterator - end(const tube_time_t &e = std::numeric_limits::infinity()); - - - TubeMapFilterIterator - insert(const tube_time_t &birth, const key_t &, const val_t &); - - TubeMapFilterIterator - insert(const tube_time_t &birth, const tube_time_t &death, const key_t &key, const val_t &value); - - TubeMapFilterIterator - between(const tube_time_t &start, const tube_time_t &to); - - void birth(const tube_time_t &, const key_t &); - void birth(const tube_time_t &, - const TubeMapFilterIterator &); - - void kill(const tube_time_t &, const key_t &); - void kill(const tube_time_t &, - const TubeMapFilterIterator &); - - // remove all dead elements before that point in time - void clean(const tube_time_t &); - - void __attribute__((noinline)) dump() { - for (auto i : container) { - std::cout << "Element: " << i.second.value << std::endl;; - } - } -}; - -template -std::pair>> -UnorderedMap::operator()(const tube_time_t &time, - const key_t &key) { - return this->at(time, key); -} - -template -std::pair>> -UnorderedMap::at(const tube_time_t & time, - const key_t & key) { - auto e = this->container.find(key); - if (e != this->container.end() && e->second.alive <= time && e->second.dead >time) { - return std::make_pair( - true, - TubeMapFilterIterator>( - e, - this->container.end(), - time, - std::numeric_limits::infinity())); - } else { - return std::make_pair( - false, - this->end(time)); - } -} - -template -TubeMapFilterIterator> -UnorderedMap::begin(const tube_time_t &time) { - return TubeMapFilterIterator>( - this->container.begin(), - this->container.end(), - time, - std::numeric_limits::infinity()); -} - -template -TubeMapFilterIterator> -UnorderedMap::end(const tube_time_t &time) { - return TubeMapFilterIterator>( - this->container.end(), - this->container.end(), - -std::numeric_limits::infinity(), - time); -} - -template -TubeMapFilterIterator> -UnorderedMap::between(const tube_time_t &from, const tube_time_t &to) { - auto it = TubeMapFilterIterator>( - this->container.begin(), - this->container.end(), - from, - to); - - if (!it.valid()) { - ++it; - } - return it; -} - -template -TubeMapFilterIterator> -UnorderedMap::insert(const tube_time_t &alive, - const key_t &key, - const val_t &value) { - return this->insert( - alive, - std::numeric_limits::infinity(), - key, - value); -} - -template -TubeMapFilterIterator> -UnorderedMap::insert(const tube_time_t &alive, - const tube_time_t &dead, - const key_t &key, - const val_t &value) { - map_element e(value, alive, dead); - auto it = this->container.insert(std::make_pair(key, e)); - return TubeMapFilterIterator>( - it.first, - this->container.end(), - alive, - dead); -} - -template -void UnorderedMap::birth(const tube_time_t &time, - const key_t &key) { - auto it = this->container.find(key); - if (it != this->container.end()) { - it->second.alive = time; - } -} - -template -void UnorderedMap::birth(const tube_time_t &time, - const TubeMapFilterIterator &it) { - it->second.alive = time; -} - -template -void UnorderedMap::kill(const tube_time_t &time, - const key_t &key) { - auto it = this->container.find(key); - if (it != this->container.end()) { - it->second.dead = time; - } -} - -template -void UnorderedMap::kill(const tube_time_t &time, - const TubeMapFilterIterator &it) { - it->second.dead = time; -} - -template -void UnorderedMap::clean(const tube_time_t &) { - // TODO save everything to a file and be happy. -} - -}} // openage::tube diff --git a/libopenage/tube/tube_object.h b/libopenage/tube/tube_object.h deleted file mode 100644 index 40f5566a72..0000000000 --- a/libopenage/tube/tube_object.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "tube.h" - -namespace openage { -namespace tube { - -class TubeObject { -public: -}; - -}} // openage::tube diff --git a/libopenage/tube/tube_objectlist.cpp b/libopenage/tube/tube_objectlist.cpp deleted file mode 100644 index b7d52005a9..0000000000 --- a/libopenage/tube/tube_objectlist.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "tube_objectlist.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/libopenage/tube/tube_queue.cpp b/libopenage/tube/tube_queue.cpp deleted file mode 100644 index 80285e5c2f..0000000000 --- a/libopenage/tube/tube_queue.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "tube_queue.h" - -namespace openage { -namespace tube { - -}} // openage::tube diff --git a/openage/testing/testlist.py b/openage/testing/testlist.py index 0e8cb22734..ba2bc34eb8 100644 --- a/openage/testing/testlist.py +++ b/openage/testing/testlist.py @@ -79,9 +79,9 @@ def tests_cpp(): yield "openage::renderer::tests::font" yield "openage::renderer::tests::font_manager" yield "openage::rng::tests::run" - yield "openage::tube::tests::container" - yield "openage::tube::tests::serialization" - yield "openage::tube::tests::tube_types" + yield "openage::curve::tests::container" + yield "openage::curve::tests::serialization" + yield "openage::curve::tests::curve_types" yield "openage::util::tests::array_conversion" yield "openage::util::tests::constinit_vector" yield "openage::util::tests::enum_" @@ -109,7 +109,7 @@ def demos_cpp(): "translates a Python exception to C++") yield ("openage::pyinterface::tests::pyobject_demo", "a tiny interactive interpreter using PyObjectRef") - yield ("openage::tubepong::demo", + yield ("openage::curvepong::demo", "a pong game implemented in curves") From 6fe426b7eb22d7f9ffbf6efdd3a31e8b16ad9a7e Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Tue, 13 Jun 2017 17:18:28 +0200 Subject: [PATCH 18/24] added event list --- libopenage/curve/CMakeLists.txt | 8 +- libopenage/curve/datatypes.md | 67 ++++++++- libopenage/curve/events.cpp | 58 ++++++++ libopenage/curve/events.h | 45 ++++++ libopenage/curve/queue.h | 176 +++++++++++++---------- libopenage/curve/queue_filter_iterator.h | 6 +- libopenage/curve/test/CMakeLists.txt | 1 + libopenage/curve/test/test_events.cpp | 108 ++++++++++++++ openage/testing/testlist.py | 7 +- 9 files changed, 394 insertions(+), 82 deletions(-) create mode 100644 libopenage/curve/events.cpp create mode 100644 libopenage/curve/events.h create mode 100644 libopenage/curve/test/test_events.cpp diff --git a/libopenage/curve/CMakeLists.txt b/libopenage/curve/CMakeLists.txt index f03dc732cc..540edc29bd 100644 --- a/libopenage/curve/CMakeLists.txt +++ b/libopenage/curve/CMakeLists.txt @@ -5,7 +5,13 @@ add_sources(libopenage queue.cpp continuous.cpp discrete.cpp - curve.cpp + events.cpp + iterator.cpp + map.cpp + map_filter_iterator.cpp + queue.cpp + queue.cpp + queue_filter_iterator.cpp ) add_subdirectory(test) diff --git a/libopenage/curve/datatypes.md b/libopenage/curve/datatypes.md index feade3a0d4..765ce74ff8 100644 --- a/libopenage/curve/datatypes.md +++ b/libopenage/curve/datatypes.md @@ -53,5 +53,68 @@ The queue container represents a random access queue while keeping the ordering It is usually used for pushing in the back and popping at the front (FIFO-Stlye) but offers random access insertion and deletion as well. This container is useful for example for action queues and buildung queues. -TUBE FILES -============ +TUBE SERIALIZATION +================== + +Serialization condenses data into change sets: + +Repeat the following blob: ++-----------------------------------------------------------+ +| ID (24Bit) | +| flags (delete, del_after, time, time2, data, add) (8Bit) | # In the first quadruple it is stored which data fields are set. +| if (flag & time) time1 | # In the second quadruple the usage of the data is stored +| if (flag & time2) time2 | # | time | time2 | data | UNUSED | delete | add | del_after | UNUSED | +| if (flag & data) keyframe: size(16) | data | ++-----------------------------------------------------------+ + +Meaning of Flags +---------------- + +== DELETE == + +After DELETE it is allowed to reuse the ID +When no Time is defined, then the deletion is "now", if TIME1 is defined, then the element will be deleted at this time. + +== ADD == + +Create a new element with the given ID. Add has to have at least TIME1 and DATA set. + +== DEL_AFTER == + +Delete all keyframes after TIME. + +== TIME1 == + +Set the Keyframe time or the creation time of an element + +== TIME2 == + +Set the Destruction time of a container element + +== DATA == + +The Keyframe data prefixed by data length + + + +Serialization of keyframes for different data types +---------------------------------------------------- + +Simple types: Binary Serialization of the data types, interpolation mode does not matter + +Containers +For Containers DELETE_AFTER is not supported. + +== Map == + +Store TIME2 as death time - if the element has a death time yet. +The ID of the object is submitted at creation as its own curve. + +== Set == + +This container is simple to store only times (birth (TIME1) and death (TIME2) of each unit) and only update the keyframe data when neccesary + +== Queue == + +Elements here have only one single time, so TIME2 is not used. +They can be created with ADD and removed with DELETE. diff --git a/libopenage/curve/events.cpp b/libopenage/curve/events.cpp new file mode 100644 index 0000000000..342cf9da0d --- /dev/null +++ b/libopenage/curve/events.cpp @@ -0,0 +1,58 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "events.h" + +namespace openage { +namespace curve { + +void EventQueue::addcallback (const curve_time_t &at, + const EventQueue::condition &precond, + const EventQueue::callback &trigger) { + Event e; + e.event = trigger; + e.precond = precond; + e.time = at; + + addcallback(e); +} + +void EventQueue::addcallback (const curve_time_t &at, + const EventQueue::condition_void &precond, + const EventQueue::callback_void &trigger) { + Event e; + e.event = [trigger](const curve_time_t &) { trigger(); }; + e.precond = [precond](const curve_time_t &) { return precond(); }; + e.time = at; + + addcallback(e); +} + +void EventQueue::addcallback (const curve_time_t &at, + const EventQueue::callback &trigger) { + this->addcallback(at, &EventQueue::_true, trigger); +} + +void EventQueue::addcallback (const curve_time_t &at, + const EventQueue::callback_void &trigger) { + this->addcallback(at, &EventQueue::_true, [trigger](const curve_time_t &) { + trigger(); + }); +} + +void EventQueue::addcallback (const EventQueue::Event &e) { + queue.insert(e.time, e); +} + +void EventQueue::trigger(const curve_time_t &from, const curve_time_t &to) { + for (auto it = queue.between(from, to); it != queue.end(); ++it) { + if (it.value().precond(it.value().time)) { + it.value().event(it.value().time); + } + } +} + +bool EventQueue::_true(const curve_time_t &) { + return true; +} + +}} // namespace openage::curve diff --git a/libopenage/curve/events.h b/libopenage/curve/events.h new file mode 100644 index 0000000000..d4aa21007b --- /dev/null +++ b/libopenage/curve/events.h @@ -0,0 +1,45 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "curve.h" +#include "queue.h" + +#include + +namespace openage { +namespace curve { + +class EventQueue { + +public: + typedef std::function callback; + typedef std::function condition; + + typedef std::function callback_void; + typedef std::function condition_void; + + class Event { + public: + callback event; + condition precond; + curve_time_t time; + }; + + void addcallback (const curve_time_t &at, const condition &, const callback &); + void addcallback (const curve_time_t &at, const condition_void &, const callback_void &); + + void addcallback (const curve_time_t &at, const callback &); + void addcallback (const curve_time_t &at, const callback_void &); + + void addcallback (const Event &); + + void trigger(const curve_time_t &from, const curve_time_t &to); + +private: + Queue queue; + + static bool _true(const curve_time_t &); +}; + +}} // namespace openage::curve diff --git a/libopenage/curve/queue.h b/libopenage/curve/queue.h index 3ef197c1ef..cbc3176f0c 100644 --- a/libopenage/curve/queue.h +++ b/libopenage/curve/queue.h @@ -2,7 +2,6 @@ #pragma once - #include "curve.h" #include "queue_filter_iterator.h" @@ -30,98 +29,129 @@ class Queue { typedef typename std::deque container_t; typedef typename container_t::iterator iterator; // Reading Access - const _T &front(const curve_time_t &) const { - return container.front(); - } + const _T &front(const curve_time_t &) const; // Modifying access QueueFilterIterator<_T, Queue<_T>> begin( - const curve_time_t &t = -std::numeric_limits::infinity()) - { - for (auto it = this->container.begin(); it != this->container.end(); ++it) { - if (it->time() >= t) { - return QueueFilterIterator<_T, Queue<_T>>( - it, - container.end(), - t, - std::numeric_limits::infinity()); - } - } - - return this->end(t); - } + const curve_time_t &t = -std::numeric_limits::infinity()); QueueFilterIterator<_T, Queue<_T>> end( - const curve_time_t &t = std::numeric_limits::infinity()) - { - return QueueFilterIterator<_T, Queue<_T>>(container.end(), - container.end(), - t, - std::numeric_limits::infinity()); - } + const curve_time_t &t = std::numeric_limits::infinity()); QueueFilterIterator<_T, Queue<_T>> between( const curve_time_t &begin = std::numeric_limits::infinity(), - const curve_time_t &end = std::numeric_limits::infinity()) - { - auto it = QueueFilterIterator<_T, Queue<_T>>( - container.begin(), - container.end(), - begin, - end); - if (!it.valid()) { - ++it; - } - return it; - } + const curve_time_t &end = std::numeric_limits::infinity()); - QueueFilterIterator<_T, Queue<_T>> erase(const CurveIterator<_T, Queue<_T>> &t) { - auto it = container.erase(t.base); - auto ct = QueueFilterIterator<_T, Queue<_T>>( - it, - container.end(), - t.from, - t.to); + QueueFilterIterator<_T, Queue<_T>> erase( + const CurveIterator<_T, Queue<_T>> &); - if (!ct.valid(t.from)) { - ++ct; + QueueFilterIterator<_T, Queue<_T>> insert( + const curve_time_t &, const _T &e); + + void __attribute__((noinline)) dump() { + for (auto i : container) { + std::cout << i.value << " at " << i.time() << std::endl; } - return ct; } - QueueFilterIterator<_T, Queue<_T>> insert(const curve_time_t & time, const _T &e) { - iterator insertion_point = this->container.end(); - for (auto it = this->container.begin(); it != this->container.end(); ++it) { - if (time < it->time()) { - insertion_point = this->container - .insert(it, queue_wrapper(time, e)); - break; - } - } - if (insertion_point == this->container.end()) { - insertion_point = this->container.insert(this->container.end(), - queue_wrapper(time, e)); - } +private: + container_t container; +}; + + +template +const _T &Queue<_T>::front(const curve_time_t &) const { + return container.front(); +} - auto ct = QueueFilterIterator<_T, Queue<_T>>( - insertion_point, - container.end(), - time, std::numeric_limits::infinity()); - if (!ct.valid()) { - ++ct; +template +QueueFilterIterator<_T, Queue<_T>> Queue<_T>::begin(const curve_time_t &t) +{ + for (auto it = this->container.begin(); it != this->container.end(); ++it) { + if (it->time() >= t) { + return QueueFilterIterator<_T, Queue<_T>>( + it, + container.end(), + t, + std::numeric_limits::infinity()); } - return ct; } - void __attribute__((noinline)) dump() { - for (auto i : container) { - std::cout << i.value << " at " << i.time() << std::endl; + return this->end(t); +} + + +template +QueueFilterIterator<_T, Queue<_T>> Queue<_T>::end(const curve_time_t &t) +{ + return QueueFilterIterator<_T, Queue<_T>>(container.end(), + container.end(), + t, + std::numeric_limits::infinity()); +} + + +template +QueueFilterIterator<_T, Queue<_T>> Queue<_T>::between( + const curve_time_t &begin, + const curve_time_t &end) +{ + auto it = QueueFilterIterator<_T, Queue<_T>>( + container.begin(), + container.end(), + begin, + end); + if (!it.valid()) { + ++it; + } + return it; +} + + +template +QueueFilterIterator<_T, Queue<_T>> Queue<_T>::erase(const CurveIterator<_T, Queue<_T>> &t) +{ + auto it = container.erase(t.base); + auto ct = QueueFilterIterator<_T, Queue<_T>>( + it, + container.end(), + t.from, + t.to); + + if (!ct.valid(t.from)) { + ++ct; + } + return ct; +} + + +template +QueueFilterIterator<_T, Queue<_T>> Queue<_T>::insert( + const curve_time_t &time, + const _T &e) { + iterator insertion_point = this->container.end(); + for (auto it = this->container.begin(); it != this->container.end(); ++it) { + if (time < it->time()) { + insertion_point = this->container + .insert(it, queue_wrapper(time, e)); + break; } } + if (insertion_point == this->container.end()) { + insertion_point = this->container.insert(this->container.end(), + queue_wrapper(time, e)); + } -private: - container_t container; -}; + auto ct = QueueFilterIterator<_T, Queue<_T>>( + insertion_point, + container.end(), + time, std::numeric_limits::infinity()); + + if (!ct.valid()) { + ++ct; + } + return ct; +} }} // openage::curve diff --git a/libopenage/curve/queue_filter_iterator.h b/libopenage/curve/queue_filter_iterator.h index 0313a95a9d..7e743ac976 100644 --- a/libopenage/curve/queue_filter_iterator.h +++ b/libopenage/curve/queue_filter_iterator.h @@ -31,9 +31,9 @@ class QueueFilterIterator : * Construct the iterator from its boundary conditions: time and container */ QueueFilterIterator(const iterator_t &base, - const iterator_t &container_end, - const curve_time_t &from, - const curve_time_t &to) : + const iterator_t &container_end, + const curve_time_t &from, + const curve_time_t &to) : CurveIterator{base, container_end, from, to} {} virtual bool valid() const override { diff --git a/libopenage/curve/test/CMakeLists.txt b/libopenage/curve/test/CMakeLists.txt index 2902fec2b7..b8e6d6a6a3 100644 --- a/libopenage/curve/test/CMakeLists.txt +++ b/libopenage/curve/test/CMakeLists.txt @@ -4,4 +4,5 @@ add_sources(libopenage test_container.cpp test_curve_types.cpp test_serialization.cpp + test_events.cpp ) diff --git a/libopenage/curve/test/test_events.cpp b/libopenage/curve/test/test_events.cpp new file mode 100644 index 0000000000..b988bd434b --- /dev/null +++ b/libopenage/curve/test/test_events.cpp @@ -0,0 +1,108 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "../../testing/testing.h" +#include "../curve.h" +#include "../events.h" + +namespace openage { +namespace curve { +namespace tests { + +static void print_vector(const std::vector> &t) { + for (const auto &a : t) { + std::cout << a.first << ":" << a.second << std::endl; + } +} + +void events () { + EventQueue q; + + std::vector> calls; + print_vector(calls); + + q.addcallback(1, [&calls](const curve_time_t &t) { + calls.push_back(std::make_pair(t, 1)); + }); + + q.addcallback(2, [&calls](const curve_time_t &t) { + calls.push_back(std::make_pair(t, 2)); + }); + + q.trigger(0, 2); + TESTEQUALS(calls.size(), 1); + TESTEQUALS(calls[0].first, 1); + TESTEQUALS(calls[0].second, 1); + + calls.clear(); + q.trigger(0, 3); + TESTEQUALS(calls.size(), 2); + TESTEQUALS(calls[0].first, 1); + TESTEQUALS(calls[0].second, 1); + TESTEQUALS(calls[1].first, 2); + TESTEQUALS(calls[1].second, 2); + + calls.clear(); + q.trigger(2, 3); + TESTEQUALS(calls.size(), 1); + TESTEQUALS(calls[0].first, 2); + TESTEQUALS(calls[0].second, 2); + + int cond1 = 1; + q.addcallback(4, [&calls, cond1](const curve_time_t &) { + return cond1 == 1; + }, + [&calls](const curve_time_t &t) { + calls.push_back(std::make_pair(t, 4)); + }); + + cond1 = 1; + calls.clear(); + q.trigger(4, 5); + TESTEQUALS(calls.size(), 1); + TESTEQUALS(calls[0].first, 4); + TESTEQUALS(calls[0].second, 4); + + cond1 = 0; + calls.clear(); + TESTEQUALS(calls.size(), 0); + + int cond2 = 1; + q.addcallback(5, [&cond2](const curve_time_t &) { + return cond2 == 1; + }, + [&calls](const curve_time_t &t) { + calls.push_back(std::make_pair(t, 5)); + }); + + q.addcallback(6, [&cond2](const curve_time_t &) { + return cond2 == 1 || cond2 == 2; + }, + [&calls, &cond2] (const curve_time_t &t) { + calls.push_back(std::make_pair(t, 6)); + cond2 ++; + }); + + cond2 = 1; + calls.clear(); + q.trigger(5, 7); + TESTEQUALS(calls.size(), 2); + TESTEQUALS(calls[0].first, 5); + TESTEQUALS(calls[0].second, 5); + TESTEQUALS(calls[1].first, 6); + TESTEQUALS(calls[1].second, 6); + TESTEQUALS(cond2, 2); + + calls.clear(); + q.trigger(5, 7); + TESTEQUALS(calls.size(), 1); + TESTEQUALS(calls[0].first, 6); + TESTEQUALS(calls[0].second, 6); + TESTEQUALS(cond2, 3); + + calls.clear(); + q.trigger(5, 7); + TESTEQUALS(calls.size(), 0); + TESTEQUALS(cond2, 3); +} + +}}} // namespace::curve::tests diff --git a/openage/testing/testlist.py b/openage/testing/testlist.py index ba2bc34eb8..af032a335e 100644 --- a/openage/testing/testlist.py +++ b/openage/testing/testlist.py @@ -68,6 +68,10 @@ def tests_cpp(): """ yield "openage::coord::tests::coord" + yield "openage::curve::tests::container" + yield "openage::curve::tests::curve_types" + yield "openage::curve::tests::events" + yield "openage::curve::tests::serialization" yield "openage::datastructure::tests::constexpr_map" yield "openage::datastructure::tests::pairing_heap" yield "openage::input::tests::parse_event_string", "keybinds parsing" @@ -79,9 +83,6 @@ def tests_cpp(): yield "openage::renderer::tests::font" yield "openage::renderer::tests::font_manager" yield "openage::rng::tests::run" - yield "openage::curve::tests::container" - yield "openage::curve::tests::serialization" - yield "openage::curve::tests::curve_types" yield "openage::util::tests::array_conversion" yield "openage::util::tests::constinit_vector" yield "openage::util::tests::enum_" From 7422c6306fac8328dca9cf2a6bfbb2334b551798 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sat, 24 Jun 2017 17:55:38 +0200 Subject: [PATCH 19/24] curve: getting the demo up and fancy --- libopenage/curve/CMakeLists.txt | 1 + libopenage/curve/continuous.h | 2 +- libopenage/curve/curve.h | 2 +- libopenage/curve/demo_event/CMakeLists.txt | 7 + libopenage/curve/demo_event/aicontroller.cpp | 30 +++ libopenage/curve/demo_event/aicontroller.h | 23 ++ libopenage/curve/demo_event/gamestate.cpp | 3 + libopenage/curve/demo_event/gamestate.h | 58 +++++ libopenage/curve/demo_event/gui.cpp | 163 ++++++++++++++ libopenage/curve/demo_event/gui.h | 25 +++ libopenage/curve/demo_event/main.cpp | 97 ++++++++ libopenage/curve/demo_event/physics.cpp | 208 ++++++++++++++++++ libopenage/curve/demo_event/physics.h | 29 +++ libopenage/curve/events.cpp | 152 ++++++++++--- libopenage/curve/events.h | 65 +++++- .../curve/internal/keyframe_container.h | 2 +- libopenage/curve/internal/value_container.h | 17 +- libopenage/curve/iterator.h | 78 ++++--- libopenage/curve/map.h | 37 ++-- libopenage/curve/map_filter_iterator.h | 28 +-- libopenage/curve/queue.h | 80 ++++--- libopenage/curve/queue_filter_iterator.h | 19 +- libopenage/curve/test/test_container.cpp | 12 + libopenage/curve/test/test_curve_types.cpp | 24 +- libopenage/curve/test/test_events.cpp | 75 ++++--- 25 files changed, 1054 insertions(+), 183 deletions(-) create mode 100644 libopenage/curve/demo_event/CMakeLists.txt create mode 100644 libopenage/curve/demo_event/aicontroller.cpp create mode 100644 libopenage/curve/demo_event/aicontroller.h create mode 100644 libopenage/curve/demo_event/gamestate.cpp create mode 100644 libopenage/curve/demo_event/gamestate.h create mode 100644 libopenage/curve/demo_event/gui.cpp create mode 100644 libopenage/curve/demo_event/gui.h create mode 100644 libopenage/curve/demo_event/main.cpp create mode 100644 libopenage/curve/demo_event/physics.cpp create mode 100644 libopenage/curve/demo_event/physics.h diff --git a/libopenage/curve/CMakeLists.txt b/libopenage/curve/CMakeLists.txt index 540edc29bd..ae4c67b179 100644 --- a/libopenage/curve/CMakeLists.txt +++ b/libopenage/curve/CMakeLists.txt @@ -14,5 +14,6 @@ add_sources(libopenage queue_filter_iterator.cpp ) +add_subdirectory(internal) add_subdirectory(test) add_subdirectory(demo) diff --git a/libopenage/curve/continuous.h b/libopenage/curve/continuous.h index 1c55b503bb..4865d085d2 100644 --- a/libopenage/curve/continuous.h +++ b/libopenage/curve/continuous.h @@ -26,7 +26,7 @@ _T Continuous<_T>::get(const curve_time_t &time) const { double offset = time - e->time; // If we do not have a next (buffer underrun!!) we assign values if (nxt == this->container.end()) { - log::log(WARN << "Continuous buffer underrun. This might be bad! Assuming constant."); +// log::log(WARN << "Continuous buffer underrun. This might be bad! Assuming constant."); } else { diff_time = nxt->time - e->time; } diff --git a/libopenage/curve/curve.h b/libopenage/curve/curve.h index b8bcca666b..b487029e30 100644 --- a/libopenage/curve/curve.h +++ b/libopenage/curve/curve.h @@ -5,7 +5,7 @@ namespace openage { namespace curve { -typedef float curve_time_t; +typedef double curve_time_t; /* template curve_time_t time(const _T &t) { diff --git a/libopenage/curve/demo_event/CMakeLists.txt b/libopenage/curve/demo_event/CMakeLists.txt new file mode 100644 index 0000000000..c1545e58c1 --- /dev/null +++ b/libopenage/curve/demo_event/CMakeLists.txt @@ -0,0 +1,7 @@ +add_sources (libopenage + aicontroller.cpp + gamestate.cpp + gui.cpp + main.cpp + physics.cpp +) diff --git a/libopenage/curve/demo_event/aicontroller.cpp b/libopenage/curve/demo_event/aicontroller.cpp new file mode 100644 index 0000000000..47ef8c0092 --- /dev/null +++ b/libopenage/curve/demo_event/aicontroller.cpp @@ -0,0 +1,30 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#include "aicontroller.h" + +namespace openage { +namespace curvepong { + +std::vector &AIInput::getInputs( + const PongPlayer &player, + const PongBall &ball, + const curve::curve_time_t &now) { + this->event_cache.clear(); + + auto position = player.position.get(now); + + // Yes i know, there is /3 used - instead of the logical /2 - this is to + // create a small safety boundary of 1/3 for enhanced fancyness + + // Ball is below position + if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { + event_cache.push_back(event(player.id, event::DOWN)); + } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { + // Ball is above position + event_cache.push_back(event(player.id, event::UP)); + } + + return this->event_cache; +} + +}} // openage::curvepong diff --git a/libopenage/curve/demo_event/aicontroller.h b/libopenage/curve/demo_event/aicontroller.h new file mode 100644 index 0000000000..d87c455be1 --- /dev/null +++ b/libopenage/curve/demo_event/aicontroller.h @@ -0,0 +1,23 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "gamestate.h" + +namespace openage { +namespace curvepong { + +class AIInput { +public: + std::vector &getInputs( + const PongPlayer &player, + const PongBall &ball, + const curve::curve_time_t &now); + +private: + std::vector event_cache; +}; + +}} // openage::curvepong diff --git a/libopenage/curve/demo_event/gamestate.cpp b/libopenage/curve/demo_event/gamestate.cpp new file mode 100644 index 0000000000..24df67232e --- /dev/null +++ b/libopenage/curve/demo_event/gamestate.cpp @@ -0,0 +1,3 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "gamestate.h" diff --git a/libopenage/curve/demo_event/gamestate.h b/libopenage/curve/demo_event/gamestate.h new file mode 100644 index 0000000000..ce2c4a742c --- /dev/null +++ b/libopenage/curve/demo_event/gamestate.h @@ -0,0 +1,58 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "../continuous.h" +#include "../discrete.h" +#include "../../util/vector.h" + +namespace openage { +namespace curvepong { + +struct event { + int player; + enum state_e { + UP, DOWN, START, IDLE, LOST + } state; + event(int id, state_e s) : player(id), state(s) {} + event() : player(0), state(IDLE) {} +}; + +class PongPlayer { +public: + PongPlayer() { + speed.set_drop(0, 1); + position.set_drop(0, 0.5); + lives.set_drop(0, 1); + state.set_drop(0, event(0, event::IDLE)); + size.set_drop(0, 0.1); + y = 0; + id = 0; + } + + curve::Discrete speed; + curve::Continuous position; + curve::Discrete lives; + curve::Discrete state; + curve::Discrete size; + float y; + int id; +}; + +class PongBall { +public: + curve::Discrete> speed; + curve::Continuous> position; +}; + +class PongState { +public: + PongPlayer p1; + PongPlayer p2; + + PongBall ball; + + util::Vector<2> resolution; +}; + +}} // openage::curvepong diff --git a/libopenage/curve/demo_event/gui.cpp b/libopenage/curve/demo_event/gui.cpp new file mode 100644 index 0000000000..f55efab316 --- /dev/null +++ b/libopenage/curve/demo_event/gui.cpp @@ -0,0 +1,163 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#include "gui.h" + +#include +#include + +namespace openage { +namespace curvepong { + +std::vector &Gui::getInputs(const PongPlayer &player) { + input_cache.clear(); + event evnt; + evnt.player = player.id; + evnt.state = event::IDLE; + timeout(0); + int c = getch(); + // mvprintw(0,1, "IN: %i", c); + switch (c) { + case KEY_DOWN: + evnt.state = event::DOWN; + input_cache.push_back(evnt); + mvprintw(1, 1, "DOWN"); + break; + case KEY_UP: + evnt.state = event::UP; + input_cache.push_back(evnt); + mvprintw(1, 1, "UP"); + break; + case ' ': evnt.state = event::START; break; + case 27: // esc or alt + endwin(); + exit(0); + default: break; + } + + return input_cache; +} + + +enum { + COLOR_PLAYER1 = 1, + COLOR_PLAYER2 = 2, + COLOR_BALL = 3, + COLOR_DEBUG = 4, + + COLOR_0 = 5, + COLOR_1 = 6, + COLOR_2 = 7, + COLOR_3 = 8, + COLOR_4 = 9, +}; + + +Gui::Gui() { + initscr(); + start_color(); + init_pair(COLOR_PLAYER1, COLOR_BLUE, COLOR_BLUE); + init_pair(COLOR_PLAYER2, COLOR_RED, COLOR_RED); + init_pair(COLOR_BALL, COLOR_BLUE, COLOR_WHITE); + init_pair(COLOR_DEBUG, COLOR_WHITE, COLOR_BLACK); + init_pair(COLOR_0, COLOR_RED, COLOR_BLACK); + init_pair(COLOR_1, COLOR_GREEN, COLOR_BLACK); + + keypad(stdscr, true); + noecho(); + curs_set(0); + // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); + + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw( + 4, 5, " oooooooooo "); + mvprintw( + 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); + mvprintw( + 6, 5, " 888oooo88 888 888 888 888 888 88o "); + mvprintw( + 7, 5, " 888 888 888 888 888 888oo888o "); + mvprintw( + 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); + mvprintw( + 9, 5, " 888ooo888 "); + attroff(COLOR_PAIR(COLOR_DEBUG)); + + getch(); +} + + +void Gui::draw(PongState &state, const curve::curve_time_t &now) { + // clear(); + // Print Score + attron(COLOR_PAIR(COLOR_DEBUG)); + getmaxyx(stdscr, state.resolution[1], state.resolution[0]); + state.resolution[1] -= 1; + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw(2, + state.resolution[0] / 2 - 5, + "P1 %i | P2 %i", + state.p1.lives(now), + state.p2.lives(now)); + + mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); + mvprintw(0, 1, "NOW: %f", now); + mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); + mvprintw(2, + 1, + "P1: %f, %f, %i", + state.p1.position(now), + state.p1.y, + state.p1.state(now).state); + mvprintw(3, + 1, + "P2: %f, %f, %i", + state.p2.position(now), + state.p2.y, + state.p2.state(now).state); + for (int i = 0; i < 1000; i += 100) { + mvprintw(4 + i / 100, + 1, + "BALL in %03i: %f | %f; SPEED: %f | %f", + i, + state.ball.position(now + i)[0], + state.ball.position(now + i)[1], + state.ball.speed(now + i)[0], + state.ball.speed(now + i)[1]); + } + mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); + attroff(COLOR_PAIR(COLOR_DEBUG)); + + attron(COLOR_PAIR(COLOR_PLAYER1)); + for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { + mvprintw(state.p1.position(now) + i, state.p1.y, "|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER1)); + + attron(COLOR_PAIR(COLOR_PLAYER2)); + for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { + mvprintw(state.p2.position(now) + i, state.p2.y, "|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER2)); + + attron(COLOR_PAIR(COLOR_1)); + for (int i = 1; i < 9999; ++i) { + draw_ball(state.ball.position(now + i), 'X'); + } + attron(COLOR_PAIR(COLOR_0)); + draw_ball(state.ball.position(now), 'M'); + /*attron(COLOR_PAIR(COLOR_BALL)); + mvprintw(state.ball.position(now)[1], + state.ball.position(now)[0], + "o"); + */ + attroff(COLOR_PAIR(COLOR_BALL)); + refresh(); + erase(); +} + + +void Gui::draw_ball(util::Vector<2> pos, char chr) { + mvprintw((int)(pos[1]), (int)(pos[0]), "%c", chr); + standend(); +} +}} // openage::curvepong diff --git a/libopenage/curve/demo_event/gui.h b/libopenage/curve/demo_event/gui.h new file mode 100644 index 0000000000..be2c152eec --- /dev/null +++ b/libopenage/curve/demo_event/gui.h @@ -0,0 +1,25 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "gamestate.h" + +namespace openage { +namespace curvepong { + + +class Gui { + +public: + Gui(); + std::vector &getInputs(const PongPlayer &player); + void draw(PongState &state, const curve::curve_time_t &now); + void draw_ball(util::Vector<2> ball, char chr); + +private: + std::vector input_cache; +}; + +}} // openage::curvepong diff --git a/libopenage/curve/demo_event/main.cpp b/libopenage/curve/demo_event/main.cpp new file mode 100644 index 0000000000..34d5ce4468 --- /dev/null +++ b/libopenage/curve/demo_event/main.cpp @@ -0,0 +1,97 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#include + +#include +#include + +#include "aicontroller.h" +#include "gamestate.h" +#include "gui.h" +#include "physics.h" + +typedef std::chrono::high_resolution_clock Clock; + +#define GUI +#define REALTIME +#undef HUMAN + +namespace openage { +namespace curvepong { + +int demo() { + // Restart forever +#ifdef GUI + curvepong::Gui gui; +#endif + curvepong::Physics phys; + curvepong::AIInput ai; + bool running = true; + curve::EventQueue queue; + srand(time(NULL)); + while (running) { + curvepong::PongState state; + curve::curve_time_t now = 1; + + state.p1.lives.set_drop(now, 3); + state.p1.id = 0; + state.p1.size.set_drop(now, 4); + state.p2.lives.set_drop(now, 3); + state.p2.id = 1; + state.p2.size.set_drop(now, 4); +#ifdef GUI + gui.draw(state, now); // update gui related parameters +#else + state.resolution[0] = 100; + state.resolution[1] = 40; +#endif + + auto loop_start = Clock::now(); + curve::curve_time_t last_now = now; + now += 1; + { + std::vector start_event { event(0, event::START) }; + phys.processInput(state, state.p1, start_event, &queue, now); + } + +#ifdef GUI + gui.draw(state, now); // initial drawing with corrected ball +#endif + while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { +#ifdef HUMAN + gui.getInputs(state.p1); + phys.processInput(state, state.p1, gui.getInputs(state.p1), &queue, now); +#else + phys.processInput( + state, state.p1, ai.getInputs(state.p1, state.ball, now), &queue, now); +#endif + phys.processInput( + state, state.p2, ai.getInputs(state.p2, state.ball, now), &queue, now); + + state.p1.y = 0; + state.p2.y = state.resolution[0] - 1; + + queue.execute_until(now + 10); + last_now = now; +// phys.update(state, now); + queue.print(); +#ifdef GUI + gui.draw(state, now); +#endif +#ifdef REALTIME + usleep(4000); + double dt = std::chrono::duration_cast( + (Clock::now() - loop_start)) + .count(); + now += dt; +#else + now += 4; +#endif + loop_start = Clock::now(); + } + } + return 0; +} + + +}} // openage::curvepong diff --git a/libopenage/curve/demo_event/physics.cpp b/libopenage/curve/demo_event/physics.cpp new file mode 100644 index 0000000000..b71ddca478 --- /dev/null +++ b/libopenage/curve/demo_event/physics.cpp @@ -0,0 +1,208 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#include "physics.h" +#include "../../error/error.h" + +#include +#include +#include + +#define GUI + +namespace openage { +namespace curvepong { + +const float extrapolating_time = 100.0f; + +void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, curve::EventQueue *queue, const curve::curve_time_t &now) { + for (auto evnt : events) { + //Process only if the future has changed + if (player.state.get(now).state != evnt.state) { + player.state.set_drop(now, evnt); + + switch(evnt.state) { + case event::UP: + case event::DOWN: { + if (evnt.state == event::UP) { + player.speed.set_drop(now, -2); + } else if (evnt.state == event::DOWN) { + player.speed.set_drop(now, 2); + } + player.speed.set_drop(now + extrapolating_time, 0); + + float new_pos = player.position.get(now) + + (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); + if (new_pos < 0) + new_pos = 0; + if (new_pos > state.resolution[1]) + new_pos = state.resolution[1]; + + player.position.set_drop(now+extrapolating_time, new_pos); + evnt.state = event::IDLE; + player.state.set_drop(now + extrapolating_time, evnt); +// predict_reflect_panel(state, queue, now); + break; + } + case event::IDLE: + player.position.set_drop(now+extrapolating_time, + player.position.get(now)); + break; + case event::START: + reset(state, queue, now); + break; + + //if (player.state.get(now).state == event::LOST) { + // state.ball.position.set_drop(now, state.resolution * 0.5); + //} + //update_ball(state, now, init_recursion_limit); + //break; + default: + break; + } + } + } +} + + +void Physics::reset(PongState &state, curve::EventQueue *q, const curve::curve_time_t &gnow) { + q->clear(); + auto now = gnow + 0.001; + state.ball.position.set_drop(now, state.resolution * 0.5); + state.p1.position.set_drop(now, state.resolution[1] / 2); + state.p2.position.set_drop(now, state.resolution[1] / 2); + + float dirx = (rand() % 2 * 2) - 1; + float diry = (rand() % 2 * 2) - 1; + auto init_speed = + util::Vector<2>( + dirx * (0.0001 + (rand() % 100) / 1000.f), + diry * (0.0001 + (rand() % 100) / 2000.f)); + + state.ball.speed.set_drop(now, init_speed); + auto pos = state.ball.position.get(now); + static int cnt = 0; + mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", init_speed[0], init_speed[1], pos[0], pos[1], ++cnt); + predict_reflect_panel(state, q, now); + predict_reflect_wall(state, q, now); +} + + +void Physics::ball_reflect_wall(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +#ifndef GUI + std::cout << "\nWall\n"; +#else + static int cnt = 0; + mvprintw(22, 22, "Wall Reflect [%i]", ++cnt); + mvprintw(23, 22, "Speed[1] is %f", speed[1]); +#endif + speed[1] *= -1.0; + state.ball.speed.set_drop(now, speed); + state.ball.position.set_drop(now, pos); + + predict_reflect_wall(state, queue, now); +} + + +void Physics::predict_reflect_wall(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); + + double ty = 0; + if (speed[1] > 0) { + ty = (state.resolution[1] - pos[1]) / speed[1]; + } else if (speed[1] < 0) { + ty = pos[1] / -speed[1]; + } else { + throw Error(MSG(err) << "speed was 0"); + } +#ifdef GUI + mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); +#endif + if (ty > 0) { + auto hit_pos = pos + speed * ty; + hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; + //assert(hit_pos[0] >= 0); + assert(hit_pos[1] >= 0); + state.ball.position.set_drop(now + ty, hit_pos); + queue->addcallback(now + ty, "COLL WALL", + [&state](curve::EventQueue *q, const curve::curve_time_t &t) { + ball_reflect_wall(state, q, t); + }); + } else { + throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); + } +} + + +void Physics::ball_reflect_panel(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { + + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +#ifdef GUI + static int cnt = 0; + mvprintw(21, 22, "Panel hit [%i] ", ++cnt); +#else + std::cout << "\nPanel\n"; +#endif + + if (pos[0] <= 1 + && speed[0] < 0 + && (pos[1] < state.p1.position.get(now) - state.p1.size.get(now) / 2 + || pos[1] > state.p1.position.get(now) + state.p1.size.get(now) / 2)) { + // Ball missed the paddel of player 1 + auto l = state.p1.lives(now); + l --; + state.p1.lives.set_drop(now, l); + reset(state, queue, now); + mvprintw(21, 18, "1"); + return; + } else if (pos[0] >= state.resolution[0]-1 + && speed[0] > 0 + && (pos[1] < state.p2.position.get(now) - state.p2.size.get(now) / 2 + || pos[1] > state.p2.position.get(now) + state.p2.size.get(now) / 2)) { + // Ball missed the paddel of player 2 + auto l = state.p2.lives(now); + l --; + state.p2.lives.set_drop(now, l); + reset(state, queue, now); + mvprintw(21, 18, "2"); + return; + } else if(pos[0] >= state.resolution[0]- 1 || pos[0] <= 1) { + speed[0] *= -1.0; + state.ball.speed.set_drop(now, speed); + state.ball.position.set_drop(now, pos); + predict_reflect_panel(state, queue, now); + } +} + + +void Physics::predict_reflect_panel(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +// speed[1] += (rand() % 50 - 50)/10; + float ty = 0; + if (speed[0] > 0) { + ty = (state.resolution[0] - pos[0]) / speed[0]; + } else if (speed[0] < 0) { + ty = pos[0] / -speed[0]; + } +#ifdef GUI + mvprintw(21, 40, "AT %f NEXT %f", now, now + ty); + mvprintw(21, 18, "2"); +#endif + auto hit_pos = pos + speed * ty; + hit_pos[0] = speed[0] > 0 ? state.resolution[0] : 0; + assert(hit_pos[0] >= 0); +// assert(hit_pos[1] >= 0); // this might validly happen + state.ball.position.set_drop(now + ty, hit_pos); + queue->addcallback(now + ty, "COLL PANEL", + [&state](curve::EventQueue *q, const curve::curve_time_t &t) { + ball_reflect_panel(state, q, t); + }); + +// predict_reflect_wall(state, queue, now); +} + +}} // openage::curvepong diff --git a/libopenage/curve/demo_event/physics.h b/libopenage/curve/demo_event/physics.h new file mode 100644 index 0000000000..cd49415711 --- /dev/null +++ b/libopenage/curve/demo_event/physics.h @@ -0,0 +1,29 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "gamestate.h" +#include "../curve.h" +#include "../events.h" + +namespace openage { +namespace curvepong { + +class Physics { +public: + + void processInput(PongState &, PongPlayer &, std::vector &input, curve::EventQueue *, const curve::curve_time_t &now); +protected: + + static void reset(PongState &, curve::EventQueue *, const curve::curve_time_t &); + + + static void ball_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void ball_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); +}; + +}} // openage::curvepong diff --git a/libopenage/curve/events.cpp b/libopenage/curve/events.cpp index 342cf9da0d..504a314500 100644 --- a/libopenage/curve/events.cpp +++ b/libopenage/curve/events.cpp @@ -1,56 +1,150 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "events.h" - +#include namespace openage { namespace curve { -void EventQueue::addcallback (const curve_time_t &at, - const EventQueue::condition &precond, - const EventQueue::callback &trigger) { - Event e; - e.event = trigger; - e.precond = precond; - e.time = at; +#define GUI - addcallback(e); +EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, + const std::string &name, + const EventQueue::condition &precond, + const EventQueue::callback &trigger) { + return addcallback(Event(at, name, trigger, precond, ++last_event_id)); } -void EventQueue::addcallback (const curve_time_t &at, - const EventQueue::condition_void &precond, - const EventQueue::callback_void &trigger) { - Event e; - e.event = [trigger](const curve_time_t &) { trigger(); }; - e.precond = [precond](const curve_time_t &) { return precond(); }; - e.time = at; - addcallback(e); +EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, + const std::string &name, + const EventQueue::condition_void &precond, + const EventQueue::callback_void &trigger) { + return addcallback(Event(at, name, + [trigger](EventQueue *q, const curve_time_t &) { trigger(q); }, + [precond](const curve_time_t &) { return precond(); }, + ++last_event_id)); } -void EventQueue::addcallback (const curve_time_t &at, - const EventQueue::callback &trigger) { - this->addcallback(at, &EventQueue::_true, trigger); + +EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, + const std::string &name, + const EventQueue::callback &trigger) { + return this->addcallback(at, name, &EventQueue::_true, trigger); } -void EventQueue::addcallback (const curve_time_t &at, - const EventQueue::callback_void &trigger) { - this->addcallback(at, &EventQueue::_true, [trigger](const curve_time_t &) { - trigger(); + +EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, + const std::string &name, + const EventQueue::callback_void &trigger) { + return this->addcallback(at, name, &EventQueue::_true, [trigger](EventQueue *q, const curve_time_t &) { + trigger(q); }); } -void EventQueue::addcallback (const EventQueue::Event &e) { - queue.insert(e.time, e); + +EventQueue::Handle EventQueue::addcallback (const EventQueue::Event &e) { + + auto it = queue.begin(); +// Iterate to find the right insertion position + for(; it != queue.end() && it->time < e.time; ++it) {} + + queue.insert(it, e); + + // todo clear the past + return Handle(e.event_id); } + +void EventQueue::execute_until(const curve_time_t &time) { +#ifndef GUI + std::cout << "\rNOW: " << time; +#endif + + auto it = queue.begin(); + int row = 1; + while ((it = queue.begin()) != queue.end() && it->time < time) { + auto tmp = *it; + queue.erase(it); +#ifndef GUI + std::cout << " Exec " << tmp.event_id << " at " << tmp.time << " " << std::endl; +#else + mvprintw(row, 75, "X"); +#endif + + it->event(this, tmp.time); + past.push_back(tmp); + + + if (this->cleared) { + this->cleared = false; + break; + } + } +} + +void EventQueue::print() { +#ifndef GUI + std::cout << "Queue: " << std::endl; + for (const auto &i : queue) { + std::cout << i.time << ": " << i.event_id << i.event_name <queue.between(from, to); + !cleared && it != queue.end(); + ) { + counter ++; + + auto time = it.value().time; + if (it.value().precond(time)) { + it.value().event(this, time); } + //this->queue.erase(it); + //if (time >= to) break; + ++it; + //it = this->queue.between(time, to); } + if (this->cleared) + this->queue.clear(); + this->cleared = false; + if (counter) counter = 0; +} +*/ + +void EventQueue::clear() { +#ifndef GUI + std::cout << "CLEAR" << std::endl; +#endif + // set cleared before actually clearing to avoid races + this->cleared = true; + this->queue.clear(); } + +void EventQueue::clear(const curve_time_t &time) { +#ifndef GUI + std::cout << "CLEAR " << time << std::endl; +#endif + auto it = queue.begin(); + for(; it != queue.end() && it->time < time; ++it) {} + for(; it != queue.end(); it = queue.erase(it) ) {} +} + + bool EventQueue::_true(const curve_time_t &) { return true; } diff --git a/libopenage/curve/events.h b/libopenage/curve/events.h index d4aa21007b..9200c6a940 100644 --- a/libopenage/curve/events.h +++ b/libopenage/curve/events.h @@ -13,32 +13,73 @@ namespace curve { class EventQueue { public: - typedef std::function callback; + typedef std::function callback; typedef std::function condition; - typedef std::function callback_void; - typedef std::function condition_void; + typedef std::function callback_void; + typedef std::function condition_void; class Event { + friend class EventQueue; + private: + Event(const curve_time_t &time, const std::string &name, const callback &event, const condition &/*cond*/, const int event_id) : + event_id{event_id}, + time{time}, + name(name), + event{event} + //precond(precond) + {} + int event_id; public: - callback event; - condition precond; + Event(const Event &rhs) : + event_id(rhs.event_id), time(rhs.time), name(rhs.name), event(rhs.event) {} + curve_time_t time; + std::string name; + callback event; +// condition precond; + bool precond(const curve_time_t &) const { return true; }; + }; + + class Handle { + friend class EventQueue; + private: + Handle(const int event_id) : + event_id(event_id) {} + + const int event_id; }; - void addcallback (const curve_time_t &at, const condition &, const callback &); - void addcallback (const curve_time_t &at, const condition_void &, const callback_void &); + EventQueue(const curve_time_t &backlog_time = 1000) : + cleared{false}, + backlog_time(backlog_time) {} - void addcallback (const curve_time_t &at, const callback &); - void addcallback (const curve_time_t &at, const callback_void &); + Handle addcallback (const curve_time_t &at, const std::string &name, const condition &, const callback &); + Handle addcallback (const curve_time_t &at, const std::string &name, const condition_void &, const callback_void &); - void addcallback (const Event &); + Handle addcallback (const curve_time_t &at, const std::string &name, const callback &); + Handle addcallback (const curve_time_t &at, const std::string &name, const callback_void &); - void trigger(const curve_time_t &from, const curve_time_t &to); + Handle addcallback (const Event &); + void execute_until(const curve_time_t &t); + + void clear(); + + // Clear the queue from this time on. + void clear(const curve_time_t &); + + size_t size() { return queue.size(); } + + void print(); private: - Queue queue; + std::deque queue; + std::deque past; + bool cleared; + + int last_event_id = 0; + const curve_time_t backlog_time; static bool _true(const curve_time_t &); }; diff --git a/libopenage/curve/internal/keyframe_container.h b/libopenage/curve/internal/keyframe_container.h index f5fbfd456f..ecd01aefb6 100644 --- a/libopenage/curve/internal/keyframe_container.h +++ b/libopenage/curve/internal/keyframe_container.h @@ -189,7 +189,7 @@ typename KeyframeContainer<_T>::KeyframeIterator KeyframeContainer<_T>::last(con if (this->container.front().time > time) { // This will never happen due to the container.front->time == -Inf magic! - throw new Error(ERR << "rupture in spacetime detected, curve container is broken"); + throw Error(ERR << "rupture in spacetime detected, curve container is broken"); } // Search in the queue diff --git a/libopenage/curve/internal/value_container.h b/libopenage/curve/internal/value_container.h index 27d911e5f7..6070d1c853 100644 --- a/libopenage/curve/internal/value_container.h +++ b/libopenage/curve/internal/value_container.h @@ -3,6 +3,7 @@ #pragma once #include "keyframe_container.h" +#include namespace openage { namespace curve { @@ -13,7 +14,7 @@ class ValueContainer { ValueContainer() : last_element{container.begin()} {} - virtual _T get(const curve_time_t &t) const=0; + virtual _T get(const curve_time_t &t) const = 0; virtual _T operator ()(const curve_time_t &now) { return get(now); @@ -33,11 +34,21 @@ class ValueContainer { mutable typename KeyframeContainer<_T>::KeyframeIterator last_element; }; + + template void ValueContainer<_T>::set_drop(const curve_time_t &at, const _T &value) { - auto hint = this->container.erase_after(this->container.last(at, this->last_element)); + auto hint = this->container.last(at, this->last_element); + + // We want to remove a possible equal timed element from the container + if (std::fabs(hint->time - at) < std::numeric_limits::min()) { + hint--; + } + + hint = this->container.erase_after(hint); + container.insert(at, value, hint); - last_element = hint; + this->last_element = hint; } template diff --git a/libopenage/curve/iterator.h b/libopenage/curve/iterator.h index c1af8e282e..8e48c34d44 100644 --- a/libopenage/curve/iterator.h +++ b/libopenage/curve/iterator.h @@ -9,77 +9,86 @@ namespace curve { template -class CurveIterator : - public std::iterator -{ + class iterator_t = typename container_t::const_iterator> +class CurveIterator { public: - virtual val_t &value() const = 0; + virtual const val_t &value() const = 0; virtual bool valid() const = 0; - CurveIterator(const CurveIterator &rhs) : - base{rhs.base}, - container_end{rhs.container_end}, - from{rhs.from}, - to{rhs.to} {} - - CurveIterator &operator =(const CurveIterator &rhs) { - this->base = rhs.base; - this->container_end = rhs.container_end; - this->from = rhs.from; - this->to = rhs.to; - return *this; - } + explicit CurveIterator(const container_t *c): + _base{}, + container{c}, + from{-std::numeric_limits::infinity()}, + to{+std::numeric_limits::infinity()} {} + + CurveIterator (const CurveIterator &) = default; + CurveIterator &operator= ( + const CurveIterator &) = default; - virtual val_t &operator *() const { + virtual const val_t &operator *() const { return this->value(); } - virtual val_t *operator ->() const { + virtual const val_t *operator ->() const { return &this->value(); } /** * For equalness only the base iterator will be testet - not the timespans - * this is defined in. + * *this is defined in. */ virtual bool operator ==(const CurveIterator &rhs) const { - return this->base == rhs.base; + return this->_base == rhs._base; } /** * For unequalness only the base iterator will be testet - not the timespans - * this is defined in. + * *this is defined in. */ virtual bool operator !=(const CurveIterator &rhs) const { - return this->base != rhs.base; + return this->_base != rhs._base; } +// virtual bool operator !=(const iterator_t &rhs) const { +// return this->base != rhs; +// } + /** * Advance to the next valid element. */ - virtual CurveIterator &operator ++() { + virtual CurveIterator &operator ++() { do { - ++this->base; - } while (this->base != this->container_end && !this->valid()); + ++(this->_base); + } while (this->container->end()._base != this->_base && !this->valid()); return *this; } + const iterator_t &base() const { + return _base; + } + + const curve_time_t &_from() const { + return from; + } + + const curve_time_t &_to() const { + return to; + } protected: - CurveIterator (const iterator_t &base, - const iterator_t &container_end, + CurveIterator(const iterator_t &base, + const container_t *container, const curve_time_t &from, const curve_time_t &to) : - base{base}, - container_end{container_end}, + _base{base}, + container{container}, from{from}, to{to} {} protected: /// The iterator this is currently referring to. - iterator_t base; - /// The iterator to the containers end. - iterator_t container_end; + iterator_t _base; + /// The base container. + const container_t *container; /// The time, from where this iterator started to iterate. curve_time_t from; @@ -87,4 +96,5 @@ class CurveIterator : curve_time_t to; }; + }} // openage::curve diff --git a/libopenage/curve/map.h b/libopenage/curve/map.h index b178e68068..ad792fed8f 100644 --- a/libopenage/curve/map.h +++ b/libopenage/curve/map.h @@ -25,22 +25,21 @@ class UnorderedMap { public: // Using does not work with templates - typedef typename std::unordered_map::iterator iterator; + typedef typename std::unordered_map::const_iterator const_iterator; -// TODO return an std::optional here. + // TODO return an std::optional here std::pair> - operator()(const curve_time_t&, const key_t &); + operator()(const curve_time_t&, const key_t &) const; -// TODO return an std::optional here. + // TODO return an std::optional here. std::pair> - at(const curve_time_t &, const key_t &); + at(const curve_time_t &, const key_t &) const; MapFilterIterator - begin(const curve_time_t &e = std::numeric_limits::infinity()); + begin(const curve_time_t &e = std::numeric_limits::infinity()) const; MapFilterIterator - end(const curve_time_t &e = std::numeric_limits::infinity()); - + end(const curve_time_t &e = std::numeric_limits::infinity()) const; MapFilterIterator insert(const curve_time_t &birth, const key_t &, const val_t &); @@ -49,7 +48,7 @@ class UnorderedMap { insert(const curve_time_t &birth, const curve_time_t &death, const key_t &key, const val_t &value); MapFilterIterator - between(const curve_time_t &start, const curve_time_t &to); + between(const curve_time_t &start, const curve_time_t &to) const; void birth(const curve_time_t &, const key_t &); void birth(const curve_time_t &, @@ -72,21 +71,21 @@ class UnorderedMap { template std::pair>> UnorderedMap::operator()(const curve_time_t &time, - const key_t &key) { + const key_t &key) const { return this->at(time, key); } template std::pair>> UnorderedMap::at(const curve_time_t & time, - const key_t & key) { + const key_t & key) const { auto e = this->container.find(key); if (e != this->container.end() && e->second.alive <= time && e->second.dead >time) { return std::make_pair( true, MapFilterIterator>( e, - this->container.end(), + this, time, std::numeric_limits::infinity())); } else { @@ -98,30 +97,30 @@ UnorderedMap::at(const curve_time_t & time, template MapFilterIterator> -UnorderedMap::begin(const curve_time_t &time) { +UnorderedMap::begin(const curve_time_t &time) const { return MapFilterIterator>( this->container.begin(), - this->container.end(), + this, time, std::numeric_limits::infinity()); } template MapFilterIterator> -UnorderedMap::end(const curve_time_t &time) { +UnorderedMap::end(const curve_time_t &time) const { return MapFilterIterator>( this->container.end(), - this->container.end(), + this, -std::numeric_limits::infinity(), time); } template MapFilterIterator> -UnorderedMap::between(const curve_time_t &from, const curve_time_t &to) { +UnorderedMap::between(const curve_time_t &from, const curve_time_t &to) const { auto it = MapFilterIterator>( this->container.begin(), - this->container.end(), + this, from, to); @@ -153,7 +152,7 @@ UnorderedMap::insert(const curve_time_t &alive, auto it = this->container.insert(std::make_pair(key, e)); return MapFilterIterator>( it.first, - this->container.end(), + this, alive, dead); } diff --git a/libopenage/curve/map_filter_iterator.h b/libopenage/curve/map_filter_iterator.h index cbb6cdadcd..7e112e745a 100644 --- a/libopenage/curve/map_filter_iterator.h +++ b/libopenage/curve/map_filter_iterator.h @@ -26,39 +26,41 @@ class MapFilterIterator : public CurveIterator { public: - typedef typename container_t::iterator iterator_t; + typedef typename container_t::const_iterator iterator_t; /** * Construct the iterator from its boundary conditions: time and container */ MapFilterIterator(const iterator_t &base, - const iterator_t &container_end, - const curve_time_t &from, - const curve_time_t &to) : - CurveIterator(base, container_end, from, to) {} + const container_t *container, + const curve_time_t &from, + const curve_time_t &to) : + CurveIterator(base, container, from, to) {} + + MapFilterIterator(const MapFilterIterator &) = default; + + using CurveIterator::operator=; virtual bool valid() const override { - return this->base->second.alive >= this->from && - this->base->second.dead < this->to; + return this->base()->second.alive >= this->from + && this->base()->second.dead < this->to; } /** * Get the value behind the iterator. * Nicer way of accessing it beside operator *. */ - val_t &value() const override { - return this->base->second.value; + val_t const &value() const override { + return this->base()->second.value; } /** * Get the key pointed to by this iterator. */ - const key_t &key() { - return this->base->first; + const key_t &key() const { + return this->base()->first; } -protected: - }; }} // openage::curve diff --git a/libopenage/curve/queue.h b/libopenage/curve/queue.h index cbc3176f0c..bec6448b00 100644 --- a/libopenage/curve/queue.h +++ b/libopenage/curve/queue.h @@ -21,32 +21,37 @@ class Queue { _time{time}, value{value} {} - curve_time_t time() { + curve_time_t time() const { return _time; } }; public: typedef typename std::deque container_t; - typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; + typedef typename container_t::const_iterator iterator; + // Reading Access const _T &front(const curve_time_t &) const; // Modifying access QueueFilterIterator<_T, Queue<_T>> begin( - const curve_time_t &t = -std::numeric_limits::infinity()); + const curve_time_t &t = -std::numeric_limits::infinity()) const; QueueFilterIterator<_T, Queue<_T>> end( - const curve_time_t &t = std::numeric_limits::infinity()); + const curve_time_t &t = std::numeric_limits::infinity()) const; QueueFilterIterator<_T, Queue<_T>> between( const curve_time_t &begin = std::numeric_limits::infinity(), - const curve_time_t &end = std::numeric_limits::infinity()); + const curve_time_t &end = std::numeric_limits::infinity()) const; + + //QueueFilterIterator<_T, Queue<_T>> + void erase(const CurveIterator<_T, Queue<_T>> &); + + QueueFilterIterator<_T, Queue<_T>> insert(const curve_time_t &, const _T &e); - QueueFilterIterator<_T, Queue<_T>> erase( - const CurveIterator<_T, Queue<_T>> &); + void clear(); - QueueFilterIterator<_T, Queue<_T>> insert( - const curve_time_t &, const _T &e); + void clean(const curve_time_t &); void __attribute__((noinline)) dump() { for (auto i : container) { @@ -66,13 +71,13 @@ const _T &Queue<_T>::front(const curve_time_t &) const { template -QueueFilterIterator<_T, Queue<_T>> Queue<_T>::begin(const curve_time_t &t) +QueueFilterIterator<_T, Queue<_T>> Queue<_T>::begin(const curve_time_t &t) const { for (auto it = this->container.begin(); it != this->container.end(); ++it) { if (it->time() >= t) { return QueueFilterIterator<_T, Queue<_T>>( it, - container.end(), + this, t, std::numeric_limits::infinity()); } @@ -83,10 +88,11 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::begin(const curve_time_t &t) template -QueueFilterIterator<_T, Queue<_T>> Queue<_T>::end(const curve_time_t &t) +QueueFilterIterator<_T, Queue<_T>> Queue<_T>::end(const curve_time_t &t) const { - return QueueFilterIterator<_T, Queue<_T>>(container.end(), + return QueueFilterIterator<_T, Queue<_T>>( container.end(), + this, t, std::numeric_limits::infinity()); } @@ -95,14 +101,14 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::end(const curve_time_t &t) template QueueFilterIterator<_T, Queue<_T>> Queue<_T>::between( const curve_time_t &begin, - const curve_time_t &end) + const curve_time_t &end) const { auto it = QueueFilterIterator<_T, Queue<_T>>( container.begin(), - container.end(), + this, begin, end); - if (!it.valid()) { + if (!container.empty() && !it.valid()) { ++it; } return it; @@ -110,19 +116,19 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::between( template -QueueFilterIterator<_T, Queue<_T>> Queue<_T>::erase(const CurveIterator<_T, Queue<_T>> &t) +/*QueueFilterIterator<_T, Queue<_T>>*/ void Queue<_T>::erase(const CurveIterator<_T, Queue<_T>> &t) { - auto it = container.erase(t.base); - auto ct = QueueFilterIterator<_T, Queue<_T>>( + auto it = container.erase(t.base()); + /*auto ct = QueueFilterIterator<_T, Queue<_T>>( it, - container.end(), - t.from, - t.to); - - if (!ct.valid(t.from)) { + this, + t._from(), + t._to()); + if (ct.base() != container.end() && !ct.valid()) { ++ct; - } - return ct; + }*/ + + return; } @@ -130,7 +136,8 @@ template QueueFilterIterator<_T, Queue<_T>> Queue<_T>::insert( const curve_time_t &time, const _T &e) { - iterator insertion_point = this->container.end(); + + const_iterator insertion_point = this->container.end(); for (auto it = this->container.begin(); it != this->container.end(); ++it) { if (time < it->time()) { insertion_point = this->container @@ -145,7 +152,7 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::insert( auto ct = QueueFilterIterator<_T, Queue<_T>>( insertion_point, - container.end(), + this, time, std::numeric_limits::infinity()); if (!ct.valid()) { @@ -154,4 +161,21 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::insert( return ct; } + +template +void Queue<_T>::clear() { + this->container.clear(); +} + + +template +void Queue<_T>::clean(const curve_time_t &time) { + for (auto it = this->container.begin(); + it != this->container.end() + && it->time() < time; + it = this->container.erase(it)) + {} +} + + }} // openage::curve diff --git a/libopenage/curve/queue_filter_iterator.h b/libopenage/curve/queue_filter_iterator.h index 7e743ac976..f48899f254 100644 --- a/libopenage/curve/queue_filter_iterator.h +++ b/libopenage/curve/queue_filter_iterator.h @@ -22,29 +22,30 @@ namespace curve { template class QueueFilterIterator : - public CurveIterator + public CurveIterator { public: - typedef typename container_t::iterator iterator_t; + typedef typename container_t::const_iterator const_iterator; /** * Construct the iterator from its boundary conditions: time and container */ - QueueFilterIterator(const iterator_t &base, - const iterator_t &container_end, + QueueFilterIterator(const const_iterator &base, + const container_t *base_container, const curve_time_t &from, const curve_time_t &to) : - CurveIterator{base, container_end, from, to} {} + CurveIterator(base, base_container, from, to) {} virtual bool valid() const override { - if (this->base != this->container_end) { - return this->base->time() >= this->from && this->base->time() < this->to; + if (this->container->end().base() != this->base()) { + return this->base()->time() >= this->from && this->base()->time() < this->to; } return false; } - val_t &value() const override { - return this->base->value; + const val_t &value() const override { + const auto &a = (*this->base()); + return a.value; } }; diff --git a/libopenage/curve/test/test_container.cpp b/libopenage/curve/test/test_container.cpp index 2f954766bd..91d5232913 100644 --- a/libopenage/curve/test/test_container.cpp +++ b/libopenage/curve/test/test_container.cpp @@ -39,6 +39,11 @@ void dump(const std::map &map) { } void test_map() { + static_assert(std::is_copy_constructible>>::value, + "UnorderedMapIterator not Copy Constructable able"); + static_assert(std::is_copy_assignable>>::value, + "UnorderedMapIterator not Copy Assignable"); + UnorderedMap map; map.insert(0, 10, 0, 0); map.insert(5, 10, 5, 1); @@ -132,6 +137,13 @@ void test_list() { } void test_queue() { + static_assert(std::is_copy_constructible>>::value, + "QueueIterator not Copy Constructable able"); + static_assert(std::is_copy_assignable>>::value, + "QueueIterator not Copy Assignable"); + + + Queue q; q.insert(0, 1); q.insert(2, 2); diff --git a/libopenage/curve/test/test_curve_types.cpp b/libopenage/curve/test/test_curve_types.cpp index 989dee9ceb..f660ddbd9e 100644 --- a/libopenage/curve/test/test_curve_types.cpp +++ b/libopenage/curve/test/test_curve_types.cpp @@ -73,7 +73,7 @@ void curve_types() { } { - Continuous c; + Continuous c; c.set_insert(0, 0); c.set_insert(20, 20); @@ -81,11 +81,12 @@ void curve_types() { TESTEQUALS(c.get(1), 1); TESTEQUALS(c.get(7), 7); - c.set_drop(10, 10); + c.set_drop(20, 10); TESTEQUALS(c.get(0), 0); - TESTEQUALS(c.get(1), 1); - TESTEQUALS(c.get(7), 7); + TESTEQUALS(c.get(2), 1); + TESTEQUALS(c.get(8), 4); } + //Check the discrete type { Discrete c; @@ -94,7 +95,7 @@ void curve_types() { TESTEQUALS(c.get(0), 0); TESTEQUALS(c.get(1), 0); - TESTEQUALS(c.get(11), 10); + TESTEQUALS(c.get(10), 10); Discrete complex; @@ -103,7 +104,7 @@ void curve_types() { TESTEQUALS(complex.get(0), "Test 0"); TESTEQUALS(complex.get(1), "Test 0"); - TESTEQUALS(complex.get(11), "Test 10"); + TESTEQUALS(complex.get(10), "Test 10"); } @@ -117,7 +118,16 @@ void curve_types() { TESTEQUALS(c.get(3), 3); c.set_drop(2, 10); - TESTEQUALS(c.get(3), 10); + TESTEQUALS(c.get(2), 10); + } + + // Encountered Errors + { + Continuous c; + c.set_insert(1, 1); + c.set_drop(1, -5); + + TESTEQUALS(c.get(1), -5); } } diff --git a/libopenage/curve/test/test_events.cpp b/libopenage/curve/test/test_events.cpp index b988bd434b..9ad4fa5d01 100644 --- a/libopenage/curve/test/test_events.cpp +++ b/libopenage/curve/test/test_events.cpp @@ -14,44 +14,66 @@ static void print_vector(const std::vector> &t) { } } -void events () { +EventQueue createQueue(std::vector> &calls) { EventQueue q; - - std::vector> calls; - print_vector(calls); - - q.addcallback(1, [&calls](const curve_time_t &t) { + q.addcallback(1, "1", [&calls](EventQueue *, const curve_time_t &t) { calls.push_back(std::make_pair(t, 1)); }); - q.addcallback(2, [&calls](const curve_time_t &t) { + q.addcallback(2, "2", [&calls](EventQueue *, const curve_time_t &t) { calls.push_back(std::make_pair(t, 2)); }); - q.trigger(0, 2); - TESTEQUALS(calls.size(), 1); - TESTEQUALS(calls[0].first, 1); - TESTEQUALS(calls[0].second, 1); + return q; +} - calls.clear(); - q.trigger(0, 3); - TESTEQUALS(calls.size(), 2); - TESTEQUALS(calls[0].first, 1); - TESTEQUALS(calls[0].second, 1); - TESTEQUALS(calls[1].first, 2); - TESTEQUALS(calls[1].second, 2); +void events () { + { + std::vector> calls; + print_vector(calls); - calls.clear(); - q.trigger(2, 3); - TESTEQUALS(calls.size(), 1); - TESTEQUALS(calls[0].first, 2); - TESTEQUALS(calls[0].second, 2); + // Test with empty queue + EventQueue q; + q.execute_until(100); + } + + { + std::vector> calls; + EventQueue q = createQueue(calls); + q.execute_until(2); + TESTEQUALS(calls.size(), 1); + TESTEQUALS(calls[0].first, 1); + TESTEQUALS(calls[0].second, 1); + } + { + std::vector> calls; + EventQueue q = createQueue(calls); + q.execute_until(3); + TESTEQUALS(calls.size(), 2); + TESTEQUALS(calls[0].first, 1); + TESTEQUALS(calls[0].second, 1); + TESTEQUALS(calls[1].first, 2); + TESTEQUALS(calls[1].second, 2); + } + + { + std::vector> calls; + EventQueue q = createQueue(calls); + q.execute_until(2); + TESTEQUALS(calls.size(), 1); + calls.clear(); + q.execute_until(3); + TESTEQUALS(calls.size(), 1); + TESTEQUALS(calls[0].first, 2); + TESTEQUALS(calls[0].second, 2); + } + /* int cond1 = 1; q.addcallback(4, [&calls, cond1](const curve_time_t &) { return cond1 == 1; }, - [&calls](const curve_time_t &t) { + [&calls](EventQueue *, const curve_time_t &t) { calls.push_back(std::make_pair(t, 4)); }); @@ -70,14 +92,14 @@ void events () { q.addcallback(5, [&cond2](const curve_time_t &) { return cond2 == 1; }, - [&calls](const curve_time_t &t) { + [&calls](EventQueue *, const curve_time_t &t) { calls.push_back(std::make_pair(t, 5)); }); q.addcallback(6, [&cond2](const curve_time_t &) { return cond2 == 1 || cond2 == 2; }, - [&calls, &cond2] (const curve_time_t &t) { + [&calls, &cond2] (EventQueue *, const curve_time_t &t) { calls.push_back(std::make_pair(t, 6)); cond2 ++; }); @@ -103,6 +125,7 @@ void events () { q.trigger(5, 7); TESTEQUALS(calls.size(), 0); TESTEQUALS(cond2, 3); + */ } }}} // namespace::curve::tests From 81ede4a71377377cfa86458e2163d86d0dbe4973 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Tue, 4 Jul 2017 00:17:32 +0200 Subject: [PATCH 20/24] curves: event concept running --- libopenage/curve/CMakeLists.txt | 1 + libopenage/curve/continuous.cpp | 2 + libopenage/curve/continuous.h | 13 ++ libopenage/curve/curve.cpp | 2 + libopenage/curve/curve.h | 19 +- libopenage/curve/demo/aicontroller.cpp | 2 +- libopenage/curve/demo/aicontroller.h | 4 +- libopenage/curve/demo/gamestate.cpp | 10 + libopenage/curve/demo/gamestate.h | 15 +- libopenage/curve/demo/gui.cpp | 30 +-- libopenage/curve/demo/gui.h | 6 +- libopenage/curve/demo/main.cpp | 76 ++++--- libopenage/curve/demo/physics.cpp | 228 +++++++++++++------ libopenage/curve/demo/physics.h | 14 +- libopenage/curve/demo_event/CMakeLists.txt | 7 - libopenage/curve/demo_event/aicontroller.cpp | 30 --- libopenage/curve/demo_event/aicontroller.h | 23 -- libopenage/curve/demo_event/gamestate.cpp | 3 - libopenage/curve/demo_event/gamestate.h | 58 ----- libopenage/curve/demo_event/gui.cpp | 163 ------------- libopenage/curve/demo_event/gui.h | 25 -- libopenage/curve/demo_event/main.cpp | 97 -------- libopenage/curve/demo_event/physics.cpp | 208 ----------------- libopenage/curve/demo_event/physics.h | 29 --- libopenage/curve/discrete.cpp | 2 + libopenage/curve/discrete.h | 13 ++ libopenage/curve/eventqueue.md | 115 ++++++++++ libopenage/curve/events.cpp | 86 ++++--- libopenage/curve/events.h | 103 +++++++-- libopenage/curve/internal/value_container.h | 16 +- libopenage/curve/iterator.cpp | 10 + libopenage/curve/iterator.h | 39 +++- libopenage/curve/map.cpp | 10 + libopenage/curve/map.h | 11 +- libopenage/curve/map_filter_iterator.cpp | 10 + libopenage/curve/map_filter_iterator.h | 6 +- libopenage/curve/object.h | 23 ++ libopenage/curve/queue.cpp | 2 +- libopenage/curve/queue.h | 5 + libopenage/curve/queue_filter_iterator.cpp | 10 + libopenage/curve/queue_filter_iterator.h | 6 +- libopenage/curve/test/CMakeLists.txt | 3 +- libopenage/curve/test/test_curve_types.cpp | 14 +- libopenage/curve/test/test_trigger.cpp | 64 ++++++ libopenage/curve/trigger.cpp | 109 +++++++++ libopenage/curve/trigger.h | 176 ++++++++++++++ openage/testing/testlist.py | 1 + 47 files changed, 1040 insertions(+), 859 deletions(-) create mode 100644 libopenage/curve/demo/gamestate.cpp delete mode 100644 libopenage/curve/demo_event/CMakeLists.txt delete mode 100644 libopenage/curve/demo_event/aicontroller.cpp delete mode 100644 libopenage/curve/demo_event/aicontroller.h delete mode 100644 libopenage/curve/demo_event/gamestate.cpp delete mode 100644 libopenage/curve/demo_event/gamestate.h delete mode 100644 libopenage/curve/demo_event/gui.cpp delete mode 100644 libopenage/curve/demo_event/gui.h delete mode 100644 libopenage/curve/demo_event/main.cpp delete mode 100644 libopenage/curve/demo_event/physics.cpp delete mode 100644 libopenage/curve/demo_event/physics.h create mode 100644 libopenage/curve/eventqueue.md create mode 100644 libopenage/curve/iterator.cpp create mode 100644 libopenage/curve/map.cpp create mode 100644 libopenage/curve/map_filter_iterator.cpp create mode 100644 libopenage/curve/object.h create mode 100644 libopenage/curve/queue_filter_iterator.cpp create mode 100644 libopenage/curve/test/test_trigger.cpp create mode 100644 libopenage/curve/trigger.cpp create mode 100644 libopenage/curve/trigger.h diff --git a/libopenage/curve/CMakeLists.txt b/libopenage/curve/CMakeLists.txt index ae4c67b179..aa4c1bb0bc 100644 --- a/libopenage/curve/CMakeLists.txt +++ b/libopenage/curve/CMakeLists.txt @@ -12,6 +12,7 @@ add_sources(libopenage queue.cpp queue.cpp queue_filter_iterator.cpp + trigger.cpp ) add_subdirectory(internal) diff --git a/libopenage/curve/continuous.cpp b/libopenage/curve/continuous.cpp index c5ed0b67f0..de78eb3e7f 100644 --- a/libopenage/curve/continuous.cpp +++ b/libopenage/curve/continuous.cpp @@ -5,4 +5,6 @@ namespace openage { namespace curve { +// This file is intended to be empty + }} // openage::curve diff --git a/libopenage/curve/continuous.h b/libopenage/curve/continuous.h index 4865d085d2..ca50fe9e97 100644 --- a/libopenage/curve/continuous.h +++ b/libopenage/curve/continuous.h @@ -9,12 +9,25 @@ namespace openage { namespace curve { +/** + * Continuous Datatype. + * Stores a value container with continuous access. + * The bound template type _T has to implement `operator+(_T)` and + * `operator*(curve_time_t)`. + * + */ template class Continuous : public ValueContainer<_T> { public: + using ValueContainer<_T>::ValueContainer; + /** + * will interpolate between the keyframes linearly based on the time. + */ _T get(const curve_time_t &) const override; }; + + template _T Continuous<_T>::get(const curve_time_t &time) const { auto e = this->container.last(time, this->last_element); diff --git a/libopenage/curve/curve.cpp b/libopenage/curve/curve.cpp index 7283022848..fdd5404149 100644 --- a/libopenage/curve/curve.cpp +++ b/libopenage/curve/curve.cpp @@ -5,4 +5,6 @@ namespace openage { namespace curve { +// This file is intended to be empty + }} // openage::curve diff --git a/libopenage/curve/curve.h b/libopenage/curve/curve.h index b487029e30..c7d5d6299e 100644 --- a/libopenage/curve/curve.h +++ b/libopenage/curve/curve.h @@ -5,21 +5,10 @@ namespace openage { namespace curve { +/** + * Defines the type that is used as time index. + * it has to implement all basic mathematically operations. + */ typedef double curve_time_t; -/* -template -curve_time_t time(const _T &t) { - return t.time(); -} -template -curve_time_t existent_from (const _T &t) { - return t.existent_from(); -} - -template -curve_time_t existent_until (const _T &t) { - return t.existent_until(); -} -*/ }} // openage::curve diff --git a/libopenage/curve/demo/aicontroller.cpp b/libopenage/curve/demo/aicontroller.cpp index 47ef8c0092..69f012d015 100644 --- a/libopenage/curve/demo/aicontroller.cpp +++ b/libopenage/curve/demo/aicontroller.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "aicontroller.h" diff --git a/libopenage/curve/demo/aicontroller.h b/libopenage/curve/demo/aicontroller.h index d87c455be1..eeddca8b0b 100644 --- a/libopenage/curve/demo/aicontroller.h +++ b/libopenage/curve/demo/aicontroller.h @@ -2,10 +2,10 @@ #pragma once -#include - #include "gamestate.h" +#include + namespace openage { namespace curvepong { diff --git a/libopenage/curve/demo/gamestate.cpp b/libopenage/curve/demo/gamestate.cpp new file mode 100644 index 0000000000..c91b21ccb0 --- /dev/null +++ b/libopenage/curve/demo/gamestate.cpp @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "gamestate.h" + +namespace openage { +namespace curvepong { + +// This file is intentionally left empty + +}} // openage::curvepong diff --git a/libopenage/curve/demo/gamestate.h b/libopenage/curve/demo/gamestate.h index ce2c4a742c..83d2be1187 100644 --- a/libopenage/curve/demo/gamestate.h +++ b/libopenage/curve/demo/gamestate.h @@ -20,7 +20,12 @@ struct event { class PongPlayer { public: - PongPlayer() { + PongPlayer(openage::curve::TriggerFactory *f) : + speed(f), + position(f), + lives(f), + state(f), + size(f) { speed.set_drop(0, 1); position.set_drop(0, 0.5); lives.set_drop(0, 1); @@ -41,12 +46,20 @@ class PongPlayer { class PongBall { public: + PongBall(curve::TriggerFactory *f) : + speed(f), + position(f) {} curve::Discrete> speed; curve::Continuous> position; }; class PongState { public: + PongState(curve::TriggerFactory *f) : + p1(f), + p2(f), + ball(f) {} + PongPlayer p1; PongPlayer p2; diff --git a/libopenage/curve/demo/gui.cpp b/libopenage/curve/demo/gui.cpp index f99ab4c18a..0f07bc5141 100644 --- a/libopenage/curve/demo/gui.cpp +++ b/libopenage/curve/demo/gui.cpp @@ -27,7 +27,9 @@ std::vector &Gui::getInputs(const PongPlayer &player) { input_cache.push_back(evnt); mvprintw(1, 1, "UP"); break; - case ' ': evnt.state = event::START; break; + case ' ': + evnt.state = event::START; + break; case 27: // esc or alt endwin(); exit(0); @@ -37,6 +39,7 @@ std::vector &Gui::getInputs(const PongPlayer &player) { return input_cache; } + enum { COLOR_PLAYER1 = 1, COLOR_PLAYER2 = 2, @@ -50,6 +53,7 @@ enum { COLOR_4 = 9, }; + Gui::Gui() { initscr(); start_color(); @@ -83,12 +87,13 @@ Gui::Gui() { getch(); } + void Gui::draw(PongState &state, const curve::curve_time_t &now) { - erase(); // clear(); // Print Score attron(COLOR_PAIR(COLOR_DEBUG)); getmaxyx(stdscr, state.resolution[1], state.resolution[0]); + state.resolution[1] -= 1; attron(COLOR_PAIR(COLOR_DEBUG)); mvprintw(2, state.resolution[0] / 2 - 5, @@ -136,10 +141,12 @@ void Gui::draw(PongState &state, const curve::curve_time_t &now) { } attroff(COLOR_PAIR(COLOR_PLAYER2)); - for (int i = 0; i < 9999; ++i) { - draw_ball(state.ball.position(now + i * 50), i); + attron(COLOR_PAIR(COLOR_1)); + for (int i = 1; i < 9999; ++i) { + draw_ball(state.ball.position(now + i), 'X'); } - + attron(COLOR_PAIR(COLOR_0)); + draw_ball(state.ball.position(now), 'M'); /*attron(COLOR_PAIR(COLOR_BALL)); mvprintw(state.ball.position(now)[1], state.ball.position(now)[0], @@ -147,17 +154,12 @@ void Gui::draw(PongState &state, const curve::curve_time_t &now) { */ attroff(COLOR_PAIR(COLOR_BALL)); refresh(); + erase(); } -void Gui::draw_ball(util::Vector<2> pos, int idx) { - switch (idx) { - case 0: attron(COLOR_PAIR(COLOR_0)); break; - default: - case 1: attron(COLOR_PAIR(COLOR_1)); break; - } - mvprintw((int)(pos[1]), (int)(pos[0]), "X"); +void Gui::draw_ball(util::Vector<2> pos, char chr) { + mvprintw((int)(pos[1]), (int)(pos[0]), "%c", chr); standend(); } -} -} // openage::curvepong +}} // openage::curvepong diff --git a/libopenage/curve/demo/gui.h b/libopenage/curve/demo/gui.h index d04662324d..708a3a8c0d 100644 --- a/libopenage/curve/demo/gui.h +++ b/libopenage/curve/demo/gui.h @@ -2,10 +2,10 @@ #pragma once -#include - #include "gamestate.h" +#include + namespace openage { namespace curvepong { @@ -16,7 +16,7 @@ class Gui { Gui(); std::vector &getInputs(const PongPlayer &player); void draw(PongState &state, const curve::curve_time_t &now); - void draw_ball(util::Vector<2> ball, int idx); + void draw_ball(util::Vector<2> ball, char chr); private: std::vector input_cache; diff --git a/libopenage/curve/demo/main.cpp b/libopenage/curve/demo/main.cpp index c7f67efe52..316227065c 100644 --- a/libopenage/curve/demo/main.cpp +++ b/libopenage/curve/demo/main.cpp @@ -1,28 +1,36 @@ // Copyright 2015-2017 the openage authors. See copying.md for legal info. -#include - -#include - #include "aicontroller.h" #include "gamestate.h" #include "gui.h" #include "physics.h" +#include + +#include + typedef std::chrono::high_resolution_clock Clock; +#define GUI +#define REALTIME 3 +#undef HUMAN + namespace openage { namespace curvepong { int demo() { // Restart forever +#ifdef GUI curvepong::Gui gui; +#endif + curve::EventQueue queue; + curve::TriggerFactory factory{&queue}; curvepong::Physics phys; curvepong::AIInput ai; bool running = true; - + srand(time(NULL)); while (running) { - curvepong::PongState state; + curvepong::PongState state(&factory); curve::curve_time_t now = 1; state.p1.lives.set_drop(now, 3); @@ -31,53 +39,61 @@ int demo() { state.p2.lives.set_drop(now, 3); state.p2.id = 1; state.p2.size.set_drop(now, 4); - - auto init_speed = - util::Vector<2>(((rand() % 2) * 2 - 1) * (0.1f + rand() % 4) / 70.f, - 0.01f * (rand() % 100) / 70.f); - +#ifdef GUI gui.draw(state, now); // update gui related parameters - - state.ball.speed.set_drop(now, init_speed); - state.ball.position.set_drop(now, state.resolution * 0.5); - state.p1.position.set_drop(now, state.resolution[1] / 2); - state.p2.position.set_drop(now, state.resolution[1] / 2); - - gui.draw(state, now); // initial drawing with corrected ball +#else + state.resolution[0] = 100; + state.resolution[1] = 40; +#endif auto loop_start = Clock::now(); now += 1; - std::cout << "p1: " << state.p1.lives.get(now) << " p2 " - << state.p2.lives.get(now) << std::endl; + { + std::vector start_event { event(0, event::START) }; + phys.processInput(state, state.p1, start_event, &queue, now); + } +#ifdef GUI + gui.draw(state, now); // initial drawing with corrected ball +#endif while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { + //We need to get the inputs to be able to kill the game #ifdef HUMAN - phys.processInput(state, state.p1, gui.getInputs(state.p1), now); + phys.processInput(state, state.p1, gui.getInputs(state.p1), &queue, now); #else gui.getInputs(state.p1); phys.processInput( - state, state.p1, ai.getInputs(state.p1, state.ball, now), now); + state, state.p1, ai.getInputs(state.p1, state.ball, now), &queue, now); #endif phys.processInput( - state, state.p2, ai.getInputs(state.p2, state.ball, now), now); + state, state.p2, ai.getInputs(state.p2, state.ball, now), &queue, now); state.p1.y = 0; state.p2.y = state.resolution[0] - 1; - phys.update(state, now); - + queue.execute_until(now + 100); +// phys.update(state, now); + queue.print(); +#ifdef GUI gui.draw(state, now); - usleep(40000); - +#endif +#if REALTIME == 1 + usleep(4000); double dt = std::chrono::duration_cast( (Clock::now() - loop_start)) .count(); now += dt; - // now += 40; +#elif REALTIME == 2 + now += 4; +#else + now += 1; + usleep(4000); +#endif loop_start = Clock::now(); } } return 0; } -} -} // openage::curvepong + + +}} // openage::curvepong diff --git a/libopenage/curve/demo/physics.cpp b/libopenage/curve/demo/physics.cpp index d069c59cfe..5e3c61e9d0 100644 --- a/libopenage/curve/demo/physics.cpp +++ b/libopenage/curve/demo/physics.cpp @@ -1,18 +1,25 @@ // Copyright 2015-2017 the openage authors. See copying.md for legal info. #include "physics.h" +#include "../../error/error.h" + +#include +#include #include -#include +#define GUI namespace openage { namespace curvepong { const float extrapolating_time = 100.0f; -const int init_recursion_limit = 50; -void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, const curve::curve_time_t &now) { +void Physics::processInput(PongState &state, + PongPlayer &player, + std::vector &events, + curve::EventQueue *queue, + const curve::curve_time_t &now) { for (auto evnt : events) { //Process only if the future has changed if (player.state.get(now).state != evnt.state) { @@ -29,7 +36,8 @@ void Physics::processInput(PongState &state, PongPlayer &player, std::vector state.resolution[1]) @@ -38,6 +46,7 @@ void Physics::processInput(PongState &state, PongPlayer &player, std::vector state.p1.position.get(now) - state.p1.size.get(now) / 2 - && pos[1] < state.p1.position.get(now) + state.p1.size.get(now) / 2 - && state.ball.speed.get(now)[0] < 0) { - //Ball hit the paddel in this frame - auto s = state.ball.speed.get(now); - s[0] *= -1.0; - state.ball.speed.set_drop(now, s); - state.ball.position.set_drop(now, pos); // this line can handle the future! - - update_ball(state, now, init_recursion_limit); - } else if (pos[0] >= state.resolution[0] - 1 - && pos[1] > state.p2.position.get(now) - state.p2.size.get(now) / 2 - && pos[1] < state.p2.position.get(now) + state.p2.size.get(now) / 2 - && state.ball.speed.get(now)[0] > 0) { - //Ball hit the paddel in this frame - auto s = state.ball.speed.get(now); - s[0] *= -1.0; - state.ball.speed.set_drop(now, s); - state.ball.position.set_drop(now, pos); // this line can handle the future! - - update_ball(state, now, init_recursion_limit); - } else if (state.ball.position.needs_update(now)) { - update_ball(state, now, init_recursion_limit); - } - - // Game loose condition - if (pos[0] < 0) { - state.p1.lives.set_drop(now, state.p1.lives.get(now) - 1); - state.p1.state.set_drop(now, event(state.p1.id, event::LOST)); - } - if (pos[0] > state.resolution[0]) { - state.p2.lives.set_drop(now, state.p2.lives.get(now) - 1); - state.p2.state.set_drop(now, event(state.p2.id, event::LOST)); - } +void Physics::reset(PongState &state, + curve::EventQueue *q, + const curve::curve_time_t &now) { + q->clear(now); + q->addcallback(now, "COLL WALL", + [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { + state.ball.position.set_drop(now, state.resolution * 0.5); + state.p1.position.set_drop(now, state.resolution[1] / 2); + state.p2.position.set_drop(now, state.resolution[1] / 2); + float dirx = (rand() % 2 * 2) - 1; + float diry = (rand() % 2 * 2) - 1; + auto init_speed = + util::Vector<2>( + dirx * (0.0001 + (rand() % 100) / 1000.f), + diry * (0.0001 + (rand() % 100) / 2000.f)); + + state.ball.speed.set_drop(now, init_speed); + auto pos = state.ball.position.get(now); + static int cnt = 0; + mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", + init_speed[0], + init_speed[1], + pos[0], + pos[1], + ++cnt); + predict_reflect_panel(state, queue, now); + predict_reflect_wall(state, queue, now); + }); } -void Physics::update_ball(PongState &state, const curve::curve_time_t &now, int recursion_limit) { - //calculate the ball takes to hit a wall. +void Physics::ball_reflect_wall(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); auto speed = state.ball.speed.get(now); +#ifndef GUI + std::cout << "\nWall\n"; +#else + static int cnt = 0; + mvprintw(22, 22, "Wall Reflect [%i]", ++cnt); + mvprintw(23, 22, "Speed[1] is %f", speed[1]); +#endif + speed[1] *= -1.0; + state.ball.speed.set_drop(now, speed); + state.ball.position.set_drop(now, pos); + + predict_reflect_wall(state, queue, now); +} + + +void Physics::predict_reflect_wall(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); - float ty = 0; - //char mode = ' '; - if (speed [1] > 0) { + double ty = 0; + if (speed[1] > 0) { ty = (state.resolution[1] - pos[1]) / speed[1]; - //mode = 'v'; } else if (speed[1] < 0) { ty = pos[1] / -speed[1]; - //mode = '^'; + } else { + throw Error(MSG(err) << "speed was 0"); } - -/* mvprintw(20 - recursion_limit, 1, "R %i: %c TY %f | pos: %f | %f speed %f | %f res %i | %i", - init_recursion_limit - recursion_limit, mode, - ty, - pos[0], pos[1], - speed[0], speed[1], - state.resolution[0], state.resolution[1] - ); -*/ +#ifdef GUI + mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); +#endif if (ty > 0) { auto hit_pos = pos + speed * ty; + hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; + //assert(hit_pos[0] >= 0); + assert(hit_pos[1] >= 0); state.ball.position.set_drop(now + ty, hit_pos); - speed[1] *= -1; - state.ball.speed.set_drop(now + ty, speed); - if (recursion_limit > 1) { - update_ball(state, now + ty, recursion_limit - 1); - } + queue->addcallback(now + ty, "COLL WALL", + [&state](curve::EventQueue *q, const curve::curve_time_t &t) { + ball_reflect_wall(state, q, t); + }); + } else { + throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); + } +} + + +void Physics::ball_reflect_panel(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +#ifdef GUI + static int cnt = 0; + mvprintw(21, 22, "Panel hit [%i] ", ++cnt); +#else + std::cout << "\nPanel\n"; +#endif + + if (pos[0] <= 1 + && speed[0] < 0 + && (pos[1] < state.p1.position.get(now) - state.p1.size.get(now) / 2 + || pos[1] > state.p1.position.get(now) + state.p1.size.get(now) / 2)) { + // Ball missed the paddel of player 1 + auto l = state.p1.lives(now); + l --; + state.p1.lives.set_drop(now, l); + state.ball.position.set_drop(now, pos); + reset(state, queue, now); + mvprintw(21, 18, "1"); + } else if (pos[0] >= state.resolution[0]-1 + && speed[0] > 0 + && (pos[1] < state.p2.position.get(now) - state.p2.size.get(now) / 2 + || pos[1] > state.p2.position.get(now) + state.p2.size.get(now) / 2)) { + // Ball missed the paddel of player 2 + auto l = state.p2.lives(now); + l --; + state.p2.lives.set_drop(now, l); + state.ball.position.set_drop(now, pos); + reset(state, queue, now); + mvprintw(21, 18, "2"); + } else if (pos[0] >= state.resolution[0]- 1 || pos[0] <= 1) { + speed[0] *= -1.0; + state.ball.speed.set_drop(now, speed); + state.ball.position.set_drop(now, pos); + predict_reflect_panel(state, queue, now); + } +} + + +void Physics::predict_reflect_panel(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +// speed[1] += (rand() % 50 - 50)/10; + float ty = 0; + if (speed[0] > 0) { + ty = (state.resolution[0] - pos[0]) / speed[0]; + } else if (speed[0] < 0) { + ty = pos[0] / -speed[0]; } +#ifdef GUI + mvprintw(21, 40, "AT %f NEXT %f", now, now + ty); + mvprintw(21, 18, "2"); +#endif + auto hit_pos = pos + speed * ty; + hit_pos[0] = speed[0] > 0 ? state.resolution[0] : 0; + assert(hit_pos[0] >= 0); +// assert(hit_pos[1] >= 0); // this might validly happen + state.ball.position.set_drop(now + ty, hit_pos); + queue->addcallback(now + ty, "COLL PANEL", + [&state](curve::EventQueue *q, const curve::curve_time_t &t) { + ball_reflect_panel(state, q, t); + }); + +// predict_reflect_wall(state, queue, now); } }} // openage::curvepong diff --git a/libopenage/curve/demo/physics.h b/libopenage/curve/demo/physics.h index cc6ccb3536..cd49415711 100644 --- a/libopenage/curve/demo/physics.h +++ b/libopenage/curve/demo/physics.h @@ -6,16 +6,24 @@ #include "gamestate.h" #include "../curve.h" +#include "../events.h" namespace openage { namespace curvepong { class Physics { public: - void processInput(PongState &, PongPlayer &, std::vector &events, const curve::curve_time_t &now); - void update(PongState &, const curve::curve_time_t &); + + void processInput(PongState &, PongPlayer &, std::vector &input, curve::EventQueue *, const curve::curve_time_t &now); protected: - void update_ball(PongState &, const curve::curve_time_t &, int recursion_limit); + + static void reset(PongState &, curve::EventQueue *, const curve::curve_time_t &); + + + static void ball_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void ball_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); }; }} // openage::curvepong diff --git a/libopenage/curve/demo_event/CMakeLists.txt b/libopenage/curve/demo_event/CMakeLists.txt deleted file mode 100644 index c1545e58c1..0000000000 --- a/libopenage/curve/demo_event/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_sources (libopenage - aicontroller.cpp - gamestate.cpp - gui.cpp - main.cpp - physics.cpp -) diff --git a/libopenage/curve/demo_event/aicontroller.cpp b/libopenage/curve/demo_event/aicontroller.cpp deleted file mode 100644 index 47ef8c0092..0000000000 --- a/libopenage/curve/demo_event/aicontroller.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "aicontroller.h" - -namespace openage { -namespace curvepong { - -std::vector &AIInput::getInputs( - const PongPlayer &player, - const PongBall &ball, - const curve::curve_time_t &now) { - this->event_cache.clear(); - - auto position = player.position.get(now); - - // Yes i know, there is /3 used - instead of the logical /2 - this is to - // create a small safety boundary of 1/3 for enhanced fancyness - - // Ball is below position - if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { - event_cache.push_back(event(player.id, event::DOWN)); - } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { - // Ball is above position - event_cache.push_back(event(player.id, event::UP)); - } - - return this->event_cache; -} - -}} // openage::curvepong diff --git a/libopenage/curve/demo_event/aicontroller.h b/libopenage/curve/demo_event/aicontroller.h deleted file mode 100644 index d87c455be1..0000000000 --- a/libopenage/curve/demo_event/aicontroller.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gamestate.h" - -namespace openage { -namespace curvepong { - -class AIInput { -public: - std::vector &getInputs( - const PongPlayer &player, - const PongBall &ball, - const curve::curve_time_t &now); - -private: - std::vector event_cache; -}; - -}} // openage::curvepong diff --git a/libopenage/curve/demo_event/gamestate.cpp b/libopenage/curve/demo_event/gamestate.cpp deleted file mode 100644 index 24df67232e..0000000000 --- a/libopenage/curve/demo_event/gamestate.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "gamestate.h" diff --git a/libopenage/curve/demo_event/gamestate.h b/libopenage/curve/demo_event/gamestate.h deleted file mode 100644 index ce2c4a742c..0000000000 --- a/libopenage/curve/demo_event/gamestate.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../continuous.h" -#include "../discrete.h" -#include "../../util/vector.h" - -namespace openage { -namespace curvepong { - -struct event { - int player; - enum state_e { - UP, DOWN, START, IDLE, LOST - } state; - event(int id, state_e s) : player(id), state(s) {} - event() : player(0), state(IDLE) {} -}; - -class PongPlayer { -public: - PongPlayer() { - speed.set_drop(0, 1); - position.set_drop(0, 0.5); - lives.set_drop(0, 1); - state.set_drop(0, event(0, event::IDLE)); - size.set_drop(0, 0.1); - y = 0; - id = 0; - } - - curve::Discrete speed; - curve::Continuous position; - curve::Discrete lives; - curve::Discrete state; - curve::Discrete size; - float y; - int id; -}; - -class PongBall { -public: - curve::Discrete> speed; - curve::Continuous> position; -}; - -class PongState { -public: - PongPlayer p1; - PongPlayer p2; - - PongBall ball; - - util::Vector<2> resolution; -}; - -}} // openage::curvepong diff --git a/libopenage/curve/demo_event/gui.cpp b/libopenage/curve/demo_event/gui.cpp deleted file mode 100644 index f55efab316..0000000000 --- a/libopenage/curve/demo_event/gui.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "gui.h" - -#include -#include - -namespace openage { -namespace curvepong { - -std::vector &Gui::getInputs(const PongPlayer &player) { - input_cache.clear(); - event evnt; - evnt.player = player.id; - evnt.state = event::IDLE; - timeout(0); - int c = getch(); - // mvprintw(0,1, "IN: %i", c); - switch (c) { - case KEY_DOWN: - evnt.state = event::DOWN; - input_cache.push_back(evnt); - mvprintw(1, 1, "DOWN"); - break; - case KEY_UP: - evnt.state = event::UP; - input_cache.push_back(evnt); - mvprintw(1, 1, "UP"); - break; - case ' ': evnt.state = event::START; break; - case 27: // esc or alt - endwin(); - exit(0); - default: break; - } - - return input_cache; -} - - -enum { - COLOR_PLAYER1 = 1, - COLOR_PLAYER2 = 2, - COLOR_BALL = 3, - COLOR_DEBUG = 4, - - COLOR_0 = 5, - COLOR_1 = 6, - COLOR_2 = 7, - COLOR_3 = 8, - COLOR_4 = 9, -}; - - -Gui::Gui() { - initscr(); - start_color(); - init_pair(COLOR_PLAYER1, COLOR_BLUE, COLOR_BLUE); - init_pair(COLOR_PLAYER2, COLOR_RED, COLOR_RED); - init_pair(COLOR_BALL, COLOR_BLUE, COLOR_WHITE); - init_pair(COLOR_DEBUG, COLOR_WHITE, COLOR_BLACK); - init_pair(COLOR_0, COLOR_RED, COLOR_BLACK); - init_pair(COLOR_1, COLOR_GREEN, COLOR_BLACK); - - keypad(stdscr, true); - noecho(); - curs_set(0); - // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); - - attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw( - 4, 5, " oooooooooo "); - mvprintw( - 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); - mvprintw( - 6, 5, " 888oooo88 888 888 888 888 888 88o "); - mvprintw( - 7, 5, " 888 888 888 888 888 888oo888o "); - mvprintw( - 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); - mvprintw( - 9, 5, " 888ooo888 "); - attroff(COLOR_PAIR(COLOR_DEBUG)); - - getch(); -} - - -void Gui::draw(PongState &state, const curve::curve_time_t &now) { - // clear(); - // Print Score - attron(COLOR_PAIR(COLOR_DEBUG)); - getmaxyx(stdscr, state.resolution[1], state.resolution[0]); - state.resolution[1] -= 1; - attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw(2, - state.resolution[0] / 2 - 5, - "P1 %i | P2 %i", - state.p1.lives(now), - state.p2.lives(now)); - - mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); - mvprintw(0, 1, "NOW: %f", now); - mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); - mvprintw(2, - 1, - "P1: %f, %f, %i", - state.p1.position(now), - state.p1.y, - state.p1.state(now).state); - mvprintw(3, - 1, - "P2: %f, %f, %i", - state.p2.position(now), - state.p2.y, - state.p2.state(now).state); - for (int i = 0; i < 1000; i += 100) { - mvprintw(4 + i / 100, - 1, - "BALL in %03i: %f | %f; SPEED: %f | %f", - i, - state.ball.position(now + i)[0], - state.ball.position(now + i)[1], - state.ball.speed(now + i)[0], - state.ball.speed(now + i)[1]); - } - mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); - attroff(COLOR_PAIR(COLOR_DEBUG)); - - attron(COLOR_PAIR(COLOR_PLAYER1)); - for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { - mvprintw(state.p1.position(now) + i, state.p1.y, "|"); - } - attroff(COLOR_PAIR(COLOR_PLAYER1)); - - attron(COLOR_PAIR(COLOR_PLAYER2)); - for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { - mvprintw(state.p2.position(now) + i, state.p2.y, "|"); - } - attroff(COLOR_PAIR(COLOR_PLAYER2)); - - attron(COLOR_PAIR(COLOR_1)); - for (int i = 1; i < 9999; ++i) { - draw_ball(state.ball.position(now + i), 'X'); - } - attron(COLOR_PAIR(COLOR_0)); - draw_ball(state.ball.position(now), 'M'); - /*attron(COLOR_PAIR(COLOR_BALL)); - mvprintw(state.ball.position(now)[1], - state.ball.position(now)[0], - "o"); - */ - attroff(COLOR_PAIR(COLOR_BALL)); - refresh(); - erase(); -} - - -void Gui::draw_ball(util::Vector<2> pos, char chr) { - mvprintw((int)(pos[1]), (int)(pos[0]), "%c", chr); - standend(); -} -}} // openage::curvepong diff --git a/libopenage/curve/demo_event/gui.h b/libopenage/curve/demo_event/gui.h deleted file mode 100644 index be2c152eec..0000000000 --- a/libopenage/curve/demo_event/gui.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gamestate.h" - -namespace openage { -namespace curvepong { - - -class Gui { - -public: - Gui(); - std::vector &getInputs(const PongPlayer &player); - void draw(PongState &state, const curve::curve_time_t &now); - void draw_ball(util::Vector<2> ball, char chr); - -private: - std::vector input_cache; -}; - -}} // openage::curvepong diff --git a/libopenage/curve/demo_event/main.cpp b/libopenage/curve/demo_event/main.cpp deleted file mode 100644 index 34d5ce4468..0000000000 --- a/libopenage/curve/demo_event/main.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include - -#include -#include - -#include "aicontroller.h" -#include "gamestate.h" -#include "gui.h" -#include "physics.h" - -typedef std::chrono::high_resolution_clock Clock; - -#define GUI -#define REALTIME -#undef HUMAN - -namespace openage { -namespace curvepong { - -int demo() { - // Restart forever -#ifdef GUI - curvepong::Gui gui; -#endif - curvepong::Physics phys; - curvepong::AIInput ai; - bool running = true; - curve::EventQueue queue; - srand(time(NULL)); - while (running) { - curvepong::PongState state; - curve::curve_time_t now = 1; - - state.p1.lives.set_drop(now, 3); - state.p1.id = 0; - state.p1.size.set_drop(now, 4); - state.p2.lives.set_drop(now, 3); - state.p2.id = 1; - state.p2.size.set_drop(now, 4); -#ifdef GUI - gui.draw(state, now); // update gui related parameters -#else - state.resolution[0] = 100; - state.resolution[1] = 40; -#endif - - auto loop_start = Clock::now(); - curve::curve_time_t last_now = now; - now += 1; - { - std::vector start_event { event(0, event::START) }; - phys.processInput(state, state.p1, start_event, &queue, now); - } - -#ifdef GUI - gui.draw(state, now); // initial drawing with corrected ball -#endif - while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { -#ifdef HUMAN - gui.getInputs(state.p1); - phys.processInput(state, state.p1, gui.getInputs(state.p1), &queue, now); -#else - phys.processInput( - state, state.p1, ai.getInputs(state.p1, state.ball, now), &queue, now); -#endif - phys.processInput( - state, state.p2, ai.getInputs(state.p2, state.ball, now), &queue, now); - - state.p1.y = 0; - state.p2.y = state.resolution[0] - 1; - - queue.execute_until(now + 10); - last_now = now; -// phys.update(state, now); - queue.print(); -#ifdef GUI - gui.draw(state, now); -#endif -#ifdef REALTIME - usleep(4000); - double dt = std::chrono::duration_cast( - (Clock::now() - loop_start)) - .count(); - now += dt; -#else - now += 4; -#endif - loop_start = Clock::now(); - } - } - return 0; -} - - -}} // openage::curvepong diff --git a/libopenage/curve/demo_event/physics.cpp b/libopenage/curve/demo_event/physics.cpp deleted file mode 100644 index b71ddca478..0000000000 --- a/libopenage/curve/demo_event/physics.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "physics.h" -#include "../../error/error.h" - -#include -#include -#include - -#define GUI - -namespace openage { -namespace curvepong { - -const float extrapolating_time = 100.0f; - -void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, curve::EventQueue *queue, const curve::curve_time_t &now) { - for (auto evnt : events) { - //Process only if the future has changed - if (player.state.get(now).state != evnt.state) { - player.state.set_drop(now, evnt); - - switch(evnt.state) { - case event::UP: - case event::DOWN: { - if (evnt.state == event::UP) { - player.speed.set_drop(now, -2); - } else if (evnt.state == event::DOWN) { - player.speed.set_drop(now, 2); - } - player.speed.set_drop(now + extrapolating_time, 0); - - float new_pos = player.position.get(now) + - (player.speed.get(now+extrapolating_time) - player.speed.get(now) / 2 + player.speed.get(now)); - if (new_pos < 0) - new_pos = 0; - if (new_pos > state.resolution[1]) - new_pos = state.resolution[1]; - - player.position.set_drop(now+extrapolating_time, new_pos); - evnt.state = event::IDLE; - player.state.set_drop(now + extrapolating_time, evnt); -// predict_reflect_panel(state, queue, now); - break; - } - case event::IDLE: - player.position.set_drop(now+extrapolating_time, - player.position.get(now)); - break; - case event::START: - reset(state, queue, now); - break; - - //if (player.state.get(now).state == event::LOST) { - // state.ball.position.set_drop(now, state.resolution * 0.5); - //} - //update_ball(state, now, init_recursion_limit); - //break; - default: - break; - } - } - } -} - - -void Physics::reset(PongState &state, curve::EventQueue *q, const curve::curve_time_t &gnow) { - q->clear(); - auto now = gnow + 0.001; - state.ball.position.set_drop(now, state.resolution * 0.5); - state.p1.position.set_drop(now, state.resolution[1] / 2); - state.p2.position.set_drop(now, state.resolution[1] / 2); - - float dirx = (rand() % 2 * 2) - 1; - float diry = (rand() % 2 * 2) - 1; - auto init_speed = - util::Vector<2>( - dirx * (0.0001 + (rand() % 100) / 1000.f), - diry * (0.0001 + (rand() % 100) / 2000.f)); - - state.ball.speed.set_drop(now, init_speed); - auto pos = state.ball.position.get(now); - static int cnt = 0; - mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", init_speed[0], init_speed[1], pos[0], pos[1], ++cnt); - predict_reflect_panel(state, q, now); - predict_reflect_wall(state, q, now); -} - - -void Physics::ball_reflect_wall(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -#ifndef GUI - std::cout << "\nWall\n"; -#else - static int cnt = 0; - mvprintw(22, 22, "Wall Reflect [%i]", ++cnt); - mvprintw(23, 22, "Speed[1] is %f", speed[1]); -#endif - speed[1] *= -1.0; - state.ball.speed.set_drop(now, speed); - state.ball.position.set_drop(now, pos); - - predict_reflect_wall(state, queue, now); -} - - -void Physics::predict_reflect_wall(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); - - double ty = 0; - if (speed[1] > 0) { - ty = (state.resolution[1] - pos[1]) / speed[1]; - } else if (speed[1] < 0) { - ty = pos[1] / -speed[1]; - } else { - throw Error(MSG(err) << "speed was 0"); - } -#ifdef GUI - mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); -#endif - if (ty > 0) { - auto hit_pos = pos + speed * ty; - hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; - //assert(hit_pos[0] >= 0); - assert(hit_pos[1] >= 0); - state.ball.position.set_drop(now + ty, hit_pos); - queue->addcallback(now + ty, "COLL WALL", - [&state](curve::EventQueue *q, const curve::curve_time_t &t) { - ball_reflect_wall(state, q, t); - }); - } else { - throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); - } -} - - -void Physics::ball_reflect_panel(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { - - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -#ifdef GUI - static int cnt = 0; - mvprintw(21, 22, "Panel hit [%i] ", ++cnt); -#else - std::cout << "\nPanel\n"; -#endif - - if (pos[0] <= 1 - && speed[0] < 0 - && (pos[1] < state.p1.position.get(now) - state.p1.size.get(now) / 2 - || pos[1] > state.p1.position.get(now) + state.p1.size.get(now) / 2)) { - // Ball missed the paddel of player 1 - auto l = state.p1.lives(now); - l --; - state.p1.lives.set_drop(now, l); - reset(state, queue, now); - mvprintw(21, 18, "1"); - return; - } else if (pos[0] >= state.resolution[0]-1 - && speed[0] > 0 - && (pos[1] < state.p2.position.get(now) - state.p2.size.get(now) / 2 - || pos[1] > state.p2.position.get(now) + state.p2.size.get(now) / 2)) { - // Ball missed the paddel of player 2 - auto l = state.p2.lives(now); - l --; - state.p2.lives.set_drop(now, l); - reset(state, queue, now); - mvprintw(21, 18, "2"); - return; - } else if(pos[0] >= state.resolution[0]- 1 || pos[0] <= 1) { - speed[0] *= -1.0; - state.ball.speed.set_drop(now, speed); - state.ball.position.set_drop(now, pos); - predict_reflect_panel(state, queue, now); - } -} - - -void Physics::predict_reflect_panel(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -// speed[1] += (rand() % 50 - 50)/10; - float ty = 0; - if (speed[0] > 0) { - ty = (state.resolution[0] - pos[0]) / speed[0]; - } else if (speed[0] < 0) { - ty = pos[0] / -speed[0]; - } -#ifdef GUI - mvprintw(21, 40, "AT %f NEXT %f", now, now + ty); - mvprintw(21, 18, "2"); -#endif - auto hit_pos = pos + speed * ty; - hit_pos[0] = speed[0] > 0 ? state.resolution[0] : 0; - assert(hit_pos[0] >= 0); -// assert(hit_pos[1] >= 0); // this might validly happen - state.ball.position.set_drop(now + ty, hit_pos); - queue->addcallback(now + ty, "COLL PANEL", - [&state](curve::EventQueue *q, const curve::curve_time_t &t) { - ball_reflect_panel(state, q, t); - }); - -// predict_reflect_wall(state, queue, now); -} - -}} // openage::curvepong diff --git a/libopenage/curve/demo_event/physics.h b/libopenage/curve/demo_event/physics.h deleted file mode 100644 index cd49415711..0000000000 --- a/libopenage/curve/demo_event/physics.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gamestate.h" -#include "../curve.h" -#include "../events.h" - -namespace openage { -namespace curvepong { - -class Physics { -public: - - void processInput(PongState &, PongPlayer &, std::vector &input, curve::EventQueue *, const curve::curve_time_t &now); -protected: - - static void reset(PongState &, curve::EventQueue *, const curve::curve_time_t &); - - - static void ball_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void ball_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); -}; - -}} // openage::curvepong diff --git a/libopenage/curve/discrete.cpp b/libopenage/curve/discrete.cpp index b233479b67..f0c58b4328 100644 --- a/libopenage/curve/discrete.cpp +++ b/libopenage/curve/discrete.cpp @@ -5,4 +5,6 @@ namespace openage { namespace curve { +// This file is intended to be empty + }} // openage::curve diff --git a/libopenage/curve/discrete.h b/libopenage/curve/discrete.h index a95343eeba..a4615578c8 100644 --- a/libopenage/curve/discrete.h +++ b/libopenage/curve/discrete.h @@ -7,9 +7,22 @@ namespace openage { namespace curve { +/** + * Does not interpolate between values. The template type does only need to + * implement `operator=` and copy ctor. + */ template class Discrete : public ValueContainer<_T> { + static_assert(std::is_copy_assignable<_T>::value, + "Template type is not copy assignable"); + static_assert(std::is_copy_constructible<_T>::value, + "Template type is not copy constructible"); public: + using ValueContainer<_T>::ValueContainer; + + /** + * Does not interpolate anything, just gives the raw value of the keyframe + */ _T get(const curve_time_t &) const override; }; diff --git a/libopenage/curve/eventqueue.md b/libopenage/curve/eventqueue.md new file mode 100644 index 0000000000..9a44c5a735 --- /dev/null +++ b/libopenage/curve/eventqueue.md @@ -0,0 +1,115 @@ +Event Queue Magic +===================== + +The Event Queue consists of Events and their Context: + +``` +struct Event { + +/// Unique Identificator for exactly this event. +int32_t event_id; + +/// Time this event should trigger +curve_time_ time_triggers; + +/// Class of the event +EventClass eventclass + +/// Curve Object this Event relates to +CurveObject context + +std::function + namespace openage { namespace curve { #define GUI -EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, - const std::string &name, - const EventQueue::condition &precond, - const EventQueue::callback &trigger) { - return addcallback(Event(at, name, trigger, precond, ++last_event_id)); -} +// FIXME convert all these std::functions into our own datatype that stores all requirements. EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, - const std::string &name, - const EventQueue::condition_void &precond, - const EventQueue::callback_void &trigger) { - return addcallback(Event(at, name, - [trigger](EventQueue *q, const curve_time_t &) { trigger(q); }, - [precond](const curve_time_t &) { return precond(); }, - ++last_event_id)); -} - - -EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, - const std::string &name, + const EventQueue::Eventclass &eventclass, const EventQueue::callback &trigger) { - return this->addcallback(at, name, &EventQueue::_true, trigger); + return addcallback(Event(at, eventclass, trigger, ++last_event_id)); } EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, - const std::string &name, + const EventQueue::Eventclass &eventclass, const EventQueue::callback_void &trigger) { - return this->addcallback(at, name, &EventQueue::_true, [trigger](EventQueue *q, const curve_time_t &) { - trigger(q); - }); + return addcallback(at, eventclass, + [trigger](EventQueue *q, const curve_time_t &) { + trigger(q); + }); } @@ -46,7 +33,7 @@ EventQueue::Handle EventQueue::addcallback (const EventQueue::Event &e) { auto it = queue.begin(); // Iterate to find the right insertion position - for(; it != queue.end() && it->time < e.time; ++it) {} + for (; it != queue.end() && it->time < e.time; ++it) {} queue.insert(it, e); @@ -55,6 +42,20 @@ EventQueue::Handle EventQueue::addcallback (const EventQueue::Event &e) { } +void EventQueue::reschedule(const EventQueue::Handle &handle, + const curve_time_t &new_time) { + auto it = resolve_handle(handle); + if (it != queue.end()) { + Event evnt = *it; + queue.erase(it); + evnt.time = new_time; + addcallback(evnt); + } else { + // the event was either not valid or has already been executed. + } +} + + void EventQueue::execute_until(const curve_time_t &time) { #ifndef GUI std::cout << "\rNOW: " << time; @@ -74,7 +75,6 @@ void EventQueue::execute_until(const curve_time_t &time) { it->event(this, tmp.time); past.push_back(tmp); - if (this->cleared) { this->cleared = false; break; @@ -82,11 +82,33 @@ void EventQueue::execute_until(const curve_time_t &time) { } } + +void EventQueue::remove(const EventQueue::Handle &handle) { + for (auto it = queue.begin(); it != queue.end(); ++it) { + if (it->event_id == handle.event_id) { + it = queue.erase(it); + break; + } + } +} + + +std::deque::iterator EventQueue::resolve_handle( + const EventQueue::Handle &handle) { + for (auto it = queue.begin(); it != queue.end(); ++it) { + if (it->event_id == handle.event_id) { + return it; + } + } + return queue.end(); +} + + void EventQueue::print() { #ifndef GUI std::cout << "Queue: " << std::endl; for (const auto &i : queue) { - std::cout << i.time << ": " << i.event_id << i.event_name <time < time; ++it) {} - for(; it != queue.end(); it = queue.erase(it) ) {} + for (; it != queue.end() && it->time < time; ++it) {} + for (; it != queue.end(); it = queue.erase(it) ) {} } -bool EventQueue::_true(const curve_time_t &) { - return true; -} - -}} // namespace openage::curve +}} // eventclassspace openage::curve diff --git a/libopenage/curve/events.h b/libopenage/curve/events.h index 9200c6a940..3009b7cc91 100644 --- a/libopenage/curve/events.h +++ b/libopenage/curve/events.h @@ -10,77 +10,138 @@ namespace openage { namespace curve { +/** + * Event container that can execute and manage the stuff. + */ class EventQueue { - public: + /** Callback with eventqueue and time as arguments */ typedef std::function callback; - typedef std::function condition; + /** Callback with only the eventqueue as argument */ typedef std::function callback_void; - typedef std::function condition_void; + /** Class of events - this identifies a type of event */ + typedef std::string Eventclass; + + /** + * One single event that will be executed. This can be rescheduled, but the + * event id will never change. + */ class Event { friend class EventQueue; private: - Event(const curve_time_t &time, const std::string &name, const callback &event, const condition &/*cond*/, const int event_id) : + /** An event can only be constructed in the event queue */ + Event(const curve_time_t &time, + const Eventclass &eventclass, + const callback &event, + const int event_id) : event_id{event_id}, time{time}, - name(name), - event{event} - //precond(precond) - {} + eventclass(eventclass), + event{event} {} + + /** The Event id is only relevant within the eventqueue */ int event_id; public: + /** Copy c'tor */ Event(const Event &rhs) : - event_id(rhs.event_id), time(rhs.time), name(rhs.name), event(rhs.event) {} + event_id(rhs.event_id), + time(rhs.time), + eventclass(rhs.eventclass), + event(rhs.event) {} + /** when will this be executed */ curve_time_t time; - std::string name; + /** class of the event, used for identification */ + Eventclass eventclass; + /** The event itself */ callback event; -// condition precond; - bool precond(const curve_time_t &) const { return true; }; }; + + /** + * Handle to be able to communicate with the event that has been stored. + * uses Event::event_id for identification. + */ class Handle { friend class EventQueue; + public: + Handle() : + Handle(0) {}; + private: + /** Can only be constructed from the EventQueue scope */ Handle(const int event_id) : event_id(event_id) {} - const int event_id; + /** Identificator */ + int event_id; }; + /** Default c'ctor */ EventQueue(const curve_time_t &backlog_time = 1000) : cleared{false}, backlog_time(backlog_time) {} - Handle addcallback (const curve_time_t &at, const std::string &name, const condition &, const callback &); - Handle addcallback (const curve_time_t &at, const std::string &name, const condition_void &, const callback_void &); + /** + * Add a callback - with an event class that takes queue and time as + * arguments + */ + Handle addcallback (const curve_time_t &at, const Eventclass &eventclass, const callback &); - Handle addcallback (const curve_time_t &at, const std::string &name, const callback &); - Handle addcallback (const curve_time_t &at, const std::string &name, const callback_void &); + /** + * Add a callback - with an event class that takes only queue as arguments + */ + Handle addcallback (const curve_time_t &at, const Eventclass &eventclass, const callback_void &); + /** Add a callback created from an event */ Handle addcallback (const Event &); + /** + * Take an event and reschedule the time, if it has not yet been executed + */ + void reschedule(const Handle &, const curve_time_t &time); + + /** + * Iteratively take the events and execute them one by one. The Queue may + * be changed during execution. + */ void execute_until(const curve_time_t &t); + /** + * Remove an event from execution, if it has not been executed yet. + */ + void remove(const Handle &); + + /** + * Remove all events from the queue + */ void clear(); - // Clear the queue from this time on. + /** + * Clear the queue from this time on. + */ void clear(const curve_time_t &); + /** + * Count the number of events that might be executed. This is only a internal + * identification number. + */ size_t size() { return queue.size(); } + /** + * Number printer + */ void print(); private: + std::deque::iterator resolve_handle(const Handle &handle); std::deque queue; std::deque past; - bool cleared; + bool cleared; int last_event_id = 0; - const curve_time_t backlog_time; - static bool _true(const curve_time_t &); }; }} // namespace openage::curve diff --git a/libopenage/curve/internal/value_container.h b/libopenage/curve/internal/value_container.h index 6070d1c853..080bd10420 100644 --- a/libopenage/curve/internal/value_container.h +++ b/libopenage/curve/internal/value_container.h @@ -2,16 +2,19 @@ #pragma once +#include "../trigger.h" #include "keyframe_container.h" + #include namespace openage { namespace curve { template -class ValueContainer { +class ValueContainer : public Trigger { public: - ValueContainer() : + ValueContainer(TriggerFactory *trigger) : + Trigger(trigger), last_element{container.begin()} {} virtual _T get(const curve_time_t &t) const = 0; @@ -35,7 +38,6 @@ class ValueContainer { }; - template void ValueContainer<_T>::set_drop(const curve_time_t &at, const _T &value) { auto hint = this->container.last(at, this->last_element); @@ -49,19 +51,25 @@ void ValueContainer<_T>::set_drop(const curve_time_t &at, const _T &value) { container.insert(at, value, hint); this->last_element = hint; + + this->data_changed(1, at); } + template void ValueContainer<_T>::set_insert(const curve_time_t &at, const _T &value) { this->container.insert(at, value, this->last_element); + this->data_changed(1, at); } + template std::pair ValueContainer<_T>::frame(const curve_time_t &time) const { auto e = this->container.last(time, this->container.end()); return std::make_pair(e->time, e->value); } + template std::pair ValueContainer<_T>::next_frame(const curve_time_t &time) const { auto e = this->container.last(time, this->container.end()); @@ -69,6 +77,7 @@ std::pair ValueContainer<_T>::next_frame(const curve_ti return std::make_pair(e->time, e->value); } + template bool ValueContainer<_T>::needs_update(const curve_time_t &at) { auto e = this->container.last(at, this->container.end()); @@ -79,4 +88,5 @@ bool ValueContainer<_T>::needs_update(const curve_time_t &at) { } } + }} // openage::curve diff --git a/libopenage/curve/iterator.cpp b/libopenage/curve/iterator.cpp new file mode 100644 index 0000000000..5f0f97c901 --- /dev/null +++ b/libopenage/curve/iterator.cpp @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "iterator.h" + +namespace openage { +namespace curve { + +// This file is intended to be empty + +}} // namespace openage::curve diff --git a/libopenage/curve/iterator.h b/libopenage/curve/iterator.h index 8e48c34d44..eb3f6306cf 100644 --- a/libopenage/curve/iterator.h +++ b/libopenage/curve/iterator.h @@ -7,35 +7,54 @@ namespace openage { namespace curve { +/** + * Default interface for curve containers + */ template class CurveIterator { public: + /** + * access the value of the iterator + */ virtual const val_t &value() const = 0; + + /** + * Check if the iterator is still valid + * (this breaks from the stl - in the best way) + */ virtual bool valid() const = 0; + /** + * The iterator needs a reference to the container + */ explicit CurveIterator(const container_t *c): _base{}, container{c}, from{-std::numeric_limits::infinity()}, to{+std::numeric_limits::infinity()} {} + /** Default copy c'tor */ CurveIterator (const CurveIterator &) = default; + + /** Default assignment operator */ CurveIterator &operator= ( const CurveIterator &) = default; + /** Dereference will call the virtual function */ virtual const val_t &operator *() const { return this->value(); } + /** Dereference will call the virutal function */ virtual const val_t *operator ->() const { return &this->value(); } /** * For equalness only the base iterator will be testet - not the timespans - * *this is defined in. + * this is defined in. */ virtual bool operator ==(const CurveIterator &rhs) const { return this->_base == rhs._base; @@ -43,16 +62,12 @@ class CurveIterator { /** * For unequalness only the base iterator will be testet - not the timespans - * *this is defined in. + * this is defined in. */ virtual bool operator !=(const CurveIterator &rhs) const { return this->_base != rhs._base; } -// virtual bool operator !=(const iterator_t &rhs) const { -// return this->base != rhs; -// } - /** * Advance to the next valid element. */ @@ -63,18 +78,30 @@ class CurveIterator { return *this; } + /** + * Access the underlying + */ const iterator_t &base() const { return _base; } + /** + * Access the lower end value of the defined time frame + */ const curve_time_t &_from() const { return from; } + /** + * Access the higher end value of the defined time frame + */ const curve_time_t &_to() const { return to; } protected: + /** + * Can only be constructed from the referenced container + */ CurveIterator(const iterator_t &base, const container_t *container, const curve_time_t &from, diff --git a/libopenage/curve/map.cpp b/libopenage/curve/map.cpp new file mode 100644 index 0000000000..a1713e56c8 --- /dev/null +++ b/libopenage/curve/map.cpp @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "map.h" + +namespace openage { +namespace curve { + +// This file is intended to be empty + +}} // namespace openage::curve diff --git a/libopenage/curve/map.h b/libopenage/curve/map.h index ad792fed8f..f9480c2175 100644 --- a/libopenage/curve/map.h +++ b/libopenage/curve/map.h @@ -2,16 +2,22 @@ #pragma once -#include - #include "curve.h" #include "map_filter_iterator.h" +#include +#include + namespace openage { namespace curve { +/** + * Map that keeps track of the lifetime of the contained elements. + * make shure, that no key is never reused. + */ template class UnorderedMap { + /** Internal container to access all data and metadata */ struct map_element { val_t value; curve_time_t alive; @@ -21,6 +27,7 @@ class UnorderedMap { alive(a), dead(d) {} }; + /** the magic is inside here */ std::unordered_map container; public: diff --git a/libopenage/curve/map_filter_iterator.cpp b/libopenage/curve/map_filter_iterator.cpp new file mode 100644 index 0000000000..17b743f145 --- /dev/null +++ b/libopenage/curve/map_filter_iterator.cpp @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "map_filter_iterator.h" + +namespace openage { +namespace curve { + +// This file is intended to be empty + +}} // namespace openage::curve diff --git a/libopenage/curve/map_filter_iterator.h b/libopenage/curve/map_filter_iterator.h index 7e112e745a..3328172ea2 100644 --- a/libopenage/curve/map_filter_iterator.h +++ b/libopenage/curve/map_filter_iterator.h @@ -2,12 +2,12 @@ #pragma once -#include -#include - #include "curve.h" #include "iterator.h" +#include +#include + namespace openage { namespace curve { diff --git a/libopenage/curve/object.h b/libopenage/curve/object.h new file mode 100644 index 0000000000..ace66404a8 --- /dev/null +++ b/libopenage/curve/object.h @@ -0,0 +1,23 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +namespace openage { +namespace curve { + +#include "internal/value_container.h" + +/** + * A Curve Object is a ordered collection of internal curves. Every sub-curve + * needs to be registered at this parent element. + */ +class Object : public Trigger { +public: + Object(TriggerFactory *factory) : + Trigger(factory, parent) {}; + +private: + +}; + +}} // openage :: curve diff --git a/libopenage/curve/queue.cpp b/libopenage/curve/queue.cpp index ead1a50d67..ce40d6ce9d 100644 --- a/libopenage/curve/queue.cpp +++ b/libopenage/curve/queue.cpp @@ -5,4 +5,4 @@ namespace openage { namespace curve { -}} // openage::curve +}} // namespace openage::curve diff --git a/libopenage/curve/queue.h b/libopenage/curve/queue.h index bec6448b00..8e8071d76f 100644 --- a/libopenage/curve/queue.h +++ b/libopenage/curve/queue.h @@ -11,6 +11,11 @@ namespace openage { namespace curve { +/** + * A container that manages events on a timeline. Every event has exactly one + * time it will happen. + * This container can be used to store interactions + */ template class Queue { struct queue_wrapper { diff --git a/libopenage/curve/queue_filter_iterator.cpp b/libopenage/curve/queue_filter_iterator.cpp new file mode 100644 index 0000000000..d80d8a581d --- /dev/null +++ b/libopenage/curve/queue_filter_iterator.cpp @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "queue_filter_iterator.h" + +namespace openage { +namespace curve { + +// This file is intended to be empty + +}} // namespace openage::curve diff --git a/libopenage/curve/queue_filter_iterator.h b/libopenage/curve/queue_filter_iterator.h index f48899f254..c752b4fcd6 100644 --- a/libopenage/curve/queue_filter_iterator.h +++ b/libopenage/curve/queue_filter_iterator.h @@ -2,12 +2,12 @@ #pragma once -#include -#include - #include "curve.h" #include "iterator.h" +#include +#include + namespace openage { namespace curve { diff --git a/libopenage/curve/test/CMakeLists.txt b/libopenage/curve/test/CMakeLists.txt index b8e6d6a6a3..7c1f6634c7 100644 --- a/libopenage/curve/test/CMakeLists.txt +++ b/libopenage/curve/test/CMakeLists.txt @@ -3,6 +3,7 @@ link_libraries(tube) add_sources(libopenage test_container.cpp test_curve_types.cpp - test_serialization.cpp test_events.cpp + test_serialization.cpp + test_trigger.cpp ) diff --git a/libopenage/curve/test/test_curve_types.cpp b/libopenage/curve/test/test_curve_types.cpp index f660ddbd9e..1ec1c3d680 100644 --- a/libopenage/curve/test/test_curve_types.cpp +++ b/libopenage/curve/test/test_curve_types.cpp @@ -13,6 +13,8 @@ namespace tests { void curve_types() { // Check the base container type + EventQueue q; + TriggerFactory f{&q}; { KeyframeContainer c; auto p0 = c.insert(0, 0); @@ -63,7 +65,7 @@ void curve_types() { // Check the Simple Continuous type { - Continuous c; + Continuous c(&f); c.set_insert(0, 0); c.set_insert(10, 1); @@ -73,7 +75,7 @@ void curve_types() { } { - Continuous c; + Continuous c(&f); c.set_insert(0, 0); c.set_insert(20, 20); @@ -89,7 +91,7 @@ void curve_types() { //Check the discrete type { - Discrete c; + Discrete c(&f); c.set_insert(0, 0); c.set_insert(10, 10); @@ -97,7 +99,7 @@ void curve_types() { TESTEQUALS(c.get(1), 0); TESTEQUALS(c.get(10), 10); - Discrete complex; + Discrete complex(&f); complex.set_insert(0, "Test 0"); complex.set_insert(10, "Test 10"); @@ -110,7 +112,7 @@ void curve_types() { //check set_drop { - Discrete c; + Discrete c(&f); c.set_insert(0, 0); c.set_insert(1, 1); c.set_insert(3, 3); @@ -123,7 +125,7 @@ void curve_types() { // Encountered Errors { - Continuous c; + Continuous c(&f); c.set_insert(1, 1); c.set_drop(1, -5); diff --git a/libopenage/curve/test/test_trigger.cpp b/libopenage/curve/test/test_trigger.cpp new file mode 100644 index 0000000000..1a9e0d6edb --- /dev/null +++ b/libopenage/curve/test/test_trigger.cpp @@ -0,0 +1,64 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "../../testing/testing.h" +#include "../trigger.h" + +#include +#include + +namespace openage { +namespace curve { +namespace tests { + +void trigger() { + { + EventQueue q; + TriggerFactory factory{&q}; + std::vector lst; + Trigger a (&factory); + + a.on_change(10, "change", [&lst](EventQueue *, const curve_time_t &) { + lst.push_back("change"); + }); + + a.on_pre_horizon(100, "horizon", [&lst](EventQueue *, const curve_time_t &) { + lst.push_back("horizon"); + }); + + a.on_pass_keyframe("keyframe", [&lst](EventQueue *, const curve_time_t &) { + lst.push_back("keyframe"); + }); + + a.on_change_future("future", [&lst](EventQueue *, const curve_time_t &) { + lst.push_back("future"); + }); + + a.data_changed(1, 50); + + q.execute_until(20); + TESTEQUALS(lst.size(), 2); + TESTEQUALS(lst[0], "future"); + TESTEQUALS(lst[1], "change"); + + a.data_changed(2, 50); + lst.clear(); + q.execute_until(20); + TESTEQUALS(lst.size(), 1); + TESTEQUALS(lst[0], "future"); + + lst.clear(); + a.passed_keyframe(10); + q.execute_until(20); + TESTEQUALS(lst.size(), 1); + TESTEQUALS(lst[0], "keyframe"); + + lst.clear(); + q.execute_until(120); + TESTEQUALS(lst.size(), 1); + TESTEQUALS(lst[0], "horizon"); + } +} + +}}} // openage::curve::tests diff --git a/libopenage/curve/trigger.cpp b/libopenage/curve/trigger.cpp new file mode 100644 index 0000000000..05158ca04f --- /dev/null +++ b/libopenage/curve/trigger.cpp @@ -0,0 +1,109 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "trigger.h" + +namespace openage { +namespace curve { + +Trigger::Trigger(class TriggerFactory *factory) : + factory{factory} { +} + + +Trigger::~Trigger() { + clearevents(); + factory->remove(this); +} + + +void Trigger::on_change_future(const EventQueue::Eventclass &eventclass, + const Trigger::change_event &event) { + EventTrigger trg{event, eventclass, 0}; + change_future_queue.insert(insert_pos(trg, change_future_queue), trg); +} + + +void Trigger::on_pass_keyframe(const EventQueue::Eventclass &eventclass, + const Trigger::change_event &event) { + EventTrigger trg{event, eventclass, 0}; + change_pass_keyframe_queue.insert(insert_pos(trg, change_pass_keyframe_queue), trg); +} + + +void Trigger::on_pre_horizon(const curve_time_t &time, + const EventQueue::Eventclass &eventclass, + const Trigger::change_event &event) { + EventTrigger trg{event, eventclass, time}; + factory->enqueue(this, trg); +} + + +void Trigger::on_change(const curve_time_t &time, + const EventQueue::Eventclass &eventclass, + const Trigger::change_event &event) { + EventTriggerChange trg{event, eventclass, time}; + change_queue.insert(insert_pos(trg, change_queue), trg); +} + + +void Trigger::clearevents() { + factory->remove(this); + change_future_queue.clear(); + change_pass_keyframe_queue.clear(); + change_queue.clear(); + +} + + +void Trigger::data_changed(const curve_time_t &now, + const curve_time_t &changed_at) { + // on_change_future will always happen when something changes + for (auto &e : change_future_queue) { + handles.push_back(EventTriggerHandle(e, factory->enqueue(this, e, now))); + } + + for (auto &e : change_queue) { + if (e.is_inserted) { + factory->reschedule(e.handle, changed_at); + } else { + EventQueue::Handle h = factory->enqueue(this, e); + e.handle = h; + e.is_inserted = true; + } + } +} + + +void Trigger::passed_keyframe(const curve_time_t &time) { + for (auto &e : change_pass_keyframe_queue) { + handles.push_back(EventTriggerHandle(e, factory->enqueue(this, e, time))); + } +} + + +EventQueue::Handle TriggerFactory::enqueue(Trigger */*trigger*/, const Trigger::EventTrigger &trg) { + return queue->addcallback(trg.time, trg.eventclass, trg.event); +} + + +EventQueue::Handle TriggerFactory::enqueue(Trigger */*trigger*/, + const Trigger::EventTrigger &trg, + const curve_time_t &time) { + return queue->addcallback(time, trg.eventclass, trg.event); +} + + +void TriggerFactory::remove(Trigger *t) { + for (const auto &handle : t->handles) { + queue->remove(handle.next_handle); + } + t->handles.clear(); +} + + +void TriggerFactory::reschedule(const EventQueue::Handle &handle, + const curve_time_t &new_time) { + queue->reschedule(handle, new_time); +} + +}} // namespace openage::curve diff --git a/libopenage/curve/trigger.h b/libopenage/curve/trigger.h new file mode 100644 index 0000000000..bba5b59827 --- /dev/null +++ b/libopenage/curve/trigger.h @@ -0,0 +1,176 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "events.h" + +#include + +namespace openage { +namespace curve { + +/* Forward declaration of testing methods */ +namespace tests { +void trigger(); +} + +class TriggerFactor; + +/** + * A Trigger is a entity, that where one can subscripe its change interface. + * It will keep track of everything for change observation on top of event queue. + */ +class Trigger { + friend class TriggerFactory; + friend void tests::trigger(); // the test needs access to data_canged +public: + typedef std::function change_event; + + Trigger(class TriggerFactory *factory); + + virtual ~Trigger(); + + /** + * Will be triggered when anything changes - immediately. + */ + void on_change_future(const EventQueue::Eventclass &, const change_event &); + + /** + * Will be triggered whenever you pass a keyframe, that is not relevant for execution anymore + */ + void on_pass_keyframe(const EventQueue::Eventclass &, const change_event &); + + /** + * Will be triggred whenever execution passes this event frame + */ + void on_pre_horizon(const curve_time_t &time, const EventQueue::Eventclass &, const change_event &); + + /** + * When the queue has changed, this event will be triggered at the referenced + * time frame/ + */ + void on_change(const curve_time_t &time, const EventQueue::Eventclass &, const change_event &); + + /** + * remove all events that are registered with the event queue at the moment + */ + void clearevents(); +protected: + + /** + * This method is to be called whenever a keyframe changes. It will take care + * to enqueue the appropriate events into the main event queue. + */ + void data_changed(const curve_time_t &now, const curve_time_t &changed_at); + + /** TODO this method is still to do. */ + void passed_keyframe(const curve_time_t &); + +private: + TriggerFactory *factory; + + /** + * Contains all relevant information for triggering of events + */ + struct EventTrigger { + EventTrigger(const change_event &event, + const EventQueue::Eventclass &eventclass, + const curve_time_t time) : + event{event}, + eventclass{eventclass}, + time{time} {} + /// The callback to invoke + change_event event; + + /// The event group this is related + EventQueue::Eventclass eventclass; + + /// The time this event is scheduled + curve_time_t time; + }; + + /** + * Contains all relevant information that are contained in the pending queue + */ + struct EventTriggerHandle { + EventTriggerHandle(const EventTrigger &trigger, + const EventQueue::Handle &handle) : + trigger{trigger}, + next_handle{handle} {} + EventTrigger trigger; + EventQueue::Handle next_handle; + }; + + /** + * Specific trigger for on_change events + **/ + class EventTriggerChange : public EventTrigger { + public: + using EventTrigger::EventTrigger; + bool is_inserted = false; + EventQueue::Handle handle; + }; + + /** + * Enqueued event handles - these events are registered with the referenced + * factory + */ + std::vector handles; + + /** + * Storage of registered events, that are not only stored within the global + * event queue + */ + std::vector change_future_queue; + std::vector change_pass_keyframe_queue; +// std::vector pre_horizon_queue; // This is directly implemented in the global queue + std::vector change_queue; + + /** + * Magic to identify the insertion position for a TriggerType. + */ + template + typename InsertQueue::iterator insert_pos(const TriggerType &trg, + InsertQueue &queue) { + auto it = queue.begin(); + while (it != queue.end() && it->time < trg.time) { + ++it; + } + return it; + } +}; + + +/** + * The triggger Factory is stored once per gamestate and manages the Eventqueue + */ +class TriggerFactory { +public: + /** Subscribe to the event queue and manage this */ + TriggerFactory(EventQueue *queue) : + queue(queue) {} + + /** + * Remove all associated events for this trigger. + * Does not invalidate the trigger! + */ + void remove(Trigger *); + + /** + * Queue the event in the underlying event queue. + */ + EventQueue::Handle enqueue(Trigger *, const Trigger::EventTrigger &); + EventQueue::Handle enqueue(Trigger *, const Trigger::EventTrigger &, const curve_time_t &time); + + /** + * Remove the event and insert it again in the required position. + * /FIXME: Only works for future events at the moment + */ + void reschedule(const EventQueue::Handle &, const curve_time_t &new_time); + +private: + + EventQueue *queue; +}; + +}} // openage::curve diff --git a/openage/testing/testlist.py b/openage/testing/testlist.py index af032a335e..435edbcadb 100644 --- a/openage/testing/testlist.py +++ b/openage/testing/testlist.py @@ -72,6 +72,7 @@ def tests_cpp(): yield "openage::curve::tests::curve_types" yield "openage::curve::tests::events" yield "openage::curve::tests::serialization" + yield "openage::curve::tests::trigger" yield "openage::datastructure::tests::constexpr_map" yield "openage::datastructure::tests::pairing_heap" yield "openage::input::tests::parse_event_string", "keybinds parsing" From b4b257a5b449d2cb8063267dc7e029dcb54b3e5d Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Mon, 10 Jul 2017 18:45:40 +0200 Subject: [PATCH 21/24] curve trigger concept running --- libopenage/curve/CMakeLists.txt | 16 +- libopenage/curve/continuous.h | 3 + libopenage/curve/curve.h | 3 + libopenage/curve/demo/aicontroller.h | 1 + libopenage/curve/demo/config.h | 15 ++ libopenage/curve/demo/gamestate.h | 28 +-- libopenage/curve/demo/gui.cpp | 7 +- libopenage/curve/demo/gui.h | 1 + libopenage/curve/demo/main.cpp | 40 +-- libopenage/curve/demo/physics.cpp | 180 +++++++++----- libopenage/curve/demo/physics.h | 11 +- libopenage/curve/demo_events/CMakeLists.txt | 7 + libopenage/curve/demo_events/aicontroller.cpp | 30 +++ libopenage/curve/demo_events/aicontroller.h | 23 ++ libopenage/curve/demo_events/gamestate.cpp | 10 + libopenage/curve/demo_events/gamestate.h | 71 ++++++ libopenage/curve/demo_events/gui.cpp | 165 +++++++++++++ libopenage/curve/demo_events/gui.h | 25 ++ libopenage/curve/demo_events/main.cpp | 99 ++++++++ libopenage/curve/demo_events/physics.cpp | 230 ++++++++++++++++++ libopenage/curve/demo_events/physics.h | 29 +++ libopenage/curve/events.cpp | 177 +++++++++----- libopenage/curve/events.h | 89 +++++-- libopenage/curve/internal/CMakeLists.txt | 8 + libopenage/curve/internal/value_container.h | 11 +- libopenage/curve/object.h | 7 +- libopenage/curve/test/test_events.cpp | 14 +- libopenage/curve/test/test_trigger.cpp | 2 - libopenage/curve/trigger.cpp | 71 ++++-- libopenage/curve/trigger.h | 51 +++- 30 files changed, 1224 insertions(+), 200 deletions(-) create mode 100644 libopenage/curve/demo/config.h create mode 100644 libopenage/curve/demo_events/CMakeLists.txt create mode 100644 libopenage/curve/demo_events/aicontroller.cpp create mode 100644 libopenage/curve/demo_events/aicontroller.h create mode 100644 libopenage/curve/demo_events/gamestate.cpp create mode 100644 libopenage/curve/demo_events/gamestate.h create mode 100644 libopenage/curve/demo_events/gui.cpp create mode 100644 libopenage/curve/demo_events/gui.h create mode 100644 libopenage/curve/demo_events/main.cpp create mode 100644 libopenage/curve/demo_events/physics.cpp create mode 100644 libopenage/curve/demo_events/physics.h create mode 100644 libopenage/curve/internal/CMakeLists.txt diff --git a/libopenage/curve/CMakeLists.txt b/libopenage/curve/CMakeLists.txt index aa4c1bb0bc..4df4e7997b 100644 --- a/libopenage/curve/CMakeLists.txt +++ b/libopenage/curve/CMakeLists.txt @@ -10,11 +10,23 @@ add_sources(libopenage map.cpp map_filter_iterator.cpp queue.cpp - queue.cpp queue_filter_iterator.cpp trigger.cpp ) -add_subdirectory(internal) +pxdgen( + continuous.h + curve.h + discrete.h + events.h + iterator.h + map.h + map_filter_iterator.h + queue.h + queue_filter_iterator.h + trigger.h +) + + add_subdirectory(test) add_subdirectory(demo) diff --git a/libopenage/curve/continuous.h b/libopenage/curve/continuous.h index ca50fe9e97..a131831ee3 100644 --- a/libopenage/curve/continuous.h +++ b/libopenage/curve/continuous.h @@ -15,6 +15,9 @@ namespace curve { * The bound template type _T has to implement `operator+(_T)` and * `operator*(curve_time_t)`. * + * pxd: + * cppclass Continuous(ValueContainer): + * _T get(const curve_time_t&) except + */ template class Continuous : public ValueContainer<_T> { diff --git a/libopenage/curve/curve.h b/libopenage/curve/curve.h index c7d5d6299e..b7827d7c46 100644 --- a/libopenage/curve/curve.h +++ b/libopenage/curve/curve.h @@ -8,6 +8,9 @@ namespace curve { /** * Defines the type that is used as time index. * it has to implement all basic mathematically operations. + * + * pxd: + * ctypedef double curve_time_t */ typedef double curve_time_t; diff --git a/libopenage/curve/demo/aicontroller.h b/libopenage/curve/demo/aicontroller.h index eeddca8b0b..34ac413dbf 100644 --- a/libopenage/curve/demo/aicontroller.h +++ b/libopenage/curve/demo/aicontroller.h @@ -2,6 +2,7 @@ #pragma once +#include "config.h" #include "gamestate.h" #include diff --git a/libopenage/curve/demo/config.h b/libopenage/curve/demo/config.h new file mode 100644 index 0000000000..2055748cc3 --- /dev/null +++ b/libopenage/curve/demo/config.h @@ -0,0 +1,15 @@ +#pragma once + +// Define this to draw an ncurses based demo. +// Without the GUI flag, just a trace of event is printed out +//#define GUI + +// If this is defined, player 1 can be played with the arrow keys. +// else the player is replaced by an AI. +//#define HUMAN + +// This can take the following values: +// 0: run in real time with real deltas +// 1: run very slow +// 2: run very fast +#define REALTIME 0 diff --git a/libopenage/curve/demo/gamestate.h b/libopenage/curve/demo/gamestate.h index 83d2be1187..6b58e2c1ab 100644 --- a/libopenage/curve/demo/gamestate.h +++ b/libopenage/curve/demo/gamestate.h @@ -2,6 +2,9 @@ #pragma once +#include "config.h" + +#include "../object.h" #include "../continuous.h" #include "../discrete.h" #include "../../util/vector.h" @@ -18,22 +21,17 @@ struct event { event() : player(0), state(IDLE) {} }; -class PongPlayer { +class PongPlayer : public curve::Object { public: PongPlayer(openage::curve::TriggerFactory *f) : + Object(f), speed(f), position(f), lives(f), state(f), - size(f) { - speed.set_drop(0, 1); - position.set_drop(0, 0.5); - lives.set_drop(0, 1); - state.set_drop(0, event(0, event::IDLE)); - size.set_drop(0, 0.1); - y = 0; - id = 0; - } + size(f), + y(0), + id(0) {} curve::Discrete speed; curve::Continuous position; @@ -44,18 +42,20 @@ class PongPlayer { int id; }; -class PongBall { +class PongBall : public curve::Object { public: PongBall(curve::TriggerFactory *f) : - speed(f), - position(f) {} + Object(f), + speed(this), + position(this) {} curve::Discrete> speed; curve::Continuous> position; }; -class PongState { +class PongState : public curve::Object { public: PongState(curve::TriggerFactory *f) : + Object(f), p1(f), p2(f), ball(f) {} diff --git a/libopenage/curve/demo/gui.cpp b/libopenage/curve/demo/gui.cpp index 0f07bc5141..ee78f851f4 100644 --- a/libopenage/curve/demo/gui.cpp +++ b/libopenage/curve/demo/gui.cpp @@ -15,7 +15,7 @@ std::vector &Gui::getInputs(const PongPlayer &player) { evnt.state = event::IDLE; timeout(0); int c = getch(); - // mvprintw(0,1, "IN: %i", c); + mvprintw(0,30, "IN: %i", c); switch (c) { case KEY_DOWN: evnt.state = event::DOWN; @@ -33,6 +33,11 @@ std::vector &Gui::getInputs(const PongPlayer &player) { case 27: // esc or alt endwin(); exit(0); + break; + case 114: //r + evnt.state = event::START; + input_cache.push_back(evnt); + break; default: break; } diff --git a/libopenage/curve/demo/gui.h b/libopenage/curve/demo/gui.h index 708a3a8c0d..3196f3b7a4 100644 --- a/libopenage/curve/demo/gui.h +++ b/libopenage/curve/demo/gui.h @@ -2,6 +2,7 @@ #pragma once +#include "config.h" #include "gamestate.h" #include diff --git a/libopenage/curve/demo/main.cpp b/libopenage/curve/demo/main.cpp index 316227065c..ac077ba557 100644 --- a/libopenage/curve/demo/main.cpp +++ b/libopenage/curve/demo/main.cpp @@ -1,5 +1,6 @@ // Copyright 2015-2017 the openage authors. See copying.md for legal info. +#include "config.h" #include "aicontroller.h" #include "gamestate.h" #include "gui.h" @@ -11,10 +12,6 @@ typedef std::chrono::high_resolution_clock Clock; -#define GUI -#define REALTIME 3 -#undef HUMAN - namespace openage { namespace curvepong { @@ -23,15 +20,16 @@ int demo() { #ifdef GUI curvepong::Gui gui; #endif - curve::EventQueue queue; - curve::TriggerFactory factory{&queue}; - curvepong::Physics phys; - curvepong::AIInput ai; - bool running = true; +bool running = true; srand(time(NULL)); while (running) { - curvepong::PongState state(&factory); + curve::EventQueue queue; + curve::TriggerFactory factory{&queue}; curve::curve_time_t now = 1; + curvepong::Physics phys; + curvepong::AIInput ai; + curvepong::PongState state(&factory); + curvepong::Physics::init(state, &queue, now); state.p1.lives.set_drop(now, 3); state.p1.id = 0; @@ -61,7 +59,10 @@ int demo() { #ifdef HUMAN phys.processInput(state, state.p1, gui.getInputs(state.p1), &queue, now); #else +#ifdef GUI gui.getInputs(state.p1); +#endif + phys.processInput( state, state.p1, ai.getInputs(state.p1, state.ball, now), &queue, now); #endif @@ -71,23 +72,28 @@ int demo() { state.p1.y = 0; state.p2.y = state.resolution[0] - 1; - queue.execute_until(now + 100); + queue.execute_until(now + 10000); // phys.update(state, now); queue.print(); #ifdef GUI gui.draw(state, now); #endif -#if REALTIME == 1 - usleep(4000); + +#if REALTIME == 0 double dt = std::chrono::duration_cast( - (Clock::now() - loop_start)) - .count(); + (Clock::now() - loop_start)) + .count(); + if (dt < 12000) { + usleep(12000 - dt); + } now += dt; +#elif REALTIME == 1 + now += 1; + usleep(12000); #elif REALTIME == 2 now += 4; #else - now += 1; - usleep(4000); + #error no REALTIME plan set #endif loop_start = Clock::now(); } diff --git a/libopenage/curve/demo/physics.cpp b/libopenage/curve/demo/physics.cpp index 5e3c61e9d0..e525d0a02b 100644 --- a/libopenage/curve/demo/physics.cpp +++ b/libopenage/curve/demo/physics.cpp @@ -1,6 +1,7 @@ // Copyright 2015-2017 the openage authors. See copying.md for legal info. #include "physics.h" + #include "../../error/error.h" #include @@ -8,13 +9,70 @@ #include -#define GUI - namespace openage { namespace curvepong { const float extrapolating_time = 100.0f; +void Physics::init(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { +#ifndef GUI + std::cout << "Init" << std::endl; +#endif + + queue->schedule( + "physics.predictor.panel", + now, + [&state, &queue](const curve::curve_time_t &now) { + return predict_reflect_panel(state, queue, now); + }, + [&state] (curve::EventQueue *queue, const curve::curve_time_t &now) { + ball_reflect_panel(state, queue, now); + }, { + &state.ball.position, + &state.p1.position, + &state.p2.position + }); + + queue->schedule( + "physics.predictor.wall", + now, + [&state, &queue](const curve::curve_time_t &now) { + return predict_reflect_wall(state, queue, now); + }, + [&state] (curve::EventQueue *queue, const curve::curve_time_t &now) { + ball_reflect_wall(state, queue, now); + }, {&state.ball.position}); + + +/* state.ball.speed.clearevents(); + state.ball.speed.on_change_future( + "physics.change_future", + [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { + predict_reflect_wall(state, queue, now); + predict_reflect_panel(state, queue, now); + }); + + state.p1.position.clearevents(); + state.p1.position.on_change( + now, + "physics.reflect_panel", + [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { + auto t = predict_reflect_panel(state, queue, now); + queue->reschedule(t); + }); + + state.p2.position.clearevents(); + state.p2.position.on_change( + now, + "physics.reflect_panel", + [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { + auto t = predict_reflect_panel(state, queue, now); + queue->reschedule(t); + }); +*/ + reset(state, queue, now); +} + void Physics::processInput(PongState &state, PongPlayer &player, std::vector &events, @@ -50,8 +108,8 @@ void Physics::processInput(PongState &state, break; } case event::IDLE: - player.position.set_drop(now+extrapolating_time, - player.position.get(now)); +// player.position.set_drop(now+extrapolating_time, +// player.position.get(now)); break; case event::START: reset(state, queue, now); @@ -71,38 +129,41 @@ void Physics::processInput(PongState &state, void Physics::reset(PongState &state, - curve::EventQueue *q, + curve::EventQueue *,//q, const curve::curve_time_t &now) { - q->clear(now); - q->addcallback(now, "COLL WALL", - [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { - state.ball.position.set_drop(now, state.resolution * 0.5); - state.p1.position.set_drop(now, state.resolution[1] / 2); - state.p2.position.set_drop(now, state.resolution[1] / 2); - float dirx = (rand() % 2 * 2) - 1; - float diry = (rand() % 2 * 2) - 1; - auto init_speed = - util::Vector<2>( - dirx * (0.0001 + (rand() % 100) / 1000.f), - diry * (0.0001 + (rand() % 100) / 2000.f)); - - state.ball.speed.set_drop(now, init_speed); - auto pos = state.ball.position.get(now); - static int cnt = 0; - mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", - init_speed[0], - init_speed[1], - pos[0], - pos[1], - ++cnt); - predict_reflect_panel(state, queue, now); - predict_reflect_wall(state, queue, now); - }); +// q->clear(now); + state.on_pre_horizon( + now, "physics.reset", + [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { + + state.ball.position.set_drop(now-0.1, state.ball.position.get(now)); + state.ball.position.set_drop(now, state.resolution * 0.5); + state.p1.position.set_drop(now, state.resolution[1] / 2); + state.p2.position.set_drop(now, state.resolution[1] / 2); + float dirx = 1;//(rand() % 2 * 2) - 1; + float diry = 0.1;//(rand() % 2 * 2) - 1; + auto init_speed = + util::Vector<2>( + dirx * (0.0001 + (rand() % 100) / 1000.f), + diry * (0.0001 + (rand() % 100) / 2000.f)); + + state.ball.speed.set_drop(now, init_speed); + auto pos = state.ball.position.get(now); + static int cnt = 0; + mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", + init_speed[0], + init_speed[1], + pos[0], + pos[1], + ++cnt); + predict_reflect_panel(state, queue, now); + predict_reflect_wall(state, queue, now); + }); } void Physics::ball_reflect_wall(PongState &state, - curve::EventQueue *queue, + curve::EventQueue *, //queue, const curve::curve_time_t &now) { auto pos = state.ball.position.get(now); auto speed = state.ball.speed.get(now); @@ -117,40 +178,40 @@ void Physics::ball_reflect_wall(PongState &state, state.ball.speed.set_drop(now, speed); state.ball.position.set_drop(now, pos); - predict_reflect_wall(state, queue, now); +// predict_reflect_wall(state, queue, now); } -void Physics::predict_reflect_wall(PongState &state, - curve::EventQueue *queue, - const curve::curve_time_t &now) { +curve::curve_time_t Physics::predict_reflect_wall( + PongState &state, + curve::EventQueue *, //queue, + const curve::curve_time_t &now) +{ auto pos = state.ball.position.get(now); auto speed = state.ball.speed.get(now); - + if (speed[1] == 0) return std::numeric_limits::max(); double ty = 0; if (speed[1] > 0) { ty = (state.resolution[1] - pos[1]) / speed[1]; } else if (speed[1] < 0) { ty = pos[1] / -speed[1]; } else { - throw Error(MSG(err) << "speed was 0"); +// throw Error(MSG(err) << "speed was 0"); } #ifdef GUI mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); #endif if (ty > 0) { - auto hit_pos = pos + speed * ty; - hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; - //assert(hit_pos[0] >= 0); - assert(hit_pos[1] >= 0); - state.ball.position.set_drop(now + ty, hit_pos); - queue->addcallback(now + ty, "COLL WALL", - [&state](curve::EventQueue *q, const curve::curve_time_t &t) { - ball_reflect_wall(state, q, t); - }); +// auto hit_pos = pos + speed * ty; +// hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; +// assert(hit_pos[0] >= 0); +// assert(hit_pos[1] >= 0); +// state.ball.position.set_drop(now + ty, hit_pos); +// ball_reflect_wall(state, queue, now + ty); } else { - throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); +// throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); } + return now + ty; } @@ -173,8 +234,9 @@ void Physics::ball_reflect_panel(PongState &state, || pos[1] > state.p1.position.get(now) + state.p1.size.get(now) / 2)) { // Ball missed the paddel of player 1 auto l = state.p1.lives(now); - l --; - state.p1.lives.set_drop(now, l); + l--; + state. + p1.lives.set_drop(now, l); state.ball.position.set_drop(now, pos); reset(state, queue, now); mvprintw(21, 18, "1"); @@ -193,17 +255,18 @@ void Physics::ball_reflect_panel(PongState &state, speed[0] *= -1.0; state.ball.speed.set_drop(now, speed); state.ball.position.set_drop(now, pos); - predict_reflect_panel(state, queue, now); +// predict_reflect_panel(state, queue, now); } } -void Physics::predict_reflect_panel(PongState &state, +curve::curve_time_t Physics::predict_reflect_panel(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { auto pos = state.ball.position.get(now); auto speed = state.ball.speed.get(now); // speed[1] += (rand() % 50 - 50)/10; + if (speed[0] == 0) return std::numeric_limits::max(); float ty = 0; if (speed[0] > 0) { ty = (state.resolution[0] - pos[0]) / speed[0]; @@ -217,14 +280,15 @@ void Physics::predict_reflect_panel(PongState &state, auto hit_pos = pos + speed * ty; hit_pos[0] = speed[0] > 0 ? state.resolution[0] : 0; assert(hit_pos[0] >= 0); -// assert(hit_pos[1] >= 0); // this might validly happen - state.ball.position.set_drop(now + ty, hit_pos); - queue->addcallback(now + ty, "COLL PANEL", - [&state](curve::EventQueue *q, const curve::curve_time_t &t) { - ball_reflect_panel(state, q, t); - }); + //assert(hit_pos[1] >= 0); // this might validly happen +// state.ball.position.set_drop(now + ty, hit_pos); + // queue->addcallback(now + ty, "physics.reflect_panel"// , + // [&state](curve::EventQueue *q, const curve::curve_time_t &t) { +// ball_reflect_panel(state, queue, now + ty); + // }) +; + return now + ty; -// predict_reflect_wall(state, queue, now); } }} // openage::curvepong diff --git a/libopenage/curve/demo/physics.h b/libopenage/curve/demo/physics.h index cd49415711..929ae97538 100644 --- a/libopenage/curve/demo/physics.h +++ b/libopenage/curve/demo/physics.h @@ -2,18 +2,21 @@ #pragma once -#include - +#include "config.h" #include "gamestate.h" + #include "../curve.h" #include "../events.h" +#include + namespace openage { namespace curvepong { class Physics { public: + static void init(PongState &, curve::EventQueue *, const curve::curve_time_t &); void processInput(PongState &, PongPlayer &, std::vector &input, curve::EventQueue *, const curve::curve_time_t &now); protected: @@ -22,8 +25,8 @@ class Physics { static void ball_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); static void ball_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static curve::curve_time_t predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static curve::curve_time_t predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); }; }} // openage::curvepong diff --git a/libopenage/curve/demo_events/CMakeLists.txt b/libopenage/curve/demo_events/CMakeLists.txt new file mode 100644 index 0000000000..c1545e58c1 --- /dev/null +++ b/libopenage/curve/demo_events/CMakeLists.txt @@ -0,0 +1,7 @@ +add_sources (libopenage + aicontroller.cpp + gamestate.cpp + gui.cpp + main.cpp + physics.cpp +) diff --git a/libopenage/curve/demo_events/aicontroller.cpp b/libopenage/curve/demo_events/aicontroller.cpp new file mode 100644 index 0000000000..69f012d015 --- /dev/null +++ b/libopenage/curve/demo_events/aicontroller.cpp @@ -0,0 +1,30 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "aicontroller.h" + +namespace openage { +namespace curvepong { + +std::vector &AIInput::getInputs( + const PongPlayer &player, + const PongBall &ball, + const curve::curve_time_t &now) { + this->event_cache.clear(); + + auto position = player.position.get(now); + + // Yes i know, there is /3 used - instead of the logical /2 - this is to + // create a small safety boundary of 1/3 for enhanced fancyness + + // Ball is below position + if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { + event_cache.push_back(event(player.id, event::DOWN)); + } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { + // Ball is above position + event_cache.push_back(event(player.id, event::UP)); + } + + return this->event_cache; +} + +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/aicontroller.h b/libopenage/curve/demo_events/aicontroller.h new file mode 100644 index 0000000000..eeddca8b0b --- /dev/null +++ b/libopenage/curve/demo_events/aicontroller.h @@ -0,0 +1,23 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "gamestate.h" + +#include + +namespace openage { +namespace curvepong { + +class AIInput { +public: + std::vector &getInputs( + const PongPlayer &player, + const PongBall &ball, + const curve::curve_time_t &now); + +private: + std::vector event_cache; +}; + +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gamestate.cpp b/libopenage/curve/demo_events/gamestate.cpp new file mode 100644 index 0000000000..c91b21ccb0 --- /dev/null +++ b/libopenage/curve/demo_events/gamestate.cpp @@ -0,0 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "gamestate.h" + +namespace openage { +namespace curvepong { + +// This file is intentionally left empty + +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gamestate.h b/libopenage/curve/demo_events/gamestate.h new file mode 100644 index 0000000000..83d2be1187 --- /dev/null +++ b/libopenage/curve/demo_events/gamestate.h @@ -0,0 +1,71 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "../continuous.h" +#include "../discrete.h" +#include "../../util/vector.h" + +namespace openage { +namespace curvepong { + +struct event { + int player; + enum state_e { + UP, DOWN, START, IDLE, LOST + } state; + event(int id, state_e s) : player(id), state(s) {} + event() : player(0), state(IDLE) {} +}; + +class PongPlayer { +public: + PongPlayer(openage::curve::TriggerFactory *f) : + speed(f), + position(f), + lives(f), + state(f), + size(f) { + speed.set_drop(0, 1); + position.set_drop(0, 0.5); + lives.set_drop(0, 1); + state.set_drop(0, event(0, event::IDLE)); + size.set_drop(0, 0.1); + y = 0; + id = 0; + } + + curve::Discrete speed; + curve::Continuous position; + curve::Discrete lives; + curve::Discrete state; + curve::Discrete size; + float y; + int id; +}; + +class PongBall { +public: + PongBall(curve::TriggerFactory *f) : + speed(f), + position(f) {} + curve::Discrete> speed; + curve::Continuous> position; +}; + +class PongState { +public: + PongState(curve::TriggerFactory *f) : + p1(f), + p2(f), + ball(f) {} + + PongPlayer p1; + PongPlayer p2; + + PongBall ball; + + util::Vector<2> resolution; +}; + +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gui.cpp b/libopenage/curve/demo_events/gui.cpp new file mode 100644 index 0000000000..0f07bc5141 --- /dev/null +++ b/libopenage/curve/demo_events/gui.cpp @@ -0,0 +1,165 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#include "gui.h" + +#include +#include + +namespace openage { +namespace curvepong { + +std::vector &Gui::getInputs(const PongPlayer &player) { + input_cache.clear(); + event evnt; + evnt.player = player.id; + evnt.state = event::IDLE; + timeout(0); + int c = getch(); + // mvprintw(0,1, "IN: %i", c); + switch (c) { + case KEY_DOWN: + evnt.state = event::DOWN; + input_cache.push_back(evnt); + mvprintw(1, 1, "DOWN"); + break; + case KEY_UP: + evnt.state = event::UP; + input_cache.push_back(evnt); + mvprintw(1, 1, "UP"); + break; + case ' ': + evnt.state = event::START; + break; + case 27: // esc or alt + endwin(); + exit(0); + default: break; + } + + return input_cache; +} + + +enum { + COLOR_PLAYER1 = 1, + COLOR_PLAYER2 = 2, + COLOR_BALL = 3, + COLOR_DEBUG = 4, + + COLOR_0 = 5, + COLOR_1 = 6, + COLOR_2 = 7, + COLOR_3 = 8, + COLOR_4 = 9, +}; + + +Gui::Gui() { + initscr(); + start_color(); + init_pair(COLOR_PLAYER1, COLOR_BLUE, COLOR_BLUE); + init_pair(COLOR_PLAYER2, COLOR_RED, COLOR_RED); + init_pair(COLOR_BALL, COLOR_BLUE, COLOR_WHITE); + init_pair(COLOR_DEBUG, COLOR_WHITE, COLOR_BLACK); + init_pair(COLOR_0, COLOR_RED, COLOR_BLACK); + init_pair(COLOR_1, COLOR_GREEN, COLOR_BLACK); + + keypad(stdscr, true); + noecho(); + curs_set(0); + // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); + + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw( + 4, 5, " oooooooooo "); + mvprintw( + 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); + mvprintw( + 6, 5, " 888oooo88 888 888 888 888 888 88o "); + mvprintw( + 7, 5, " 888 888 888 888 888 888oo888o "); + mvprintw( + 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); + mvprintw( + 9, 5, " 888ooo888 "); + attroff(COLOR_PAIR(COLOR_DEBUG)); + + getch(); +} + + +void Gui::draw(PongState &state, const curve::curve_time_t &now) { + // clear(); + // Print Score + attron(COLOR_PAIR(COLOR_DEBUG)); + getmaxyx(stdscr, state.resolution[1], state.resolution[0]); + state.resolution[1] -= 1; + attron(COLOR_PAIR(COLOR_DEBUG)); + mvprintw(2, + state.resolution[0] / 2 - 5, + "P1 %i | P2 %i", + state.p1.lives(now), + state.p2.lives(now)); + + mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); + mvprintw(0, 1, "NOW: %f", now); + mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); + mvprintw(2, + 1, + "P1: %f, %f, %i", + state.p1.position(now), + state.p1.y, + state.p1.state(now).state); + mvprintw(3, + 1, + "P2: %f, %f, %i", + state.p2.position(now), + state.p2.y, + state.p2.state(now).state); + for (int i = 0; i < 1000; i += 100) { + mvprintw(4 + i / 100, + 1, + "BALL in %03i: %f | %f; SPEED: %f | %f", + i, + state.ball.position(now + i)[0], + state.ball.position(now + i)[1], + state.ball.speed(now + i)[0], + state.ball.speed(now + i)[1]); + } + mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); + attroff(COLOR_PAIR(COLOR_DEBUG)); + + attron(COLOR_PAIR(COLOR_PLAYER1)); + for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { + mvprintw(state.p1.position(now) + i, state.p1.y, "|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER1)); + + attron(COLOR_PAIR(COLOR_PLAYER2)); + for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { + mvprintw(state.p2.position(now) + i, state.p2.y, "|"); + } + attroff(COLOR_PAIR(COLOR_PLAYER2)); + + attron(COLOR_PAIR(COLOR_1)); + for (int i = 1; i < 9999; ++i) { + draw_ball(state.ball.position(now + i), 'X'); + } + attron(COLOR_PAIR(COLOR_0)); + draw_ball(state.ball.position(now), 'M'); + /*attron(COLOR_PAIR(COLOR_BALL)); + mvprintw(state.ball.position(now)[1], + state.ball.position(now)[0], + "o"); + */ + attroff(COLOR_PAIR(COLOR_BALL)); + refresh(); + erase(); +} + + +void Gui::draw_ball(util::Vector<2> pos, char chr) { + mvprintw((int)(pos[1]), (int)(pos[0]), "%c", chr); + standend(); +} +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gui.h b/libopenage/curve/demo_events/gui.h new file mode 100644 index 0000000000..708a3a8c0d --- /dev/null +++ b/libopenage/curve/demo_events/gui.h @@ -0,0 +1,25 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "gamestate.h" + +#include + +namespace openage { +namespace curvepong { + + +class Gui { + +public: + Gui(); + std::vector &getInputs(const PongPlayer &player); + void draw(PongState &state, const curve::curve_time_t &now); + void draw_ball(util::Vector<2> ball, char chr); + +private: + std::vector input_cache; +}; + +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/main.cpp b/libopenage/curve/demo_events/main.cpp new file mode 100644 index 0000000000..316227065c --- /dev/null +++ b/libopenage/curve/demo_events/main.cpp @@ -0,0 +1,99 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#include "aicontroller.h" +#include "gamestate.h" +#include "gui.h" +#include "physics.h" + +#include + +#include + +typedef std::chrono::high_resolution_clock Clock; + +#define GUI +#define REALTIME 3 +#undef HUMAN + +namespace openage { +namespace curvepong { + +int demo() { + // Restart forever +#ifdef GUI + curvepong::Gui gui; +#endif + curve::EventQueue queue; + curve::TriggerFactory factory{&queue}; + curvepong::Physics phys; + curvepong::AIInput ai; + bool running = true; + srand(time(NULL)); + while (running) { + curvepong::PongState state(&factory); + curve::curve_time_t now = 1; + + state.p1.lives.set_drop(now, 3); + state.p1.id = 0; + state.p1.size.set_drop(now, 4); + state.p2.lives.set_drop(now, 3); + state.p2.id = 1; + state.p2.size.set_drop(now, 4); +#ifdef GUI + gui.draw(state, now); // update gui related parameters +#else + state.resolution[0] = 100; + state.resolution[1] = 40; +#endif + + auto loop_start = Clock::now(); + now += 1; + { + std::vector start_event { event(0, event::START) }; + phys.processInput(state, state.p1, start_event, &queue, now); + } + +#ifdef GUI + gui.draw(state, now); // initial drawing with corrected ball +#endif + while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { + //We need to get the inputs to be able to kill the game +#ifdef HUMAN + phys.processInput(state, state.p1, gui.getInputs(state.p1), &queue, now); +#else + gui.getInputs(state.p1); + phys.processInput( + state, state.p1, ai.getInputs(state.p1, state.ball, now), &queue, now); +#endif + phys.processInput( + state, state.p2, ai.getInputs(state.p2, state.ball, now), &queue, now); + + state.p1.y = 0; + state.p2.y = state.resolution[0] - 1; + + queue.execute_until(now + 100); +// phys.update(state, now); + queue.print(); +#ifdef GUI + gui.draw(state, now); +#endif +#if REALTIME == 1 + usleep(4000); + double dt = std::chrono::duration_cast( + (Clock::now() - loop_start)) + .count(); + now += dt; +#elif REALTIME == 2 + now += 4; +#else + now += 1; + usleep(4000); +#endif + loop_start = Clock::now(); + } + } + return 0; +} + + +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/physics.cpp b/libopenage/curve/demo_events/physics.cpp new file mode 100644 index 0000000000..5e3c61e9d0 --- /dev/null +++ b/libopenage/curve/demo_events/physics.cpp @@ -0,0 +1,230 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#include "physics.h" +#include "../../error/error.h" + +#include +#include + +#include + +#define GUI + +namespace openage { +namespace curvepong { + +const float extrapolating_time = 100.0f; + +void Physics::processInput(PongState &state, + PongPlayer &player, + std::vector &events, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + for (auto evnt : events) { + //Process only if the future has changed + if (player.state.get(now).state != evnt.state) { + player.state.set_drop(now, evnt); + + switch(evnt.state) { + case event::UP: + case event::DOWN: { + if (evnt.state == event::UP) { + player.speed.set_drop(now, -2); + } else if (evnt.state == event::DOWN) { + player.speed.set_drop(now, 2); + } + player.speed.set_drop(now + extrapolating_time, 0); + + float new_pos = player.position.get(now) + + (player.speed.get(now+extrapolating_time) + - player.speed.get(now) / 2 + player.speed.get(now)); + if (new_pos < 0) + new_pos = 0; + if (new_pos > state.resolution[1]) + new_pos = state.resolution[1]; + + player.position.set_drop(now+extrapolating_time, new_pos); + evnt.state = event::IDLE; + player.state.set_drop(now + extrapolating_time, evnt); +// predict_reflect_panel(state, queue, now); + break; + } + case event::IDLE: + player.position.set_drop(now+extrapolating_time, + player.position.get(now)); + break; + case event::START: + reset(state, queue, now); + break; + + //if (player.state.get(now).state == event::LOST) { + // state.ball.position.set_drop(now, state.resolution * 0.5); + //} + //update_ball(state, now, init_recursion_limit); + //break; + default: + break; + } + } + } +} + + +void Physics::reset(PongState &state, + curve::EventQueue *q, + const curve::curve_time_t &now) { + q->clear(now); + q->addcallback(now, "COLL WALL", + [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { + state.ball.position.set_drop(now, state.resolution * 0.5); + state.p1.position.set_drop(now, state.resolution[1] / 2); + state.p2.position.set_drop(now, state.resolution[1] / 2); + float dirx = (rand() % 2 * 2) - 1; + float diry = (rand() % 2 * 2) - 1; + auto init_speed = + util::Vector<2>( + dirx * (0.0001 + (rand() % 100) / 1000.f), + diry * (0.0001 + (rand() % 100) / 2000.f)); + + state.ball.speed.set_drop(now, init_speed); + auto pos = state.ball.position.get(now); + static int cnt = 0; + mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", + init_speed[0], + init_speed[1], + pos[0], + pos[1], + ++cnt); + predict_reflect_panel(state, queue, now); + predict_reflect_wall(state, queue, now); + }); +} + + +void Physics::ball_reflect_wall(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +#ifndef GUI + std::cout << "\nWall\n"; +#else + static int cnt = 0; + mvprintw(22, 22, "Wall Reflect [%i]", ++cnt); + mvprintw(23, 22, "Speed[1] is %f", speed[1]); +#endif + speed[1] *= -1.0; + state.ball.speed.set_drop(now, speed); + state.ball.position.set_drop(now, pos); + + predict_reflect_wall(state, queue, now); +} + + +void Physics::predict_reflect_wall(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); + + double ty = 0; + if (speed[1] > 0) { + ty = (state.resolution[1] - pos[1]) / speed[1]; + } else if (speed[1] < 0) { + ty = pos[1] / -speed[1]; + } else { + throw Error(MSG(err) << "speed was 0"); + } +#ifdef GUI + mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); +#endif + if (ty > 0) { + auto hit_pos = pos + speed * ty; + hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; + //assert(hit_pos[0] >= 0); + assert(hit_pos[1] >= 0); + state.ball.position.set_drop(now + ty, hit_pos); + queue->addcallback(now + ty, "COLL WALL", + [&state](curve::EventQueue *q, const curve::curve_time_t &t) { + ball_reflect_wall(state, q, t); + }); + } else { + throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); + } +} + + +void Physics::ball_reflect_panel(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +#ifdef GUI + static int cnt = 0; + mvprintw(21, 22, "Panel hit [%i] ", ++cnt); +#else + std::cout << "\nPanel\n"; +#endif + + if (pos[0] <= 1 + && speed[0] < 0 + && (pos[1] < state.p1.position.get(now) - state.p1.size.get(now) / 2 + || pos[1] > state.p1.position.get(now) + state.p1.size.get(now) / 2)) { + // Ball missed the paddel of player 1 + auto l = state.p1.lives(now); + l --; + state.p1.lives.set_drop(now, l); + state.ball.position.set_drop(now, pos); + reset(state, queue, now); + mvprintw(21, 18, "1"); + } else if (pos[0] >= state.resolution[0]-1 + && speed[0] > 0 + && (pos[1] < state.p2.position.get(now) - state.p2.size.get(now) / 2 + || pos[1] > state.p2.position.get(now) + state.p2.size.get(now) / 2)) { + // Ball missed the paddel of player 2 + auto l = state.p2.lives(now); + l --; + state.p2.lives.set_drop(now, l); + state.ball.position.set_drop(now, pos); + reset(state, queue, now); + mvprintw(21, 18, "2"); + } else if (pos[0] >= state.resolution[0]- 1 || pos[0] <= 1) { + speed[0] *= -1.0; + state.ball.speed.set_drop(now, speed); + state.ball.position.set_drop(now, pos); + predict_reflect_panel(state, queue, now); + } +} + + +void Physics::predict_reflect_panel(PongState &state, + curve::EventQueue *queue, + const curve::curve_time_t &now) { + auto pos = state.ball.position.get(now); + auto speed = state.ball.speed.get(now); +// speed[1] += (rand() % 50 - 50)/10; + float ty = 0; + if (speed[0] > 0) { + ty = (state.resolution[0] - pos[0]) / speed[0]; + } else if (speed[0] < 0) { + ty = pos[0] / -speed[0]; + } +#ifdef GUI + mvprintw(21, 40, "AT %f NEXT %f", now, now + ty); + mvprintw(21, 18, "2"); +#endif + auto hit_pos = pos + speed * ty; + hit_pos[0] = speed[0] > 0 ? state.resolution[0] : 0; + assert(hit_pos[0] >= 0); +// assert(hit_pos[1] >= 0); // this might validly happen + state.ball.position.set_drop(now + ty, hit_pos); + queue->addcallback(now + ty, "COLL PANEL", + [&state](curve::EventQueue *q, const curve::curve_time_t &t) { + ball_reflect_panel(state, q, t); + }); + +// predict_reflect_wall(state, queue, now); +} + +}} // openage::curvepong diff --git a/libopenage/curve/demo_events/physics.h b/libopenage/curve/demo_events/physics.h new file mode 100644 index 0000000000..cd49415711 --- /dev/null +++ b/libopenage/curve/demo_events/physics.h @@ -0,0 +1,29 @@ +// Copyright 2015-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "gamestate.h" +#include "../curve.h" +#include "../events.h" + +namespace openage { +namespace curvepong { + +class Physics { +public: + + void processInput(PongState &, PongPlayer &, std::vector &input, curve::EventQueue *, const curve::curve_time_t &now); +protected: + + static void reset(PongState &, curve::EventQueue *, const curve::curve_time_t &); + + + static void ball_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void ball_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); +}; + +}} // openage::curvepong diff --git a/libopenage/curve/events.cpp b/libopenage/curve/events.cpp index 0f45a62a8d..0f2a16236c 100644 --- a/libopenage/curve/events.cpp +++ b/libopenage/curve/events.cpp @@ -1,54 +1,112 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "events.h" +#include "trigger.h" #include namespace openage { namespace curve { -#define GUI +// FIXME convert all these std::functions to a custom datatype to remove multiple level of stack indirection -// FIXME convert all these std::functions into our own datatype that stores all requirements. +EventQueue::Handle EventQueue::addcallback ( + const Eventclass &eventclass, + const curve_time_t &initial_now, + const time_predictor &at, + const callback &event, + const std::vector dependents) +{ + auto it = queue.begin(); + for (; it != queue.end() && it->eventclass != eventclass; ++it) {} + Event e; + if (it != queue.end()) { + e = *it; + e.time = at(initial_now); + e.event = event; + queue.erase(it); + } else { + e = Event(at, initial_now, eventclass, event, ++last_event_id, dependents); -EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, - const EventQueue::Eventclass &eventclass, - const EventQueue::callback &trigger) { - return addcallback(Event(at, eventclass, trigger, ++last_event_id)); + // FIXME Register all on change events + } + + return this->addcallback(e); } -EventQueue::Handle EventQueue::addcallback (const curve_time_t &at, - const EventQueue::Eventclass &eventclass, - const EventQueue::callback_void &trigger) { - return addcallback(at, eventclass, - [trigger](EventQueue *q, const curve_time_t &) { - trigger(q); - }); +EventQueue::Handle EventQueue::schedule ( + const Eventclass &eventclass, + const curve_time_t &initial_now, + const time_predictor &at, + const callback &event, + const std::vector dependents) +{ + auto it = queue.begin(); + for (; it != queue.end() && it->eventclass != eventclass; ++it) {} + + Event e; + if (it != queue.end()) { + e = *it; + e.time = at(initial_now); + e.event = event; + queue.erase(it); + } else { + e = Event(at, initial_now, eventclass, event, ++last_event_id, dependents, true); + // FIXME Register all on change events + } + + auto handle = this->addcallback(e); + + for (const auto &t : dependents) { + t->on_change_future( + std::string("dependency_") + eventclass, + [handle](EventQueue *q, const curve_time_t &t) { + q->reschedule(handle, t); + }); + } + return handle; + + } -EventQueue::Handle EventQueue::addcallback (const EventQueue::Event &e) { +EventQueue::Handle EventQueue::addcallback ( + const Eventclass &eventclass, + const curve_time_t &initial_now, + const time_predictor &at, + const callback_void &event, + const std::vector dependents) +{ + return addcallback( + eventclass, + initial_now, + at, + [event](EventQueue *q, const curve_time_t &) { + event(q); + }, dependents); +} + +EventQueue::Handle EventQueue::addcallback (const Event &e) { auto it = queue.begin(); -// Iterate to find the right insertion position for (; it != queue.end() && it->time < e.time; ++it) {} - queue.insert(it, e); - // todo clear the past return Handle(e.event_id); } void EventQueue::reschedule(const EventQueue::Handle &handle, - const curve_time_t &new_time) { + const EventQueue::time_predictor &new_timer, + const curve_time_t &at) { auto it = resolve_handle(handle); if (it != queue.end()) { Event evnt = *it; queue.erase(it); - evnt.time = new_time; + evnt.predictor = new_timer; + evnt.time = new_timer(at); addcallback(evnt); } else { // the event was either not valid or has already been executed. @@ -56,24 +114,56 @@ void EventQueue::reschedule(const EventQueue::Handle &handle, } -void EventQueue::execute_until(const curve_time_t &time) { -#ifndef GUI - std::cout << "\rNOW: " << time; -#endif +void EventQueue::reschedule(const EventQueue::Handle &handle, const curve_time_t &at) { + auto it = resolve_handle(handle); + if (it != queue.end()) { + Event evnt = *it; + queue.erase(it); + evnt.time = evnt.predictor(at); + addcallback(evnt); + } else { + // the event was either not valid or has already been executed. + } +} + + +void EventQueue::reschedule(const EventQueue::time_predictor &new_timer, const curve_time_t &at) { + if (active_event != nullptr) { + auto evnt = *active_event; + evnt.predictor = new_timer; + evnt.time = evnt.predictor(at); + addcallback(evnt); + } +} + + +void EventQueue::reschedule(const curve_time_t &at) { + if (active_event != nullptr) { + auto evnt = *active_event; + evnt.time = evnt.predictor(at); + addcallback(evnt); + } +} + +void EventQueue::execute_until(const curve_time_t &time) { auto it = queue.begin(); - int row = 1; while ((it = queue.begin()) != queue.end() && it->time < time) { auto tmp = *it; queue.erase(it); -#ifndef GUI - std::cout << " Exec " << tmp.event_id << " at " << tmp.time << " " << std::endl; -#else - mvprintw(row, 75, "X"); -#endif + this->active_event = &tmp; it->event(this, tmp.time); - past.push_back(tmp); + active_event = nullptr; + + if (tmp.repeat) { + // if the event is to be scheduled again after execution + // just insert it again + tmp.time = tmp.predictor(tmp.time); + addcallback(tmp); + } else { + past.push_back(tmp); + } if (this->cleared) { this->cleared = false; @@ -108,7 +198,7 @@ void EventQueue::print() { #ifndef GUI std::cout << "Queue: " << std::endl; for (const auto &i : queue) { - std::cout << i.time << ": " << i.event_id << i.event_eventclass <queue.between(from, to); - !cleared && it != queue.end(); - ) { - counter ++; - - auto time = it.value().time; - if (it.value().precond(time)) { - it.value().event(this, time); - } - //this->queue.erase(it); - //if (time >= to) break; - ++it; - //it = this->queue.between(time, to); - } - if (this->cleared) - this->queue.clear(); - this->cleared = false; - if (counter) counter = 0; -} -*/ void EventQueue::clear() { #ifndef GUI @@ -167,4 +234,4 @@ void EventQueue::clear(const curve_time_t &time) { } -}} // eventclassspace openage::curve +}} // namespace openage::curve diff --git a/libopenage/curve/events.h b/libopenage/curve/events.h index 3009b7cc91..23934a8a25 100644 --- a/libopenage/curve/events.h +++ b/libopenage/curve/events.h @@ -2,16 +2,28 @@ #pragma once +// pxd: from libcpp.string cimport string #include "curve.h" #include "queue.h" #include +#include namespace openage { namespace curve { +class Trigger; + /** * Event container that can execute and manage the stuff. + * + * pxd: + * cppclass EventQueue: + * ctypedef string Eventclass + * + * cppclass EventQueue__Handle "openage::curve::EventQueue::Handle": + * pass + * */ class EventQueue { public: @@ -21,6 +33,8 @@ class EventQueue { /** Callback with only the eventqueue as argument */ typedef std::function callback_void; + typedef std::function time_predictor; + /** Class of events - this identifies a type of event */ typedef std::string Eventclass; @@ -32,24 +46,32 @@ class EventQueue { friend class EventQueue; private: /** An event can only be constructed in the event queue */ - Event(const curve_time_t &time, + Event(const time_predictor &predictor, + const curve_time_t &initial_now, const Eventclass &eventclass, const callback &event, - const int event_id) : + const int event_id, + const std::vector &dependents, + bool repeat = false) : event_id{event_id}, - time{time}, + dependents{dependents}, + predictor{predictor}, + time{predictor(initial_now)}, eventclass(eventclass), - event{event} {} + event{event}, + repeat{repeat} {} /** The Event id is only relevant within the eventqueue */ int event_id; + + std::vector dependents; + + time_predictor predictor; public: + Event() = default; + /** Copy c'tor */ - Event(const Event &rhs) : - event_id(rhs.event_id), - time(rhs.time), - eventclass(rhs.eventclass), - event(rhs.event) {} + //Event(const Event &rhs) = default; /** when will this be executed */ curve_time_t time; @@ -57,22 +79,25 @@ class EventQueue { Eventclass eventclass; /** The event itself */ callback event; + + bool repeat; + }; /** * Handle to be able to communicate with the event that has been stored. * uses Event::event_id for identification. + * */ class Handle { friend class EventQueue; public: Handle() : Handle(0) {}; - private: /** Can only be constructed from the EventQueue scope */ - Handle(const int event_id) : + explicit Handle(const int event_id) : event_id(event_id) {} /** Identificator */ @@ -88,20 +113,49 @@ class EventQueue { * Add a callback - with an event class that takes queue and time as * arguments */ - Handle addcallback (const curve_time_t &at, const Eventclass &eventclass, const callback &); + Handle addcallback ( + const Eventclass &eventclass, + const curve_time_t &initial_now, + const time_predictor &at, + const callback &event, + const std::vector dependents); /** * Add a callback - with an event class that takes only queue as arguments */ - Handle addcallback (const curve_time_t &at, const Eventclass &eventclass, const callback_void &); + Handle addcallback( + const Eventclass &eventclass, + const curve_time_t &initial_now, + const time_predictor &at, + const callback_void &event, + const std::vector dependents); + + Handle schedule( + const Eventclass &eventclass, + const curve_time_t &initial_now, + const time_predictor &at, + const callback &event, + const std::vector dependents); - /** Add a callback created from an event */ - Handle addcallback (const Event &); + /** + * Take an event and reschedule the time, if it has not yet been executed + */ + void reschedule(const Handle &, const time_predictor &timer, const curve_time_t &at); /** * Take an event and reschedule the time, if it has not yet been executed */ - void reschedule(const Handle &, const curve_time_t &time); + void reschedule(const Handle &, const curve_time_t &at); + + /** + * Reschedule the currently running event to the time given + */ + void reschedule(const time_predictor &timer, const curve_time_t &at); + + /** + * Reschedule the Event and reevaluate the timer + */ + void reschedule(const curve_time_t &at); /** * Iteratively take the events and execute them one by one. The Queue may @@ -135,9 +189,12 @@ class EventQueue { */ void print(); private: + Handle addcallback(const Event &event); + std::deque::iterator resolve_handle(const Handle &handle); std::deque queue; std::deque past; + Event *active_event; bool cleared; int last_event_id = 0; diff --git a/libopenage/curve/internal/CMakeLists.txt b/libopenage/curve/internal/CMakeLists.txt new file mode 100644 index 0000000000..1683189a25 --- /dev/null +++ b/libopenage/curve/internal/CMakeLists.txt @@ -0,0 +1,8 @@ +add_sources(libopenage + keyframe_container.cpp + value_container.cpp +) + +pxdgen( + value_container.h +) diff --git a/libopenage/curve/internal/value_container.h b/libopenage/curve/internal/value_container.h index 080bd10420..c05b09b7e4 100644 --- a/libopenage/curve/internal/value_container.h +++ b/libopenage/curve/internal/value_container.h @@ -2,6 +2,7 @@ #pragma once +// pxd: from libopenage.curve cimport Trigger #include "../trigger.h" #include "keyframe_container.h" @@ -10,6 +11,14 @@ namespace openage { namespace curve { +/** + * pxd: + * + * cppclass ValueContainer(Trigger): + * void set_drop(const curve_time_t &) except + + * void set_insert(const curve_time_t &) except + + * + */ template class ValueContainer : public Trigger { public: @@ -52,7 +61,7 @@ void ValueContainer<_T>::set_drop(const curve_time_t &at, const _T &value) { container.insert(at, value, hint); this->last_element = hint; - this->data_changed(1, at); + this->data_changed(at, at); } diff --git a/libopenage/curve/object.h b/libopenage/curve/object.h index ace66404a8..a57fedf64b 100644 --- a/libopenage/curve/object.h +++ b/libopenage/curve/object.h @@ -2,19 +2,20 @@ #pragma once +#include "internal/value_container.h" + namespace openage { namespace curve { -#include "internal/value_container.h" /** * A Curve Object is a ordered collection of internal curves. Every sub-curve * needs to be registered at this parent element. */ -class Object : public Trigger { +class Object : public TriggerIntermediateMaster { public: Object(TriggerFactory *factory) : - Trigger(factory, parent) {}; + TriggerIntermediateMaster(factory) {}; private: diff --git a/libopenage/curve/test/test_events.cpp b/libopenage/curve/test/test_events.cpp index 9ad4fa5d01..5c9a18659b 100644 --- a/libopenage/curve/test/test_events.cpp +++ b/libopenage/curve/test/test_events.cpp @@ -16,13 +16,19 @@ static void print_vector(const std::vector> &t) { EventQueue createQueue(std::vector> &calls) { EventQueue q; - q.addcallback(1, "1", [&calls](EventQueue *, const curve_time_t &t) { + q.addcallback("1", 1, [](const curve_time_t &) { + return 1; + }, + [&calls](EventQueue *, const curve_time_t &t) { calls.push_back(std::make_pair(t, 1)); - }); + }, {}); - q.addcallback(2, "2", [&calls](EventQueue *, const curve_time_t &t) { + q.addcallback("2", 2, [](const curve_time_t &) { + return 2; + }, + [&calls](EventQueue *, const curve_time_t &t) { calls.push_back(std::make_pair(t, 2)); - }); + }, {}); return q; } diff --git a/libopenage/curve/test/test_trigger.cpp b/libopenage/curve/test/test_trigger.cpp index 1a9e0d6edb..7581a2d3b2 100644 --- a/libopenage/curve/test/test_trigger.cpp +++ b/libopenage/curve/test/test_trigger.cpp @@ -1,7 +1,5 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - #include "../../testing/testing.h" #include "../trigger.h" diff --git a/libopenage/curve/trigger.cpp b/libopenage/curve/trigger.cpp index 05158ca04f..124c5d3b51 100644 --- a/libopenage/curve/trigger.cpp +++ b/libopenage/curve/trigger.cpp @@ -2,10 +2,13 @@ #include "trigger.h" +#include + namespace openage { namespace curve { Trigger::Trigger(class TriggerFactory *factory) : + name(factory->generate_uuid(this)), factory{factory} { } @@ -18,14 +21,14 @@ Trigger::~Trigger() { void Trigger::on_change_future(const EventQueue::Eventclass &eventclass, const Trigger::change_event &event) { - EventTrigger trg{event, eventclass, 0}; + EventTrigger trg{event, this->name + eventclass, 0}; change_future_queue.insert(insert_pos(trg, change_future_queue), trg); } void Trigger::on_pass_keyframe(const EventQueue::Eventclass &eventclass, const Trigger::change_event &event) { - EventTrigger trg{event, eventclass, 0}; + EventTrigger trg{event, this->name + eventclass, 0}; change_pass_keyframe_queue.insert(insert_pos(trg, change_pass_keyframe_queue), trg); } @@ -33,15 +36,15 @@ void Trigger::on_pass_keyframe(const EventQueue::Eventclass &eventclass, void Trigger::on_pre_horizon(const curve_time_t &time, const EventQueue::Eventclass &eventclass, const Trigger::change_event &event) { - EventTrigger trg{event, eventclass, time}; - factory->enqueue(this, trg); + EventTrigger trg{event, this->name + eventclass, time}; + factory->enqueue(this, trg, time); } void Trigger::on_change(const curve_time_t &time, const EventQueue::Eventclass &eventclass, const Trigger::change_event &event) { - EventTriggerChange trg{event, eventclass, time}; + EventTriggerChange trg{event, this->name + eventclass, time}; change_queue.insert(insert_pos(trg, change_queue), trg); } @@ -51,22 +54,22 @@ void Trigger::clearevents() { change_future_queue.clear(); change_pass_keyframe_queue.clear(); change_queue.clear(); - } void Trigger::data_changed(const curve_time_t &now, - const curve_time_t &changed_at) { + const curve_time_t &/*changed_at*/) { // on_change_future will always happen when something changes for (auto &e : change_future_queue) { + // TODO Determine if "now" or "changed_at" is more convenient handles.push_back(EventTriggerHandle(e, factory->enqueue(this, e, now))); } for (auto &e : change_queue) { if (e.is_inserted) { - factory->reschedule(e.handle, changed_at); + factory->reschedule(e.handle, now); } else { - EventQueue::Handle h = factory->enqueue(this, e); + EventQueue::Handle h = factory->enqueue(this, e, now); e.handle = h; e.is_inserted = true; } @@ -81,15 +84,32 @@ void Trigger::passed_keyframe(const curve_time_t &time) { } -EventQueue::Handle TriggerFactory::enqueue(Trigger */*trigger*/, const Trigger::EventTrigger &trg) { - return queue->addcallback(trg.time, trg.eventclass, trg.event); +EventQueue::Handle TriggerFactory::enqueue(Trigger *trigger, + const Trigger::EventTrigger &trg, + const curve_time_t &at) { + auto t = trg.time; + return queue->addcallback( + trg.eventclass, + at, + [t](const curve_time_t &) { + return t; + }, + trg.event, + {trigger}); } -EventQueue::Handle TriggerFactory::enqueue(Trigger */*trigger*/, +EventQueue::Handle TriggerFactory::enqueue(Trigger *trigger, const Trigger::EventTrigger &trg, - const curve_time_t &time) { - return queue->addcallback(time, trg.eventclass, trg.event); + const EventQueue::time_predictor &timer, + const curve_time_t &at) { + return queue->addcallback( + trg.eventclass, + at, + timer, + trg.event, + {trigger} + ); } @@ -102,8 +122,27 @@ void TriggerFactory::remove(Trigger *t) { void TriggerFactory::reschedule(const EventQueue::Handle &handle, - const curve_time_t &new_time) { - queue->reschedule(handle, new_time); + const EventQueue::time_predictor &new_timer, + const curve_time_t &at) { + queue->reschedule(handle, new_timer, at); +} + + +void TriggerFactory::reschedule(const EventQueue::Handle &handle, + const curve_time_t &at) { + queue->reschedule(handle, at); } + +std::string TriggerFactory::generate_uuid(void const *ptr) { + char buf[32]; + snprintf(buf, sizeof(buf), "%p", ptr); + return std::string(buf); +} + + +TriggerIntermediateMaster::TriggerIntermediateMaster(TriggerFactory *superfactory) : + Trigger(this), TriggerFactory(superfactory->queue) { } + + }} // namespace openage::curve diff --git a/libopenage/curve/trigger.h b/libopenage/curve/trigger.h index bba5b59827..ed1d9d5f2f 100644 --- a/libopenage/curve/trigger.h +++ b/libopenage/curve/trigger.h @@ -2,6 +2,9 @@ #pragma once +// pxd: from libcpp.string cimport string +// pxd: from libopenage.curve.events cimport EventQueue +// pxd: from libopenage.curve.curve cimport curve_time_t #include "events.h" #include @@ -14,11 +17,22 @@ namespace tests { void trigger(); } -class TriggerFactor; +class TriggerFactory; /** * A Trigger is a entity, that where one can subscripe its change interface. * It will keep track of everything for change observation on top of event queue. + * + * pxd: + * + * cppclass Trigger: + * ctypedef void (*change_event)(EventQueue *, const curve_time_t &) + * void Trigger(TriggerFactory *) except + + * void on_change_future(const string &, const Trigger.change_event &) except + + * void on_pass_keyframe(const string &, const Trigger.change_event &) except + + * void on_pre_horizon(const curve_time_t &, const string &, const change_event &) except + + * void on_change(const curve_time_t &, const string &, const change_event &) except + + * void clearevents() except + */ class Trigger { friend class TriggerFactory; @@ -26,6 +40,7 @@ class Trigger { public: typedef std::function change_event; + const std::string name; Trigger(class TriggerFactory *factory); virtual ~Trigger(); @@ -33,7 +48,7 @@ class Trigger { /** * Will be triggered when anything changes - immediately. */ - void on_change_future(const EventQueue::Eventclass &, const change_event &); + void on_change_future(const EventQueue::Eventclass &, const change_event & ); /** * Will be triggered whenever you pass a keyframe, that is not relevant for execution anymore @@ -143,6 +158,10 @@ class Trigger { /** * The triggger Factory is stored once per gamestate and manages the Eventqueue + * + * pxd: + * cppclass TriggerFactory: + * pass */ class TriggerFactory { public: @@ -154,23 +173,41 @@ class TriggerFactory { * Remove all associated events for this trigger. * Does not invalidate the trigger! */ - void remove(Trigger *); + virtual void remove(Trigger *); /** * Queue the event in the underlying event queue. */ - EventQueue::Handle enqueue(Trigger *, const Trigger::EventTrigger &); - EventQueue::Handle enqueue(Trigger *, const Trigger::EventTrigger &, const curve_time_t &time); + EventQueue::Handle enqueue(Trigger *, + const Trigger::EventTrigger &, + const curve_time_t &now); + EventQueue::Handle enqueue(Trigger *, + const Trigger::EventTrigger &, + const EventQueue::time_predictor &, + const curve_time_t &now); /** * Remove the event and insert it again in the required position. * /FIXME: Only works for future events at the moment */ - void reschedule(const EventQueue::Handle &, const curve_time_t &new_time); + void reschedule(const EventQueue::Handle &, + const EventQueue::time_predictor &new_timer, + const curve_time_t &now); -private: + void reschedule(const EventQueue::Handle &, + const curve_time_t &now); + + void reschedule(const curve_time_t &now); + + std::string generate_uuid(void const *); EventQueue *queue; }; +class TriggerIntermediateMaster : public Trigger, public TriggerFactory { +public: + TriggerIntermediateMaster(TriggerFactory *superFactory); +}; + + }} // openage::curve From 1681601dc2e744a9658108de8bf885e689b611ca Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Fri, 21 Jul 2017 21:14:48 +0200 Subject: [PATCH 22/24] Overhaul the event system. Again. And Again. --- libopenage/curve/CMakeLists.txt | 7 +- libopenage/curve/continuous.h | 2 +- libopenage/curve/curve.h | 4 +- libopenage/curve/demo/aicontroller.cpp | 16 +- libopenage/curve/demo/aicontroller.h | 4 +- libopenage/curve/demo/config.h | 6 +- libopenage/curve/demo/gamestate.h | 119 ++-- libopenage/curve/demo/gui.cpp | 99 ++-- libopenage/curve/demo/gui.h | 4 +- libopenage/curve/demo/main.cpp | 59 +- libopenage/curve/demo/physics.cpp | 507 ++++++++++-------- libopenage/curve/demo/physics.h | 27 +- libopenage/curve/demo_events/CMakeLists.txt | 7 - libopenage/curve/demo_events/aicontroller.cpp | 30 -- libopenage/curve/demo_events/aicontroller.h | 23 - libopenage/curve/demo_events/gamestate.cpp | 10 - libopenage/curve/demo_events/gamestate.h | 71 --- libopenage/curve/demo_events/gui.cpp | 165 ------ libopenage/curve/demo_events/gui.h | 25 - libopenage/curve/demo_events/main.cpp | 99 ---- libopenage/curve/demo_events/physics.cpp | 230 -------- libopenage/curve/demo_events/physics.h | 29 - libopenage/curve/events.cpp | 237 -------- libopenage/curve/events.h | 204 ------- libopenage/curve/events/CMakeLists.txt | 8 + libopenage/curve/events/event.cpp | 23 + libopenage/curve/events/event.h | 54 ++ libopenage/curve/events/eventclass.cpp | 34 ++ libopenage/curve/events/eventclass.h | 167 ++++++ libopenage/curve/events/eventmanager.cpp | 148 +++++ libopenage/curve/events/eventmanager.h | 115 ++++ libopenage/curve/events/eventqueue.cpp | 231 ++++++++ libopenage/curve/events/eventqueue.h | 125 +++++ libopenage/curve/events/events.h | 14 + libopenage/curve/events/events2.cpp | 17 + libopenage/curve/events/events2.h | 34 ++ libopenage/curve/events/eventtarget.cpp | 75 +++ libopenage/curve/events/eventtarget.h | 55 ++ .../curve/internal/keyframe_container.h | 4 +- libopenage/curve/internal/value_container.h | 44 +- libopenage/curve/iterator.h | 4 +- libopenage/curve/map.h | 12 +- libopenage/curve/object.h | 24 - libopenage/curve/queue.h | 14 +- libopenage/curve/test/CMakeLists.txt | 3 +- libopenage/curve/test/test_curve_types.cpp | 23 +- libopenage/curve/test/test_events2.cpp | 457 ++++++++++++++++ libopenage/curve/test/test_trigger.cpp | 62 --- libopenage/curve/trigger.cpp | 148 ----- libopenage/curve/trigger.h | 213 -------- openage/CMakeLists.txt | 2 +- openage/testing/testlist.py | 3 +- 52 files changed, 2090 insertions(+), 2007 deletions(-) delete mode 100644 libopenage/curve/demo_events/CMakeLists.txt delete mode 100644 libopenage/curve/demo_events/aicontroller.cpp delete mode 100644 libopenage/curve/demo_events/aicontroller.h delete mode 100644 libopenage/curve/demo_events/gamestate.cpp delete mode 100644 libopenage/curve/demo_events/gamestate.h delete mode 100644 libopenage/curve/demo_events/gui.cpp delete mode 100644 libopenage/curve/demo_events/gui.h delete mode 100644 libopenage/curve/demo_events/main.cpp delete mode 100644 libopenage/curve/demo_events/physics.cpp delete mode 100644 libopenage/curve/demo_events/physics.h delete mode 100644 libopenage/curve/events.cpp delete mode 100644 libopenage/curve/events.h create mode 100644 libopenage/curve/events/CMakeLists.txt create mode 100644 libopenage/curve/events/event.cpp create mode 100644 libopenage/curve/events/event.h create mode 100644 libopenage/curve/events/eventclass.cpp create mode 100644 libopenage/curve/events/eventclass.h create mode 100644 libopenage/curve/events/eventmanager.cpp create mode 100644 libopenage/curve/events/eventmanager.h create mode 100644 libopenage/curve/events/eventqueue.cpp create mode 100644 libopenage/curve/events/eventqueue.h create mode 100644 libopenage/curve/events/events.h create mode 100644 libopenage/curve/events/events2.cpp create mode 100644 libopenage/curve/events/events2.h create mode 100644 libopenage/curve/events/eventtarget.cpp create mode 100644 libopenage/curve/events/eventtarget.h delete mode 100644 libopenage/curve/object.h create mode 100644 libopenage/curve/test/test_events2.cpp delete mode 100644 libopenage/curve/test/test_trigger.cpp delete mode 100644 libopenage/curve/trigger.cpp delete mode 100644 libopenage/curve/trigger.h diff --git a/libopenage/curve/CMakeLists.txt b/libopenage/curve/CMakeLists.txt index 4df4e7997b..cee2633835 100644 --- a/libopenage/curve/CMakeLists.txt +++ b/libopenage/curve/CMakeLists.txt @@ -5,28 +5,25 @@ add_sources(libopenage queue.cpp continuous.cpp discrete.cpp - events.cpp iterator.cpp map.cpp map_filter_iterator.cpp queue.cpp queue_filter_iterator.cpp - trigger.cpp ) pxdgen( continuous.h curve.h discrete.h - events.h iterator.h map.h map_filter_iterator.h queue.h queue_filter_iterator.h - trigger.h ) - +add_subdirectory(events) +add_subdirectory(internal) add_subdirectory(test) add_subdirectory(demo) diff --git a/libopenage/curve/continuous.h b/libopenage/curve/continuous.h index a131831ee3..166eb22c48 100644 --- a/libopenage/curve/continuous.h +++ b/libopenage/curve/continuous.h @@ -42,7 +42,7 @@ _T Continuous<_T>::get(const curve_time_t &time) const { double offset = time - e->time; // If we do not have a next (buffer underrun!!) we assign values if (nxt == this->container.end()) { -// log::log(WARN << "Continuous buffer underrun. This might be bad! Assuming constant."); + // log::log(WARN << "Continuous buffer underrun. This might be bad! Assuming constant."); } else { diff_time = nxt->time - e->time; } diff --git a/libopenage/curve/curve.h b/libopenage/curve/curve.h index b7827d7c46..6fa0b779ca 100644 --- a/libopenage/curve/curve.h +++ b/libopenage/curve/curve.h @@ -2,6 +2,8 @@ #pragma once +#include + namespace openage { namespace curve { @@ -12,6 +14,6 @@ namespace curve { * pxd: * ctypedef double curve_time_t */ -typedef double curve_time_t; +typedef int64_t curve_time_t; }} // openage::curve diff --git a/libopenage/curve/demo/aicontroller.cpp b/libopenage/curve/demo/aicontroller.cpp index 69f012d015..270fe03e03 100644 --- a/libopenage/curve/demo/aicontroller.cpp +++ b/libopenage/curve/demo/aicontroller.cpp @@ -6,22 +6,22 @@ namespace openage { namespace curvepong { std::vector &AIInput::getInputs( - const PongPlayer &player, - const PongBall &ball, - const curve::curve_time_t &now) { + const std::shared_ptr &player, + const std::shared_ptr &ball, + const curve::curve_time_t &now) { this->event_cache.clear(); - auto position = player.position.get(now); + auto position = player->position->get(now); // Yes i know, there is /3 used - instead of the logical /2 - this is to // create a small safety boundary of 1/3 for enhanced fancyness // Ball is below position - if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { - event_cache.push_back(event(player.id, event::DOWN)); - } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { + if (ball->position->get(now)[1] > position + player->size->get(now) / 3) { + event_cache.push_back(event(player->id(), event::DOWN)); + } else if (ball->position->get(now)[1] < position - player->size->get(now) / 3) { // Ball is above position - event_cache.push_back(event(player.id, event::UP)); + event_cache.push_back(event(player->id(), event::UP)); } return this->event_cache; diff --git a/libopenage/curve/demo/aicontroller.h b/libopenage/curve/demo/aicontroller.h index 34ac413dbf..abcade24ec 100644 --- a/libopenage/curve/demo/aicontroller.h +++ b/libopenage/curve/demo/aicontroller.h @@ -13,8 +13,8 @@ namespace curvepong { class AIInput { public: std::vector &getInputs( - const PongPlayer &player, - const PongBall &ball, + const std::shared_ptr &player, + const std::shared_ptr &ball, const curve::curve_time_t &now); private: diff --git a/libopenage/curve/demo/config.h b/libopenage/curve/demo/config.h index 2055748cc3..9e09c4a4e0 100644 --- a/libopenage/curve/demo/config.h +++ b/libopenage/curve/demo/config.h @@ -1,8 +1,10 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + #pragma once // Define this to draw an ncurses based demo. // Without the GUI flag, just a trace of event is printed out -//#define GUI +#define GUI // If this is defined, player 1 can be played with the arrow keys. // else the player is replaced by an AI. @@ -12,4 +14,4 @@ // 0: run in real time with real deltas // 1: run very slow // 2: run very fast -#define REALTIME 0 +#define REALTIME 1 diff --git a/libopenage/curve/demo/gamestate.h b/libopenage/curve/demo/gamestate.h index 6b58e2c1ab..cb026d45e8 100644 --- a/libopenage/curve/demo/gamestate.h +++ b/libopenage/curve/demo/gamestate.h @@ -4,11 +4,12 @@ #include "config.h" -#include "../object.h" +#include "../events/eventtarget.h" #include "../continuous.h" #include "../discrete.h" #include "../../util/vector.h" +#include namespace openage { namespace curvepong { @@ -21,51 +22,95 @@ struct event { event() : player(0), state(IDLE) {} }; -class PongPlayer : public curve::Object { + +using namespace std::placeholders; +class PongPlayer : public openage::curve::EventTarget { public: - PongPlayer(openage::curve::TriggerFactory *f) : - Object(f), - speed(f), - position(f), - lives(f), - state(f), - size(f), - y(0), - id(0) {} - - curve::Discrete speed; - curve::Continuous position; - curve::Discrete lives; - curve::Discrete state; - curve::Discrete size; + PongPlayer(curve::EventManager *mgr, size_t id) : + EventTarget(mgr), + speed(std::make_shared>( + mgr, + (id << 4) + 1, + std::bind(&PongPlayer::child_changed, this, _1))), + position(std::make_shared>( + mgr, + (id << 4) + 2, + std::bind(&PongPlayer::child_changed, this, _1))), + lives(std::make_shared>( + mgr, + (id << 4) + 3, + std::bind(&PongPlayer::child_changed, this, _1))), + state(std::make_shared>( + mgr, + (id << 4) + 4, + std::bind(&PongPlayer::child_changed, this, _1))), + size(std::make_shared>( + mgr, + (id << 4) + 5, + std::bind(&PongPlayer::child_changed, this, _1))), + _id{id}, + y{0} {} + + std::shared_ptr> speed; + std::shared_ptr> position; + std::shared_ptr> lives; + std::shared_ptr> state; + std::shared_ptr> size; + size_t _id; float y; - int id; -}; -class PongBall : public curve::Object { -public: - PongBall(curve::TriggerFactory *f) : - Object(f), - speed(this), - position(this) {} - curve::Discrete> speed; - curve::Continuous> position; + size_t id() const override{ + return _id; + } +private: + void child_changed(const curve::curve_time_t &time) { + this->on_change(time); + } }; -class PongState : public curve::Object { + +class PongBall : public openage::curve::EventTarget { public: - PongState(curve::TriggerFactory *f) : - Object(f), - p1(f), - p2(f), - ball(f) {} + PongBall(curve::EventManager *mgr,size_t id) : + EventTarget(mgr), + speed(std::make_shared>>( + mgr, + (id << 2) + 1, + std::bind(&PongBall::child_changed, this, _1))), + position(std::make_shared>>( + mgr, + (id << 2) + 2, + std::bind(&PongBall::child_changed, this, _1))), + _id{id} + {} - PongPlayer p1; - PongPlayer p2; + std::shared_ptr>> speed; + std::shared_ptr>> position; - PongBall ball; + size_t id() const override{ + return _id; + } +private: + void child_changed(const curve::curve_time_t &time) { + this->on_change(time); + } + size_t _id; +}; +}} // namespace openage::curvepong + + +namespace openage { +class State { +public: + State(curve::EventManager *mgr) : + p1(std::make_shared(mgr, 0)), + p2(std::make_shared(mgr, 1)), + ball(std::make_shared(mgr, 2)) {} + std::shared_ptr p1; + std::shared_ptr p2; + std::shared_ptr ball; util::Vector<2> resolution; }; -}} // openage::curvepong +} // namespace openage diff --git a/libopenage/curve/demo/gui.cpp b/libopenage/curve/demo/gui.cpp index ee78f851f4..3a3bd5c0d4 100644 --- a/libopenage/curve/demo/gui.cpp +++ b/libopenage/curve/demo/gui.cpp @@ -8,10 +8,10 @@ namespace openage { namespace curvepong { -std::vector &Gui::getInputs(const PongPlayer &player) { +std::vector &Gui::getInputs(const std::shared_ptr &player) { input_cache.clear(); event evnt; - evnt.player = player.id; + evnt.player = player->id(); evnt.state = event::IDLE; timeout(0); int c = getch(); @@ -72,89 +72,98 @@ Gui::Gui() { keypad(stdscr, true); noecho(); curs_set(0); - // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); + + int x, y; + getmaxyx(stdscr, y, x); attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw( - 4, 5, " oooooooooo "); - mvprintw( - 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); - mvprintw( - 6, 5, " 888oooo88 888 888 888 888 888 88o "); - mvprintw( - 7, 5, " 888 888 888 888 888 888oo888o "); - mvprintw( - 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); - mvprintw( - 9, 5, " 888ooo888 "); + + std::vector buffer{ + "oooooooooo ", + " 888 888 ooooooo ooooooo oooooooo8 ", + " 888oooo88 888 888 888 888 888 88o ", + " 888 888 888 888 888 888oo888o ", + "o888o 88ooo88 o888o o888o 88 888 ", + " 888ooo888", + }; + + size_t colwidth = 0; + for (const auto &c : buffer) { + colwidth = std::max(colwidth, strlen(c)); + } + int row = (y - buffer.size()) / 2;; + int col = (x - colwidth) / 2; + for (const auto &c : buffer) { + mvprintw(row++, col, c); + } attroff(COLOR_PAIR(COLOR_DEBUG)); getch(); } -void Gui::draw(PongState &state, const curve::curve_time_t &now) { +void Gui::draw(std::shared_ptr &state, const curve::curve_time_t &now) { // clear(); // Print Score attron(COLOR_PAIR(COLOR_DEBUG)); - getmaxyx(stdscr, state.resolution[1], state.resolution[0]); - state.resolution[1] -= 1; + getmaxyx(stdscr, state->resolution[1], state->resolution[0]); + state->resolution[1] -= 1; attron(COLOR_PAIR(COLOR_DEBUG)); mvprintw(2, - state.resolution[0] / 2 - 5, + state->resolution[0] / 2 - 5, "P1 %i | P2 %i", - state.p1.lives(now), - state.p2.lives(now)); + state->p1->lives->get(now), + state->p2->lives->get(now)); - mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); - mvprintw(0, 1, "NOW: %f", now); - mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); + mvvline(0, state->resolution[0] / 2, ACS_VLINE, state->resolution[1]); + mvprintw(0, 1, "NOW: %d", now); + mvprintw(1, 1, "SCR: %i | %i", state->resolution[0], state->resolution[1]); mvprintw(2, 1, "P1: %f, %f, %i", - state.p1.position(now), - state.p1.y, - state.p1.state(now).state); + state->p1->position->get(now), + state->p1->y, + state->p1->state->get(now).state); mvprintw(3, 1, "P2: %f, %f, %i", - state.p2.position(now), - state.p2.y, - state.p2.state(now).state); - for (int i = 0; i < 1000; i += 100) { - mvprintw(4 + i / 100, + state->p2->position->get(now), + state->p2->y, + state->p2->state->get(now).state); + for (int i = 0; i < 100; i += 10) { + mvprintw(4 + i / 10, 1, "BALL in %03i: %f | %f; SPEED: %f | %f", i, - state.ball.position(now + i)[0], - state.ball.position(now + i)[1], - state.ball.speed(now + i)[0], - state.ball.speed(now + i)[1]); + state->ball->position->get(now + i)[0], + state->ball->position->get(now + i)[1], + state->ball->speed->get(now + i)[0], + state->ball->speed->get(now + i)[1]); } - mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); + mvprintw(state->resolution[1] - 1, 1, "Press ESC twice to Exit"); attroff(COLOR_PAIR(COLOR_DEBUG)); attron(COLOR_PAIR(COLOR_PLAYER1)); - for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { - mvprintw(state.p1.position(now) + i, state.p1.y, "|"); + for (int i = -state->p1->size->get(now) / 2; i < state->p1->size->get(now) / 2; i++) { + mvprintw(state->p1->position->get(now) + i, state->p1->y, "|"); } attroff(COLOR_PAIR(COLOR_PLAYER1)); attron(COLOR_PAIR(COLOR_PLAYER2)); - for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { - mvprintw(state.p2.position(now) + i, state.p2.y, "|"); + for (int i = -state->p2->size->get(now) / 2; i < state->p2->size->get(now) / 2; i++) { + mvprintw(state->p2->position->get(now) + i, state->p2->y, "|"); } attroff(COLOR_PAIR(COLOR_PLAYER2)); attron(COLOR_PAIR(COLOR_1)); for (int i = 1; i < 9999; ++i) { - draw_ball(state.ball.position(now + i), 'X'); + draw_ball(state->ball->position->get(now + i), 'X'); } attron(COLOR_PAIR(COLOR_0)); - draw_ball(state.ball.position(now), 'M'); + draw_ball(state->ball->position->get(now), 'M'); /*attron(COLOR_PAIR(COLOR_BALL)); - mvprintw(state.ball.position(now)[1], - state.ball.position(now)[0], + mvprintw(state->ball->position->get(now)[1], + state->ball->position->get(now)[0], "o"); */ attroff(COLOR_PAIR(COLOR_BALL)); diff --git a/libopenage/curve/demo/gui.h b/libopenage/curve/demo/gui.h index 3196f3b7a4..63f4bd7008 100644 --- a/libopenage/curve/demo/gui.h +++ b/libopenage/curve/demo/gui.h @@ -15,8 +15,8 @@ class Gui { public: Gui(); - std::vector &getInputs(const PongPlayer &player); - void draw(PongState &state, const curve::curve_time_t &now); + std::vector &getInputs(const std::shared_ptr &player); + void draw(std::shared_ptr &state, const curve::curve_time_t &now); void draw_ball(util::Vector<2> ball, char chr); private: diff --git a/libopenage/curve/demo/main.cpp b/libopenage/curve/demo/main.cpp index ac077ba557..91b60fd17e 100644 --- a/libopenage/curve/demo/main.cpp +++ b/libopenage/curve/demo/main.cpp @@ -6,10 +6,14 @@ #include "gui.h" #include "physics.h" +#include "../events/event.h" + #include #include +#include + typedef std::chrono::high_resolution_clock Clock; namespace openage { @@ -23,60 +27,67 @@ int demo() { bool running = true; srand(time(NULL)); while (running) { - curve::EventQueue queue; - curve::TriggerFactory factory{&queue}; + curve::EventManager events; curve::curve_time_t now = 1; curvepong::Physics phys; curvepong::AIInput ai; - curvepong::PongState state(&factory); - curvepong::Physics::init(state, &queue, now); - - state.p1.lives.set_drop(now, 3); - state.p1.id = 0; - state.p1.size.set_drop(now, 4); - state.p2.lives.set_drop(now, 3); - state.p2.id = 1; - state.p2.size.set_drop(now, 4); + auto state = std::make_shared(&events); + curvepong::Physics::init(state, &events, now); + + state->p1->lives->set_drop(now, 3); + state->p1->size->set_drop(now, 4); + + state->p2->lives->set_drop(now, 3); + state->p2->size->set_drop(now, 4); #ifdef GUI gui.draw(state, now); // update gui related parameters #else - state.resolution[0] = 100; - state.resolution[1] = 40; + state->resolution[0] = 100; + state->resolution[1] = 40; #endif auto loop_start = Clock::now(); now += 1; { std::vector start_event { event(0, event::START) }; - phys.processInput(state, state.p1, start_event, &queue, now); + phys.processInput(state, state->p1, start_event, &events, now); } #ifdef GUI gui.draw(state, now); // initial drawing with corrected ball #endif - while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { + while (state->p1->lives->get(now) > 0 && state->p2->lives->get(now) > 0) { //We need to get the inputs to be able to kill the game #ifdef HUMAN - phys.processInput(state, state.p1, gui.getInputs(state.p1), &queue, now); + phys.processInput(state, state->p1, gui.getInputs(state->p1), &events, now); #else #ifdef GUI - gui.getInputs(state.p1); + gui.getInputs(state->p1); #endif phys.processInput( - state, state.p1, ai.getInputs(state.p1, state.ball, now), &queue, now); + state, state->p1, ai.getInputs(state->p1, state->ball, now), &events, now); #endif phys.processInput( - state, state.p2, ai.getInputs(state.p2, state.ball, now), &queue, now); + state, state->p2, ai.getInputs(state->p2, state->ball, now), &events, now); - state.p1.y = 0; - state.p2.y = state.resolution[0] - 1; + state->p1->y = 0; + state->p2->y = state->resolution[0] - 1; - queue.execute_until(now + 10000); + events.execute_until(now, state); // phys.update(state, now); - queue.print(); #ifdef GUI gui.draw(state, now); + + + int pos = 1; + mvprintw(pos++, state->resolution[0]/2 + 10, "Queue: "); + for (const auto & e : events.queue.ro_queue()) { + mvprintw(pos++, state->resolution[0]/2 + 10, + "%d: %s ", + e->time(), e->eventclass()->id().c_str()); + } + #endif #if REALTIME == 0 @@ -89,7 +100,7 @@ bool running = true; now += dt; #elif REALTIME == 1 now += 1; - usleep(12000); + usleep(20000); #elif REALTIME == 2 now += 4; #else diff --git a/libopenage/curve/demo/physics.cpp b/libopenage/curve/demo/physics.cpp index e525d0a02b..215f06cbd5 100644 --- a/libopenage/curve/demo/physics.cpp +++ b/libopenage/curve/demo/physics.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "physics.h" @@ -14,109 +14,303 @@ namespace curvepong { const float extrapolating_time = 100.0f; -void Physics::init(PongState &state, curve::EventQueue *queue, const curve::curve_time_t &now) { +using namespace curve; + +class BallReflectWall : public EventClass { +public: + BallReflectWall () : EventClass("demo.ball.reflect_wall", EventClass::Type::ON_CHANGE) {} // FIXME: on_change as own class + + void setup(const std::shared_ptr &evnt, + const std::shared_ptr &state) override { + this->add_dependency(evnt, state->ball->position); // FIXME: add_trigger (and warn if not on_change) + this->add_dependency(evnt, state->ball->speed); + // TODO add dependency to size of area + // FIXME dependency to a full ball object + } + + // FIXME we REALLY need dependencies to objects i.e. Ball : public EventTarget() + // FIXME rename to invoke + // FIXME EventTarget for BALL!! + void call(curve::EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &now, + const EventClass::param_map &/*param*/) override { + // TODO Do we really need to check for the time? + auto positioncurve = std::dynamic_pointer_cast>>(target); + auto speedcurve = state->ball->speed; + + // All the magic in the next lines + auto speed = speedcurve->get(now); + auto pos = positioncurve->get(now); + speed[1] *= -1.0; + state->ball->speed->set_drop(now, speed); + state->ball->position->set_drop(now, pos); + + if (speed[1] == 0) + return; + + double ty = 0; + if (speed[1] > 0) { + // fixme rename resolution to display_boundary + ty = (state->resolution[1] - pos[1]) / speed[1]; + } else if (speed[1] < 0) { + ty = pos[1] / -speed[1]; + } else { + } + state->ball->position->set_drop(now+ty, pos + speed * ty); + } + + // FIXME rename to predict_invoke_time + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &now) override { + auto positioncurve = std::dynamic_pointer_cast>>(target); + auto speed = state->ball->speed->get(now); + auto pos = positioncurve->get(now); + + if (speed[1] == 0) { + return std::numeric_limits::max(); + } + double ty = 0; + if (speed[1] > 0) { + ty = (state->resolution[1] - pos[1]) / speed[1]; + } else if (speed[1] < 0) { + ty = pos[1] / -speed[1]; + } else { + } +#ifdef GUI + mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); +#endif + return now + ty; + } +}; + +class BallReflectPanel : public curve::EventClass { +public: + BallReflectPanel () : curve::EventClass("demo.ball.reflect_panel", EventClass::Type::ON_CHANGE) {} + + void setup(const std::shared_ptr &target, + const std::shared_ptr &state) override { + add_dependency(target, state->ball->position); + add_dependency(target, state->ball->speed); + add_dependency(target, state->p1->position); + add_dependency(target, state->p2->position); + // TODO add dependency to size of area + // FIXME dependency to a full ball object + } + + // FIXME we REALLY need dependencies to objects + void call(curve::EventManager *mgr, + const std::shared_ptr & /*target*/, + const std::shared_ptr &state, + const curve::curve_time_t &now, + const EventClass::param_map &/*param*/) override { + + auto pos = state->ball->position->get(now); + auto speed = state->ball->speed->get(now); +#ifdef GUI + static int cnt = 0; + mvprintw(21, 22, "Panel hit [%i] ", ++cnt); +#else + std::cout << "\nPanel\n"; +#endif + + if (pos[0] <= 1 + && speed[0] < 0 + && (pos[1] < state->p1->position->get(now) - state->p1->size->get(now) / 2 + || pos[1] > state->p1->position->get(now) + state->p1->size->get(now) / 2)) { + // Ball missed the paddel of player 1 + auto l = state->p1->lives->get(now); + l--; + state-> + p1->lives->set_drop(now, l); + state->ball->position->set_drop(now, pos); + Physics::reset(state, mgr, now); + mvprintw(21, 18, "1"); + } else if (pos[0] >= state->resolution[0]-1 + && speed[0] > 0 + && (pos[1] < state->p2->position->get(now) - state->p2->size->get(now) / 2 + || pos[1] > state->p2->position->get(now) + state->p2->size->get(now) / 2)) { + // Ball missed the paddel of player 2 + auto l = state->p2->lives->get(now); + l --; + state->p2->lives->set_drop(now, l); + state->ball->position->set_drop(now, pos); + Physics::reset(state, mgr, now); + mvprintw(21, 18, "2"); + } else if (pos[0] >= state->resolution[0]- 1 || pos[0] <= 1) { + speed[0] *= -1; + state->ball->speed->set_drop(now, speed); + state->ball->position->set_drop(now, pos); + } + + float ty = 0; + if (speed[0] > 0) { + ty = (state->resolution[0] - pos[0]) / speed[0]; + } else if (speed[0] < 0) { + ty = pos[0] / -speed[0]; + } + auto hit_pos = pos + speed * ty; + hit_pos[0] = speed[0] > 0 ? state->resolution[0] : 0; + state->ball->position->set_drop(now+ty, hit_pos); + } + + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &now) override { + auto positioncurve = std::dynamic_pointer_cast>>(target); + auto speed = state->ball->speed->get(now); + auto pos = positioncurve->get(now); + + if (speed[0] == 0) + return std::numeric_limits::max(); + float ty = 0; + if (speed[0] > 0) { + ty = (state->resolution[0] - pos[0]) / speed[0]; + } else if (speed[0] < 0) { + ty = pos[0] / -speed[0]; + } +#ifdef GUI + mvprintw(21, 40, "AT %f NEXT %f", now, now + ty); + mvprintw(21, 18, "2"); +#endif + auto hit_pos = pos + speed * ty; + hit_pos[0] = speed[0] > 0 ? state->resolution[0] : 0; + assert(hit_pos[0] >= 0); + return now + ty; + } +}; + + +class ResetGame : public curve::EventClass { +public: + ResetGame () : curve::EventClass("demo.reset", EventClass::Type::ONCE) {} + + void setup(const std::shared_ptr &target, const std::shared_ptr &state) override { + (void)target; + (void)state; + } + + void call(curve::EventManager *mgr, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &now, + const EventClass::param_map &/*param*/) override { + (void) mgr; + (void) target; + + // Check if the condition still applies + { + auto pos = state->ball->position->get(now); + if (pos[0] > 0 && pos[0] < state->resolution[0]) { + // the gamestate is still valid - there is no need to reset + return; + } + } + + state->ball->position->set_drop(now-0.1, state->ball->position->get(now)); + state->ball->position->set_drop(now, state->resolution * 0.5); + state->p1->position->set_drop(now, state->resolution[1] / 2); + state->p2->position->set_drop(now, state->resolution[1] / 2); + + float dirx = 1;//(rand() % 2 * 2) - 1; + float diry = 0.1;//(rand() % 2 * 2) - 1; + auto init_speed = + util::Vector<2>( + dirx * (0.001 + (rand() % 100) / 100.f), + diry * (0.001 + (rand() % 100) / 200.f)); + + state->ball->speed->set_drop(now, init_speed); + auto pos = state->ball->position->get(now); + static int cnt = 0; + mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", + init_speed[0], + init_speed[1], + pos[0], + pos[1], + ++cnt); + + double ty = 0; + if (init_speed[1] > 0) { + ty = (state->resolution[1] - pos[1]) / init_speed[1]; + } else if (init_speed[1] < 0) { + ty = pos[1] / -init_speed[1]; + } else { + } + state->ball->position->set_drop(now+ty, pos + init_speed * ty); + } + + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &old_time) override { + (void) target; + (void) state; + return old_time; + } +}; + +void Physics::init(std::shared_ptr &state, + curve::EventManager *mgr, + const curve::curve_time_t &now) { #ifndef GUI std::cout << "Init" << std::endl; #endif + mgr->add_class(std::make_shared()); + mgr->add_class(std::make_shared()); + mgr->add_class(std::make_shared()); - queue->schedule( - "physics.predictor.panel", - now, - [&state, &queue](const curve::curve_time_t &now) { - return predict_reflect_panel(state, queue, now); - }, - [&state] (curve::EventQueue *queue, const curve::curve_time_t &now) { - ball_reflect_panel(state, queue, now); - }, { - &state.ball.position, - &state.p1.position, - &state.p2.position - }); - - queue->schedule( - "physics.predictor.wall", - now, - [&state, &queue](const curve::curve_time_t &now) { - return predict_reflect_wall(state, queue, now); - }, - [&state] (curve::EventQueue *queue, const curve::curve_time_t &now) { - ball_reflect_wall(state, queue, now); - }, {&state.ball.position}); - - -/* state.ball.speed.clearevents(); - state.ball.speed.on_change_future( - "physics.change_future", - [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { - predict_reflect_wall(state, queue, now); - predict_reflect_panel(state, queue, now); - }); - - state.p1.position.clearevents(); - state.p1.position.on_change( - now, - "physics.reflect_panel", - [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { - auto t = predict_reflect_panel(state, queue, now); - queue->reschedule(t); - }); - - state.p2.position.clearevents(); - state.p2.position.on_change( - now, - "physics.reflect_panel", - [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { - auto t = predict_reflect_panel(state, queue, now); - queue->reschedule(t); - }); -*/ - reset(state, queue, now); + mgr->on("demo.ball.reflect_wall", state->ball->position, state, now); + mgr->on("demo.ball.reflect_panel", state->ball->position, state, now); + // FIXME once "reset": deregister + +// reset(state, mgr, now); } -void Physics::processInput(PongState &state, - PongPlayer &player, +void Physics::processInput(std::shared_ptr &state, + std::shared_ptr &player, std::vector &events, - curve::EventQueue *queue, - const curve::curve_time_t &now) { + EventManager *mgr, + const curve_time_t &now) { for (auto evnt : events) { //Process only if the future has changed - if (player.state.get(now).state != evnt.state) { - player.state.set_drop(now, evnt); + if (player->state->get(now).state != evnt.state) { + player->state->set_drop(now, evnt); switch(evnt.state) { case event::UP: case event::DOWN: { if (evnt.state == event::UP) { - player.speed.set_drop(now, -2); + player->speed->set_drop(now, -2); } else if (evnt.state == event::DOWN) { - player.speed.set_drop(now, 2); + player->speed->set_drop(now, 2); } - player.speed.set_drop(now + extrapolating_time, 0); + player->speed->set_drop(now + extrapolating_time, 0); - float new_pos = player.position.get(now) + - (player.speed.get(now+extrapolating_time) - - player.speed.get(now) / 2 + player.speed.get(now)); + float new_pos = player->position->get(now) + + (player->speed->get(now+extrapolating_time) + - player->speed->get(now) / 2 + player->speed->get(now)); if (new_pos < 0) new_pos = 0; - if (new_pos > state.resolution[1]) - new_pos = state.resolution[1]; + if (new_pos > state->resolution[1]) + new_pos = state->resolution[1]; - player.position.set_drop(now+extrapolating_time, new_pos); + player->position->set_drop(now+extrapolating_time, new_pos); evnt.state = event::IDLE; - player.state.set_drop(now + extrapolating_time, evnt); + player->state->set_drop(now + extrapolating_time, evnt); // predict_reflect_panel(state, queue, now); break; } case event::IDLE: -// player.position.set_drop(now+extrapolating_time, -// player.position.get(now)); +// player->position->set_drop(now+extrapolating_time, +// player->position->get(now)); break; case event::START: - reset(state, queue, now); + reset(state, mgr, now); break; - //if (player.state.get(now).state == event::LOST) { - // state.ball.position.set_drop(now, state.resolution * 0.5); + //if (player->state->get(now).state == event::LOST) { + // state->ball.position->set_drop(now, state.resolution * 0.5); //} //update_ball(state, now, init_recursion_limit); //break; @@ -128,167 +322,10 @@ void Physics::processInput(PongState &state, } -void Physics::reset(PongState &state, - curve::EventQueue *,//q, +void Physics::reset(const std::shared_ptr &state, + curve::EventManager *mgr, const curve::curve_time_t &now) { -// q->clear(now); - state.on_pre_horizon( - now, "physics.reset", - [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { - - state.ball.position.set_drop(now-0.1, state.ball.position.get(now)); - state.ball.position.set_drop(now, state.resolution * 0.5); - state.p1.position.set_drop(now, state.resolution[1] / 2); - state.p2.position.set_drop(now, state.resolution[1] / 2); - float dirx = 1;//(rand() % 2 * 2) - 1; - float diry = 0.1;//(rand() % 2 * 2) - 1; - auto init_speed = - util::Vector<2>( - dirx * (0.0001 + (rand() % 100) / 1000.f), - diry * (0.0001 + (rand() % 100) / 2000.f)); - - state.ball.speed.set_drop(now, init_speed); - auto pos = state.ball.position.get(now); - static int cnt = 0; - mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", - init_speed[0], - init_speed[1], - pos[0], - pos[1], - ++cnt); - predict_reflect_panel(state, queue, now); - predict_reflect_wall(state, queue, now); - }); -} - - -void Physics::ball_reflect_wall(PongState &state, - curve::EventQueue *, //queue, - const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -#ifndef GUI - std::cout << "\nWall\n"; -#else - static int cnt = 0; - mvprintw(22, 22, "Wall Reflect [%i]", ++cnt); - mvprintw(23, 22, "Speed[1] is %f", speed[1]); -#endif - speed[1] *= -1.0; - state.ball.speed.set_drop(now, speed); - state.ball.position.set_drop(now, pos); - -// predict_reflect_wall(state, queue, now); -} - - -curve::curve_time_t Physics::predict_reflect_wall( - PongState &state, - curve::EventQueue *, //queue, - const curve::curve_time_t &now) -{ - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); - if (speed[1] == 0) return std::numeric_limits::max(); - double ty = 0; - if (speed[1] > 0) { - ty = (state.resolution[1] - pos[1]) / speed[1]; - } else if (speed[1] < 0) { - ty = pos[1] / -speed[1]; - } else { -// throw Error(MSG(err) << "speed was 0"); - } -#ifdef GUI - mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); -#endif - if (ty > 0) { -// auto hit_pos = pos + speed * ty; -// hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; -// assert(hit_pos[0] >= 0); -// assert(hit_pos[1] >= 0); -// state.ball.position.set_drop(now + ty, hit_pos); -// ball_reflect_wall(state, queue, now + ty); - } else { -// throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); - } - return now + ty; -} - - -void Physics::ball_reflect_panel(PongState &state, - curve::EventQueue *queue, - const curve::curve_time_t &now) { - - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -#ifdef GUI - static int cnt = 0; - mvprintw(21, 22, "Panel hit [%i] ", ++cnt); -#else - std::cout << "\nPanel\n"; -#endif - - if (pos[0] <= 1 - && speed[0] < 0 - && (pos[1] < state.p1.position.get(now) - state.p1.size.get(now) / 2 - || pos[1] > state.p1.position.get(now) + state.p1.size.get(now) / 2)) { - // Ball missed the paddel of player 1 - auto l = state.p1.lives(now); - l--; - state. - p1.lives.set_drop(now, l); - state.ball.position.set_drop(now, pos); - reset(state, queue, now); - mvprintw(21, 18, "1"); - } else if (pos[0] >= state.resolution[0]-1 - && speed[0] > 0 - && (pos[1] < state.p2.position.get(now) - state.p2.size.get(now) / 2 - || pos[1] > state.p2.position.get(now) + state.p2.size.get(now) / 2)) { - // Ball missed the paddel of player 2 - auto l = state.p2.lives(now); - l --; - state.p2.lives.set_drop(now, l); - state.ball.position.set_drop(now, pos); - reset(state, queue, now); - mvprintw(21, 18, "2"); - } else if (pos[0] >= state.resolution[0]- 1 || pos[0] <= 1) { - speed[0] *= -1.0; - state.ball.speed.set_drop(now, speed); - state.ball.position.set_drop(now, pos); -// predict_reflect_panel(state, queue, now); - } -} - - -curve::curve_time_t Physics::predict_reflect_panel(PongState &state, - curve::EventQueue *queue, - const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -// speed[1] += (rand() % 50 - 50)/10; - if (speed[0] == 0) return std::numeric_limits::max(); - float ty = 0; - if (speed[0] > 0) { - ty = (state.resolution[0] - pos[0]) / speed[0]; - } else if (speed[0] < 0) { - ty = pos[0] / -speed[0]; - } -#ifdef GUI - mvprintw(21, 40, "AT %f NEXT %f", now, now + ty); - mvprintw(21, 18, "2"); -#endif - auto hit_pos = pos + speed * ty; - hit_pos[0] = speed[0] > 0 ? state.resolution[0] : 0; - assert(hit_pos[0] >= 0); - //assert(hit_pos[1] >= 0); // this might validly happen -// state.ball.position.set_drop(now + ty, hit_pos); - // queue->addcallback(now + ty, "physics.reflect_panel"// , - // [&state](curve::EventQueue *q, const curve::curve_time_t &t) { -// ball_reflect_panel(state, queue, now + ty); - // }) -; - return now + ty; - + mgr->on("demo.reset", state->ball->position, state, now); } }} // openage::curvepong diff --git a/libopenage/curve/demo/physics.h b/libopenage/curve/demo/physics.h index 929ae97538..5d84f533e9 100644 --- a/libopenage/curve/demo/physics.h +++ b/libopenage/curve/demo/physics.h @@ -6,7 +6,7 @@ #include "gamestate.h" #include "../curve.h" -#include "../events.h" +#include "../events/eventmanager.h" #include @@ -15,18 +15,19 @@ namespace curvepong { class Physics { public: - - static void init(PongState &, curve::EventQueue *, const curve::curve_time_t &); - void processInput(PongState &, PongPlayer &, std::vector &input, curve::EventQueue *, const curve::curve_time_t &now); -protected: - - static void reset(PongState &, curve::EventQueue *, const curve::curve_time_t &); - - - static void ball_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void ball_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static curve::curve_time_t predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static curve::curve_time_t predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); + static void init(std::shared_ptr &, + curve::EventManager *, + const curve::curve_time_t &); + + void processInput(std::shared_ptr &, + std::shared_ptr &, + std::vector &input, + curve::EventManager *, + const curve::curve_time_t &now); + + static void reset(const std::shared_ptr &, + curve::EventManager *mgr, + const curve::curve_time_t &); }; }} // openage::curvepong diff --git a/libopenage/curve/demo_events/CMakeLists.txt b/libopenage/curve/demo_events/CMakeLists.txt deleted file mode 100644 index c1545e58c1..0000000000 --- a/libopenage/curve/demo_events/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_sources (libopenage - aicontroller.cpp - gamestate.cpp - gui.cpp - main.cpp - physics.cpp -) diff --git a/libopenage/curve/demo_events/aicontroller.cpp b/libopenage/curve/demo_events/aicontroller.cpp deleted file mode 100644 index 69f012d015..0000000000 --- a/libopenage/curve/demo_events/aicontroller.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "aicontroller.h" - -namespace openage { -namespace curvepong { - -std::vector &AIInput::getInputs( - const PongPlayer &player, - const PongBall &ball, - const curve::curve_time_t &now) { - this->event_cache.clear(); - - auto position = player.position.get(now); - - // Yes i know, there is /3 used - instead of the logical /2 - this is to - // create a small safety boundary of 1/3 for enhanced fancyness - - // Ball is below position - if (ball.position.get(now)[1] > position + player.size.get(now) / 3) { - event_cache.push_back(event(player.id, event::DOWN)); - } else if (ball.position.get(now)[1] < position - player.size.get(now) / 3) { - // Ball is above position - event_cache.push_back(event(player.id, event::UP)); - } - - return this->event_cache; -} - -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/aicontroller.h b/libopenage/curve/demo_events/aicontroller.h deleted file mode 100644 index eeddca8b0b..0000000000 --- a/libopenage/curve/demo_events/aicontroller.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gamestate.h" - -#include - -namespace openage { -namespace curvepong { - -class AIInput { -public: - std::vector &getInputs( - const PongPlayer &player, - const PongBall &ball, - const curve::curve_time_t &now); - -private: - std::vector event_cache; -}; - -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gamestate.cpp b/libopenage/curve/demo_events/gamestate.cpp deleted file mode 100644 index c91b21ccb0..0000000000 --- a/libopenage/curve/demo_events/gamestate.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "gamestate.h" - -namespace openage { -namespace curvepong { - -// This file is intentionally left empty - -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gamestate.h b/libopenage/curve/demo_events/gamestate.h deleted file mode 100644 index 83d2be1187..0000000000 --- a/libopenage/curve/demo_events/gamestate.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../continuous.h" -#include "../discrete.h" -#include "../../util/vector.h" - -namespace openage { -namespace curvepong { - -struct event { - int player; - enum state_e { - UP, DOWN, START, IDLE, LOST - } state; - event(int id, state_e s) : player(id), state(s) {} - event() : player(0), state(IDLE) {} -}; - -class PongPlayer { -public: - PongPlayer(openage::curve::TriggerFactory *f) : - speed(f), - position(f), - lives(f), - state(f), - size(f) { - speed.set_drop(0, 1); - position.set_drop(0, 0.5); - lives.set_drop(0, 1); - state.set_drop(0, event(0, event::IDLE)); - size.set_drop(0, 0.1); - y = 0; - id = 0; - } - - curve::Discrete speed; - curve::Continuous position; - curve::Discrete lives; - curve::Discrete state; - curve::Discrete size; - float y; - int id; -}; - -class PongBall { -public: - PongBall(curve::TriggerFactory *f) : - speed(f), - position(f) {} - curve::Discrete> speed; - curve::Continuous> position; -}; - -class PongState { -public: - PongState(curve::TriggerFactory *f) : - p1(f), - p2(f), - ball(f) {} - - PongPlayer p1; - PongPlayer p2; - - PongBall ball; - - util::Vector<2> resolution; -}; - -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gui.cpp b/libopenage/curve/demo_events/gui.cpp deleted file mode 100644 index 0f07bc5141..0000000000 --- a/libopenage/curve/demo_events/gui.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "gui.h" - -#include -#include - -namespace openage { -namespace curvepong { - -std::vector &Gui::getInputs(const PongPlayer &player) { - input_cache.clear(); - event evnt; - evnt.player = player.id; - evnt.state = event::IDLE; - timeout(0); - int c = getch(); - // mvprintw(0,1, "IN: %i", c); - switch (c) { - case KEY_DOWN: - evnt.state = event::DOWN; - input_cache.push_back(evnt); - mvprintw(1, 1, "DOWN"); - break; - case KEY_UP: - evnt.state = event::UP; - input_cache.push_back(evnt); - mvprintw(1, 1, "UP"); - break; - case ' ': - evnt.state = event::START; - break; - case 27: // esc or alt - endwin(); - exit(0); - default: break; - } - - return input_cache; -} - - -enum { - COLOR_PLAYER1 = 1, - COLOR_PLAYER2 = 2, - COLOR_BALL = 3, - COLOR_DEBUG = 4, - - COLOR_0 = 5, - COLOR_1 = 6, - COLOR_2 = 7, - COLOR_3 = 8, - COLOR_4 = 9, -}; - - -Gui::Gui() { - initscr(); - start_color(); - init_pair(COLOR_PLAYER1, COLOR_BLUE, COLOR_BLUE); - init_pair(COLOR_PLAYER2, COLOR_RED, COLOR_RED); - init_pair(COLOR_BALL, COLOR_BLUE, COLOR_WHITE); - init_pair(COLOR_DEBUG, COLOR_WHITE, COLOR_BLACK); - init_pair(COLOR_0, COLOR_RED, COLOR_BLACK); - init_pair(COLOR_1, COLOR_GREEN, COLOR_BLACK); - - keypad(stdscr, true); - noecho(); - curs_set(0); - // getmaxyx(stdscr,state.resolution[1], state.resolution[0]); - - attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw( - 4, 5, " oooooooooo "); - mvprintw( - 5, 5, " 888 888 ooooooo ooooooo oooooooo8 "); - mvprintw( - 6, 5, " 888oooo88 888 888 888 888 888 88o "); - mvprintw( - 7, 5, " 888 888 888 888 888 888oo888o "); - mvprintw( - 8, 5, " o888o 88ooo88 o888o o888o 88 888 "); - mvprintw( - 9, 5, " 888ooo888 "); - attroff(COLOR_PAIR(COLOR_DEBUG)); - - getch(); -} - - -void Gui::draw(PongState &state, const curve::curve_time_t &now) { - // clear(); - // Print Score - attron(COLOR_PAIR(COLOR_DEBUG)); - getmaxyx(stdscr, state.resolution[1], state.resolution[0]); - state.resolution[1] -= 1; - attron(COLOR_PAIR(COLOR_DEBUG)); - mvprintw(2, - state.resolution[0] / 2 - 5, - "P1 %i | P2 %i", - state.p1.lives(now), - state.p2.lives(now)); - - mvvline(0, state.resolution[0] / 2, ACS_VLINE, state.resolution[1]); - mvprintw(0, 1, "NOW: %f", now); - mvprintw(1, 1, "SCR: %i | %i", state.resolution[0], state.resolution[1]); - mvprintw(2, - 1, - "P1: %f, %f, %i", - state.p1.position(now), - state.p1.y, - state.p1.state(now).state); - mvprintw(3, - 1, - "P2: %f, %f, %i", - state.p2.position(now), - state.p2.y, - state.p2.state(now).state); - for (int i = 0; i < 1000; i += 100) { - mvprintw(4 + i / 100, - 1, - "BALL in %03i: %f | %f; SPEED: %f | %f", - i, - state.ball.position(now + i)[0], - state.ball.position(now + i)[1], - state.ball.speed(now + i)[0], - state.ball.speed(now + i)[1]); - } - mvprintw(state.resolution[1] - 1, 1, "Press ESC twice to Exit"); - attroff(COLOR_PAIR(COLOR_DEBUG)); - - attron(COLOR_PAIR(COLOR_PLAYER1)); - for (int i = -state.p1.size(now) / 2; i < state.p1.size(now) / 2; i++) { - mvprintw(state.p1.position(now) + i, state.p1.y, "|"); - } - attroff(COLOR_PAIR(COLOR_PLAYER1)); - - attron(COLOR_PAIR(COLOR_PLAYER2)); - for (int i = -state.p2.size(now) / 2; i < state.p2.size(now) / 2; i++) { - mvprintw(state.p2.position(now) + i, state.p2.y, "|"); - } - attroff(COLOR_PAIR(COLOR_PLAYER2)); - - attron(COLOR_PAIR(COLOR_1)); - for (int i = 1; i < 9999; ++i) { - draw_ball(state.ball.position(now + i), 'X'); - } - attron(COLOR_PAIR(COLOR_0)); - draw_ball(state.ball.position(now), 'M'); - /*attron(COLOR_PAIR(COLOR_BALL)); - mvprintw(state.ball.position(now)[1], - state.ball.position(now)[0], - "o"); - */ - attroff(COLOR_PAIR(COLOR_BALL)); - refresh(); - erase(); -} - - -void Gui::draw_ball(util::Vector<2> pos, char chr) { - mvprintw((int)(pos[1]), (int)(pos[0]), "%c", chr); - standend(); -} -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/gui.h b/libopenage/curve/demo_events/gui.h deleted file mode 100644 index 708a3a8c0d..0000000000 --- a/libopenage/curve/demo_events/gui.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gamestate.h" - -#include - -namespace openage { -namespace curvepong { - - -class Gui { - -public: - Gui(); - std::vector &getInputs(const PongPlayer &player); - void draw(PongState &state, const curve::curve_time_t &now); - void draw_ball(util::Vector<2> ball, char chr); - -private: - std::vector input_cache; -}; - -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/main.cpp b/libopenage/curve/demo_events/main.cpp deleted file mode 100644 index 316227065c..0000000000 --- a/libopenage/curve/demo_events/main.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "aicontroller.h" -#include "gamestate.h" -#include "gui.h" -#include "physics.h" - -#include - -#include - -typedef std::chrono::high_resolution_clock Clock; - -#define GUI -#define REALTIME 3 -#undef HUMAN - -namespace openage { -namespace curvepong { - -int demo() { - // Restart forever -#ifdef GUI - curvepong::Gui gui; -#endif - curve::EventQueue queue; - curve::TriggerFactory factory{&queue}; - curvepong::Physics phys; - curvepong::AIInput ai; - bool running = true; - srand(time(NULL)); - while (running) { - curvepong::PongState state(&factory); - curve::curve_time_t now = 1; - - state.p1.lives.set_drop(now, 3); - state.p1.id = 0; - state.p1.size.set_drop(now, 4); - state.p2.lives.set_drop(now, 3); - state.p2.id = 1; - state.p2.size.set_drop(now, 4); -#ifdef GUI - gui.draw(state, now); // update gui related parameters -#else - state.resolution[0] = 100; - state.resolution[1] = 40; -#endif - - auto loop_start = Clock::now(); - now += 1; - { - std::vector start_event { event(0, event::START) }; - phys.processInput(state, state.p1, start_event, &queue, now); - } - -#ifdef GUI - gui.draw(state, now); // initial drawing with corrected ball -#endif - while (state.p1.lives.get(now) > 0 && state.p2.lives.get(now) > 0) { - //We need to get the inputs to be able to kill the game -#ifdef HUMAN - phys.processInput(state, state.p1, gui.getInputs(state.p1), &queue, now); -#else - gui.getInputs(state.p1); - phys.processInput( - state, state.p1, ai.getInputs(state.p1, state.ball, now), &queue, now); -#endif - phys.processInput( - state, state.p2, ai.getInputs(state.p2, state.ball, now), &queue, now); - - state.p1.y = 0; - state.p2.y = state.resolution[0] - 1; - - queue.execute_until(now + 100); -// phys.update(state, now); - queue.print(); -#ifdef GUI - gui.draw(state, now); -#endif -#if REALTIME == 1 - usleep(4000); - double dt = std::chrono::duration_cast( - (Clock::now() - loop_start)) - .count(); - now += dt; -#elif REALTIME == 2 - now += 4; -#else - now += 1; - usleep(4000); -#endif - loop_start = Clock::now(); - } - } - return 0; -} - - -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/physics.cpp b/libopenage/curve/demo_events/physics.cpp deleted file mode 100644 index 5e3c61e9d0..0000000000 --- a/libopenage/curve/demo_events/physics.cpp +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "physics.h" -#include "../../error/error.h" - -#include -#include - -#include - -#define GUI - -namespace openage { -namespace curvepong { - -const float extrapolating_time = 100.0f; - -void Physics::processInput(PongState &state, - PongPlayer &player, - std::vector &events, - curve::EventQueue *queue, - const curve::curve_time_t &now) { - for (auto evnt : events) { - //Process only if the future has changed - if (player.state.get(now).state != evnt.state) { - player.state.set_drop(now, evnt); - - switch(evnt.state) { - case event::UP: - case event::DOWN: { - if (evnt.state == event::UP) { - player.speed.set_drop(now, -2); - } else if (evnt.state == event::DOWN) { - player.speed.set_drop(now, 2); - } - player.speed.set_drop(now + extrapolating_time, 0); - - float new_pos = player.position.get(now) + - (player.speed.get(now+extrapolating_time) - - player.speed.get(now) / 2 + player.speed.get(now)); - if (new_pos < 0) - new_pos = 0; - if (new_pos > state.resolution[1]) - new_pos = state.resolution[1]; - - player.position.set_drop(now+extrapolating_time, new_pos); - evnt.state = event::IDLE; - player.state.set_drop(now + extrapolating_time, evnt); -// predict_reflect_panel(state, queue, now); - break; - } - case event::IDLE: - player.position.set_drop(now+extrapolating_time, - player.position.get(now)); - break; - case event::START: - reset(state, queue, now); - break; - - //if (player.state.get(now).state == event::LOST) { - // state.ball.position.set_drop(now, state.resolution * 0.5); - //} - //update_ball(state, now, init_recursion_limit); - //break; - default: - break; - } - } - } -} - - -void Physics::reset(PongState &state, - curve::EventQueue *q, - const curve::curve_time_t &now) { - q->clear(now); - q->addcallback(now, "COLL WALL", - [&state](curve::EventQueue *queue, const curve::curve_time_t &now) { - state.ball.position.set_drop(now, state.resolution * 0.5); - state.p1.position.set_drop(now, state.resolution[1] / 2); - state.p2.position.set_drop(now, state.resolution[1] / 2); - float dirx = (rand() % 2 * 2) - 1; - float diry = (rand() % 2 * 2) - 1; - auto init_speed = - util::Vector<2>( - dirx * (0.0001 + (rand() % 100) / 1000.f), - diry * (0.0001 + (rand() % 100) / 2000.f)); - - state.ball.speed.set_drop(now, init_speed); - auto pos = state.ball.position.get(now); - static int cnt = 0; - mvprintw(20, 20, "Reset. Speed %f | %f POS %f | %f [%i]", - init_speed[0], - init_speed[1], - pos[0], - pos[1], - ++cnt); - predict_reflect_panel(state, queue, now); - predict_reflect_wall(state, queue, now); - }); -} - - -void Physics::ball_reflect_wall(PongState &state, - curve::EventQueue *queue, - const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -#ifndef GUI - std::cout << "\nWall\n"; -#else - static int cnt = 0; - mvprintw(22, 22, "Wall Reflect [%i]", ++cnt); - mvprintw(23, 22, "Speed[1] is %f", speed[1]); -#endif - speed[1] *= -1.0; - state.ball.speed.set_drop(now, speed); - state.ball.position.set_drop(now, pos); - - predict_reflect_wall(state, queue, now); -} - - -void Physics::predict_reflect_wall(PongState &state, - curve::EventQueue *queue, - const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); - - double ty = 0; - if (speed[1] > 0) { - ty = (state.resolution[1] - pos[1]) / speed[1]; - } else if (speed[1] < 0) { - ty = pos[1] / -speed[1]; - } else { - throw Error(MSG(err) << "speed was 0"); - } -#ifdef GUI - mvprintw(22, 40, "WALL TY %f NOW %f, NOWTY %f ", ty, now, now + ty); -#endif - if (ty > 0) { - auto hit_pos = pos + speed * ty; - hit_pos[1] = speed[1] > 0 ? state.resolution[1] : 0; - //assert(hit_pos[0] >= 0); - assert(hit_pos[1] >= 0); - state.ball.position.set_drop(now + ty, hit_pos); - queue->addcallback(now + ty, "COLL WALL", - [&state](curve::EventQueue *q, const curve::curve_time_t &t) { - ball_reflect_wall(state, q, t); - }); - } else { - throw Error(MSG(err) << "lost a callback because ty was " << ty << " <= 0"); - } -} - - -void Physics::ball_reflect_panel(PongState &state, - curve::EventQueue *queue, - const curve::curve_time_t &now) { - - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -#ifdef GUI - static int cnt = 0; - mvprintw(21, 22, "Panel hit [%i] ", ++cnt); -#else - std::cout << "\nPanel\n"; -#endif - - if (pos[0] <= 1 - && speed[0] < 0 - && (pos[1] < state.p1.position.get(now) - state.p1.size.get(now) / 2 - || pos[1] > state.p1.position.get(now) + state.p1.size.get(now) / 2)) { - // Ball missed the paddel of player 1 - auto l = state.p1.lives(now); - l --; - state.p1.lives.set_drop(now, l); - state.ball.position.set_drop(now, pos); - reset(state, queue, now); - mvprintw(21, 18, "1"); - } else if (pos[0] >= state.resolution[0]-1 - && speed[0] > 0 - && (pos[1] < state.p2.position.get(now) - state.p2.size.get(now) / 2 - || pos[1] > state.p2.position.get(now) + state.p2.size.get(now) / 2)) { - // Ball missed the paddel of player 2 - auto l = state.p2.lives(now); - l --; - state.p2.lives.set_drop(now, l); - state.ball.position.set_drop(now, pos); - reset(state, queue, now); - mvprintw(21, 18, "2"); - } else if (pos[0] >= state.resolution[0]- 1 || pos[0] <= 1) { - speed[0] *= -1.0; - state.ball.speed.set_drop(now, speed); - state.ball.position.set_drop(now, pos); - predict_reflect_panel(state, queue, now); - } -} - - -void Physics::predict_reflect_panel(PongState &state, - curve::EventQueue *queue, - const curve::curve_time_t &now) { - auto pos = state.ball.position.get(now); - auto speed = state.ball.speed.get(now); -// speed[1] += (rand() % 50 - 50)/10; - float ty = 0; - if (speed[0] > 0) { - ty = (state.resolution[0] - pos[0]) / speed[0]; - } else if (speed[0] < 0) { - ty = pos[0] / -speed[0]; - } -#ifdef GUI - mvprintw(21, 40, "AT %f NEXT %f", now, now + ty); - mvprintw(21, 18, "2"); -#endif - auto hit_pos = pos + speed * ty; - hit_pos[0] = speed[0] > 0 ? state.resolution[0] : 0; - assert(hit_pos[0] >= 0); -// assert(hit_pos[1] >= 0); // this might validly happen - state.ball.position.set_drop(now + ty, hit_pos); - queue->addcallback(now + ty, "COLL PANEL", - [&state](curve::EventQueue *q, const curve::curve_time_t &t) { - ball_reflect_panel(state, q, t); - }); - -// predict_reflect_wall(state, queue, now); -} - -}} // openage::curvepong diff --git a/libopenage/curve/demo_events/physics.h b/libopenage/curve/demo_events/physics.h deleted file mode 100644 index cd49415711..0000000000 --- a/libopenage/curve/demo_events/physics.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gamestate.h" -#include "../curve.h" -#include "../events.h" - -namespace openage { -namespace curvepong { - -class Physics { -public: - - void processInput(PongState &, PongPlayer &, std::vector &input, curve::EventQueue *, const curve::curve_time_t &now); -protected: - - static void reset(PongState &, curve::EventQueue *, const curve::curve_time_t &); - - - static void ball_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void ball_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void predict_reflect_wall(PongState &, curve::EventQueue *, const curve::curve_time_t &); - static void predict_reflect_panel(PongState &, curve::EventQueue *, const curve::curve_time_t &); -}; - -}} // openage::curvepong diff --git a/libopenage/curve/events.cpp b/libopenage/curve/events.cpp deleted file mode 100644 index 0f2a16236c..0000000000 --- a/libopenage/curve/events.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "events.h" -#include "trigger.h" - -#include - -namespace openage { -namespace curve { - -// FIXME convert all these std::functions to a custom datatype to remove multiple level of stack indirection - -EventQueue::Handle EventQueue::addcallback ( - const Eventclass &eventclass, - const curve_time_t &initial_now, - const time_predictor &at, - const callback &event, - const std::vector dependents) -{ - auto it = queue.begin(); - for (; it != queue.end() && it->eventclass != eventclass; ++it) {} - - Event e; - if (it != queue.end()) { - e = *it; - e.time = at(initial_now); - e.event = event; - queue.erase(it); - } else { - e = Event(at, initial_now, eventclass, event, ++last_event_id, dependents); - - // FIXME Register all on change events - } - - return this->addcallback(e); -} - - -EventQueue::Handle EventQueue::schedule ( - const Eventclass &eventclass, - const curve_time_t &initial_now, - const time_predictor &at, - const callback &event, - const std::vector dependents) -{ - auto it = queue.begin(); - for (; it != queue.end() && it->eventclass != eventclass; ++it) {} - - Event e; - if (it != queue.end()) { - e = *it; - e.time = at(initial_now); - e.event = event; - queue.erase(it); - } else { - e = Event(at, initial_now, eventclass, event, ++last_event_id, dependents, true); - // FIXME Register all on change events - } - - auto handle = this->addcallback(e); - - for (const auto &t : dependents) { - t->on_change_future( - std::string("dependency_") + eventclass, - [handle](EventQueue *q, const curve_time_t &t) { - q->reschedule(handle, t); - }); - } - return handle; - - -} - - -EventQueue::Handle EventQueue::addcallback ( - const Eventclass &eventclass, - const curve_time_t &initial_now, - const time_predictor &at, - const callback_void &event, - const std::vector dependents) -{ - return addcallback( - eventclass, - initial_now, - at, - [event](EventQueue *q, const curve_time_t &) { - event(q); - }, dependents); -} - - -EventQueue::Handle EventQueue::addcallback (const Event &e) { - auto it = queue.begin(); - for (; it != queue.end() && it->time < e.time; ++it) {} - queue.insert(it, e); - - return Handle(e.event_id); -} - - -void EventQueue::reschedule(const EventQueue::Handle &handle, - const EventQueue::time_predictor &new_timer, - const curve_time_t &at) { - auto it = resolve_handle(handle); - if (it != queue.end()) { - Event evnt = *it; - queue.erase(it); - evnt.predictor = new_timer; - evnt.time = new_timer(at); - addcallback(evnt); - } else { - // the event was either not valid or has already been executed. - } -} - - -void EventQueue::reschedule(const EventQueue::Handle &handle, const curve_time_t &at) { - auto it = resolve_handle(handle); - if (it != queue.end()) { - Event evnt = *it; - queue.erase(it); - evnt.time = evnt.predictor(at); - addcallback(evnt); - } else { - // the event was either not valid or has already been executed. - } -} - - -void EventQueue::reschedule(const EventQueue::time_predictor &new_timer, const curve_time_t &at) { - if (active_event != nullptr) { - auto evnt = *active_event; - evnt.predictor = new_timer; - evnt.time = evnt.predictor(at); - addcallback(evnt); - } -} - - -void EventQueue::reschedule(const curve_time_t &at) { - if (active_event != nullptr) { - auto evnt = *active_event; - evnt.time = evnt.predictor(at); - addcallback(evnt); - } -} - - -void EventQueue::execute_until(const curve_time_t &time) { - auto it = queue.begin(); - while ((it = queue.begin()) != queue.end() && it->time < time) { - auto tmp = *it; - queue.erase(it); - - this->active_event = &tmp; - it->event(this, tmp.time); - active_event = nullptr; - - if (tmp.repeat) { - // if the event is to be scheduled again after execution - // just insert it again - tmp.time = tmp.predictor(tmp.time); - addcallback(tmp); - } else { - past.push_back(tmp); - } - - if (this->cleared) { - this->cleared = false; - break; - } - } -} - - -void EventQueue::remove(const EventQueue::Handle &handle) { - for (auto it = queue.begin(); it != queue.end(); ++it) { - if (it->event_id == handle.event_id) { - it = queue.erase(it); - break; - } - } -} - - -std::deque::iterator EventQueue::resolve_handle( - const EventQueue::Handle &handle) { - for (auto it = queue.begin(); it != queue.end(); ++it) { - if (it->event_id == handle.event_id) { - return it; - } - } - return queue.end(); -} - - -void EventQueue::print() { -#ifndef GUI - std::cout << "Queue: " << std::endl; - for (const auto &i : queue) { - std::cout << i.time << ": " << i.event_id << i.eventclass <cleared = true; - this->queue.clear(); -} - - -void EventQueue::clear(const curve_time_t &time) { -#ifndef GUI - std::cout << "CLEAR " << time << std::endl; -#endif - auto it = queue.begin(); - for (; it != queue.end() && it->time < time; ++it) {} - for (; it != queue.end(); it = queue.erase(it) ) {} -} - - -}} // namespace openage::curve diff --git a/libopenage/curve/events.h b/libopenage/curve/events.h deleted file mode 100644 index 23934a8a25..0000000000 --- a/libopenage/curve/events.h +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -// pxd: from libcpp.string cimport string -#include "curve.h" -#include "queue.h" - -#include -#include - -namespace openage { -namespace curve { - -class Trigger; - -/** - * Event container that can execute and manage the stuff. - * - * pxd: - * cppclass EventQueue: - * ctypedef string Eventclass - * - * cppclass EventQueue__Handle "openage::curve::EventQueue::Handle": - * pass - * - */ -class EventQueue { -public: - /** Callback with eventqueue and time as arguments */ - typedef std::function callback; - - /** Callback with only the eventqueue as argument */ - typedef std::function callback_void; - - typedef std::function time_predictor; - - /** Class of events - this identifies a type of event */ - typedef std::string Eventclass; - - /** - * One single event that will be executed. This can be rescheduled, but the - * event id will never change. - */ - class Event { - friend class EventQueue; - private: - /** An event can only be constructed in the event queue */ - Event(const time_predictor &predictor, - const curve_time_t &initial_now, - const Eventclass &eventclass, - const callback &event, - const int event_id, - const std::vector &dependents, - bool repeat = false) : - event_id{event_id}, - dependents{dependents}, - predictor{predictor}, - time{predictor(initial_now)}, - eventclass(eventclass), - event{event}, - repeat{repeat} {} - - /** The Event id is only relevant within the eventqueue */ - int event_id; - - std::vector dependents; - - time_predictor predictor; - public: - Event() = default; - - /** Copy c'tor */ - //Event(const Event &rhs) = default; - - /** when will this be executed */ - curve_time_t time; - /** class of the event, used for identification */ - Eventclass eventclass; - /** The event itself */ - callback event; - - bool repeat; - - }; - - - /** - * Handle to be able to communicate with the event that has been stored. - * uses Event::event_id for identification. - * - */ - class Handle { - friend class EventQueue; - public: - Handle() : - Handle(0) {}; - private: - /** Can only be constructed from the EventQueue scope */ - explicit Handle(const int event_id) : - event_id(event_id) {} - - /** Identificator */ - int event_id; - }; - - /** Default c'ctor */ - EventQueue(const curve_time_t &backlog_time = 1000) : - cleared{false}, - backlog_time(backlog_time) {} - - /** - * Add a callback - with an event class that takes queue and time as - * arguments - */ - Handle addcallback ( - const Eventclass &eventclass, - const curve_time_t &initial_now, - const time_predictor &at, - const callback &event, - const std::vector dependents); - - /** - * Add a callback - with an event class that takes only queue as arguments - */ - Handle addcallback( - const Eventclass &eventclass, - const curve_time_t &initial_now, - const time_predictor &at, - const callback_void &event, - const std::vector dependents); - - Handle schedule( - const Eventclass &eventclass, - const curve_time_t &initial_now, - const time_predictor &at, - const callback &event, - const std::vector dependents); - - /** - * Take an event and reschedule the time, if it has not yet been executed - */ - void reschedule(const Handle &, const time_predictor &timer, const curve_time_t &at); - - /** - * Take an event and reschedule the time, if it has not yet been executed - */ - void reschedule(const Handle &, const curve_time_t &at); - - /** - * Reschedule the currently running event to the time given - */ - void reschedule(const time_predictor &timer, const curve_time_t &at); - - /** - * Reschedule the Event and reevaluate the timer - */ - void reschedule(const curve_time_t &at); - - /** - * Iteratively take the events and execute them one by one. The Queue may - * be changed during execution. - */ - void execute_until(const curve_time_t &t); - - /** - * Remove an event from execution, if it has not been executed yet. - */ - void remove(const Handle &); - - /** - * Remove all events from the queue - */ - void clear(); - - /** - * Clear the queue from this time on. - */ - void clear(const curve_time_t &); - - /** - * Count the number of events that might be executed. This is only a internal - * identification number. - */ - size_t size() { return queue.size(); } - - /** - * Number printer - */ - void print(); -private: - Handle addcallback(const Event &event); - - std::deque::iterator resolve_handle(const Handle &handle); - std::deque queue; - std::deque past; - Event *active_event; - - bool cleared; - int last_event_id = 0; - const curve_time_t backlog_time; -}; - -}} // namespace openage::curve diff --git a/libopenage/curve/events/CMakeLists.txt b/libopenage/curve/events/CMakeLists.txt new file mode 100644 index 0000000000..d65a5557f5 --- /dev/null +++ b/libopenage/curve/events/CMakeLists.txt @@ -0,0 +1,8 @@ + +add_sources(libopenage + eventclass.cpp + event.cpp + eventmanager.cpp + eventqueue.cpp + eventtarget.cpp +) diff --git a/libopenage/curve/events/event.cpp b/libopenage/curve/events/event.cpp new file mode 100644 index 0000000000..d9d52d84f7 --- /dev/null +++ b/libopenage/curve/events/event.cpp @@ -0,0 +1,23 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "event.h" + +#include "eventtarget.h" +#include "eventclass.h" + +#include "../../util/hash.h" + +namespace openage { +namespace curve { + +Event::Event(const std::shared_ptr &trgt, + const std::shared_ptr &eventclass, + const EventClass::param_map ¶ms) : + params(params), + _target{trgt}, + _eventclass{eventclass}, + myhash{util::hash_combine(std::hash()(trgt->id()), + std::hash()(eventclass->id())) } +{} + +}} // namespace openage::curve diff --git a/libopenage/curve/events/event.h b/libopenage/curve/events/event.h new file mode 100644 index 0000000000..a68b27f1eb --- /dev/null +++ b/libopenage/curve/events/event.h @@ -0,0 +1,54 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "eventclass.h" + +#include "../curve.h" + +#include + +namespace openage { +namespace curve { + +class EventQueue; +class EventTarget; + +/** + * The actual one event that may be called - it is used to manage the event itself. + * It does not need to be stored + */ +class Event { + friend EventQueue; + friend EventManager; +public: + + Event(const std::shared_ptr &trgt, + const std::shared_ptr &eventclass, + const EventClass::param_map ¶ms); + + std::weak_ptr &target() { return _target; } + std::shared_ptr &eventclass() {return _eventclass; } + + /** + * Reschedule will call the recalculate_time method to initiate a reschedule for the event + * it uses the reference_time as base for its calculation + */ + void reschedule(const curve_time_t reference_time); + + size_t hash() const { return myhash; } + curve_time_t time() const { return _time; } + void time(const curve_time_t &t) { _time = t; } + + curve_time_t last_triggered = 0; +private: + EventClass::param_map params; + + std::weak_ptr _target; + std::shared_ptr _eventclass; + size_t myhash; + curve_time_t _time; +}; + + +}} // namespace openage::curve diff --git a/libopenage/curve/events/eventclass.cpp b/libopenage/curve/events/eventclass.cpp new file mode 100644 index 0000000000..d9c57faf23 --- /dev/null +++ b/libopenage/curve/events/eventclass.cpp @@ -0,0 +1,34 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "eventclass.h" + +#include "event.h" +#include "eventtarget.h" + +#include "../../log/log.h" + +namespace openage { +namespace curve { + +void EventClass::add_dependency (const std::shared_ptr &dependency, + const std::shared_ptr &element) { + // ON_EXECUTE and ON_KEYFRAME do not listen on changes, so they do not have + // any dependents. + if (type != Type::ON_EXECUTE) { + log::log(DBG << "Adding change listener for: " << dependency->eventclass()->id() + << " to " << element->id()); + element->add_dependent(dependency); + } +} + + +EventClass::EventClass(const std::string &name, EventClass::Type type) : + type(type), + _id{name} {} + + +const std::string &EventClass::id() { + return _id; +} + +}} // namespace openage::curve diff --git a/libopenage/curve/events/eventclass.h b/libopenage/curve/events/eventclass.h new file mode 100644 index 0000000000..8272074a71 --- /dev/null +++ b/libopenage/curve/events/eventclass.h @@ -0,0 +1,167 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "../curve.h" + +#include +#include +#include +#include + +namespace openage { +class State; +namespace curve { + +class Event; +class EventManager; +class EventTarget; + +/** + * A eventclass has to be implemented for every type of event that exists. + * + * There shall be a genric on_X class, with a trigger_X interface for generic + * events; + */ +class EventClass { +public: + enum class Type { + /// Will be triggered at the time of the event. + /// "at" is the time, when the new value comes into action. + /// We want to be called at this time. + ON_CHANGE, + + /// Will be triggered immediately, when something changes. + /// "at" is the time when something was changed. + /// Behaves exactly like ON_CHANGE, if the ON_CHANGE is in the current + /// execution frame. + ON_CHANGE_IMMEDIATELY, + + /// Will be triggered on keyframe transition, when a keyframe is not + /// relevant for the "now" execution anymore. "at" is the time of the + /// keyframe + ON_KEYFRAME, + + /// Will be triggered unconditionally at the set time, "at" is the + /// time that was set as return of recalculate_time. This event will + /// be issued again until recalculate_time returns +max(). To execute + /// Something only once (i.E. triggered somewhere from the logic and + /// not based on time, use ONCE + + ON_EXECUTE, + + /// Will be triggered only once, but until it is triggered the time, + /// when this should happen can be recalculated again and again using + /// the recalculate_time method. + ONCE + }; + + class param_map { + public: + using any_t = std::experimental::fundamentals_v1::any; + using map_t = std::map; + + param_map(std::initializer_list l) : map(l) {} + param_map(const map_t& map) : map{std::move(map)} {} + + // Returns the value, if it exists and is the right type. + // dflt if not. + template + _T get(const std::string &key, const _T& dflt = _T()) const { + auto it = this->map.find(key); + if (it != this->map.end() && this->check_type<_T>(it)) { + //return std::any_cast<_T>(it->second); + return std::experimental::fundamentals_v1::any_cast<_T>(it->second); + + } else { + return dflt; + } + } + + bool contains(const std::string &key) const { + return map.find(key) != map.end(); + } + + // Check if the type is correct + template + bool check_type(const std::string &key) const { + auto it = map.find(key); + if (it != map.end()) { + return check_type<_T>(it); + } + return false; + } + + private: + template + bool check_type(const map_t::const_iterator &it) const { + return it->second.type() == typeid(_T); + } + + private: + const map_t map; + + }; + + /** + * Constructor to be constructed with the unique identifier + */ + EventClass(const std::string &name, Type); + + /** + * The Type the event class was constructed as. + */ + const Type type; + + /** + * Return a unique Identifier + */ + const std::string &id(); + + /** + * To be used in the setup functionality + */ + void add_dependency (const std::shared_ptr &event, + const std::shared_ptr &dependency); + + /** + * The job of the setup function is to add all dependencies with other event + * targets found in state. + */ + virtual void setup(const std::shared_ptr &event, + const std::shared_ptr &state) = 0; + + /** + * will be called at the time, that was recalculated. + * Here all the stuff happens. + */ + virtual void call(EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &t, + const param_map ¶ms) = 0; + + /** + * will be called to recalculate, when the event shall happen. + * The Calculation is triggered whenever one of the set up dependencies was + * changed. + * + * \param target the target this was defined on + * \param state the state this shall work on + * \param at the time when the change happened, from there on it shall be + * calculated onwards + * + * If the event is not relevant anymore at shall be returned as negative ::max(); + * If the time is lower than the previous time, then it may happen, that the + * dependencies are not perfectly resolved anymore (if other events have + * already been calculated before that + */ + virtual curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &at)= 0; + +private: + std::string _id; +}; + +}} // namespace openage::curve diff --git a/libopenage/curve/events/eventmanager.cpp b/libopenage/curve/events/eventmanager.cpp new file mode 100644 index 0000000000..ac422bb61f --- /dev/null +++ b/libopenage/curve/events/eventmanager.cpp @@ -0,0 +1,148 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "eventmanager.h" + +#include "event.h" +#include "eventclass.h" +#include "eventqueue.h" +#include "eventtarget.h" + +#include "../../error/error.h" +#include "../../log/log.h" + +namespace openage { +namespace curve { + +void EventManager::changed(const std::shared_ptr &event, const curve_time_t &changed_at) { + log::log(DBG << "Change: " << event->eventclass()->id() << " at " << changed_at); + queue.add_change(event, changed_at); +} + + +void EventManager::add_class(const std::shared_ptr &cls) { + classstore.insert(std::make_pair(cls->id(), cls)); +} + + +std::weak_ptr EventManager::on(const std::string &name, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &reference_time, + const EventClass::param_map ¶ms) { + auto it = classstore.find(name); + if (it == classstore.end()) { + // TODO FAIL + throw Error(MSG(err) << "Trying to subscribe to eventclass " << name << ", which does not exist."); + } + return queue.add(target, it->second, state, reference_time, params); +} + + +std::weak_ptr EventManager::on(const std::shared_ptr &eventclass, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &reference_time, + const EventClass::param_map ¶ms) { + auto it = classstore.find(eventclass->id()); + if (it == classstore.end()) { + auto res = classstore.insert(std::make_pair(eventclass->id(), eventclass)); + if (res.second) { + it = res.first; + } else { + return std::weak_ptr(); + } + } + + return queue.add(target, it->second, state, reference_time, params); +} + + +void EventManager::execute_until(const curve_time_t &time, + std::shared_ptr<::openage::State> &state) { + int cnt = 0; + do { + update_changes(state); + cnt = execute_events(time, state); + log::log(DBG << "Executed " << cnt << " events"); + } while (cnt != 0); + // Swap in the end of the execution, else we might skip changes that happen + // in the main loop for one frame - which is bad btw. + std::swap(queue.changes, queue.future_changes); + log::log(DBG << "Cycle done"); +} + + +int EventManager::execute_events(const curve_time_t &time_until, + const std::shared_ptr &state) { + log::log(DBG << "Pending Events: "); + for (const auto &e : queue.queue) { + log::log(DBG << "\tEVENT: T:" << e->time() << ": " << e->eventclass()->id()); + } + auto it = queue.queue.begin(); + int cnt = 0; + while ((it = queue.queue.begin()) != queue.queue.end() && (*it)->time() < time_until) { + auto tmp = *it; + queue.queue.pop_front(); + auto target = tmp->target().lock(); + if (target) { + this->active_event = tmp; + + log::log(DBG << "Calling Event \"" << tmp->eventclass()->id() + << "\" on Element \"" << target->id() + << "\" at time " << tmp->time()); + + tmp->eventclass()->call(this, target, state, tmp->time(), tmp->params); + active_event = nullptr; + cnt ++; + + if (tmp->eventclass()->type == EventClass::Type::ON_EXECUTE) { + auto new_time = tmp->eventclass()->recalculate_time(target, state, tmp->time()); + if (new_time != -std::numeric_limits::max()) { + tmp->time(new_time); + queue.readd(tmp); + } + } + } else { + // The element was already removed from the queue, so we can safely + // kill it by ignoring it. + } + } + return cnt; +} + + +void EventManager::update_changes(const std::shared_ptr &state) { + // The second magic happens here + log::log(DBG << "Updating " << queue.changes->size() << " changes"); + for (const auto &change : *queue.changes) { + auto evnt = change.evnt.lock(); + if (evnt) { + switch(evnt->eventclass()->type) { + case EventClass::Type::ONCE: + case EventClass::Type::ON_CHANGE: { + auto target = evnt->target().lock(); + // TODO what happens when the target is degraded? + if (target) { + curve_time_t new_time = evnt->eventclass() + ->recalculate_time(target, state, change.time); + log::log(DBG << "Recalculating Event " << evnt->eventclass()->id() << " on Element " << target->id() << " at time " << change.time << ", new time: " << new_time); + if (new_time != -std::numeric_limits::max()) { + evnt->time(new_time); + queue.update(evnt); + } + } + } break; + case EventClass::Type::ON_KEYFRAME: + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + evnt->time(change.time); + queue.update(evnt); + break; + case EventClass::Type::ON_EXECUTE: + break; + } + } + } + queue.changes->clear(); +} + +}} // namespace openage::curve diff --git a/libopenage/curve/events/eventmanager.h b/libopenage/curve/events/eventmanager.h new file mode 100644 index 0000000000..e1f7710934 --- /dev/null +++ b/libopenage/curve/events/eventmanager.h @@ -0,0 +1,115 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "../curve.h" + +#include "eventqueue.h" + +#include +#include +#include +#include + +// The demo wants to display details +namespace openage { +class State; +namespace curvepong { +int demo(); +} +} + + +namespace openage { +class State; +namespace curve { + +class EventTarget; +class Event; + +class EventFilter { +public: + EventFilter(std::function &)> &filter) : + _filter(filter) {} + + bool apply(const std::shared_ptr target) { + return _filter(target); + } +private: + std::function&)> _filter; +}; + +/** + * The core class to manage event class and targets. + */ +class EventManager { + friend int openage::curvepong::demo(); +public: + void add_class(const std::shared_ptr &cls); + + std::weak_ptr on(const std::string &name, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &reference_time, + const EventClass::param_map ¶ms = EventClass::param_map({})); + /** + * This will generate a new randonmly named eventclass for this specific element + */ + std::weak_ptr on(const std::shared_ptr &eventclass, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &reference_time, + const EventClass::param_map ¶ms = EventClass::param_map({})); + + void onfilter(const std::shared_ptr &eventclass, const EventFilter &); + + template + void onfilter(const EventFilter &filter) { + onfilter(std::make_shared(), filter); + } + + void refilter(const std::shared_ptr &); + void refilter(const std::shared_ptr &); + + void register_object(const std::shared_ptr &); + + /** + * Submit a change in a dependent value to an event. Insert it into the + * changes queue and evaluate it accordingly + */ + void changed(const std::shared_ptr &event, + const curve_time_t &changed_at); + + /** + * Execute all events that are registered until a certain point in time. + */ + void execute_until(const curve_time_t &time, std::shared_ptr<::openage::State> &state); + +private: + /** + * Execute the events + * + * \return number of events processed + */ + int execute_events(const curve_time_t &time, + const std::shared_ptr &state); + + /** + * Call all the time change functions. This is constant on the state! + */ + void update_changes(const std::shared_ptr &state); + + /// Here we do the bookkeeping of registered classes. + std::map> classstore; + + /** + * Here we store all running filters that shall be applied whenever a new + * obejct is added to our objectstore + */ + std::list filters; + + EventQueue queue; + std::shared_ptr active_event; +}; + +}} // namespace openage::curve diff --git a/libopenage/curve/events/eventqueue.cpp b/libopenage/curve/events/eventqueue.cpp new file mode 100644 index 0000000000..ac9b7ea952 --- /dev/null +++ b/libopenage/curve/events/eventqueue.cpp @@ -0,0 +1,231 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "eventqueue.h" + +#include "event.h" +#include "eventclass.h" +#include "eventtarget.h" + +#include "../../error/error.h" +#include "../../log/log.h" + +namespace openage { +namespace curve { + +std::weak_ptr EventQueue::add(const std::shared_ptr &trgt, + const std::shared_ptr &cls, + const std::shared_ptr &state, + const curve_time_t &reference_time, + const EventClass::param_map ¶ms) { + auto sp = std::make_shared(trgt, cls, params); + + cls->setup(sp, state); + switch(cls->type) { + case EventClass::Type::ON_CHANGE: + case EventClass::Type::ON_EXECUTE: + case EventClass::Type::ONCE: + sp->time(sp->eventclass()->recalculate_time(trgt, state, reference_time)); + if (sp->time() == -std::numeric_limits::max()) { + return std::weak_ptr(); + } + break; + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + case EventClass::Type::ON_KEYFRAME: + sp->_time = reference_time; + break; + } + select_queue(sp->eventclass()->type).emplace_back(sp); + + this->check_in(sp); + + return sp; +} + + +EventQueue::EventQueue() : + changes(&changeset_A), future_changes(&changeset_B) {} + + +void EventQueue::check_in(const std::shared_ptr &evnt) { + switch(evnt->eventclass()->type) { + case EventClass::Type::ON_CHANGE: + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + // TODO Set up these fellows + break; + case EventClass::Type::ON_KEYFRAME: + // TODO set up this fellow + break; + case EventClass::Type::ON_EXECUTE: + // Add this to the event queue, although it is already in the other queue + queue.emplace_back(evnt); + break; + case EventClass::Type::ONCE: + // Has already been added to the queue, so nothing to do here + break; + } +} + + +void EventQueue::add_change(const std::shared_ptr &event, + const curve_time_t &changed_at) { + + auto it = changes->find(OnChangeElement(event, changed_at)); + + // Has the event been triggered in this round? + if (event->last_triggered < changed_at) { + // Is the change already in the queue? + if (it != changes->end()) { + // Is the new change dated _before_ the old one? + if (it->time > changed_at) { + // Save the element + OnChangeElement e = *it; + e.time = changed_at; + // delete it from the container and readd it + it = changes->erase(it); + it = changes->insert(it, e); + log::log(DBG << "adjusting time in change queue"); + } else { + // this change is to be ignored + log::log(DBG << "skipping change " << event->eventclass()->id() + << " at " << changed_at + << " because there was already a better one at " << it->time); + } + } else { + // the change was not in the to be changed list + changes->emplace(event, changed_at); + log::log(DBG << "inserting change " << event->eventclass()->id() << " at " << changed_at); + } + } else { + // the event has been triggered in this round already, so skip it this time + future_changes->emplace(event, changed_at); + log::log(DBG << "putting change into the future: " << event->eventclass()->id() << " at " << changed_at); + } + event->last_triggered = changed_at; +} + + +void EventQueue::remove(const std::shared_ptr &evnt) { + auto &queue = select_queue(evnt->eventclass()->type); + auto it = std::find(std::begin(queue), std::end(queue), evnt); + + if (it != queue.end()) { + queue.erase(it); + } +} + +std::deque> &EventQueue::select_queue(EventClass::Type type) { + switch(type) { + case EventClass::Type::ON_CHANGE: + return on_change; + break; + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + return on_change_immediately; + break; + case EventClass::Type::ON_KEYFRAME: + return on_keyframe; + break; + case EventClass::Type::ON_EXECUTE: + return on_execute; + break; + default: + case EventClass::Type::ONCE: + return queue; + break; + } +} + + +void EventQueue::update(const std::shared_ptr &evnt) { + decltype(queue)::iterator it = std::find(std::begin(queue), std::end(queue), evnt); + if (it != queue.end()) { // we only want to update the pending queue + int dir = 0; + { + auto nxt = std::next(it); + if (nxt != std::end(queue) && (*nxt)->time() < (*it)->time()) { + dir --; + } + auto prv = std::prev(it); + if (it != std::begin(queue) && (*prv)->time() > (*it)->time()) { + dir ++; + } + // dir is now one of these values: + // 0: the element is perfectly placed + // +: the elements time is too low for its position, move forward + // -: the elements time is too high for its position, move backwards + } + if (dir == 0) { + // do nothing + } else if (dir > 0) { + auto e = *it; + it = queue.erase(it); + while (it != queue.begin() + && evnt->time() < (*std::prev(it))->time()) { + it--; + } + queue.insert(it, e); + } else if (dir < 0) { + auto e = *it; + it = queue.erase(it); + while (it != queue.end() + && evnt->time() > (*std::prev(it))->time()) { + it++; + } + queue.insert(it, e); + } + log::log(DBG << "Readded Element: " << evnt->eventclass()->id() << " at " << evnt->time()); + } else { + it = std::find_if( + std::begin(queue), + std::end(queue), + [&evnt] (const std::shared_ptr &e) { + return e->time() > evnt->time(); + }); + queue.insert(it, evnt); + log::log(DBG << "Inserted Element: " << evnt->eventclass()->id() << " at " << evnt->time()); + } +} + + +void EventQueue::readd(const std::shared_ptr &evnt) { + auto &container = select_queue(evnt->eventclass()->type); + + auto it = std::find_if( + std::begin(container), + std::end(container), + [&evnt](const std::shared_ptr &element) { + return element->time() < evnt->time(); + }); + container.insert(it, evnt); + + check_in(evnt); +} + + +EventQueue::OnChangeElement::OnChangeElement(const std::shared_ptr &evnt, + const curve_time_t &time) : + time{time}, + evnt{evnt}, + hash{evnt->hash()} {} + + +size_t EventQueue::OnChangeElement::Equal::operator()(const OnChangeElement& left, + const OnChangeElement& right) const { + auto left_evnt = left.evnt.lock(); + auto right_evnt = right.evnt.lock(); + if (left_evnt && right_evnt) { + if (left_evnt->eventclass()->id() == right_evnt->eventclass()->id()) { + return true; + } + } else { + return false; + } + + auto left_trgt = left_evnt->target().lock(); + auto right_trgt = right_evnt->target().lock(); + + return left_trgt && right_trgt && + left_trgt->id() == right_trgt->id(); +} + + +}} // namespace openage::curve diff --git a/libopenage/curve/events/eventqueue.h b/libopenage/curve/events/eventqueue.h new file mode 100644 index 0000000000..b3eb9ee240 --- /dev/null +++ b/libopenage/curve/events/eventqueue.h @@ -0,0 +1,125 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +// for eventclass::types +#include "eventclass.h" + +#include "../curve.h" + +#include "../../util/hash.h" + +#include +#include +#include + +namespace openage { +class State; +namespace curve { + +class Event; +class EventManager; +class EventTarget; + +/** + * The core event class for execution and execution dependencies. + */ +class EventQueue { + friend class EventManager; +public: + EventQueue(); + + /** + * Add an event for a specified target + * + * A target is every single unit in the game word - so best add these events + * in the constructor of the game objects. + */ + std::weak_ptr add(const std::shared_ptr &eventtarget, + const std::shared_ptr &eventclass, + const std::shared_ptr &state, + const curve_time_t &reference_time, + const EventClass::param_map ¶ms); + + void remove(const std::shared_ptr &evnt); + + /** + * The event may be already part of the execution queue, + * so update it, if it shall be executed in the future. + */ + void update(const std::shared_ptr &); + + /** + * The event was just removed. + */ + void readd(const std::shared_ptr &); + + /** + * An event target has changed, and the event shall be retriggered + */ + void add_change(const std::shared_ptr &event, const curve_time_t &changed_at); + + /** + * Get an event identified by EventTarget and EventClass, or a shared_ptr if not found + */ + const std::shared_ptr &get_evnt(const std::shared_ptr &, + const std::shared_ptr &); + + /** + * get an accessor to the running queue for state ouput purpose + */ + const std::deque> &ro_queue() const { return queue; } + +private: + void check_in(const std::shared_ptr &evnt); + + class OnChangeElement { + public: + OnChangeElement(const std::shared_ptr &evnt, + const curve_time_t &time); + + curve_time_t time; + std::weak_ptr evnt; + const size_t hash; + + class Hasher : public std::unary_function { + public: + size_t operator()(const OnChangeElement& e) const { + return e.hash; + } + }; + + class Equal : public std::unary_function { + public: + size_t operator()(const OnChangeElement& left, + const OnChangeElement& right) const; + }; + }; + + using change_set = std::unordered_set; + // Implement double buffering around changesets, that we do not run into deadlocks + change_set *changes; + change_set *future_changes; + + change_set changeset_A; + change_set changeset_B; + + std::deque> &select_queue(EventClass::Type type); + + std::deque> on_change; // will trigger itself and add to the queue + std::deque> on_change_immediately; // will trigger itself and at to the queue + std::deque> on_keyframe; // will trigger itself + // TODO is this required? + std::deque> on_execute; // whenever one of these is executed, it shall be reinserted + // Type::ONCE is only inserted into the queue + + + std::deque> queue; + + + std::shared_ptr null_evnt; +}; + +}} // namespace openage::curve diff --git a/libopenage/curve/events/events.h b/libopenage/curve/events/events.h new file mode 100644 index 0000000000..bb4146c5f0 --- /dev/null +++ b/libopenage/curve/events/events.h @@ -0,0 +1,14 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "event.h" +#include "eventclass.h" +#include "eventmanager.h" +#include "eventqueue.h" +#include "eventtarget.h" + +namespace openage { +namespace curve { + +}} diff --git a/libopenage/curve/events/events2.cpp b/libopenage/curve/events/events2.cpp new file mode 100644 index 0000000000..5e7161f174 --- /dev/null +++ b/libopenage/curve/events/events2.cpp @@ -0,0 +1,17 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "events2.h" + +#include "../log/log.h" +#include "../error/error.h" + +#include + +namespace openage { +namespace curve { + + + + + +}} // namespace openage::curve diff --git a/libopenage/curve/events/events2.h b/libopenage/curve/events/events2.h new file mode 100644 index 0000000000..fedae6e178 --- /dev/null +++ b/libopenage/curve/events/events2.h @@ -0,0 +1,34 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "../curve.h" + +#include "../../util/hash.h" + +#include +#include +#include +#include +#include + +// Forward declarations +namespace openage { +class State; +namespace curvepong { +int demo(); +} +} + +namespace openage { +namespace curve { + +class Event; +class EventQueue; +class EventClass; +class EventManager; + + + + +}} // openage::curve diff --git a/libopenage/curve/events/eventtarget.cpp b/libopenage/curve/events/eventtarget.cpp new file mode 100644 index 0000000000..6e6608eb2d --- /dev/null +++ b/libopenage/curve/events/eventtarget.cpp @@ -0,0 +1,75 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "eventtarget.h" + +#include "event.h" +#include "eventclass.h" +#include "eventmanager.h" + +#include "../../error/error.h" +#include "../../log/log.h" + +namespace openage { +namespace curve { + +void EventTarget::on_change(const curve_time_t &time) { + log::log(DBG << "Change happened on " << this->id() << " at " << time); + if (parent_notifier != nullptr) { + parent_notifier(time); + } + // Iterator advancement is done inside the loop - it is an maybe-erase construct + for (auto it = dependents.begin(); it != dependents.end(); ) { + auto sp = it->lock(); + if (sp) { + switch (sp->eventclass()->type) { + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + case EventClass::Type::ON_CHANGE: + // Change events will be retriggered + manager->changed(sp, time); + ++it; + break; + case EventClass::Type::ONCE: + // Has it been triggered? If so - forget it. + if (sp->last_triggered > 0) { + it = dependents.erase(it); + } else { + manager->changed(sp, time); + ++it; + } + break; + case EventClass::Type::ON_KEYFRAME: + case EventClass::Type::ON_EXECUTE: + // Ignore changes for execute events + ++it; + break; + } + } else { + // The dependent is no more, so we can safely forget him + it = dependents.erase(it); + } + } +} + + +void EventTarget::on_pass_keyframe(const curve_time_t &last_valid_time) { + for (auto it = dependents.begin(); it != dependents.end(); ) { + auto sp = it->lock(); + if (sp) { + if (sp->eventclass()->type == EventClass::Type::ON_KEYFRAME) { + log::log(DBG << "Encountered keyframe " << sp->eventclass()->id() + << " at T:" << last_valid_time); + manager->changed(sp, last_valid_time); + } + ++it; + } else { + it = dependents.erase(it); + } + } +} + + +void EventTarget::add_dependent(const std::weak_ptr &event) { + this->dependents.emplace_back(event); +} + +}} // namespace openage::curve diff --git a/libopenage/curve/events/eventtarget.h b/libopenage/curve/events/eventtarget.h new file mode 100644 index 0000000000..15d0c42474 --- /dev/null +++ b/libopenage/curve/events/eventtarget.h @@ -0,0 +1,55 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "../curve.h" + +#include +#include + +namespace openage { +namespace curve { + +class Event; +class EventManager; +class EventClass; + +/** + * Every Object in the gameworld that wants to be targeted by events or as + * dependency for events, has to implement this class. + */ +class EventTarget { + friend EventClass; +public: + /** Give a unique identifier for the unit */ + virtual size_t id() const = 0; + + using single_change_notifier = std::function; +protected: + /** + * For children to be able to initialize us. + * + * The notifier is used by hierarchical structures to be able to traverse a + * change up in the tree, this is necessary to make containers with event + * targets inside and listen to any changes on the full. + */ + EventTarget(EventManager *manager, single_change_notifier parent_notifier = nullptr) : + manager{manager}, + parent_notifier{parent_notifier} {} + + /** Whenever some data in the Target changed */ + void on_change(const curve_time_t &); + + /** when a keyframe in the underlying container was passed. */ + void on_pass_keyframe(const curve_time_t &last_valid_time); + + /** add a dependent class, that should be notified when on_change is called */ + void add_dependent(const std::weak_ptr &event); + +private: + EventManager *manager; + std::list> dependents; + single_change_notifier parent_notifier; +}; + +}} // namespace openage::curve diff --git a/libopenage/curve/internal/keyframe_container.h b/libopenage/curve/internal/keyframe_container.h index ecd01aefb6..7fce03b396 100644 --- a/libopenage/curve/internal/keyframe_container.h +++ b/libopenage/curve/internal/keyframe_container.h @@ -50,7 +50,7 @@ class KeyframeContainer { time{time}, value{value} {} - const curve_time_t time = std::numeric_limits::infinity(); + const curve_time_t time = std::numeric_limits::max(); _T value = _T(); }; @@ -168,7 +168,7 @@ template KeyframeContainer<_T>::KeyframeContainer() { //Create a default element at -Inf, that can always be dereferenced - so there will by definition never be //a element that cannot be dereferenced - this->container.push_back(Keyframe(-std::numeric_limits::infinity(), _T())); + this->container.push_back(Keyframe(-std::numeric_limits::max(), _T())); } template diff --git a/libopenage/curve/internal/value_container.h b/libopenage/curve/internal/value_container.h index c05b09b7e4..83855150a9 100644 --- a/libopenage/curve/internal/value_container.h +++ b/libopenage/curve/internal/value_container.h @@ -2,8 +2,8 @@ #pragma once -// pxd: from libopenage.curve cimport Trigger -#include "../trigger.h" +#include "../events/eventtarget.h" + #include "keyframe_container.h" #include @@ -14,16 +14,19 @@ namespace curve { /** * pxd: * - * cppclass ValueContainer(Trigger): + * cppclass ValueContainer(EventTarget): * void set_drop(const curve_time_t &) except + * void set_insert(const curve_time_t &) except + * */ template -class ValueContainer : public Trigger { +class ValueContainer : public EventTarget { public: - ValueContainer(TriggerFactory *trigger) : - Trigger(trigger), + ValueContainer(EventManager *mgr, + size_t id, + const EventTarget::single_change_notifier ¬ifier = nullptr) : + EventTarget(mgr, notifier), + _id{id}, last_element{container.begin()} {} virtual _T get(const curve_time_t &t) const = 0; @@ -32,17 +35,19 @@ class ValueContainer : public Trigger { return get(now); } - virtual bool needs_update(const curve_time_t &at); - virtual std::pair frame(const curve_time_t &) const; virtual std::pair next_frame(const curve_time_t &) const; -public: + // Inserter mode virtual void set_drop(const curve_time_t &at, const _T &value); virtual void set_insert(const curve_time_t &at, const _T &value); + virtual size_t id() const override { + return _id; + } protected: KeyframeContainer<_T> container; + const size_t _id; mutable typename KeyframeContainer<_T>::KeyframeIterator last_element; }; @@ -52,7 +57,10 @@ void ValueContainer<_T>::set_drop(const curve_time_t &at, const _T &value) { auto hint = this->container.last(at, this->last_element); // We want to remove a possible equal timed element from the container - if (std::fabs(hint->time - at) < std::numeric_limits::min()) { + // to do fabs(x-y) < min is only necessary when curve_time_t is floating point! + //if (std::abs(hint->time - at) < std::numeric_limits::min()) { + + if (hint->time == at) { hint--; } @@ -61,14 +69,14 @@ void ValueContainer<_T>::set_drop(const curve_time_t &at, const _T &value) { container.insert(at, value, hint); this->last_element = hint; - this->data_changed(at, at); + this->on_change(at); } template void ValueContainer<_T>::set_insert(const curve_time_t &at, const _T &value) { this->container.insert(at, value, this->last_element); - this->data_changed(1, at); + this->on_change(at); } @@ -86,16 +94,4 @@ std::pair ValueContainer<_T>::next_frame(const curve_ti return std::make_pair(e->time, e->value); } - -template -bool ValueContainer<_T>::needs_update(const curve_time_t &at) { - auto e = this->container.last(at, this->container.end()); - if (e->time > at || ++e == this->container.end() || e->time > at) { - return true; - } else { - return false; - } -} - - }} // openage::curve diff --git a/libopenage/curve/iterator.h b/libopenage/curve/iterator.h index eb3f6306cf..cc54f941a2 100644 --- a/libopenage/curve/iterator.h +++ b/libopenage/curve/iterator.h @@ -32,8 +32,8 @@ class CurveIterator { explicit CurveIterator(const container_t *c): _base{}, container{c}, - from{-std::numeric_limits::infinity()}, - to{+std::numeric_limits::infinity()} {} + from{-std::numeric_limits::max()}, + to{+std::numeric_limits::max()} {} /** Default copy c'tor */ CurveIterator (const CurveIterator &) = default; diff --git a/libopenage/curve/map.h b/libopenage/curve/map.h index f9480c2175..e523d8f3ce 100644 --- a/libopenage/curve/map.h +++ b/libopenage/curve/map.h @@ -43,10 +43,10 @@ class UnorderedMap { at(const curve_time_t &, const key_t &) const; MapFilterIterator - begin(const curve_time_t &e = std::numeric_limits::infinity()) const; + begin(const curve_time_t &e = std::numeric_limits::max()) const; MapFilterIterator - end(const curve_time_t &e = std::numeric_limits::infinity()) const; + end(const curve_time_t &e = std::numeric_limits::max()) const; MapFilterIterator insert(const curve_time_t &birth, const key_t &, const val_t &); @@ -94,7 +94,7 @@ UnorderedMap::at(const curve_time_t & time, e, this, time, - std::numeric_limits::infinity())); + std::numeric_limits::max())); } else { return std::make_pair( false, @@ -109,7 +109,7 @@ UnorderedMap::begin(const curve_time_t &time) const { this->container.begin(), this, time, - std::numeric_limits::infinity()); + std::numeric_limits::max()); } template @@ -118,7 +118,7 @@ UnorderedMap::end(const curve_time_t &time) const { return MapFilterIterator>( this->container.end(), this, - -std::numeric_limits::infinity(), + -std::numeric_limits::max(), time); } @@ -144,7 +144,7 @@ UnorderedMap::insert(const curve_time_t &alive, const val_t &value) { return this->insert( alive, - std::numeric_limits::infinity(), + std::numeric_limits::max(), key, value); } diff --git a/libopenage/curve/object.h b/libopenage/curve/object.h deleted file mode 100644 index a57fedf64b..0000000000 --- a/libopenage/curve/object.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "internal/value_container.h" - -namespace openage { -namespace curve { - - -/** - * A Curve Object is a ordered collection of internal curves. Every sub-curve - * needs to be registered at this parent element. - */ -class Object : public TriggerIntermediateMaster { -public: - Object(TriggerFactory *factory) : - TriggerIntermediateMaster(factory) {}; - -private: - -}; - -}} // openage :: curve diff --git a/libopenage/curve/queue.h b/libopenage/curve/queue.h index 8e8071d76f..47cd10501a 100644 --- a/libopenage/curve/queue.h +++ b/libopenage/curve/queue.h @@ -40,14 +40,14 @@ class Queue { // Modifying access QueueFilterIterator<_T, Queue<_T>> begin( - const curve_time_t &t = -std::numeric_limits::infinity()) const; + const curve_time_t &t = -std::numeric_limits::max()) const; QueueFilterIterator<_T, Queue<_T>> end( - const curve_time_t &t = std::numeric_limits::infinity()) const; + const curve_time_t &t = std::numeric_limits::max()) const; QueueFilterIterator<_T, Queue<_T>> between( - const curve_time_t &begin = std::numeric_limits::infinity(), - const curve_time_t &end = std::numeric_limits::infinity()) const; + const curve_time_t &begin = std::numeric_limits::max(), + const curve_time_t &end = std::numeric_limits::max()) const; //QueueFilterIterator<_T, Queue<_T>> void erase(const CurveIterator<_T, Queue<_T>> &); @@ -84,7 +84,7 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::begin(const curve_time_t &t) const it, this, t, - std::numeric_limits::infinity()); + std::numeric_limits::max()); } } @@ -99,7 +99,7 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::end(const curve_time_t &t) const container.end(), this, t, - std::numeric_limits::infinity()); + std::numeric_limits::max()); } @@ -158,7 +158,7 @@ QueueFilterIterator<_T, Queue<_T>> Queue<_T>::insert( auto ct = QueueFilterIterator<_T, Queue<_T>>( insertion_point, this, - time, std::numeric_limits::infinity()); + time, std::numeric_limits::max()); if (!ct.valid()) { ++ct; diff --git a/libopenage/curve/test/CMakeLists.txt b/libopenage/curve/test/CMakeLists.txt index 7c1f6634c7..df83cfb5a1 100644 --- a/libopenage/curve/test/CMakeLists.txt +++ b/libopenage/curve/test/CMakeLists.txt @@ -3,7 +3,6 @@ link_libraries(tube) add_sources(libopenage test_container.cpp test_curve_types.cpp - test_events.cpp + test_events2.cpp test_serialization.cpp - test_trigger.cpp ) diff --git a/libopenage/curve/test/test_curve_types.cpp b/libopenage/curve/test/test_curve_types.cpp index 1ec1c3d680..1aea16bbd5 100644 --- a/libopenage/curve/test/test_curve_types.cpp +++ b/libopenage/curve/test/test_curve_types.cpp @@ -6,6 +6,9 @@ #include "../continuous.h" #include "../discrete.h" +#include "../events/eventmanager.h" + +#include "../../log/log.h" namespace openage { namespace curve { @@ -13,8 +16,7 @@ namespace tests { void curve_types() { // Check the base container type - EventQueue q; - TriggerFactory f{&q}; + EventManager f; { KeyframeContainer c; auto p0 = c.insert(0, 0); @@ -28,7 +30,7 @@ void curve_types() { TESTEQUALS(c.last(10)->value, 2); TESTEQUALS(c.last(47)->value, 2); - // last() with hints. Yes this can make a difference. we want to be + // last() with hints. Yes this can make a diference. we want to be // absolutely shure! // hint p1 TESTEQUALS(c.last(0, p0)->value, 0); @@ -65,7 +67,7 @@ void curve_types() { // Check the Simple Continuous type { - Continuous c(&f); + Continuous c(&f, 0); c.set_insert(0, 0); c.set_insert(10, 1); @@ -75,8 +77,10 @@ void curve_types() { } { - Continuous c(&f); + Continuous c(&f, 0); + log::log(DBG << "Testing Continuous float"); c.set_insert(0, 0); + log::log(DBG << "Inserting t:20, v:20"); c.set_insert(20, 20); TESTEQUALS(c.get(0), 0); @@ -84,6 +88,7 @@ void curve_types() { TESTEQUALS(c.get(7), 7); c.set_drop(20, 10); + log::log(DBG << "Inserting t:20, v:10. This should overwrite the old values!"); TESTEQUALS(c.get(0), 0); TESTEQUALS(c.get(2), 1); TESTEQUALS(c.get(8), 4); @@ -91,7 +96,7 @@ void curve_types() { //Check the discrete type { - Discrete c(&f); + Discrete c(&f, 0); c.set_insert(0, 0); c.set_insert(10, 10); @@ -99,7 +104,7 @@ void curve_types() { TESTEQUALS(c.get(1), 0); TESTEQUALS(c.get(10), 10); - Discrete complex(&f); + Discrete complex(&f, 0); complex.set_insert(0, "Test 0"); complex.set_insert(10, "Test 10"); @@ -112,7 +117,7 @@ void curve_types() { //check set_drop { - Discrete c(&f); + Discrete c(&f, 0); c.set_insert(0, 0); c.set_insert(1, 1); c.set_insert(3, 3); @@ -125,7 +130,7 @@ void curve_types() { // Encountered Errors { - Continuous c(&f); + Continuous c(&f, 0); c.set_insert(1, 1); c.set_drop(1, -5); diff --git a/libopenage/curve/test/test_events2.cpp b/libopenage/curve/test/test_events2.cpp new file mode 100644 index 0000000000..41c50ee105 --- /dev/null +++ b/libopenage/curve/test/test_events2.cpp @@ -0,0 +1,457 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#include "../events/events.h" + +#include "../../testing/testing.h" +#include "../../log/log.h" + +#include + +#include // for strcmp + +namespace openage { + +// We have to create a temporary State due to the magic of C++ +class State { +public: + class TestObject : public curve::EventTarget { + const int _id; + public: + TestObject(curve::EventManager *manager, int id) : EventTarget(manager), _id{id}, number(0) {} + void set_number(int number, const curve::curve_time_t &time) { + this->number = number; + this->on_change(time + 1); + } + int number; + + size_t id() const override { return _id; } + void trigger_keyframe(const curve::curve_time_t &time) { this->on_pass_keyframe(time); } + }; + + State(curve::EventManager *manager) : + objectA(std::make_shared(manager, 0)) , + objectB(std::make_shared(manager, 1)) + {} + + std::shared_ptr objectA; + std::shared_ptr objectB; + + struct traceelement { + traceelement(const std::string &event, curve::curve_time_t time) : + time{time}, name{event} {} + curve::curve_time_t time; + std::string name; + }; + std::list trace; + + void log_dbg() { + log::log(DBG << "Trace: "); + for (const auto &e : this->trace) { + log::log(DBG << "T: " << e.time << ": " << e.name); + } + } +}; + +namespace curve { +namespace tests { + +class TestEventClass : public EventClass { + int idx; +public: + TestEventClass(const std::string &name, int idx) : EventClass(name, EventClass::Type::ON_CHANGE), idx{idx} {} + + void setup(const std::shared_ptr &target, + const std::shared_ptr &state) override { + switch(idx) { + case 0: + add_dependency(target, state->objectB); + break; + case 1: + add_dependency(target, state->objectA); + break; + } + } + + void call(EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &time, + const EventClass::param_map &/*param*/) override { + (void)target; + switch (idx) { + case 0: { + auto t = std::dynamic_pointer_cast(target); + state->objectA->set_number(t->number + 1, time); + log::log(DBG << "I am Event A. Setting number to " << state->objectA->number); + state->trace.emplace_back("A", time); + } break; + case 1: { + auto t = std::dynamic_pointer_cast(target); + state->objectB->set_number(t->number + 1, time); + log::log(DBG << "I am Event B. Setting number to " << state->objectB->number); + state->trace.emplace_back("B", time); + } break; + } + } + + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &at) override { + // TODO recalculate a hit time + (void)target; + (void)state; + return at + 2; + } +}; + +class TestEventClassTwo : public EventClass { +public: + TestEventClassTwo(const std::string &name) : EventClass(name, EventClass::Type::ON_CHANGE) {} + + void setup(const std::shared_ptr &target, const std::shared_ptr &state) override { + add_dependency(target, state->objectA); + } + + void call(EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &time, + const EventClass::param_map &/*param*/) override { + auto t = std::dynamic_pointer_cast(target); + state->objectB->set_number(t->number + 1, time); + log::log(DBG << "I am EventClassTwo. Setting B.number to " << state->objectB->number); + state->trace.emplace_back("B", time); + } + + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &at) override { + // TODO recalculate a hit time + (void)target; + (void)state; + return at + 1; + } +}; + +class EventTypeTestClass : public EventClass { +public: + EventTypeTestClass(const std::string &name, EventClass::Type type) : EventClass(name, type) {} + + void setup(const std::shared_ptr &target, + const std::shared_ptr &state) override { + add_dependency(target, state->objectA); + } + + void call(EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &time, + const EventClass::param_map &/*param*/) override { + switch(this->type) { + case EventClass::Type::ON_CHANGE: + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + case EventClass::Type::ON_KEYFRAME: + case EventClass::Type::ON_EXECUTE: + case EventClass::Type::ONCE: + break; + } + auto t = std::dynamic_pointer_cast(target); + log::log(DBG << this->id() << " got called on " << t->id() + << " with number " << t->number << " at " << time); + state->trace.emplace_back(this->id(), time); + (void)time; + (void)state; + } + + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &at) override { + (void)target; + (void)state; + switch(this->type) { + case EventClass::Type::ON_CHANGE: + return at+1; // Execute 1 after the change (usually it is neccessary to recalculate a colission + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + TESTFAILMSG("ON_CHANGE_IMMEDIATELY does not recalculate time!"); + return 0; // This is ignored anyway + case EventClass::Type::ON_KEYFRAME: + TESTFAILMSG("ON_KEYFRAME does not recalculate time!"); + return 0; // This is ignored anyway + case EventClass::Type::ON_EXECUTE: + return at + 5; // This will force the execution every 5ms + case EventClass::Type::ONCE: + return 10; // even if data changed it will happen at the given time! + } + return at; + } +}; + +void events2() { + log::log(DBG << "------------- [ Starting Test: Basic Ping Pong ] ------------"); + // test destruction + std::weak_ptr destruction_test_state; + { + // Test with one event class + EventManager manager; + + manager.add_class(std::make_shared("testOnA", 0)); + manager.add_class(std::make_shared("testOnB", 1)); + + auto state = std::make_shared(&manager); + destruction_test_state = state; + // One must not start the game at 0 - this leads to randomness in execution + manager.on("testOnB", state->objectB, state, 1); + manager.on("testOnA", state->objectA, state, 1); + + // It is expected, that A and B hand over the "changed" events between each other + state->objectA->set_number(0, 0); + for (int i = 1; i < 10; ++i) { + manager.execute_until(i * 2, state); + } + + state->log_dbg(); + + int i = 0; + curve_time_t last_time = 0; + for (auto it = state->trace.begin(); it != state->trace.end(); ++it, ++i) { + const auto &e = *it; + if (last_time > e.time) { + TESTFAILMSG("You broke the time continuum: one shall not execute randomly!"); + } + last_time = e.time; + switch(i) { + case 0: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 3); break; + case 1: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 6); break; + case 2: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 9); break; + case 3: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 12); break; + case 4: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 15); break; + default: TESTFAILMSG("Too many elements in stack trace"); break; + } + } + } + if (!destruction_test_state.expired()) { + TESTFAILMSG("Test Failed because State was not automatically destructed"); + } + + log::log(DBG << "------------- [ Starting Test: Two Event Ping Pong ] ------------"); + { + // Test with two event classes to check interplay + // Test with one event class + EventManager manager; + + manager.add_class(std::make_shared("testOnA", 0)); + manager.add_class(std::make_shared("testOnB")); + + auto state = std::make_shared(&manager); + // One must not start the game at 0 - this leads to randomness in execution + manager.on("testOnB", state->objectB, state, 1); + manager.on("testOnA", state->objectA, state, 1); + + // It is expected, that A and B hand over the "changed" events between each other + state->objectA->set_number(0, 1); + for (int i = 1; i < 10; ++i) { + manager.execute_until(i * 2, state); + } + + state->log_dbg(); + + int i = 0; + curve_time_t last_time = 0; + for (auto it = state->trace.begin(); it != state->trace.end(); ++it, ++i) { + const auto &e = *it; + if (last_time > e.time) { + TESTFAILMSG("You broke the time continuum: one shall not execute randomly!"); + } + last_time = e.time; + switch(i) { + case 0: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 3); break; + case 1: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 6); break; + case 2: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 8); break; + case 3: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 11); break; + case 4: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 13); break; + case 5: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 16); break; + default: TESTFAILMSG("Too many elements in stack trace"); break; + } + } + } + + log::log(DBG << "------------- [ Starting Test: Complex Event Types ] ------------"); + // Now set up a more complex test to test the different event types + { + EventManager manager; + manager.add_class(std::make_shared( + "onChange", + EventClass::Type::ON_CHANGE)); + manager.add_class(std::make_shared( + "onChangeImm", + EventClass::Type::ON_CHANGE_IMMEDIATELY)); + manager.add_class(std::make_shared( + "onKeyframe", + EventClass::Type::ON_KEYFRAME)); + manager.add_class(std::make_shared( + "onExecute", + EventClass::Type::ON_EXECUTE)); + manager.add_class(std::make_shared( + "once", + EventClass::Type::ONCE)); + + auto state = std::make_shared(&manager); + + // One must not start the game at 0 - this leads to randomness in execution + manager.on("onChange", state->objectA, state, 4); + manager.on("onChangeImm", state->objectA, state, 1); + manager.on("onKeyframe", state->objectA, state, 1); + manager.on("onExecute", state->objectA, state, 5); + manager.on("once", state->objectA, state, 10); + + log::log(DBG << "##### SETUP DONE "); + // Without anything happen and until time 0 nothing will happen + { + manager.execute_until(0, state); // Expected: onChangeImm(1) [ we changed data at t=1] + TESTEQUALS(state->trace.empty(), true); + } + state->objectA->set_number(0, 1); + { + manager.execute_until(2, state); // Expected: nothing + TESTEQUALS(state->trace.empty(), true); + } + { + manager.execute_until(2, state); // Expected: nothing + TESTEQUALS(state->trace.empty(), true); + } + log::log(DBG << "##### INIT DONE "); + log::log(DBG << "Triggering Keyframe at 1"); + state->objectA->trigger_keyframe(1); + { + manager.execute_until(2, state); // Expected: onKeyframe(1) + state->log_dbg(); + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onKeyframe") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onKeyframe"); + TESTEQUALS(it->time, 1); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + { + manager.execute_until(5, state); // Expected: onChangeImm(2), onChange(2) and onExecute(5) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onChangeImm") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChangeImm"); + TESTEQUALS(it->time, 2); + it ++; + if (it->name != "onChange") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChange"); + TESTEQUALS(it->time, 3); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + { + manager.execute_until(11, state); // Expected: onExecute(10), once(10) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onExecute") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onExecute"); + TESTEQUALS(it->time, 10); + it ++; + if (it->name != "once") + TESTFAILMSG("Unexpected Event: " << it->name << " expected once"); + TESTEQUALS(it->time, 10); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + + log::log(DBG << "changing the value at 12"); + state->objectA->set_number(1, 12); + { + manager.execute_until(15, state); // Expected: onChangeImm, onChange(12) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onChangeImm") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChangeImm"); + TESTEQUALS(it->time, 13); + it ++; + if (it->name != "onChange") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChange"); + TESTEQUALS(it->time, 14); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + { + manager.execute_until(16, state); // Expected: onExecute(15) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onExecute") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onExecute"); + TESTEQUALS(it->time, 15); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + } + log::log(DBG << "------------- [ Starting Test: Event parameter Mapping ] ------------"); + { + class EventParameterMapTestClass : public curve::EventClass { + public: + EventParameterMapTestClass() : EventClass("EventParameterMap", EventClass::Type::ONCE) {} + + void setup(const std::shared_ptr &/*target*/, + const std::shared_ptr &/*state*/) override { + } + + void call(EventManager *, + const std::shared_ptr &/*target*/, + const std::shared_ptr &/*state*/, + const curve_time_t &/*time*/, + const EventClass::param_map ¶m) override { + log::log(DBG << "Testing unknown parameter"); + TESTEQUALS(param.contains("tomato"), false); + TESTEQUALS(param.check_type("tomato"), false); + TESTEQUALS(param.get("tomato", 1), 1); + TESTEQUALS(param.get("tomato"), 0); + TESTEQUALS(param.get("tomato", "test"), "test"); + TESTEQUALS(param.get("tomato"), ""); + + log::log(DBG << "Testing Integer parameter"); + TESTEQUALS(param.contains("testInt"), true); + TESTEQUALS(param.check_type("testInt"), true); + TESTEQUALS(param.get("testInt"), 1); + // FIXME: This should hurt you!!! + TESTEQUALS(param.get("testInt", "int"), "int"); + + log::log(DBG << "Testing char* parameter"); + TESTEQUALS(param.contains("testString"), true); + TESTEQUALS(param.check_type("testString"), true); + TESTEQUALS(strcmp(param.get("testString"), "string"), 0); + + log::log(DBG << "Testing std::string parameter"); + TESTEQUALS(param.contains("testStdString"), true); + TESTEQUALS(param.check_type("testStdString"), true); + TESTEQUALS(param.get("testStdString"), "stdstring"); + } + curve_time_t recalculate_time(const std::shared_ptr &/*target*/, + const std::shared_ptr &/*state*/, + const curve::curve_time_t &at) override { + return at; + } + }; + + curve::EventManager manager; + manager.add_class(std::make_shared()); + auto state = std::make_shared(&manager); + manager.on("EventParameterMap", state->objectA, state, 1, { + {"testInt", 1}, + {"testStdString", std::string("stdstring")}, + {"testString", "string"}}); + manager.execute_until(10, state); + + + } +} + +}}} // namespace openage::curve::tests diff --git a/libopenage/curve/test/test_trigger.cpp b/libopenage/curve/test/test_trigger.cpp deleted file mode 100644 index 7581a2d3b2..0000000000 --- a/libopenage/curve/test/test_trigger.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "../../testing/testing.h" -#include "../trigger.h" - -#include -#include - -namespace openage { -namespace curve { -namespace tests { - -void trigger() { - { - EventQueue q; - TriggerFactory factory{&q}; - std::vector lst; - Trigger a (&factory); - - a.on_change(10, "change", [&lst](EventQueue *, const curve_time_t &) { - lst.push_back("change"); - }); - - a.on_pre_horizon(100, "horizon", [&lst](EventQueue *, const curve_time_t &) { - lst.push_back("horizon"); - }); - - a.on_pass_keyframe("keyframe", [&lst](EventQueue *, const curve_time_t &) { - lst.push_back("keyframe"); - }); - - a.on_change_future("future", [&lst](EventQueue *, const curve_time_t &) { - lst.push_back("future"); - }); - - a.data_changed(1, 50); - - q.execute_until(20); - TESTEQUALS(lst.size(), 2); - TESTEQUALS(lst[0], "future"); - TESTEQUALS(lst[1], "change"); - - a.data_changed(2, 50); - lst.clear(); - q.execute_until(20); - TESTEQUALS(lst.size(), 1); - TESTEQUALS(lst[0], "future"); - - lst.clear(); - a.passed_keyframe(10); - q.execute_until(20); - TESTEQUALS(lst.size(), 1); - TESTEQUALS(lst[0], "keyframe"); - - lst.clear(); - q.execute_until(120); - TESTEQUALS(lst.size(), 1); - TESTEQUALS(lst[0], "horizon"); - } -} - -}}} // openage::curve::tests diff --git a/libopenage/curve/trigger.cpp b/libopenage/curve/trigger.cpp deleted file mode 100644 index 124c5d3b51..0000000000 --- a/libopenage/curve/trigger.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "trigger.h" - -#include - -namespace openage { -namespace curve { - -Trigger::Trigger(class TriggerFactory *factory) : - name(factory->generate_uuid(this)), - factory{factory} { -} - - -Trigger::~Trigger() { - clearevents(); - factory->remove(this); -} - - -void Trigger::on_change_future(const EventQueue::Eventclass &eventclass, - const Trigger::change_event &event) { - EventTrigger trg{event, this->name + eventclass, 0}; - change_future_queue.insert(insert_pos(trg, change_future_queue), trg); -} - - -void Trigger::on_pass_keyframe(const EventQueue::Eventclass &eventclass, - const Trigger::change_event &event) { - EventTrigger trg{event, this->name + eventclass, 0}; - change_pass_keyframe_queue.insert(insert_pos(trg, change_pass_keyframe_queue), trg); -} - - -void Trigger::on_pre_horizon(const curve_time_t &time, - const EventQueue::Eventclass &eventclass, - const Trigger::change_event &event) { - EventTrigger trg{event, this->name + eventclass, time}; - factory->enqueue(this, trg, time); -} - - -void Trigger::on_change(const curve_time_t &time, - const EventQueue::Eventclass &eventclass, - const Trigger::change_event &event) { - EventTriggerChange trg{event, this->name + eventclass, time}; - change_queue.insert(insert_pos(trg, change_queue), trg); -} - - -void Trigger::clearevents() { - factory->remove(this); - change_future_queue.clear(); - change_pass_keyframe_queue.clear(); - change_queue.clear(); -} - - -void Trigger::data_changed(const curve_time_t &now, - const curve_time_t &/*changed_at*/) { - // on_change_future will always happen when something changes - for (auto &e : change_future_queue) { - // TODO Determine if "now" or "changed_at" is more convenient - handles.push_back(EventTriggerHandle(e, factory->enqueue(this, e, now))); - } - - for (auto &e : change_queue) { - if (e.is_inserted) { - factory->reschedule(e.handle, now); - } else { - EventQueue::Handle h = factory->enqueue(this, e, now); - e.handle = h; - e.is_inserted = true; - } - } -} - - -void Trigger::passed_keyframe(const curve_time_t &time) { - for (auto &e : change_pass_keyframe_queue) { - handles.push_back(EventTriggerHandle(e, factory->enqueue(this, e, time))); - } -} - - -EventQueue::Handle TriggerFactory::enqueue(Trigger *trigger, - const Trigger::EventTrigger &trg, - const curve_time_t &at) { - auto t = trg.time; - return queue->addcallback( - trg.eventclass, - at, - [t](const curve_time_t &) { - return t; - }, - trg.event, - {trigger}); -} - - -EventQueue::Handle TriggerFactory::enqueue(Trigger *trigger, - const Trigger::EventTrigger &trg, - const EventQueue::time_predictor &timer, - const curve_time_t &at) { - return queue->addcallback( - trg.eventclass, - at, - timer, - trg.event, - {trigger} - ); -} - - -void TriggerFactory::remove(Trigger *t) { - for (const auto &handle : t->handles) { - queue->remove(handle.next_handle); - } - t->handles.clear(); -} - - -void TriggerFactory::reschedule(const EventQueue::Handle &handle, - const EventQueue::time_predictor &new_timer, - const curve_time_t &at) { - queue->reschedule(handle, new_timer, at); -} - - -void TriggerFactory::reschedule(const EventQueue::Handle &handle, - const curve_time_t &at) { - queue->reschedule(handle, at); -} - - -std::string TriggerFactory::generate_uuid(void const *ptr) { - char buf[32]; - snprintf(buf, sizeof(buf), "%p", ptr); - return std::string(buf); -} - - -TriggerIntermediateMaster::TriggerIntermediateMaster(TriggerFactory *superfactory) : - Trigger(this), TriggerFactory(superfactory->queue) { } - - -}} // namespace openage::curve diff --git a/libopenage/curve/trigger.h b/libopenage/curve/trigger.h deleted file mode 100644 index ed1d9d5f2f..0000000000 --- a/libopenage/curve/trigger.h +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -// pxd: from libcpp.string cimport string -// pxd: from libopenage.curve.events cimport EventQueue -// pxd: from libopenage.curve.curve cimport curve_time_t -#include "events.h" - -#include - -namespace openage { -namespace curve { - -/* Forward declaration of testing methods */ -namespace tests { -void trigger(); -} - -class TriggerFactory; - -/** - * A Trigger is a entity, that where one can subscripe its change interface. - * It will keep track of everything for change observation on top of event queue. - * - * pxd: - * - * cppclass Trigger: - * ctypedef void (*change_event)(EventQueue *, const curve_time_t &) - * void Trigger(TriggerFactory *) except + - * void on_change_future(const string &, const Trigger.change_event &) except + - * void on_pass_keyframe(const string &, const Trigger.change_event &) except + - * void on_pre_horizon(const curve_time_t &, const string &, const change_event &) except + - * void on_change(const curve_time_t &, const string &, const change_event &) except + - * void clearevents() except + - */ -class Trigger { - friend class TriggerFactory; - friend void tests::trigger(); // the test needs access to data_canged -public: - typedef std::function change_event; - - const std::string name; - Trigger(class TriggerFactory *factory); - - virtual ~Trigger(); - - /** - * Will be triggered when anything changes - immediately. - */ - void on_change_future(const EventQueue::Eventclass &, const change_event & ); - - /** - * Will be triggered whenever you pass a keyframe, that is not relevant for execution anymore - */ - void on_pass_keyframe(const EventQueue::Eventclass &, const change_event &); - - /** - * Will be triggred whenever execution passes this event frame - */ - void on_pre_horizon(const curve_time_t &time, const EventQueue::Eventclass &, const change_event &); - - /** - * When the queue has changed, this event will be triggered at the referenced - * time frame/ - */ - void on_change(const curve_time_t &time, const EventQueue::Eventclass &, const change_event &); - - /** - * remove all events that are registered with the event queue at the moment - */ - void clearevents(); -protected: - - /** - * This method is to be called whenever a keyframe changes. It will take care - * to enqueue the appropriate events into the main event queue. - */ - void data_changed(const curve_time_t &now, const curve_time_t &changed_at); - - /** TODO this method is still to do. */ - void passed_keyframe(const curve_time_t &); - -private: - TriggerFactory *factory; - - /** - * Contains all relevant information for triggering of events - */ - struct EventTrigger { - EventTrigger(const change_event &event, - const EventQueue::Eventclass &eventclass, - const curve_time_t time) : - event{event}, - eventclass{eventclass}, - time{time} {} - /// The callback to invoke - change_event event; - - /// The event group this is related - EventQueue::Eventclass eventclass; - - /// The time this event is scheduled - curve_time_t time; - }; - - /** - * Contains all relevant information that are contained in the pending queue - */ - struct EventTriggerHandle { - EventTriggerHandle(const EventTrigger &trigger, - const EventQueue::Handle &handle) : - trigger{trigger}, - next_handle{handle} {} - EventTrigger trigger; - EventQueue::Handle next_handle; - }; - - /** - * Specific trigger for on_change events - **/ - class EventTriggerChange : public EventTrigger { - public: - using EventTrigger::EventTrigger; - bool is_inserted = false; - EventQueue::Handle handle; - }; - - /** - * Enqueued event handles - these events are registered with the referenced - * factory - */ - std::vector handles; - - /** - * Storage of registered events, that are not only stored within the global - * event queue - */ - std::vector change_future_queue; - std::vector change_pass_keyframe_queue; -// std::vector pre_horizon_queue; // This is directly implemented in the global queue - std::vector change_queue; - - /** - * Magic to identify the insertion position for a TriggerType. - */ - template - typename InsertQueue::iterator insert_pos(const TriggerType &trg, - InsertQueue &queue) { - auto it = queue.begin(); - while (it != queue.end() && it->time < trg.time) { - ++it; - } - return it; - } -}; - - -/** - * The triggger Factory is stored once per gamestate and manages the Eventqueue - * - * pxd: - * cppclass TriggerFactory: - * pass - */ -class TriggerFactory { -public: - /** Subscribe to the event queue and manage this */ - TriggerFactory(EventQueue *queue) : - queue(queue) {} - - /** - * Remove all associated events for this trigger. - * Does not invalidate the trigger! - */ - virtual void remove(Trigger *); - - /** - * Queue the event in the underlying event queue. - */ - EventQueue::Handle enqueue(Trigger *, - const Trigger::EventTrigger &, - const curve_time_t &now); - EventQueue::Handle enqueue(Trigger *, - const Trigger::EventTrigger &, - const EventQueue::time_predictor &, - const curve_time_t &now); - - /** - * Remove the event and insert it again in the required position. - * /FIXME: Only works for future events at the moment - */ - void reschedule(const EventQueue::Handle &, - const EventQueue::time_predictor &new_timer, - const curve_time_t &now); - - void reschedule(const EventQueue::Handle &, - const curve_time_t &now); - - void reschedule(const curve_time_t &now); - - std::string generate_uuid(void const *); - - EventQueue *queue; -}; - -class TriggerIntermediateMaster : public Trigger, public TriggerFactory { -public: - TriggerIntermediateMaster(TriggerFactory *superFactory); -}; - - -}} // openage::curve diff --git a/openage/CMakeLists.txt b/openage/CMakeLists.txt index 12d46f6f5c..89a54c3ba8 100644 --- a/openage/CMakeLists.txt +++ b/openage/CMakeLists.txt @@ -20,5 +20,5 @@ add_subdirectory(cppinterface) add_subdirectory(cvar) add_subdirectory(game) add_subdirectory(log) -add_subdirectory(util) add_subdirectory(testing) +add_subdirectory(util) diff --git a/openage/testing/testlist.py b/openage/testing/testlist.py index 435edbcadb..e3f12da991 100644 --- a/openage/testing/testlist.py +++ b/openage/testing/testlist.py @@ -70,9 +70,8 @@ def tests_cpp(): yield "openage::coord::tests::coord" yield "openage::curve::tests::container" yield "openage::curve::tests::curve_types" - yield "openage::curve::tests::events" + yield "openage::curve::tests::events2" yield "openage::curve::tests::serialization" - yield "openage::curve::tests::trigger" yield "openage::datastructure::tests::constexpr_map" yield "openage::datastructure::tests::pairing_heap" yield "openage::input::tests::parse_event_string", "keybinds parsing" From 2647a1b5930cfb5f8043e19e8a21b02edf0408f8 Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Thu, 19 Oct 2017 00:53:08 +0200 Subject: [PATCH 23/24] initial gamestate draft --- libopenage/gamestate/gamestate.h | 111 +++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 libopenage/gamestate/gamestate.h diff --git a/libopenage/gamestate/gamestate.h b/libopenage/gamestate/gamestate.h new file mode 100644 index 0000000000..42f0887477 --- /dev/null +++ b/libopenage/gamestate/gamestate.h @@ -0,0 +1,111 @@ +// Copyright 2017-2017 the openage authors. See copying.md for legal info. + +#pragma once + +#include "../curve/events/eventtarget.h" +#include "../curve/map.h" +#include "../util/vector.h" + +#include + +namespace openage { +namespace curvepong { + +using unit_id_t = uint64_t; +using property_id_t = uint64_t; +using player_id_t = uint64_t; + +class NyanObserver : curve::EventTarget { +public: + NyanObserver(const EventManager &mgr, const nyan::Object &object) : + EventTarget(mgr) { + object.onchange([this](const curve::curve_time_t &at){ + this->onchange(at); + }); + } +}; + +struct NyanIdentifier { + nyan::fqon_t fqon; + nyan::memberid_t member; +}; + + +class Player { +public: + nyan::Object civilisation; + + std::set units; +}; + + +class Ability { +public: + Ability(const nyan::Object &); + nyan::Object type; +}; + +class Property : curve::EventTarget { +public: + Property(const EventManager *mgr) : + EventTarget(mgr) {}; +}; + +/** + * Element in the game universe. + * + * Everything that is somehow relevant in the game is a Unit. + */ +class Unit : curve::EventTarget { +public: + Unit (unit_id_t, const nyan::Object &); + + // Has to be kept in sync with the player list + curve::Discrete owning_player; + + /** The least common denominator is the position of an object. */ + std::shared_ptr>> position; + + /** + * List of per-unit variables that are constructed from abilities and + * properties from nyan + */ + curve::unordered_map> properties; + + /** + * property tracking within the nyan tree + * + * properties watched by this unit in nyan. This is used to traverse the + * on-change events from nyan into the event library. + */ + std::unordered_map> observed; + + /** + * The referenced unit type + */ + nyan::Object type; + + /** + * The unique identifier of this object. + */ + unit_id_t id; +}; + +class Universe { +public: + Universe(const nyan::Object &); + nyan::Object data; + + curve::unordered_map units; + + unit_id_t next_unit_id; +}; + +class Game { +public: + Universe universe; + EventManager evntmgr; + std::unordered_map players; +}; + +}} From 22e470390bc2d81750b72521213d56bb0853c85e Mon Sep 17 00:00:00 2001 From: johannes walcher Date: Sun, 3 Dec 2017 21:35:27 +0100 Subject: [PATCH 24/24] cleanup --- libopenage/curve/demo/gui.cpp | 2 +- libopenage/curve/demo/gui.h | 2 +- libopenage/curve/demo/main.cpp | 2 +- libopenage/curve/demo/physics.h | 2 +- libopenage/curve/events/event.h | 2 +- libopenage/curve/events/eventmanager.h | 4 +- .../curve/events/{events2.cpp => events.cpp} | 0 libopenage/curve/events/events.h | 32 +- libopenage/curve/events/events2.h | 34 -- libopenage/curve/events/eventtarget.h | 1 + libopenage/curve/iterator.h | 2 + libopenage/curve/queue.cpp | 2 + libopenage/curve/test/CMakeLists.txt | 2 +- libopenage/curve/test/test_events.cpp | 550 ++++++++++++++---- libopenage/curve/test/test_events2.cpp | 457 --------------- libopenage/gamestate/gamestate.h | 2 +- 16 files changed, 477 insertions(+), 619 deletions(-) rename libopenage/curve/events/{events2.cpp => events.cpp} (100%) delete mode 100644 libopenage/curve/events/events2.h delete mode 100644 libopenage/curve/test/test_events2.cpp diff --git a/libopenage/curve/demo/gui.cpp b/libopenage/curve/demo/gui.cpp index 3a3bd5c0d4..0e9afdf445 100644 --- a/libopenage/curve/demo/gui.cpp +++ b/libopenage/curve/demo/gui.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "gui.h" diff --git a/libopenage/curve/demo/gui.h b/libopenage/curve/demo/gui.h index 63f4bd7008..b5bda31620 100644 --- a/libopenage/curve/demo/gui.h +++ b/libopenage/curve/demo/gui.h @@ -1,4 +1,4 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2017-2017 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/curve/demo/main.cpp b/libopenage/curve/demo/main.cpp index 91b60fd17e..48a2924ed7 100644 --- a/libopenage/curve/demo/main.cpp +++ b/libopenage/curve/demo/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2017-2017 the openage authors. See copying.md for legal info. #include "config.h" #include "aicontroller.h" diff --git a/libopenage/curve/demo/physics.h b/libopenage/curve/demo/physics.h index 5d84f533e9..051fd5ee46 100644 --- a/libopenage/curve/demo/physics.h +++ b/libopenage/curve/demo/physics.h @@ -1,4 +1,4 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2017-2017 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/curve/events/event.h b/libopenage/curve/events/event.h index a68b27f1eb..725877a457 100644 --- a/libopenage/curve/events/event.h +++ b/libopenage/curve/events/event.h @@ -25,7 +25,7 @@ class Event { Event(const std::shared_ptr &trgt, const std::shared_ptr &eventclass, - const EventClass::param_map ¶ms); + const EventClass::param_map ¶ms); std::weak_ptr &target() { return _target; } std::shared_ptr &eventclass() {return _eventclass; } diff --git a/libopenage/curve/events/eventmanager.h b/libopenage/curve/events/eventmanager.h index e1f7710934..0e8d480405 100644 --- a/libopenage/curve/events/eventmanager.h +++ b/libopenage/curve/events/eventmanager.h @@ -2,10 +2,10 @@ #pragma once -#include "../curve.h" - #include "eventqueue.h" +#include "../curve.h" + #include #include #include diff --git a/libopenage/curve/events/events2.cpp b/libopenage/curve/events/events.cpp similarity index 100% rename from libopenage/curve/events/events2.cpp rename to libopenage/curve/events/events.cpp diff --git a/libopenage/curve/events/events.h b/libopenage/curve/events/events.h index bb4146c5f0..fedae6e178 100644 --- a/libopenage/curve/events/events.h +++ b/libopenage/curve/events/events.h @@ -2,13 +2,33 @@ #pragma once -#include "event.h" -#include "eventclass.h" -#include "eventmanager.h" -#include "eventqueue.h" -#include "eventtarget.h" +#include "../curve.h" + +#include "../../util/hash.h" + +#include +#include +#include +#include +#include + +// Forward declarations +namespace openage { +class State; +namespace curvepong { +int demo(); +} +} namespace openage { namespace curve { -}} +class Event; +class EventQueue; +class EventClass; +class EventManager; + + + + +}} // openage::curve diff --git a/libopenage/curve/events/events2.h b/libopenage/curve/events/events2.h deleted file mode 100644 index fedae6e178..0000000000 --- a/libopenage/curve/events/events2.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../curve.h" - -#include "../../util/hash.h" - -#include -#include -#include -#include -#include - -// Forward declarations -namespace openage { -class State; -namespace curvepong { -int demo(); -} -} - -namespace openage { -namespace curve { - -class Event; -class EventQueue; -class EventClass; -class EventManager; - - - - -}} // openage::curve diff --git a/libopenage/curve/events/eventtarget.h b/libopenage/curve/events/eventtarget.h index 15d0c42474..41db00b367 100644 --- a/libopenage/curve/events/eventtarget.h +++ b/libopenage/curve/events/eventtarget.h @@ -4,6 +4,7 @@ #include "../curve.h" +#include #include #include diff --git a/libopenage/curve/iterator.h b/libopenage/curve/iterator.h index cc54f941a2..64f4f021a5 100644 --- a/libopenage/curve/iterator.h +++ b/libopenage/curve/iterator.h @@ -4,6 +4,8 @@ #include "curve.h" +#include + namespace openage { namespace curve { diff --git a/libopenage/curve/queue.cpp b/libopenage/curve/queue.cpp index ce40d6ce9d..744674ac7d 100644 --- a/libopenage/curve/queue.cpp +++ b/libopenage/curve/queue.cpp @@ -5,4 +5,6 @@ namespace openage { namespace curve { +// This file is intended to be empty + }} // namespace openage::curve diff --git a/libopenage/curve/test/CMakeLists.txt b/libopenage/curve/test/CMakeLists.txt index df83cfb5a1..7538eb49ea 100644 --- a/libopenage/curve/test/CMakeLists.txt +++ b/libopenage/curve/test/CMakeLists.txt @@ -3,6 +3,6 @@ link_libraries(tube) add_sources(libopenage test_container.cpp test_curve_types.cpp - test_events2.cpp + test_events.cpp test_serialization.cpp ) diff --git a/libopenage/curve/test/test_events.cpp b/libopenage/curve/test/test_events.cpp index 5c9a18659b..20a2634b84 100644 --- a/libopenage/curve/test/test_events.cpp +++ b/libopenage/curve/test/test_events.cpp @@ -1,137 +1,461 @@ // Copyright 2017-2017 the openage authors. See copying.md for legal info. +#include "../events/events.h" +#include "../events/eventtarget.h" +#include "../events/eventclass.h" +#include "../events/eventmanager.h" + + #include "../../testing/testing.h" -#include "../curve.h" -#include "../events.h" +#include "../../log/log.h" + +#include + +#include // for strcmp namespace openage { + +// We have to create a temporary State due to the magic of C++ +class State { +public: + class TestObject : public curve::EventTarget { + const int _id; + public: + TestObject(curve::EventManager *manager, int id) : EventTarget(manager), _id{id}, number(0) {} + void set_number(int number, const curve::curve_time_t &time) { + this->number = number; + this->on_change(time + 1); + } + int number; + + size_t id() const override { return _id; } + void trigger_keyframe(const curve::curve_time_t &time) { this->on_pass_keyframe(time); } + }; + + State(curve::EventManager *manager) : + objectA(std::make_shared(manager, 0)) , + objectB(std::make_shared(manager, 1)) + {} + + std::shared_ptr objectA; + std::shared_ptr objectB; + + struct traceelement { + traceelement(const std::string &event, curve::curve_time_t time) : + time{time}, name{event} {} + curve::curve_time_t time; + std::string name; + }; + std::list trace; + + void log_dbg() { + log::log(DBG << "Trace: "); + for (const auto &e : this->trace) { + log::log(DBG << "T: " << e.time << ": " << e.name); + } + } +}; + namespace curve { namespace tests { -static void print_vector(const std::vector> &t) { - for (const auto &a : t) { - std::cout << a.first << ":" << a.second << std::endl; +class TestEventClass : public EventClass { + int idx; +public: + TestEventClass(const std::string &name, int idx) : EventClass(name, EventClass::Type::ON_CHANGE), idx{idx} {} + + void setup(const std::shared_ptr &target, + const std::shared_ptr &state) override { + switch(idx) { + case 0: + add_dependency(target, state->objectB); + break; + case 1: + add_dependency(target, state->objectA); + break; + } } -} -EventQueue createQueue(std::vector> &calls) { - EventQueue q; - q.addcallback("1", 1, [](const curve_time_t &) { - return 1; - }, - [&calls](EventQueue *, const curve_time_t &t) { - calls.push_back(std::make_pair(t, 1)); - }, {}); - - q.addcallback("2", 2, [](const curve_time_t &) { - return 2; - }, - [&calls](EventQueue *, const curve_time_t &t) { - calls.push_back(std::make_pair(t, 2)); - }, {}); - - return q; -} + void call(EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &time, + const EventClass::param_map &/*param*/) override { + (void)target; + switch (idx) { + case 0: { + auto t = std::dynamic_pointer_cast(target); + state->objectA->set_number(t->number + 1, time); + log::log(DBG << "I am Event A. Setting number to " << state->objectA->number); + state->trace.emplace_back("A", time); + } break; + case 1: { + auto t = std::dynamic_pointer_cast(target); + state->objectB->set_number(t->number + 1, time); + log::log(DBG << "I am Event B. Setting number to " << state->objectB->number); + state->trace.emplace_back("B", time); + } break; + } + } -void events () { - { - std::vector> calls; - print_vector(calls); + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &at) override { + // TODO recalculate a hit time + (void)target; + (void)state; + return at + 2; + } +}; + +class TestEventClassTwo : public EventClass { +public: + TestEventClassTwo(const std::string &name) : EventClass(name, EventClass::Type::ON_CHANGE) {} + + void setup(const std::shared_ptr &target, const std::shared_ptr &state) override { + add_dependency(target, state->objectA); + } - // Test with empty queue - EventQueue q; - q.execute_until(100); + void call(EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &time, + const EventClass::param_map &/*param*/) override { + auto t = std::dynamic_pointer_cast(target); + state->objectB->set_number(t->number + 1, time); + log::log(DBG << "I am EventClassTwo. Setting B.number to " << state->objectB->number); + state->trace.emplace_back("B", time); } + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &at) override { + // TODO recalculate a hit time + (void)target; + (void)state; + return at + 1; + } +}; + +class EventTypeTestClass : public EventClass { +public: + EventTypeTestClass(const std::string &name, EventClass::Type type) : EventClass(name, type) {} + + void setup(const std::shared_ptr &target, + const std::shared_ptr &state) override { + add_dependency(target, state->objectA); + } + + void call(EventManager *, + const std::shared_ptr &target, + const std::shared_ptr &state, + const curve_time_t &time, + const EventClass::param_map &/*param*/) override { + switch(this->type) { + case EventClass::Type::ON_CHANGE: + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + case EventClass::Type::ON_KEYFRAME: + case EventClass::Type::ON_EXECUTE: + case EventClass::Type::ONCE: + break; + } + auto t = std::dynamic_pointer_cast(target); + log::log(DBG << this->id() << " got called on " << t->id() + << " with number " << t->number << " at " << time); + state->trace.emplace_back(this->id(), time); + (void)time; + (void)state; + } + + curve_time_t recalculate_time(const std::shared_ptr &target, + const std::shared_ptr &state, + const curve::curve_time_t &at) override { + (void)target; + (void)state; + switch(this->type) { + case EventClass::Type::ON_CHANGE: + return at+1; // Execute 1 after the change (usually it is neccessary to recalculate a colission + case EventClass::Type::ON_CHANGE_IMMEDIATELY: + TESTFAILMSG("ON_CHANGE_IMMEDIATELY does not recalculate time!"); + return 0; // This is ignored anyway + case EventClass::Type::ON_KEYFRAME: + TESTFAILMSG("ON_KEYFRAME does not recalculate time!"); + return 0; // This is ignored anyway + case EventClass::Type::ON_EXECUTE: + return at + 5; // This will force the execution every 5ms + case EventClass::Type::ONCE: + return 10; // even if data changed it will happen at the given time! + } + return at; + } +}; + +void events2() { + log::log(DBG << "------------- [ Starting Test: Basic Ping Pong ] ------------"); + // test destruction + std::weak_ptr destruction_test_state; { - std::vector> calls; - EventQueue q = createQueue(calls); - q.execute_until(2); - TESTEQUALS(calls.size(), 1); - TESTEQUALS(calls[0].first, 1); - TESTEQUALS(calls[0].second, 1); + // Test with one event class + EventManager manager; + + manager.add_class(std::make_shared("testOnA", 0)); + manager.add_class(std::make_shared("testOnB", 1)); + + auto state = std::make_shared(&manager); + destruction_test_state = state; + // One must not start the game at 0 - this leads to randomness in execution + manager.on("testOnB", state->objectB, state, 1); + manager.on("testOnA", state->objectA, state, 1); + + // It is expected, that A and B hand over the "changed" events between each other + state->objectA->set_number(0, 0); + for (int i = 1; i < 10; ++i) { + manager.execute_until(i * 2, state); + } + + state->log_dbg(); + + int i = 0; + curve_time_t last_time = 0; + for (auto it = state->trace.begin(); it != state->trace.end(); ++it, ++i) { + const auto &e = *it; + if (last_time > e.time) { + TESTFAILMSG("You broke the time continuum: one shall not execute randomly!"); + } + last_time = e.time; + switch(i) { + case 0: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 3); break; + case 1: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 6); break; + case 2: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 9); break; + case 3: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 12); break; + case 4: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 15); break; + default: TESTFAILMSG("Too many elements in stack trace"); break; + } + } + } + if (!destruction_test_state.expired()) { + TESTFAILMSG("Test Failed because State was not automatically destructed"); } + + log::log(DBG << "------------- [ Starting Test: Two Event Ping Pong ] ------------"); { - std::vector> calls; - EventQueue q = createQueue(calls); - q.execute_until(3); - TESTEQUALS(calls.size(), 2); - TESTEQUALS(calls[0].first, 1); - TESTEQUALS(calls[0].second, 1); - TESTEQUALS(calls[1].first, 2); - TESTEQUALS(calls[1].second, 2); + // Test with two event classes to check interplay + // Test with one event class + EventManager manager; + + manager.add_class(std::make_shared("testOnA", 0)); + manager.add_class(std::make_shared("testOnB")); + + auto state = std::make_shared(&manager); + // One must not start the game at 0 - this leads to randomness in execution + manager.on("testOnB", state->objectB, state, 1); + manager.on("testOnA", state->objectA, state, 1); + + // It is expected, that A and B hand over the "changed" events between each other + state->objectA->set_number(0, 1); + for (int i = 1; i < 10; ++i) { + manager.execute_until(i * 2, state); + } + + state->log_dbg(); + + int i = 0; + curve_time_t last_time = 0; + for (auto it = state->trace.begin(); it != state->trace.end(); ++it, ++i) { + const auto &e = *it; + if (last_time > e.time) { + TESTFAILMSG("You broke the time continuum: one shall not execute randomly!"); + } + last_time = e.time; + switch(i) { + case 0: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 3); break; + case 1: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 6); break; + case 2: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 8); break; + case 3: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 11); break; + case 4: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 13); break; + case 5: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 16); break; + default: TESTFAILMSG("Too many elements in stack trace"); break; + } + } } + log::log(DBG << "------------- [ Starting Test: Complex Event Types ] ------------"); + // Now set up a more complex test to test the different event types { - std::vector> calls; - EventQueue q = createQueue(calls); - q.execute_until(2); - TESTEQUALS(calls.size(), 1); - calls.clear(); - q.execute_until(3); - TESTEQUALS(calls.size(), 1); - TESTEQUALS(calls[0].first, 2); - TESTEQUALS(calls[0].second, 2); + EventManager manager; + manager.add_class(std::make_shared( + "onChange", + EventClass::Type::ON_CHANGE)); + manager.add_class(std::make_shared( + "onChangeImm", + EventClass::Type::ON_CHANGE_IMMEDIATELY)); + manager.add_class(std::make_shared( + "onKeyframe", + EventClass::Type::ON_KEYFRAME)); + manager.add_class(std::make_shared( + "onExecute", + EventClass::Type::ON_EXECUTE)); + manager.add_class(std::make_shared( + "once", + EventClass::Type::ONCE)); + + auto state = std::make_shared(&manager); + + // One must not start the game at 0 - this leads to randomness in execution + manager.on("onChange", state->objectA, state, 4); + manager.on("onChangeImm", state->objectA, state, 1); + manager.on("onKeyframe", state->objectA, state, 1); + manager.on("onExecute", state->objectA, state, 5); + manager.on("once", state->objectA, state, 10); + + log::log(DBG << "##### SETUP DONE "); + // Without anything happen and until time 0 nothing will happen + { + manager.execute_until(0, state); // Expected: onChangeImm(1) [ we changed data at t=1] + TESTEQUALS(state->trace.empty(), true); + } + state->objectA->set_number(0, 1); + { + manager.execute_until(2, state); // Expected: nothing + TESTEQUALS(state->trace.empty(), true); + } + { + manager.execute_until(2, state); // Expected: nothing + TESTEQUALS(state->trace.empty(), true); + } + log::log(DBG << "##### INIT DONE "); + log::log(DBG << "Triggering Keyframe at 1"); + state->objectA->trigger_keyframe(1); + { + manager.execute_until(2, state); // Expected: onKeyframe(1) + state->log_dbg(); + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onKeyframe") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onKeyframe"); + TESTEQUALS(it->time, 1); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + { + manager.execute_until(5, state); // Expected: onChangeImm(2), onChange(2) and onExecute(5) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onChangeImm") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChangeImm"); + TESTEQUALS(it->time, 2); + it ++; + if (it->name != "onChange") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChange"); + TESTEQUALS(it->time, 3); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + { + manager.execute_until(11, state); // Expected: onExecute(10), once(10) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onExecute") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onExecute"); + TESTEQUALS(it->time, 10); + it ++; + if (it->name != "once") + TESTFAILMSG("Unexpected Event: " << it->name << " expected once"); + TESTEQUALS(it->time, 10); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + + log::log(DBG << "changing the value at 12"); + state->objectA->set_number(1, 12); + { + manager.execute_until(15, state); // Expected: onChangeImm, onChange(12) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onChangeImm") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChangeImm"); + TESTEQUALS(it->time, 13); + it ++; + if (it->name != "onChange") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onChange"); + TESTEQUALS(it->time, 14); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } + { + manager.execute_until(16, state); // Expected: onExecute(15) + TESTEQUALS(state->trace.empty(), false); + auto it = state->trace.begin(); + if (it->name != "onExecute") + TESTFAILMSG("Unexpected Event: " << it->name << " expected onExecute"); + TESTEQUALS(it->time, 15); + it ++; + TESTEQUALS(it == state->trace.end(), true); + state->trace.clear(); + } } + log::log(DBG << "------------- [ Starting Test: Event parameter Mapping ] ------------"); + { + class EventParameterMapTestClass : public curve::EventClass { + public: + EventParameterMapTestClass() : EventClass("EventParameterMap", EventClass::Type::ONCE) {} + + void setup(const std::shared_ptr &/*target*/, + const std::shared_ptr &/*state*/) override { + } + + void call(EventManager *, + const std::shared_ptr &/*target*/, + const std::shared_ptr &/*state*/, + const curve_time_t &/*time*/, + const EventClass::param_map ¶m) override { + log::log(DBG << "Testing unknown parameter"); + TESTEQUALS(param.contains("tomato"), false); + TESTEQUALS(param.check_type("tomato"), false); + TESTEQUALS(param.get("tomato", 1), 1); + TESTEQUALS(param.get("tomato"), 0); + TESTEQUALS(param.get("tomato", "test"), "test"); + TESTEQUALS(param.get("tomato"), ""); + + log::log(DBG << "Testing Integer parameter"); + TESTEQUALS(param.contains("testInt"), true); + TESTEQUALS(param.check_type("testInt"), true); + TESTEQUALS(param.get("testInt"), 1); + // FIXME: This should hurt you!!! + TESTEQUALS(param.get("testInt", "int"), "int"); + + log::log(DBG << "Testing char* parameter"); + TESTEQUALS(param.contains("testString"), true); + TESTEQUALS(param.check_type("testString"), true); + TESTEQUALS(strcmp(param.get("testString"), "string"), 0); + + log::log(DBG << "Testing std::string parameter"); + TESTEQUALS(param.contains("testStdString"), true); + TESTEQUALS(param.check_type("testStdString"), true); + TESTEQUALS(param.get("testStdString"), "stdstring"); + } + curve_time_t recalculate_time(const std::shared_ptr &/*target*/, + const std::shared_ptr &/*state*/, + const curve::curve_time_t &at) override { + return at; + } + }; + + curve::EventManager manager; + manager.add_class(std::make_shared()); + auto state = std::make_shared(&manager); + manager.on("EventParameterMap", state->objectA, state, 1, { + {"testInt", 1}, + {"testStdString", std::string("stdstring")}, + {"testString", "string"}}); + manager.execute_until(10, state); + - /* - int cond1 = 1; - q.addcallback(4, [&calls, cond1](const curve_time_t &) { - return cond1 == 1; - }, - [&calls](EventQueue *, const curve_time_t &t) { - calls.push_back(std::make_pair(t, 4)); - }); - - cond1 = 1; - calls.clear(); - q.trigger(4, 5); - TESTEQUALS(calls.size(), 1); - TESTEQUALS(calls[0].first, 4); - TESTEQUALS(calls[0].second, 4); - - cond1 = 0; - calls.clear(); - TESTEQUALS(calls.size(), 0); - - int cond2 = 1; - q.addcallback(5, [&cond2](const curve_time_t &) { - return cond2 == 1; - }, - [&calls](EventQueue *, const curve_time_t &t) { - calls.push_back(std::make_pair(t, 5)); - }); - - q.addcallback(6, [&cond2](const curve_time_t &) { - return cond2 == 1 || cond2 == 2; - }, - [&calls, &cond2] (EventQueue *, const curve_time_t &t) { - calls.push_back(std::make_pair(t, 6)); - cond2 ++; - }); - - cond2 = 1; - calls.clear(); - q.trigger(5, 7); - TESTEQUALS(calls.size(), 2); - TESTEQUALS(calls[0].first, 5); - TESTEQUALS(calls[0].second, 5); - TESTEQUALS(calls[1].first, 6); - TESTEQUALS(calls[1].second, 6); - TESTEQUALS(cond2, 2); - - calls.clear(); - q.trigger(5, 7); - TESTEQUALS(calls.size(), 1); - TESTEQUALS(calls[0].first, 6); - TESTEQUALS(calls[0].second, 6); - TESTEQUALS(cond2, 3); - - calls.clear(); - q.trigger(5, 7); - TESTEQUALS(calls.size(), 0); - TESTEQUALS(cond2, 3); - */ + } } -}}} // namespace::curve::tests +}}} // namespace openage::curve::tests diff --git a/libopenage/curve/test/test_events2.cpp b/libopenage/curve/test/test_events2.cpp deleted file mode 100644 index 41c50ee105..0000000000 --- a/libopenage/curve/test/test_events2.cpp +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "../events/events.h" - -#include "../../testing/testing.h" -#include "../../log/log.h" - -#include - -#include // for strcmp - -namespace openage { - -// We have to create a temporary State due to the magic of C++ -class State { -public: - class TestObject : public curve::EventTarget { - const int _id; - public: - TestObject(curve::EventManager *manager, int id) : EventTarget(manager), _id{id}, number(0) {} - void set_number(int number, const curve::curve_time_t &time) { - this->number = number; - this->on_change(time + 1); - } - int number; - - size_t id() const override { return _id; } - void trigger_keyframe(const curve::curve_time_t &time) { this->on_pass_keyframe(time); } - }; - - State(curve::EventManager *manager) : - objectA(std::make_shared(manager, 0)) , - objectB(std::make_shared(manager, 1)) - {} - - std::shared_ptr objectA; - std::shared_ptr objectB; - - struct traceelement { - traceelement(const std::string &event, curve::curve_time_t time) : - time{time}, name{event} {} - curve::curve_time_t time; - std::string name; - }; - std::list trace; - - void log_dbg() { - log::log(DBG << "Trace: "); - for (const auto &e : this->trace) { - log::log(DBG << "T: " << e.time << ": " << e.name); - } - } -}; - -namespace curve { -namespace tests { - -class TestEventClass : public EventClass { - int idx; -public: - TestEventClass(const std::string &name, int idx) : EventClass(name, EventClass::Type::ON_CHANGE), idx{idx} {} - - void setup(const std::shared_ptr &target, - const std::shared_ptr &state) override { - switch(idx) { - case 0: - add_dependency(target, state->objectB); - break; - case 1: - add_dependency(target, state->objectA); - break; - } - } - - void call(EventManager *, - const std::shared_ptr &target, - const std::shared_ptr &state, - const curve_time_t &time, - const EventClass::param_map &/*param*/) override { - (void)target; - switch (idx) { - case 0: { - auto t = std::dynamic_pointer_cast(target); - state->objectA->set_number(t->number + 1, time); - log::log(DBG << "I am Event A. Setting number to " << state->objectA->number); - state->trace.emplace_back("A", time); - } break; - case 1: { - auto t = std::dynamic_pointer_cast(target); - state->objectB->set_number(t->number + 1, time); - log::log(DBG << "I am Event B. Setting number to " << state->objectB->number); - state->trace.emplace_back("B", time); - } break; - } - } - - curve_time_t recalculate_time(const std::shared_ptr &target, - const std::shared_ptr &state, - const curve::curve_time_t &at) override { - // TODO recalculate a hit time - (void)target; - (void)state; - return at + 2; - } -}; - -class TestEventClassTwo : public EventClass { -public: - TestEventClassTwo(const std::string &name) : EventClass(name, EventClass::Type::ON_CHANGE) {} - - void setup(const std::shared_ptr &target, const std::shared_ptr &state) override { - add_dependency(target, state->objectA); - } - - void call(EventManager *, - const std::shared_ptr &target, - const std::shared_ptr &state, - const curve_time_t &time, - const EventClass::param_map &/*param*/) override { - auto t = std::dynamic_pointer_cast(target); - state->objectB->set_number(t->number + 1, time); - log::log(DBG << "I am EventClassTwo. Setting B.number to " << state->objectB->number); - state->trace.emplace_back("B", time); - } - - curve_time_t recalculate_time(const std::shared_ptr &target, - const std::shared_ptr &state, - const curve::curve_time_t &at) override { - // TODO recalculate a hit time - (void)target; - (void)state; - return at + 1; - } -}; - -class EventTypeTestClass : public EventClass { -public: - EventTypeTestClass(const std::string &name, EventClass::Type type) : EventClass(name, type) {} - - void setup(const std::shared_ptr &target, - const std::shared_ptr &state) override { - add_dependency(target, state->objectA); - } - - void call(EventManager *, - const std::shared_ptr &target, - const std::shared_ptr &state, - const curve_time_t &time, - const EventClass::param_map &/*param*/) override { - switch(this->type) { - case EventClass::Type::ON_CHANGE: - case EventClass::Type::ON_CHANGE_IMMEDIATELY: - case EventClass::Type::ON_KEYFRAME: - case EventClass::Type::ON_EXECUTE: - case EventClass::Type::ONCE: - break; - } - auto t = std::dynamic_pointer_cast(target); - log::log(DBG << this->id() << " got called on " << t->id() - << " with number " << t->number << " at " << time); - state->trace.emplace_back(this->id(), time); - (void)time; - (void)state; - } - - curve_time_t recalculate_time(const std::shared_ptr &target, - const std::shared_ptr &state, - const curve::curve_time_t &at) override { - (void)target; - (void)state; - switch(this->type) { - case EventClass::Type::ON_CHANGE: - return at+1; // Execute 1 after the change (usually it is neccessary to recalculate a colission - case EventClass::Type::ON_CHANGE_IMMEDIATELY: - TESTFAILMSG("ON_CHANGE_IMMEDIATELY does not recalculate time!"); - return 0; // This is ignored anyway - case EventClass::Type::ON_KEYFRAME: - TESTFAILMSG("ON_KEYFRAME does not recalculate time!"); - return 0; // This is ignored anyway - case EventClass::Type::ON_EXECUTE: - return at + 5; // This will force the execution every 5ms - case EventClass::Type::ONCE: - return 10; // even if data changed it will happen at the given time! - } - return at; - } -}; - -void events2() { - log::log(DBG << "------------- [ Starting Test: Basic Ping Pong ] ------------"); - // test destruction - std::weak_ptr destruction_test_state; - { - // Test with one event class - EventManager manager; - - manager.add_class(std::make_shared("testOnA", 0)); - manager.add_class(std::make_shared("testOnB", 1)); - - auto state = std::make_shared(&manager); - destruction_test_state = state; - // One must not start the game at 0 - this leads to randomness in execution - manager.on("testOnB", state->objectB, state, 1); - manager.on("testOnA", state->objectA, state, 1); - - // It is expected, that A and B hand over the "changed" events between each other - state->objectA->set_number(0, 0); - for (int i = 1; i < 10; ++i) { - manager.execute_until(i * 2, state); - } - - state->log_dbg(); - - int i = 0; - curve_time_t last_time = 0; - for (auto it = state->trace.begin(); it != state->trace.end(); ++it, ++i) { - const auto &e = *it; - if (last_time > e.time) { - TESTFAILMSG("You broke the time continuum: one shall not execute randomly!"); - } - last_time = e.time; - switch(i) { - case 0: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 3); break; - case 1: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 6); break; - case 2: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 9); break; - case 3: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 12); break; - case 4: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 15); break; - default: TESTFAILMSG("Too many elements in stack trace"); break; - } - } - } - if (!destruction_test_state.expired()) { - TESTFAILMSG("Test Failed because State was not automatically destructed"); - } - - log::log(DBG << "------------- [ Starting Test: Two Event Ping Pong ] ------------"); - { - // Test with two event classes to check interplay - // Test with one event class - EventManager manager; - - manager.add_class(std::make_shared("testOnA", 0)); - manager.add_class(std::make_shared("testOnB")); - - auto state = std::make_shared(&manager); - // One must not start the game at 0 - this leads to randomness in execution - manager.on("testOnB", state->objectB, state, 1); - manager.on("testOnA", state->objectA, state, 1); - - // It is expected, that A and B hand over the "changed" events between each other - state->objectA->set_number(0, 1); - for (int i = 1; i < 10; ++i) { - manager.execute_until(i * 2, state); - } - - state->log_dbg(); - - int i = 0; - curve_time_t last_time = 0; - for (auto it = state->trace.begin(); it != state->trace.end(); ++it, ++i) { - const auto &e = *it; - if (last_time > e.time) { - TESTFAILMSG("You broke the time continuum: one shall not execute randomly!"); - } - last_time = e.time; - switch(i) { - case 0: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 3); break; - case 1: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 6); break; - case 2: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 8); break; - case 3: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 11); break; - case 4: TESTEQUALS(e.name, "B"); TESTEQUALS(e.time, 13); break; - case 5: TESTEQUALS(e.name, "A"); TESTEQUALS(e.time, 16); break; - default: TESTFAILMSG("Too many elements in stack trace"); break; - } - } - } - - log::log(DBG << "------------- [ Starting Test: Complex Event Types ] ------------"); - // Now set up a more complex test to test the different event types - { - EventManager manager; - manager.add_class(std::make_shared( - "onChange", - EventClass::Type::ON_CHANGE)); - manager.add_class(std::make_shared( - "onChangeImm", - EventClass::Type::ON_CHANGE_IMMEDIATELY)); - manager.add_class(std::make_shared( - "onKeyframe", - EventClass::Type::ON_KEYFRAME)); - manager.add_class(std::make_shared( - "onExecute", - EventClass::Type::ON_EXECUTE)); - manager.add_class(std::make_shared( - "once", - EventClass::Type::ONCE)); - - auto state = std::make_shared(&manager); - - // One must not start the game at 0 - this leads to randomness in execution - manager.on("onChange", state->objectA, state, 4); - manager.on("onChangeImm", state->objectA, state, 1); - manager.on("onKeyframe", state->objectA, state, 1); - manager.on("onExecute", state->objectA, state, 5); - manager.on("once", state->objectA, state, 10); - - log::log(DBG << "##### SETUP DONE "); - // Without anything happen and until time 0 nothing will happen - { - manager.execute_until(0, state); // Expected: onChangeImm(1) [ we changed data at t=1] - TESTEQUALS(state->trace.empty(), true); - } - state->objectA->set_number(0, 1); - { - manager.execute_until(2, state); // Expected: nothing - TESTEQUALS(state->trace.empty(), true); - } - { - manager.execute_until(2, state); // Expected: nothing - TESTEQUALS(state->trace.empty(), true); - } - log::log(DBG << "##### INIT DONE "); - log::log(DBG << "Triggering Keyframe at 1"); - state->objectA->trigger_keyframe(1); - { - manager.execute_until(2, state); // Expected: onKeyframe(1) - state->log_dbg(); - TESTEQUALS(state->trace.empty(), false); - auto it = state->trace.begin(); - if (it->name != "onKeyframe") - TESTFAILMSG("Unexpected Event: " << it->name << " expected onKeyframe"); - TESTEQUALS(it->time, 1); - it ++; - TESTEQUALS(it == state->trace.end(), true); - state->trace.clear(); - } - { - manager.execute_until(5, state); // Expected: onChangeImm(2), onChange(2) and onExecute(5) - TESTEQUALS(state->trace.empty(), false); - auto it = state->trace.begin(); - if (it->name != "onChangeImm") - TESTFAILMSG("Unexpected Event: " << it->name << " expected onChangeImm"); - TESTEQUALS(it->time, 2); - it ++; - if (it->name != "onChange") - TESTFAILMSG("Unexpected Event: " << it->name << " expected onChange"); - TESTEQUALS(it->time, 3); - it ++; - TESTEQUALS(it == state->trace.end(), true); - state->trace.clear(); - } - { - manager.execute_until(11, state); // Expected: onExecute(10), once(10) - TESTEQUALS(state->trace.empty(), false); - auto it = state->trace.begin(); - if (it->name != "onExecute") - TESTFAILMSG("Unexpected Event: " << it->name << " expected onExecute"); - TESTEQUALS(it->time, 10); - it ++; - if (it->name != "once") - TESTFAILMSG("Unexpected Event: " << it->name << " expected once"); - TESTEQUALS(it->time, 10); - it ++; - TESTEQUALS(it == state->trace.end(), true); - state->trace.clear(); - } - - log::log(DBG << "changing the value at 12"); - state->objectA->set_number(1, 12); - { - manager.execute_until(15, state); // Expected: onChangeImm, onChange(12) - TESTEQUALS(state->trace.empty(), false); - auto it = state->trace.begin(); - if (it->name != "onChangeImm") - TESTFAILMSG("Unexpected Event: " << it->name << " expected onChangeImm"); - TESTEQUALS(it->time, 13); - it ++; - if (it->name != "onChange") - TESTFAILMSG("Unexpected Event: " << it->name << " expected onChange"); - TESTEQUALS(it->time, 14); - it ++; - TESTEQUALS(it == state->trace.end(), true); - state->trace.clear(); - } - { - manager.execute_until(16, state); // Expected: onExecute(15) - TESTEQUALS(state->trace.empty(), false); - auto it = state->trace.begin(); - if (it->name != "onExecute") - TESTFAILMSG("Unexpected Event: " << it->name << " expected onExecute"); - TESTEQUALS(it->time, 15); - it ++; - TESTEQUALS(it == state->trace.end(), true); - state->trace.clear(); - } - } - log::log(DBG << "------------- [ Starting Test: Event parameter Mapping ] ------------"); - { - class EventParameterMapTestClass : public curve::EventClass { - public: - EventParameterMapTestClass() : EventClass("EventParameterMap", EventClass::Type::ONCE) {} - - void setup(const std::shared_ptr &/*target*/, - const std::shared_ptr &/*state*/) override { - } - - void call(EventManager *, - const std::shared_ptr &/*target*/, - const std::shared_ptr &/*state*/, - const curve_time_t &/*time*/, - const EventClass::param_map ¶m) override { - log::log(DBG << "Testing unknown parameter"); - TESTEQUALS(param.contains("tomato"), false); - TESTEQUALS(param.check_type("tomato"), false); - TESTEQUALS(param.get("tomato", 1), 1); - TESTEQUALS(param.get("tomato"), 0); - TESTEQUALS(param.get("tomato", "test"), "test"); - TESTEQUALS(param.get("tomato"), ""); - - log::log(DBG << "Testing Integer parameter"); - TESTEQUALS(param.contains("testInt"), true); - TESTEQUALS(param.check_type("testInt"), true); - TESTEQUALS(param.get("testInt"), 1); - // FIXME: This should hurt you!!! - TESTEQUALS(param.get("testInt", "int"), "int"); - - log::log(DBG << "Testing char* parameter"); - TESTEQUALS(param.contains("testString"), true); - TESTEQUALS(param.check_type("testString"), true); - TESTEQUALS(strcmp(param.get("testString"), "string"), 0); - - log::log(DBG << "Testing std::string parameter"); - TESTEQUALS(param.contains("testStdString"), true); - TESTEQUALS(param.check_type("testStdString"), true); - TESTEQUALS(param.get("testStdString"), "stdstring"); - } - curve_time_t recalculate_time(const std::shared_ptr &/*target*/, - const std::shared_ptr &/*state*/, - const curve::curve_time_t &at) override { - return at; - } - }; - - curve::EventManager manager; - manager.add_class(std::make_shared()); - auto state = std::make_shared(&manager); - manager.on("EventParameterMap", state->objectA, state, 1, { - {"testInt", 1}, - {"testStdString", std::string("stdstring")}, - {"testString", "string"}}); - manager.execute_until(10, state); - - - } -} - -}}} // namespace openage::curve::tests diff --git a/libopenage/gamestate/gamestate.h b/libopenage/gamestate/gamestate.h index 42f0887477..862dc79dcd 100644 --- a/libopenage/gamestate/gamestate.h +++ b/libopenage/gamestate/gamestate.h @@ -19,7 +19,7 @@ class NyanObserver : curve::EventTarget { public: NyanObserver(const EventManager &mgr, const nyan::Object &object) : EventTarget(mgr) { - object.onchange([this](const curve::curve_time_t &at){ + object.onchange([this](const curve::curve_time_t &at) { this->onchange(at); }); }