From 5a69f22f2d44478dd1f4c7b00f9922436579c7c8 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 10 Aug 2021 16:27:58 +0300 Subject: [PATCH] Move ScTile code into cpp --- src/openrct2/libopenrct2.vcxproj | 1 + .../scripting/bindings/world/ScTile.cpp | 243 ++++++++++++++++++ .../scripting/bindings/world/ScTile.hpp | 222 ++-------------- 3 files changed, 260 insertions(+), 206 deletions(-) create mode 100644 src/openrct2/scripting/bindings/world/ScTile.cpp diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 67c5d17b36..7029514897 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -871,6 +871,7 @@ + diff --git a/src/openrct2/scripting/bindings/world/ScTile.cpp b/src/openrct2/scripting/bindings/world/ScTile.cpp new file mode 100644 index 0000000000..28d4d2751b --- /dev/null +++ b/src/openrct2/scripting/bindings/world/ScTile.cpp @@ -0,0 +1,243 @@ +/***************************************************************************** + * Copyright (c) 2014-2021 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#ifdef ENABLE_SCRIPTING + +# include "ScTile.hpp" + +# include "../../../Context.h" +# include "../../../common.h" +# include "../../../core/Guard.hpp" +# include "../../../ride/Track.h" +# include "../../../world/Footpath.h" +# include "../../../world/Scenery.h" +# include "../../../world/Sprite.h" +# include "../../../world/Surface.h" +# include "../../Duktape.hpp" +# include "../../ScriptEngine.h" +# include "ScTileElement.hpp" + +# include +# include +# include + +namespace OpenRCT2::Scripting +{ + ScTile::ScTile(const CoordsXY& coords) + : _coords(coords) + { + } + + int32_t ScTile::x_get() const + { + return _coords.x / COORDS_XY_STEP; + } + + int32_t ScTile::y_get() const + { + return _coords.y / COORDS_XY_STEP; + } + + uint32_t ScTile::numElements_get() const + { + auto first = GetFirstElement(); + return static_cast(GetNumElements(first)); + } + + std::vector> ScTile::elements_get() const + { + std::vector> result; + auto first = GetFirstElement(); + auto currentNumElements = GetNumElements(first); + if (currentNumElements != 0) + { + result.reserve(currentNumElements); + for (size_t i = 0; i < currentNumElements; i++) + { + result.push_back(std::make_shared(_coords, &first[i])); + } + } + return result; + } + + DukValue ScTile::data_get() const + { + auto ctx = GetDukContext(); + auto first = map_get_first_element_at(_coords); + auto dataLen = GetNumElements(first) * sizeof(TileElement); + auto data = duk_push_fixed_buffer(ctx, dataLen); + if (first != nullptr) + { + std::memcpy(data, first, dataLen); + } + duk_push_buffer_object(ctx, -1, 0, dataLen, DUK_BUFOBJ_UINT8ARRAY); + return DukValue::take_from_stack(ctx); + } + + void ScTile::data_set(DukValue value) + { + ThrowIfGameStateNotMutable(); + auto ctx = value.context(); + value.push(); + if (duk_is_buffer_data(ctx, -1)) + { + duk_size_t dataLen{}; + auto data = duk_get_buffer_data(ctx, -1, &dataLen); + auto numElements = dataLen / sizeof(TileElement); + if (numElements == 0) + { + map_set_tile_element(TileCoordsXY(_coords), nullptr); + } + else + { + auto first = GetFirstElement(); + auto currentNumElements = GetNumElements(first); + if (numElements > currentNumElements) + { + // Allocate space for the extra tile elements (inefficient but works) + auto pos = TileCoordsXYZ(TileCoordsXY(_coords), 0).ToCoordsXYZ(); + auto numToInsert = numElements - currentNumElements; + for (size_t i = 0; i < numToInsert; i++) + { + tile_element_insert(pos, 0, TileElementType::Surface); + } + + // Copy data to element span + first = map_get_first_element_at(_coords); + currentNumElements = GetNumElements(first); + if (currentNumElements != 0) + { + std::memcpy(first, data, currentNumElements * sizeof(TileElement)); + // Safely force last tile flag for last element to avoid read overrun + first[numElements - 1].SetLastForTile(true); + } + } + else + { + std::memcpy(first, data, numElements * sizeof(TileElement)); + // Safely force last tile flag for last element to avoid read overrun + first[numElements - 1].SetLastForTile(true); + } + } + map_invalidate_tile_full(_coords); + } + } + + std::shared_ptr ScTile::getElement(uint32_t index) const + { + auto first = GetFirstElement(); + if (static_cast(index) < GetNumElements(first)) + { + return std::make_shared(_coords, &first[index]); + } + return {}; + } + + std::shared_ptr ScTile::insertElement(uint32_t index) + { + ThrowIfGameStateNotMutable(); + std::shared_ptr result; + auto first = GetFirstElement(); + auto origNumElements = GetNumElements(first); + if (index <= origNumElements) + { + std::vector data(first, first + origNumElements); + + auto pos = TileCoordsXYZ(TileCoordsXY(_coords), 0).ToCoordsXYZ(); + auto newElement = tile_element_insert(pos, 0, TileElementType::Surface); + if (newElement == nullptr) + { + auto ctx = GetDukContext(); + duk_error(ctx, DUK_ERR_ERROR, "Unable to allocate element."); + } + else + { + // Inefficient, requires a dedicated method in tile element manager + first = GetFirstElement(); + // Copy elements before index + if (index > 0) + { + std::memcpy(first, &data[0], index * sizeof(TileElement)); + } + // Zero new element + std::memset(first + index, 0, sizeof(TileElement)); + // Copy elements after index + if (index < origNumElements) + { + std::memcpy(first + index + 1, &data[index], (origNumElements - index) * sizeof(TileElement)); + } + for (size_t i = 0; i < origNumElements; i++) + { + first[i].SetLastForTile(false); + } + first[origNumElements].SetLastForTile(true); + map_invalidate_tile_full(_coords); + result = std::make_shared(_coords, &first[index]); + } + } + else + { + auto ctx = GetDukContext(); + duk_error(ctx, DUK_ERR_RANGE_ERROR, "Index must be between zero and the number of elements on the tile."); + } + return result; + } + + void ScTile::removeElement(uint32_t index) + { + ThrowIfGameStateNotMutable(); + auto first = GetFirstElement(); + if (index < GetNumElements(first)) + { + tile_element_remove(&first[index]); + map_invalidate_tile_full(_coords); + } + } + + TileElement* ScTile::GetFirstElement() const + { + return map_get_first_element_at(_coords); + } + + size_t ScTile::GetNumElements(const TileElement* first) + { + size_t count = 0; + if (first != nullptr) + { + auto element = first; + do + { + count++; + } while (!(element++)->IsLastForTile()); + } + return count; + } + + duk_context* ScTile::GetDukContext() const + { + auto& scriptEngine = GetContext()->GetScriptEngine(); + auto ctx = scriptEngine.GetContext(); + return ctx; + } + + void ScTile::Register(duk_context* ctx) + { + dukglue_register_property(ctx, &ScTile::x_get, nullptr, "x"); + dukglue_register_property(ctx, &ScTile::y_get, nullptr, "y"); + dukglue_register_property(ctx, &ScTile::elements_get, nullptr, "elements"); + dukglue_register_property(ctx, &ScTile::numElements_get, nullptr, "numElements"); + dukglue_register_property(ctx, &ScTile::data_get, &ScTile::data_set, "data"); + dukglue_register_method(ctx, &ScTile::getElement, "getElement"); + dukglue_register_method(ctx, &ScTile::insertElement, "insertElement"); + dukglue_register_method(ctx, &ScTile::removeElement, "removeElement"); + } + +} // namespace OpenRCT2::Scripting + +#endif diff --git a/src/openrct2/scripting/bindings/world/ScTile.hpp b/src/openrct2/scripting/bindings/world/ScTile.hpp index 2126d5cc0e..1698377c42 100644 --- a/src/openrct2/scripting/bindings/world/ScTile.hpp +++ b/src/openrct2/scripting/bindings/world/ScTile.hpp @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers + * Copyright (c) 2014-2021 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 @@ -11,21 +11,14 @@ #ifdef ENABLE_SCRIPTING -# include "../../../Context.h" # include "../../../common.h" -# include "../../../core/Guard.hpp" -# include "../../../ride/Track.h" -# include "../../../world/Footpath.h" -# include "../../../world/Scenery.h" -# include "../../../world/Sprite.h" -# include "../../../world/Surface.h" # include "../../Duktape.hpp" -# include "../../ScriptEngine.h" # include "ScTileElement.hpp" # include # include # include +# include namespace OpenRCT2::Scripting { @@ -35,216 +28,33 @@ namespace OpenRCT2::Scripting CoordsXY _coords; public: - ScTile(const CoordsXY& coords) - : _coords(coords) - { - } + ScTile(const CoordsXY& coords); private: - int32_t x_get() const - { - return _coords.x / COORDS_XY_STEP; - } + int32_t x_get() const; - int32_t y_get() const - { - return _coords.y / COORDS_XY_STEP; - } + int32_t y_get() const; - uint32_t numElements_get() const - { - auto first = GetFirstElement(); - return static_cast(GetNumElements(first)); - } + uint32_t numElements_get() const; - std::vector> elements_get() const - { - std::vector> result; - auto first = GetFirstElement(); - auto currentNumElements = GetNumElements(first); - if (currentNumElements != 0) - { - result.reserve(currentNumElements); - for (size_t i = 0; i < currentNumElements; i++) - { - result.push_back(std::make_shared(_coords, &first[i])); - } - } - return result; - } + std::vector> elements_get() const; - DukValue data_get() const - { - auto ctx = GetDukContext(); - auto first = map_get_first_element_at(_coords); - auto dataLen = GetNumElements(first) * sizeof(TileElement); - auto data = duk_push_fixed_buffer(ctx, dataLen); - if (first != nullptr) - { - std::memcpy(data, first, dataLen); - } - duk_push_buffer_object(ctx, -1, 0, dataLen, DUK_BUFOBJ_UINT8ARRAY); - return DukValue::take_from_stack(ctx); - } + DukValue data_get() const; + void data_set(DukValue value); - void data_set(DukValue value) - { - ThrowIfGameStateNotMutable(); - auto ctx = value.context(); - value.push(); - if (duk_is_buffer_data(ctx, -1)) - { - duk_size_t dataLen{}; - auto data = duk_get_buffer_data(ctx, -1, &dataLen); - auto numElements = dataLen / sizeof(TileElement); - if (numElements == 0) - { - map_set_tile_element(TileCoordsXY(_coords), nullptr); - } - else - { - auto first = GetFirstElement(); - auto currentNumElements = GetNumElements(first); - if (numElements > currentNumElements) - { - // Allocate space for the extra tile elements (inefficient but works) - auto pos = TileCoordsXYZ(TileCoordsXY(_coords), 0).ToCoordsXYZ(); - auto numToInsert = numElements - currentNumElements; - for (size_t i = 0; i < numToInsert; i++) - { - tile_element_insert(pos, 0, TileElementType::Surface); - } + std::shared_ptr getElement(uint32_t index) const; + std::shared_ptr insertElement(uint32_t index); - // Copy data to element span - first = map_get_first_element_at(_coords); - currentNumElements = GetNumElements(first); - if (currentNumElements != 0) - { - std::memcpy(first, data, currentNumElements * sizeof(TileElement)); - // Safely force last tile flag for last element to avoid read overrun - first[numElements - 1].SetLastForTile(true); - } - } - else - { - std::memcpy(first, data, numElements * sizeof(TileElement)); - // Safely force last tile flag for last element to avoid read overrun - first[numElements - 1].SetLastForTile(true); - } - } - map_invalidate_tile_full(_coords); - } - } + void removeElement(uint32_t index); - std::shared_ptr getElement(uint32_t index) const - { - auto first = GetFirstElement(); - if (static_cast(index) < GetNumElements(first)) - { - return std::make_shared(_coords, &first[index]); - } - return {}; - } + TileElement* GetFirstElement() const; - std::shared_ptr insertElement(uint32_t index) - { - ThrowIfGameStateNotMutable(); - std::shared_ptr result; - auto first = GetFirstElement(); - auto origNumElements = GetNumElements(first); - if (index <= origNumElements) - { - std::vector data(first, first + origNumElements); + static size_t GetNumElements(const TileElement* first); - auto pos = TileCoordsXYZ(TileCoordsXY(_coords), 0).ToCoordsXYZ(); - auto newElement = tile_element_insert(pos, 0, TileElementType::Surface); - if (newElement == nullptr) - { - auto ctx = GetDukContext(); - duk_error(ctx, DUK_ERR_ERROR, "Unable to allocate element."); - } - else - { - // Inefficient, requires a dedicated method in tile element manager - first = GetFirstElement(); - // Copy elements before index - if (index > 0) - { - std::memcpy(first, &data[0], index * sizeof(TileElement)); - } - // Zero new element - std::memset(first + index, 0, sizeof(TileElement)); - // Copy elements after index - if (index < origNumElements) - { - std::memcpy(first + index + 1, &data[index], (origNumElements - index) * sizeof(TileElement)); - } - for (size_t i = 0; i < origNumElements; i++) - { - first[i].SetLastForTile(false); - } - first[origNumElements].SetLastForTile(true); - map_invalidate_tile_full(_coords); - result = std::make_shared(_coords, &first[index]); - } - } - else - { - auto ctx = GetDukContext(); - duk_error(ctx, DUK_ERR_RANGE_ERROR, "Index must be between zero and the number of elements on the tile."); - } - return result; - } - - void removeElement(uint32_t index) - { - ThrowIfGameStateNotMutable(); - auto first = GetFirstElement(); - if (index < GetNumElements(first)) - { - tile_element_remove(&first[index]); - map_invalidate_tile_full(_coords); - } - } - - TileElement* GetFirstElement() const - { - return map_get_first_element_at(_coords); - } - - static size_t GetNumElements(const TileElement* first) - { - size_t count = 0; - if (first != nullptr) - { - auto element = first; - do - { - count++; - } while (!(element++)->IsLastForTile()); - } - return count; - } - - duk_context* GetDukContext() const - { - auto& scriptEngine = GetContext()->GetScriptEngine(); - auto ctx = scriptEngine.GetContext(); - return ctx; - } + duk_context* GetDukContext() const; public: - static void Register(duk_context* ctx) - { - dukglue_register_property(ctx, &ScTile::x_get, nullptr, "x"); - dukglue_register_property(ctx, &ScTile::y_get, nullptr, "y"); - dukglue_register_property(ctx, &ScTile::elements_get, nullptr, "elements"); - dukglue_register_property(ctx, &ScTile::numElements_get, nullptr, "numElements"); - dukglue_register_property(ctx, &ScTile::data_get, &ScTile::data_set, "data"); - dukglue_register_method(ctx, &ScTile::getElement, "getElement"); - dukglue_register_method(ctx, &ScTile::insertElement, "insertElement"); - dukglue_register_method(ctx, &ScTile::removeElement, "removeElement"); - } + static void Register(duk_context* ctx); }; } // namespace OpenRCT2::Scripting