From dc7706184094e653dbb46310195e88604c007854 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Sat, 9 Mar 2024 12:18:22 +1100 Subject: [PATCH] hopefully fix #33 in OpenStarbound, players can place blocks with their own collision type. this can cause objects to override the collision type if the object has material spaces and a previous attempt at accounting for this led to that bug: giving object collision its own field in the server tile should fix this --- source/base/StarAssets.cpp | 2 +- source/game/StarWorldServer.cpp | 43 +++++++++-------------- source/game/StarWorldTiles.cpp | 23 ++++++++++-- source/game/StarWorldTiles.hpp | 8 +++++ source/game/interfaces/StarTileEntity.hpp | 1 - 5 files changed, 47 insertions(+), 30 deletions(-) diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp index 5628e4f..de7bc51 100644 --- a/source/base/StarAssets.cpp +++ b/source/base/StarAssets.cpp @@ -681,7 +681,7 @@ ByteArray Assets::read(String const& path) const { Json Assets::checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe const external) const { auto externalRef = external.value(); auto newResult = result; - for (auto const patch : patchData) { + for (auto const& patch : patchData) { switch(patch.type()) { case Json::Type::Array: // if the patch is an array, go down recursively until we get objects try { diff --git a/source/game/StarWorldServer.cpp b/source/game/StarWorldServer.cpp index 7837221..d878a4c 100644 --- a/source/game/StarWorldServer.cpp +++ b/source/game/StarWorldServer.cpp @@ -1255,7 +1255,7 @@ void WorldServer::init(bool firstTime) { m_entityMessageResponses = {}; m_collisionGenerator.init([=](int x, int y) { - return m_tileArray->tile({x, y}).collision; + return m_tileArray->tile({x, y}).getCollision(); }); m_tileEntityBreakCheckTimer = GameTimer(m_serverConfig.getFloat("tileEntityBreakCheckInterval")); @@ -1505,21 +1505,20 @@ void WorldServer::updateTileEntityTiles(TileEntityPtr const& entity, bool removi ServerTile* tile = m_tileArray->modifyTile(pos); if (tile) { - bool updated = false; + tile->rootSource = {}; + bool updatedTile = false; if (tile->foreground == materialSpace.material) { tile->foreground = EmptyMaterialId; tile->foregroundMod = NoModId; - tile->rootSource = {}; - updated = true; + updatedTile = true; } - if (tile->collision == materialDatabase->materialCollisionKind(materialSpace.material) - && tile->updateCollision(materialSpace.prevCollision.value(CollisionKind::None))) { + if (tile->updateObjectCollision(CollisionKind::None)) { m_liquidEngine->visitLocation(pos); m_fallingBlocksAgent->visitLocation(pos); dirtyCollision(RectI::withSize(pos, { 1, 1 })); - updated = true; + updatedTile = true; } - if (updated) + if (updatedTile) queueTileUpdates(pos); } } @@ -1533,35 +1532,27 @@ void WorldServer::updateTileEntityTiles(TileEntityPtr const& entity, bool removi for (auto const& materialSpace : newMaterialSpaces) { Vec2I pos = materialSpace.space + entity->tilePosition(); - bool updated = false; + bool updatedTile = false; bool updatedCollision = false; ServerTile* tile = m_tileArray->modifyTile(pos); - if (tile && (tile->foreground == EmptyMaterialId || tile->foreground == materialSpace.material)) { - tile->foreground = materialSpace.material; - tile->foregroundMod = NoModId; + if (tile) { + if (tile->foreground == EmptyMaterialId) { + tile->foreground = materialSpace.material; + tile->foregroundMod = NoModId; + updatedTile = true; + } bool hadRoot = tile->rootSource.isValid(); if (isRealMaterial(materialSpace.material)) tile->rootSource = entity->tilePosition(); auto& space = passedSpaces.emplaceAppend(materialSpace); - if (hadRoot) - space.prevCollision.emplace(tile->collision); - updatedCollision = tile->updateCollision(materialDatabase->materialCollisionKind(tile->foreground)); - updated = true; - } - else if (tile && tile->collision < CollisionKind::Dynamic) { - bool hadRoot = tile->rootSource.isValid(); - auto& space = passedSpaces.emplaceAppend(materialSpace); - if (hadRoot) - space.prevCollision.emplace(tile->collision); - updatedCollision = tile->updateCollision(materialDatabase->materialCollisionKind(materialSpace.material)); - updated = true; + updatedTile |= updatedCollision = tile->updateObjectCollision(materialDatabase->materialCollisionKind(materialSpace.material)); } if (updatedCollision) { m_liquidEngine->visitLocation(pos); m_fallingBlocksAgent->visitLocation(pos); dirtyCollision(RectI::withSize(pos, { 1, 1 })); } - if (updated) + if (updatedTile) queueTileUpdates(pos); } spaces.materials = std::move(passedSpaces); @@ -1997,7 +1988,7 @@ void WorldServer::writeNetTile(Vec2I const& pos, NetTile& netTile) const { netTile.backgroundMod = tile.backgroundMod; netTile.backgroundModHueShift = tile.backgroundModHueShift; netTile.liquid = tile.liquid.netUpdate(); - netTile.collision = tile.collision; + netTile.collision = tile.getCollision(); netTile.blockBiomeIndex = tile.blockBiomeIndex; netTile.environmentBiomeIndex = tile.environmentBiomeIndex; netTile.dungeonId = tile.dungeonId; diff --git a/source/game/StarWorldTiles.cpp b/source/game/StarWorldTiles.cpp index 20ced8d..826bfbb 100644 --- a/source/game/StarWorldTiles.cpp +++ b/source/game/StarWorldTiles.cpp @@ -26,7 +26,7 @@ bool WorldTile::isColliding(CollisionSet const& collisionSet) const { VersionNumber const ServerTile::CurrentSerializationVersion = 418; -ServerTile::ServerTile() {} +ServerTile::ServerTile() : objectCollision(CollisionKind::None) {} ServerTile::ServerTile(ServerTile const& serverTile) : WorldTile() { *this = serverTile; @@ -37,7 +37,7 @@ ServerTile& ServerTile::operator=(ServerTile const& serverTile) { liquid = serverTile.liquid; rootSource = serverTile.rootSource; - + objectCollision = serverTile.objectCollision; return *this; } @@ -109,6 +109,25 @@ bool ServerTile::updateCollision(CollisionKind kind) { return false; } +bool ServerTile::updateObjectCollision(CollisionKind kind) { + if (objectCollision != kind) { + objectCollision = kind; + collisionCacheDirty = true; + collisionCache.clear(); + return true; + } + return false; +} + +CollisionKind ServerTile::getCollision() const { + CollisionKind kind = collision; + if (objectCollision != CollisionKind::None + && (objectCollision != CollisionKind::Platform || kind == CollisionKind::None)) { + kind = objectCollision; + } + return kind; +} + PredictedTile::operator bool() const { return background diff --git a/source/game/StarWorldTiles.hpp b/source/game/StarWorldTiles.hpp index 19c83d4..56fbb1b 100644 --- a/source/game/StarWorldTiles.hpp +++ b/source/game/StarWorldTiles.hpp @@ -69,12 +69,20 @@ struct ServerTile : public WorldTile { // Updates collision, clears cache, and if the collision kind does not // support liquid destroys it. bool updateCollision(CollisionKind kind); + // Used for setting the second collision kind calculated by object material spaces. + bool updateObjectCollision(CollisionKind kind); + + // Calculates the actually-used collision kind based on the tile and object collision kinds. + CollisionKind getCollision() const; LiquidStore liquid; // If set, a plant or object is rooted to the tile and tile damage // should be redirected to this position Maybe rootSource; + + // Do not serialize - calculated at runtime + CollisionKind objectCollision; }; typedef TileSectorArray ServerTileSectorArray; typedef shared_ptr ServerTileSectorArrayPtr; diff --git a/source/game/interfaces/StarTileEntity.hpp b/source/game/interfaces/StarTileEntity.hpp index 60e953d..64b45cb 100644 --- a/source/game/interfaces/StarTileEntity.hpp +++ b/source/game/interfaces/StarTileEntity.hpp @@ -17,7 +17,6 @@ struct MaterialSpace { Vec2I space; MaterialId material; - Maybe prevCollision; //exclude from == }; DataStream& operator<<(DataStream& ds, MaterialSpace const& materialSpace);