Delayed floating block detection in hopes that #216 is fixed
This commit is contained in:
parent
3f9d454460
commit
87185910f5
@ -29,7 +29,7 @@ namespace spades {
|
||||
|
||||
struct CellPos {
|
||||
short x, y, z;
|
||||
CellPos(){}
|
||||
CellPos() = default;
|
||||
CellPos(int xx, int yy, int zz):
|
||||
x(xx), y(yy), z(zz){}
|
||||
|
||||
@ -52,6 +52,22 @@ namespace spades {
|
||||
|
||||
};
|
||||
|
||||
struct CellPosHash {
|
||||
inline std::size_t operator () (const CellPos& pos) const {
|
||||
std::size_t ret;
|
||||
if(sizeof(std::size_t) > 4) {
|
||||
ret = pos.x; ret <<= 16;
|
||||
ret |= pos.y; ret <<= 16;
|
||||
ret |= pos.z;
|
||||
}else{
|
||||
ret = pos.x; ret <<= 16;
|
||||
ret |= pos.y;
|
||||
ret ^= pos.z;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
/** Wraps GameMap and provides floating-block detection.*/
|
||||
class GameMapWrapper {
|
||||
friend class Client; // FIXME: for debug
|
||||
@ -99,3 +115,5 @@ namespace spades {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "IWorldListener.h"
|
||||
#include <Core/Settings.h>
|
||||
#include "HitTestDebugger.h"
|
||||
#include <deque>
|
||||
|
||||
SPADES_SETTING(cg_debugHitTest, "0");
|
||||
|
||||
@ -82,6 +83,8 @@ namespace spades {
|
||||
void World::Advance(float dt) {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
ApplyBlockActions();
|
||||
|
||||
for(size_t i = 0; i < players.size(); i++)
|
||||
if(players[i])
|
||||
players[i]->Update(dt);
|
||||
@ -158,15 +161,123 @@ namespace spades {
|
||||
mode = m;
|
||||
}
|
||||
|
||||
static std::vector<std::vector<CellPos>> ClusterizeBlocks(const std::vector<CellPos>& blocks) {
|
||||
std::unordered_map<CellPos, bool, CellPosHash> blockMap;
|
||||
for(const auto& block: blocks) {
|
||||
blockMap[block] = true;
|
||||
}
|
||||
|
||||
std::vector<std::vector<CellPos>> ret;
|
||||
std::deque<decltype(blockMap)::iterator> queue;
|
||||
|
||||
ret.reserve(64);
|
||||
// wish I could `reserve()` queue...
|
||||
|
||||
std::size_t addedCount = 0;
|
||||
|
||||
for(auto it = blockMap.begin(); it != blockMap.end(); it++) {
|
||||
SPAssert(queue.empty());
|
||||
|
||||
if(!it->second) continue;
|
||||
queue.emplace_back(it);
|
||||
|
||||
std::vector<CellPos> outBlocks;
|
||||
|
||||
while(!queue.empty()) {
|
||||
auto blockitem = queue.front();
|
||||
queue.pop_front();
|
||||
|
||||
if(!blockitem->second) continue;
|
||||
|
||||
auto pos = blockitem->first;
|
||||
outBlocks.emplace_back(pos);
|
||||
blockitem->second = false;
|
||||
|
||||
decltype(blockMap)::iterator nextIt;
|
||||
|
||||
nextIt = blockMap.find(CellPos(pos.x - 1, pos.y, pos.z));
|
||||
if(nextIt != blockMap.end() && nextIt->second) {
|
||||
queue.emplace_back(nextIt);
|
||||
}
|
||||
nextIt = blockMap.find(CellPos(pos.x + 1, pos.y, pos.z));
|
||||
if(nextIt != blockMap.end() && nextIt->second) {
|
||||
queue.emplace_back(nextIt);
|
||||
}
|
||||
nextIt = blockMap.find(CellPos(pos.x, pos.y - 1, pos.z));
|
||||
if(nextIt != blockMap.end() && nextIt->second) {
|
||||
queue.emplace_back(nextIt);
|
||||
}
|
||||
nextIt = blockMap.find(CellPos(pos.x, pos.y + 1, pos.z));
|
||||
if(nextIt != blockMap.end() && nextIt->second) {
|
||||
queue.emplace_back(nextIt);
|
||||
}
|
||||
nextIt = blockMap.find(CellPos(pos.x, pos.y, pos.z - 1));
|
||||
if(nextIt != blockMap.end() && nextIt->second) {
|
||||
queue.emplace_back(nextIt);
|
||||
}
|
||||
nextIt = blockMap.find(CellPos(pos.x, pos.y, pos.z + 1));
|
||||
if(nextIt != blockMap.end() && nextIt->second) {
|
||||
queue.emplace_back(nextIt);
|
||||
}
|
||||
}
|
||||
|
||||
SPAssert(!outBlocks.empty());
|
||||
addedCount += outBlocks.size();
|
||||
ret.emplace_back(std::move(outBlocks));
|
||||
}
|
||||
|
||||
SPAssert(addedCount == blocks.size());
|
||||
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
void World::ApplyBlockActions() {
|
||||
for(const auto& creation: createdBlocks) {
|
||||
const auto& pos = creation.first;
|
||||
const auto& color = creation.second;
|
||||
if(map->IsSolid(pos.x, pos.y, pos.z))
|
||||
continue;
|
||||
mapWrapper->AddBlock(pos.x, pos.y, pos.z,
|
||||
color.x |
|
||||
(color.y << 8) |
|
||||
(color.z << 16) |
|
||||
(100UL << 24));
|
||||
}
|
||||
|
||||
std::vector<CellPos> cells;
|
||||
for(const auto& cell: destroyedBlocks) {
|
||||
if(!map->IsSolid(cell.x, cell.y, cell.z))
|
||||
continue;
|
||||
cells.emplace_back(cell);
|
||||
}
|
||||
|
||||
cells = mapWrapper->RemoveBlocks(cells);
|
||||
|
||||
auto clusters = ClusterizeBlocks(cells);
|
||||
std::vector<IntVector3> cells2;
|
||||
|
||||
for(const auto& cluster: clusters) {
|
||||
cells2.resize(cluster.size());
|
||||
for(std::size_t i = 0; i < cluster.size(); i++) {
|
||||
auto p = cluster[i];
|
||||
cells2[i] = IntVector3(p.x, p.y, p.z);
|
||||
map->Set(p.x, p.y, p.z, false, 0);
|
||||
}
|
||||
if(listener)
|
||||
listener->BlocksFell(cells2);
|
||||
}
|
||||
|
||||
createdBlocks.clear();
|
||||
destroyedBlocks.clear();
|
||||
}
|
||||
|
||||
void World::CreateBlock(spades::IntVector3 pos,
|
||||
spades::IntVector3 color) {
|
||||
if(map->IsSolid(pos.x, pos.y, pos.z))
|
||||
return;
|
||||
mapWrapper->AddBlock(pos.x, pos.y, pos.z,
|
||||
color.x |
|
||||
(color.y << 8) |
|
||||
(color.z << 16) |
|
||||
(100UL << 24));
|
||||
auto it = destroyedBlocks.find(CellPos(pos.x, pos.y, pos.z));
|
||||
if(it != destroyedBlocks.end())
|
||||
destroyedBlocks.erase(it);
|
||||
|
||||
createdBlocks[CellPos(pos.x, pos.y, pos.z)] = color;
|
||||
}
|
||||
void World::DestroyBlock(std::vector<spades::IntVector3>& pos){
|
||||
std::vector<CellPos> cells;
|
||||
@ -176,27 +287,14 @@ namespace spades {
|
||||
if(p.z >= (allowToDestroyLand ? 63 : 62) || p.z < 0 || p.x < 0 || p.y < 0 ||
|
||||
p.x >= map->Width() || p.y >= map->Height())
|
||||
continue;
|
||||
if(!map->IsSolid(p.x, p.y, p.z))
|
||||
continue;
|
||||
cells.push_back(CellPos(p.x,p.y,p.z));
|
||||
|
||||
CellPos cellp(p.x, p.y, p.z);
|
||||
auto it = createdBlocks.find(cellp);
|
||||
if(it != createdBlocks.end())
|
||||
createdBlocks.erase(it);
|
||||
destroyedBlocks.insert(cellp);
|
||||
}
|
||||
|
||||
cells = mapWrapper->RemoveBlocks(cells);
|
||||
|
||||
for(size_t i =0 ; i < cells.size(); i++){
|
||||
CellPos& p = cells[i];
|
||||
map->Set(p.x, p.y, p.z, false, 0);
|
||||
}
|
||||
|
||||
std::vector<IntVector3> cells2;
|
||||
for(size_t i =0 ; i < cells.size(); i++){
|
||||
cells2.push_back(IntVector3::Make(cells[i].x,
|
||||
cells[i].y,
|
||||
cells[i].z));
|
||||
}
|
||||
|
||||
if(listener)
|
||||
listener->BlocksFell(cells2);
|
||||
}
|
||||
|
||||
World::PlayerPersistent& World::GetPlayerPersistent(int index) {
|
||||
|
@ -27,6 +27,9 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include "GameMapWrapper.h"
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace spades {
|
||||
namespace client {
|
||||
@ -68,6 +71,11 @@ namespace spades {
|
||||
std::list<Grenade *> grenades;
|
||||
std::unique_ptr<HitTestDebugger> hitTestDebugger;
|
||||
|
||||
std::unordered_map<CellPos, spades::IntVector3, CellPosHash> createdBlocks;
|
||||
std::unordered_set<CellPos, CellPosHash> destroyedBlocks;
|
||||
|
||||
void ApplyBlockActions();
|
||||
|
||||
public:
|
||||
World();
|
||||
~World();
|
||||
|
Loading…
x
Reference in New Issue
Block a user