Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/game/StarWorldClient.cpp129
-rw-r--r--source/game/StarWorldClient.hpp2
-rw-r--r--source/game/StarWorldImpl.hpp55
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);