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

summaryrefslogtreecommitdiff
path: root/source/game/StarWorldServer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/StarWorldServer.cpp')
-rw-r--r--source/game/StarWorldServer.cpp102
1 files changed, 73 insertions, 29 deletions
diff --git a/source/game/StarWorldServer.cpp b/source/game/StarWorldServer.cpp
index 0c2a089..9d53d54 100644
--- a/source/game/StarWorldServer.cpp
+++ b/source/game/StarWorldServer.cpp
@@ -373,6 +373,11 @@ void WorldServer::handleIncomingPackets(ConnectionId clientId, List<PacketPtr> c
if (!unappliedModifications.empty())
clientInfo->outgoingPackets.append(make_shared<TileModificationFailurePacket>(unappliedModifications));
+ } else if (auto rtpacket = as<ReplaceTileListPacket>(packet)) {
+ auto unappliedModifications = replaceTiles(rtpacket->modifications, rtpacket->tileDamage);
+ if (!unappliedModifications.empty())
+ clientInfo->outgoingPackets.append(make_shared<TileModificationFailurePacket>(unappliedModifications));
+
} else if (auto dtgpacket = as<DamageTileGroupPacket>(packet)) {
damageTiles(dtgpacket->tilePositions, dtgpacket->layer, dtgpacket->sourcePosition, dtgpacket->tileDamage, dtgpacket->sourceEntity);
@@ -875,6 +880,58 @@ TileModificationList WorldServer::forceApplyTileModifications(TileModificationLi
return doApplyTileModifications(modificationList, allowEntityOverlap, true);
}
+bool WorldServer::replaceTile(Vec2I const& pos, TileModification const& modification, TileDamage const& tileDamage) {
+ if (isTileProtected(pos))
+ return false;
+
+ if (!WorldImpl::validateTileReplacement(modification))
+ return false;
+
+ if (auto placeMaterial = modification.ptr<PlaceMaterial>()) {
+ if (!isTileConnectable(pos, placeMaterial->layer, true))
+ return false;
+
+ if (auto tile = m_tileArray->modifyTile(pos)) {
+ auto damageParameters = WorldImpl::tileDamageParameters(tile, placeMaterial->layer, tileDamage);
+ bool harvested = tileDamage.harvestLevel >= damageParameters.requiredHarvestLevel();
+ auto damage = placeMaterial->layer == TileLayer::Foreground ? tile->foregroundDamage : tile->backgroundDamage;
+ Vec2F dropPosition = centerOfTile(pos);
+
+ for (auto drop : destroyBlock(placeMaterial->layer, pos, harvested, !tileDamageIsPenetrating(damage.damageType()), false))
+ addEntity(ItemDrop::createRandomizedDrop(drop, dropPosition));
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+TileModificationList WorldServer::replaceTiles(TileModificationList const& modificationList, TileDamage const& tileDamage) {
+ TileModificationList success, failures;
+
+ for (auto pair : modificationList) {
+ if (replaceTile(pair.first, pair.second, tileDamage))
+ success.append(pair);
+ else
+ failures.append(pair);
+ }
+
+ failures.appendAll(doApplyTileModifications(success, true, false, false));
+
+ for (auto pair : success) {
+ checkEntityBreaks(RectF::withSize(Vec2F(pair.first), Vec2F(1, 1)));
+ m_liquidEngine->visitLocation(pair.first);
+ m_fallingBlocksAgent->visitLocation(pair.first);
+ }
+
+ return failures;
+}
+
+bool WorldServer::damageWouldDestroy(Vec2I const& pos, TileLayer layer, TileDamage const& tileDamage) const {
+ return WorldImpl::damageWouldDestroy(m_tileArray, pos, layer, tileDamage);
+}
+
TileDamageResult WorldServer::damageTiles(List<Vec2I> const& positions, TileLayer layer, Vec2F const& sourcePosition, TileDamage const& damage, Maybe<EntityId> sourceEntity) {
Set<Vec2I> positionSet;
for (auto const& pos : positions)
@@ -929,20 +986,11 @@ TileDamageResult WorldServer::damageTiles(List<Vec2I> const& positions, TileLaye
// Penetrating damage should carry through to the blocks behind this
// entity.
if (tileRes == TileDamageResult::None || tileDamageIsPenetrating(tileDamage.type)) {
- auto materialDatabase = Root::singleton().materialDatabase();
+ auto damageParameters = WorldImpl::tileDamageParameters(tile, layer, tileDamage);
if (layer == TileLayer::Foreground && isRealMaterial(tile->foreground)) {
if (!tile->rootSource) {
- if (isRealMod(tile->foregroundMod)) {
- if (tileDamageIsPenetrating(tileDamage.type))
- tile->foregroundDamage.damage(materialDatabase->materialDamageParameters(tile->foreground), sourcePosition, tileDamage);
- else if (materialDatabase->modBreaksWithTile(tile->foregroundMod))
- tile->foregroundDamage.damage(materialDatabase->modDamageParameters(tile->foregroundMod).sum(materialDatabase->materialDamageParameters(tile->foreground)), sourcePosition, tileDamage);
- else
- tile->foregroundDamage.damage(materialDatabase->modDamageParameters(tile->foregroundMod), sourcePosition, tileDamage);
- } else {
- tile->foregroundDamage.damage(materialDatabase->materialDamageParameters(tile->foreground), sourcePosition, tileDamage);
- }
+ tile->foregroundDamage.damage(damageParameters, sourcePosition, tileDamage);
// if the tile is broken, send a message back to the source entity with position, layer, dungeonId, and whether the tile was harvested
if (sourceEntity.isValid() && tile->foregroundDamage.dead()) {
@@ -964,16 +1012,7 @@ TileDamageResult WorldServer::damageTiles(List<Vec2I> const& positions, TileLaye
tileRes = TileDamageResult::Normal;
}
} else if (layer == TileLayer::Background && isRealMaterial(tile->background)) {
- if (isRealMod(tile->backgroundMod)) {
- if (tileDamageIsPenetrating(tileDamage.type))
- tile->backgroundDamage.damage(materialDatabase->materialDamageParameters(tile->background), sourcePosition, tileDamage);
- else if (materialDatabase->modBreaksWithTile(tile->backgroundMod))
- tile->backgroundDamage.damage(materialDatabase->modDamageParameters(tile->backgroundMod).sum(materialDatabase->materialDamageParameters(tile->background)), sourcePosition, tileDamage);
- else
- tile->backgroundDamage.damage(materialDatabase->modDamageParameters(tile->backgroundMod), sourcePosition, tileDamage);
- } else {
- tile->backgroundDamage.damage(materialDatabase->materialDamageParameters(tile->background), sourcePosition, tileDamage);
- }
+ tile->backgroundDamage.damage(damageParameters, sourcePosition, tileDamage);
// if the tile is broken, send a message back to the source entity with position and whether the tile was harvested
if (sourceEntity.isValid() && tile->backgroundDamage.dead()) {
@@ -1394,7 +1433,7 @@ Maybe<unsigned> WorldServer::shouldRunThisStep(String const& timingConfiguration
return {};
}
-TileModificationList WorldServer::doApplyTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap, bool ignoreTileProtection) {
+TileModificationList WorldServer::doApplyTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap, bool ignoreTileProtection, bool updateNeighbors) {
auto materialDatabase = Root::singleton().materialDatabase();
TileModificationList unapplied = modificationList;
@@ -1454,9 +1493,12 @@ TileModificationList WorldServer::doApplyTileModifications(TileModificationList
tile->dungeonId = ConstructionDungeonId;
- checkEntityBreaks(RectF::withSize(Vec2F(pos), Vec2F(1, 1)));
- m_liquidEngine->visitLocation(pos);
- m_fallingBlocksAgent->visitLocation(pos);
+ if (updateNeighbors) {
+ checkEntityBreaks(RectF::withSize(Vec2F(pos), Vec2F(1, 1)));
+ m_liquidEngine->visitLocation(pos);
+ m_fallingBlocksAgent->visitLocation(pos);
+ }
+
if (placeMaterial->layer == TileLayer::Foreground)
dirtyCollision(RectI::withSize(pos, {1, 1}));
queueTileUpdates(pos);
@@ -1737,7 +1779,7 @@ void WorldServer::setLiquid(Vec2I const& pos, LiquidId liquid, float level, floa
}
}
-List<ItemDescriptor> WorldServer::destroyBlock(TileLayer layer, Vec2I const& pos, bool genItems, bool destroyModFirst) {
+List<ItemDescriptor> WorldServer::destroyBlock(TileLayer layer, Vec2I const& pos, bool genItems, bool destroyModFirst, bool updateNeighbors) {
auto materialDatabase = Root::singleton().materialDatabase();
auto* tile = m_tileArray->modifyTile(pos);
@@ -1803,9 +1845,11 @@ List<ItemDescriptor> WorldServer::destroyBlock(TileLayer layer, Vec2I const& pos
tile->dungeonId = DestroyedBlockDungeonId;
- checkEntityBreaks(RectF::withSize(Vec2F(pos), Vec2F(1, 1)));
- m_liquidEngine->visitLocation(pos);
- m_fallingBlocksAgent->visitLocation(pos);
+ if (updateNeighbors) {
+ checkEntityBreaks(RectF::withSize(Vec2F(pos), Vec2F(1, 1)));
+ m_liquidEngine->visitLocation(pos);
+ m_fallingBlocksAgent->visitLocation(pos);
+ }
queueTileUpdates(pos);
queueTileDamageUpdates(pos, layer);