forked from Kolyah35/minecraft-pe-0.6.1
the whole game
This commit is contained in:
264
src/world/level/chunk/ChunkCache.h
Executable file
264
src/world/level/chunk/ChunkCache.h
Executable file
@@ -0,0 +1,264 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include "ChunkSource.h"
|
||||
#include "storage/ChunkStorage.h"
|
||||
#include "EmptyLevelChunk.h"
|
||||
#include "../Level.h"
|
||||
#include "../LevelConstants.h"
|
||||
|
||||
class ChunkCache: public ChunkSource {
|
||||
//static const int CHUNK_CACHE_WIDTH = CHUNK_CACHE_WIDTH; // WAS 32;
|
||||
static const int MAX_SAVES = 2;
|
||||
public:
|
||||
ChunkCache(Level* level_, ChunkStorage* storage_, ChunkSource* source_)
|
||||
: xLast(-999999999),
|
||||
zLast(-999999999),
|
||||
last(NULL),
|
||||
level(level_),
|
||||
storage(storage_),
|
||||
source(source_)
|
||||
{
|
||||
isChunkCache = true;
|
||||
//emptyChunk = new EmptyLevelChunk(level_, emptyChunkBlocks, 0, 0);
|
||||
emptyChunk = new EmptyLevelChunk(level_, NULL, 0, 0);
|
||||
memset(chunks, 0, sizeof(LevelChunk*) * CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH);
|
||||
}
|
||||
|
||||
~ChunkCache() {
|
||||
delete source;
|
||||
delete emptyChunk;
|
||||
|
||||
for (int i = 0; i < CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; i++)
|
||||
{
|
||||
if (chunks[i])
|
||||
{
|
||||
chunks[i]->deleteBlockData();
|
||||
delete chunks[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool fits(int x, int z) {
|
||||
return (x >= 0 && z >= 0 && x < CHUNK_CACHE_WIDTH && z < CHUNK_CACHE_WIDTH);
|
||||
}
|
||||
|
||||
bool hasChunk(int x, int z) {
|
||||
// with a fixed world size, chunks outside the fitting area are always available (emptyChunks)
|
||||
if (!fits(x, z)) return true;
|
||||
|
||||
if (x == xLast && z == zLast && last != NULL) {
|
||||
return true;
|
||||
}
|
||||
int xs = x & (CHUNK_CACHE_WIDTH - 1);
|
||||
int zs = z & (CHUNK_CACHE_WIDTH - 1);
|
||||
int slot = xs + zs * CHUNK_CACHE_WIDTH;
|
||||
return chunks[slot] != NULL && (chunks[slot] == emptyChunk || chunks[slot]->isAt(x, z));
|
||||
}
|
||||
|
||||
LevelChunk* create(int x, int z) {
|
||||
return getChunk(x, z);
|
||||
}
|
||||
|
||||
LevelChunk* getChunk(int x, int z) {
|
||||
//static Stopwatch sw;
|
||||
//sw.start();
|
||||
|
||||
if (x == xLast && z == zLast && last != NULL) {
|
||||
return last;
|
||||
}
|
||||
if (!fits(x, z)) return emptyChunk;
|
||||
//if (!level->isFindingSpawn && !fits(x, z)) return emptyChunk;
|
||||
int xs = x & (CHUNK_CACHE_WIDTH - 1);
|
||||
int zs = z & (CHUNK_CACHE_WIDTH - 1);
|
||||
int slot = xs + zs * CHUNK_CACHE_WIDTH;
|
||||
if (!hasChunk(x, z)) {
|
||||
if (chunks[slot] != NULL) {
|
||||
chunks[slot]->unload();
|
||||
save(chunks[slot]);
|
||||
saveEntities(chunks[slot]);
|
||||
}
|
||||
|
||||
LevelChunk* newChunk = load(x, z);
|
||||
bool updateLights = false;
|
||||
if (newChunk == NULL) {
|
||||
if (source == NULL) {
|
||||
newChunk = emptyChunk;
|
||||
} else {
|
||||
newChunk = source->getChunk(x, z);
|
||||
}
|
||||
} else {
|
||||
//return emptyChunk;
|
||||
updateLights = true;
|
||||
}
|
||||
chunks[slot] = newChunk;
|
||||
newChunk->lightLava();
|
||||
|
||||
if (updateLights)
|
||||
{
|
||||
for (int cx = 0; cx < 16; cx++)
|
||||
{
|
||||
for (int cz = 0; cz < 16; cz++)
|
||||
{
|
||||
int height = level->getHeightmap(cx + x * 16, cz + z * 16);
|
||||
for (int cy = height; cy >= 0; cy--)
|
||||
{
|
||||
level->updateLight(LightLayer::Sky, cx + x * 16, cy, cz + z * 16, cx + x * 16, cy, cz + z * 16);
|
||||
level->updateLight(LightLayer::Block, cx + x * 16 - 1, cy, cz + z * 16 - 1, cx + x * 16 + 1, cy, cz + z * 16 + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//level->updateLight(LightLayer::Sky, x * 16, 0, z * 16, x * 16 + 15, 128, z * 16 + 15);
|
||||
//level->updateLight(LightLayer::Block, x * 16, 0, z * 16, x * 16 + 15, 128, z * 16 + 15);
|
||||
}
|
||||
|
||||
if (chunks[slot] != NULL) {
|
||||
chunks[slot]->load();
|
||||
}
|
||||
|
||||
if (!chunks[slot]->terrainPopulated && hasChunk(x + 1, z + 1) && hasChunk(x, z + 1) && hasChunk(x + 1, z)) postProcess(this, x, z);
|
||||
if (hasChunk(x - 1, z) && !getChunk(x - 1, z)->terrainPopulated && hasChunk(x - 1, z + 1) && hasChunk(x, z + 1) && hasChunk(x - 1, z)) postProcess(this, x - 1, z);
|
||||
if (hasChunk(x, z - 1) && !getChunk(x, z - 1)->terrainPopulated && hasChunk(x + 1, z - 1) && hasChunk(x, z - 1) && hasChunk(x + 1, z)) postProcess(this, x, z - 1);
|
||||
if (hasChunk(x - 1, z - 1) && !getChunk(x - 1, z - 1)->terrainPopulated && hasChunk(x - 1, z - 1) && hasChunk(x, z - 1) && hasChunk(x - 1, z)) postProcess(this, x - 1, z - 1);
|
||||
}
|
||||
xLast = x;
|
||||
zLast = z;
|
||||
last = chunks[slot];
|
||||
|
||||
//sw.stop();
|
||||
//sw.printEvery(500000, "ChunkCache::load: ");
|
||||
|
||||
return chunks[slot];
|
||||
}
|
||||
|
||||
Biome::MobList getMobsAt(const MobCategory& mobCategory, int x, int y, int z) {
|
||||
return source->getMobsAt(mobCategory, x, y, z);
|
||||
}
|
||||
|
||||
void postProcess(ChunkSource* parent, int x, int z) {
|
||||
if (!fits(x, z)) return;
|
||||
LevelChunk* chunk = getChunk(x, z);
|
||||
if (!chunk->terrainPopulated) {
|
||||
chunk->terrainPopulated = true;
|
||||
if (source != NULL) {
|
||||
source->postProcess(parent, x, z);
|
||||
chunk->clearUpdateMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//bool save(bool force, ProgressListener progressListener) {
|
||||
// int saves = 0;
|
||||
// int count = 0;
|
||||
// if (progressListener != NULL) {
|
||||
// for (int i = 0; i < chunks.length; i++) {
|
||||
// if (chunks[i] != NULL && chunks[i].shouldSave(force)) {
|
||||
// count++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// int cc = 0;
|
||||
// for (int i = 0; i < chunks.length; i++) {
|
||||
// if (chunks[i] != NULL) {
|
||||
// if (force && !chunks[i].dontSave) saveEntities(chunks[i]);
|
||||
// if (chunks[i].shouldSave(force)) {
|
||||
// save(chunks[i]);
|
||||
// chunks[i].unsaved = false;
|
||||
// if (++saves == MAX_SAVES && !force) return false;
|
||||
// if (progressListener != NULL) {
|
||||
// if (++cc % 10 == 0) {
|
||||
// progressListener.progressStagePercentage(cc * 100 / count);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (force) {
|
||||
// if (storage == NULL) return true;
|
||||
// storage.flush();
|
||||
// }
|
||||
// return true;
|
||||
//}
|
||||
|
||||
bool tick() {
|
||||
if (storage != NULL) storage->tick();
|
||||
return source->tick();
|
||||
}
|
||||
|
||||
bool shouldSave() {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string gatherStats() {
|
||||
return "ChunkCache: 1024";
|
||||
}
|
||||
|
||||
void saveAll(bool onlyUnsaved) {
|
||||
if (storage != NULL) {
|
||||
std::vector<LevelChunk*> chunks;
|
||||
for (int z = 0; z < CHUNK_CACHE_WIDTH; ++z)
|
||||
for (int x = 0; x < CHUNK_CACHE_WIDTH; ++x) {
|
||||
LevelChunk* chunk = level->getChunk(x, z);
|
||||
if (!onlyUnsaved || chunk->shouldSave(false))
|
||||
chunks.push_back( chunk );
|
||||
}
|
||||
storage->saveAll(level, chunks);
|
||||
}
|
||||
}
|
||||
private:
|
||||
LevelChunk* load(int x, int z) {
|
||||
if (storage == NULL) return emptyChunk;
|
||||
if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH)
|
||||
{
|
||||
return emptyChunk;
|
||||
}
|
||||
//try {
|
||||
LevelChunk* levelChunk = storage->load(level, x, z);
|
||||
if (levelChunk != NULL) {
|
||||
levelChunk->lastSaveTime = level->getTime();
|
||||
}
|
||||
return levelChunk;
|
||||
//} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return emptyChunk;
|
||||
//}
|
||||
}
|
||||
|
||||
void saveEntities(LevelChunk* levelChunk) {
|
||||
if (storage == NULL) return;
|
||||
//try {
|
||||
storage->saveEntities(level, levelChunk);
|
||||
//} catch (Error e) {
|
||||
// e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
|
||||
void save(LevelChunk* levelChunk) {
|
||||
if (storage == NULL) return;
|
||||
//try {
|
||||
levelChunk->lastSaveTime = level->getTime();
|
||||
storage->save(level, levelChunk);
|
||||
//} catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
|
||||
public:
|
||||
int xLast;
|
||||
int zLast;
|
||||
private:
|
||||
//unsigned char emptyChunkBlocks[LevelChunk::ChunkBlockCount];
|
||||
LevelChunk* emptyChunk;
|
||||
ChunkSource* source;
|
||||
ChunkStorage* storage;
|
||||
LevelChunk* chunks[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
Level* level;
|
||||
|
||||
LevelChunk* last;
|
||||
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__*/
|
||||
46
src/world/level/chunk/ChunkSource.h
Executable file
46
src/world/level/chunk/ChunkSource.h
Executable file
@@ -0,0 +1,46 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkSource_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkSource_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include <string>
|
||||
#include "../biome/Biome.h"
|
||||
|
||||
class ProgressListener;
|
||||
class LevelChunk;
|
||||
|
||||
class ChunkSource
|
||||
{
|
||||
public:
|
||||
bool isChunkCache;
|
||||
|
||||
ChunkSource()
|
||||
: isChunkCache(false)
|
||||
{}
|
||||
|
||||
virtual ~ChunkSource(){}
|
||||
|
||||
virtual bool hasChunk(int x, int y) = 0;
|
||||
|
||||
virtual LevelChunk* getChunk(int x, int z) = 0;
|
||||
|
||||
virtual LevelChunk* create(int x, int z) = 0;
|
||||
|
||||
virtual void postProcess(ChunkSource* parent, int x, int z) = 0;
|
||||
|
||||
//virtual bool save(bool force, ProgressListener* progressListener) = 0;
|
||||
|
||||
virtual bool tick() = 0;
|
||||
|
||||
virtual bool shouldSave() = 0;
|
||||
virtual void saveAll(bool onlyUnsaved) {}
|
||||
|
||||
virtual Biome::MobList getMobsAt(const MobCategory& mobCategory, int x, int y, int z) = 0;
|
||||
|
||||
/**
|
||||
* Returns some stats that are rendered when the user holds F3.
|
||||
*/
|
||||
virtual std::string gatherStats() = 0;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkSource_H__*/
|
||||
75
src/world/level/chunk/DataLayer.h
Executable file
75
src/world/level/chunk/DataLayer.h
Executable file
@@ -0,0 +1,75 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__DataLayer_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__DataLayer_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include <cstring>
|
||||
|
||||
class DataLayer
|
||||
{
|
||||
public:
|
||||
DataLayer()
|
||||
: data(NULL),
|
||||
length(0)
|
||||
{}
|
||||
|
||||
DataLayer(int length) {
|
||||
this->length = length >> 1;
|
||||
data = new unsigned char[this->length];
|
||||
setAll(0);
|
||||
slotMax = this->length;
|
||||
}
|
||||
|
||||
DataLayer(unsigned char* data, int length) {
|
||||
this->length = length >> 1;
|
||||
this->data = data;
|
||||
}
|
||||
|
||||
~DataLayer() {
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
int get(int x, int y, int z) {
|
||||
return get(x << 11 | z << 7 | y);
|
||||
}
|
||||
|
||||
void set(int x, int y, int z, int val) {
|
||||
set(x << 11 | z << 7 | y, val);
|
||||
}
|
||||
|
||||
__inline int get(int pos) {
|
||||
int slot = pos >> 1;
|
||||
int part = pos & 1;
|
||||
|
||||
if (part == 0) {
|
||||
return data[slot] & 0xf;
|
||||
} else {
|
||||
return (data[slot] >> 4) & 0xf;
|
||||
}
|
||||
}
|
||||
__inline void set(int pos, int val) {
|
||||
int slot = pos >> 1;
|
||||
int part = pos & 1;
|
||||
|
||||
if (part == 0) {
|
||||
data[slot] = ((data[slot] & 0xf0) | (val & 0xf));
|
||||
} else {
|
||||
data[slot] = ((data[slot] & 0x0f) | ((val & 0xf) << 4));
|
||||
}
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return data != NULL;
|
||||
}
|
||||
|
||||
void setAll(int br) {
|
||||
unsigned char val = (br & (br << 4));
|
||||
memset(data, val, length);
|
||||
}
|
||||
|
||||
unsigned char* data;
|
||||
int length;
|
||||
int slotMax;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__DataLayer_H__*/
|
||||
196
src/world/level/chunk/EmptyLevelChunk.h
Executable file
196
src/world/level/chunk/EmptyLevelChunk.h
Executable file
@@ -0,0 +1,196 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__EmptyLevelChunk_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__EmptyLevelChunk_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
/* import java.util.* */
|
||||
|
||||
//#include "world/entity/Entity.h"
|
||||
/* import net.minecraft.world.level.* */
|
||||
//#include "world/level/tile/entity/TileEntity.h"
|
||||
//#include "world/phys/AABB.h"
|
||||
|
||||
#include "LevelChunk.h"
|
||||
#include "../tile/Tile.h"
|
||||
#include "../Level.h"
|
||||
|
||||
class EmptyLevelChunk: public LevelChunk
|
||||
{
|
||||
public:
|
||||
EmptyLevelChunk(Level* level, int x, int z)
|
||||
: LevelChunk(level, x, z)
|
||||
{
|
||||
dontSave = true;
|
||||
}
|
||||
|
||||
EmptyLevelChunk(Level* level, unsigned char* blocks, int x, int z)
|
||||
: LevelChunk(level, blocks, x, z)
|
||||
{
|
||||
dontSave = true;
|
||||
}
|
||||
|
||||
bool isAt(int x, int z) {
|
||||
return x == this->x && z == this->z;
|
||||
}
|
||||
|
||||
int getHeightmap(int x, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void recalcBlockLights() {
|
||||
}
|
||||
|
||||
void recalcHeightmapOnly() {
|
||||
return;
|
||||
}
|
||||
|
||||
void recalcHeightmap() {
|
||||
return;
|
||||
}
|
||||
|
||||
void lightLava() {
|
||||
return;
|
||||
}
|
||||
|
||||
int getTile(int x, int y, int z) {
|
||||
//if (y <= 1)
|
||||
//{
|
||||
// return Tile::unbreakable->id;
|
||||
//}
|
||||
//else if (y < 64)
|
||||
//{
|
||||
// return Tile::water->id;
|
||||
//}
|
||||
//return 0;
|
||||
return Tile::invisible_bedrock->id;
|
||||
}
|
||||
|
||||
bool setTileAndData(int x, int y, int z, int _tile, int _data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setTile(int x, int y, int z, int _tile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int getData(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setData(int x, int y, int z, int val) {
|
||||
return;
|
||||
}
|
||||
|
||||
int getBrightness(const LightLayer& layer, int x, int y, int z) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
void setBrightness(const LightLayer& layer, int x, int y, int z, int brightness) {
|
||||
return;
|
||||
}
|
||||
|
||||
int getRawBrightness(int x, int y, int z, int skyDampen) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
void addEntity(Entity* e) {
|
||||
return;
|
||||
}
|
||||
|
||||
void removeEntity(Entity* e) {
|
||||
return;
|
||||
}
|
||||
|
||||
void removeEntity(Entity* e, int yc) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isSkyLit(int x, int y, int z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void skyBrightnessChanged() {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
TileEntity getTileEntity(int x, int y, int z) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void addTileEntity(TileEntity te) {
|
||||
return;
|
||||
}
|
||||
|
||||
void setTileEntity(int x, int y, int z, TileEntity tileEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
void removeTileEntity(int x, int y, int z) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
void load() {
|
||||
return;
|
||||
}
|
||||
|
||||
void unload() {
|
||||
return;
|
||||
}
|
||||
|
||||
void markUnsaved() {
|
||||
return;
|
||||
}
|
||||
|
||||
void getEntities(Entity* except, const AABB& bb, std::vector<Entity*>& es) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
void getEntitiesOfClass(Class<? extends Entity> baseClass, AABB bb, List<Entity> es) {
|
||||
return;
|
||||
}
|
||||
|
||||
int countEntities() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool shouldSave(bool force) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
void setBlocks(unsigned char* newBlocks, int sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
int getBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p) {
|
||||
int xs = x1 - x0;
|
||||
int ys = y1 - y0;
|
||||
int zs = z1 - z0;
|
||||
|
||||
int s = xs * ys * zs;
|
||||
int len = s + s / 2 * 3;
|
||||
|
||||
memset(data + p, Tile::invisible_bedrock->id, len); //Arrays.fill(data, p, p + len, (char) 0);
|
||||
return len;
|
||||
}
|
||||
|
||||
int setBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p) {
|
||||
int xs = x1 - x0;
|
||||
int ys = y1 - y0;
|
||||
int zs = z1 - z0;
|
||||
|
||||
int s = xs * ys * zs;
|
||||
return s + s / 2 * 3;
|
||||
}
|
||||
|
||||
Random getRandom(long l) {
|
||||
return /*new*/ Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l);
|
||||
}
|
||||
|
||||
bool isEmpty() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__EmptyLevelChunk_H__*/
|
||||
713
src/world/level/chunk/LevelChunk.cpp
Executable file
713
src/world/level/chunk/LevelChunk.cpp
Executable file
@@ -0,0 +1,713 @@
|
||||
#include "LevelChunk.h"
|
||||
#include "../LightLayer.h"
|
||||
#include "../tile/Tile.h"
|
||||
#include "../Level.h"
|
||||
#include "../dimension/Dimension.h"
|
||||
#include "../../phys/AABB.h"
|
||||
#include "../../entity/Entity.h"
|
||||
#include "../TilePos.h"
|
||||
#include "../tile/entity/TileEntity.h"
|
||||
#include "../tile/EntityTile.h"
|
||||
#include "../LevelConstants.h"
|
||||
|
||||
/*static*/
|
||||
bool LevelChunk::touchedSky = false;
|
||||
|
||||
LevelChunk::LevelChunk( Level* level, int x, int z )
|
||||
: level(level),
|
||||
x(x),
|
||||
z(z),
|
||||
xt(x * CHUNK_WIDTH),
|
||||
zt(z * CHUNK_DEPTH)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LevelChunk::LevelChunk( Level* level, unsigned char* blocks, int x, int z )
|
||||
: level(level),
|
||||
x(x),
|
||||
z(z),
|
||||
xt(x * CHUNK_WIDTH),
|
||||
zt(z * CHUNK_DEPTH),
|
||||
blocks(blocks),
|
||||
data(ChunkBlockCount),
|
||||
skyLight(ChunkBlockCount),
|
||||
blockLight(ChunkBlockCount),
|
||||
blocksLength(ChunkBlockCount)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LevelChunk::~LevelChunk()
|
||||
{
|
||||
//delete blocks;
|
||||
}
|
||||
|
||||
void LevelChunk::init()
|
||||
{
|
||||
terrainPopulated = false;
|
||||
dontSave = false;
|
||||
unsaved = false;
|
||||
lastSaveHadEntities = false;
|
||||
createdFromSave = false;
|
||||
lastSaveTime = 0;
|
||||
memset(heightmap, 0, 256);
|
||||
memset(updateMap, 0, 256);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
bool LevelChunk::setTileAndData(int x, int y, int z, int tile_, int data_) {
|
||||
|
||||
int tile = tile_ & 0xff;
|
||||
|
||||
int oldHeight = heightmap[z << 4 | x];
|
||||
|
||||
int old = blocks[x << 11 | z << 7 | y];
|
||||
if (old == tile && data.get(x, y, z) == data_) return false;
|
||||
int xOffs = xt + x;
|
||||
int zOffs = zt + z;
|
||||
blocks[x << 11 | z << 7 | y] = (unsigned char) tile;
|
||||
if (old != 0) {
|
||||
if (!level->isClientSide) {
|
||||
Tile::tiles[old]->onRemove(level, xOffs, y, zOffs);
|
||||
} else if (old != tile && Tile::isEntityTile[old]) {
|
||||
level->removeTileEntity(xOffs, y, zOffs);
|
||||
}
|
||||
}
|
||||
data.set(x, y, z, data_);
|
||||
|
||||
if (!level->dimension->hasCeiling) {
|
||||
if (Tile::lightBlock[tile] != 0) {
|
||||
if (y >= oldHeight) {
|
||||
recalcHeight(x, y + 1, z);
|
||||
}
|
||||
} else {
|
||||
if (y == oldHeight - 1) {
|
||||
recalcHeight(x, y, z);
|
||||
}
|
||||
}
|
||||
level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
}
|
||||
|
||||
level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
lightGaps(x, z);
|
||||
|
||||
if (!level->isClientSide && tile != 0) {
|
||||
Tile::tiles[tile]->onPlace(level, xOffs, y, zOffs);
|
||||
}
|
||||
|
||||
this->unsaved = true;
|
||||
this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*public*/
|
||||
bool LevelChunk::setTile(int x, int y, int z, int tile_) {
|
||||
|
||||
int tile = tile_ & 0xff;
|
||||
int oldHeight = heightmap[z << 4 | x] & 0xff;
|
||||
|
||||
int old = blocks[x << 11 | z << 7 | y] & 0xff;
|
||||
if (old == tile_) return false;
|
||||
int xOffs = xt + x;
|
||||
int zOffs = zt + z;
|
||||
blocks[x << 11 | z << 7 | y] = (unsigned char) (tile & 0xff);
|
||||
if (old != 0) {
|
||||
Tile::tiles[old]->onRemove(level, xOffs, y, zOffs);
|
||||
}
|
||||
data.set(x, y, z, 0);
|
||||
|
||||
if (Tile::lightBlock[tile & 0xff] != 0) {
|
||||
if (y >= oldHeight) {
|
||||
recalcHeight(x, y + 1, z);
|
||||
}
|
||||
} else {
|
||||
if (y == oldHeight - 1) {
|
||||
recalcHeight(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
lightGaps(x, z);
|
||||
|
||||
if (tile_ != 0) {
|
||||
if (!level->isClientSide) Tile::tiles[tile_]->onPlace(level, xOffs, y, zOffs);
|
||||
}
|
||||
|
||||
this->unsaved = true;
|
||||
this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift));
|
||||
return true;
|
||||
}
|
||||
|
||||
void LevelChunk::setTileRaw(int x, int y, int z, int tile) {
|
||||
blocks[x << 11 | z << 7 | y] = tile;
|
||||
}
|
||||
|
||||
/*public*/
|
||||
int LevelChunk::getData(int x, int y, int z) {
|
||||
return data.get(x, y, z);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
void LevelChunk::recalcHeightmapOnly() {
|
||||
int min = Level::DEPTH - 1;
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int y = Level::DEPTH - 1;
|
||||
int p = x << 11 | z << 7;
|
||||
while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0)
|
||||
y--;
|
||||
heightmap[z << 4 | x] = (char) y;
|
||||
if (y < min) min = y;
|
||||
}
|
||||
|
||||
this->minHeight = min;
|
||||
//this->unsaved = true;
|
||||
}
|
||||
|
||||
/*public?*/
|
||||
void LevelChunk::recalcHeightmap() {
|
||||
int min = Level::DEPTH - 1;
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int y = Level::DEPTH - 1;
|
||||
int p = x << 11 | z << 7;
|
||||
while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0)
|
||||
y--;
|
||||
heightmap[z << 4 | x] = (char) y;
|
||||
if (y < min) min = y;
|
||||
|
||||
if (!level->dimension->hasCeiling) {
|
||||
int br = Level::MAX_BRIGHTNESS;
|
||||
int yy = Level::DEPTH - 1;
|
||||
do {
|
||||
br -= Tile::lightBlock[blocks[p + yy] & 0xff];
|
||||
if (br > 0) {
|
||||
skyLight.set(x, yy, z, br);
|
||||
}
|
||||
yy--;
|
||||
} while (yy > 0 && br > 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this->minHeight = min;
|
||||
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int z = 0; z < 16; z++) {
|
||||
lightGaps(x, z);
|
||||
}
|
||||
|
||||
//this->unsaved = true;
|
||||
}
|
||||
|
||||
/*private*/
|
||||
void LevelChunk::recalcHeight(int x, int yStart, int z) {
|
||||
int yOld = heightmap[z << 4 | x] & 0xff;
|
||||
int y = yOld;
|
||||
if (yStart > yOld) y = yStart;
|
||||
|
||||
int p = x << 11 | z << 7;
|
||||
while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0)
|
||||
y--;
|
||||
if (y == yOld) return;
|
||||
|
||||
const int xOffs = xt + x;
|
||||
const int zOffs = zt + z;
|
||||
level->lightColumnChanged(xOffs, zOffs, y, yOld);
|
||||
heightmap[z << 4 | x] = (char) y;
|
||||
|
||||
if (y < minHeight) {
|
||||
minHeight = y;
|
||||
} else {
|
||||
int min = Level::DEPTH - 1;
|
||||
for (int _x = 0; _x < 16; _x++)
|
||||
for (int _z = 0; _z < 16; _z++) {
|
||||
if ((heightmap[_z << 4 | _x] & 0xff) < min) min = (heightmap[_z << 4 | _x] & 0xff);
|
||||
}
|
||||
this->minHeight = min;
|
||||
}
|
||||
|
||||
if (y < yOld) {
|
||||
for (int yy = y; yy < yOld; yy++) {
|
||||
skyLight.set(x, yy, z, 15);
|
||||
}
|
||||
} else {
|
||||
level->updateLight(LightLayer::Sky, xOffs, yOld, zOffs, xOffs, y, zOffs);
|
||||
for (int yy = yOld; yy < y; yy++) {
|
||||
skyLight.set(x, yy, z, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int br = 15;
|
||||
int y0 = y;
|
||||
while (y > 0 && br > 0) {
|
||||
y--;
|
||||
int block = Tile::lightBlock[getTile(x, y, z)];
|
||||
if (block == 0) block = 1;
|
||||
br -= block;
|
||||
if (br < 0) br = 0;
|
||||
skyLight.set(x, y, z, br);
|
||||
}
|
||||
while (y > 0 && Tile::lightBlock[getTile(x, y - 1, z)] == 0)
|
||||
y--;
|
||||
if (y != y0) {
|
||||
level->updateLight(LightLayer::Sky, xOffs - 1, y, zOffs - 1, xOffs + 1, y0, zOffs + 1);
|
||||
}
|
||||
|
||||
//this->unsaved = true;
|
||||
}
|
||||
|
||||
/*public*/
|
||||
void LevelChunk::skyBrightnessChanged() {
|
||||
// int x0 = xt;
|
||||
// int y0 = this->minHeight - 16;
|
||||
// int z0 = zt;
|
||||
// int x1 = xt + 16;
|
||||
// int y1 = Level::DEPTH - 1;
|
||||
// int z1 = zt + 16;
|
||||
|
||||
//level->setTilesDirty(x0, y0, z0, x1, y1, z1);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
bool LevelChunk::shouldSave(bool force) {
|
||||
if (dontSave) return false;
|
||||
/*
|
||||
if (force) {
|
||||
if (lastSaveHadEntities && level->getTime() != lastSaveTime) return true;
|
||||
} else {
|
||||
if (lastSaveHadEntities && level->getTime() >= lastSaveTime + 20 * 30) return true;
|
||||
}
|
||||
*/
|
||||
|
||||
return unsaved;
|
||||
}
|
||||
|
||||
/*public*/
|
||||
void LevelChunk::setBlocks(unsigned char* newBlocks, int sub) { //@byte[]
|
||||
LOGI("LevelChunk::setBlocks\n");
|
||||
for (int i = 0; i < 128 * 16 * 4; i++) {
|
||||
blocks[sub * 128 * 16 * 4 + i] = newBlocks[i];
|
||||
}
|
||||
|
||||
for (int x = sub * 4; x < sub * 4 + 4; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
recalcHeight(x, 0, z);
|
||||
}
|
||||
}
|
||||
|
||||
level->updateLight(LightLayer::Sky, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16);
|
||||
level->updateLight(LightLayer::Block, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16);
|
||||
|
||||
//for (int x = sub * 4; x < sub * 4 + 4; x++) {
|
||||
// for (int z = 0; z < 16; z++) {
|
||||
// lightGaps(x, z);
|
||||
// }
|
||||
//}
|
||||
level->setTilesDirty(xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
Random LevelChunk::getRandom(long l) {
|
||||
return /*new*/ Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l);
|
||||
}
|
||||
|
||||
/*private*/
|
||||
void LevelChunk::lightGap( int x, int z, int source )
|
||||
{
|
||||
int height = level->getHeightmap(x, z);
|
||||
if (height > source) {
|
||||
level->updateLight(LightLayer::Sky, x, source, z, x, height, z);
|
||||
} else if (height < source) {
|
||||
level->updateLight(LightLayer::Sky, x, height, z, x, source, z);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::clearUpdateMap()
|
||||
{
|
||||
memset(updateMap, 0x0, 256);
|
||||
unsaved = false;
|
||||
}
|
||||
|
||||
void LevelChunk::deleteBlockData()
|
||||
{
|
||||
delete [] blocks;
|
||||
blocks = NULL;
|
||||
}
|
||||
|
||||
bool LevelChunk::isAt( int x, int z )
|
||||
{
|
||||
return x == this->x && z == this->z;
|
||||
}
|
||||
|
||||
int LevelChunk::getHeightmap( int x, int z )
|
||||
{
|
||||
return heightmap[z << 4 | x] & 0xff;
|
||||
}
|
||||
|
||||
void LevelChunk::recalcBlockLights()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LevelChunk::lightGaps( int x, int z )
|
||||
{
|
||||
int height = getHeightmap(x, z);
|
||||
|
||||
int xOffs = xt + x;
|
||||
int zOffs = zt + z;
|
||||
lightGap(xOffs - 1, zOffs, height);
|
||||
lightGap(xOffs + 1, zOffs, height);
|
||||
lightGap(xOffs, zOffs - 1, height);
|
||||
lightGap(xOffs, zOffs + 1, height);
|
||||
}
|
||||
|
||||
int LevelChunk::getTile( int x, int y, int z )
|
||||
{
|
||||
return blocks[x << 11 | z << 7 | y] & 0xff;
|
||||
}
|
||||
|
||||
void LevelChunk::setData( int x, int y, int z, int val )
|
||||
{
|
||||
//this->unsaved = true;
|
||||
data.set(x, y, z, val);
|
||||
}
|
||||
|
||||
int LevelChunk::getBrightness( const LightLayer& layer, int x, int y, int z )
|
||||
{
|
||||
if (&layer == &LightLayer::Sky) return skyLight.get(x, y, z);
|
||||
else if (&layer == &LightLayer::Block) return blockLight.get(x, y, z);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void LevelChunk::setBrightness( const LightLayer& layer, int x, int y, int z, int brightness )
|
||||
{
|
||||
//this->unsaved = true;
|
||||
if (&layer == &LightLayer::Sky) skyLight.set(x, y, z, brightness);
|
||||
else if (&layer == &LightLayer::Block) blockLight.set(x, y, z, brightness);
|
||||
else return;
|
||||
}
|
||||
|
||||
int LevelChunk::getRawBrightness( int x, int y, int z, int skyDampen )
|
||||
{
|
||||
int light = skyLight.get(x, y, z);
|
||||
if (light > 0) LevelChunk::touchedSky = true;
|
||||
light -= skyDampen;
|
||||
int block = blockLight.get(x, y, z);
|
||||
if (block > light) light = block;
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
void LevelChunk::addEntity( Entity* e )
|
||||
{
|
||||
lastSaveHadEntities = true;
|
||||
|
||||
int xc = Mth::floor(e->x / 16);
|
||||
int zc = Mth::floor(e->z / 16);
|
||||
if (xc != this->x || zc != this->z) {
|
||||
LOGE("ERR: WRONG LOCATION : %d, %d, %d, %d", xc, x, zc, z);
|
||||
//Thread.dumpStack();
|
||||
}
|
||||
int yc = Mth::floor(e->y / 16);
|
||||
if (yc < 0) yc = 0;
|
||||
if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1;
|
||||
e->inChunk = true;
|
||||
e->xChunk = x;
|
||||
e->yChunk = yc;
|
||||
e->zChunk = z;
|
||||
entityBlocks[yc].push_back(e);
|
||||
}
|
||||
|
||||
void LevelChunk::removeEntity( Entity* e )
|
||||
{
|
||||
removeEntity(e, e->yChunk);
|
||||
}
|
||||
|
||||
void LevelChunk::removeEntity( Entity* e, int yc )
|
||||
{
|
||||
if (yc < 0) yc = 0;
|
||||
if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1;
|
||||
|
||||
EntityList::iterator newEnd = std::remove( entityBlocks[yc].begin(), entityBlocks[yc].end(), e);
|
||||
entityBlocks[yc].erase(newEnd, entityBlocks[yc].end());
|
||||
}
|
||||
|
||||
bool LevelChunk::isSkyLit( int x, int y, int z )
|
||||
{
|
||||
return y >= (heightmap[z << 4 | x] & 0xff);
|
||||
}
|
||||
|
||||
void LevelChunk::load()
|
||||
{
|
||||
loaded = true;
|
||||
/* level->tileEntityList.addAll(tileEntities.values());
|
||||
for (int i = 0; i < entityBlocks.length; i++) {
|
||||
level->addEntities(entityBlocks[i]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void LevelChunk::unload()
|
||||
{
|
||||
loaded = false;
|
||||
/* level->tileEntityList.removeAll(tileEntities.values());
|
||||
for (int i = 0; i < entityBlocks.length; i++) {
|
||||
level->removeEntities(entityBlocks[i]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void LevelChunk::markUnsaved()
|
||||
{
|
||||
this->unsaved = true;
|
||||
}
|
||||
|
||||
void LevelChunk::getEntities( Entity* except, const AABB& bb, std::vector<Entity*>& es )
|
||||
{
|
||||
int yc0 = Mth::floor((bb.y0 - 2) / 16);
|
||||
int yc1 = Mth::floor((bb.y1 + 2) / 16);
|
||||
if (yc0 < 0) yc0 = 0;
|
||||
if (yc1 >= EntityBlocksArraySize) yc1 = EntityBlocksArraySize - 1;
|
||||
for (int yc = yc0; yc <= yc1; yc++) {
|
||||
std::vector<Entity*>& entities = entityBlocks[yc];
|
||||
for (unsigned int i = 0; i < entities.size(); i++) {
|
||||
Entity* e = entities[i];
|
||||
if (e != except && e->bb.intersects(bb)){
|
||||
es.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::getEntitiesOfType( int entityType, const AABB& bb, EntityList& list )
|
||||
{
|
||||
int yc0 = Mth::floor((bb.y0 - 2) / 16);
|
||||
int yc1 = Mth::floor((bb.y1 + 2) / 16);
|
||||
if (yc0 < 0) {
|
||||
yc0 = 0;
|
||||
} else if (yc0 >= EntityBlocksArraySize) {
|
||||
yc0 = EntityBlocksArraySize - 1;
|
||||
}
|
||||
if (yc1 >= EntityBlocksArraySize) {
|
||||
yc1 = EntityBlocksArraySize - 1;
|
||||
} else if (yc1 < 0) {
|
||||
yc1 = 0;
|
||||
}
|
||||
for (int yc = yc0; yc <= yc1; yc++) {
|
||||
std::vector<Entity*>& entities = entityBlocks[yc];
|
||||
for (unsigned int i = 0; i < entities.size(); i++) {
|
||||
Entity* e = entities[i];
|
||||
if (e->getEntityTypeId() == entityType)
|
||||
list.push_back(e);
|
||||
//if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::getEntitiesOfClass( int type, const AABB& bb, EntityList& list )
|
||||
{
|
||||
int yc0 = Mth::floor((bb.y0 - 2) / 16);
|
||||
int yc1 = Mth::floor((bb.y1 + 2) / 16);
|
||||
if (yc0 < 0) {
|
||||
yc0 = 0;
|
||||
} else if (yc0 >= EntityBlocksArraySize) {
|
||||
yc0 = EntityBlocksArraySize - 1;
|
||||
}
|
||||
if (yc1 >= EntityBlocksArraySize) {
|
||||
yc1 = EntityBlocksArraySize - 1;
|
||||
} else if (yc1 < 0) {
|
||||
yc1 = 0;
|
||||
}
|
||||
for (int yc = yc0; yc <= yc1; yc++) {
|
||||
std::vector<Entity*>& entities = entityBlocks[yc];
|
||||
for (unsigned int i = 0; i < entities.size(); i++) {
|
||||
Entity* e = entities[i];
|
||||
if (e->getCreatureBaseType() == type)
|
||||
list.push_back(e);
|
||||
//if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int LevelChunk::countEntities()
|
||||
{
|
||||
int entityCount = 0;
|
||||
for (int yc = 0; yc < EntityBlocksArraySize; yc++) {
|
||||
entityCount += entityBlocks[yc].size();
|
||||
}
|
||||
return entityCount;
|
||||
}
|
||||
|
||||
//@note: @todo @te Verify
|
||||
TileEntity* LevelChunk::getTileEntity(int x, int y, int z) {
|
||||
TilePos pos(x, y, z);
|
||||
TEMap::iterator cit = tileEntities.find(pos);
|
||||
TileEntity* tileEntity = NULL;
|
||||
//bool ex = cit != tileEntities.end();
|
||||
//LOGI("Getting tile entity @ %d, %d, %d. Already existing? %d (%p)\n", x, y, z, ex, ex?cit->second:0);
|
||||
if (cit == tileEntities.end())
|
||||
{
|
||||
int t = getTile(x, y, z);
|
||||
if (t <= 0 || !Tile::isEntityTile[t])
|
||||
return NULL;
|
||||
|
||||
if (tileEntity == NULL) {
|
||||
tileEntity = ((EntityTile*) Tile::tiles[t])->newTileEntity();
|
||||
level->setTileEntity(xt + x, y, zt + z, tileEntity);
|
||||
}
|
||||
// @attn @bug @fix: Don't go via level->setTileEntity since we
|
||||
// know this tile is loaded if we are here
|
||||
//cit = tileEntities.find(pos);
|
||||
//tileEntity = (cit != tileEntities.end())? cit->second : NULL;
|
||||
}
|
||||
else {
|
||||
tileEntity = cit->second;
|
||||
}
|
||||
if (tileEntity != NULL && tileEntity->isRemoved()) {
|
||||
tileEntities.erase(cit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tileEntity;
|
||||
}
|
||||
|
||||
bool LevelChunk::hasTileEntityAt( int x, int y, int z )
|
||||
{
|
||||
return tileEntities.find(TilePos(x, y, z)) != tileEntities.end();
|
||||
}
|
||||
bool LevelChunk::hasTileEntityAt( TileEntity* te )
|
||||
{
|
||||
return tileEntities.find(TilePos(te->x & 15, te->y, te->z & 15)) != tileEntities.end();
|
||||
}
|
||||
|
||||
void LevelChunk::addTileEntity(TileEntity* te) {
|
||||
|
||||
int xx = te->x - xt;
|
||||
int yy = te->y;
|
||||
int zz = te->z - zt;
|
||||
setTileEntity(xx, yy, zz, te);
|
||||
if (loaded) {
|
||||
level->tileEntities.push_back(te);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::setTileEntity(int x, int y, int z, TileEntity* tileEntity)
|
||||
{
|
||||
tileEntity->setLevelAndPos(level, xt + x, y, zt + z);
|
||||
int t = getTile(x, y, z);
|
||||
if (t == 0 || !Tile::isEntityTile[t]) {
|
||||
LOGW("Attempted to place a tile entity where there was no entity tile! %d, %d, %d\n",
|
||||
tileEntity->x, tileEntity->y, tileEntity->z);
|
||||
return;
|
||||
}
|
||||
|
||||
tileEntity->clearRemoved();
|
||||
tileEntities.insert(std::make_pair(TilePos(x, y, z), tileEntity));
|
||||
}
|
||||
|
||||
void LevelChunk::removeTileEntity(int x, int y, int z) {
|
||||
if (loaded) {
|
||||
TilePos pos(x, y, z);
|
||||
TEMap::iterator cit = tileEntities.find(pos);
|
||||
if (cit != tileEntities.end()) {
|
||||
cit->second->setRemoved();
|
||||
|
||||
if (!level->isClientSide) {
|
||||
for (unsigned int i = 0; i < level->players.size(); ++i) {
|
||||
level->players[i]->tileEntityDestroyed(cit->second->runningId);
|
||||
}
|
||||
}
|
||||
tileEntities.erase(cit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LevelChunk::getBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p )
|
||||
{
|
||||
int len = y1 - y0;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = x << 11 | z << 7 | y0;
|
||||
memcpy(data + p, blocks + slot, len); //System.arraycopy(blocks, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(data + p, this->data.data + slot, len); //System.arraycopy(this->data.data, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(data + p, blockLight.data + slot, len); //System.arraycopy(blockLight.data, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(data + p, skyLight.data + slot, len); //System.arraycopy(skyLight.data, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int LevelChunk::setBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p )
|
||||
{
|
||||
int len = y1 - y0;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = x << 11 | z << 7 | y0;
|
||||
memcpy(blocks + slot, data + p, len); //System.arraycopy(data, p, blocks, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
recalcHeightmapOnly();
|
||||
|
||||
len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(this->data.data + slot, data + p, len); //System.arraycopy(data, p, this->data.data, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(blockLight.data + slot, data + p, len); //System.arraycopy(data, p, blockLight.data, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(skyLight.data + slot, data + p, len); //System.arraycopy(data, p, skyLight.data, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
bool LevelChunk::isEmpty()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const LevelChunk::TEMap& LevelChunk::getTileEntityMap() const {
|
||||
return tileEntities;
|
||||
}
|
||||
142
src/world/level/chunk/LevelChunk.h
Executable file
142
src/world/level/chunk/LevelChunk.h
Executable file
@@ -0,0 +1,142 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__LevelChunk_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__LevelChunk_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "DataLayer.h"
|
||||
#include "../LevelConstants.h"
|
||||
#include "../../../util/Random.h"
|
||||
#include "../TilePos.h"
|
||||
|
||||
class Level;
|
||||
class Entity;
|
||||
class LightLayer;
|
||||
class AABB;
|
||||
class TileEntity;
|
||||
typedef std::vector<Entity*> EntityList;
|
||||
|
||||
class LevelChunk
|
||||
{
|
||||
public:
|
||||
typedef std::map<TilePos, TileEntity*> TEMap;
|
||||
typedef TEMap::const_iterator TEMapCIterator;
|
||||
|
||||
LevelChunk(Level* level, int x, int z);
|
||||
LevelChunk(Level* level, unsigned char* blocks, int x, int z);
|
||||
virtual ~LevelChunk();
|
||||
|
||||
void init(); // @todo virtual?;
|
||||
|
||||
// Clears the update map. This should be called when the chunk is
|
||||
// identical to the data generated by the level generator. It is
|
||||
// used to identify which parts of the chunk to transfer in multiplayer.
|
||||
void clearUpdateMap();
|
||||
|
||||
void deleteBlockData();
|
||||
|
||||
virtual bool isAt(int x, int z);
|
||||
|
||||
virtual int getHeightmap(int x, int z);
|
||||
|
||||
virtual void recalcHeightmap();
|
||||
virtual void recalcHeightmapOnly();
|
||||
|
||||
unsigned char* getBlockData() { return blocks; }
|
||||
|
||||
virtual int getBrightness(const LightLayer& layer, int x, int y, int z);
|
||||
virtual void setBrightness(const LightLayer& layer, int x, int y, int z, int brightness);
|
||||
virtual int getRawBrightness(int x, int y, int z, int skyDampen);
|
||||
|
||||
virtual void addEntity(Entity* e);
|
||||
virtual void removeEntity(Entity* e);
|
||||
virtual void removeEntity(Entity* e, int yc);
|
||||
|
||||
virtual void getEntitiesOfClass( int type, const AABB& bb, EntityList& list );
|
||||
virtual void getEntitiesOfType(int entityType, const AABB& bb, EntityList& list);
|
||||
|
||||
//
|
||||
// TileEntity
|
||||
//
|
||||
TileEntity* getTileEntity(int x, int y, int z);
|
||||
//bool hasOtherTileEntity(int x, int y, int z, TileEntity* e);
|
||||
bool hasTileEntityAt(int x, int y, int z);
|
||||
bool hasTileEntityAt(TileEntity* te);
|
||||
void addTileEntity(TileEntity* te);
|
||||
void setTileEntity(int x, int y, int z, TileEntity* tileEntity);
|
||||
void removeTileEntity(int x, int y, int z);
|
||||
|
||||
virtual bool isSkyLit(int x, int y, int z);
|
||||
virtual void lightLava() {}
|
||||
virtual void recalcBlockLights();
|
||||
virtual void skyBrightnessChanged();
|
||||
|
||||
virtual void load();
|
||||
virtual void unload();
|
||||
|
||||
virtual bool shouldSave(bool force);
|
||||
virtual void markUnsaved();
|
||||
|
||||
virtual int countEntities();
|
||||
virtual void getEntities(Entity* except, const AABB& bb, std::vector<Entity*>& es);
|
||||
|
||||
virtual int getTile(int x, int y, int z);
|
||||
virtual bool setTile(int x, int y, int z, int tile_);
|
||||
void setTileRaw(int x, int y, int z, int tile);
|
||||
virtual bool setTileAndData(int x, int y, int z, int tile_, int data_);
|
||||
|
||||
virtual int getData(int x, int y, int z);
|
||||
virtual void setData(int x, int y, int z, int val);
|
||||
|
||||
virtual void setBlocks(unsigned char* newBlocks, int sub);
|
||||
|
||||
virtual int getBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p);
|
||||
virtual int setBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p);
|
||||
|
||||
virtual Random getRandom(long l);
|
||||
|
||||
virtual bool isEmpty();
|
||||
const TEMap& getTileEntityMap() const;
|
||||
private:
|
||||
void lightGap(int x, int z, int source);
|
||||
void lightGaps(int x, int z);
|
||||
|
||||
void recalcHeight(int x, int yStart, int z);
|
||||
public:
|
||||
static bool touchedSky;
|
||||
static const int ChunkBlockCount = CHUNK_BLOCK_COUNT;
|
||||
static const int ChunkSize = ChunkBlockCount;
|
||||
static const int UpdateMapBitShift = 4; // power of (LEVEL_HEIGHT / 8) == 16
|
||||
|
||||
int blocksLength; // ? needed or not? (i.e. are all chunks the same size?)
|
||||
|
||||
bool loaded;
|
||||
Level* level;
|
||||
DataLayer data;
|
||||
DataLayer skyLight;
|
||||
DataLayer blockLight;
|
||||
|
||||
char heightmap[CHUNK_COLUMNS];
|
||||
unsigned char updateMap[CHUNK_COLUMNS]; // marks regions within block columns that have been modified
|
||||
int minHeight;
|
||||
|
||||
const int x, z;
|
||||
const int xt, zt;
|
||||
|
||||
bool terrainPopulated;
|
||||
bool unsaved;
|
||||
bool dontSave;
|
||||
bool createdFromSave;
|
||||
bool lastSaveHadEntities;
|
||||
long lastSaveTime;
|
||||
protected:
|
||||
unsigned char* blocks;
|
||||
|
||||
static const int EntityBlocksArraySize = 128/16;
|
||||
std::vector<Entity*> entityBlocks[EntityBlocksArraySize];
|
||||
|
||||
TEMap tileEntities;
|
||||
};
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__LevelChunk_H__*/
|
||||
30
src/world/level/chunk/storage/ChunkStorage.h
Executable file
30
src/world/level/chunk/storage/ChunkStorage.h
Executable file
@@ -0,0 +1,30 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__ChunkStorage_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__ChunkStorage_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk.storage;
|
||||
|
||||
class Level;
|
||||
class LevelChunk;
|
||||
|
||||
/**@todo: load, save* threw exceptions - I think we need to substitute
|
||||
it for something else since it hasn't very good support on
|
||||
all embedded devices */
|
||||
|
||||
/*was-interface*/
|
||||
class ChunkStorage {
|
||||
public:
|
||||
virtual ~ChunkStorage() {}
|
||||
virtual LevelChunk* load(Level* level, int x, int z) {
|
||||
return NULL;
|
||||
}
|
||||
virtual void save(Level* level, LevelChunk* levelChunk) {}
|
||||
virtual void saveEntities(Level* level, LevelChunk* levelChunk) {}
|
||||
virtual void saveAll(Level* level, std::vector<LevelChunk*>& levelChunks) {
|
||||
for (unsigned int i = 0; i < levelChunks.size(); ++i) save(level, levelChunks[i]);
|
||||
}
|
||||
|
||||
virtual void tick() {}
|
||||
virtual void flush() {}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__ChunkStorage_H__*/
|
||||
10
src/world/level/chunk/storage/MemoryChunkStorage.h
Executable file
10
src/world/level/chunk/storage/MemoryChunkStorage.h
Executable file
@@ -0,0 +1,10 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__MemoryChunkStorage_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__MemoryChunkStorage_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk.storage;
|
||||
|
||||
#include "ChunkStorage.h"
|
||||
|
||||
class MemoryChunkStorage: public ChunkStorage {};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__MemoryChunkStorage_H__*/
|
||||
Reference in New Issue
Block a user