diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-07-31 17:31:02 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-07-31 17:31:02 +1000 |
commit | 2dc10fa5ad76784c7053d00887a7f878b58dfcf9 (patch) | |
tree | 7138b9321517a3e4ead4b9b293ab6524ed4b1bca | |
parent | 72e33fdef5e8e847a26a5525cc64b6a198aeebd4 (diff) |
Tile Prediction improvements
each tile modification is now validated and then added to prediction one-by-one
-rw-r--r-- | source/game/StarWorldClient.cpp | 129 | ||||
-rw-r--r-- | source/game/StarWorldClient.hpp | 2 | ||||
-rw-r--r-- | source/game/StarWorldImpl.hpp | 55 |
3 files changed, 114 insertions, 72 deletions
diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp index 25e5ae7..f9ad833 100644 --- a/source/game/StarWorldClient.cpp +++ b/source/game/StarWorldClient.cpp @@ -322,23 +322,27 @@ TileModificationList WorldClient::applyTileModifications(TileModificationList co if (!inWorld()) return {}; - auto extraCheck = [this](Vec2I pos, TileModification) { - return !isTileProtected(pos); - }; - - // thanks to new prediction: do it aggressively until no changes occur - auto result = WorldImpl::splitTileModifications(m_entityMap, modificationList, allowEntityOverlap, m_tileGetterFunction, extraCheck); - while (true) { - if (!result.first.empty()) { - informTilePredictions(result.first); - m_outgoingPackets.append(make_shared<ModifyTileListPacket>(result.first, true)); - - auto list = move(result.second); - result = WorldImpl::splitTileModifications(m_entityMap, list, allowEntityOverlap, m_tileGetterFunction, extraCheck); + // thanks to new prediction: do each one by one so that previous modifications affect placeability + + TileModificationList success; + TileModificationList failures; + for (auto const& pair : modificationList) { + if (!isTileProtected(pair.first)) { + auto result = WorldImpl::validateTileModification(m_entityMap, pair.first, pair.second, allowEntityOverlap, m_tileGetterFunction); + + if (result.first) { + informTilePrediction(pair.first, pair.second); + success.append(pair); + continue; + } } - else - return result.second; + failures.append(pair); } + + if (!success.empty()) + m_outgoingPackets.append(make_shared<ModifyTileListPacket>(move(success), true)); + + return failures; } float WorldClient::gravity(Vec2F const& pos) const { @@ -817,8 +821,41 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) { // player, but this may not be true in the future. In the future, there // may be context hints with tile modifications to figure out what to do // with failures. - for (auto modification : tileModificationFailure->modifications) { - m_predictedTiles.remove(modification.first); + for (auto& modification : tileModificationFailure->modifications) { + auto findPrediction = m_predictedTiles.find(modification.first); + if (findPrediction != m_predictedTiles.end()) { + auto& p = findPrediction->second; + if (auto placeMaterial = modification.second.ptr<PlaceMaterial>()) { + if (placeMaterial->layer == TileLayer::Foreground) { + p.foreground.reset(); + p.foregroundHueShift.reset(); + } + else { + p.background.reset(); + p.backgroundHueShift.reset(); + } + } else if (auto placeMod = modification.second.ptr<PlaceMod>()) { + if (placeMod->layer == TileLayer::Foreground) { + p.foregroundMod.reset(); + p.foregroundModHueShift.reset(); + } + else { + p.backgroundMod.reset(); + p.backgroundModHueShift.reset(); + } + } else if (auto placeColor = modification.second.ptr<PlaceMaterialColor>()) { + if (placeColor->layer == TileLayer::Foreground) + p.foregroundColorVariant.reset(); + else + p.backgroundColorVariant.reset(); + } else if (auto placeLiquid = modification.second.ptr<PlaceLiquid>()) { + p.liquid.reset(); + } + + if (!p) + m_predictedTiles.erase(findPrediction); + } + if (auto placeMaterial = modification.second.ptr<PlaceMaterial>()) { auto stack = materialDatabase->materialItemDrop(placeMaterial->material); tryGiveMainPlayerItem(itemDatabase->item(stack)); @@ -2148,39 +2185,37 @@ void WorldClient::renderCollisionDebug() { } } -void WorldClient::informTilePredictions(TileModificationList const& modifications) { +void WorldClient::informTilePrediction(Vec2I const& pos, TileModification const& modification) { auto now = Time::monotonicMilliseconds(); - for (auto& pair : modifications) { - auto& p = m_predictedTiles[pair.first]; - p.time = now; - if (auto placeMaterial = pair.second.ptr<PlaceMaterial>()) { - if (placeMaterial->layer == TileLayer::Foreground) { - p.foreground = placeMaterial->material; - p.foregroundHueShift = placeMaterial->materialHueShift; - } else { - p.background = placeMaterial->material; - p.backgroundHueShift = placeMaterial->materialHueShift; - } - } - else if (auto placeMod = pair.second.ptr<PlaceMod>()) { - if (placeMod->layer == TileLayer::Foreground) - p.foregroundMod = placeMod->mod; - else - p.backgroundMod = placeMod->mod; - } - else if (auto placeColor = pair.second.ptr<PlaceMaterialColor>()) { - if (placeColor->layer == TileLayer::Foreground) - p.foregroundColorVariant = placeColor->color; - else - p.backgroundColorVariant = placeColor->color; - } - else if (auto placeLiquid = pair.second.ptr<PlaceLiquid>()) { - if (!p.liquid || p.liquid->liquid != placeLiquid->liquid) - p.liquid = LiquidLevel(placeLiquid->liquid, placeLiquid->liquidLevel); - else - p.liquid->level += placeLiquid->liquidLevel; + auto& p = m_predictedTiles[pos]; + p.time = now; + if (auto placeMaterial = modification.ptr<PlaceMaterial>()) { + if (placeMaterial->layer == TileLayer::Foreground) { + p.foreground = placeMaterial->material; + p.foregroundHueShift = placeMaterial->materialHueShift; + } else { + p.background = placeMaterial->material; + p.backgroundHueShift = placeMaterial->materialHueShift; } } + else if (auto placeMod = modification.ptr<PlaceMod>()) { + if (placeMod->layer == TileLayer::Foreground) + p.foregroundMod = placeMod->mod; + else + p.backgroundMod = placeMod->mod; + } + else if (auto placeColor = modification.ptr<PlaceMaterialColor>()) { + if (placeColor->layer == TileLayer::Foreground) + p.foregroundColorVariant = placeColor->color; + else + p.backgroundColorVariant = placeColor->color; + } + else if (auto placeLiquid = modification.ptr<PlaceLiquid>()) { + if (!p.liquid || p.liquid->liquid != placeLiquid->liquid) + p.liquid = LiquidLevel(placeLiquid->liquid, placeLiquid->liquidLevel); + else + p.liquid->level += placeLiquid->liquidLevel; + } } void WorldClient::setupForceRegions() { diff --git a/source/game/StarWorldClient.hpp b/source/game/StarWorldClient.hpp index d271f3f..0adbef6 100644 --- a/source/game/StarWorldClient.hpp +++ b/source/game/StarWorldClient.hpp @@ -236,7 +236,7 @@ private: void freshenCollision(RectI const& region); void renderCollisionDebug(); - void informTilePredictions(TileModificationList const& modifications); + void informTilePrediction(Vec2I const& pos, TileModification const& modification); void setTileProtection(DungeonId dungeonId, bool isProtected); diff --git a/source/game/StarWorldImpl.hpp b/source/game/StarWorldImpl.hpp index e8c0823..91e03fb 100644 --- a/source/game/StarWorldImpl.hpp +++ b/source/game/StarWorldImpl.hpp @@ -49,10 +49,12 @@ namespace WorldImpl { bool canPlaceMaterialColorVariant(Vec2I const& pos, TileLayer layer, MaterialColorVariant color, GetTileFunction& getTile); template <typename GetTileFunction> bool canPlaceMod(Vec2I const& pos, TileLayer layer, ModId mod, GetTileFunction& getTile); + template <typename GetTileFunction> + pair<bool, bool> validateTileModification(EntityMapPtr const& entityMap, Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap, GetTileFunction& getTile); // Split modification list into good and bad template <typename GetTileFunction> pair<TileModificationList, TileModificationList> splitTileModifications(EntityMapPtr const& entityMap, TileModificationList const& modificationList, - bool allowEntityOverlap, function<bool(Vec2I pos, GetTileFunction& getTile, TileModification modification)> extraCheck = {}); + bool allowEntityOverlap, GetTileFunction& getTile, function<bool(Vec2I pos, TileModification modification)> extraCheck = {}); template <typename TileSectorArray> float windLevel(shared_ptr<TileSectorArray> const& tileSectorArray, Vec2F const& position, float weatherWindLevel); @@ -314,33 +316,38 @@ namespace WorldImpl { } template <typename GetTileFunction> - pair<TileModificationList, TileModificationList> splitTileModifications(EntityMapPtr const& entityMap, - TileModificationList const& modificationList, bool allowEntityOverlap, GetTileFunction& getTile, function<bool(Vec2I pos, TileModification modification)> extraCheck) { + pair<bool, bool> validateTileModification(EntityMapPtr const& entityMap, Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap, GetTileFunction& getTile) { + bool good = false; + bool perhaps = false; + + if (auto placeMaterial = modification.ptr<PlaceMaterial>()) { + perhaps = WorldImpl::perhapsCanPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, getTile); + if (perhaps) + good = WorldImpl::canPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, getTile); + } else if (auto placeMod = modification.ptr<PlaceMod>()) { + good = WorldImpl::canPlaceMod(pos, placeMod->layer, placeMod->mod, getTile); + } else if (auto placeMaterialColor = modification.ptr<PlaceMaterialColor>()) { + good = WorldImpl::canPlaceMaterialColorVariant(pos, placeMaterialColor->layer, placeMaterialColor->color, getTile); + } else if (modification.is<PlaceLiquid>()) { + good = getTile(pos).collision == CollisionKind::None; + } else { + good = false; + } + + return { good, perhaps }; + } + + template <typename GetTileFunction> + pair<TileModificationList, TileModificationList> splitTileModifications(EntityMapPtr const& entityMap, TileModificationList const& modificationList, + bool allowEntityOverlap, GetTileFunction& getTile, function<bool(Vec2I pos, TileModification modification)> extraCheck) { TileModificationList success; TileModificationList unknown; TileModificationList failures; for (auto const& pair : modificationList) { - Vec2I pos; - TileModification modification; - std::tie(pos, modification) = pair; - - bool good = false; - bool perhaps = false; - if (extraCheck && !extraCheck(pos, modification)) { - good = false; - } else if (auto placeMaterial = modification.ptr<PlaceMaterial>()) { - perhaps = WorldImpl::perhapsCanPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, getTile); - if (perhaps) - good = WorldImpl::canPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, getTile); - } else if (auto placeMod = modification.ptr<PlaceMod>()) { - good = WorldImpl::canPlaceMod(pos, placeMod->layer, placeMod->mod, getTile); - } else if (auto placeMaterialColor = modification.ptr<PlaceMaterialColor>()) { - good = WorldImpl::canPlaceMaterialColorVariant(pos, placeMaterialColor->layer, placeMaterialColor->color, getTile); - } else if (modification.is<PlaceLiquid>()) { - good = getTile(pos).collision == CollisionKind::None; - } else { - good = false; - } + + bool good = false, perhaps = false; + if (!extraCheck || extraCheck(pair.first, pair.second)) + std::tie(good, perhaps) = validateTileModification(entityMap, pair.first, pair.second, allowEntityOverlap, getTile); if (good) success.append(pair); |