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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/game/StarObjectDatabase.cpp4
-rw-r--r--source/game/StarWorldClient.cpp10
-rw-r--r--source/game/StarWorldClient.hpp3
-rw-r--r--source/game/StarWorldImpl.hpp55
-rw-r--r--source/game/StarWorldServer.cpp60
-rw-r--r--source/game/StarWorldServer.hpp3
-rw-r--r--source/game/interfaces/StarTileEntity.hpp6
-rw-r--r--source/game/interfaces/StarWorld.hpp5
8 files changed, 100 insertions, 46 deletions
diff --git a/source/game/StarObjectDatabase.cpp b/source/game/StarObjectDatabase.cpp
index 4c9a968..d886be8 100644
--- a/source/game/StarObjectDatabase.cpp
+++ b/source/game/StarObjectDatabase.cpp
@@ -32,9 +32,9 @@ bool ObjectOrientation::placementValid(World const* world, Vec2I const& position
if (!world)
return false;
- for (auto space : spaces) {
+ for (Vec2I space : spaces) {
space += position;
- if (world->tileIsOccupied(space, TileLayer::Foreground) || world->isTileProtected(space))
+ if (world->tileIsOccupied(space, TileLayer::Foreground, false, true) || world->isTileProtected(space))
return false;
}
return true;
diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp
index 6f4c68d..547c21d 100644
--- a/source/game/StarWorldClient.cpp
+++ b/source/game/StarWorldClient.cpp
@@ -238,10 +238,16 @@ EntityPtr WorldClient::findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEnt
return m_entityMap->findEntityAtTile(pos, entityFilter);
}
-bool WorldClient::tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral) const {
+bool WorldClient::tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral, bool checkCollision) const {
if (!inWorld())
return false;
- return WorldImpl::tileIsOccupied(m_tileArray, m_entityMap, pos, layer, includeEphemeral);
+ return WorldImpl::tileIsOccupied(m_tileArray, m_entityMap, pos, layer, includeEphemeral, checkCollision);
+}
+
+CollisionKind WorldClient::tileCollisionKind(Vec2I const& pos) const {
+ if (!inWorld())
+ return CollisionKind::Null;
+ return WorldImpl::tileCollisionKind(m_tileArray, m_entityMap, pos);
}
void WorldClient::forEachCollisionBlock(RectI const& region, function<void(CollisionBlock const&)> const& iterator) const {
diff --git a/source/game/StarWorldClient.hpp b/source/game/StarWorldClient.hpp
index 7a2a834..7298863 100644
--- a/source/game/StarWorldClient.hpp
+++ b/source/game/StarWorldClient.hpp
@@ -63,7 +63,8 @@ public:
EntityPtr findEntity(RectF const& boundBox, EntityFilter entityFilter) const override;
EntityPtr findEntityLine(Vec2F const& begin, Vec2F const& end, EntityFilter entityFilter) const override;
EntityPtr findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEntity> entityFilter) const override;
- bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false) const override;
+ bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false, bool checkCollision = false) const override;
+ CollisionKind tileCollisionKind(Vec2I const& pos) const override;
void forEachCollisionBlock(RectI const& region, function<void(CollisionBlock const&)> const& iterator) const override;
bool isTileConnectable(Vec2I const& pos, TileLayer layer, bool tilesOnly = false) const override;
bool pointTileCollision(Vec2F const& point, CollisionSet const& collisionSet = DefaultCollisionSet) const override;
diff --git a/source/game/StarWorldImpl.hpp b/source/game/StarWorldImpl.hpp
index 91e03fb..b72b095 100644
--- a/source/game/StarWorldImpl.hpp
+++ b/source/game/StarWorldImpl.hpp
@@ -21,7 +21,11 @@ namespace Star {
namespace WorldImpl {
template <typename TileSectorArray>
bool tileIsOccupied(shared_ptr<TileSectorArray> const& tileSectorArray, EntityMapPtr const& entityMap,
- Vec2I const& pos, TileLayer layer, bool includeEphemeral);
+ Vec2I const& pos, TileLayer layer, bool includeEphemeral, bool checkCollision = false);
+
+ template <typename TileSectorArray>
+ CollisionKind tileCollisionKind(shared_ptr<TileSectorArray> const& tileSectorArray, EntityMapPtr const& entityMap,
+ Vec2I const& pos);
template <typename TileSectorArray>
bool rectTileCollision(shared_ptr<TileSectorArray> const& tileSectorArray, RectI const& region, bool solidCollision);
@@ -38,13 +42,13 @@ namespace WorldImpl {
template <typename GetTileFunction>
bool canPlaceMaterial(EntityMapPtr const& entityMap,
- Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, GetTileFunction& getTile);
+ Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, bool allowTileOverlap, GetTileFunction& getTile);
// returns true if this material could be placed if in the same batch other
// tiles can be placed
// that connect to it
template <typename GetTileFunction>
bool perhapsCanPlaceMaterial(EntityMapPtr const& entityMap,
- Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, GetTileFunction& getTile);
+ Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, bool allowTileOverlap, GetTileFunction& getTile);
template <typename GetTileFunction>
bool canPlaceMaterialColorVariant(Vec2I const& pos, TileLayer layer, MaterialColorVariant color, GetTileFunction& getTile);
template <typename GetTileFunction>
@@ -80,11 +84,18 @@ namespace WorldImpl {
template <typename TileSectorArray>
bool tileIsOccupied(shared_ptr<TileSectorArray> const& tileSectorArray, EntityMapPtr const& entityMap,
- Vec2I const& pos, TileLayer layer, bool includeEphemeral) {
+ Vec2I const& pos, TileLayer layer, bool includeEphemeral, bool checkCollision) {
+ auto& tile = tileSectorArray->tile(pos);
if (layer == TileLayer::Foreground)
- return tileSectorArray->tile(pos).foreground != EmptyMaterialId || entityMap->tileIsOccupied(pos, includeEphemeral);
+ return (checkCollision ? tile.collision >= CollisionKind::Dynamic : tile.foreground != EmptyMaterialId) || entityMap->tileIsOccupied(pos, includeEphemeral);
else
- return tileSectorArray->tile(pos).background != EmptyMaterialId;
+ return tile.background != EmptyMaterialId;
+ }
+
+ template <typename TileSectorArray>
+ CollisionKind tileCollisionKind(shared_ptr<TileSectorArray> const& tileSectorArray, EntityMapPtr const& entityMap,
+ Vec2I const& pos) {
+ return tileSectorArray->tile(pos).collision;
}
template <typename TileSectorArray>
@@ -210,7 +221,7 @@ namespace WorldImpl {
template <typename GetTileFunction>
bool canPlaceMaterial(EntityMapPtr const& entityMap,
- Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, GetTileFunction& getTile) {
+ Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, bool allowTileOverlap, GetTileFunction& getTile) {
auto materialDatabase = Root::singleton().materialDatabase();
if (!isRealMaterial(material))
@@ -239,26 +250,26 @@ namespace WorldImpl {
if (!materialDatabase->canPlaceInLayer(material, layer))
return false;
+ auto& tile = getTile(pos);
if (layer == TileLayer::Background) {
- if (getTile(pos).background != EmptyMaterialId)
+ if (tile.background != EmptyMaterialId && tile.background != ObjectPlatformMaterialId)
return false;
// Can attach background blocks to other background blocks, *or* the
// foreground block in front of it.
- if (!isAdjacentToConnectable(pos, 1, false)
- && !isConnectableMaterial(getTile({pos[0], pos[1]}).foreground))
+ if (!isAdjacentToConnectable(pos, 1, false) && !isConnectableMaterial(tile.foreground))
return false;
} else {
- if (getTile(pos).foreground != EmptyMaterialId)
+ if (tile.foreground != EmptyMaterialId && tile.foreground != ObjectPlatformMaterialId)
return false;
- if (entityMap->tileIsOccupied(pos))
+ if (!allowTileOverlap && entityMap->tileIsOccupied(pos))
return false;
- if (!allowEntityOverlap && entityMap->spaceIsOccupied(RectF::withSize(Vec2F(pos), Vec2F(1, 1))))
+ if (!allowEntityOverlap && entityMap->spaceIsOccupied(RectF::withSize(Vec2F(pos), Vec2F(0.999f, 0.999f))))
return false;
- if (!isAdjacentToConnectable(pos, 1, true) && !isConnectableMaterial(getTile({pos[0], pos[1]}).background))
+ if (!isAdjacentToConnectable(pos, 1, true) && !isConnectableMaterial(tile.background))
return false;
}
@@ -267,7 +278,7 @@ namespace WorldImpl {
template <typename GetTileFunction>
bool perhapsCanPlaceMaterial(EntityMapPtr const& entityMap,
- Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, GetTileFunction& getTile) {
+ Vec2I const& pos, TileLayer layer, MaterialId material, bool allowEntityOverlap, bool allowTileOverlap, GetTileFunction& getTile) {
auto materialDatabase = Root::singleton().materialDatabase();
if (!isRealMaterial(material))
@@ -276,17 +287,18 @@ namespace WorldImpl {
if (!materialDatabase->canPlaceInLayer(material, layer))
return false;
+ auto& tile = getTile(pos);
if (layer == TileLayer::Background) {
- if (getTile(pos).background != EmptyMaterialId)
+ if (tile.background != EmptyMaterialId && tile.background != ObjectPlatformMaterialId)
return false;
} else {
- if (getTile(pos).foreground != EmptyMaterialId)
+ if (tile.foreground != EmptyMaterialId && tile.foreground != ObjectPlatformMaterialId)
return false;
- if (entityMap->tileIsOccupied(pos))
+ if (!allowTileOverlap && entityMap->tileIsOccupied(pos))
return false;
- if (!allowEntityOverlap && entityMap->spaceIsOccupied(RectF::withSize(Vec2F(pos), Vec2F(1, 1))))
+ if (!allowEntityOverlap && entityMap->spaceIsOccupied(RectF::withSize(Vec2F(pos), Vec2F(0.999f, 0.999f))))
return false;
}
@@ -321,9 +333,10 @@ namespace WorldImpl {
bool perhaps = false;
if (auto placeMaterial = modification.ptr<PlaceMaterial>()) {
- perhaps = WorldImpl::perhapsCanPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, getTile);
+ bool allowTileOverlap = placeMaterial->collisionOverride != TileCollisionOverride::None && collisionKindFromOverride(placeMaterial->collisionOverride) < CollisionKind::Dynamic;
+ perhaps = WorldImpl::perhapsCanPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, allowTileOverlap, getTile);
if (perhaps)
- good = WorldImpl::canPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, getTile);
+ good = WorldImpl::canPlaceMaterial(entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, allowTileOverlap, getTile);
} else if (auto placeMod = modification.ptr<PlaceMod>()) {
good = WorldImpl::canPlaceMod(pos, placeMod->layer, placeMod->mod, getTile);
} else if (auto placeMaterialColor = modification.ptr<PlaceMaterialColor>()) {
diff --git a/source/game/StarWorldServer.cpp b/source/game/StarWorldServer.cpp
index 6579c91..26ce363 100644
--- a/source/game/StarWorldServer.cpp
+++ b/source/game/StarWorldServer.cpp
@@ -756,10 +756,15 @@ EntityPtr WorldServer::findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEnt
return m_entityMap->findEntityAtTile(pos, entityFilter);
}
-bool WorldServer::tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral) const {
- return WorldImpl::tileIsOccupied(m_tileArray, m_entityMap, pos, layer, includeEphemeral);
+bool WorldServer::tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral, bool checkCollision) const {
+ return WorldImpl::tileIsOccupied(m_tileArray, m_entityMap, pos, layer, includeEphemeral, checkCollision);
}
+CollisionKind WorldServer::tileCollisionKind(Vec2I const& pos) const {
+ return WorldImpl::tileCollisionKind(m_tileArray, m_entityMap, pos);
+}
+
+
void WorldServer::forEachCollisionBlock(RectI const& region, function<void(CollisionBlock const&)> const& iterator) const {
const_cast<WorldServer*>(this)->freshenCollision(region);
m_tileArray->tileEach(region, [iterator](Vec2I const& pos, ServerTile const& tile) {
@@ -1348,7 +1353,8 @@ TileModificationList WorldServer::doApplyTileModifications(TileModificationList
continue;
if (auto placeMaterial = modification.ptr<PlaceMaterial>()) {
- if (!WorldImpl::canPlaceMaterial(m_entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, m_tileGetterFunction))
+ bool allowTileOverlap = placeMaterial->collisionOverride != TileCollisionOverride::None && collisionKindFromOverride(placeMaterial->collisionOverride) < CollisionKind::Dynamic;
+ if (!WorldImpl::canPlaceMaterial(m_entityMap, pos, placeMaterial->layer, placeMaterial->material, allowEntityOverlap, allowTileOverlap, m_tileGetterFunction))
continue;
ServerTile* tile = m_tileArray->modifyTile(pos);
@@ -1498,15 +1504,22 @@ void WorldServer::updateTileEntityTiles(TileEntityPtr const& entity, bool removi
ServerTile* tile = m_tileArray->modifyTile(pos);
if (tile) {
- tile->foreground = EmptyMaterialId;
- tile->foregroundMod = NoModId;
- tile->rootSource = {};
- if (tile->updateCollision(materialDatabase->materialCollisionKind(tile->foreground))) {
+ bool updated = false;
+ if (tile->foreground == materialSpace.material) {
+ tile->foreground = EmptyMaterialId;
+ tile->foregroundMod = NoModId;
+ tile->rootSource = {};
+ updated = true;
+ }
+ if (tile->collision == materialDatabase->materialCollisionKind(materialSpace.material)
+ && tile->updateCollision(materialSpace.prevCollision.value(CollisionKind::None))) {
m_liquidEngine->visitLocation(pos);
m_fallingBlocksAgent->visitLocation(pos);
- dirtyCollision(RectI::withSize(pos, {1, 1}));
+ dirtyCollision(RectI::withSize(pos, { 1, 1 }));
+ updated = true;
}
- queueTileUpdates(pos);
+ if (updated)
+ queueTileUpdates(pos);
}
}
@@ -1515,24 +1528,37 @@ void WorldServer::updateTileEntityTiles(TileEntityPtr const& entity, bool removi
} else {
// add new material spaces and update the known material spaces entry
+ List<MaterialSpace> passedSpaces;
for (auto const& materialSpace : newMaterialSpaces) {
Vec2I pos = materialSpace.space + entity->tilePosition();
+ bool updated = false;
+ bool updatedCollision = false;
ServerTile* tile = m_tileArray->modifyTile(pos);
- if (tile) {
+ if (tile && (tile->foreground == EmptyMaterialId || tile->foreground == materialSpace.material)) {
tile->foreground = materialSpace.material;
tile->foregroundMod = NoModId;
if (isRealMaterial(materialSpace.material))
tile->rootSource = entity->tilePosition();
- if (tile->updateCollision(materialDatabase->materialCollisionKind(tile->foreground))) {
- m_liquidEngine->visitLocation(pos);
- m_fallingBlocksAgent->visitLocation(pos);
- dirtyCollision(RectI::withSize(pos, {1, 1}));
- }
- queueTileUpdates(pos);
+ passedSpaces.emplaceAppend(materialSpace).prevCollision.emplace(tile->collision);
+ updatedCollision = tile->updateCollision(materialDatabase->materialCollisionKind(tile->foreground));
+ updated = true;
+ passedSpaces.emplaceAppend(materialSpace);
+ }
+ else if (tile && tile->collision < CollisionKind::Dynamic) {
+ passedSpaces.emplaceAppend(materialSpace).prevCollision.emplace(tile->collision);
+ updatedCollision = tile->updateCollision(materialDatabase->materialCollisionKind(materialSpace.material));
+ updated = true;
}
+ if (updatedCollision) {
+ m_liquidEngine->visitLocation(pos);
+ m_fallingBlocksAgent->visitLocation(pos);
+ dirtyCollision(RectI::withSize(pos, { 1, 1 }));
+ }
+ if (updated)
+ queueTileUpdates(pos);
}
- spaces.materials = move(newMaterialSpaces);
+ spaces.materials = move(passedSpaces);
// add new roots and update known roots entry
for (auto const& rootPos : newRoots) {
diff --git a/source/game/StarWorldServer.hpp b/source/game/StarWorldServer.hpp
index 7e14efa..24436b6 100644
--- a/source/game/StarWorldServer.hpp
+++ b/source/game/StarWorldServer.hpp
@@ -144,7 +144,8 @@ public:
EntityPtr findEntity(RectF const& boundBox, EntityFilter entityFilter) const override;
EntityPtr findEntityLine(Vec2F const& begin, Vec2F const& end, EntityFilter entityFilter) const override;
EntityPtr findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEntity> entityFilter) const override;
- bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false) const override;
+ bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false, bool checkCollision = false) const override;
+ CollisionKind tileCollisionKind(Vec2I const& pos) const override;
void forEachCollisionBlock(RectI const& region, function<void(CollisionBlock const&)> const& iterator) const override;
bool isTileConnectable(Vec2I const& pos, TileLayer layer, bool tilesOnly = false) const override;
bool pointTileCollision(Vec2F const& point, CollisionSet const& collisionSet = DefaultCollisionSet) const override;
diff --git a/source/game/interfaces/StarTileEntity.hpp b/source/game/interfaces/StarTileEntity.hpp
index 86c01b6..c9037e5 100644
--- a/source/game/interfaces/StarTileEntity.hpp
+++ b/source/game/interfaces/StarTileEntity.hpp
@@ -4,6 +4,7 @@
#include "StarEntity.hpp"
#include "StarTileDamage.hpp"
#include "StarInteractiveEntity.hpp"
+#include "StarCollisionBlock.hpp"
namespace Star {
@@ -17,6 +18,7 @@ struct MaterialSpace {
Vec2I space;
MaterialId material;
+ Maybe<CollisionKind> prevCollision;
};
DataStream& operator<<(DataStream& ds, MaterialSpace const& materialSpace);
@@ -89,7 +91,9 @@ inline MaterialSpace::MaterialSpace(Vec2I space, MaterialId material)
: space(space), material(material) {}
inline bool MaterialSpace::operator==(MaterialSpace const& rhs) const {
- return tie(space, material) == tie(rhs.space, rhs.material);
+ return space == rhs.space
+ && material == rhs.material
+ && prevCollision == rhs.prevCollision;
}
}
diff --git a/source/game/interfaces/StarWorld.hpp b/source/game/interfaces/StarWorld.hpp
index f2af197..9c97be5 100644
--- a/source/game/interfaces/StarWorld.hpp
+++ b/source/game/interfaces/StarWorld.hpp
@@ -76,7 +76,10 @@ public:
virtual EntityPtr findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEntity> entityFilter) const = 0;
// Is the given tile layer and position occupied by an entity or block?
- virtual bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false) const = 0;
+ virtual bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false, bool checkCollision = false) const = 0;
+
+ // Returns the collision kind of a tile.
+ virtual CollisionKind tileCollisionKind(Vec2I const& pos) const = 0;
// Iterate over the collision block for each tile in the region. Collision
// polys for tiles can extend to a maximum of 1 tile outside of the natural