| 1615 | } |
| 1616 | |
| 1617 | void WorldServer::updateTileEntityTiles(TileEntityPtr const& entity, bool removing, bool checkBreaks) { |
| 1618 | // This method of updating tile entity collision only works if each tile |
| 1619 | // entity's collision spaces are a subset of their normal spaces, and thus no |
| 1620 | // two tile entities can have collision spaces that overlap. |
| 1621 | // NOTE: Some entities may violate this; it's an odd thing to rely on policy |
| 1622 | // for and maybe we shouldn't allow tile entity configurations to specify |
| 1623 | // material spaces outside of their spaces |
| 1624 | |
| 1625 | auto& spaces = m_tileEntitySpaces[entity->entityId()]; |
| 1626 | |
| 1627 | List<MaterialSpace> newMaterialSpaces = removing ? List<MaterialSpace>() : entity->materialSpaces(); |
| 1628 | List<Vec2I> newRoots = removing || entity->ephemeral() ? List<Vec2I>() : entity->roots(); |
| 1629 | |
| 1630 | if (!removing && spaces.materials == newMaterialSpaces && spaces.roots == newRoots) |
| 1631 | return; |
| 1632 | |
| 1633 | auto materialDatabase = Root::singleton().materialDatabase(); |
| 1634 | |
| 1635 | // remove all old roots |
| 1636 | for (auto const& rootPos : spaces.roots) { |
| 1637 | if (auto tile = m_tileArray->modifyTile(rootPos + entity->tilePosition())) |
| 1638 | tile->rootSource = {}; |
| 1639 | } |
| 1640 | |
| 1641 | // remove all old material spaces |
| 1642 | for (auto const& materialSpace : spaces.materials) { |
| 1643 | Vec2I pos = materialSpace.space + entity->tilePosition(); |
| 1644 | |
| 1645 | ServerTile* tile = m_tileArray->modifyTile(pos); |
| 1646 | if (tile) { |
| 1647 | tile->rootSource = {}; |
| 1648 | bool updatedTile = false; |
| 1649 | bool updatedCollision = false; |
| 1650 | if (isBiomeMaterial(materialSpace.material) || tile->foreground == materialSpace.material) { |
| 1651 | // if the world is old, the materialSpace's collision may still be in the tile |
| 1652 | tile->foreground = EmptyMaterialId; |
| 1653 | tile->foregroundMod = NoModId; |
| 1654 | updatedTile = true; |
| 1655 | updatedCollision = tile->updateCollision(CollisionKind::None); |
| 1656 | } |
| 1657 | if (tile->updateObjectCollision(CollisionKind::None)) |
| 1658 | updatedTile = updatedCollision = true; |
| 1659 | if (updatedCollision) { |
| 1660 | m_liquidEngine->visitLocation(pos); |
| 1661 | m_fallingBlocksAgent->visitLocation(pos); |
| 1662 | dirtyCollision(RectI::withSize(pos, { 1, 1 })); |
| 1663 | } |
| 1664 | if (updatedTile) |
| 1665 | queueTileUpdates(pos); |
| 1666 | } |
| 1667 | } |
| 1668 | |
| 1669 | if (removing) { |
| 1670 | m_tileEntitySpaces.remove(entity->entityId()); |
| 1671 | } else { |
| 1672 | // add new material spaces and update the known material spaces entry |
| 1673 | List<MaterialSpace> passedSpaces; |
| 1674 | for (auto const& materialSpace : newMaterialSpaces) { |
no test coverage detected