//send to client
size_t i = 0;
for (Creature* spectator : spectators) {
if (Player* tmpPlayer = spectator->getPlayer()) {
//Use the correct stackpos
int32_t stackpos = oldStackPosVector[i++];
if (stackpos != -1) {
tmpPlayer->sendCreatureMove(&creature, newPos, newTile.getClientIndexOfCreature(tmpPlayer, &creature), oldPos, stackpos, teleport);
}
}
}
//event method
for (Creature* spectator : spectators) {
spectator->onCreatureMove(&creature, &newTile, newPos, &oldTile, oldPos, teleport);
}
oldTile.postRemoveNotification(&creature, &newTile, 0);
newTile.postAddNotification(&creature, &oldTile, 0);
}
void Map::getSpectatorsInternal(SpectatorVec& spectators, const Position& centerPos, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, int32_t minRangeZ, int32_t maxRangeZ, bool onlyPlayers) const
{
int_fast16_t min_y = centerPos.y + minRangeY;
int_fast16_t min_x = centerPos.x + minRangeX;
int_fast16_t max_y = centerPos.y + maxRangeY;
int_fast16_t max_x = centerPos.x + maxRangeX;
int32_t minoffset = centerPos.getZ() - maxRangeZ;
uint16_t x1 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (min_x + minoffset)));
uint16_t y1 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (min_y + minoffset)));
int32_t maxoffset = centerPos.getZ() - minRangeZ;
uint16_t x2 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (max_x + maxoffset)));
uint16_t y2 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (max_y + maxoffset)));
int32_t startx1 = x1 - (x1 % FLOOR_SIZE);
int32_t starty1 = y1 - (y1 % FLOOR_SIZE);
int32_t endx2 = x2 - (x2 % FLOOR_SIZE);
int32_t endy2 = y2 - (y2 % FLOOR_SIZE);
const QTreeLeafNode* startLeaf = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, startx1, starty1);
const QTreeLeafNode* leafS = startLeaf;
const QTreeLeafNode* leafE;
for (int_fast32_t ny = starty1; ny <= endy2; ny += FLOOR_SIZE) {
leafE = leafS;
for (int_fast32_t nx = startx1; nx <= endx2; nx += FLOOR_SIZE) {
if (leafE) {
const CreatureVector& node_list = (onlyPlayers ? leafE->player_list : leafE->creature_list);
for (Creature* creature : node_list) {
const Position& cpos = creature->getPosition();
if (minRangeZ > cpos.z || maxRangeZ < cpos.z) {
continue;
}
int_fast16_t offsetZ = Position::getOffsetZ(centerPos, cpos);
if ((min_y + offsetZ) > cpos.y || (max_y + offsetZ) < cpos.y || (min_x + offsetZ) > cpos.x || (max_x + offsetZ) < cpos.x) {
continue;
}
spectators.emplace_back(creature);
}
leafE = leafE->leafE;
} else {
leafE = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, nx + FLOOR_SIZE, ny);
}
}
if (leafS) {
leafS = leafS->leafS;
} else {
leafS = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, startx1, ny + FLOOR_SIZE);
}
}
}
void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, bool multifloor /*= false*/, bool onlyPlayers /*= false*/, int32_t minRangeX /*= 0*/, int32_t maxRangeX /*= 0*/, int32_t minRangeY /*= 0*/, int32_t maxRangeY /*= 0*/)
{
if (centerPos.z >= MAP_MAX_LAYERS) {
return;
}
bool foundCache = false;
bool cacheResult = false;
minRangeX = (minRangeX == 0 ? -maxViewportX : -minRangeX);
maxRangeX = (maxRangeX == 0 ? maxViewportX : maxRangeX);
minRangeY = (minRangeY == 0 ? -maxViewportY : -minRangeY);
maxRangeY = (maxRangeY == 0 ? maxViewportY : maxRangeY);
if (minRangeX == -maxViewportX && maxRangeX == maxViewportX && minRangeY == -maxViewportY && maxRangeY == maxViewportY && multifloor) {
if (onlyPlayers) {
auto it = playersSpectatorCache.find(centerPos);
if (it != playersSpectatorCache.end()) {
if (!spectators.empty()) {
spectators.addSpectators(it->second);
} else {
spectators = it->second;
}
foundCache = true;
}
}
if (!foundCache) {
auto it = spectatorCache.find(centerPos);
if (it != spectatorCache.end()) {
if (!onlyPlayers) {
if (!spectators.empty()) {
const SpectatorVec& cachedSpectators = it->second;
spectators.addSpectators(cachedSpectators);
} else {
spectators = it->second;
}
} else {
const SpectatorVec& cachedSpectators = it->second;
for (Creature* spectator : cachedSpectators) {
if (spectator->getPlayer()) {
spectators.emplace_back(spectator);
}
}
}
foundCache = true;
} else {
cacheResult = true;
}
}
}
if (!foundCache) {
int32_t minRangeZ;
int32_t maxRangeZ;
if (multifloor) {
if (centerPos.z > 7) {
//underground (8->15)
minRangeZ = std::max<int32_t>(centerPos.getZ() - 2, 0);
maxRangeZ = std::min<int32_t>(centerPos.getZ() + 2, MAP_MAX_LAYERS - 1);
} else if (centerPos.z == 6) {
minRangeZ = 0;
maxRangeZ = 8;
} else if (centerPos.z == 7) {
minRangeZ = 0;
maxRangeZ = 9;
} else {
minRangeZ = 0;
maxRangeZ = 7;
}
} else {
minRangeZ = centerPos.z;
maxRangeZ = centerPos.z;
}
getSpectatorsInternal(spectators, centerPos, minRangeX, maxRangeX, minRangeY, maxRangeY, minRangeZ, maxRangeZ, onlyPlayers);
if (cacheResult) {
if (onlyPlayers) {
playersSpectatorCache[centerPos] = spectators;
} else {
spectatorCache[centerPos] = spectators;
}
}
}
}