diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 83e676be2..dc3b097fc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -24,7 +24,7 @@ If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. mac/linux/windows] - - Version [e.g. 0.3.1] + - Version [e.g. 0.3.2] **Additional context** Add any other context about the problem here. diff --git a/CMakeLists.txt b/CMakeLists.txt index 16502fa97..563beb28b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10.0) -project(Griddly VERSION 0.3.1) +project(Griddly VERSION 0.3.2) set(BINARY ${CMAKE_PROJECT_NAME}) diff --git a/bindings/python.cpp b/bindings/python.cpp index 9e94db8a9..776ad6be6 100644 --- a/bindings/python.cpp +++ b/bindings/python.cpp @@ -12,7 +12,7 @@ namespace griddly { PYBIND11_MODULE(python_griddly, m) { m.doc() = "Griddly python bindings"; - m.attr("version") = "0.3.1"; + m.attr("version") = "0.3.2"; #ifndef NDEBUG spdlog::set_level(spdlog::level::debug); diff --git a/bindings/wrapper/GameWrapper.cpp b/bindings/wrapper/GameWrapper.cpp index c408e509b..8d58b4eec 100644 --- a/bindings/wrapper/GameWrapper.cpp +++ b/bindings/wrapper/GameWrapper.cpp @@ -240,6 +240,7 @@ class Py_GameWrapper { py_objectInfo["Location"] = py::cast(std::vector{ objectInfo.location.x, objectInfo.location.y}); + py_objectInfo["Orientation"] = objectInfo.orientation.getName(); py_objectInfo["PlayerId"] = objectInfo.playerId; py_objectInfo["Variables"] = py_objectVariables; diff --git a/bindings/wrapper/NumpyWrapper.cpp b/bindings/wrapper/NumpyWrapper.cpp index ead3978e2..ce9097e5f 100644 --- a/bindings/wrapper/NumpyWrapper.cpp +++ b/bindings/wrapper/NumpyWrapper.cpp @@ -6,18 +6,18 @@ namespace griddly { template class NumpyWrapper { public: - NumpyWrapper(std::vector shape, std::vector strides, std::shared_ptr data) - : shape_(shape), strides_(strides), data_(std::move(data)) { + NumpyWrapper(std::vector shape, std::vector strides, Scalar* data) + : shape_(shape), strides_(strides), data_(data) { } std::vector getShape() const { return shape_; } std::vector getStrides() const { return strides_; } uint32_t getScalarSize() const { return sizeof(Scalar); } - Scalar* getData() const { return data_.get(); } + Scalar* getData() const { return data_; } private: const std::vector shape_; const std::vector strides_; - const std::shared_ptr data_; + Scalar* data_; }; } // namespace griddly \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index d37ad1189..e7b0f366d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ author = 'Chris Bamford' # The full version, including alpha/beta/rc tags -release = '0.3.1' +release = '0.3.2' # -- General configuration --------------------------------------------------- diff --git a/python/benchmarks/BWDistantResources32x32.yaml b/python/benchmarks/BWDistantResources32x32.yaml deleted file mode 100644 index 76b50c0e5..000000000 --- a/python/benchmarks/BWDistantResources32x32.yaml +++ /dev/null @@ -1,133 +0,0 @@ -Version: "0.1" -Environment: - Name: BWDistantResources32x32 - Observers: - Sprite2D: - TileSize: 16 - BackgroundTile: oryx/oryx_tiny_galaxy/tg_sliced/tg_world/tg_world_floor_panel_metal_a.png - Player: - Count: 2 - Termination: - Lose: - - eq: [base:count, 0] # If the player has no bases - Win: - - eq: [_score, 10] # First player to 10 reward points - Levels: - - | - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . M M M - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . M M - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . M - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . H1 . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . B1 . . . . . . . . . . . . . . . . W . . . . . . . . - . . . . . . . . . . . . . . . . . . . . . . . W W W W W . . . . - . . . . W W W W W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . B2 . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . H2 . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - M . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - M M . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . - M M M . . . . . W . . . . . . . . . . . . . . . . . . . . . . . -Actions: - - Name: gather - Behaviours: - - Src: - Object: harvester - Commands: - - incr: resources - - reward: 1 - Dst: - Object: minerals - Commands: - - decr: resources - - Src: - Object: harvester - Commands: - - decr: resources - - reward: 1 - Dst: - Object: base - Commands: - - incr: resources - - - Name: move - Behaviours: - - Src: - Object: [harvester] - Commands: - - mov: _dest # mov will move the object, _dest is the destination location of the action - Dst: - Object: _empty - -Objects: - - Name: minerals - MapCharacter: M - Variables: - - Name: resources - InitialValue: 10 - Observers: - Sprite2D: - - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_items/tg_items_crystal_green.png - Block2D: - - Shape: triangle - Color: [0.0, 1.0, 0.0] - Scale: 1.0 - - - Name: fixed_wall - MapCharacter: W - Observers: - Sprite2D: - - TilingMode: WALL_2 # Will tile walls with two images - Image: - - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img33.png - - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img40.png - Block2D: - - Color: [0.5, 0.5, 0.5] - Shape: square - - - Name: harvester - MapCharacter: H - Variables: - - Name: resources - InitialValue: 0 - - Name: health - InitialValue: 10 - Observers: - Sprite2D: - - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_jelly_d1.png - Block2D: - - Shape: square - Color: [0.6, 0.2, 0.2] - Scale: 0.5 - - - Name: base - MapCharacter: B - Variables: - - Name: resources - InitialValue: 0 - - Name: health - InitialValue: 10 - Observers: - Sprite2D: - - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img324.png - Block2D: - - Color: [0.8, 0.8, 0.3] - Shape: triangle \ No newline at end of file diff --git a/python/benchmarks/MicrortsMining.yaml b/python/benchmarks/MicrortsMining.yaml new file mode 100644 index 000000000..87940a5f6 --- /dev/null +++ b/python/benchmarks/MicrortsMining.yaml @@ -0,0 +1,131 @@ +Version: "0.1" +Environment: + Name: MicrortsMining + Observers: + Sprite2D: + TileSize: 24 + BackgroundTile: oryx/oryx_tiny_galaxy/tg_sliced/tg_world/tg_world_floor_panel_metal_a.png + Player: + Count: 2 + Termination: + Win: + - eq: [_score, 10] # First player to 10 reward points + Levels: + - | + . . . . . . . . . . . . . . . M + . . . . . . . . . . . . . . H2 M + . . . . . . . . . . . . . B2 . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . B1 . . . . . . . . . . . . . + M H1 . . . . . . . . . . . . . . + M . . . . . . . . . . . . . . . + + + + + + + + + + + + + + + + +Actions: + - Name: gather + Behaviours: + - Src: + Object: harvester + Commands: + - incr: resources + - reward: 1 + Dst: + Object: minerals + Commands: + - decr: resources + - Src: + Object: harvester + Commands: + - decr: resources + - reward: 1 + Dst: + Object: base + Commands: + - incr: resources + + - Name: move + Behaviours: + - Src: + Object: [harvester] + Commands: + - mov: _dest # mov will move the object, _dest is the destination location of the action + Dst: + Object: _empty + +Objects: + - Name: minerals + MapCharacter: M + Variables: + - Name: resources + InitialValue: 10 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_items/tg_items_crystal_green.png + Block2D: + - Shape: triangle + Color: [0.0, 1.0, 0.0] + Scale: 1.0 + + - Name: fixed_wall + MapCharacter: W + Observers: + Sprite2D: + - TilingMode: WALL_2 # Will tile walls with two images + Image: + - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img33.png + - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img40.png + Block2D: + - Color: [0.5, 0.5, 0.5] + Shape: square + + - Name: harvester + MapCharacter: H + Variables: + - Name: resources + InitialValue: 0 + - Name: health + InitialValue: 10 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_jelly_d1.png + Block2D: + - Shape: square + Color: [0.6, 0.2, 0.2] + Scale: 0.5 + + - Name: base + MapCharacter: B + Variables: + - Name: resources + InitialValue: 0 + - Name: health + InitialValue: 10 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img324.png + Block2D: + - Color: [0.8, 0.8, 0.3] + Shape: triangle \ No newline at end of file diff --git a/python/benchmarks/benchmark.py b/python/benchmarks/benchmark.py old mode 100644 new mode 100755 index 9c855ee4a..43e2545d5 --- a/python/benchmarks/benchmark.py +++ b/python/benchmarks/benchmark.py @@ -1,10 +1,14 @@ +#!/home/bam4d/anaconda3/envs/griddly/bin/python3 from timeit import default_timer as timer import numpy as np import gym import os import psutil +from gym import register + process = psutil.Process(os.getpid()) + def griddly(gdy_file): from griddly import GymWrapperFactory, gd @@ -13,36 +17,41 @@ def griddly(gdy_file): level=0) return gym.make(f'GDY-Griddly-v0') + def micro_rts_test(): import gym_microrts - return gym.make('BWDistantResources32x32-v0') + return gym.make('MicrortsMining-v4') + def minigrid_test(): import gym_minigrid return gym.make("MiniGrid-FourRooms-v0") + def gvgai_test(): import gvgai return gym.make("gvgai-sokoban-lvl0-v0") + def gvgai_test_old(): import gym_gvgai return gym_gvgai.make("gvgai-sokoban-lvl0-v0") + if __name__ == '__main__': #env = griddly('dmlab_pushbox.yaml') - #env = minigrid_test() - #env = griddly('Single-Player/Mini-Grid/minigrid-eyeball.yaml') + # env = minigrid_test() + # env = griddly('Single-Player/Mini-Grid/minigrid-eyeball.yaml') - #env = micro_rts_test() - env = griddly('BWDistantResources32x32.yaml') + # env = micro_rts_test() + # env = griddly('MicrortsMining.yaml') # memory usage recorded in these tests is inaccurate because the GVGAI environment is in a different process - #env = gvgai_test() - #env = gvgai_test_old() - #env = griddly('Single-Player/GVGAI/sokoban.yaml') + # env = gvgai_test() + # env = gvgai_test_old() + env = griddly('Single-Player/GVGAI/sokoban.yaml') env.reset() start = timer() @@ -57,8 +66,8 @@ def gvgai_test_old(): frames += 1 obs, reward, done, info = env.step(env.action_space.sample()) - #env.render() - #rendered_obs = env.render(mode='rgb_array') + # env.render() + # rendered_obs = env.render(mode='rgb_array') if frames % 1000 == 0: end = timer() @@ -70,5 +79,5 @@ def gvgai_test_old(): print(f'mem: {mem}') frames = 0 start = timer() - print(f'mean fps: {np.mean(fps_samples)}') - print(f'mean mem: {np.mean(mem_samples)}') \ No newline at end of file + print(f'mean fps: {np.mean(fps_samples)}, std: {np.std(fps_samples)}') + print(f'mean mem: {np.mean(mem_samples)}') diff --git a/python/benchmarks/dmlab_pushbox.yaml b/python/benchmarks/dmlab_pushbox.yaml index 4a8e5c095..f2d1d39bf 100644 --- a/python/benchmarks/dmlab_pushbox.yaml +++ b/python/benchmarks/dmlab_pushbox.yaml @@ -4,7 +4,7 @@ Environment: Description: Push the boxes onto the marked spaces, once a box has moved onto a space, it cannot be moved Observers: Sprite2D: - TileSize: 8 + TileSize: 24 BackgroundTile: gvgai/newset/floor2.png Player: AvatarObject: avatar # The player can only control a single avatar in the game @@ -12,43 +12,6 @@ Environment: Win: - eq: [ box:count, 0 ] # If there are no boxes left Levels: - - | - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w - w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w - w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w - w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w - w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w - w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w - w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w - w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w - w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w - w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w - w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w - w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w - w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w - w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w - w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w - w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w - w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - | w w w w w w w w w w w w w w . . . . . w @@ -59,7 +22,159 @@ Environment: w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w - + w w w w w w w w w w + - | + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + - | + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w Actions: # Define the move action diff --git a/python/examples/griddlyrts/play_griddlyrts_gym.py b/python/examples/griddlyrts/play_griddlyrts_gym.py index b743486fd..62a1f891f 100644 --- a/python/examples/griddlyrts/play_griddlyrts_gym.py +++ b/python/examples/griddlyrts/play_griddlyrts_gym.py @@ -10,10 +10,10 @@ wrapper = GymWrapperFactory() wrapper.build_gym_from_yaml("GriddlyRTS-Adv", - 'RTS/GriddlyRTS.yaml', - global_observer_type=gd.ObserverType.ISOMETRIC, + 'RTS/Stratega/kill-the-king.yaml', + global_observer_type=gd.ObserverType.SPRITE_2D, player_observer_type=gd.ObserverType.ISOMETRIC, - level=2) + level=0) env_original = gym.make(f'GDY-GriddlyRTS-Adv-v0') # env_original = gym.make(f'GDY-GriddlyRTS-Adv-v0') diff --git a/python/examples/gym/gym_human_player.py b/python/examples/gym/gym_human_player.py index 98ad5cac8..0588ab47a 100644 --- a/python/examples/gym/gym_human_player.py +++ b/python/examples/gym/gym_human_player.py @@ -34,16 +34,16 @@ def _callback(prev_obs, obs, action, rew, env_done, info): environment_name = 'TestEnv' # yaml_path = 'Single-Player/GVGAI/bait.yaml' - #yaml_path = 'Single-Player/GVGAI/butterflies.yaml' + # yaml_path = 'Single-Player/GVGAI/butterflies.yaml' # yaml_path = 'Single-Player/GVGAI/random_butterflies.yaml' # yaml_path = 'Single-Player/GVGAI/bait_keys.yaml' # yaml_path = 'Single-Player/Mini-Grid/minigrid-drunkdwarf.yaml' - # yaml_path = 'Single-Player/Mini-Grid/minigrid-spiders.yaml' + yaml_path = 'Single-Player/Mini-Grid/minigrid-spiders.yaml' # yaml_path = 'Single-Player/GVGAI/spider-nest.yaml' # yaml_path = 'Single-Player/GVGAI/cookmepasta.yaml' # yaml_path = 'Single-Player/GVGAI/clusters.yaml' # yaml_path = 'Single-Player/GVGAI/zenpuzzle.yaml' - yaml_path = 'Single-Player/GVGAI/sokoban.yaml' + # yaml_path = 'Single-Player/GVGAI/sokoban.yaml' # yaml_path = 'Single-Player/GVGAI/sokoban2.yaml' # yaml_path = 'Single-Player/GVGAI/sokoban2_partially_observable.yaml' # yaml_path = 'Single-Player/GVGAI/cookmepasta_partially_observable.yaml' @@ -58,8 +58,8 @@ def _callback(prev_obs, obs, action, rew, env_done, info): level = 0 wrapper.build_gym_from_yaml(environment_name, yaml_path, - player_observer_type=gd.ObserverType.SPRITE_2D, - global_observer_type=gd.ObserverType.SPRITE_2D, level=level) + player_observer_type=gd.ObserverType.VECTOR, + global_observer_type=gd.ObserverType.VECTOR, level=level) env = gym.make(f'GDY-{environment_name}-v0') # env.enable_history(True) env.reset() diff --git a/python/examples/snippet.py b/python/examples/snippet.py index e4c18ee0a..83bda594a 100644 --- a/python/examples/snippet.py +++ b/python/examples/snippet.py @@ -1,18 +1,76 @@ +from timeit import default_timer as timer +import numpy as np import gym -import griddly -from griddly import gd + +from griddly import GymWrapperFactory, gd +from griddly.RenderTools import VideoRecorder from griddly.util.wrappers import InvalidMaskingRTSWrapper if __name__ == '__main__': + wrapper = GymWrapperFactory() + + wrapper.build_gym_from_yaml("GriddlyRTS-Adv", + 'RTS/Stratega/kill-the-king.yaml', + global_observer_type=gd.ObserverType.VECTOR, + player_observer_type=gd.ObserverType.VECTOR, + level=0) + + env_original = gym.make(f'GDY-GriddlyRTS-Adv-v0') + # env_original = gym.make(f'GDY-GriddlyRTS-Adv-v0') + + env_original.reset() + + env = InvalidMaskingRTSWrapper(env_original) + + start = timer() + + frames = 0 + + fps_samples = [] + + player1_recorder = VideoRecorder() + player1_visualization = env.render(observer=0, mode='rgb_array') + player1_recorder.start("player1_video_test.mp4", player1_visualization.shape) + + player2_recorder = VideoRecorder() + player2_visualization = env.render(observer=1, mode='rgb_array') + player2_recorder.start("player2_video_test.mp4", player2_visualization.shape) + + global_recorder = VideoRecorder() + global_visualization = env.render(observer='global', mode='rgb_array') + global_recorder.start("global_video_test.mp4", global_visualization.shape) + + for s in range(10000): + + frames += 1 + + action = env.action_space.sample() + + obs, reward, done, info = env.step(action) + + global_observation = env.render(mode='rgb_array', observer='global') + player1_observation = env.render(observer=0, mode='rgb_array') + player2_observation = env.render(observer=1, mode='rgb_array') + + global_recorder.add_frame(global_observation) + player1_recorder.add_frame(player1_observation) + player2_recorder.add_frame(player2_observation) - env = gym.make('GDY-Heal-Or-Die-v0', level=1, global_observer_type=gd.ObserverType.ISOMETRIC) - env.reset() - env = InvalidMaskingRTSWrapper(env) + if done: + #state = env.get_state() + #print(state) + print(info) - # Replace with your own control algorithm! - for s in range(1000): - obs, reward, done, info = env.step(env.action_space.sample()) - for p in range(env.player_count): - env.render(observer=p) # Renders the environment from the perspective of a single player + if frames % 1000 == 0: + end = timer() + fps = (frames / (end - start)) + fps_samples.append(fps) + print(f'fps: {fps}') + frames = 0 + start = timer() - env.render(observer='global') # Renders the entire environment \ No newline at end of file + # Have to close the video recorders + player1_recorder.close() + player2_recorder.close() + global_recorder.close() + print(f'mean fps: {np.mean(fps_samples)}') diff --git a/python/examples/vectorized.py b/python/examples/vectorized.py new file mode 100644 index 000000000..036782273 --- /dev/null +++ b/python/examples/vectorized.py @@ -0,0 +1,23 @@ +from stable_baselines3.common.vec_env import SubprocVecEnv +import numpy as np +import gym +import griddly + +game = "GDY-Partially-Observable-Zelda-v0" + +def make_env(): + def _monad(): + env = gym.make(game) + return env + return _monad + +if __name__ == '__main__': + raw_list = [make_env() for _ in range(10)] + envs = SubprocVecEnv(raw_list) + + init_obs = envs.reset() + + for i in range(10000): + + envs.step(np.zeros((10,2))) + envs.render() \ No newline at end of file diff --git a/python/griddly/GymWrapper.py b/python/griddly/GymWrapper.py index 0a4a13e41..c910ec295 100644 --- a/python/griddly/GymWrapper.py +++ b/python/griddly/GymWrapper.py @@ -129,6 +129,8 @@ def step(self, action): f'A valid example: {self.action_space.sample()}') for p in range(self.player_count): + # Copy only if the environment is done (it will reset itself) + # This is because the underlying data will be released self._player_last_observation[p] = np.array(self._players[p].observe(), copy=False) obs = self._player_last_observation[0] if self.player_count == 1 else self._player_last_observation @@ -157,6 +159,7 @@ def reset(self, level_id=None, level_string=None, global_observations=False): return self._player_last_observation[0] if self.player_count == 1 else self._player_last_observation def initialize_spaces(self): + self._player_last_observation = [] for p in range(self.player_count): self._player_last_observation.append(np.array(self._players[p].observe(), copy=False)) diff --git a/python/setup.py b/python/setup.py index 560910dce..dababff2c 100644 --- a/python/setup.py +++ b/python/setup.py @@ -71,7 +71,7 @@ def griddly_package_data(config='Debug'): setup( name='griddly', - version="0.3.1", + version="0.3.2", author_email="chrisbam4d@gmail.com", description="Griddly Python Libraries", long_description=long_description, diff --git a/src/Griddly/Core/GDY/Actions/Direction.hpp b/src/Griddly/Core/GDY/Actions/Direction.hpp index 273b87ff0..345a2cb0f 100644 --- a/src/Griddly/Core/GDY/Actions/Direction.hpp +++ b/src/Griddly/Core/GDY/Actions/Direction.hpp @@ -82,6 +82,23 @@ class DiscreteOrientation { return unitVector_; } + std::string getName() { + switch (direction_) { + case Direction::NONE: + return "NONE"; + case Direction::UP: + return "UP"; + case Direction::RIGHT: + return "RIGHT"; + case Direction::DOWN: + return "DOWN"; + case Direction::LEFT: + return "LEFT"; + default: + return "NONE"; + } + } + // If the current direction is DOWN and the input vector is "right" we return "left" etc.. glm::ivec2 getRelativeUnitVector(glm::ivec2 vector) { return vector * getRotationMatrix(); diff --git a/src/Griddly/Core/GameProcess.cpp b/src/Griddly/Core/GameProcess.cpp index 26d8cf2c9..163b8d247 100644 --- a/src/Griddly/Core/GameProcess.cpp +++ b/src/Griddly/Core/GameProcess.cpp @@ -124,16 +124,9 @@ void GameProcess::init(bool isCloned) { isInitialized_ = true; } -std::shared_ptr GameProcess::resetObservers() { +uint8_t* GameProcess::resetObservers() { auto playerAvatarObjects = grid_->getPlayerAvatarObjects(); - std::shared_ptr observation; - if (observer_ != nullptr) { - observation = observer_->reset(); - } else { - observation = nullptr; - } - for (auto &p : players_) { p->reset(); if (playerAvatarObjects.size() > 0) { @@ -141,10 +134,14 @@ std::shared_ptr GameProcess::resetObservers() { } } - return observation; + if (observer_ == nullptr) { + return nullptr; + } + + return observer_->reset(); } -std::shared_ptr GameProcess::reset() { +uint8_t* GameProcess::reset() { if (!isInitialized_) { throw std::runtime_error("Cannot reset game process before initialization."); } @@ -195,10 +192,10 @@ uint32_t GameProcess::getNumPlayers() const { return players_.size(); } -std::shared_ptr GameProcess::observe() const { - if (observer_ == nullptr) { - return nullptr; - } +uint8_t* GameProcess::observe() const { + // if (observer_ == nullptr) { + // return nullptr; + // } return observer_->update(); } @@ -284,12 +281,13 @@ StateInfo GameProcess::getState() const { } } - for (auto object : grid_->getObjects()) { + for (auto& object : grid_->getObjects()) { ObjectInfo objectInfo; objectInfo.name = object->getObjectName(); objectInfo.location = object->getLocation(); objectInfo.playerId = object->getPlayerId(); + objectInfo.orientation = object->getObjectOrientation(); for (auto varIt : object->getAvailableVariables()) { if (globalVariables.find(varIt.first) == globalVariables.end()) { diff --git a/src/Griddly/Core/GameProcess.hpp b/src/Griddly/Core/GameProcess.hpp index 88495618c..fc347d95f 100644 --- a/src/Griddly/Core/GameProcess.hpp +++ b/src/Griddly/Core/GameProcess.hpp @@ -22,6 +22,7 @@ struct ObjectInfo { std::string name; std::unordered_map variables; glm::ivec2 location; + DiscreteOrientation orientation; uint8_t playerId; }; @@ -35,7 +36,7 @@ class GameProcess : public std::enable_shared_from_this { public: GameProcess(ObserverType globalObserverType, std::shared_ptr gdyFactory, std::shared_ptr grid); - virtual std::shared_ptr observe() const; + virtual uint8_t* observe() const; virtual ActionResult performActions(uint32_t playerId, std::vector> actions, bool updateTicks=true) = 0; @@ -49,7 +50,7 @@ class GameProcess : public std::enable_shared_from_this { virtual void init(bool isCloned=false); - virtual std::shared_ptr reset(); + virtual uint8_t* reset(); bool isInitialized(); @@ -91,7 +92,7 @@ class GameProcess : public std::enable_shared_from_this { bool isInitialized_ = false; private: - std::shared_ptr resetObservers(); + uint8_t* resetObservers(); ObserverConfig getObserverConfig(ObserverType observerType) const; }; } // namespace griddly \ No newline at end of file diff --git a/src/Griddly/Core/Observers/BlockObserver.cpp b/src/Griddly/Core/Observers/BlockObserver.cpp index e01d74aee..eb1704857 100644 --- a/src/Griddly/Core/Observers/BlockObserver.cpp +++ b/src/Griddly/Core/Observers/BlockObserver.cpp @@ -71,7 +71,7 @@ void BlockObserver::renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 obje glm::vec4 outlineColor; if (playerId == objectPlayerId) { - outlineColor = glm::vec4(0.0, 1.0, 0.0, 0.7); + outlineColor = glm::vec4(0.0, 1.0, 0.0, 1.0); } else { outlineColor = globalObserverPlayerColors_[objectPlayerId-1]; } diff --git a/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp b/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp index 501b24703..c0b3b7303 100644 --- a/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp +++ b/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp @@ -33,7 +33,7 @@ void IsometricSpriteObserver::resetShape() { isoOriginOffset_ = {gridHeight_ * tileSize.x / 2, tileSize.y / 2}; observationShape_ = {3, pixelWidth_, pixelHeight_}; - observationStrides_ = {1, 3, 3 * pixelWidth_}; + observationStrides_ = {1, 4, 4 * pixelWidth_}; } std::vector IsometricSpriteObserver::calculateDirtyRectangles(std::unordered_set updatedLocations) const { @@ -118,7 +118,7 @@ void IsometricSpriteObserver::renderLocation(vk::VulkanRenderContext& ctx, glm:: glm::vec4 outlineColor; if (playerId == objectPlayerId) { - outlineColor = glm::vec4(0.0, 1.0, 0.0, 0.7); + outlineColor = glm::vec4(0.0, 1.0, 0.0, 1.0); } else { outlineColor = globalObserverPlayerColors_[objectPlayerId - 1]; } @@ -158,7 +158,7 @@ void IsometricSpriteObserver::render(vk::VulkanRenderContext& ctx) const { auto tileSize = observerConfig_.tileSize; auto tileOffset = (glm::vec2)tileSize / 2.0f; - if (avatarObject_ != nullptr) { + if (avatarObject_ != nullptr) { VulkanGridObserver::render(ctx); } else { auto objy = observerConfig_.gridYOffset; diff --git a/src/Griddly/Core/Observers/Observer.hpp b/src/Griddly/Core/Observers/Observer.hpp index cf5d98403..c2107b921 100644 --- a/src/Griddly/Core/Observers/Observer.hpp +++ b/src/Griddly/Core/Observers/Observer.hpp @@ -40,8 +40,8 @@ class Observer { * The data is returned as a byte array for consistency across observers and * interfaces */ - virtual std::shared_ptr update() const = 0; - virtual std::shared_ptr reset() = 0; + virtual uint8_t* update() const = 0; + virtual uint8_t* reset() = 0; virtual std::vector getShape() const; virtual std::vector getStrides() const; diff --git a/src/Griddly/Core/Observers/SpriteObserver.cpp b/src/Griddly/Core/Observers/SpriteObserver.cpp index 56bf0a70e..d6ffdde12 100644 --- a/src/Griddly/Core/Observers/SpriteObserver.cpp +++ b/src/Griddly/Core/Observers/SpriteObserver.cpp @@ -207,7 +207,7 @@ void SpriteObserver::renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 obj glm::vec4 outlineColor; if (playerId == objectPlayerId) { - outlineColor = glm::vec4(0.0, 1.0, 0.0, 0.7); + outlineColor = glm::vec4(0.0, 1.0, 0.0, 1.0); } else { outlineColor = globalObserverPlayerColors_[objectPlayerId - 1]; } diff --git a/src/Griddly/Core/Observers/VectorObserver.cpp b/src/Griddly/Core/Observers/VectorObserver.cpp index 4b5059122..8bcd70756 100644 --- a/src/Griddly/Core/Observers/VectorObserver.cpp +++ b/src/Griddly/Core/Observers/VectorObserver.cpp @@ -37,12 +37,12 @@ void VectorObserver::resetShape() { observation_ = std::shared_ptr(new uint8_t[uniqueObjectCount * gridWidth_ * gridHeight_]{}); } -std::shared_ptr VectorObserver::reset() { +uint8_t* VectorObserver::reset() { resetShape(); return update(); }; -std::shared_ptr VectorObserver::update() const { +uint8_t* VectorObserver::update() const { auto uniqueObjectCount = grid_->getUniqueObjectCount(); if (avatarObject_ != nullptr) { @@ -50,6 +50,10 @@ std::shared_ptr VectorObserver::update() const { auto avatarOrientation = avatarObject_->getObjectOrientation(); auto avatarDirection = avatarOrientation.getDirection(); + // Have to reset the observation + auto size = sizeof(uint8_t) * uniqueObjectCount * gridWidth_ * gridHeight_; + memset(observation_.get(), 0, size); + if (observerConfig_.rotateWithAvatar) { // Assuming here that gridWidth and gridHeight are odd numbers auto pGrid = getAvatarObservableGrid(avatarLocation, avatarDirection); @@ -168,7 +172,7 @@ std::shared_ptr VectorObserver::update() const { grid_->purgeUpdatedLocations(observerConfig_.playerId); - return observation_; + return observation_.get(); } void VectorObserver::print(std::shared_ptr observation) { diff --git a/src/Griddly/Core/Observers/VectorObserver.hpp b/src/Griddly/Core/Observers/VectorObserver.hpp index 975b64568..1d1e2be63 100644 --- a/src/Griddly/Core/Observers/VectorObserver.hpp +++ b/src/Griddly/Core/Observers/VectorObserver.hpp @@ -10,8 +10,8 @@ class VectorObserver : public Observer { void init(ObserverConfig observerConfig) override; - std::shared_ptr update() const override; - std::shared_ptr reset() override; + uint8_t* update() const override; + uint8_t* reset() override; void resetShape() override; ObserverType getObserverType() const override; diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp index 86a2dda69..43a82b50d 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp @@ -160,7 +160,7 @@ void VulkanDevice::initRenderMode(RenderMode mode) { } } -void VulkanDevice::resetRenderSurface(uint32_t pixelWidth, uint32_t pixelHeight) { +std::vector VulkanDevice::resetRenderSurface(uint32_t pixelWidth, uint32_t pixelHeight) { freeRenderSurfaceMemory(); height_ = pixelHeight; @@ -177,7 +177,7 @@ void VulkanDevice::resetRenderSurface(uint32_t pixelWidth, uint32_t pixelHeight) createRenderPass(); spdlog::debug("Allocating offscreen host image data."); - allocateHostImageData(); + auto imageStrides = allocateHostImageData(); switch (renderMode_) { case SHAPES: @@ -187,6 +187,8 @@ void VulkanDevice::resetRenderSurface(uint32_t pixelWidth, uint32_t pixelHeight) spriteRenderPipeline_ = createSpriteRenderPipeline(); break; } + + return imageStrides; } VkCommandBuffer VulkanDevice::beginCommandBuffer() { @@ -385,20 +387,18 @@ void VulkanDevice::drawSprite(VulkanRenderContext& renderContext, uint32_t array vkCmdDrawIndexed(commandBuffer, spriteShapeBuffer_.indices, 1, 0, 0, 0); } -std::shared_ptr VulkanDevice::endRender(VulkanRenderContext& renderContext, std::vector dirtyRectangles = {}) { +uint8_t* VulkanDevice::endRender(VulkanRenderContext& renderContext, std::vector dirtyRectangles = {}) { isRendering_ = false; auto commandBuffer = renderContext.commandBuffer; vkCmdEndRenderPass(commandBuffer); - endCommandBuffer(commandBuffer); - - vkDeviceWaitIdle(device_); + copyImage(commandBuffer, colorAttachment_.image, renderedImage_, dirtyRectangles); - copySceneToHostImage(dirtyRectangles); + endCommandBuffer(commandBuffer); - return imageRGB_; + return imageRGBA_; } void VulkanDevice::copyBufferToImage(VkBuffer bufferSrc, VkImage imageDst, std::vector rects, uint32_t arrayLayer) { @@ -458,8 +458,8 @@ void VulkanDevice::copyBufferToImage(VkBuffer bufferSrc, VkImage imageDst, std:: endCommandBuffer(commandBuffer); } -void VulkanDevice::copyImage(VkImage imageSrc, VkImage imageDst, std::vector rects) { - VkCommandBuffer commandBuffer = beginCommandBuffer(); +void VulkanDevice::copyImage(VkCommandBuffer commandBuffer, VkImage imageSrc, VkImage imageDst, std::vector rects) { + //VkCommandBuffer commandBuffer = beginCommandBuffer(); auto numRects = rects.size(); @@ -515,43 +515,9 @@ void VulkanDevice::copyImage(VkImage imageSrc, VkImage imageDst, std::vector dirtyRectangles) { - copyImage(colorAttachment_.image, renderedImage_, dirtyRectangles); - - // Get layout of the image (including row pitch) - VkImageSubresource subResource{}; - subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - VkSubresourceLayout subResourceLayout; - - vkGetImageSubresourceLayout(device_, renderedImage_, &subResource, &subResourceLayout); - - uint8_t* imageRGBA = imageRGBA_ + subResourceLayout.offset; - - for (auto dirtyRect : dirtyRectangles) { - int bottom = dirtyRect.offset.y; - int top = bottom + dirtyRect.extent.height; - int left = dirtyRect.offset.x; - int right = left + dirtyRect.extent.width; - - for (int32_t y = bottom; y < top; y++) { - auto dest = (width_ * y + dirtyRect.offset.x) * 3; - auto src = subResourceLayout.rowPitch * y + dirtyRect.offset.x * 4; - for (int32_t x = left; x < right; x++) { - uint8_t* img = imageRGB_.get(); - img[dest] = imageRGBA[src]; - img[dest + 1] = imageRGBA[src + 1]; - img[dest + 2] = imageRGBA[src + 2]; - dest += 3; // RGB - src += 4; // RGBA - } - } - } } -void VulkanDevice::allocateHostImageData() { +std::vector VulkanDevice::allocateHostImageData() { // Create the linear tiled destination image to copy to and to read the memory from auto imageBuffer = createImage(width_, height_, 1, colorFormat_, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT); @@ -561,7 +527,18 @@ void VulkanDevice::allocateHostImageData() { // Map image memory so we can start copying from it vkMapMemory(device_, renderedImageMemory_, 0, VK_WHOLE_SIZE, 0, (void**)&imageRGBA_); - imageRGB_ = std::shared_ptr(new uint8_t[width_ * height_ * 3](), std::default_delete()); + // imageRGB_ = std::shared_ptr(new uint8_t[width_ * height_ * 4](), std::default_delete()); + + // Get layout of the image (including row pitch) + VkImageSubresource subResource{}; + subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + VkSubresourceLayout subResourceLayout; + + vkGetImageSubresourceLayout(device_, renderedImage_, &subResource, &subResourceLayout); + + imageRGBA_ += subResourceLayout.offset; + + return {1, 4, (uint32_t)subResourceLayout.rowPitch}; } void VulkanDevice::preloadSprites(std::unordered_map& spritesData) { diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp index 3b836947b..e0382ab2f 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp @@ -93,7 +93,7 @@ class VulkanDevice { void initDevice(bool useGpu); void initRenderMode(RenderMode mode); - void resetRenderSurface(uint32_t pixelWidth, uint32_t pixelHeight); + std::vector resetRenderSurface(uint32_t pixelWidth, uint32_t pixelHeight); // Load the sprites void preloadSprites(std::unordered_map& spritesData); @@ -109,7 +109,7 @@ class VulkanDevice { void drawSprite(VulkanRenderContext& renderContext, uint32_t arrayLayer, glm::mat4 model, glm::vec4 color, glm::vec4 outlineColor={0,0,0,0}); void drawBackgroundTiling(VulkanRenderContext& renderContext, uint32_t arrayLayer); - std::shared_ptr endRender(VulkanRenderContext& renderContext, std::vector dirtyRectangles); + uint8_t* endRender(VulkanRenderContext& renderContext, std::vector dirtyRectangles); private: std::vector getAvailablePhysicalDevices(); @@ -128,7 +128,7 @@ class VulkanDevice { VkSampler createTextureSampler(); ImageBuffer createImage(uint32_t width, uint32_t height, uint32_t arrayLayers, VkFormat& colorFormat, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties); - void copyImage(VkImage imageSrc, VkImage destSrc, std::vector rects); + void copyImage(VkCommandBuffer commandBuffer, VkImage imageSrc, VkImage destSrc, std::vector rects); void copyBufferToImage(VkBuffer bufferSrc, VkImage imageDst, std::vector rects, uint32_t arrayLayer); ShapeBuffer createSpriteShapeBuffer(); @@ -151,8 +151,7 @@ class VulkanDevice { VulkanPipeline createShapeRenderPipeline(); VulkanPipeline createSpriteRenderPipeline(); - void allocateHostImageData(); - void copySceneToHostImage(std::vector dirtyRectangles); + std::vector allocateHostImageData(); void submitCommands(VkCommandBuffer cmdBuffer); @@ -193,7 +192,7 @@ class VulkanDevice { VkImage renderedImage_ = VK_NULL_HANDLE; VkDeviceMemory renderedImageMemory_ = VK_NULL_HANDLE; uint8_t* imageRGBA_; - std::shared_ptr imageRGB_; + //std::shared_ptr imageRGB_; // Use 8 bit color VkFormat colorFormat_ = VK_FORMAT_R8G8B8A8_UNORM; @@ -201,6 +200,7 @@ class VulkanDevice { uint32_t height_; uint32_t width_; + glm::mat4 ortho_; const glm::ivec2 tileSize_; diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp index c55ce8ccf..daadf8be7 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp @@ -37,7 +37,7 @@ void VulkanObserver::init(ObserverConfig observerConfig) { resetShape(); } -std::shared_ptr VulkanObserver::reset() { +uint8_t* VulkanObserver::reset() { resetShape(); resetRenderSurface(); @@ -53,7 +53,7 @@ std::shared_ptr VulkanObserver::reset() { return device_->endRender(ctx, dirtyRectangles); } -std::shared_ptr VulkanObserver::update() const { +uint8_t* VulkanObserver::update() const { auto ctx = device_->beginRender(); render(ctx); @@ -78,7 +78,7 @@ std::shared_ptr VulkanObserver::update() const { void VulkanObserver::resetRenderSurface() { spdlog::debug("Initializing Render Surface. Grid width={0}, height={1}. Pixel width={2}. height={3}", gridWidth_, gridHeight_, pixelWidth_, pixelHeight_); - device_->resetRenderSurface(pixelWidth_, pixelHeight_); + observationStrides_ = device_->resetRenderSurface(pixelWidth_, pixelHeight_); } void VulkanObserver::release() { diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp index b076ef3df..ee62763e2 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp @@ -28,8 +28,8 @@ class VulkanObserver : public Observer { void print(std::shared_ptr observation) override; void init(ObserverConfig observerConfig) override; - virtual std::shared_ptr update() const override; - virtual std::shared_ptr reset() override; + virtual uint8_t* update() const override; + virtual uint8_t* reset() override; void release() override; diff --git a/src/Griddly/Core/Observers/VulkanGridObserver.cpp b/src/Griddly/Core/Observers/VulkanGridObserver.cpp index edc6139df..4b126daa1 100644 --- a/src/Griddly/Core/Observers/VulkanGridObserver.cpp +++ b/src/Griddly/Core/Observers/VulkanGridObserver.cpp @@ -28,7 +28,6 @@ void VulkanGridObserver::resetShape() { pixelHeight_ = gridHeight_ * tileSize.y; observationShape_ = {3, pixelWidth_, pixelHeight_}; - observationStrides_ = {1, 3, 3 * pixelWidth_}; } void VulkanGridObserver::init(ObserverConfig observerConfig) { @@ -62,28 +61,13 @@ std::vector VulkanGridObserver::calculateDirtyRectangles(std::unordere } VkOffset2D offset = { - std::max(0, (int32_t)location.x * tileSize.x - 2), - std::max(0, (int32_t)location.y * tileSize.y - 2)}; - - // Because we make the dirty rectangles slightly larger than the sprites, must check boundaries do not go beyond - // the render image surface - // Because we make the dirty rectangles slightly larger than the sprites, must check boundaries do not go beyond - // the render image surface - auto extentWidth = (uint32_t)tileSize.x + 4; - auto boundaryX = (int32_t)extentWidth + offset.x - (int32_t)pixelWidth_; - if (boundaryX > 0) { - extentWidth -= boundaryX; - } - - auto extentHeight = (uint32_t)tileSize.y + 4; - auto boundaryY = (int32_t)extentHeight + offset.y - (int32_t)pixelHeight_; - if (boundaryY > 0) { - extentHeight -= boundaryY; - } + std::max(0, (int32_t)location.x * tileSize.x), + std::max(0, (int32_t)location.y * tileSize.y)}; - VkExtent2D extent; - extent.width = extentWidth; - extent.height = extentHeight; + VkExtent2D extent = { + (uint32_t)tileSize.x, + (uint32_t)tileSize.y + }; dirtyRectangles.push_back({offset, extent}); } @@ -170,48 +154,19 @@ void VulkanGridObserver::render(vk::VulkanRenderContext& ctx) const { } } } else { - // in 2D RTS games have to render the objects around the rendered location so the highlighting works correctly - if (observerConfig_.playerCount > 1) { - auto& updatedLocations = grid_->getUpdatedLocations(observerConfig_.playerId); - - for (auto& location : updatedLocations) { - for (int i = -1; i < 2; i++) { - for (int j = -1; j < 2; j++) { - auto sublocation = glm::ivec2( - location.x + i, - location.y + j); - - if (sublocation.x >= observerConfig_.gridXOffset && - sublocation.x < gridWidth_ + observerConfig_.gridXOffset && - sublocation.y >= observerConfig_.gridYOffset && - sublocation.y < gridHeight_ + observerConfig_.gridYOffset) { - auto outputLocation = glm::ivec2( - sublocation.x - observerConfig_.gridXOffset, - sublocation.y - observerConfig_.gridYOffset); - - if (outputLocation.x < gridWidth_ && outputLocation.x >= 0 && outputLocation.y < gridHeight_ && outputLocation.y >= 0) { - renderLocation(ctx, sublocation, outputLocation, tileOffset, Direction::NONE); - } - } - } - } - } - - } else { - auto& updatedLocations = grid_->getUpdatedLocations(observerConfig_.playerId); - - for (auto& location : updatedLocations) { - if (location.x >= observerConfig_.gridXOffset && - location.x < gridWidth_ + observerConfig_.gridXOffset && - location.y >= observerConfig_.gridYOffset && - location.y < gridHeight_ + observerConfig_.gridYOffset) { - auto outputLocation = glm::ivec2( - location.x - observerConfig_.gridXOffset, - location.y - observerConfig_.gridYOffset); - - if (outputLocation.x < gridWidth_ && outputLocation.x >= 0 && outputLocation.y < gridHeight_ && outputLocation.y >= 0) { - renderLocation(ctx, location, outputLocation, tileOffset, Direction::NONE); - } + auto& updatedLocations = grid_->getUpdatedLocations(observerConfig_.playerId); + + for (auto& location : updatedLocations) { + if (location.x >= observerConfig_.gridXOffset && + location.x < gridWidth_ + observerConfig_.gridXOffset && + location.y >= observerConfig_.gridYOffset && + location.y < gridHeight_ + observerConfig_.gridYOffset) { + auto outputLocation = glm::ivec2( + location.x - observerConfig_.gridXOffset, + location.y - observerConfig_.gridYOffset); + + if (outputLocation.x < gridWidth_ && outputLocation.x >= 0 && outputLocation.y < gridHeight_ && outputLocation.y >= 0) { + renderLocation(ctx, location, outputLocation, tileOffset, Direction::NONE); } } } diff --git a/src/Griddly/Core/Players/Player.cpp b/src/Griddly/Core/Players/Player.cpp index ba36944fc..013fafbc0 100644 --- a/src/Griddly/Core/Players/Player.cpp +++ b/src/Griddly/Core/Players/Player.cpp @@ -75,10 +75,10 @@ ActionResult Player::performActions(std::vector> actions return actionResult; } -std::shared_ptr Player::observe() { - if (observer_ == nullptr) { - return nullptr; - } +uint8_t* Player::observe() { + // if (observer_ == nullptr) { + // return nullptr; + // } return observer_->update(); } diff --git a/src/Griddly/Core/Players/Player.hpp b/src/Griddly/Core/Players/Player.hpp index 61dcf691a..619b50631 100644 --- a/src/Griddly/Core/Players/Player.hpp +++ b/src/Griddly/Core/Players/Player.hpp @@ -32,7 +32,7 @@ class Player { virtual void init(ObserverConfig observerConfig, bool trackAvatar, std::shared_ptr gameProcess); virtual void reset(); - virtual std::shared_ptr observe(); + virtual uint8_t* observe(); virtual std::string getName() const; virtual uint32_t getId() const; diff --git a/tests/resources/observer/block/defaultObserverConfig.png b/tests/resources/observer/block/defaultObserverConfig.png index 6f473cfec..f0e2f6440 100644 Binary files a/tests/resources/observer/block/defaultObserverConfig.png and b/tests/resources/observer/block/defaultObserverConfig.png differ diff --git a/tests/resources/observer/block/defaultObserverConfig_trackAvatar.png b/tests/resources/observer/block/defaultObserverConfig_trackAvatar.png new file mode 100644 index 000000000..f0e2f6440 Binary files /dev/null and b/tests/resources/observer/block/defaultObserverConfig_trackAvatar.png differ diff --git a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png index 2b6fb0907..7c61955da 100644 Binary files a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png and b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png differ diff --git a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png index ea89e0289..6cca1aa5c 100644 Binary files a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png and b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png differ diff --git a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png new file mode 100644 index 000000000..f0e2f6440 Binary files /dev/null and b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png differ diff --git a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png index 0a5266ebd..82c72b6ca 100644 Binary files a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png and b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png differ diff --git a/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png new file mode 100644 index 000000000..f0e2f6440 Binary files /dev/null and b/tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png differ diff --git a/tests/resources/observer/block/multiPlayer_Outline_Global.png b/tests/resources/observer/block/multiPlayer_Outline_Global.png index 3766d734a..8d56e1bc9 100644 Binary files a/tests/resources/observer/block/multiPlayer_Outline_Global.png and b/tests/resources/observer/block/multiPlayer_Outline_Global.png differ diff --git a/tests/resources/observer/block/multiPlayer_Outline_Player1.png b/tests/resources/observer/block/multiPlayer_Outline_Player1.png index f421e643e..544a8bede 100644 Binary files a/tests/resources/observer/block/multiPlayer_Outline_Player1.png and b/tests/resources/observer/block/multiPlayer_Outline_Player1.png differ diff --git a/tests/resources/observer/block/multiPlayer_Outline_Player2.png b/tests/resources/observer/block/multiPlayer_Outline_Player2.png index 4d8a66305..84c8664d4 100644 Binary files a/tests/resources/observer/block/multiPlayer_Outline_Player2.png and b/tests/resources/observer/block/multiPlayer_Outline_Player2.png differ diff --git a/tests/resources/observer/block/multiPlayer_Outline_Player3.png b/tests/resources/observer/block/multiPlayer_Outline_Player3.png index 36be78c1a..1fade310e 100644 Binary files a/tests/resources/observer/block/multiPlayer_Outline_Player3.png and b/tests/resources/observer/block/multiPlayer_Outline_Player3.png differ diff --git a/tests/resources/observer/block/partialObserver.png b/tests/resources/observer/block/partialObserver.png index 43d763935..5d4905eb6 100644 Binary files a/tests/resources/observer/block/partialObserver.png and b/tests/resources/observer/block/partialObserver.png differ diff --git a/tests/resources/observer/block/partialObserver_trackAvatar.png b/tests/resources/observer/block/partialObserver_trackAvatar.png deleted file mode 100644 index eb21fb26c..000000000 Binary files a/tests/resources/observer/block/partialObserver_trackAvatar.png and /dev/null differ diff --git a/tests/resources/observer/block/partialObserver_trackAvatar_DOWN.png b/tests/resources/observer/block/partialObserver_trackAvatar_DOWN.png index 9b0be9458..a8aa341da 100644 Binary files a/tests/resources/observer/block/partialObserver_trackAvatar_DOWN.png and b/tests/resources/observer/block/partialObserver_trackAvatar_DOWN.png differ diff --git a/tests/resources/observer/block/partialObserver_trackAvatar_LEFT.png b/tests/resources/observer/block/partialObserver_trackAvatar_LEFT.png index 2c1ce163f..66ff9e76f 100644 Binary files a/tests/resources/observer/block/partialObserver_trackAvatar_LEFT.png and b/tests/resources/observer/block/partialObserver_trackAvatar_LEFT.png differ diff --git a/tests/resources/observer/block/partialObserver_trackAvatar_NONE.png b/tests/resources/observer/block/partialObserver_trackAvatar_NONE.png new file mode 100644 index 000000000..c54b73c04 Binary files /dev/null and b/tests/resources/observer/block/partialObserver_trackAvatar_NONE.png differ diff --git a/tests/resources/observer/block/partialObserver_trackAvatar_RIGHT.png b/tests/resources/observer/block/partialObserver_trackAvatar_RIGHT.png index 310721a52..497e51813 100644 Binary files a/tests/resources/observer/block/partialObserver_trackAvatar_RIGHT.png and b/tests/resources/observer/block/partialObserver_trackAvatar_RIGHT.png differ diff --git a/tests/resources/observer/block/partialObserver_trackAvatar_UP.png b/tests/resources/observer/block/partialObserver_trackAvatar_UP.png new file mode 100644 index 000000000..c54b73c04 Binary files /dev/null and b/tests/resources/observer/block/partialObserver_trackAvatar_UP.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset.png b/tests/resources/observer/block/partialObserver_withOffset.png index eb21fb26c..c54b73c04 100644 Binary files a/tests/resources/observer/block/partialObserver_withOffset.png and b/tests/resources/observer/block/partialObserver_withOffset.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar.png deleted file mode 100644 index 43d763935..000000000 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar.png and /dev/null differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_DOWN.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_DOWN.png index 928b8fb2d..d2446c88f 100644 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_DOWN.png and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_DOWN.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_LEFT.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_LEFT.png index 6fd93eff6..383889896 100644 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_LEFT.png and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_LEFT.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_NONE.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_NONE.png new file mode 100644 index 000000000..5d4905eb6 Binary files /dev/null and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_NONE.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_RIGHT.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_RIGHT.png index 33b11addf..cfd087e94 100644 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_RIGHT.png and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_RIGHT.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_UP.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_UP.png new file mode 100644 index 000000000..5d4905eb6 Binary files /dev/null and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_UP.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar.png deleted file mode 100644 index 43d763935..000000000 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar.png and /dev/null differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png index b45c6062f..c3a0425dd 100644 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png index e320e506e..5d1753f69 100644 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png new file mode 100644 index 000000000..5d4905eb6 Binary files /dev/null and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png index 6022a727a..63b8552d0 100644 Binary files a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png differ diff --git a/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png new file mode 100644 index 000000000..5d4905eb6 Binary files /dev/null and b/tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png differ diff --git a/tests/resources/observer/isometric/multiPlayer_Outline_Global.png b/tests/resources/observer/isometric/multiPlayer_Outline_Global.png index 705eaa961..69a2bbe3c 100644 Binary files a/tests/resources/observer/isometric/multiPlayer_Outline_Global.png and b/tests/resources/observer/isometric/multiPlayer_Outline_Global.png differ diff --git a/tests/resources/observer/isometric/multiPlayer_Outline_Player1.png b/tests/resources/observer/isometric/multiPlayer_Outline_Player1.png index 589051be0..730607b58 100644 Binary files a/tests/resources/observer/isometric/multiPlayer_Outline_Player1.png and b/tests/resources/observer/isometric/multiPlayer_Outline_Player1.png differ diff --git a/tests/resources/observer/isometric/multiPlayer_Outline_Player2.png b/tests/resources/observer/isometric/multiPlayer_Outline_Player2.png index 9f8cf720d..571e969cc 100644 Binary files a/tests/resources/observer/isometric/multiPlayer_Outline_Player2.png and b/tests/resources/observer/isometric/multiPlayer_Outline_Player2.png differ diff --git a/tests/resources/observer/isometric/multiPlayer_Outline_Player3.png b/tests/resources/observer/isometric/multiPlayer_Outline_Player3.png index 64cf1a4c2..686599bf1 100644 Binary files a/tests/resources/observer/isometric/multiPlayer_Outline_Player3.png and b/tests/resources/observer/isometric/multiPlayer_Outline_Player3.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Global.png b/tests/resources/observer/sprite/multiPlayer_Outline_Global.png index ee537f4bc..788c9635e 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Global.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Global.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png b/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png index 32299f64b..96feb7bc3 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png b/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png index 484b40f16..112d83b19 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png b/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png index 94e26d0e5..1b7eadcbd 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png differ diff --git a/tests/src/Griddly/Core/GameProcessTest.cpp b/tests/src/Griddly/Core/GameProcessTest.cpp index 80f0e0c90..6492bb38c 100644 --- a/tests/src/Griddly/Core/GameProcessTest.cpp +++ b/tests/src/Griddly/Core/GameProcessTest.cpp @@ -386,7 +386,7 @@ TEST(GameProcessTest, reset) { EXPECT_CALL(*mockObserverPtr, getObserverType()) .WillRepeatedly(Return(ObserverType::VECTOR)); - auto mockObservationPtr = std::shared_ptr(new uint8_t[3]{0, 1, 2}); + auto mockObservationPtr = new uint8_t[3]{0, 1, 2}; EXPECT_CALL(*mockObserverPtr, reset()) .WillOnce(Return(mockObservationPtr)); @@ -410,9 +410,9 @@ TEST(GameProcessTest, reset) { auto observation = gameProcessPtr->reset(); - auto resetObservationPointer = std::vector(observation.get(), observation.get() + 3); + auto resetObservationPointer = std::vector(observation, observation + 3); - ASSERT_THAT(resetObservationPointer, ElementsAreArray(mockObservationPtr.get(), 3)); + ASSERT_THAT(resetObservationPointer, ElementsAreArray(mockObservationPtr, 3)); ASSERT_EQ(gameProcessPtr->getNumPlayers(), 1); ASSERT_TRUE(gameProcessPtr->isInitialized()); diff --git a/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp b/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp index 8a920552c..504a23abf 100644 --- a/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp @@ -125,7 +125,7 @@ void runBlockObserverTest(ObserverConfig observerConfig, Direction avatarDirection, std::vector expectedObservationShape, std::vector expectedObservationStride, - std::string filenameExpectedOutputFilename, + std::string expectedOutputFilename, bool trackAvatar, bool writeOutputFile = false) { @@ -145,24 +145,22 @@ void runBlockObserverTest(ObserverConfig observerConfig, ASSERT_EQ(blockObserver->getTileSize(), glm::ivec2(20, 20)); ASSERT_EQ(blockObserver->getShape(), expectedObservationShape); - ASSERT_EQ(blockObserver->getStrides(), expectedObservationStride); + ASSERT_EQ(blockObserver->getStrides()[0], expectedObservationStride[0]); + ASSERT_EQ(blockObserver->getStrides()[1], expectedObservationStride[1]); auto updateObservation = blockObserver->update(); if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation.get(), blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); + write_image(testName + ".png", resetObservation, blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); } - size_t dataLength = blockObserver->getShape()[0] * blockObserver->getShape()[1] * blockObserver->getShape()[2]; + size_t dataLength = 4 * blockObserver->getShape()[1] * blockObserver->getShape()[2]; - auto expectedImageData = loadExpectedImage(filenameExpectedOutputFilename); - - auto resetObservationPointer = std::vector(resetObservation.get(), resetObservation.get() + dataLength); - auto updateObservationPointer = std::vector(updateObservation.get(), updateObservation.get() + dataLength); + auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), resetObservation)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); } @@ -186,24 +184,22 @@ void runBlockObserverRTSTest(ObserverConfig observerConfig, auto resetObservation = blockObserver->reset(); ASSERT_EQ(blockObserver->getShape(), expectedObservationShape); - ASSERT_EQ(blockObserver->getStrides(), expectedObservationStride); + ASSERT_EQ(blockObserver->getStrides()[0], expectedObservationStride[0]); + ASSERT_EQ(blockObserver->getStrides()[1], expectedObservationStride[1]); auto updateObservation = blockObserver->update(); if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation.get(), blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); + write_image(testName + ".png", resetObservation, blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); } - size_t dataLength = blockObserver->getShape()[0] * blockObserver->getShape()[1] * blockObserver->getShape()[2]; + size_t dataLength = 4 * blockObserver->getShape()[1] * blockObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - auto resetObservationPointer = std::vector(resetObservation.get(), resetObservation.get() + dataLength); - auto updateObservationPointer = std::vector(updateObservation.get(), updateObservation.get() + dataLength); - - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), resetObservation)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); } @@ -216,7 +212,7 @@ TEST(BlockObserverTest, defaultObserverConfig) { 0, false}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 100}, {1, 3, 3 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", false); + runBlockObserverTest(config, Direction::NONE, {3, 100, 100}, {1, 4, 4 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", false); } TEST(BlockObserverTest, defaultObserverConfig_trackAvatar) { @@ -226,7 +222,7 @@ TEST(BlockObserverTest, defaultObserverConfig_trackAvatar) { 0, 0, false}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 100}, {1, 3, 3 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", true); + runBlockObserverTest(config, Direction::NONE, {3, 100, 100}, {1, 4, 4 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", true); } TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE) { @@ -237,7 +233,7 @@ TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE) 0, true}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 100}, {1, 3, 3 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", true); + runBlockObserverTest(config, Direction::NONE, {3, 100, 100}, {1, 4, 4 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", true); } TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_UP) { @@ -248,7 +244,7 @@ TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_UP) { 0, true}; - runBlockObserverTest(config, Direction::UP, {3, 100, 100}, {1, 3, 3 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", true); + runBlockObserverTest(config, Direction::UP, {3, 100, 100}, {1, 4, 4 * 100}, "tests/resources/observer/block/defaultObserverConfig.png", true); } TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT) { @@ -259,7 +255,7 @@ TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT 0, true}; - runBlockObserverTest(config, Direction::RIGHT, {3, 100, 100}, {1, 3, 3 * 100}, "tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png", true); + runBlockObserverTest(config, Direction::RIGHT, {3, 100, 100}, {1, 4, 4 * 100}, "tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png", true); } TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN) { @@ -270,7 +266,7 @@ TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN) 0, true}; - runBlockObserverTest(config, Direction::DOWN, {3, 100, 100}, {1, 3, 3 * 100}, "tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png", true); + runBlockObserverTest(config, Direction::DOWN, {3, 100, 100}, {1, 4, 4 * 100}, "tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png", true); } TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT) { @@ -281,7 +277,7 @@ TEST(BlockObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT) 0, true}; - runBlockObserverTest(config, Direction::LEFT, {3, 100, 100}, {1, 3, 3 * 100}, "tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png", true); + runBlockObserverTest(config, Direction::LEFT, {3, 100, 100}, {1, 4, 4 * 100}, "tests/resources/observer/block/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png", true); } TEST(BlockObserverTest, partialObserver) { @@ -292,7 +288,7 @@ TEST(BlockObserverTest, partialObserver) { 0, false}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver.png", false); + runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver.png", false); } TEST(BlockObserverTest, partialObserver_withOffset) { @@ -303,7 +299,7 @@ TEST(BlockObserverTest, partialObserver_withOffset) { 1, false}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset.png", false); + runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset.png", false); } TEST(BlockObserverTest, partialObserver_trackAvatar_NONE) { @@ -314,7 +310,7 @@ TEST(BlockObserverTest, partialObserver_trackAvatar_NONE) { 0, false}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar.png", true); + runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_NONE.png", true); } TEST(BlockObserverTest, partialObserver_trackAvatar_UP) { @@ -325,7 +321,7 @@ TEST(BlockObserverTest, partialObserver_trackAvatar_UP) { 0, false}; - runBlockObserverTest(config, Direction::UP, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar.png", true); + runBlockObserverTest(config, Direction::UP, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_UP.png", true); } TEST(BlockObserverTest, partialObserver_trackAvatar_RIGHT) { @@ -336,7 +332,7 @@ TEST(BlockObserverTest, partialObserver_trackAvatar_RIGHT) { 0, false}; - runBlockObserverTest(config, Direction::RIGHT, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_RIGHT.png", true); + runBlockObserverTest(config, Direction::RIGHT, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_RIGHT.png", true); } TEST(BlockObserverTest, partialObserver_trackAvatar_DOWN) { @@ -347,7 +343,7 @@ TEST(BlockObserverTest, partialObserver_trackAvatar_DOWN) { 0, false}; - runBlockObserverTest(config, Direction::DOWN, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_DOWN.png", true); + runBlockObserverTest(config, Direction::DOWN, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_DOWN.png", true); } TEST(BlockObserverTest, partialObserver_trackAvatar_LEFT) { @@ -358,7 +354,7 @@ TEST(BlockObserverTest, partialObserver_trackAvatar_LEFT) { 0, false}; - runBlockObserverTest(config, Direction::LEFT, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_LEFT.png", true); + runBlockObserverTest(config, Direction::LEFT, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_trackAvatar_LEFT.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_NONE) { @@ -369,7 +365,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_NONE) { 1, false}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar.png", true); + runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_NONE.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_UP) { @@ -380,7 +376,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_UP) { 1, false}; - runBlockObserverTest(config, Direction::UP, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar.png", true); + runBlockObserverTest(config, Direction::UP, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_UP.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_RIGHT) { @@ -391,7 +387,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_RIGHT) { 1, false}; - runBlockObserverTest(config, Direction::RIGHT, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_RIGHT.png", true); + runBlockObserverTest(config, Direction::RIGHT, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_RIGHT.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_DOWN) { @@ -402,7 +398,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_DOWN) { 1, false}; - runBlockObserverTest(config, Direction::DOWN, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_DOWN.png", true); + runBlockObserverTest(config, Direction::DOWN, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_DOWN.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_LEFT) { @@ -413,7 +409,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_LEFT) { 1, false}; - runBlockObserverTest(config, Direction::LEFT, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_LEFT.png", true); + runBlockObserverTest(config, Direction::LEFT, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_LEFT.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE) { @@ -424,7 +420,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_ 1, true}; - runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar.png", true); + runBlockObserverTest(config, Direction::NONE, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP) { @@ -435,7 +431,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_ 1, true}; - runBlockObserverTest(config, Direction::UP, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar.png", true); + runBlockObserverTest(config, Direction::UP, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT) { @@ -446,7 +442,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_ 1, true}; - runBlockObserverTest(config, Direction::RIGHT, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png", true); + runBlockObserverTest(config, Direction::RIGHT, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN) { @@ -457,7 +453,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_ 1, true}; - runBlockObserverTest(config, Direction::DOWN, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png", true); + runBlockObserverTest(config, Direction::DOWN, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png", true); } TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT) { @@ -468,7 +464,7 @@ TEST(BlockObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_ 1, true}; - runBlockObserverTest(config, Direction::LEFT, {3, 100, 60}, {1, 3, 3 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png", true); + runBlockObserverTest(config, Direction::LEFT, {3, 100, 60}, {1, 4, 4 * 100}, "tests/resources/observer/block/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png", true); } TEST(BlockObserverTest, multiPlayer_Outline_Player1) { @@ -476,7 +472,7 @@ TEST(BlockObserverTest, multiPlayer_Outline_Player1) { config.playerId = 1; config.playerCount = 3; - runBlockObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Player1.png"); + runBlockObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Player1.png"); } TEST(BlockObserverTest, multiPlayer_Outline_Player2) { @@ -484,7 +480,7 @@ TEST(BlockObserverTest, multiPlayer_Outline_Player2) { config.playerId = 2; config.playerCount = 3; - runBlockObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Player2.png"); + runBlockObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Player2.png"); } TEST(BlockObserverTest, multiPlayer_Outline_Player3) { @@ -492,7 +488,7 @@ TEST(BlockObserverTest, multiPlayer_Outline_Player3) { config.playerId = 3; config.playerCount = 3; - runBlockObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Player3.png"); + runBlockObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Player3.png"); } TEST(BlockObserverTest, multiPlayer_Outline_Global) { @@ -500,7 +496,7 @@ TEST(BlockObserverTest, multiPlayer_Outline_Global) { config.playerId = 0; config.playerCount = 3; - runBlockObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Global.png"); + runBlockObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/block/multiPlayer_Outline_Global.png"); } } // namespace griddly \ No newline at end of file diff --git a/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp b/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp index 4485f562f..63c7e57b2 100644 --- a/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp @@ -87,24 +87,22 @@ void runIsometricSpriteObserverRTSTest(ObserverConfig observerConfig, ASSERT_EQ(isometricObserver->getTileSize(), glm::ivec2(32, 48)); ASSERT_EQ(isometricObserver->getShape(), expectedObservationShape); - ASSERT_EQ(isometricObserver->getStrides(), expectedObservationStride); + ASSERT_EQ(isometricObserver->getStrides()[0], expectedObservationStride[0]); + ASSERT_EQ(isometricObserver->getStrides()[1], expectedObservationStride[1]); auto updateObservation = isometricObserver->update(); if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation.get(), isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); + write_image(testName + ".png", resetObservation, isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); } - size_t dataLength = isometricObserver->getShape()[0] * isometricObserver->getShape()[1] * isometricObserver->getShape()[2]; + size_t dataLength = 4 * isometricObserver->getShape()[1] * isometricObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - auto resetObservationPointer = std::vector(resetObservation.get(), resetObservation.get() + dataLength); - auto updateObservationPointer = std::vector(updateObservation.get(), updateObservation.get() + dataLength); - - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), resetObservation)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); } @@ -159,7 +157,7 @@ void runIsometricSpriteObserverTest(ObserverConfig observerConfig, Direction avatarDirection, std::vector expectedObservationShape, std::vector expectedObservationStride, - std::string filenameExpectedOutputFilename, + std::string expectedOutputFilename, bool trackAvatar, bool writeOutputFile = false) { ResourceConfig resourceConfig = {"resources/images", "resources/shaders"}; @@ -180,23 +178,22 @@ void runIsometricSpriteObserverTest(ObserverConfig observerConfig, auto resetObservation = isometricObserver->reset(); ASSERT_EQ(isometricObserver->getShape(), expectedObservationShape); - ASSERT_EQ(isometricObserver->getStrides(), expectedObservationStride); + ASSERT_EQ(isometricObserver->getStrides()[0], expectedObservationStride[0]); + ASSERT_EQ(isometricObserver->getStrides()[1], expectedObservationStride[1]); + auto updateObservation = isometricObserver->update(); if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation.get(), isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); + write_image(testName + ".png", resetObservation, isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); } - size_t dataLength = isometricObserver->getShape()[0] * isometricObserver->getShape()[1] * isometricObserver->getShape()[2]; + size_t dataLength = 4 * isometricObserver->getShape()[1] * isometricObserver->getShape()[2]; - auto expectedImageData = loadExpectedImage(filenameExpectedOutputFilename); - - auto resetObservationPointer = std::vector(resetObservation.get(), resetObservation.get() + dataLength); - auto updateObservationPointer = std::vector(updateObservation.get(), updateObservation.get() + dataLength); + auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), resetObservation)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); } @@ -209,7 +206,7 @@ TEST(IsometricSpriteObserverTest, defaultObserverConfig) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/defaultObserverConfig.png", false); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/defaultObserverConfig.png", false); } TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar) { @@ -220,7 +217,7 @@ TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/defaultObserverConfig.png", true); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/defaultObserverConfig.png", true); } TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE) { @@ -231,7 +228,7 @@ TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAv 0, true}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png", true); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png", true); } TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_UP) { @@ -242,7 +239,7 @@ TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAv 0, true}; - runIsometricSpriteObserverTest(config, Direction::UP, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png", true); + runIsometricSpriteObserverTest(config, Direction::UP, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png", true); } TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT) { @@ -253,7 +250,7 @@ TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAv 0, true}; - runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png", true); + runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png", true); } TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN) { @@ -264,7 +261,7 @@ TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAv 0, true}; - runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png", true); + runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png", true); } TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT) { @@ -275,7 +272,7 @@ TEST(IsometricSpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAv 0, true}; - runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png", true); + runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png", true); } TEST(IsometricSpriteObserverTest, partialObserver) { @@ -286,7 +283,7 @@ TEST(IsometricSpriteObserverTest, partialObserver) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver.png", false); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver.png", false); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset) { @@ -297,7 +294,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset) { 1, false}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset.png", false); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset.png", false); } TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_NONE) { @@ -308,7 +305,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_NONE) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_NONE.png", true); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_NONE.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_UP) { @@ -319,7 +316,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_UP) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::UP, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_UP.png", true); + runIsometricSpriteObserverTest(config, Direction::UP, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_UP.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_RIGHT) { @@ -330,7 +327,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_RIGHT) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_RIGHT.png", true); + runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_RIGHT.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_DOWN) { @@ -341,7 +338,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_DOWN) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_DOWN.png", true); + runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_DOWN.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_LEFT) { @@ -352,7 +349,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_trackAvatar_LEFT) { 0, false}; - runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_LEFT.png", true); + runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_trackAvatar_LEFT.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_NONE) { @@ -363,7 +360,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_NONE) { 1, false}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_NONE.png", true); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_NONE.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_UP) { @@ -374,7 +371,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_UP) { 1, false}; - runIsometricSpriteObserverTest(config, Direction::UP, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_UP.png", true); + runIsometricSpriteObserverTest(config, Direction::UP, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_UP.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_RIGHT) { @@ -385,7 +382,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_RIGHT) 1, false}; - runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_RIGHT.png", true); + runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_RIGHT.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_DOWN) { @@ -396,7 +393,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_DOWN) { 1, false}; - runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_DOWN.png", true); + runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_DOWN.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_LEFT) { @@ -407,7 +404,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_LEFT) { 1, false}; - runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_LEFT.png", true); + runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_LEFT.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE) { @@ -418,7 +415,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateW 1, true}; - runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png", true); + runIsometricSpriteObserverTest(config, Direction::NONE, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP) { @@ -429,7 +426,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateW 1, true}; - runIsometricSpriteObserverTest(config, Direction::UP, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png", true); + runIsometricSpriteObserverTest(config, Direction::UP, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT) { @@ -440,7 +437,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateW 1, true}; - runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png", true); + runIsometricSpriteObserverTest(config, Direction::RIGHT, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN) { @@ -451,7 +448,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateW 1, true}; - runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png", true); + runIsometricSpriteObserverTest(config, Direction::DOWN, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png", true); } TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT) { @@ -462,7 +459,7 @@ TEST(IsometricSpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateW 1, true}; - runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 128, 116}, {1, 3, 3 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png", true); + runIsometricSpriteObserverTest(config, Direction::LEFT, {3, 128, 116}, {1, 4, 4 * 128}, "tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png", true); } TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Player1) { @@ -470,7 +467,7 @@ TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Player1) { config.playerId = 1; config.playerCount = 3; - runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Player1.png"); + runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Player1.png"); } TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Player2) { @@ -478,7 +475,7 @@ TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Player2) { config.playerId = 2; config.playerCount = 3; - runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Player2.png"); + runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Player2.png"); } TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Player3) { @@ -486,7 +483,7 @@ TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Player3) { config.playerId = 3; config.playerCount = 3; - runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Player3.png"); + runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Player3.png"); } TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Global) { @@ -494,7 +491,7 @@ TEST(IsometricSpriteObserverTest, multiPlayer_Outline_Global) { config.playerId = 0; config.playerCount = 3; - runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 3, 3 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Global.png"); + runIsometricSpriteObserverRTSTest(config, {3, 160, 132}, {1, 4, 4 * 160}, "tests/resources/observer/isometric/multiPlayer_Outline_Global.png"); } } // namespace griddly \ No newline at end of file diff --git a/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp b/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp index 3874befc9..5d64d2a32 100644 --- a/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp @@ -98,24 +98,22 @@ void runSpriteObserverRTSTest(ObserverConfig observerConfig, ASSERT_EQ(spriteObserver->getTileSize(), glm::ivec2(50, 50)); ASSERT_EQ(spriteObserver->getShape(), expectedObservationShape); - ASSERT_EQ(spriteObserver->getStrides(), expectedObservationStride); + ASSERT_EQ(spriteObserver->getStrides()[0], expectedObservationStride[0]); + ASSERT_EQ(spriteObserver->getStrides()[1], expectedObservationStride[1]); auto updateObservation = spriteObserver->update(); if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation.get(), spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); + write_image(testName + ".png", resetObservation, spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); } - size_t dataLength = spriteObserver->getShape()[0] * spriteObserver->getShape()[1] * spriteObserver->getShape()[2]; + size_t dataLength = 4 * spriteObserver->getShape()[1] * spriteObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - auto resetObservationPointer = std::vector(resetObservation.get(), resetObservation.get() + dataLength); - auto updateObservationPointer = std::vector(updateObservation.get(), updateObservation.get() + dataLength); - - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), resetObservation)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); } @@ -184,7 +182,7 @@ void runSpriteObserverTest(ObserverConfig observerConfig, Direction avatarDirection, std::vector expectedObservationShape, std::vector expectedObservationStride, - std::string filenameExpectedOutputFilename, + std::string expectedOutputFilename, bool trackAvatar, bool writeOutputFile = false) { ResourceConfig resourceConfig = {"resources/images", "resources/shaders"}; @@ -202,23 +200,22 @@ void runSpriteObserverTest(ObserverConfig observerConfig, auto resetObservation = spriteObserver->reset(); ASSERT_EQ(spriteObserver->getShape(), expectedObservationShape); - ASSERT_EQ(spriteObserver->getStrides(), expectedObservationStride); + ASSERT_EQ(spriteObserver->getStrides()[0], expectedObservationStride[0]); + ASSERT_EQ(spriteObserver->getStrides()[1], expectedObservationStride[1]); + auto updateObservation = spriteObserver->update(); if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation.get(), spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); + write_image(testName + ".png", resetObservation, spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); } - size_t dataLength = spriteObserver->getShape()[0] * spriteObserver->getShape()[1] * spriteObserver->getShape()[2]; + size_t dataLength = 4 * spriteObserver->getShape()[1] * spriteObserver->getShape()[2]; - auto expectedImageData = loadExpectedImage(filenameExpectedOutputFilename); - - auto resetObservationPointer = std::vector(resetObservation.get(), resetObservation.get() + dataLength); - auto updateObservationPointer = std::vector(updateObservation.get(), updateObservation.get() + dataLength); + auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), resetObservation)); + ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); } @@ -231,7 +228,7 @@ TEST(SpriteObserverTest, defaultObserverConfig) { 0, false}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 120}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/defaultObserverConfig.png", false); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 120}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/defaultObserverConfig.png", false); } TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar) { @@ -241,7 +238,7 @@ TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar) { 0, 0, false}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 120}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/defaultObserverConfig.png", true); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 120}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/defaultObserverConfig.png", true); } TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE) { @@ -252,7 +249,7 @@ TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE 0, true}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 120}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png", true); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 120}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png", true); } TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_UP) { @@ -263,7 +260,7 @@ TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_UP) 0, true}; - runSpriteObserverTest(config, Direction::UP, {3, 120, 120}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png", true); + runSpriteObserverTest(config, Direction::UP, {3, 120, 120}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png", true); } TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT) { @@ -274,7 +271,7 @@ TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGH 0, true}; - runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 120}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png", true); + runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 120}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png", true); } TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN) { @@ -285,7 +282,7 @@ TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN 0, true}; - runSpriteObserverTest(config, Direction::DOWN, {3, 120, 120}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png", true); + runSpriteObserverTest(config, Direction::DOWN, {3, 120, 120}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png", true); } TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT) { @@ -296,7 +293,7 @@ TEST(SpriteObserverTest, defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT 0, true}; - runSpriteObserverTest(config, Direction::LEFT, {3, 120, 120}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png", true); + runSpriteObserverTest(config, Direction::LEFT, {3, 120, 120}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png", true); } TEST(SpriteObserverTest, partialObserver) { @@ -307,7 +304,7 @@ TEST(SpriteObserverTest, partialObserver) { 0, false}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver.png", false); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver.png", false); } TEST(SpriteObserverTest, partialObserver_withOffset) { @@ -318,7 +315,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset) { 1, false}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset.png", false); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset.png", false); } TEST(SpriteObserverTest, partialObserver_trackAvatar_NONE) { @@ -329,7 +326,7 @@ TEST(SpriteObserverTest, partialObserver_trackAvatar_NONE) { 0, false}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_NONE.png", true); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_NONE.png", true); } TEST(SpriteObserverTest, partialObserver_trackAvatar_UP) { @@ -340,7 +337,7 @@ TEST(SpriteObserverTest, partialObserver_trackAvatar_UP) { 0, false}; - runSpriteObserverTest(config, Direction::UP, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_UP.png", true); + runSpriteObserverTest(config, Direction::UP, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_UP.png", true); } TEST(SpriteObserverTest, partialObserver_trackAvatar_RIGHT) { @@ -351,7 +348,7 @@ TEST(SpriteObserverTest, partialObserver_trackAvatar_RIGHT) { 0, false}; - runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_RIGHT.png", true); + runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_RIGHT.png", true); } TEST(SpriteObserverTest, partialObserver_trackAvatar_DOWN) { @@ -362,7 +359,7 @@ TEST(SpriteObserverTest, partialObserver_trackAvatar_DOWN) { 0, false}; - runSpriteObserverTest(config, Direction::DOWN, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_DOWN.png", true); + runSpriteObserverTest(config, Direction::DOWN, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_DOWN.png", true); } TEST(SpriteObserverTest, partialObserver_trackAvatar_LEFT) { @@ -373,7 +370,7 @@ TEST(SpriteObserverTest, partialObserver_trackAvatar_LEFT) { 0, false}; - runSpriteObserverTest(config, Direction::LEFT, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_LEFT.png", true); + runSpriteObserverTest(config, Direction::LEFT, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_trackAvatar_LEFT.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_NONE) { @@ -384,7 +381,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_NONE) { 1, false}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_NONE.png", true); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_NONE.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_UP) { @@ -395,7 +392,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_UP) { 1, false}; - runSpriteObserverTest(config, Direction::UP, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_UP.png", true); + runSpriteObserverTest(config, Direction::UP, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_UP.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_RIGHT) { @@ -406,7 +403,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_RIGHT) { 1, false}; - runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_RIGHT.png", true); + runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_RIGHT.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_DOWN) { @@ -417,7 +414,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_DOWN) { 1, false}; - runSpriteObserverTest(config, Direction::DOWN, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_DOWN.png", true); + runSpriteObserverTest(config, Direction::DOWN, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_DOWN.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_LEFT) { @@ -428,7 +425,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_LEFT) { 1, false}; - runSpriteObserverTest(config, Direction::LEFT, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_LEFT.png", true); + runSpriteObserverTest(config, Direction::LEFT, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_LEFT.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE) { @@ -439,7 +436,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar 1, true}; - runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png", true); + runSpriteObserverTest(config, Direction::NONE, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_NONE.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP) { @@ -450,7 +447,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar 1, true}; - runSpriteObserverTest(config, Direction::UP, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png", true); + runSpriteObserverTest(config, Direction::UP, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT) { @@ -461,7 +458,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar 1, true}; - runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png", true); + runSpriteObserverTest(config, Direction::RIGHT, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN) { @@ -472,7 +469,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar 1, true}; - runSpriteObserverTest(config, Direction::DOWN, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png", true); + runSpriteObserverTest(config, Direction::DOWN, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png", true); } TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT) { @@ -483,7 +480,7 @@ TEST(SpriteObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar 1, true}; - runSpriteObserverTest(config, Direction::LEFT, {3, 120, 72}, {1, 3, 3 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png", true); + runSpriteObserverTest(config, Direction::LEFT, {3, 120, 72}, {1, 4, 4 * 120}, "tests/resources/observer/sprite/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png", true); } TEST(SpriteObserverTest, multiPlayer_Outline_Player1) { @@ -491,7 +488,7 @@ TEST(SpriteObserverTest, multiPlayer_Outline_Player1) { config.playerId = 1; config.playerCount = 3; - runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Player1.png"); + runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Player1.png"); } TEST(SpriteObserverTest, multiPlayer_Outline_Player2) { @@ -499,7 +496,7 @@ TEST(SpriteObserverTest, multiPlayer_Outline_Player2) { config.playerId = 2; config.playerCount = 3; - runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Player2.png"); + runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Player2.png"); } TEST(SpriteObserverTest, multiPlayer_Outline_Player3) { @@ -507,7 +504,7 @@ TEST(SpriteObserverTest, multiPlayer_Outline_Player3) { config.playerId = 3; config.playerCount = 3; - runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Player3.png"); + runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Player3.png"); } TEST(SpriteObserverTest, multiPlayer_Outline_Global) { @@ -515,7 +512,7 @@ TEST(SpriteObserverTest, multiPlayer_Outline_Global) { config.playerId = 0; config.playerCount = 3; - runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 3, 3 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Global.png"); + runSpriteObserverRTSTest(config, {3, 250, 250}, {1, 4, 4 * 250}, "tests/resources/observer/sprite/multiPlayer_Outline_Global.png"); } } // namespace griddly \ No newline at end of file diff --git a/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp b/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp index e2db9e958..45efbb7f2 100644 --- a/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp @@ -44,8 +44,8 @@ void runVectorObserverTest(ObserverConfig observerConfig, size_t dataLength = vectorObserver->getShape()[0] * vectorObserver->getShape()[1] * vectorObserver->getShape()[2]; - auto resetObservationPointer = std::vector(resetObservation.get(), resetObservation.get() + dataLength); - auto updateObservationPointer = std::vector(updateObservation.get(), updateObservation.get() + dataLength); + auto resetObservationPointer = std::vector(resetObservation, resetObservation + dataLength); + auto updateObservationPointer = std::vector(updateObservation, updateObservation + dataLength); ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedData, dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedData, dataLength)); diff --git a/tests/src/Griddly/Core/Observers/VulkanObserverTest.hpp b/tests/src/Griddly/Core/Observers/VulkanObserverTest.hpp index e5c935bd6..e907324fb 100644 --- a/tests/src/Griddly/Core/Observers/VulkanObserverTest.hpp +++ b/tests/src/Griddly/Core/Observers/VulkanObserverTest.hpp @@ -2,12 +2,12 @@ #define STB_IMAGE_WRITE_STATIC #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION +#include #include #include #include - using ::testing::Return; namespace griddly { @@ -15,7 +15,7 @@ namespace griddly { inline std::unique_ptr loadExpectedImage(std::string filename) { int width, height, channels; - stbi_uc* pixels = stbi_load(filename.c_str(), &width, &height, &channels, STBI_rgb); + stbi_uc* pixels = stbi_load(filename.c_str(), &width, &height, &channels, STBI_rgb_alpha); if (!pixels) { throw std::runtime_error("Failed to load texture image."); @@ -29,6 +29,24 @@ inline std::unique_ptr loadExpectedImage(std::string filename) { } inline int write_image(std::string filename, uint8_t* imageData, int stride, int width, int height) { - return stbi_write_png(filename.c_str(), width, height, 3, imageData, stride); + return stbi_write_png(filename.c_str(), width, height, STBI_rgb_alpha, imageData, stride); } -} \ No newline at end of file + +MATCHER_P3(ObservationResultMatcher, shape, strides, imageData, "") { + for (int x = 0; x < shape[1]; x++) { + for (int y = 0; y < shape[2]; y++) { + for (int c = 0; c < 4; c++) { + uint8_t srcImageBit = *(arg + y * strides[1] * shape[1] + x * strides[1] + c); + uint8_t dstImageBit = *(imageData + y * strides[2] + x * strides[1] + c * strides[0]); + if (srcImageBit != dstImageBit) { + spdlog::debug("source x: {0} y: {1} c: {2} ({3} != {7})", + x, y, c, srcImageBit, dstImageBit); + return false; + } + } + } + } + return true; +} + +} // namespace griddly \ No newline at end of file diff --git a/tests/src/Griddly/Core/Players/PlayerTest.cpp b/tests/src/Griddly/Core/Players/PlayerTest.cpp index eef53db2c..a55a15771 100644 --- a/tests/src/Griddly/Core/Players/PlayerTest.cpp +++ b/tests/src/Griddly/Core/Players/PlayerTest.cpp @@ -93,8 +93,7 @@ TEST(PlayerTest, performActions_terminated) { TEST(PlayerTest, observe) { auto mockGrid = std::shared_ptr(new MockGrid()); auto mockObserverPtr = std::shared_ptr(new MockObserver(mockGrid)); - auto mockObservationBytesPtr = std::shared_ptr(new uint8_t[10 * 10]{}, std::default_delete()); - auto mockObservationBytes = mockObservationBytesPtr.get(); + auto mockObservationBytesPtr = new uint8_t[10 * 10]{}; int playerId = 0; std::string name = "PlayerName"; @@ -102,11 +101,11 @@ TEST(PlayerTest, observe) { EXPECT_CALL(*mockObserverPtr, update()) .Times(1) - .WillOnce(Return(ByMove(std::move(mockObservationBytesPtr)))); + .WillOnce(Return(mockObservationBytesPtr)); auto observation = player->observe(); - ASSERT_EQ(observation.get(), mockObservationBytes); + ASSERT_EQ(observation, mockObservationBytesPtr); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockObserverPtr.get())); } diff --git a/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp b/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp index d0f71241f..df1dd1a88 100644 --- a/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp +++ b/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp @@ -10,8 +10,8 @@ class MockObserver : public Observer { ~MockObserver() {} MOCK_METHOD(void, init, (ObserverConfig observerConfig), ()); - MOCK_METHOD(std::shared_ptr, update, (), (const)); - MOCK_METHOD(std::shared_ptr, reset, (), ()); + MOCK_METHOD(uint8_t*, update, (), (const)); + MOCK_METHOD(uint8_t*, reset, (), ()); MOCK_METHOD(void, resetShape, (), ()); MOCK_METHOD(std::vector, getShape, (), (const)); diff --git a/tests/src/Mocks/Griddly/Core/Players/MockPlayer.hpp b/tests/src/Mocks/Griddly/Core/Players/MockPlayer.hpp index 2b343dfe7..3b8a7d325 100644 --- a/tests/src/Mocks/Griddly/Core/Players/MockPlayer.hpp +++ b/tests/src/Mocks/Griddly/Core/Players/MockPlayer.hpp @@ -11,7 +11,7 @@ class MockPlayer : public Player { MockPlayer() : Player(0, "testPlayer", nullptr) { } - MOCK_METHOD(std::shared_ptr, observe, (), ()); + MOCK_METHOD(uint8_t*, observe, (), ()); MOCK_METHOD(std::string, getName, (), (const)); MOCK_METHOD(uint32_t, getId, (), (const));