Optimize map view zoomout performance
This commit is contained in:
parent
aef3a5b8db
commit
e2921c6407
|
@ -38,8 +38,8 @@ Game g_game;
|
||||||
Game::Game()
|
Game::Game()
|
||||||
{
|
{
|
||||||
resetGameStates();
|
resetGameStates();
|
||||||
//setProtocolVersion(960);
|
|
||||||
m_protocolVersion = 0;
|
m_protocolVersion = 0;
|
||||||
|
setProtocolVersion(PROTOCOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::resetGameStates()
|
void Game::resetGameStates()
|
||||||
|
|
|
@ -553,10 +553,11 @@ void Map::clean()
|
||||||
m_tiles.clear();
|
m_tiles.clear();
|
||||||
m_waypoints.clear();
|
m_waypoints.clear();
|
||||||
|
|
||||||
// This is a fix to a segfault on exit.
|
|
||||||
m_towns.clear();
|
m_towns.clear();
|
||||||
m_houses.clear();
|
m_houses.clear();
|
||||||
m_creatures.clear();
|
m_creatures.clear();
|
||||||
|
m_monsters.clear();
|
||||||
|
m_tilesRect = Rect(65534, 65534, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::cleanDynamicThings()
|
void Map::cleanDynamicThings()
|
||||||
|
@ -693,15 +694,26 @@ TilePtr Map::createTile(const Position& pos)
|
||||||
{
|
{
|
||||||
TilePtr tile = TilePtr(new Tile(pos));
|
TilePtr tile = TilePtr(new Tile(pos));
|
||||||
m_tiles[pos] = tile;
|
m_tiles[pos] = tile;
|
||||||
|
if(pos.x < m_tilesRect.left())
|
||||||
|
m_tilesRect.setLeft(pos.x);
|
||||||
|
if(pos.y < m_tilesRect.top())
|
||||||
|
m_tilesRect.setTop(pos.y);
|
||||||
|
if(pos.x > m_tilesRect.right())
|
||||||
|
m_tilesRect.setRight(pos.x);
|
||||||
|
if(pos.y > m_tilesRect.bottom())
|
||||||
|
m_tilesRect.setBottom(pos.y);
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TilePtr& Map::getTile(const Position& pos)
|
const TilePtr& Map::getTile(const Position& pos)
|
||||||
{
|
{
|
||||||
|
static TilePtr nulltile;
|
||||||
|
if(!m_tilesRect.contains(Point(pos.x, pos.y)))
|
||||||
|
return nulltile;
|
||||||
|
|
||||||
auto it = m_tiles.find(pos);
|
auto it = m_tiles.find(pos);
|
||||||
if(it != m_tiles.end())
|
if(it != m_tiles.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
static TilePtr nulltile;
|
|
||||||
return nulltile;
|
return nulltile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,6 +185,7 @@ private:
|
||||||
|
|
||||||
Light m_light;
|
Light m_light;
|
||||||
Position m_centralPosition;
|
Position m_centralPosition;
|
||||||
|
Rect m_tilesRect;
|
||||||
|
|
||||||
std::string m_description, m_spawnFile, m_houseFile;
|
std::string m_description, m_spawnFile, m_houseFile;
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ MapView::MapView()
|
||||||
m_lockedFirstVisibleFloor = -1;
|
m_lockedFirstVisibleFloor = -1;
|
||||||
m_cachedFirstVisibleFloor = 7;
|
m_cachedFirstVisibleFloor = 7;
|
||||||
m_cachedLastVisibleFloor = 7;
|
m_cachedLastVisibleFloor = 7;
|
||||||
|
m_updateTilesPos = 0;
|
||||||
m_optimizedSize = Size(Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES) * Otc::TILE_PIXELS;
|
m_optimizedSize = Size(Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES) * Otc::TILE_PIXELS;
|
||||||
|
|
||||||
m_framebuffer = g_framebuffers.createFrameBuffer();
|
m_framebuffer = g_framebuffers.createFrameBuffer();
|
||||||
|
@ -57,8 +58,8 @@ MapView::~MapView()
|
||||||
void MapView::draw(const Rect& rect)
|
void MapView::draw(const Rect& rect)
|
||||||
{
|
{
|
||||||
// update visible tiles cache when needed
|
// update visible tiles cache when needed
|
||||||
if(m_mustUpdateVisibleTilesCache)
|
if(m_mustUpdateVisibleTilesCache || m_updateTilesPos > 0)
|
||||||
updateVisibleTilesCache();
|
updateVisibleTilesCache(m_mustUpdateVisibleTilesCache ? 0 : m_updateTilesPos);
|
||||||
|
|
||||||
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
|
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
|
||||||
Position cameraPosition = getCameraPosition();
|
Position cameraPosition = getCameraPosition();
|
||||||
|
@ -67,14 +68,8 @@ void MapView::draw(const Rect& rect)
|
||||||
if(m_viewMode == NEAR_VIEW)
|
if(m_viewMode == NEAR_VIEW)
|
||||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls |
|
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls |
|
||||||
Otc::DrawItems | Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawMissiles | Otc::DrawAnimations;
|
Otc::DrawItems | Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawMissiles | Otc::DrawAnimations;
|
||||||
else if(m_viewMode == MID_VIEW)
|
else
|
||||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawItems;
|
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawItems;
|
||||||
else if(m_viewMode == FAR_VIEW)
|
|
||||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls;
|
|
||||||
else if(m_tileSize >= 4) // HUGE_VIEW 1
|
|
||||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders;
|
|
||||||
else // HUGE_VIEW 2
|
|
||||||
drawFlags = Otc::DrawGround;
|
|
||||||
|
|
||||||
Size tileSize = Size(1,1) * m_tileSize;
|
Size tileSize = Size(1,1) * m_tileSize;
|
||||||
if(m_mustDrawVisibleTilesCache || (drawFlags & Otc::DrawAnimations)) {
|
if(m_mustDrawVisibleTilesCache || (drawFlags & Otc::DrawAnimations)) {
|
||||||
|
@ -244,11 +239,6 @@ void MapView::draw(const Rect& rect)
|
||||||
void MapView::updateVisibleTilesCache(int start)
|
void MapView::updateVisibleTilesCache(int start)
|
||||||
{
|
{
|
||||||
if(start == 0) {
|
if(start == 0) {
|
||||||
if(m_updateTilesCacheEvent) {
|
|
||||||
m_updateTilesCacheEvent->cancel();
|
|
||||||
m_updateTilesCacheEvent = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_cachedFirstVisibleFloor = calcFirstVisibleFloor();
|
m_cachedFirstVisibleFloor = calcFirstVisibleFloor();
|
||||||
m_cachedLastVisibleFloor = calcLastVisibleFloor();
|
m_cachedLastVisibleFloor = calcLastVisibleFloor();
|
||||||
assert(m_cachedFirstVisibleFloor >= 0 && m_cachedLastVisibleFloor >= 0 &&
|
assert(m_cachedFirstVisibleFloor >= 0 && m_cachedLastVisibleFloor >= 0 &&
|
||||||
|
@ -263,6 +253,7 @@ void MapView::updateVisibleTilesCache(int start)
|
||||||
m_mustCleanFramebuffer = true;
|
m_mustCleanFramebuffer = true;
|
||||||
m_mustDrawVisibleTilesCache = true;
|
m_mustDrawVisibleTilesCache = true;
|
||||||
m_mustUpdateVisibleTilesCache = false;
|
m_mustUpdateVisibleTilesCache = false;
|
||||||
|
m_updateTilesPos = 0;
|
||||||
} else
|
} else
|
||||||
m_mustCleanFramebuffer = false;
|
m_mustCleanFramebuffer = false;
|
||||||
|
|
||||||
|
@ -271,12 +262,12 @@ void MapView::updateVisibleTilesCache(int start)
|
||||||
if(!cameraPosition.isValid())
|
if(!cameraPosition.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
bool stop = false;
|
bool stop = false;
|
||||||
|
|
||||||
// clear current visible tiles cache
|
// clear current visible tiles cache
|
||||||
m_cachedVisibleTiles.clear();
|
m_cachedVisibleTiles.clear();
|
||||||
m_mustDrawVisibleTilesCache = true;
|
m_mustDrawVisibleTilesCache = true;
|
||||||
|
m_updateTilesPos = 0;
|
||||||
|
|
||||||
// cache visible tiles in draw order
|
// cache visible tiles in draw order
|
||||||
// draw from last floor (the lower) to first floor (the higher)
|
// draw from last floor (the lower) to first floor (the higher)
|
||||||
|
@ -289,13 +280,13 @@ void MapView::updateVisibleTilesCache(int start)
|
||||||
int advance = std::max(diagonal - m_drawDimension.height(), 0);
|
int advance = std::max(diagonal - m_drawDimension.height(), 0);
|
||||||
for(int iy = diagonal - advance, ix = advance; iy >= 0 && ix < m_drawDimension.width() && !stop; --iy, ++ix) {
|
for(int iy = diagonal - advance, ix = advance; iy >= 0 && ix < m_drawDimension.width() && !stop; --iy, ++ix) {
|
||||||
// only start really looking tiles in the desired start
|
// only start really looking tiles in the desired start
|
||||||
if(count < start) {
|
if(m_updateTilesPos < start) {
|
||||||
count++;
|
m_updateTilesPos++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid rendering too much tiles at once on far views
|
// avoid rendering too much tiles at once
|
||||||
if(count - start + 1 > MAX_TILE_UPDATES && m_viewMode >= HUGE_VIEW) {
|
if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS && m_viewMode >= HUGE_VIEW) {
|
||||||
stop = true;
|
stop = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -314,108 +305,63 @@ void MapView::updateVisibleTilesCache(int start)
|
||||||
continue;
|
continue;
|
||||||
m_cachedVisibleTiles.push_back(tile);
|
m_cachedVisibleTiles.push_back(tile);
|
||||||
}
|
}
|
||||||
count++;
|
m_updateTilesPos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
static std::vector<Point> points;
|
// cache tiles in spiral mode
|
||||||
points.clear();
|
static std::vector<Point> m_spiral;
|
||||||
//assert(m_drawDimension.width() % 2 == 0 && m_drawDimension.height() % 2 == 0);
|
if(start == 0) {
|
||||||
Point quadTopLeft(m_drawDimension.width()/2 - 1, m_drawDimension.height()/2 - 1);
|
m_spiral.resize(m_drawDimension.area());
|
||||||
for(int step = 1; !(quadTopLeft.x < 0 && quadTopLeft.y < 0) && !stop; ++step) {
|
int width = m_drawDimension.width();
|
||||||
int quadWidth = std::min(2*step, m_drawDimension.width());
|
int height = m_drawDimension.height();
|
||||||
int quadHeight = std::min(2*step, m_drawDimension.height());
|
int tpx = width/2 - 2;
|
||||||
int fillWidth = (quadTopLeft.x >= 0) ? quadWidth-1 : quadWidth;
|
int tpy = height/2 - 2;
|
||||||
int fillHeight = (quadTopLeft.x >= 0) ? quadHeight-1 : quadHeight;
|
int count = 0;
|
||||||
if(quadTopLeft.y >= 0) {
|
Rect area(0, 0, m_drawDimension);
|
||||||
for(int qx=0;qx<fillWidth;++qx) {
|
m_spiral[count++] = Point(tpx+1,tpy+1);
|
||||||
//TODO: remvoe this repeated code
|
for(int step = 1; tpx >= 0 || tpy >= 0; ++step, --tpx, --tpy) {
|
||||||
// only start really looking tiles in the desired start
|
int qs = 2*step;
|
||||||
if(count < start) {
|
Rect lines[4] = {
|
||||||
count++;
|
Rect(tpx, tpy, qs, 1),
|
||||||
continue;
|
Rect(tpx + qs, tpy, 1, qs),
|
||||||
}
|
Rect(tpx + 1, tpy + qs, qs, 1),
|
||||||
|
Rect(tpx, tpy + 1, 1, qs),
|
||||||
|
};
|
||||||
|
|
||||||
// avoid rendering too much tiles at once on far views
|
for(int i=0;i<4;++i) {
|
||||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
int sx = std::max(lines[i].left(), area.left());
|
||||||
stop = true;
|
int ex = std::min(lines[i].right(), area.right());
|
||||||
break;
|
int sy = std::max(lines[i].top(), area.top());
|
||||||
}
|
int ey = std::min(lines[i].bottom(), area.bottom());
|
||||||
points.push_back(Point(std::max(quadTopLeft.x, 0) + qx, quadTopLeft.y));
|
for(int qx=sx;qx<=ex;++qx)
|
||||||
count++;
|
for(int qy=sy;qy<=ey;++qy)
|
||||||
|
m_spiral[count++] = Point(qx, qy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(quadTopLeft.x >= 0) {
|
|
||||||
for(int qy=0;qy<fillHeight;++qy) {
|
|
||||||
// only start really looking tiles in the desired start
|
|
||||||
if(count < start) {
|
|
||||||
count++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid rendering too much tiles at once on far views
|
|
||||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
points.push_back(Point(quadTopLeft.x + quadWidth-1, std::max(quadTopLeft.y, 0) + qy));
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(quadTopLeft.y >= 0) {
|
|
||||||
for(int qx=0;qx<fillWidth;++qx) {
|
|
||||||
// only start really looking tiles in the desired start
|
|
||||||
if(count < start) {
|
|
||||||
count++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid rendering too much tiles at once on far views
|
|
||||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
points.push_back(Point(std::max(quadTopLeft.x, 0) + quadWidth-qx-1, quadTopLeft.y + quadHeight-1));
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(quadTopLeft.x >= 0) {
|
|
||||||
for(int qy=0;qy<fillHeight;++qy) {
|
|
||||||
// only start really looking tiles in the desired start
|
|
||||||
if(count < start) {
|
|
||||||
count++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid rendering too much tiles at once on far views
|
|
||||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
points.push_back(Point(quadTopLeft.x, std::max(quadTopLeft.y, 0) + quadHeight-qy-1));
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
quadTopLeft -= Point(1,1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const Point& point : points) {
|
for(m_updateTilesPos = start; m_updateTilesPos < (int)m_spiral.size(); ++m_updateTilesPos) {
|
||||||
Position tilePos = cameraPosition.translated(point.x - m_virtualCenterOffset.x, point.y - m_virtualCenterOffset.y);
|
// avoid rendering too much tiles at once
|
||||||
// adjust tilePos to the wanted floor
|
if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS) {
|
||||||
|
stop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point& p = m_spiral[m_updateTilesPos];
|
||||||
|
Position tilePos = cameraPosition.translated(p.x - m_virtualCenterOffset.x, p.y - m_virtualCenterOffset.y);
|
||||||
tilePos.coveredUp(cameraPosition.z - iz);
|
tilePos.coveredUp(cameraPosition.z - iz);
|
||||||
if(const TilePtr& tile = g_map.getTile(tilePos)) {
|
if(const TilePtr& tile = g_map.getTile(tilePos)) {
|
||||||
// skip tiles that have nothing
|
if(!tile->isEmpty())
|
||||||
if(tile->isEmpty())
|
m_cachedVisibleTiles.push_back(tile);
|
||||||
continue;
|
|
||||||
m_cachedVisibleTiles.push_back(tile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stop) {
|
if(!stop) {
|
||||||
// schedule next update continuation to avoid freezes
|
m_updateTilesPos = 0;
|
||||||
m_updateTilesCacheEvent = g_dispatcher.scheduleEvent(std::bind(&MapView::updateVisibleTilesCache, asMapView(), count), 1);
|
m_spiral.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(start == 0 && m_drawTexts && m_viewMode <= NEAR_VIEW)
|
if(start == 0 && m_drawTexts && m_viewMode <= NEAR_VIEW)
|
||||||
|
@ -462,6 +408,11 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized
|
||||||
viewMode = FAR_VIEW;
|
viewMode = FAR_VIEW;
|
||||||
else
|
else
|
||||||
viewMode = HUGE_VIEW;
|
viewMode = HUGE_VIEW;
|
||||||
|
|
||||||
|
if(viewMode >= FAR_VIEW)
|
||||||
|
m_multifloor = false;
|
||||||
|
else
|
||||||
|
m_multifloor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw actually more than what is needed to avoid massive recalculations on huge views
|
// draw actually more than what is needed to avoid massive recalculations on huge views
|
||||||
|
@ -473,6 +424,7 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
m_viewMode = viewMode;
|
m_viewMode = viewMode;
|
||||||
m_visibleDimension = visibleDimension;
|
m_visibleDimension = visibleDimension;
|
||||||
m_drawDimension = drawDimension;
|
m_drawDimension = drawDimension;
|
||||||
|
@ -570,7 +522,7 @@ int MapView::calcFirstVisibleFloor()
|
||||||
// this could happens if the player is not known yet
|
// this could happens if the player is not known yet
|
||||||
if(cameraPosition.isValid()) {
|
if(cameraPosition.isValid()) {
|
||||||
// avoid rendering multifloors in far views
|
// avoid rendering multifloors in far views
|
||||||
if(m_viewMode >= FAR_VIEW || !m_multifloor) {
|
if(!m_multifloor) {
|
||||||
z = cameraPosition.z;
|
z = cameraPosition.z;
|
||||||
} else {
|
} else {
|
||||||
// if nothing is limiting the view, the first visible floor is 0
|
// if nothing is limiting the view, the first visible floor is 0
|
||||||
|
@ -620,7 +572,7 @@ int MapView::calcFirstVisibleFloor()
|
||||||
|
|
||||||
int MapView::calcLastVisibleFloor()
|
int MapView::calcLastVisibleFloor()
|
||||||
{
|
{
|
||||||
if(!m_multifloor || m_viewMode >= FAR_VIEW)
|
if(!m_multifloor)
|
||||||
return calcFirstVisibleFloor();
|
return calcFirstVisibleFloor();
|
||||||
|
|
||||||
int z = 7;
|
int z = 7;
|
||||||
|
|
|
@ -39,7 +39,7 @@ class MapView : public LuaObject
|
||||||
NEAR_VIEW_AREA = 32*32,
|
NEAR_VIEW_AREA = 32*32,
|
||||||
MID_VIEW_AREA = 64*64,
|
MID_VIEW_AREA = 64*64,
|
||||||
FAR_VIEW_AREA = 128*128,
|
FAR_VIEW_AREA = 128*128,
|
||||||
MAX_TILE_UPDATES = NEAR_VIEW_AREA*7
|
MAX_TILE_DRAWS = NEAR_VIEW_AREA*7
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -127,6 +127,7 @@ private:
|
||||||
int m_cachedFirstVisibleFloor;
|
int m_cachedFirstVisibleFloor;
|
||||||
int m_cachedLastVisibleFloor;
|
int m_cachedLastVisibleFloor;
|
||||||
int m_tileSize;
|
int m_tileSize;
|
||||||
|
int m_updateTilesPos;
|
||||||
Size m_drawDimension;
|
Size m_drawDimension;
|
||||||
Size m_visibleDimension;
|
Size m_visibleDimension;
|
||||||
Size m_optimizedSize;
|
Size m_optimizedSize;
|
||||||
|
@ -145,12 +146,12 @@ private:
|
||||||
Boolean<true> m_follow;
|
Boolean<true> m_follow;
|
||||||
std::vector<TilePtr> m_cachedVisibleTiles;
|
std::vector<TilePtr> m_cachedVisibleTiles;
|
||||||
std::vector<CreaturePtr> m_cachedFloorVisibleCreatures;
|
std::vector<CreaturePtr> m_cachedFloorVisibleCreatures;
|
||||||
EventPtr m_updateTilesCacheEvent;
|
|
||||||
CreaturePtr m_followingCreature;
|
CreaturePtr m_followingCreature;
|
||||||
FrameBufferPtr m_framebuffer;
|
FrameBufferPtr m_framebuffer;
|
||||||
PainterShaderProgramPtr m_shader;
|
PainterShaderProgramPtr m_shader;
|
||||||
ViewMode m_viewMode;
|
ViewMode m_viewMode;
|
||||||
Otc::DrawFlags m_drawFlags;
|
Otc::DrawFlags m_drawFlags;
|
||||||
|
std::vector<Point> m_spiral;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -214,7 +214,7 @@ public:
|
||||||
|
|
||||||
struct PositionHasher : std::unary_function<Position, std::size_t> {
|
struct PositionHasher : std::unary_function<Position, std::size_t> {
|
||||||
std::size_t operator()(const Position& pos) const {
|
std::size_t operator()(const Position& pos) const {
|
||||||
return (((((pos.x * 2048) + pos.y) * 16) + pos.z) % (2048*2048)) % 1000000;
|
return (((((pos.x * 8192) + pos.y) * 16) + pos.z) % (8192*8192)) % 100000000;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue