the whole game

This commit is contained in:
2026-03-02 22:04:18 +03:00
parent 816e9060b4
commit f0617a5d22
2069 changed files with 581500 additions and 0 deletions

49
src/world/level/ChunkPos.h Executable file
View File

@@ -0,0 +1,49 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__ChunkPos_H__
#define NET_MINECRAFT_WORLD_LEVEL__ChunkPos_H__
//package net.minecraft.world.level;
#include "../entity/Entity.h"
class ChunkPos {
public:
const int x, z;
ChunkPos()
: x(0),
z(0)
{}
ChunkPos(int x_, int z_)
: x(x_),
z(z_)
{}
static int hashCode(int x, int z) {
return (x < 0 ? 0x80000000 : 0) | ((x & 0x7fff) << 16) | (z < 0 ? 0x00008000 : 0) | (z & 0x7fff);
}
int hashCode() const {
return hashCode(x, z);
}
bool operator==(const ChunkPos& rhs) const {
return x == rhs.x && z == rhs.z;
}
bool operator<(const ChunkPos& rhs) const {
return hashCode() < rhs.hashCode();
}
float distanceToSqr(const Entity* e) const {
float xPos = (float) (x * 16 + 8);
float zPos = (float) (z * 16 + 8);
float xd = xPos - e->x;
float zd = zPos - e->z;
return xd * xd + zd * zd;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__ChunkPos_H__*/

164
src/world/level/Explosion.cpp Executable file
View File

@@ -0,0 +1,164 @@
#include "Explosion.h"
#include "Level.h"
#include "tile/Tile.h"
#include "../entity/Entity.h"
Explosion::Explosion(Level* level, Entity* source, float x, float y, float z, float r)
: level(level),
source(source),
x(x),
y(y),
z(z),
r(r),
fire(false)
{
}
void Explosion::explode()
{
float org = r;
int size = 16;
for (int xx = 0; xx < size; xx++)
for (int yy = 0; yy < size; yy++)
for (int zz = 0; zz < size; zz++) {
if ((xx != 0 && xx != size - 1) && (yy != 0 && yy != size - 1) && (zz != 0 && zz != size - 1)) continue;
float xd = xx / (size - 1.0f) * 2 - 1;
float yd = yy / (size - 1.0f) * 2 - 1;
float zd = zz / (size - 1.0f) * 2 - 1;
float d = sqrt(xd * xd + yd * yd + zd * zd);
xd /= d;
yd /= d;
zd /= d;
float remainingPower = r * (0.7f + level->random.nextFloat() * 0.6f);
float xp = x;
float yp = y;
float zp = z;
float stepSize = 0.3f;
while (remainingPower > 0) {
int xt = Mth::floor(xp);
int yt = Mth::floor(yp);
int zt = Mth::floor(zp);
int t = level->getTile(xt, yt, zt);
if (t > 0) {
remainingPower -= (Tile::tiles[t]->getExplosionResistance(source) + 0.3f) * stepSize;
}
if (remainingPower > 0) {
toBlow.insert(TilePos(xt, yt, zt));
}
xp += xd * stepSize;
yp += yd * stepSize;
zp += zd * stepSize;
remainingPower -= stepSize * 0.75f;
}
}
r += r;
int x0 = Mth::floor(x - r - 1);
int x1 = Mth::floor(x + r + 1);
int y0 = Mth::floor(y - r - 1);
int y1 = Mth::floor(y + r + 1);
int z0 = Mth::floor(z - r - 1);
int z1 = Mth::floor(z + r + 1);
EntityList& entities = level->getEntities(source, AABB((float)x0, (float)y0, (float)z0, (float)x1, (float)y1, (float)z1));
Vec3 center(x, y, z);
for (unsigned int i = 0; i < entities.size(); i++) {
Entity* e = entities[i];
float dist = e->distanceTo(x, y, z) / r;
if (dist <= 1) {
float xa = e->x - x;
float ya = e->y - y;
float za = e->z - z;
float ida = Mth::invSqrt(xa * xa + ya * ya + za * za);
xa *= ida;
ya *= ida;
za *= ida;
float sp = level->getSeenPercent(center, e->bb);
float pow = (1 - dist) * sp;
e->hurt(source, (int) ((pow * pow + pow) / 2 * 8 * r + 1));
float push = pow;
e->xd += xa * push;
e->yd += ya * push;
e->zd += za * push;
}
}
r = org;
std::vector<TilePos> toBlowArray;
toBlowArray.insert(toBlowArray.end(), toBlow.begin(), toBlow.end());
if (fire) {
for (int j = (int)toBlowArray.size() - 1; j >= 0; j--) {
const TilePos& tp = toBlowArray[j];
int xt = tp.x;
int yt = tp.y;
int zt = tp.z;
int t = level->getTile(xt, yt, zt);
int b = level->getTile(xt, yt - 1, zt);
if (t == 0 && Tile::solid[b] && random.nextInt(3) == 0) {
level->setTileNoUpdate(xt, yt, zt, ((Tile*)Tile::fire)->id);
}
}
}
}
void Explosion::finalizeExplosion()
{
level->playSound(x, y, z, "random.explode", 4, (1 + (level->random.nextFloat() - level->random.nextFloat()) * 0.2f) * 0.7f);
//level->addParticle(PARTICLETYPE(hugeexplosion), x, y, z, 0, 0, 0);
int j = 0;
for (TilePosSet::const_iterator cit = toBlow.begin(); cit != toBlow.end(); ++cit, ++j) {
const TilePos& tp = *cit;
int xt = tp.x;
int yt = tp.y;
int zt = tp.z;
int t = level->getTile(xt, yt, zt);
do {
if (j & 7) break;
float xa = xt + level->random.nextFloat();
float ya = yt + level->random.nextFloat();
float za = zt + level->random.nextFloat();
float xd = xa - x;
float yd = ya - y;
float zd = za - z;
float invdd = 1.0f / Mth::sqrt(xd * xd + yd * yd + zd * zd);
xd *= invdd;
yd *= invdd;
zd *= invdd;
float speed = 0.5f / (r / invdd + 0.1f);
speed *= (level->random.nextFloat() * level->random.nextFloat() + 0.3f);
xd *= speed;
yd *= speed;
zd *= speed;
level->addParticle(PARTICLETYPE(explode), (xa + x * 1) / 2, (ya + y * 1) / 2, (za + z * 1) / 2, xd, yd, zd);
level->addParticle(PARTICLETYPE(smoke), xa, ya, za, xd, yd, zd);
} while (0);
if (t > 0) {
if (!level->isClientSide) Tile::tiles[t]->spawnResources(level, xt, yt, zt, level->getData(xt, yt, zt), 0.3f);
if (level->setTileNoUpdate(xt, yt, zt, 0))
level->updateNeighborsAt(xt, yt, zt, 0);
level->setTileDirty(xt, yt, zt);
if (!level->isClientSide) Tile::tiles[t]->wasExploded(level, xt, yt, zt);
}
}
}

38
src/world/level/Explosion.h Executable file
View File

@@ -0,0 +1,38 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__Explosion_H__
#define NET_MINECRAFT_WORLD_LEVEL__Explosion_H__
//package net.minecraft.world.level;
#include <set>
#include "TilePos.h"
#include "../../util/Random.h"
class Level;
class Entity;
typedef std::set<TilePos> TilePosSet;
class Explosion
{
public:
Explosion(Level* level, Entity* source, float x, float y, float z, float r);
void explode();
void finalizeExplosion();
float x, y, z;
float r;
TilePosSet toBlow;
bool fire;
Entity* source;
private:
Random random;
Level* level;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__Explosion_H__*/

36
src/world/level/FoliageColor.h Executable file
View File

@@ -0,0 +1,36 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__FoliageColor_H__
#define NET_MINECRAFT_WORLD_LEVEL__FoliageColor_H__
//package net.minecraft.world.level;
class FoliageColor
{
public:
// static void init(int[] pixels) {
// FoliageColor::pixels = pixels;
// }
//
// static int get(float temp, float rain) {
// rain *= temp;
// int x = (int) ((1 - temp) * 255);
// int y = (int) ((1 - rain) * 255);
// return pixels[y << 8 | x];
// }
static int getEvergreenColor() {
return 0x619961;
}
static int getBirchColor() {
return 0x80a755;
}
static int getDefaultColor() {
return 0x48b518;
}
private:
//static int pixels[256*256];
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__FoliageColor_H__*/

2241
src/world/level/Level.cpp Executable file

File diff suppressed because it is too large Load Diff

343
src/world/level/Level.h Executable file
View File

@@ -0,0 +1,343 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__Level_H__
#define NET_MINECRAFT_WORLD_LEVEL__Level_H__
//package net.minecraft.world.level;
#include <set>
#include <string>
//#include "world/Difficulty.h"
#include "LevelSettings.h"
#include "LevelConstants.h"
#include "ChunkPos.h"
#include "TickNextTickData.h"
#include "storage/LevelData.h"
#include "LightUpdate.h"
#include "LevelSource.h"
#include "../Pos.h"
#include "../../SharedConstants.h"
#include "biome/Biome.h"
class BiomeSource;
class Dimension;
class ChunkSource;
class LevelStorage;
class LightLayer;
class Path;
class TripodCamera;
class Player;
class PathFinder;
class LevelListener;
class IRakNetInstance;
class Zombie;
class TileEntity;
typedef std::vector<Entity*> EntityList;
typedef std::map<int, Entity*> EntityMap;
typedef std::vector<TileEntity*> TileEntityList;
typedef std::vector<Player*> PlayerList;
typedef std::vector<LevelListener*> ListenerList;
typedef std::set<ChunkPos> ChunkPosSet;
typedef std::set<TickNextTickData> TickDataSet;
typedef std::vector<LightUpdate> LightUpdateList;
typedef struct PRInfo {
PRInfo(Entity* e, int ticks): e(e), ticks(ticks) {}
Entity* e;
int ticks;
} PRInfo;
typedef std::vector<PRInfo> PendingList;
typedef struct AdventureSettings {
AdventureSettings();
bool doTickTime;
bool noPvP;
bool noPvM;
bool noMvP;
bool immutableWorld;
bool showNameTags;
} AdventureSettings;
class Level: public LevelSource
{
static const int MAX_TICK_TILES_PER_TICK = 100; // was 1000
public:
static const int MAX_LEVEL_SIZE = 32000000;
static const short DEPTH = LEVEL_HEIGHT;
static const short SEA_LEVEL = DEPTH / 2 - 1;
static const int MAX_BRIGHTNESS = 15;
static const int TICKS_PER_DAY = SharedConstants::TicksPerSecond * 60 * 16;// SharedConstants::TicksPerSecond * 60 * 12; // ORG:20*60*20
static const int MIDDLE_OF_NIGHT_TIME = 12000;
static const int genDepthBits = 7;
static const int genDepthBitsPlusFour = genDepthBits + 4;
static const int genDepth = 1 << genDepthBits;
static const int genDepthMinusOne = genDepth - 1;
Level(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension = NULL);
virtual ~Level();
void _init(const std::string& levelName, const LevelSettings& settings, int levelVersion, Dimension* fixedDimension);
void validateSpawn();
int getTopTile(int x, int z);
int getTopTileY(int x, int z);
int getTopSolidBlock(int x, int z);
bool isEmptyTile(int x, int y, int z);
bool isSolidRenderTile(int x, int y, int z);
bool isSolidBlockingTile(int x, int y, int z);
int getTile(int x, int y, int z);
bool setTile(int x, int y, int z, int tile);
bool hasChunkAt(int x, int y, int z);
bool hasChunksAt(int x, int y, int z, int r);
bool hasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1);
bool hasChunk(int x, int z);
LevelChunk* getChunkAt(int x, int z);
LevelChunk* getChunk(int x, int z);
bool setTileAndDataNoUpdate(int x, int y, int z, int tile, int data);
bool setTileNoUpdate(int x, int y, int z, int tile);
int getData(int x, int y, int z);
void setData(int x, int y, int z, int data);
bool setDataNoUpdate(int x, int y, int z, int data);
bool setTileAndData(int x, int y, int z, int tile, int data);
void sendTileUpdated(int x, int y, int z);
void lightColumnChanged(int x, int z, int y0, int y1);
void setTileDirty(int x, int y, int z);
void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1);
const Material* getMaterial(int x, int y, int z);
void loadPlayer(Player* player, bool doAddPlayer);
void swap(int x1, int y1, int z1, int x2, int y2, int z2);
void updateNeighborsAt(int x, int y, int z, int tile);
int getHeightmap(int x, int z);
BiomeSource* getBiomeSource();
Biome* getBiome(int x, int z);
int getRawBrightness(int x, int y, int z);
int getRawBrightness(int x, int y, int z, bool propagate);
float getBrightness(int x, int y, int z);
int getBrightness(const LightLayer& layer, int x, int y, int z);
void setBrightness(const LightLayer& layer, int x, int y, int z, int brightness);
void updateLightIfOtherThan(const LightLayer& layer, int x, int y, int z, int expected);
int getLightsToUpdate();
bool updateLights();
void setUpdateLights(bool doUpdate);
void updateLight(const LightLayer& layer, int x0, int y0, int z0, int x1, int y1, int z1);
void updateLight(const LightLayer& layer, int x0, int y0, int z0, int x1, int y1, int z1, bool join);
//HitResult clip(const Vec3& a, const Vec3& b);
HitResult clip(const Vec3& a, const Vec3& b, bool liquid = false, bool solidOnly = false);
bool addEntity(Entity* e);
void removeEntity(Entity* e);
void removePlayer( Player* player );
//void removeEntityImmediately(Entity* e);
//void removeAllPendingEntityRemovals();
Entity* getEntity(int entityId);
Mob* getMob(int entityId);
Biome::MobSpawnerData getRandomMobSpawnAt(const MobCategory& mobCategory, int x, int y, int z);
void addListener(LevelListener* listener);
void removeListener(LevelListener* listener);
void dispatchEntityData(Entity* e);
std::vector<AABB> boxes;
std::vector<AABB>& getCubes(const Entity* source, const AABB& box);
bool isDay();
float getTimeOfDay(float a);
float getSunAngle(float a);
int getSkyDarken(float a);
Vec3 getFogColor(float a);
Vec3 getCloudColor(float a);
Vec3 getSkyColor(Entity* source, float a);
bool canSeeSky(int x, int y, int z);
int getLightDepth(int x, int z);
float getStarBrightness(float a);
bool updateSkyBrightness();
bool isSkyLit(int x, int y, int z);
void tickEntities();
virtual void tick();
void tick(Entity* e);
void tick(Entity* e, bool actual);
bool tickPendingTicks(bool force);
void animateTick(int xt, int yt, int zt);
void addToTickNextTick(int x, int y, int z, int tileId, int tickDelay);
bool isUnobstructed(const AABB& aabb);
float getSeenPercent(const Vec3& center, const AABB& bb);
void explode(Entity* source, float x, float y, float z, float r);
void explode(Entity* source, float x, float y, float z, float r, bool fire);
bool containsAnyLiquid(const AABB& box);
bool containsFireTile(const AABB& box);
bool containsMaterial(const AABB& box, const Material* material);
bool containsLiquid(const AABB& box, const Material* material);
bool checkAndHandleWater(const AABB& box, const Material* material, Entity* e);
void extinguishFire(int x, int y, int z, int face);
//void addEntities(const EntityList& list);
//void removeEntities(const EntityList& list);
//void ensureAdded(Entity* entity);
EntityList& getEntities(Entity* except, const AABB& bb);
const EntityList& getAllEntities();
TileEntity* getTileEntity(int x, int y, int z);
void setTileEntity(int x, int y, int z, TileEntity* tileEntity);
void removeTileEntity(int x, int y, int z);
void tileEntityChanged(int x, int y, int z, TileEntity* te);
void prepare();
bool isNew() { return _isNew; }
int getSeaLevel();
bool mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, unsigned char face);
bool mayInteract(Player* player, int xt, int yt, int zt);
bool findPath(Path* path, Entity* from, Entity* to, float maxDist, bool canOpenDoors, bool avoidWater);
bool findPath(Path* path, Entity* from, int xBest, int yBest, int zBest, float maxDist, bool canOpenDoors, bool avoidWater);
bool getDirectSignal(int x, int y, int z, int dir);
bool hasDirectSignal(int x, int y, int z);
bool getSignal(int x, int y, int z, int dir);
bool hasNeighborSignal(int x, int y, int z);
Player* getNearestPlayer(Entity* source, float maxDist);
Player* getNearestPlayer(float x, float y, float z, float maxDist);
int getEntitiesOfType(int entityType, const AABB& bb, EntityList& list);
int getEntitiesOfClass(int type, const AABB& bb, EntityList& list);
int countInstanceOfType(int typeId);
int countInstanceOfBaseType(int baseTypeId);
// Not currently used in MC either but will perhaps be used later.
virtual void updateSleepingPlayerList() {}
long getTime();
void setTime(long time);
long getSeed();
Pos getSharedSpawnPos();
void setSpawnPos(Pos spawnPos);
void setSpawnSettings(bool spawnEnemies, bool spawnFriendlies);
ChunkSource* getChunkSource();
LevelStorage* getLevelStorage();
LevelData* getLevelData();
void saveLevelData();
//void savePlayerData();
void saveGame();
void loadEntities();
void addParticle(const std::string& id, float x, float y, float z, float xd, float yd, float zd, int data = 0);
void addParticle(ParticleType::Id id, float x, float y, float z, float xd, float yd, float zd, int data = 0);
void playSound(Entity* entity, const std::string& name, float volume, float pitch);
void playSound(float x, float y, float z, const std::string& name, float volume, float pitch);
void levelEvent(Player* source, int type, int x, int y, int z, int data);
void tileEvent(int x, int y, int z, int b0, int b1);
void broadcastEntityEvent(Entity* e, char eventId);
void awakenAllPlayers();
void takePicture( TripodCamera* cam, Entity* e );
/**
* Sets the initial spawn, created this method so we could do a special
* location for the demo version.
*/
/*virtual*/ void setInitialSpawn();
bool inRange(int x, int y, int z);
protected:
void setZombieAi(std::vector<Zombie*>& zombies);
/*virtual*/ void entityAdded(Entity* e);
/*virtual*/ void entityRemoved(Entity* e);
/*virtual*/ void tileUpdated(int x, int y, int z, int tile);
void updateSkyDarken();
virtual ChunkSource* createChunkSource();
private:
void neighborChanged(int x, int y, int z, int type);
//void saveAllChunks();
void tickTiles();
public:
bool instaTick;
bool isClientSide;
bool isGeneratingTerrain;
int difficulty;
AdventureSettings adventureSettings;
int isNightMode();
void setNightMode(bool isNightMode);
EntityList entities;
EntityMap entityIdLookup;
TileEntityList tileEntities;
TileEntityList pendingTileEntities;
bool updatingTileEntities;
PlayerList players;
int skyDarken;
bool noNeighborUpdate;
Dimension* dimension;
IRakNetInstance* raknetInstance;
Random random;
protected:
bool isFindingSpawn;
ListenerList _listeners;
ChunkSource* _chunkSource;
LevelStorage* const levelStorage;
LevelData levelData;
bool allPlayersAreSleeping;
bool _spawnFriendlies;
bool _spawnEnemies;
int _randValue;
int _addend;
private:
EntityList _es;
//EntityList _entitiesToRemove;
TickDataSet _tickNextTickSet;
ChunkPosSet _chunksToPoll;
LightUpdateList _lightUpdates;
EntityMap _pendingEntityData;
bool _updateLights;
int _maxRecurse;
bool _isNew;
bool _nightMode;
PathFinder* _pathFinder;
float _lastSavedPlayerTime;
PendingList _pendingPlayerRemovals;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__Level_H__*/

View File

@@ -0,0 +1,14 @@
#ifndef _MINECRAFT_WORLD_LEVELCONSTANTS_H_
#define _MINECRAFT_WORLD_LEVELCONSTANTS_H_
const int LEVEL_HEIGHT = 128;
const int CHUNK_CACHE_WIDTH = 16; // in chunks
const int CHUNK_WIDTH = 16; // in blocks
const int CHUNK_DEPTH = 16;
const int LEVEL_WIDTH = CHUNK_CACHE_WIDTH * CHUNK_WIDTH;
const int LEVEL_DEPTH = CHUNK_CACHE_WIDTH * CHUNK_DEPTH;
const int CHUNK_COLUMNS = CHUNK_WIDTH * CHUNK_DEPTH;
const int CHUNK_BLOCK_COUNT = CHUNK_COLUMNS * LEVEL_HEIGHT;
#endif

43
src/world/level/LevelListener.h Executable file
View File

@@ -0,0 +1,43 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__LevelListener_H__
#define NET_MINECRAFT_WORLD_LEVEL__LevelListener_H__
//package net.minecraft.world.level;
#include <string>
#include "../entity/EntityTypes.h"
class Entity;
class TripodCamera;
class Player;
class TileEntity;
class LevelListener
{
public:
virtual ~LevelListener() {}
virtual void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1) {}
virtual void tileChanged(int x, int y, int z) {}
virtual void tileBrightnessChanged(int x, int y, int z) { tileChanged(x, y, z); }
virtual void skyColorChanged() {}
virtual void allChanged() {}
virtual void takePicture(TripodCamera* cam, Entity* entity) {}
virtual void addParticle(const std::string& name, float x, float y, float z, float xa, float ya, float za, int data) {}
virtual void addParticle(ParticleType::Id name, float x, float y, float z, float xa, float ya, float za, int data) {}
virtual void playSound(const std::string& name, float x, float y, float z, float volume, float pitch) {}
virtual void playMusic(const std::string& name, float x, float y, float z, float songOffset) {}
virtual void playStreamingMusic(const std::string& name, int x, int y, int z) {}
virtual void entityAdded(Entity* entity) {}
virtual void entityRemoved(Entity* entity) {}
virtual void levelEvent(Player* source, int type, int x, int y, int z, int data) {}
virtual void tileEvent(int x, int y, int z, int b0, int b1) {}
virtual void tileEntityChanged(int x, int y, int z, TileEntity* te) {}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__LevelListener_H__*/

58
src/world/level/LevelSettings.h Executable file
View File

@@ -0,0 +1,58 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__LevelSettings_H__
#define NET_MINECRAFT_WORLD_LEVEL__LevelSettings_H__
//package net.minecraft.world.level;
namespace GameType {
const int Undefined = -1;
const int Survival = 0;
const int Creative = 1;
const int Default = Creative;
}
class LevelSettings
{
public:
LevelSettings(long seed, int gameType)
: seed(seed),
gameType(gameType)
{
}
static LevelSettings None() {
return LevelSettings(-1,-1);
}
long getSeed() const {
return seed;
}
int getGameType() const {
return gameType;
}
//
// Those two should actually not be here
// @todo: Move out when we add LevelSettings.cpp :p
//
static int validateGameType(int gameType) {
switch (gameType) {
case GameType::Creative:
case GameType::Survival:
return gameType;
}
return GameType::Default;
}
static std::string gameTypeToString(int gameType) {
if (gameType == GameType::Survival) return "Survival";
if (gameType == GameType::Creative) return "Creative";
return "Undefined";
}
private:
const long seed;
const int gameType;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__LevelSettings_H__*/

36
src/world/level/LevelSource.h Executable file
View File

@@ -0,0 +1,36 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__LevelSource_H__
#define NET_MINECRAFT_WORLD_LEVEL__LevelSource_H__
//package net.minecraft.world.level;
/*
class BiomeSource;
class TileEntity;
*/
class Material;
class Biome;
class LevelSource
{
public:
virtual ~LevelSource() {}
virtual int getTile(int x, int y, int z) = 0;
virtual bool isEmptyTile(int x, int y, int z) = 0;
//virtual TileEntity* getTileEntity(int x, int y, int z) = 0;
virtual float getBrightness(int x, int y, int z) = 0;
virtual int getData(int x, int y, int z) = 0;
virtual const Material* getMaterial(int xx, int i, int zz) = 0;
virtual bool isSolidRenderTile(int x, int i, int z) = 0;
virtual bool isSolidBlockingTile(int x, int i, int z) = 0;
//virtual BiomeSource* getBiomeSource() = 0;
virtual Biome* getBiome(int x, int z) = 0;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__LevelSource_H__*/

4
src/world/level/LightLayer.cpp Executable file
View File

@@ -0,0 +1,4 @@
#include "LightLayer.h"
const LightLayer LightLayer::Sky(15);
const LightLayer LightLayer::Block(0);

20
src/world/level/LightLayer.h Executable file
View File

@@ -0,0 +1,20 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__LightLayer_H__
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__LightLayer_H__
//package net.minecraft.world.level;
class LightLayer
{
public:
static const LightLayer Sky; // (15)
static const LightLayer Block;// (0)
const int surrounding;
private:
LightLayer(int surrounding_)
: surrounding(surrounding_)
{}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__LightLayer_H__*/

194
src/world/level/LightUpdate.cpp Executable file
View File

@@ -0,0 +1,194 @@
#include "Level.h"
#include "LightUpdate.h"
#include "tile/Tile.h"
//LightUpdate::LightUpdate()
//:
// layer(&LightLayer::Sky),
// x0(0),
// y0(0),
// z0(0),
// x1(1),
// y1(1),
// z1(1)
//{} // for using std::set
LightUpdate::LightUpdate(const LightUpdate* t)
:
layer(t->layer),
x0(t->x0),
y0(t->y0),
z0(t->z0),
x1(t->x1),
y1(t->y1),
z1(t->z1)
{
}
LightUpdate::LightUpdate(const LightUpdate& t)
:
layer(t.layer),
x0(t.x0),
y0(t.y0),
z0(t.z0),
x1(t.x1),
y1(t.y1),
z1(t.z1)
{
}
LightUpdate::LightUpdate(const LightLayer& _layer, int _x0, int _y0, int _z0, int _x1, int _y1, int _z1)
:
layer(&_layer),
x0(_x0),
y0(_y0),
z0(_z0),
x1(_x1),
y1(_y1),
z1(_z1)
{
}
void LightUpdate::operator=(const LightUpdate* t)
{
layer = t->layer;
x0 = t->x0;
y0 = t->y0;
z0 = t->z0;
x1 = t->x1;
y1 = t->y1;
z1 = t->z1;
}
void LightUpdate::update(Level* level)
{
int xd = (x1 - x0) + 1;
int yd = (y1 - y0) + 1;
int zd = (z1 - z0) + 1;
int size = xd * yd * zd;
if (size > 16 * 16 * 128) {
//System.out.println("Light too large, skipping!");
return;
}
int lastxc = 0;
int lastzc = 0;
bool hasLast = false;
bool lastOk = false;
for (int x = x0; x <= x1; x++)
for (int z = z0; z <= z1; z++) {
int xc = x >> 4;
int zc = z >> 4;
bool ok = false;
if (hasLast && xc == lastxc && zc == lastzc) {
ok = lastOk;
} else {
ok = level->hasChunksAt(x, 0, z, 1);
if (ok) {
LevelChunk* lc = level->getChunk(x >> 4, z >> 4);
if (lc->isEmpty()) ok = false;
}
lastOk = ok;
lastxc = xc;
lastzc = zc;
}
if (ok) {
if (y0 < 0) y0 = 0;
if (y1 >= Level::DEPTH) y1 = Level::DEPTH - 1;
for (int y = y0; y <= y1; y++) {
int old = level->getBrightness(*layer, x, y, z);
int target = 0;
int tile = level->getTile(x, y, z);
int block = Tile::lightBlock[tile];
if (block == 0) block = 1;
int emit = 0;
if (layer == &LightLayer::Sky) {
if (level->isSkyLit(x, y, z)) emit = 15;
} else if (layer == &LightLayer::Block) {
emit = Tile::lightEmission[tile];
}
if (block >= 15 && emit == 0) {
target = 0;
} else {
int d0 = level->getBrightness(*layer, x - 1, y, z);
int d1 = level->getBrightness(*layer, x + 1, y, z);
int d2 = level->getBrightness(*layer, x, y - 1, z);
int d3 = level->getBrightness(*layer, x, y + 1, z);
int d4 = level->getBrightness(*layer, x, y, z - 1);
int d5 = level->getBrightness(*layer, x, y, z + 1);
target = d0;
if (d1 > target) target = d1;
if (d2 > target) target = d2;
if (d3 > target) target = d3;
if (d4 > target) target = d4;
if (d5 > target) target = d5;
target -= block;
if (target < 0) target = 0;
if (emit > target) target = emit;
}
if (old != target) {
level->setBrightness(*layer, x, y, z, target);
int t = target - 1;
if (t < 0) t = 0;
level->updateLightIfOtherThan(*layer, x - 1, y, z, t);
level->updateLightIfOtherThan(*layer, x, y - 1, z, t);
level->updateLightIfOtherThan(*layer, x, y, z - 1, t);
if (x + 1 >= x1) level->updateLightIfOtherThan(*layer, x + 1, y, z, t);
if (y + 1 >= y1) level->updateLightIfOtherThan(*layer, x, y + 1, z, t);
if (z + 1 >= z1) level->updateLightIfOtherThan(*layer, x, y, z + 1, t);
}
}
}
}
}
bool LightUpdate::expandToContain(int _x0, int _y0, int _z0, int _x1, int _y1, int _z1) {
if (_x0 >= x0 && _y0 >= y0 && _z0 >= z0 && _x1 <= x1 && _y1 <= y1 && _z1 <= z1) return true;
int r = 1;
if (_x0 >= x0 - r && _y0 >= y0 - r && _z0 >= z0 - r && _x1 <= x1 + r && _y1 <= y1 + r && _z1 <= z1 + r) {
int xs = x1 - x0;
int ys = y1 - y0;
int zs = z1 - z0;
if (_x0 > x0) _x0 = x0;
if (_y0 > y0) _y0 = y0;
if (_z0 > z0) _z0 = z0;
if (_x1 < x1) _x1 = x1;
if (_y1 < y1) _y1 = y1;
if (_z1 < z1) _z1 = z1;
int _xs = _x1 - _x0;
int _ys = _y1 - _y0;
int _zs = _z1 - _z0;
int os = xs * ys * zs;
int ns = _xs * _ys * _zs;
if (ns - os <= 2) {
x0 = _x0;
y0 = _y0;
z0 = _z0;
x1 = _x1;
y1 = _y1;
z1 = _z1;
return true;
}
}
return false;
}

31
src/world/level/LightUpdate.h Executable file
View File

@@ -0,0 +1,31 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__LightUpdate_H__
#define NET_MINECRAFT_WORLD_LEVEL__LightUpdate_H__
//package net.minecraft.world.level;
#include "LightLayer.h"
#include "chunk/LevelChunk.h"
class Level;
class LightUpdate
{
public:
const LightLayer* layer;
int x0, y0, z0;
int x1, y1, z1;
//LightUpdate(); // for using std::set
LightUpdate(const LightUpdate* t);
LightUpdate(const LightUpdate& t);
LightUpdate(const LightLayer& _layer, int _x0, int _y0, int _z0, int _x1, int _y1, int _z1);
void operator=(const LightUpdate* t);
void update(Level* level);
bool expandToContain(int _x0, int _y0, int _z0, int _x1, int _y1, int _z1);
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__LightUpdate_H__*/

284
src/world/level/MobSpawner.cpp Executable file
View File

@@ -0,0 +1,284 @@
#include "MobSpawner.h"
#include <algorithm>
#include "Level.h"
#include "biome/Biome.h"
#include "material/Material.h"
#include "../entity/EntityTypes.h"
#include "../entity/MobFactory.h"
#include "../entity/MobCategory.h"
#include "../entity/player/Player.h"
//#include "../entity/animal/Sheep.h"
//#include "tile/BedTile.h"
std::map<ChunkPos, bool> MobSpawner::chunksToPoll;
static int _bedEnemies[] = {
MobTypes::Spider,
MobTypes::Zombie,
MobTypes::Skeleton,
MobTypes::PigZombie
};
static const std::vector<int> bedEnemies(_bedEnemies, _bedEnemies + sizeof(_bedEnemies) / sizeof(_bedEnemies[0]));
/*static*/
int MobSpawner::tick(Level* level, bool spawnEnemies, bool spawnFriendlies) {
//return 0;
if (!spawnEnemies && !spawnFriendlies) {
return 0;
}
chunksToPoll.clear();
// Add all chunks as a quick-and-dirty test
// (The code above is the same as in the java version)
// This code goes over the whole map one "row" at a time
// Spawn friendlies == loop over whole map, and disable Monster spawning this tick
if (spawnFriendlies) {
spawnEnemies = false;
for (int i = 0; i < 256; ++i)
chunksToPoll.insert( std::make_pair( ChunkPos(i>>4, i&15), false) );
} else {
// Only spawn mobs, check around one player per tick (@todo: optimize the "count instances of"?)
static unsigned int _pid = 0;
if (++_pid >= level->players.size()) _pid = 0;
if (level->players.size()) {
Player* p = level->players[_pid];
int xx = Mth::floor(p->x / 16);
int zz = Mth::floor(p->z / 16);
int r = 128 / 16;
for (int x = -r; x <= r; x++)
for (int z = -r; z <= r; z++) {
const int cx = xx + x;
const int cz = zz + z;
if (cx >= 0 && cx < 16 && cz >= 0 && cz < 16)
chunksToPoll.insert(std::make_pair(ChunkPos(cx, cz), false ));
}
}
}
int count = 0;
Pos spawnPos = level->getSharedSpawnPos();
for (int i = 0; i < MobCategory::numValues; ++i) {
const MobCategory& mobCategory = *MobCategory::values[i];
if ((mobCategory.isFriendly() && !spawnFriendlies) || (!mobCategory.isFriendly() && !spawnEnemies))
continue;
int numMobs = level->countInstanceOfBaseType(mobCategory.getBaseClassId());
if (numMobs > mobCategory.getMaxInstancesPerLevel())
continue;
//LOGI("NumMobs: %d of Category: %d\n", numMobs, mobCategory.getBaseClassId());
chunkLoop:
for(std::map<ChunkPos, bool>::iterator it = chunksToPoll.begin(); it != chunksToPoll.end(); ++it) {
const ChunkPos& cp = it->first;
TilePos start = getRandomPosWithin(level, cp.x * 16, cp.z * 16);
int xStart = start.x;
int yStart = start.y;
int zStart = start.z;
if (level->isSolidBlockingTile(xStart, yStart, zStart)) continue;
if (level->getMaterial(xStart, yStart, zStart) != mobCategory.getSpawnPositionMaterial()) continue;
int clusterSize = 0;
for (int dd = 0; dd < 3; dd++) {
int x = xStart;
int y = yStart;
int z = zStart;
int ss = 6;
Biome::MobSpawnerData currentMobType;
int maxCreatureCount = 999;
int currentCreatureCount = 0;
for (int ll = 0; ll < 4; ll++) {
if (currentCreatureCount > maxCreatureCount)
break;
x += level->random.nextInt(ss) - level->random.nextInt(ss);
y += level->random.nextInt(1) - level->random.nextInt(1);
z += level->random.nextInt(ss) - level->random.nextInt(ss);
// int y = heightMap[x + z * w] + 1;
if (isSpawnPositionOk(mobCategory, level, x, y, z)) {
float xx = (float)x + 0.5f;
float yy = (float)y;
float zz = (float)z + 0.5f;
if (level->getNearestPlayer(xx, yy, zz, (float)MIN_SPAWN_DISTANCE) != NULL) {
continue;
} else {
float xd = xx - spawnPos.x;
float yd = yy - spawnPos.y;
float zd = zz - spawnPos.z;
float sd = xd * xd + yd * yd + zd * zd;
if (sd < MIN_SPAWN_DISTANCE * MIN_SPAWN_DISTANCE) {
continue;
}
}
static Stopwatch sw;
sw.start();
if (!currentMobType.isValid()) {
currentMobType = level->getRandomMobSpawnAt(mobCategory, x, y, z);
if (!currentMobType.isValid())
break;
// Don't allow monster to spawn (much) more than their defined
// probability weight.
if (&mobCategory == &MobCategory::monster) {
int typeCount = level->countInstanceOfType(currentMobType.mobClassId);
int typeMax = (int)(1.5f * currentMobType.randomWeight * mobCategory.getMaxInstancesPerLevel()) / Biome::defaultTotalEnemyWeight;
//LOGI("Has %d (max %d) of type: %d\n", typeCount, typeMax, currentMobType.mobClassId);
if (typeCount >= typeMax)
break;
}
maxCreatureCount = currentMobType.minCount + level->random.nextInt(1 + currentMobType.maxCount - currentMobType.minCount);
}
Mob* tmp = MobFactory::getStaticTestMob(currentMobType.mobClassId, level);
if (!tmp) continue;
tmp->moveTo(xx, yy, zz, 0, 0);
if (!tmp->canSpawn()) continue;
Mob* mob = MobFactory::CreateMob(currentMobType.mobClassId, level);
if (!mob) continue;
if (addMob(level, mob, xx, yy, zz, level->random.nextFloat() * 360, 0, false)) {
++currentCreatureCount;
if (++clusterSize >= mob->getMaxSpawnClusterSize()) goto chunkLoop;
}
else
delete mob;
count += clusterSize;
}
}
}
}
}
return count;
}
/*static*/
void MobSpawner::postProcessSpawnMobs(Level* level, Biome* biome, int xo, int zo, int cellWidth, int cellHeight, Random* random) {
//return;
Biome::MobList mobs = biome->getMobs(MobCategory::creature);
if (mobs.empty()) {
return;
}
while (random->nextFloat() < biome->getCreatureProbability()) {
Biome::MobSpawnerData* type = (Biome::MobSpawnerData*) WeighedRandom::getRandomItem(&level->random, mobs);
int count = type->minCount + random->nextInt(1 + type->maxCount - type->minCount);
int x = xo + random->nextInt(cellWidth);
int z = zo + random->nextInt(cellHeight);
int startX = x, startZ = z;
for (int c = 0; c < count; c++) {
bool success = false;
for (int attempts = 0; !success && attempts < 4; attempts++) {
// these mobs always spawn at the topmost position
int y = level->getTopSolidBlock(x, z);
if (isSpawnPositionOk(MobCategory::creature, level, x, y, z)) {
float xx = (float)x + 0.5f;
float yy = (float)y;
float zz = (float)z + 0.5f;
Mob* mob = MobFactory::CreateMob(type->mobClassId, level);
if (!mob) continue;
// System.out.println("Placing night mob");
mob->moveTo(xx, yy, zz, random->nextFloat() * 360, 0);
level->addEntity(mob);
finalizeMobSettings(mob, level, xx, yy, zz);
success = true;
}
x += random->nextInt(5) - random->nextInt(5);
z += random->nextInt(5) - random->nextInt(5);
while (x < xo || x >= (xo + cellWidth) || z < zo || z >= (zo + cellWidth)) {
x = startX + random->nextInt(5) - random->nextInt(5);
z = startZ + random->nextInt(5) - random->nextInt(5);
}
}
}
}
}
/*static*/
TilePos MobSpawner::getRandomPosWithin(Level* level, int xo, int zo) {
int x = xo + level->random.nextInt(16);
int y = level->random.nextInt(Level::DEPTH); //@note: level->depth);
int z = zo + level->random.nextInt(16);
return TilePos(x, y, z);
}
/*static*/
bool MobSpawner::isSpawnPositionOk(const MobCategory& category, Level* level, int x, int y, int z) {
if (category.getSpawnPositionMaterial() == Material::water) {
return level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z);
} else {
return level->isSolidBlockingTile(x, y - 1, z) && !level->isSolidBlockingTile(x, y, z) && !level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z);
}
}
/*static*/
void MobSpawner::finalizeMobSettings(Mob* mob, Level* level, float xx, float yy, float zz) {
// @todo
// if (mob instanceof Spider && level->random->nextInt(100) == 0) {
// Skeleton skeleton = /*new*/ Skeleton(level);
// skeleton.moveTo(xx, yy, zz, mob.yRot, 0);
// level->addEntity(skeleton);
// skeleton.ride(mob);
// } else if (mob instanceof Sheep) {
// ((Sheep) mob).setColor(Sheep.getSheepColor(level->random));
// }
if (mob->getEntityTypeId() == MobTypes::Sheep) {
((Sheep*) mob)->setColor(Sheep::getSheepColor(&level->random));
}
makeBabyMob(mob, 0.5f);
}
/*static*/
bool MobSpawner::addMob(Level* level, Mob* mob, float xx, float yy, float zz, float yRot, float xRot, bool force)
{
mob->moveTo(xx, yy, zz, yRot, xRot);
if (force || mob->canSpawn()) {
level->addEntity(mob);
finalizeMobSettings(mob, level, xx, yy, zz);
return true;
} else {
//LOGI("Couldn't add the entity\n");
return false;
}
}
void MobSpawner::makeBabyMob( Mob* mob, float probability ) {
static Random babyRandom(98495119L);
if (MobTypes::BaseCreature == mob->getCreatureBaseType()) {
if (babyRandom.nextFloat() < probability)
((Animal*)mob)->setAge(-20 * 60 * SharedConstants::TicksPerSecond);
}
}

41
src/world/level/MobSpawner.h Executable file
View File

@@ -0,0 +1,41 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__MobSpawner_H__
#define NET_MINECRAFT_WORLD_LEVEL__MobSpawner_H__
//package net.minecraft.world.level;
#include <map>
#include <vector>
class Mob;
class Level;
class Biome;
class Random;
class MobCategory;
class TilePos;
class ChunkPos;
//
//@NOTE: This class is FINAL/sealed! (at least in java)
//
class MobSpawner
{
public:
static int tick(Level* level, bool spawnEnemies, bool spawnFriendlies);
static void postProcessSpawnMobs(Level* level, Biome* biome, int xo, int zo, int cellWidth, int cellHeight, Random* random);
static void finalizeMobSettings(Mob* mob, Level* level, float xx, float yy, float zz);
static bool isSpawnPositionOk(const MobCategory& category, Level* level, int x, int y, int z);
static TilePos getRandomPosWithin(Level* level, int xo, int zo);
static bool addMob(Level* level, Mob* mob, float x, float y, float z, float yRot, float xRot, bool force);
static void makeBabyMob(Mob* mob, float probability);
protected:
static const std::vector<int> bedEnemies;
private:
static const int MIN_SPAWN_DISTANCE = 24;
static std::map<ChunkPos, bool> chunksToPoll;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__MobSpawner_H__*/

140
src/world/level/Region.cpp Executable file
View File

@@ -0,0 +1,140 @@
#include "Region.h"
#include "chunk/LevelChunk.h"
#include "material/Material.h"
#include "tile/Tile.h"
#include "Level.h"
Region::Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2) {
this->level = level;
xc1 = x1 >> 4;
zc1 = z1 >> 4;
int xc2 = x2 >> 4;
int zc2 = z2 >> 4;
size_x = xc2 - xc1 + 1;
size_z = zc2 - zc1 + 1;
chunks = new LevelChunk**[size_x];
for (int i = 0; i < size_x; ++i)
chunks[i] = new LevelChunk*[size_z];
for (int xc = xc1; xc <= xc2; xc++) {
for (int zc = zc1; zc <= zc2; zc++) {
chunks[xc - xc1][zc - zc1] = level->getChunk(xc, zc);
}
}
}
Region::~Region() {
for (int i = 0 ; i < size_x; ++i)
delete[] chunks[i];
delete[] chunks;
}
int Region::getTile(int x, int y, int z) {
if (y < 0) return 0;
if (y >= Level::DEPTH) return 0;
int xc = (x >> 4) - xc1;
int zc = (z >> 4) - zc1;
if (xc < 0 || xc >= size_x || zc < 0 || zc >= size_z) {
return 0;
}
LevelChunk* lc = chunks[xc][zc];
if (lc == NULL) return 0;
return lc->getTile(x & 15, y, z & 15);
}
bool Region::isEmptyTile( int x, int y, int z )
{
//return getTile(x, y, z) == 0; //@todo?
return Tile::tiles[getTile(x, y, z)] == NULL;
}
//TileEntity getTileEntity(int x, int y, int z) {
// int xc = (x >> 4) - xc1;
// int zc = (z >> 4) - zc1;
// return chunks[xc][zc].getTileEntity(x & 15, y, z & 15);
//}
float Region::getBrightness(int x, int y, int z) {
return level->dimension->brightnessRamp[getRawBrightness(x, y, z)];
}
int Region::getRawBrightness(int x, int y, int z) {
return getRawBrightness(x, y, z, true);
}
int Region::getRawBrightness(int x, int y, int z, bool propagate) {
if (x < -Level::MAX_LEVEL_SIZE || z < -Level::MAX_LEVEL_SIZE || x >= Level::MAX_LEVEL_SIZE || z > Level::MAX_LEVEL_SIZE) {
return Level::MAX_BRIGHTNESS;
}
if (propagate) {
int id = getTile(x, y, z);
if (id == Tile::stoneSlabHalf->id || id == Tile::farmland->id) {
int br = getRawBrightness(x, y + 1, z, false);
int br1 = getRawBrightness(x + 1, y, z, false);
int br2 = getRawBrightness(x - 1, y, z, false);
int br3 = getRawBrightness(x, y, z + 1, false);
int br4 = getRawBrightness(x, y, z - 1, false);
if (br1 > br) br = br1;
if (br2 > br) br = br2;
if (br3 > br) br = br3;
if (br4 > br) br = br4;
return br;
}
}
if (y < 0) return 0;
if (y >= Level::DEPTH) {
int br = Level::MAX_BRIGHTNESS - level->skyDarken;
if (br < 0) br = 0;
return br;
}
int xc = (x >> 4) - xc1;
int zc = (z >> 4) - zc1;
return chunks[xc][zc]->getRawBrightness(x & 15, y, z & 15, level->skyDarken);
}
int Region::getData(int x, int y, int z) {
if (y < 0) return 0;
if (y >= Level::DEPTH) return 0;
int xc = (x >> 4) - xc1;
int zc = (z >> 4) - zc1;
return chunks[xc][zc]->getData(x & 15, y, z & 15);
}
const Material* Region::getMaterial(int x, int y, int z) {
int t = getTile(x, y, z);
if (t == 0) return Material::air;
return Tile::tiles[t]->material;
}
bool Region::isSolidBlockingTile(int x, int y, int z)
{
Tile* tile = Tile::tiles[getTile(x, y, z)];
if (tile == NULL) return false;
return tile->material->isSolidBlocking() && tile->isCubeShaped();
}
bool Region::isSolidRenderTile(int x, int y, int z) {
Tile* tile = Tile::tiles[getTile(x, y, z)];
if (tile == NULL) return false;
return tile->isSolidRender();
}
Biome* Region::getBiome( int x, int z ) {
return level->getBiome(x, z);
}
//BiomeSource getBiomeSource() {
// return level.getBiomeSource();
//}

39
src/world/level/Region.h Executable file
View File

@@ -0,0 +1,39 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__Region_H__
#define NET_MINECRAFT_WORLD_LEVEL__Region_H__
//package net.minecraft.world.level;
#include "LevelSource.h"
class Level;
class Material;
class LevelChunk;
class Region: public LevelSource
{
public:
Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2);
~Region();
bool isSolidRenderTile(int x, int y, int z);
bool isSolidBlockingTile(int x, int y, int z);
int getTile(int x, int y, int z);
bool isEmptyTile(int x, int y, int z);
float getBrightness(int x, int y, int z);
int getRawBrightness(int x, int y, int z);
int getRawBrightness(int x, int y, int z, bool propagate);
int getData(int x, int y, int z);
const Material* getMaterial(int x, int y, int z);
Biome* getBiome(int x, int z);
private:
int xc1, zc1;
LevelChunk*** chunks;
Level* level;
int size_x;
int size_z;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__Region_H__*/

View File

@@ -0,0 +1,29 @@
#include "TickNextTickData.h"
long TickNextTickData::C = 0;
TickNextTickData::TickNextTickData(int x_, int y_, int z_, int tileId_)
: x(x_), y(y_), z(z_), tileId(tileId_), c(++C)
{
}
bool TickNextTickData::operator==(const TickNextTickData& t) const {
return x == t.x && y == t.y && z == t.z && tileId == t.tileId;
}
int TickNextTickData::hashCode() const {
return (((x * 128 * 1024) + (z * 128) + y) * 256) + tileId;
}
TickNextTickData* TickNextTickData::setDelay(long l) {
this->delay = l;
return this;
}
bool TickNextTickData::operator<(const TickNextTickData& tnd) const {
if (delay < tnd.delay) return true;
if (delay > tnd.delay) return false;
if (c < tnd.c) return true;
if (c > tnd.c) return false;
return false;
}

View File

@@ -0,0 +1,25 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__TickNextTickData_H__
#define NET_MINECRAFT_WORLD_LEVEL__TickNextTickData_H__
//package net.minecraft.world.level;
class TickNextTickData
{
static long C;
long c;
public:
int x, y, z, tileId;
long delay;
TickNextTickData(int x_, int y_, int z_, int tileId_);
int hashCode() const;
bool operator==(const TickNextTickData& t) const;
bool operator<(const TickNextTickData& tnd) const;
TickNextTickData* setDelay(long l);
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__TickNextTickData_H__*/

44
src/world/level/TilePos.h Executable file
View File

@@ -0,0 +1,44 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL__TilePos_H__
#define NET_MINECRAFT_WORLD_LEVEL__TilePos_H__
//package net.minecraft.world.level;
class TilePos
{
public:
int x, y, z;
TilePos(int x_, int y_, int z_)
: x(x_),
y(y_),
z(z_)
{
}
TilePos(const TilePos& rhs)
: x(rhs.x),
y(rhs.y),
z(rhs.z)
{}
bool operator<(const TilePos& rhs) const {
return hashCode() < rhs.hashCode();
}
TilePos& operator=(const TilePos& rhs) {
x = rhs.x;
y = rhs.y;
z = rhs.z;
return *this;
}
bool operator==(const TilePos& rhs) const {
return x == rhs.x && y == rhs.y && z == rhs.z;
}
int hashCode() const {
return x * 8976890 + y * 981131 + z;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL__TilePos_H__*/

229
src/world/level/biome/Biome.cpp Executable file
View File

@@ -0,0 +1,229 @@
#include "BiomeInclude.h"
#include "../levelgen/feature/TreeFeature.h"
#include "../levelgen/feature/TallgrassFeature.h"
#include "../../entity/EntityTypes.h"
#include "../../entity/MobCategory.h"
#include "../../level/tile/TallGrass.h"
Biome* Biome::rainForest = NULL;
Biome* Biome::swampland = NULL;
Biome* Biome::seasonalForest = NULL;
Biome* Biome::forest = NULL;
Biome* Biome::savanna = NULL;
Biome* Biome::shrubland = NULL;
Biome* Biome::taiga = NULL;
Biome* Biome::desert = NULL;
Biome* Biome::plains = NULL;
Biome* Biome::iceDesert = NULL;
Biome* Biome::tundra = NULL;
/*static*/
Biome::MobList Biome::_emptyMobList;
int Biome::defaultTotalEnemyWeight = 0;
int Biome::defaultTotalFriendlyWeight = 0;
/*static*/
Biome* Biome::map[64*64];
Biome::Biome()
: topMaterial(((Tile*)Tile::grass)->id),
material(((Tile*)Tile::dirt)->id),
leafColor(0x4EE031)
{
_friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Sheep, 12, 2, 3));
_friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Pig, 10, 1, 3));
_friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Chicken, 10, 2, 4));
_friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Cow, 8, 2, 3));
_enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Spider, 8, 2, 3));
_enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Zombie, 12, 2, 4));
_enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Skeleton, 6, 1, 3));
_enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Creeper, 4, 1, 1));
//_enemies.insert(_enemies.end(), MobSpawnerData(Slime.class, 10, 4, 4));
//_enemies.insert(_enemies.end(), MobSpawnerData(EnderMan.class, 1, 1, 4));
// wolves are added to forests and taigas
// _friendlies.insert(_friendlies.end(), new MobSpawnerData(Wolf.class, 2));
//_waterFriendlies.insert(_waterFriendlies.end(), (new MobSpawnerData(Squid.class, 10, 4, 4));
//
// Sum up the weights
//
defaultTotalEnemyWeight = 0;
for (MobList::const_iterator cit = _enemies.begin(); cit != _enemies.end(); ++cit)
defaultTotalEnemyWeight += cit->randomWeight;
defaultTotalFriendlyWeight = 0;
for (MobList::const_iterator cit = _friendlies.begin(); cit != _friendlies.end(); ++cit)
defaultTotalFriendlyWeight += cit->randomWeight;
}
Biome* Biome::setName( const std::string& name )
{
this->name = name;
return this;
}
Biome* Biome::setLeafColor( int leafColor )
{
this->leafColor = leafColor;
return this;
}
Biome* Biome::setColor( int color )
{
this->color = color;
return this;
}
Biome* Biome::setSnowCovered()
{
return this;
}
Biome* Biome::clearMobs( bool friendlies /*= true*/, bool waterFriendlies /*= true*/, bool enemies /*= true*/ )
{
if (friendlies) _friendlies.clear();
if (waterFriendlies) _waterFriendlies.clear();
if (enemies) _enemies.clear();
return this;
}
/*static*/
void Biome::recalc()
{
for (int a = 0; a < 64; a++) {
for (int b = 0; b < 64; b++) {
map[a + b * 64] = _getBiome(a / 63.0f, b / 63.0f);
}
}
Biome::desert->topMaterial = Biome::desert->material = (char) Tile::sand->id;
Biome::iceDesert->topMaterial = Biome::iceDesert->material = (char) Tile::sand->id;
}
/*static*/
void Biome::initBiomes() {
rainForest = (new RainforestBiome())->setColor(0x08FA36)->setName("Rainforest")->setLeafColor(0x1FF458);
swampland = (new SwampBiome())->setColor(0x07F9B2)->setName("Swampland")->setLeafColor(0x8BAF48);
seasonalForest = (new Biome())->setColor(0x9BE023)->setName("Seasonal Forest");
forest = (new ForestBiome())->setColor(0x056621)->setName("Forest")->setLeafColor(0x4EBA31);
savanna = (new FlatBiome())->setColor(0xD9E023)->setName("Savanna");
shrubland = (new Biome())->setColor(0xA1AD20)->setName("Shrubland");
taiga = (new TaigaBiome())->setColor(0x2EB153)->setName("Taiga")->setSnowCovered()->setLeafColor(0x7BB731);
desert = (new FlatBiome())->setColor(0xFA9418)->clearMobs(true, true, false)->setName("Desert");
plains = (new FlatBiome())->setColor(0xFFD910)->setName("Plains");
iceDesert = (new FlatBiome())->setColor(0xFFED93)->clearMobs(true, false, false)->setName("Ice Desert")->setSnowCovered()->setLeafColor(0xC4D339);
tundra = (new Biome())->setColor(0x57EBF9)->setName("Tundra")->setSnowCovered()->setLeafColor(0xC4D339);
recalc();
}
/*static*/
void Biome::teardownBiomes() {
delete rainForest; rainForest= NULL;
delete swampland; swampland = NULL;
delete seasonalForest; seasonalForest = NULL;
delete forest; forest = NULL;
delete savanna; savanna = NULL;
delete shrubland; shrubland = NULL;
delete taiga; taiga = NULL;
delete desert; desert = NULL;
delete plains; plains = NULL;
delete iceDesert; iceDesert = NULL;
delete tundra; tundra = NULL;
}
Feature* Biome::getTreeFeature( Random* random )
{
if (random->nextInt(10) == 0) {
//return /*new*/ BasicTree();
}
return new TreeFeature(false);
}
Feature* Biome::getGrassFeature( Random* random ) {
return new TallgrassFeature(Tile::tallgrass->id, TallGrass::TALL_GRASS);
}
Biome* Biome::getBiome( float temperature, float downfall )
{
int a = (int) (temperature * 63);
int b = (int) (downfall * 63);
//printf("Getting biome: %s\n", map[a + b * 64]->name.c_str());
return map[a + b * 64];
}
Biome* Biome::_getBiome( float temperature, float downfall )
{
downfall *= (temperature);
if (temperature < 0.10f) {
return Biome::tundra;
} else if (downfall < 0.20f) {
if (temperature < 0.50f) {
return Biome::tundra;
} else if (temperature < 0.95f) {
return Biome::savanna;
} else {
return Biome::desert;
}
} else if (downfall > 0.5f && temperature < 0.7f) {
return Biome::swampland;
} else if (temperature < 0.50f) {
return Biome::taiga;
} else if (temperature < 0.97f) {
if (downfall < 0.35f) {
return Biome::shrubland;
} else {
return Biome::forest;
}
} else {
if (downfall < 0.45f) {
return Biome::plains;
} else if (downfall < 0.90f) {
return Biome::seasonalForest;
} else {
return Biome::rainForest;
}
}
}
float Biome::adjustScale( float scale )
{
return scale;
}
float Biome::adjustDepth( float depth )
{
return depth;
}
int Biome::getSkyColor( float temp )
{
// temp /= 3.f;
// if (temp < -1) temp = -1;
// if (temp > 1) temp = 1;
return 0x80808080;
//return Color.getHSBColor(224 / 360.0f - temp * 0.05f, 0.50f + temp * 0.1f, 1.0f).getRGB();
}
Biome::MobList& Biome::getMobs(const MobCategory& category)
{
if (&category == &MobCategory::monster)
return _enemies;
if (&category == &MobCategory::creature)
return _friendlies;
if (&category == &MobCategory::waterCreature)
return _waterFriendlies;
LOGE("Unknown MobCategory!");
return _emptyMobList;
}
float Biome::getCreatureProbability() {
return 0.08f;
}

95
src/world/level/biome/Biome.h Executable file
View File

@@ -0,0 +1,95 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__Biome_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__Biome_H__
//package net.minecraft.world.level.biome;
#include <string>
#include <vector>
#include "../../../util/WeighedRandom.h"
class Feature;
class MobCategory;
class Biome
{
public:
static Biome* rainForest;
static Biome* swampland;
static Biome* seasonalForest;
static Biome* forest;
static Biome* savanna;
static Biome* shrubland;
static Biome* taiga;
static Biome* desert;
static Biome* plains;
static Biome* iceDesert;
static Biome* tundra;
class MobSpawnerData: public WeighedRandom::WeighedRandomItem
{
typedef WeighedRandom::WeighedRandomItem super;
public:
int mobClassId;
int minCount;
int maxCount;
MobSpawnerData()
{}
MobSpawnerData(int mobClassId, int probabilityWeight, int minCount, int maxCount)
: super(probabilityWeight),
mobClassId(mobClassId),
minCount(minCount),
maxCount(maxCount)
{}
};
typedef std::vector<MobSpawnerData> MobList;
protected:
Biome();
Biome* setName(const std::string& name);
Biome* setLeafColor(int leafColor);
Biome* setColor(int color);
Biome* setSnowCovered();
Biome* clearMobs(bool friendlies = true, bool waterFriendlies = true, bool enemies = true);
MobList _enemies;
MobList _friendlies;
MobList _waterFriendlies;
static MobList _emptyMobList;
public:
static int defaultTotalEnemyWeight;
static int defaultTotalFriendlyWeight;
virtual ~Biome() {}
static void recalc();
static void initBiomes();
static void teardownBiomes();
virtual Feature* getTreeFeature(Random* random);
virtual Feature* getGrassFeature(Random* random);
static Biome* getBiome(float temperature, float downfall);
static Biome* _getBiome(float temperature, float downfall);
virtual float adjustScale(float scale);
virtual float adjustDepth(float depth);
virtual int getSkyColor(float temp);
virtual MobList& getMobs(const MobCategory& category);
virtual float getCreatureProbability();
std::string name;
int color;
char topMaterial;
char material;
int leafColor;
private:
static Biome* map[64*64];
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__Biome_H__*/

View File

@@ -0,0 +1,11 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__BiomeInclude_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__BiomeInclude_H__
#include "Biome.h"
#include "FlatBiome.h"
#include "ForestBiome.h"
#include "RainforestBiome.h"
#include "SwampBiome.h"
#include "TaigaBiome.h"
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__BiomeInclude_H__*/

View File

@@ -0,0 +1,178 @@
#include "BiomeSource.h"
#include "Biome.h"
#include "../Level.h"
#include "../ChunkPos.h"
const float BiomeSource::zoom = 2 * 1;
const float BiomeSource::tempScale = zoom / 80.0f;
const float BiomeSource::downfallScale = zoom / 40.0f;
const float BiomeSource::noiseScale = 1 / 4.0f;
BiomeSource::BiomeSource()
: temperatureMap(NULL),
downfallMap(NULL),
noiseMap(NULL),
lenTemperatures(0),
lenDownfalls(0),
lenNoises(0),
lenBiomes(0),
temperatures(NULL),
downfalls(NULL),
noises(NULL),
biomes(NULL)
{
biomes = new Biome*[16*16];
}
BiomeSource::BiomeSource( Level* level )
: rndTemperature(level->getSeed() * 9871),
rndDownfall(level->getSeed() * 39811),
rndNoise(level->getSeed() * 543321),
lenTemperatures(0),
lenDownfalls(0),
lenNoises(0),
lenBiomes(0),
temperatures(NULL),
downfalls(NULL),
noises(NULL),
biomes(NULL)
{
temperatureMap = new PerlinSimplexNoise(&rndTemperature, 4);
downfallMap = new PerlinSimplexNoise(&rndDownfall, 4);
noiseMap = new PerlinSimplexNoise(&rndNoise, 2);
biomes = new Biome*[16*16];
temperatures = new float[16*16];
}
BiomeSource::~BiomeSource() {
LOGI("Deleting biome maps...\n");
delete temperatureMap;
delete downfallMap;
delete noiseMap;
LOGI("Deleting biome data arrays...\n");
delete[] temperatures;
delete[] downfalls;
delete[] noises;
delete[] biomes;
}
Biome* BiomeSource::getBiome( const ChunkPos& chunk )
{
return getBiome(chunk.x << 4, chunk.z << 4);
}
Biome* BiomeSource::getBiome( int x, int z )
{
return getBiomeBlock(x, z, 1, 1)[0];
}
//float BiomeSource::getTemperature( int x, int z )
//{
// temperatures = temperatureMap->getRegion(temperatures, x, z, 1, 1, tempScale, tempScale, 0.5f);
// return temperatures[0];
//}
Biome** BiomeSource::getBiomeBlock( int x, int z, int w, int h )
{
biomes = getBiomeBlock(biomes, x, z, w, h);
return biomes;
}
Biome** BiomeSource::getBiomeBlock( Biome** biomes__, int x, int z, int w, int h )
{
//for (int i = 0; i < w*h; ++i) biomes__[i] = Biome::tundra;
//const int size = w * h;
//if (lenBiomes < size) {
// //printf("changing to size: %d (was %d). %d, %d (%d, %d)\n", size, lenBiomes, x, z, w, h);
// if (biomes) delete[] biomes;
// biomes = new Biome*[size];
// lenBiomes = size;
//}
temperatures = temperatureMap->getRegion(temperatures, x, z, w, w, tempScale, tempScale, 0.25f);
downfalls = downfallMap->getRegion(downfalls, x, z, w, w, downfallScale, downfallScale, 0.3333f);
noises = noiseMap->getRegion(noises, x, z, w, w, noiseScale, noiseScale, 0.588f);
int pp = 0;
for (int yy = 0; yy < w; yy++) {
for (int xx = 0; xx < h; xx++) {
float noise = (noises[pp] * 1.1f + 0.5f);
float split2 = 0.01f;
float split1 = 1 - split2;
float temperature = (temperatures[pp] * 0.15f + 0.7f) * split1 + noise * split2;
split2 = 0.002f;
split1 = 1 - split2;
float downfall = (downfalls[pp] * 0.15f + 0.5f) * split1 + noise * split2;
temperature = 1 - ((1 - temperature) * (1 - temperature));
if (temperature < 0) temperature = 0;
if (downfall < 0) downfall = 0;
if (temperature > 1) temperature = 1;
if (downfall > 1) downfall = 1;
temperatures[pp] = temperature;
downfalls[pp] = downfall;
// System.out.println(downfall);
biomes[pp++] = Biome::getBiome(temperature, downfall);
}
}
return biomes;
}
float* BiomeSource::getTemperatureBlock( /*float* temperatures__, */int x, int z, int w, int h )
{
//LOGI("gTempBlock: 1\n");
//const int size = w * h;
//if (lenTemperatures < size) {
// if (temperatures) delete[] temperatures;
// temperatures = new float[size];
// lenTemperatures = size;
//}
float * ot = temperatures;
temperatures = temperatureMap->getRegion(temperatures, x, z, w, h, tempScale, tempScale, 0.25f);
noises = noiseMap->getRegion(noises, x, z, w, h, noiseScale, noiseScale, 0.588f);
if (ot != temperatures) {
LOGI("tmp ptr changed\n");
}
int pp = 0;
for (int yy = 0; yy < w; yy++) {
for (int xx = 0; xx < h; xx++) {
float noise = (noises[pp] * 1.1f + 0.5f);
float split2 = 0.01f;
float split1 = 1 - split2;
float temperature = (temperatures[pp] * 0.15f + 0.7f) * split1 + noise * split2;
temperature = 1 - ((1 - temperature) * (1 - temperature));
if (temperature < 0) temperature = 0;
if (temperature > 1) temperature = 1;
temperatures[pp] = temperature;
pp++;
}
}
// System.out.println(min+", "+max);
return temperatures;
}
//float* BiomeSource::getDownfallBlock( /*float* downfalls__,*/ int x, int z, int w, int h )
//{
// //const int size = w * h;
// //if (lenDownfalls < size) {
// // delete[] downfalls;
// // downfalls = new float[size];
// // lenDownfalls = size;
// //}
//
// downfalls = downfallMap->getRegion(downfalls, x, z, w, w, downfallScale, downfallScale, 0.5f);
// return downfalls;
//}

View File

@@ -0,0 +1,62 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__BiomeSource_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__BiomeSource_H__
//package net.minecraft.world.level.biome;
#include "../../../util/Random.h"
#include "../levelgen/synth/PerlinNoise.h"
typedef PerlinNoise PerlinSimplexNoise;
class Level;
class Biome;
class ChunkPos;
class BiomeSource
{
protected:
BiomeSource();
public:
BiomeSource(Level* level);
virtual ~BiomeSource();
float* temperatures;
float* downfalls;
float* noises;
int lenTemperatures;
int lenDownfalls;
int lenNoises;
int lenBiomes;
virtual Biome* getBiome(const ChunkPos& chunk);
virtual Biome* getBiome(int x, int z);
//virtual float getTemperature(int x, int z);
// Note: The arrays returned here are temporary in the meaning that their
// contents might change in the future. If you need to SAVE the
// values, do a shallow copy to an array of your own.
virtual float* getTemperatureBlock(/*float* temperatures, */ int x, int z, int w, int h);
//virtual float* getDownfallBlock(/*float* downfalls, */int x, int z, int w, int h);
virtual Biome** getBiomeBlock(int x, int z, int w, int h);
private:
virtual Biome** getBiomeBlock(Biome** biomes, int x, int z, int w, int h);
Biome** biomes;
PerlinSimplexNoise* temperatureMap;
PerlinSimplexNoise* downfallMap;
PerlinSimplexNoise* noiseMap;
Random rndTemperature;
Random rndDownfall;
Random rndNoise;
static const float zoom;
static const float tempScale;
static const float downfallScale;
static const float noiseScale;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__BiomeSource_H__*/

View File

@@ -0,0 +1,11 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__FlatBiome_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__FlatBiome_H__
//package net.minecraft.world.level.biome;
#include "Biome.h"
class FlatBiome: public Biome {
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__FlatBiome_H__*/

View File

@@ -0,0 +1,24 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__ForestBiome_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__ForestBiome_H__
//package net.minecraft.world.level.biome;
#include "Biome.h"
#include "../levelgen/feature/TreeFeature.h"
#include "../levelgen/feature/BirchFeature.h"
class ForestBiome: public Biome
{
public:
Feature* getTreeFeature(Random* random) {
if (random->nextInt(5) == 0) {
return new BirchFeature();
}
if (random->nextInt(3) == 0) {
//return new BasicTree();
}
return new TreeFeature(false);
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__ForestBiome_H__*/

View File

@@ -0,0 +1,21 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__RainforestBiome_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__RainforestBiome_H__
//package net.minecraft.world.level.biome;
#include "Biome.h"
#include "../../../util/Random.h"
#include "../levelgen/feature/TreeFeature.h"
class RainforestBiome: public Biome
{
public:
Feature* getTreeFeature(Random* random) {
if (random->nextInt(3) == 0) {
//return new BasicTree();
}
return new TreeFeature(false);
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__RainforestBiome_H__*/

View File

@@ -0,0 +1,11 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__SwampBiome_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__SwampBiome_H__
//package net.minecraft.world.level.biome;
#include "Biome.h"
class SwampBiome: public Biome {
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__SwampBiome_H__*/

View File

@@ -0,0 +1,22 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_BIOME__TaigaBiome_H__
#define NET_MINECRAFT_WORLD_LEVEL_BIOME__TaigaBiome_H__
//package net.minecraft.world.level.biome;
#include "Biome.h"
#include "../../../util/Random.h"
#include "../levelgen/feature/PineFeature.h"
#include "../levelgen/feature/SpruceFeature.h"
class TaigaBiome: public Biome
{
public:
Feature* getTreeFeature(Random* random) {
if (random->nextInt(3) == 0) {
return new PineFeature();
}
return new SpruceFeature();
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_BIOME__TaigaBiome_H__*/

View 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__*/

View 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__*/

View 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__*/

View 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__*/

View 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;
}

View 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__*/

View 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__*/

View 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__*/

View File

@@ -0,0 +1,140 @@
#include "Dimension.h"
#include "NormalDayCycleDimension.h"
//#include "../levelgen/SimpleLevelSource.h"
#include "../levelgen/RandomLevelSource.h"
#include "../Level.h"
#include "../biome/BiomeSource.h"
#include "../chunk/ChunkSource.h"
#include "../tile/Tile.h"
#include "../../../util/Mth.h"
Dimension::Dimension()
: foggy(false),
ultraWarm(false),
hasCeiling(false),
biomeSource(NULL),
id(0)
{
}
Dimension::~Dimension()
{
delete biomeSource;
}
void Dimension::init( Level* level )
{
this->level = level;
init();
updateLightRamp();
}
void Dimension::init()
{
biomeSource = new BiomeSource(level);
}
/*virtual*/
bool Dimension::isValidSpawn(int x, int z) {
int topTile = level->getTopTile(x, z);
if (topTile == Tile::invisible_bedrock->id)
return false;
//if (topTile != Tile::sand->id) return false;
if (!Tile::tiles[topTile]->isSolidRender()) return false;
return true;
}
float Dimension::getTimeOfDay(long time, float a) {
return 1;
}
ChunkSource* Dimension::createRandomLevelSource() {
return new RandomLevelSource(
level,
level->getSeed(),
level->getLevelData()->getGeneratorVersion(),
!level->isClientSide && level->getLevelData()->getSpawnMobs());
//return new PerformanceTestChunkSource(level);
}
void Dimension::updateLightRamp()
{
float ambientLight = 0.05f;
for (int i = 0; i <= 15; /*Level::MAX_BRIGHTNESS;*/ i++) {
float v = (1 - i / (float) (16 /*Level::MAX_BRIGHTNESS*/));
// Boosted ambient lightning by ten times.
brightnessRamp[i] = ((1 - v) / (v * 3 + 1)) * (1 - ambientLight) + ambientLight * 3;
}
}
float* Dimension::getSunriseColor( float td, float a )
{
float span = 0.4f;
float tt = Mth::cos(td * Mth::PI * 2) - 0.0f;
float mid = -0.0f;
if (tt >= mid - span && tt <= mid + span) {
float aa = ((tt - mid) / span) * 0.5f + 0.5f;
float mix = 1 - (((1 - Mth::sin(aa * Mth::PI))) * 0.99f);
mix = mix * mix;
sunriseCol[0] = (aa * 0.3f + 0.7f);
sunriseCol[1] = (aa * aa * 0.7f + 0.2f);
sunriseCol[2] = (aa * aa * 0.0f + 0.2f);
sunriseCol[3] = mix;
return sunriseCol;
}
return NULL;
}
Vec3 Dimension::getFogColor( float td, float a )
{
float br = Mth::cos(td * Mth::PI * 2) * 2 + 0.5f;
if (br < 0.0f) br = 0.0f;
if (br > 1.0f) br = 1.0f;
float r = ((fogColor >> 16) & 0xff) / 255.0f;
float g = ((fogColor >> 8) & 0xff) / 255.0f;
float b = ((fogColor) & 0xff) / 255.0f;
r *= br * 0.94f + 0.06f;
g *= br * 0.94f + 0.06f;
b *= br * 0.91f + 0.09f;
return Vec3(r, g, b);
//return Vec3(0.752941f, 0.847059f, 1);
}
bool Dimension::mayRespawn()
{
return true;
}
Dimension* Dimension::getNew( int id )
{
if (id == NORMAL) return new Dimension();
if (id == NORMAL_DAYCYCLE) return new NormalDayCycleDimension();
return NULL;
}
//
// DimensionFactory
//
#include "../storage/LevelData.h"
Dimension* DimensionFactory::createDefaultDimension(LevelData* data )
{
int dimensionId = Dimension::NORMAL;
switch(data->getGameType()) {
case GameType::Survival: dimensionId = Dimension::NORMAL_DAYCYCLE;
break;
case GameType::Creative:
default:
dimensionId = Dimension::NORMAL;
break;
}
return Dimension::getNew(dimensionId);
}

View File

@@ -0,0 +1,64 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_DIMENSION__Dimension_H__
#define NET_MINECRAFT_WORLD_LEVEL_DIMENSION__Dimension_H__
//package net.minecraft.world.level.dimension;
#include "../../phys/Vec3.h"
class Level;
class BiomeSource;
class ChunkSource;
class Dimension
{
public:
static const int NORMAL = 0;
static const int NORMAL_DAYCYCLE = 10;
Dimension();
virtual ~Dimension();
virtual void init(Level* level);
//@fix @port The caller is responsible for this ChunkSource, I presume
virtual ChunkSource* createRandomLevelSource();
virtual bool isValidSpawn(int x, int z);
virtual bool isNaturalDimension() {
return false;
}
virtual float getTimeOfDay(long time, float a);
virtual float* getSunriseColor(float td, float a);
virtual Vec3 getFogColor(float td, float a);
virtual bool mayRespawn();
// @fix @port Caller is responsible (+ move this to a "factory method" outside?)
// @NOTE: RIGHT NOW, Level deletes the dimension.
static Dimension* getNew(int id);
protected:
virtual void updateLightRamp();
virtual void init();
public:
Level* level;
BiomeSource* biomeSource;
bool foggy;
bool ultraWarm;
bool hasCeiling;
float brightnessRamp[16];//Level::MAX_BRIGHTNESS + 1];
int id;
protected:
static const long fogColor = 0x80daff;//0x406fe5;//0xc0d8ff;
float sunriseCol[4];
};
class LevelData;
class DimensionFactory
{
public:
static Dimension* createDefaultDimension(LevelData* data);
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_DIMENSION__Dimension_H__*/

View File

@@ -0,0 +1,41 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_DIMENSION__NormalDayCycleDimension_H__
#define NET_MINECRAFT_WORLD_LEVEL_DIMENSION__NormalDayCycleDimension_H__
//package net.minecraft.world.level.dimension;
#include "Dimension.h"
#include "../Level.h"
#include "../../../util/Mth.h"
class NormalDayCycleDimension: public Dimension {
public:
float getTimeOfDay(long time, float a) {
int dayStep = (int) (time % Level::TICKS_PER_DAY);
float td = (dayStep + a) / Level::TICKS_PER_DAY - 0.25f;
if (td < 0) td += 1;
if (td > 1) td -= 1;
float tdo = td;
td = 1 - (cos(td * Mth::PI) + 1) * 0.5f;
return tdo + (td - tdo) / 3.0f;
}
Vec3 getFogColor( float td, float a ) {
float br = cos(td * Mth::PI * 2) * 2 + 0.5f;
if (br < 0) br = 0;
if (br > 1.f) br = 1.f;
float r = ((fogColor >> 16) & 0xff) / 255.0f;
float g = ((fogColor >> 8) & 0xff) / 255.0f;
float b = ((fogColor) & 0xff) / 255.0f;
r *= br * 0.94f + 0.06f;
g *= br * 0.94f + 0.06f;
b *= br * 0.91f + 0.09f;
//LOGI("rgb: %f, %f, %f\n", r, g, b);
return Vec3(r, g, b);
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_DIMENSION__NormalDayCycleDimension_H__*/

View File

@@ -0,0 +1,168 @@
#if 0
#include "CanyonFeature.h"
#include "../Level.h"
#include "../tile/Tile.h"
#include "../../../util/Random.h"
#include "../../../util/Mth.h"
void CanyonFeature::addTunnel( int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale )
{
float xMid = xOffs * 16 + 8;
float zMid = zOffs * 16 + 8;
float yRota = 0;
float xRota = 0;
// int dist = CAVE_RADIUS * 16 - 16;
// if (step>0) dist = step*2;
Random random(this->random.nextLong());
if (dist <= 0) {
int max = radius * 16 - 16;
dist = max - random.nextInt(max / 4);
}
bool singleStep = false;
if (step == -1) {
step = dist / 2;
singleStep = true;
}
int splitPoint = random.nextInt(dist / 2) + dist / 4;
bool steep = random.nextInt(6) == 0;
for (; step < dist; step++) {
float rad = 1.5 + (sin(step * Mth::PI / dist) * thickness) * 1;
float yRad = rad * yScale;
float xc = cos(xRot);
float xs = sin(xRot);
xCave += cos(yRot) * xc;
yCave += xs;
zCave += sin(yRot) * xc;
if (steep) {
xRot *= 0.92f;
} else {
xRot *= 0.7f;
}
xRot += xRota * 0.1f;
yRot += yRota * 0.1f;
xRota *= 0.50f;
yRota *= 0.50f;
xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2;
yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4;
if (!singleStep && step == splitPoint && thickness > 1) {
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - Mth::PI / 2, xRot / 3, step, dist, 1.0);
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + Mth::PI / 2, xRot / 3, step, dist, 1.0);
return;
}
if (!singleStep && random.nextInt(4) == 0) continue;
{
float xd = xCave - xMid;
float zd = zCave - zMid;
float remaining = dist - step;
float rr = (thickness + 2) + 16;
if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) {
return;
}
}
if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue;
int x0 = floor(xCave - rad) - xOffs * 16 - 1;
int x1 = floor(xCave + rad) - xOffs * 16 + 1;
int y0 = floor(yCave - yRad) - 1;
int y1 = floor(yCave + yRad) + 1;
int z0 = floor(zCave - rad) - zOffs * 16 - 1;
int z1 = floor(zCave + rad) - zOffs * 16 + 1;
if (x0 < 0) x0 = 0;
if (x1 > 16) x1 = 16;
if (y0 < 1) y0 = 1;
if (y1 > 120) y1 = 120;
if (z0 < 0) z0 = 0;
if (z1 > 16) z1 = 16;
bool detectedWater = false;
for (int xx = x0; !detectedWater && xx < x1; xx++) {
for (int zz = z0; !detectedWater && zz < z1; zz++) {
for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) {
int p = (xx * 16 + zz) * 128 + yy;
if (yy < 0 || yy >= Level::DEPTH) continue;
if (blocks[p] == Tile::water->id || blocks[p] == Tile::calmWater->id) {
detectedWater = true;
}
if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) {
yy = y0;
}
}
}
}
if (detectedWater) continue;
for (int xx = x0; xx < x1; xx++) {
float xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad;
for (int zz = z0; zz < z1; zz++) {
float zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad;
int p = (xx * 16 + zz) * 128 + y1;
bool hasGrass = false;
for (int yy = y1 - 1; yy >= y0; yy--) {
float yd = (yy + 0.5 - yCave) / yRad;
if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) {
int block = blocks[p];
if (block == Tile::grass->id) hasGrass = true;
if (block == Tile::rock->id || block == Tile::dirt->id || block == Tile::grass->id) {
if (yy < 10) {
blocks[p] = (unsigned char) Tile::lava->id;
} else {
blocks[p] = (unsigned char) 0;
if (hasGrass && blocks[p - 1] == Tile::dirt->id) blocks[p - 1] = (unsigned char) Tile::grass->id;
}
}
}
p--;
}
}
}
if (singleStep) break;
}
}
void CanyonFeature::addFeature( Level level, int x, int z, int xOffs, int zOffs, char* blocks )
{
if (random.nextInt(15) != 0) return;
float xCave = x * 16 + random.nextInt(16);
float yCave = random.nextInt(random.nextInt(120) + 8);
float zCave = z * 16 + random.nextInt(16);
float yRot = random.nextFloat() * Mth::PI * 2;
float xRot = ((random.nextFloat() - 0.5f) * 2) / 8;
float thickness = (random.nextFloat() * 2 + random.nextFloat()) + 1;
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 5.0);
}
/* //private
void addCaves(Level level, int xOffs, int zOffs, byte[] blocks) {
int r = radius;
random.setSeed(level.seed);
long xScale = random.nextLong() / 2 * 2 + 1;
long zScale = random.nextLong() / 2 * 2 + 1;
for (int x = xOffs - r; x <= xOffs + r; x++) {
for (int z = zOffs - r; z <= zOffs + r; z++) {
random.setSeed((x * xScale + z * zScale) ^ level.seed);*/
#endif

View File

@@ -0,0 +1,19 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__CanyonFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__CanyonFeature_H__
#if 0
//package net.minecraft.world.level.levelgen;
#include "LargeFeature.h"
class CanyonFeature: public LargeFeature {
/*protected*/
void addTunnel(int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale);
/*protected*/
void addFeature(Level level, int x, int z, int xOffs, int zOffs, char* blocks);
};
#endif
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__CanyonFeature_H__*/

View File

@@ -0,0 +1,176 @@
#if 0
#include "DungeonFeature.h"
#include "../Level.h"
#include "../tile/Tile.h"
#include "../../../util/Random.h"
#include "../../../util/Mth.h"
void DungeonFeature::addRoom( int xOffs, int zOffs, unsigned char* blocks, float xRoom, float yRoom, float zRoom )
{
addTunnel(xOffs, zOffs, blocks, xRoom, yRoom, zRoom, 1 + random.nextFloat() * 6, 0, 0, -1, -1, 0.5);
}
void DungeonFeature::addTunnel( int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale )
{
float xMid = xOffs * 16 + 8;
float zMid = zOffs * 16 + 8;
float yRota = 0;
float xRota = 0;
// int dist = CAVE_RADIUS * 16 - 16;
// if (step>0) dist = step*2;
Random random(this->random.nextLong());
if (dist <= 0) {
int max = radius * 16 - 16;
dist = max - random.nextInt(max / 4);
}
bool singleStep = false;
if (step == -1) {
step = dist / 2;
singleStep = true;
}
int splitPoint = random.nextInt(dist / 2) + dist / 4;
bool steep = random.nextInt(6) == 0;
for (; step < dist; step++) {
float rad = 1.5 + (sin(step * Mth::PI / dist) * thickness) * 1;
float yRad = rad * yScale;
float xc = cos(xRot);
float xs = sin(xRot);
xCave += cos(yRot) * xc;
yCave += xs;
zCave += sin(yRot) * xc;
if (steep) {
xRot *= 0.92f;
} else {
xRot *= 0.7f;
}
xRot += xRota * 0.1f;
yRot += yRota * 0.1f;
xRota *= 0.90f;
yRota *= 0.75f;
xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2;
yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4;
if (!singleStep && step == splitPoint && thickness > 1) {
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - Mth::PI / 2, xRot / 3, step, dist, 1.0);
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + Mth::PI / 2, xRot / 3, step, dist, 1.0);
return;
}
if (!singleStep && random.nextInt(4) == 0) continue;
{
float xd = xCave - xMid;
float zd = zCave - zMid;
float remaining = dist - step;
float rr = (thickness + 2) + 16;
if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) {
return;
}
}
if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue;
int x0 = floor(xCave - rad) - xOffs * 16 - 1;
int x1 = floor(xCave + rad) - xOffs * 16 + 1;
int y0 = floor(yCave - yRad) - 1;
int y1 = floor(yCave + yRad) + 1;
int z0 = floor(zCave - rad) - zOffs * 16 - 1;
int z1 = floor(zCave + rad) - zOffs * 16 + 1;
if (x0 < 0) x0 = 0;
if (x1 > 16) x1 = 16;
if (y0 < 1) y0 = 1;
if (y1 > 120) y1 = 120;
if (z0 < 0) z0 = 0;
if (z1 > 16) z1 = 16;
bool detectedWater = false;
for (int xx = x0; !detectedWater && xx < x1; xx++) {
for (int zz = z0; !detectedWater && zz < z1; zz++) {
for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) {
int p = (xx * 16 + zz) * 128 + yy;
if (yy < 0 || yy >= Level::DEPTH) continue;
if (blocks[p] == Tile::water->id || blocks[p] == Tile::calmWater->id) {
detectedWater = true;
}
if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) {
yy = y0;
}
}
}
}
if (detectedWater) continue;
for (int xx = x0; xx < x1; xx++) {
float xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad;
for (int zz = z0; zz < z1; zz++) {
float zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad;
int p = (xx * 16 + zz) * 128 + y1;
bool hasGrass = false;
for (int yy = y1 - 1; yy >= y0; yy--) {
float yd = (yy + 0.5 - yCave) / yRad;
if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) {
int block = blocks[p];
if (block == Tile::grass->id) hasGrass = true;
if (block == Tile::rock->id || block == Tile.dirt.id || block == Tile.grass.id) {
if (yy < 10) {
blocks[p] = (char) Tile.lava.id;
} else {
blocks[p] = (char) 0;
if (hasGrass && blocks[p - 1] == Tile.dirt.id) blocks[p - 1] = (char) Tile.grass.id;
}
}
}
p--;
}
}
}
if (singleStep) break;
}
}
void DungeonFeature::addFeature( Level level, int x, int z, int xOffs, int zOffs, unsigned char* blocks )
{
int caves = random.nextInt(random.nextInt(random.nextInt(40) + 1) + 1);
if (random.nextInt(15) != 0) caves = 0;
for (int cave = 0; cave < caves; cave++) {
float xCave = x * 16 + random.nextInt(16);
// float yCave = (random.nextInt(random.nextInt(120) + 8) + random.nextInt(128)) / 2;
float yCave = random.nextInt(random.nextInt(120) + 8);
//float yCave = random.nextInt(128);
float zCave = z * 16 + random.nextInt(16);
int tunnels = 1;
if (random.nextInt(4) == 0) {
addRoom(xOffs, zOffs, blocks, xCave, yCave, zCave);
tunnels += random.nextInt(4);
}
for (int i = 0; i < tunnels; i++) {
float yRot = random.nextFloat() * Mth::PI * 2;
float xRot = ((random.nextFloat() - 0.5f) * 2) / 8;
float thickness = random.nextFloat() * 2 + random.nextFloat();
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0);
}
}
}
#endif

View File

@@ -0,0 +1,23 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__DungeonFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__DungeonFeature_H__
#if 0
//package net.minecraft.world.level.levelgen;
#include "LargeFeature.h"
class DungeonFeature: public LargeFeature {
/*protected*/
void addRoom(int xOffs, int zOffs, unsigned char* blocks, float xRoom, float yRoom, float zRoom);
/*protected*/
void addTunnel(int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale);
/*protected*/
void addFeature(Level level, int x, int z, int xOffs, int zOffs, unsigned char* blocks);
};
#endif
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__DungeonFeature_H__*/

View File

View File

@@ -0,0 +1,180 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__LargeCaveFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__LargeCaveFeature_H__
//package net.minecraft.world.level.levelgen;
#include "../../../util/Random.h"
#include "../../../util/Mth.h"
#include "LargeFeature.h"
#include "../Level.h"
#include "../tile/Tile.h"
#include "../tile/GrassTile.h"
class LargeCaveFeature: public LargeFeature
{
protected:
void addRoom(int xOffs, int zOffs, unsigned char* blocks, float xRoom, float yRoom, float zRoom) {
addTunnel(xOffs, zOffs, blocks, xRoom, yRoom, zRoom, 1 + random.nextFloat() * 6, 0, 0, -1, -1, 0.5);
}
void addTunnel(int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale) {
float xMid = (float)(xOffs * 16 + 8);
float zMid = (float)(zOffs * 16 + 8);
float yRota = 0;
float xRota = 0;
Random random(this->random.nextLong());
if (dist <= 0) {
int max = radius * 16 - 16;
dist = max - random.nextInt(max / 4);
}
bool singleStep = false;
if (step == -1) {
step = dist / 2;
singleStep = true;
}
int splitPoint = random.nextInt(dist / 2) + dist / 4;
bool steep = random.nextInt(6) == 0;
for (; step < dist; step++) {
float rad = 1.5f + (sin(step * Mth::PI / dist) * thickness) * 1;
float yRad = rad * yScale;
float xc = cos(xRot);
float xs = sin(xRot);
xCave += cos(yRot) * xc;
yCave += xs;
zCave += sin(yRot) * xc;
if (steep) {
xRot *= 0.92f;
} else {
xRot *= 0.7f;
}
xRot += xRota * 0.1f;
yRot += yRota * 0.1f;
xRota *= 0.90f;
yRota *= 0.75f;
xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2;
yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4;
if (!singleStep && step == splitPoint && thickness > 1) {
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - Mth::PI / 2, xRot / 3, step, dist, 1.0);
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + Mth::PI / 2, xRot / 3, step, dist, 1.0);
return;
}
if (!singleStep && random.nextInt(4) == 0) continue;
{
float xd = xCave - xMid;
float zd = zCave - zMid;
float remaining = (float)(dist - step);
float rr = (thickness + 2) + 16;
if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) {
return;
}
}
if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue;
int x0 = (int)floor(xCave - rad) - xOffs * 16 - 1;
int x1 = (int)floor(xCave + rad) - xOffs * 16 + 1;
int y0 = (int)floor(yCave - yRad) - 1;
int y1 = (int)floor(yCave + yRad) + 1;
int z0 = (int)floor(zCave - rad) - zOffs * 16 - 1;
int z1 = (int)floor(zCave + rad) - zOffs * 16 + 1;
if (x0 < 0) x0 = 0;
if (x1 > 16) x1 = 16;
if (y0 < 1) y0 = 1;
if (y1 > 120) y1 = 120;
if (z0 < 0) z0 = 0;
if (z1 > 16) z1 = 16;
bool detectedWater = false;
for (int xx = x0; !detectedWater && xx < x1; xx++) {
for (int zz = z0; !detectedWater && zz < z1; zz++) {
for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) {
int p = (xx * 16 + zz) * 128 + yy;
if (yy < 0 || yy >= Level::DEPTH) continue;
if (blocks[p] == Tile::water->id || blocks[p] == Tile::calmWater->id) {
detectedWater = true;
}
if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) {
yy = y0;
}
}
}
}
if (detectedWater) continue;
for (int xx = x0; xx < x1; xx++) {
float xd = ((xx + xOffs * 16 + 0.5f) - xCave) / rad;
for (int zz = z0; zz < z1; zz++) {
float zd = ((zz + zOffs * 16 + 0.5f) - zCave) / rad;
int p = (xx * 16 + zz) * 128 + y1;
bool hasGrass = false;
if (xd * xd + zd * zd < 1) {
for (int yy = y1 - 1; yy >= y0; yy--) {
float yd = (yy + 0.5f - yCave) / yRad;
if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) {
int block = blocks[p];
if (block == Tile::grass->id) hasGrass = true;
if (block == Tile::rock->id || block == Tile::dirt->id || block == Tile::grass->id) {
if (yy < 10) {
blocks[p] = (unsigned char) Tile::lava->id;
} else {
blocks[p] = (unsigned char) 0;
if (hasGrass && blocks[p - 1] == Tile::dirt->id) blocks[p - 1] = (unsigned char) Tile::grass->id;
}
}
}
p--;
}
}
}
}
if (singleStep) break;
}
}
void addFeature(Level* level, int x, int z, int xOffs, int zOffs, unsigned char* blocks, int blocksSize) {
int caves = random.nextInt(random.nextInt(random.nextInt(40) + 1) + 1);
if (random.nextInt(15) != 0) caves = 0;
for (int cave = 0; cave < caves; cave++) {
float xCave = (float)(x * 16 + random.nextInt(16));
float yCave = (float)(random.nextInt(random.nextInt(120) + 8));
float zCave = (float)(z * 16 + random.nextInt(16));
int tunnels = 1;
if (random.nextInt(4) == 0) {
addRoom(xOffs, zOffs, blocks, xCave, yCave, zCave);
tunnels += random.nextInt(4);
}
for (int i = 0; i < tunnels; i++) {
float yRot = random.nextFloat() * Mth::PI * 2;
float xRot = ((random.nextFloat() - 0.5f) * 2) / 8;
float thickness = random.nextFloat() * 2 + random.nextFloat();
addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0);
}
}
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__LargeCaveFeature_H__*/

View File

@@ -0,0 +1,27 @@
#include "LargeFeature.h"
#include "../Level.h"
LargeFeature::LargeFeature() : radius(8)
{
}
LargeFeature::~LargeFeature()
{
}
void LargeFeature::apply( ChunkSource* chunkSource, Level* level, int xOffs, int zOffs, unsigned char* blocks, int blocksSize )
{
int r = radius;
random.setSeed(level->getSeed());
long xScale = random.nextLong() / 2 * 2 + 1;
long zScale = random.nextLong() / 2 * 2 + 1;
for (int x = xOffs - r; x <= xOffs + r; x++) {
for (int z = zOffs - r; z <= zOffs + r; z++) {
random.setSeed((x * xScale + z * zScale) ^ level->getSeed());
addFeature(level, x, z, xOffs, zOffs, blocks, blocksSize);
}
}
}

View File

@@ -0,0 +1,27 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__LargeFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__LargeFeature_H__
//package net.minecraft.world.level.levelgen;
#include "../../../util/Random.h"
class Random;
class Level;
class ChunkSource;
class LargeFeature
{
public:
LargeFeature();
virtual ~LargeFeature();
virtual void apply(ChunkSource* chunkSource, Level* level, int xOffs, int zOffs, unsigned char* blocks, int blocksSize);
protected:
virtual void addFeature(Level* level, int x, int z, int xOffs, int zOffs, unsigned char* blocks, int blocksSize) = 0;
int radius;
Random random;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__LargeFeature_H__*/

View File

@@ -0,0 +1,723 @@
#include "RandomLevelSource.h"
#include "feature/FeatureInclude.h"
#include "../Level.h"
#include "../ChunkPos.h"
#include "../MobSpawner.h"
#include "../biome/Biome.h"
#include "../biome/BiomeSource.h"
#include "../chunk/LevelChunk.h"
#include "../material/Material.h"
#include "../tile/Tile.h"
#include "../tile/HeavyTile.h"
#include "../../../util/Random.h"
const float RandomLevelSource::SNOW_CUTOFF = 0.5f;
const float RandomLevelSource::SNOW_SCALE = 0.3f;
static const int MAX_BUFFER_SIZE = 1024;
RandomLevelSource::RandomLevelSource(Level* level, long seed, int version, bool spawnMobs)
: random(seed),
level(level),
lperlinNoise1(&random, 16),
lperlinNoise2(&random, 16),
perlinNoise1(&random, 8),
perlinNoise2(&random, 4),
perlinNoise3(&random, 4),
scaleNoise(&random, 10),
depthNoise(&random, 16),
forestNoise(&random, 8),
spawnMobs(spawnMobs),
pnr(NULL), ar(NULL), br(NULL), sr(NULL), dr(NULL), fi(NULL), fis(NULL)
//biomes(NULL)
{
for (int i=0; i<32; ++i)
for (int j=0; j<32; ++j)
waterDepths[i][j] = 0;
buffer = new float[MAX_BUFFER_SIZE];
Random randomCopy = random;
printf("random.get : %d\n", randomCopy.nextInt());
}
RandomLevelSource::~RandomLevelSource() {
// chunks are deleted in the chunk cache instead
//ChunkMap::iterator it = chunkMap.begin();
//while (it != chunkMap.end()) {
// it->second->deleteBlockData(); //@attn: we delete the block data here, for now
// delete it->second;
// ++it;
//}
delete[] buffer;
delete[] pnr;
delete[] ar;
delete[] br;
delete[] sr;
delete[] dr;
delete[] fi;
delete[] fis;
}
/*public*/
void RandomLevelSource::prepareHeights(int xOffs, int zOffs, unsigned char* blocks, /*Biome*/void* biomes, float* temperatures) {
int xChunks = 16 / CHUNK_WIDTH;
int waterHeight = Level::DEPTH - 64;
int xSize = xChunks + 1;
int ySize = 128 / CHUNK_HEIGHT + 1;
int zSize = xChunks + 1;
buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize);
for (int xc = 0; xc < xChunks; xc++) {
for (int zc = 0; zc < xChunks; zc++) {
for (int yc = 0; yc < 128 / CHUNK_HEIGHT; yc++) {
float yStep = 1 / (float) CHUNK_HEIGHT;
float s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)];
float s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)];
float s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)];
float s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)];
float s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep;
float s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep;
float s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep;
float s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep;
for (int y = 0; y < CHUNK_HEIGHT; y++) {
float xStep = 1 / (float) CHUNK_WIDTH;
float _s0 = s0;
float _s1 = s1;
float _s0a = (s2 - s0) * xStep;
float _s1a = (s3 - s1) * xStep;
for (int x = 0; x < CHUNK_WIDTH; x++) {
int offs = (x + xc * CHUNK_WIDTH) << 11 | (0 + zc * CHUNK_WIDTH) << 7 | (yc * CHUNK_HEIGHT + y);
int step = 1 << 7;
float zStep = 1 / (float) CHUNK_WIDTH;
float val = _s0;
float vala = (_s1 - _s0) * zStep;
for (int z = 0; z < CHUNK_WIDTH; z++) {
// + (zc * CHUNK_WIDTH + z)];
float temp = temperatures[(xc * CHUNK_WIDTH + x) * 16 + (zc * CHUNK_WIDTH + z)];
int tileId = 0;
if (yc * CHUNK_HEIGHT + y < waterHeight) {
if (temp < SNOW_CUTOFF && yc * CHUNK_HEIGHT + y >= waterHeight - 1) {
tileId = Tile::ice->id;
} else {
tileId = Tile::calmWater->id;
}
}
if (val > 0) {
tileId = Tile::rock->id;
} else {
}
blocks[offs] = (unsigned char) tileId;
offs += step;
val += vala;
}
_s0 += _s0a;
_s1 += _s1a;
}
s0 += s0a;
s1 += s1a;
s2 += s2a;
s3 += s3a;
}
}
}
}
}
void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, unsigned char* blocks, Biome** biomes) {
int waterHeight = Level::DEPTH - 64;
float s = 1 / 32.0f;
perlinNoise2.getRegion(sandBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s, s, 1);
perlinNoise2.getRegion(gravelBuffer, (float)(xOffs * 16), 109.01340f, (float)(zOffs * 16), 16, 1, 16, s, 1, s);
perlinNoise3.getRegion(depthBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s * 2, s * 2, s * 2);
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
float temp = 1; // @todo: read temp from BiomeSource
Biome* b = biomes[x + z * 16];
bool sand = (sandBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 0;
bool gravel = (gravelBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 3;
int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random.nextFloat() * 0.25f);
int run = -1;
char top = b->topMaterial;
char material = b->material;
for (int y = 127; y >= 0; y--) {
int offs = (z * 16 + x) * 128 + y;
if (y <= 0 + random.nextInt(5)) {
blocks[offs] = (char) Tile::unbreakable->id;
} else {
int old = blocks[offs];
if (old == 0) {
run = -1;
} else if (old == Tile::rock->id) {
if (run == -1) {
if (runDepth <= 0) {
top = 0;
material = (char) Tile::rock->id;
} else if (y >= waterHeight - 4 && y <= waterHeight + 1) {
top = b->topMaterial;
material = b->material;
//@attn: ?
if (gravel) {
top = 0;
material = (char) Tile::gravel->id;
}
if (sand) {
top = (char) Tile::sand->id;
material = (char) Tile::sand->id;
}
}
if (y < waterHeight && top == 0) {
if (temp < 0.15f)
top = (char) Tile::ice->id;
else
top = (char) Tile::calmWater->id;
}
run = runDepth;
if (y >= waterHeight - 1) blocks[offs] = top;
else blocks[offs] = material;
} else if (run > 0) {
run--;
blocks[offs] = material;
// place a few sandstone blocks beneath sand
// runs
if (run == 0 && material == Tile::sand->id) {
run = random.nextInt(4);
material = (char) Tile::sandStone->id;
}
}
}
}
}
}
}
}
/*public*/
void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) {
level->isGeneratingTerrain = true;
HeavyTile::instaFall = true;
int xo = xt * 16;
int zo = zt * 16;
Biome* biome = level->getBiomeSource()->getBiome(xo + 16, zo + 16);
// Biome* biome = Biome::forest;
random.setSeed(level->getSeed());
int xScale = random.nextInt() / 2 * 2 + 1;
int zScale = random.nextInt() / 2 * 2 + 1;
random.setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed());
// //@todo: hide those chunks if they are aren't visible
// if (random.nextInt(4) == 0) {
// int x = xo + random.nextInt(16) + 8;
// int y = random.nextInt(128);
// int z = zo + random.nextInt(16) + 8;
// LakeFeature feature(Tile::calmWater->id);
// feature.place(level, &random, x, y, z);
// LOGI("Adding underground lake @ (%d,%d,%d)\n", x, y, z);
// }
////@todo: hide those chunks if they are aren't visible
// if (random.nextInt(8) == 0) {
// int x = xo + random.nextInt(16) + 8;
// int y = random.nextInt(random.nextInt(120) + 8);
// int z = zo + random.nextInt(16) + 8;
// if (y < 64 || random.nextInt(10) == 0) {
// LakeFeature feature(Tile::calmLava->id);
// feature.place(level, &random, x, y, z);
// }
// }
static float totalTime = 0;
const float st = getTimeS();
//for (int i = 0; i < 8; i++) {
// int x = xo + random.nextInt(16) + 8;
// int y = random.nextInt(128);
// int z = zo + random.nextInt(16) + 8;
// MonsterRoomFeature().place(level, random, x, y, z);
//}
for (int i = 0; i < 10; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(128);
int z = zo + random.nextInt(16);
ClayFeature feature(32);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 20; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(128);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::dirt->id, 32);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 10; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(128);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::gravel->id, 32);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 20; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(128);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::coalOre->id, 16);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 20; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(64);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::ironOre->id, 8);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 2; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(32);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::goldOre->id, 8);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 8; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(16);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::redStoneOre->id, 7);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 1; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(16);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::emeraldOre->id, 7);
feature.place(level, &random, x, y, z);
}
// lapis ore
for (int i = 0; i < 1; i++) {
int x = xo + random.nextInt(16);
int y = random.nextInt(16) + random.nextInt(16);
int z = zo + random.nextInt(16);
OreFeature feature(Tile::lapisOre->id, 6);
feature.place(level, &random, x, y, z);
}
const float ss = 0.5f;
int oFor = (int) ((forestNoise.getValue(xo * ss, zo * ss) / 8 + random.nextFloat() * 4 + 4) / 3);
int forests = 0;//1; (java: 0)
if (random.nextInt(10) == 0) forests += 1;
if (biome == Biome::forest) forests += oFor + 2; // + 5
if (biome == Biome::rainForest) forests += oFor + 2; //+ 5
if (biome == Biome::seasonalForest) forests += oFor + 1; // 2
if (biome == Biome::taiga) {
forests += oFor + 1; // + 5
//LOGI("Biome is taiga!\n");
}
if (biome == Biome::desert) forests -= 20;
if (biome == Biome::tundra) forests -= 20;
if (biome == Biome::plains) forests -= 20;
for (int i = 0; i < forests; i++) {
int x = xo + random.nextInt(16) + 8;
int z = zo + random.nextInt(16) + 8;
int y = level->getHeightmap(x, z);
Feature* tree = biome->getTreeFeature(&random);
if (tree) {
tree->init(1, 1, 1);
tree->place(level, &random, x, y, z);
delete tree;
}
//printf("placing tree at %d, %d, %d\n", x, y, z);
}
for (int i = 0; i < 2; i++) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(128);
int z = zo + random.nextInt(16) + 8;
FlowerFeature feature(Tile::flower->id);
feature.place(level, &random, x, y, z);
}
if (random.nextInt(2) == 0) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(128);
int z = zo + random.nextInt(16) + 8;
FlowerFeature feature(Tile::rose->id);
feature.place(level, &random, x, y, z);
}
if (random.nextInt(4) == 0) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(128);
int z = zo + random.nextInt(16) + 8;
FlowerFeature feature(Tile::mushroom1->id);
feature.place(level, &random, x, y, z);
}
if (random.nextInt(8) == 0) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(128);
int z = zo + random.nextInt(16) + 8;
FlowerFeature feature(Tile::mushroom2->id);
feature.place(level, &random, x, y, z);
}
/*int grassCount = 1;
for (int i = 0; i < grassCount; i++) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(Level::genDepth);
int z = zo + random.nextInt(16) + 8;
Feature* grassFeature = biome->getGrassFeature(&random);
if (grassFeature) {
grassFeature->place(level, &random, x, y, z);
delete grassFeature;
}
}*/
for (int i = 0; i < 10; i++) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(128);
int z = zo + random.nextInt(16) + 8;
ReedsFeature feature;
feature.place(level, &random, x, y, z);
}
//if (random.nextInt(32) == 0) {
// int x = xo + random.nextInt(16) + 8;
// int y = random.nextInt(128);
// int z = zo + random.nextInt(16) + 8;
// PumpkinFeature().place(level, random, x, y, z);
//}
int cacti = 0;
if (biome == Biome::desert) cacti += 5;
for (int i = 0; i < cacti; i++) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(128);
int z = zo + random.nextInt(16) + 8;
CactusFeature feature;
//LOGI("Tried creating a cactus at %d, %d, %d\n", x, y, z);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 50; i++) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(random.nextInt(120) + 8);
int z = zo + random.nextInt(16) + 8;
SpringFeature feature(Tile::water->id);
feature.place(level, &random, x, y, z);
}
for (int i = 0; i < 20; i++) {
int x = xo + random.nextInt(16) + 8;
int y = random.nextInt(random.nextInt(random.nextInt(112) + 8) + 8);
int z = zo + random.nextInt(16) + 8;
SpringFeature feature(Tile::lava->id);
feature.place(level, &random, x, y, z);
}
if (spawnMobs && !level->isClientSide)
MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, &random);
//LOGI("Reading temp: 1\n");
float* temperatures = level->getBiomeSource()->getTemperatureBlock(/*NULL,*/ xo + 8, zo + 8, 16, 16);
for (int x = xo + 8; x < xo + 8 + 16; x++)
for (int z = zo + 8; z < zo + 8 + 16; z++) {
int xp = x - (xo + 8);
int zp = z - (zo + 8);
int y = level->getTopSolidBlock(x, z);
float temp = temperatures[xp * 16 + zp] - (y - 64) / 64.0f * SNOW_SCALE;
if (temp < SNOW_CUTOFF) {
if (y > 0 && y < 128 && level->isEmptyTile(x, y, z) && level->getMaterial(x, y - 1, z)->blocksMotion()) {
if (level->getMaterial(x, y - 1, z) != Material::ice) level->setTile(x, y, z, Tile::topSnow->id);
}
}
}
//LOGI("Reading temp: 0 END\n");
const float et = getTimeS();
totalTime += (et-st);
//printf("Time to place features: %f. Total %f\n", et - st, totalTime);
HeavyTile::instaFall = false;
level->isGeneratingTerrain = false;
}
LevelChunk* RandomLevelSource::create(int x, int z) {
return getChunk(x, z);
}
LevelChunk* RandomLevelSource::getChunk(int xOffs, int zOffs) {
//static int chunkx = 0;
int hashedPos = ChunkPos::hashCode(xOffs, zOffs);
ChunkMap::iterator it = chunkMap.find(hashedPos);
if (it != chunkMap.end())
return it->second;
random.setSeed((long)(xOffs * 341872712l + zOffs * 132899541l)); //@fix
unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount];
LevelChunk* levelChunk = new LevelChunk(level, blocks, xOffs, zOffs);
chunkMap.insert(std::make_pair(hashedPos, levelChunk));
Biome** biomes = level->getBiomeSource()->getBiomeBlock(/*biomes, */xOffs * 16, zOffs * 16, 16, 16);
float* temperatures = level->getBiomeSource()->temperatures;
prepareHeights(xOffs, zOffs, blocks, 0, temperatures);//biomes, temperatures);
buildSurfaces(xOffs, zOffs, blocks, biomes);
//caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount);
levelChunk->recalcHeightmap();
return levelChunk;
}
/*private*/
float* RandomLevelSource::getHeights(float* buffer, int x, int y, int z, int xSize, int ySize, int zSize) {
const int size = xSize * ySize * zSize;
if (size > MAX_BUFFER_SIZE) {
LOGI("RandomLevelSource::getHeights: TOO LARGE BUFFER REQUESTED: %d (max %d)\n", size, MAX_BUFFER_SIZE);
}
float s = 1 * 684.412f;
float hs = 1 * 684.412f;
float* temperatures = level->getBiomeSource()->temperatures;
float* downfalls = level->getBiomeSource()->downfalls;
sr = scaleNoise.getRegion(sr, x, z, xSize, zSize, 1.121f, 1.121f, 0.5f);
dr = depthNoise.getRegion(dr, x, z, xSize, zSize, 200.0f, 200.0f, 0.5f);
pnr = perlinNoise1.getRegion(pnr, (float)x, (float)y, (float)z, xSize, ySize, zSize, s / 80.0f, hs / 160.0f, s / 80.0f);
ar = lperlinNoise1.getRegion(ar, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s);
br = lperlinNoise2.getRegion(br, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s);
int p = 0;
int pp = 0;
int wScale = 16 / xSize;
for (int xx = 0; xx < xSize; xx++) {
int xp = xx * wScale + wScale / 2;
for (int zz = 0; zz < zSize; zz++) {
int zp = zz * wScale + wScale / 2;
float temperature = temperatures[xp * 16 + zp];
float downfall = downfalls[xp * 16 + zp] * temperature;
float dd = 1 - downfall;
dd = dd * dd;
dd = dd * dd;
dd = 1 - dd;
float scale = ((sr[pp] + 256.0f) / 512);
scale *= dd;
if (scale > 1) scale = 1;
float depth = (dr[pp] / 8000.0f);
if (depth < 0) depth = -depth * 0.3f;
depth = depth * 3.0f - 2.0f;
if (depth < 0) {
depth = depth / 2;
if (depth < -1) depth = -1;
depth = depth / 1.4f;
depth /= 2;
scale = 0;
} else {
if (depth > 1) depth = 1;
depth = depth / 8;
}
if (scale < 0) scale = 0;
scale = (scale) + 0.5f;
depth = depth * ySize / 16;
float yCenter = ySize / 2.0f + depth * 4;
pp++;
for (int yy = 0; yy < ySize; yy++) {
float val = 0;
float yOffs = (yy - (yCenter)) * 12 / scale;
if (yOffs < 0) yOffs *= 4;
float bb = ar[p] / 512;
float cc = br[p] / 512;
float v = (pnr[p] / 10 + 1) / 2;
if (v < 0) val = bb;
else if (v > 1) val = cc;
else val = bb + (cc - bb) * v;
val -= yOffs;
if (yy > ySize - 4) {
float slide = (yy - (ySize - 4)) / (4 - 1.0f);
val = val * (1 - slide) + -10 * slide;
}
buffer[p] = val;
p++;
}
}
}
return buffer;
}
/*private*/
void RandomLevelSource::calcWaterDepths(ChunkSource* parent, int xt, int zt) {
int xo = xt * 16;
int zo = zt * 16;
for (int x = 0; x < 16; x++) {
int y = level->getSeaLevel();
for (int z = 0; z < 16; z++) {
int xp = xo + x + 7;
int zp = zo + z + 7;
int h = level->getHeightmap(xp, zp);
if (h <= 0) {
if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) {
bool hadWater = false;
if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater->id && level->getData(xp - 1, y, zp) < 7)) hadWater = true;
if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater->id && level->getData(xp + 1, y, zp) < 7)) hadWater = true;
if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater->id && level->getData(xp, y, zp - 1) < 7)) hadWater = true;
if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater->id && level->getData(xp, y, zp + 1) < 7)) hadWater = true;
if (hadWater) {
for (int x2 = -5; x2 <= 5; x2++) {
for (int z2 = -5; z2 <= 5; z2++) {
int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2);
if (d <= 5) {
d = 6 - d;
if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater->id) {
int od = level->getData(xp + x2, y, zp + z2);
if (od < 7 && od < d) {
level->setData(xp + x2, y, zp + z2, d);
}
}
}
}
}
if (hadWater) {
level->setTileAndDataNoUpdate(xp, y, zp, Tile::calmWater->id, 7);
for (int y2 = 0; y2 < y; y2++) {
level->setTileAndDataNoUpdate(xp, y2, zp, Tile::calmWater->id, 8);
}
}
}
}
}
}
}
}
bool RandomLevelSource::hasChunk(int x, int y) {
//return x >= 0 && x < 16 && y >= 0 && y < 16;
return true;
}
bool RandomLevelSource::tick() {
return false;
}
bool RandomLevelSource::shouldSave() {
return true;
}
std::string RandomLevelSource::gatherStats() {
return "RandomLevelSource";
}
//bool RandomLevelSource::save(bool force, ProgressListener progressListener) {
// return true;
//}
Biome::MobList RandomLevelSource::getMobsAt(const MobCategory& mobCategory, int x, int y, int z) {
BiomeSource* biomeSource = level->getBiomeSource();
if (biomeSource == NULL) {
return Biome::MobList();
}
// static Stopwatch sw; sw.start();
Biome* biome = biomeSource->getBiome(x, z);
// sw.stop();
// sw.printEvery(10, "getBiome::");
if (biome == NULL) {
return Biome::MobList();
}
return biome->getMobs(mobCategory);
}
LevelChunk* PerformanceTestChunkSource::create(int x, int z)
{
unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount];
memset(blocks, 0, LevelChunk::ChunkBlockCount);
for (int y = 0; y < 65; y++)
{
if (y < 60)
{
for (int x = (y + 1) & 1; x < 16; x += 2)
{
for (int z = y & 1; z < 16; z += 2)
{
blocks[x << 11 | z << 7 | y] = 3;
}
}
}
else
{
for (int x = 0; x < 16; x += 2)
{
for (int z = 0; z < 16; z += 2)
{
blocks[x << 11 | z << 7 | y] = 3;
}
}
}
}
LevelChunk* levelChunk = new LevelChunk(level, blocks, x, z);
//caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount);
levelChunk->recalcHeightmap();
return levelChunk;
}

View File

@@ -0,0 +1,125 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__RandomLevelSource_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__RandomLevelSource_H__
//package net.minecraft.world.level.levelgen;
class Biome;
class Level;
class LevelChunk;
#if 1 || USE_MAP
#include <map>
typedef std::map<int, LevelChunk*> ChunkMap;
#else
#if defined(__APPLE__)
#include <ext/hash_map>
namespace std {
using namespace __gnu_cxx;
}
#else
#include <hash_map>
#endif
typedef std::hash_map<int, LevelChunk*> ChunkMap;
#endif
#include "../chunk/ChunkSource.h"
#include "LargeCaveFeature.h"
#include "synth/PerlinNoise.h"
#include "../../../SharedConstants.h"
class RandomLevelSource: public ChunkSource
{
static const float SNOW_CUTOFF;
static const float SNOW_SCALE;
public:
static const int CHUNK_HEIGHT = 8;
static const int CHUNK_WIDTH = 4;
RandomLevelSource(Level* level, long seed, int version, bool spawnMobs);
~RandomLevelSource();
bool hasChunk(int x, int y);
LevelChunk* create(int x, int z);
LevelChunk* getChunk(int xOffs, int zOffs);
void prepareHeights(int xOffs, int zOffs, unsigned char* blocks, /*Biome*/void* biomes, float* temperatures);
void buildSurfaces(int xOffs, int zOffs, unsigned char* blocks, Biome** biomes);
void postProcess(ChunkSource* parent, int xt, int zt);
bool tick();
Biome::MobList getMobsAt(const MobCategory& mobCategory, int x, int y, int z);
bool shouldSave();
std::string gatherStats();
//bool save(bool force, ProgressListener progressListener) {
private:
float* getHeights(float* buffer, int x, int y, int z, int xSize, int ySize, int zSize);
void calcWaterDepths(ChunkSource* parent, int xt, int zt);
public:
//Biome** biomes;
LargeCaveFeature caveFeature;
int waterDepths[16+16][16+16];
private:
ChunkMap chunkMap;
Random random;
PerlinNoise lperlinNoise1;
PerlinNoise lperlinNoise2;
PerlinNoise perlinNoise1;
PerlinNoise perlinNoise2;
PerlinNoise perlinNoise3;
PerlinNoise scaleNoise;
PerlinNoise depthNoise;
PerlinNoise forestNoise;
Level* level;
bool spawnMobs;
float* buffer;
float sandBuffer[16 * 16];
float gravelBuffer[16 * 16];
float depthBuffer[16 * 16];
float* pnr;
float* ar;
float* br;
float* sr;
float* dr;
float* fi;
float* fis;
///*private*/ float[] temperatures;
};
class PerformanceTestChunkSource : public ChunkSource
{
Level* level;
public:
PerformanceTestChunkSource(Level* level)
: ChunkSource(),
level(level)
{
}
virtual bool hasChunk(int x, int y) { return true; };
virtual LevelChunk* getChunk(int x, int z) { return create(x, z); };
virtual LevelChunk* create(int x, int z);
virtual void postProcess(ChunkSource* parent, int x, int z) {};
virtual bool tick() { return false; };
virtual bool shouldSave() { return false; };
/**
* Returns some stats that are rendered when the user holds F3.
*/
virtual std::string gatherStats() { return "PerformanceTestChunkSource"; };
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__RandomLevelSource_H__*/

View File

@@ -0,0 +1,13 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__TownFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__TownFeature_H__
//package net.minecraft.world.level.levelgen;
#include "world/level/Level.h"
/*public*/ class TownFeature extends LargeFeature {
/*protected*/ void addFeature(Level level, int x, int z, int xOffs, int zOffs, byte[] blocks) {
}
}
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN__TownFeature_H__*/

View File

@@ -0,0 +1,75 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__BirchFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__BirchFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../../../util/Random.h"
#include "../../Level.h"
#include "../../tile/LeafTile.h"
#include "../../tile/Tile.h"
#include "../../tile/TreeTile.h"
/**
* Same as tree feature, but slightly taller and white in color
*
*/
class BirchFeature: public Feature
{
typedef Feature super;
public:
BirchFeature(bool doUpdate = false)
: super(doUpdate)
{
}
bool place(Level* level, Random* random, int x, int y, int z) {
int treeHeight = random->nextInt(3) + 5;
bool free = true;
if (y < 1 || y + treeHeight + 1 > Level::DEPTH) return false;
for (int yy = y; yy <= y + 1 + treeHeight; yy++) {
int r = 1;
if (yy == y) r = 0;
if (yy >= y + 1 + treeHeight - 2) r = 2;
for (int xx = x - r; xx <= x + r && free; xx++) {
for (int zz = z - r; zz <= z + r && free; zz++) {
if (yy >= 0 && yy < Level::DEPTH) {
int tt = level->getTile(xx, yy, zz);
if (tt != 0 && tt != ((Tile*)Tile::leaves)->id) free = false;
} else {
free = false;
}
}
}
}
if (!free) return false;
int belowTile = level->getTile(x, y - 1, z);
if ((belowTile != ((Tile*)Tile::grass)->id && belowTile != Tile::dirt->id) || y >= Level::DEPTH - treeHeight - 1) return false;
placeBlock(level, x, y - 1, z, Tile::dirt->id);
for (int yy = y - 3 + treeHeight; yy <= y + treeHeight; yy++) {
int yo = yy - (y + treeHeight);
int offs = 1 - yo / 2;
for (int xx = x - offs; xx <= x + offs; xx++) {
int xo = xx - (x);
for (int zz = z - offs; zz <= z + offs; zz++) {
int zo = zz - (z);
if (std::abs(xo) == offs && std::abs(zo) == offs && (random->nextInt(2) == 0 || yo == 0)) continue;
if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::leaves->id, LeafTile::BIRCH_LEAF);
}
}
}
for (int hh = 0; hh < treeHeight; hh++) {
int t = level->getTile(x, y + hh, z);
if (t == 0 || t == ((Tile*)Tile::leaves)->id) placeBlock(level, x, y + hh, z, Tile::treeTrunk->id, TreeTile::BIRCH_TRUNK);
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__BirchFeature_H__*/

View File

@@ -0,0 +1,35 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__CactusFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__CactusFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "../../../../util/Mth.h"
#include "../../Level.h"
#include "../../tile/CactusTile.h"
/* import net.minecraft.world.level.tile.* */
class CactusFeature: public Feature
{
public:
bool place(Level* level, Random* random, int x, int y, int z) {
for (int i = 0; i < 10; i++) {
int x2 = x + random->nextInt(8) - random->nextInt(8);
int y2 = y + random->nextInt(4) - random->nextInt(4);
int z2 = z + random->nextInt(8) - random->nextInt(8);
if (level->isEmptyTile(x2, y2, z2)) {
int h = 1 + random->nextInt(random->nextInt(3) + 1);
for (int yy = 0; yy < h; yy++) {
if (Tile::cactus->canSurvive(level, x2, y2+yy, z2)) {
//LOGI("Creating cactus part at %d, %d, %d\n", x, y, z);
level->setTileNoUpdate(x2, y2+yy, z2, Tile::cactus->id);
}
}
}
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__CactusFeature_H__*/

View File

@@ -0,0 +1,63 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__ClayFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__ClayFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../Level.h"
#include "../../tile/Tile.h"
#include "../../material/Material.h"
#include "../../../../util/Mth.h"
#include "../../../../util/Random.h"
class ClayFeature: public Feature
{
int tile;
int count;
public:
ClayFeature(int count) {
this->tile = Tile::clay->id;
this->count = count;
}
bool place(Level* level, Random* random, int x, int y, int z) {
if (level->getMaterial(x, y, z) != Material::water) return false;
float dir = random->nextFloat() * Mth::PI;
float x0 = x + 8 + sin(dir) * count / 8;
float x1 = x + 8 - sin(dir) * count / 8;
float z0 = z + 8 + cos(dir) * count / 8;
float z1 = z + 8 - cos(dir) * count / 8;
float y0 = (float)(y + random->nextInt(3) + 2);
float y1 = (float)(y + random->nextInt(3) + 2);
for (int d = 0; d <= count; d++) {
float xx = x0 + (x1 - x0) * d / count;
float yy = y0 + (y1 - y0) * d / count;
float zz = z0 + (z1 - z0) * d / count;
float ss = random->nextFloat() * (float)(count >> 4);
float r = (sin(d * Mth::PI / count) + 1) * ss + 1;
float hr = (sin(d * Mth::PI / count) + 1) * ss + 1;
for (int x2 = (int) (xx - r / 2); x2 <= (int) (xx + r * 0.5f); x2++)
for (int y2 = (int) (yy - hr / 2); y2 <= (int) (yy + hr * 0.5f); y2++)
for (int z2 = (int) (zz - r / 2); z2 <= (int) (zz + r * 0.5f); z2++) {
float xd = ((x2 + 0.5f) - xx) / (r * 0.5f);
float yd = ((y2 + 0.5f) - yy) / (hr * 0.5f);
float zd = ((z2 + 0.5f) - zz) / (r * 0.5f);
if (xd * xd + yd * yd + zd * zd < 1) {
int t = level->getTile(x2, y2, z2);
if (t == Tile::sand->id) level->setTileNoUpdate(x2, y2, z2, tile);
}
}
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__ClayFeature_H__*/

View File

@@ -0,0 +1,26 @@
#include "Feature.h"
Feature::Feature( bool doUpdate /*= false*/ )
: doUpdate(doUpdate)
{
}
void Feature::placeBlock( Level* level, int x, int y, int z, int tile )
{
placeBlock(level, x, y, z, tile, 0);
}
void Feature::placeBlock( Level* level, int x, int y, int z, int tile, int data )
{
if (doUpdate) {
level->setTileAndData(x, y, z, tile, data);
/*
} else if (level->hasChunkAt(x, y, z) && level->getChunkAt(x, z).seenByPlayer) {
if (level->setTileAndDataNoUpdate(x, y, z, tile, data)) {
level->sendTileUpdated(x, y, z);
}
*/
} else {
level->setTileAndDataNoUpdate(x, y, z, tile, data);
}
}

View File

@@ -0,0 +1,23 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__Feature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__Feature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "../../Level.h"
class Random;
class Feature
{
public:
Feature(bool doUpdate = false);
virtual ~Feature() {}
virtual bool place(Level* level, Random* random, int x, int y, int z) = 0;
virtual void init(float v1, float v2, float v3) {}
protected:
void placeBlock(Level* level, int x, int y, int z, int tile);
void placeBlock(Level* level, int x, int y, int z, int tile, int data);
private:
bool doUpdate;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__Feature_H__*/

View File

@@ -0,0 +1,14 @@
#ifndef FEATURE_INCLUDE_H__
#define FEATURE_INCLUDE_H__
#include "Feature.h"
#include "CactusFeature.h"
#include "ClayFeature.h"
#include "FlowerFeature.h"
#include "TreeFeature.h"
#include "LakeFeature.h"
#include "OreFeature.h"
#include "ReedsFeature.h"
#include "SpringFeature.h"
#endif /*FEATURE_INCLUDE__H__*/

View File

@@ -0,0 +1,35 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__FlowerFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__FlowerFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "../../../../util/Random.h"
#include "../../Level.h"
#include "../../tile/Bush.h"
#include "Feature.h"
class FlowerFeature: public Feature {
public:
int tile;
FlowerFeature(int tile) {
this->tile = tile;
}
bool place(Level* level, Random* random, int x, int y, int z) {
for (int i = 0; i < 64; i++) {
int x2 = x + random->nextInt(8) - random->nextInt(8);
int y2 = y + random->nextInt(4) - random->nextInt(4);
int z2 = z + random->nextInt(8) - random->nextInt(8);
if (level->isEmptyTile(x2, y2, z2)) {
if (((Bush*) Tile::tiles[tile])->canSurvive(level, x2, y2, z2)) {
level->setTileNoUpdate(x2, y2, z2, tile);
}
}
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__FlowerFeature_H__*/

View File

@@ -0,0 +1,127 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__LakeFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__LakeFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../Level.h"
#include "../../tile/Tile.h"
#include "../../material/Material.h"
#include "../../../../util/Mth.h"
#include "../../../../util/Random.h"
class LakeFeature: public Feature
{
int tile;
public:
LakeFeature(int tile_)
: tile(tile_)
{
}
bool place(Level* level, Random* random, int x, int y, int z) {
x -= 8;
z -= 8;
while (y > 0 && level->isEmptyTile(x, y, z))
y--;
y -= 4;
const int size = 16 * 16 * 8;
bool grid[size];
for (int i = 0; i < size; ++i)
grid[i] = false;
int spots = random->nextInt(4) + 4;
for (int i = 0; i < spots; i++) {
float xr = random->nextFloat() * 6 + 3;
float yr = random->nextFloat() * 4 + 2;
float zr = random->nextFloat() * 6 + 3;
float xp = random->nextFloat() * (16 - xr - 2) + 1 + xr / 2;
float yp = random->nextFloat() * (8 - yr - 4) + 2 + yr / 2;
float zp = random->nextFloat() * (16 - zr - 2) + 1 + zr / 2;
for (int xx = 1; xx < 15; xx++) {
for (int zz = 1; zz < 15; zz++) {
for (int yy = 1; yy < 7; yy++) {
float xd = ((xx - xp) / (xr / 2));
float yd = ((yy - yp) / (yr / 2));
float zd = ((zz - zp) / (zr / 2));
float d = xd * xd + yd * yd + zd * zd;
if (d < 1) grid[((xx) * 16 + (zz)) * 8 + (yy)] = true;
}
}
}
}
for (int xx = 0; xx < 16; xx++) {
for (int zz = 0; zz < 16; zz++) {
for (int yy = 0; yy < 8; yy++) {
bool check = !grid[((xx) * 16 + (zz)) * 8 + (yy)] && (false//
|| (xx < 15 && grid[((xx + 1) * 16 + (zz)) * 8 + (yy)])//
|| (xx > 0 && grid[((xx - 1) * 16 + (zz)) * 8 + (yy)])//
|| (zz < 15 && grid[((xx) * 16 + (zz + 1)) * 8 + (yy)])//
|| (zz > 0 && grid[((xx) * 16 + (zz - 1)) * 8 + (yy)])//
|| (yy < 7 && grid[((xx) * 16 + (zz)) * 8 + (yy + 1)])//
|| (yy > 0 && grid[((xx) * 16 + (zz)) * 8 + (yy - 1)]));
if (check) {
const Material* m = level->getMaterial(x + xx, y + yy, z + zz);
if (yy >= 4 && m->isLiquid()) return false;
if (yy < 4 && (!m->isSolid() && level->getTile(x + xx, y + yy, z + zz) != tile)) return false;
}
}
}
}
for (int xx = 0; xx < 16; xx++) {
for (int zz = 0; zz < 16; zz++) {
for (int yy = 0; yy < 8; yy++) {
if (grid[((xx) * 16 + (zz)) * 8 + (yy)]) {
level->setTileNoUpdate(x + xx, y + yy, z + zz, yy >= 4 ? 0 : tile);
}
}
}
}
for (int xx = 0; xx < 16; xx++) {
for (int zz = 0; zz < 16; zz++) {
for (int yy = 4; yy < 8; yy++) {
if (grid[((xx) * 16 + (zz)) * 8 + (yy)]) {
if (level->getTile(x + xx, y + yy - 1, z + zz) == Tile::dirt->id && level->getBrightness(LightLayer::Sky, x + xx, y + yy, z + zz) > 0) {
level->setTileNoUpdate(x + xx, y + yy - 1, z + zz, Tile::grass->id);
}
}
}
}
}
if (Tile::tiles[tile]->material == Material::lava) {
for (int xx = 0; xx < 16; xx++) {
for (int zz = 0; zz < 16; zz++) {
for (int yy = 0; yy < 8; yy++) {
bool check = !grid[((xx) * 16 + (zz)) * 8 + (yy)] && (false//
|| (xx < 15 && grid[((xx + 1) * 16 + (zz)) * 8 + (yy)])//
|| (xx > 0 && grid[((xx - 1) * 16 + (zz)) * 8 + (yy)])//
|| (zz < 15 && grid[((xx) * 16 + (zz + 1)) * 8 + (yy)])//
|| (zz > 0 && grid[((xx) * 16 + (zz - 1)) * 8 + (yy)])//
|| (yy < 7 && grid[((xx) * 16 + (zz)) * 8 + (yy + 1)])//
|| (yy > 0 && grid[((xx) * 16 + (zz)) * 8 + (yy - 1)]));
if (check) {
if ((yy<4 || random->nextInt(2)!=0) && level->getMaterial(x + xx, y + yy, z + zz)->isSolid()) {
level->setTileNoUpdate(x + xx, y + yy, z + zz, Tile::rock->id);
}
}
}
}
}
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__LakeFeature_H__*/

View File

@@ -0,0 +1,77 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__OreFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__OreFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../Level.h"
#include "../../tile/Tile.h"
#include "../../material/Material.h"
#include "../../../../util/Mth.h"
#include "../../../../util/Random.h"
class OreFeature: public Feature {
int tile;
int count;
public:
OreFeature(int tile, int count) {
this->tile = tile;
this->count = count;
}
bool place(Level* level, Random* random, int x, int y, int z) {
float dir = random->nextFloat() * Mth::PI;
float x0 = x + 8 + Mth::sin(dir) * count / 8;
float x1 = x + 8 - Mth::sin(dir) * count / 8;
float z0 = z + 8 + Mth::cos(dir) * count / 8;
float z1 = z + 8 - Mth::cos(dir) * count / 8;
float y0 = (float)(y + random->nextInt(3) + 2);
float y1 = (float)(y + random->nextInt(3) + 2);
for (int D = 0; D <= count; D++) {
float d = (float) D;
float xx = x0 + (x1 - x0) * d / count;
float yy = y0 + (y1 - y0) * d / count;
float zz = z0 + (z1 - z0) * d / count;
float ss = random->nextFloat() * count / 16;
float r = (Mth::sin(d * Mth::PI / count) + 1) * ss + 1;
float hr = (Mth::sin(d * Mth::PI / count) + 1) * ss + 1;
int xt0 = (int) (xx - r / 2);
int yt0 = (int) (yy - hr / 2);
int zt0 = (int) (zz - r / 2);
int xt1 = (int) (xx + r / 2);
int yt1 = (int) (yy + hr / 2);
int zt1 = (int) (zz + r / 2);
for (int x2 = xt0; x2 <= xt1; x2++) {
float xd = ((x2 + 0.5f) - xx) / (r / 2);
if (xd * xd < 1) {
for (int y2 = yt0; y2 <= yt1; y2++) {
float yd = ((y2 + 0.5f) - yy) / (hr / 2);
if (xd * xd + yd * yd < 1) {
for (int z2 = zt0; z2 <= zt1; z2++) {
float zd = ((z2 + 0.5f) - zz) / (r / 2);
if (xd * xd + yd * yd + zd * zd < 1) {
if (level->getTile(x2, y2, z2) == Tile::rock->id) level->setTileNoUpdate(x2, y2, z2, tile);
}
}
}
}
}
}
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__OreFeature_H__*/

View File

@@ -0,0 +1,92 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__PineFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__PineFeature_H__
//package net.minecraft.world.level->levelgen.feature;
#include "Feature.h"
#include "../../../../util/Random.h"
#include "../../Level.h"
#include "../../tile/LeafTile.h"
#include "../../tile/Tile.h"
#include "../../tile/TreeTile.h"
class PineFeature: public Feature
{
typedef Feature super;
public:
PineFeature(bool doUpdate = false)
: super(doUpdate)
{
}
bool place(Level* level, Random* random, int x, int y, int z) {
// pines can be quite tall
int treeHeight = random->nextInt(5) + 7;
int trunkHeight = treeHeight - random->nextInt(2) - 3;
int topHeight = treeHeight - trunkHeight;
int topRadius = 1 + random->nextInt(topHeight + 1);
bool free = true;
// may not be outside of y boundaries
if (y < 1 || y + treeHeight + 1 > Level::DEPTH) {
return false;
}
// make sure there is enough space
for (int yy = y; yy <= y + 1 + treeHeight && free; yy++) {
int r = 1;
if ((yy - y) < trunkHeight) {
r = 0;
} else {
r = topRadius;
}
for (int xx = x - r; xx <= x + r && free; xx++) {
for (int zz = z - r; zz <= z + r && free; zz++) {
if (yy >= 0 && yy < Level::DEPTH) {
int tt = level->getTile(xx, yy, zz);
if (tt != 0 && tt != Tile::leaves->id) free = false;
} else {
free = false;
}
}
}
}
if (!free) return false;
// must stand on ground
int belowTile = level->getTile(x, y - 1, z);
if ((belowTile != ((Tile*)Tile::grass)->id && belowTile != Tile::dirt->id) || y >= Level::DEPTH - treeHeight - 1) return false;
placeBlock(level, x, y - 1, z, Tile::dirt->id);
// place leaf top
int currentRadius = 0;
for (int yy = y + treeHeight; yy >= y + trunkHeight; yy--) {
for (int xx = x - currentRadius; xx <= x + currentRadius; xx++) {
int xo = xx - (x);
for (int zz = z - currentRadius; zz <= z + currentRadius; zz++) {
int zo = zz - (z);
if (std::abs(xo) == currentRadius && std::abs(zo) == currentRadius && currentRadius > 0) continue;
if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::leaves->id, LeafTile::EVERGREEN_LEAF);
}
}
if (currentRadius >= 1 && yy == (y + trunkHeight + 1)) {
currentRadius -= 1;
} else if (currentRadius < topRadius) {
currentRadius += 1;
}
}
for (int hh = 0; hh < treeHeight - 1; hh++) {
int t = level->getTile(x, y + hh, z);
if (t == 0 || t == Tile::leaves->id) placeBlock(level, x, y + hh, z, Tile::treeTrunk->id, TreeTile::DARK_TRUNK);
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__PineFeature_H__*/

View File

@@ -0,0 +1,40 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__ReedsFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__ReedsFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../Level.h"
#include "../../tile/Tile.h"
#include "../../material/Material.h"
#include "../../../../util/Random.h"
class ReedsFeature: public Feature
{
public:
bool place(Level* level, Random* random, int x, int y, int z) {
for (int i = 0; i < 20; i++) {
int x2 = x + random->nextInt(4) - random->nextInt(4);
int y2 = y;
int z2 = z + random->nextInt(4) - random->nextInt(4);
if (level->isEmptyTile(x2, y2, z2)) {
if (level->getMaterial(x2-1, y2-1, z2) == Material::water ||
level->getMaterial(x2+1, y2-1, z2) == Material::water ||
level->getMaterial(x2, y2-1, z2-1) == Material::water ||
level->getMaterial(x2, y2-1, z2+1) == Material::water) {
int h = 2 + random->nextInt(random->nextInt(3) + 1);
for (int yy = 0; yy < h; yy++) {
if (Tile::reeds->canSurvive(level, x2, y2 + yy, z2)) {
level->setTileNoUpdate(x2, y2 + yy, z2, Tile::reeds->id);
}
}
}
}
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__ReedsFeature_H__*/

View File

@@ -0,0 +1,50 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__SpringFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__SpringFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../Level.h"
#include "../../tile/Tile.h"
#include "../../material/Material.h"
#include "../../../../util/Random.h"
class SpringFeature: public Feature
{
int tile;
public:
SpringFeature(int tile) {
this->tile = tile;
}
bool place(Level* level, Random* random, int x, int y, int z) {
if (level->getTile(x, y + 1, z) != Tile::rock->id) return false;
if (level->getTile(x, y - 1, z) != Tile::rock->id) return false;
if (level->getTile(x, y, z) != 0 && level->getTile(x, y, z) != Tile::rock->id) return false;
int rockCount = 0;
if (level->getTile(x - 1, y, z) == Tile::rock->id) rockCount++;
if (level->getTile(x + 1, y, z) == Tile::rock->id) rockCount++;
if (level->getTile(x, y, z - 1) == Tile::rock->id) rockCount++;
if (level->getTile(x, y, z + 1) == Tile::rock->id) rockCount++;
int holeCount = 0;
if (level->isEmptyTile(x - 1, y, z)) holeCount++;
if (level->isEmptyTile(x + 1, y, z)) holeCount++;
if (level->isEmptyTile(x, y, z - 1)) holeCount++;
if (level->isEmptyTile(x, y, z + 1)) holeCount++;
if (rockCount == 3 && holeCount == 1) {
level->setTile(x, y, z, tile);
level->instaTick = true;
Tile::tiles[tile]->tick(level, x, y, z, random);
level->instaTick = false;
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__SpringFeature_H__*/

View File

@@ -0,0 +1,101 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__SpruceFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__SpruceFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../../../util/Random.h"
#include "../../Level.h"
#include "../../tile/LeafTile.h"
#include "../../tile/TreeTile.h"
class SpruceFeature: public Feature
{
typedef Feature super;
public:
SpruceFeature(bool doUpdate = false)
: super(doUpdate)
{
}
bool place(Level* level, Random* random, int x, int y, int z) {
// pines can be quite tall
int treeHeight = random->nextInt(4) + 6;
int trunkHeight = 1 + random->nextInt(2);
int topHeight = treeHeight - trunkHeight;
int leafRadius = 2 + random->nextInt(2);
bool free = true;
// may not be outside of y boundaries
if (y < 1 || y + treeHeight + 1 > Level::DEPTH) {
return false;
}
// make sure there is enough space
for (int yy = y; yy <= y + 1 + treeHeight && free; yy++) {
int r = 1;
if ((yy - y) < trunkHeight) {
r = 0;
} else {
r = leafRadius;
}
for (int xx = x - r; xx <= x + r && free; xx++) {
for (int zz = z - r; zz <= z + r && free; zz++) {
if (yy >= 0 && yy < Level::DEPTH) {
int tt = level->getTile(xx, yy, zz);
if (tt != 0 && tt != Tile::leaves->id) free = false;
} else {
free = false;
}
}
}
}
if (!free) return false;
// must stand on ground
int belowTile = level->getTile(x, y - 1, z);
if ((belowTile != ((Tile*)Tile::grass)->id && belowTile != Tile::dirt->id) || y >= Level::DEPTH - treeHeight - 1) return false;
placeBlock(level, x, y - 1, z, Tile::dirt->id);
// place leaf top
int currentRadius = random->nextInt(2);
int maxRadius = 1;
int minRadius = 0;
for (int heightPos = 0; heightPos <= topHeight; heightPos++) {
const int yy = y + treeHeight - heightPos;
for (int xx = x - currentRadius; xx <= x + currentRadius; xx++) {
int xo = xx - (x);
for (int zz = z - currentRadius; zz <= z + currentRadius; zz++) {
int zo = zz - (z);
if (std::abs(xo) == currentRadius && std::abs(zo) == currentRadius && currentRadius > 0) continue;
if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::leaves->id, LeafTile::EVERGREEN_LEAF);
}
}
if (currentRadius >= maxRadius) {
currentRadius = minRadius;
minRadius = 1;
maxRadius += 1;
if (maxRadius > leafRadius) {
maxRadius = leafRadius;
}
} else {
currentRadius = currentRadius + 1;
}
}
int topOffset = random->nextInt(3);
for (int hh = 0; hh < treeHeight - topOffset; hh++) {
int t = level->getTile(x, y + hh, z);
if (t == 0 || t == Tile::leaves->id) placeBlock(level, x, y + hh, z, Tile::treeTrunk->id, TreeTile::DARK_TRUNK);
}
return true;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__SpruceFeature_H__*/

View File

@@ -0,0 +1,40 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__TallgrassFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__TallgrassFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
class TallgrassFeature : public Feature
{
typedef Feature super;
public:
TallgrassFeature(int tile, int type)
: super(false), tile(tile), type(type)
{
}
bool place(Level* level, Random* random, int x, int y, int z) {
int t = 0;
while (((t = level->getTile(x, y, z)) == 0 || t == Tile::leaves->id) && y > 0)
y--;
for (int i = 0; i < 128; i++) {
int x2 = x + random->nextInt(8) - random->nextInt(8);
int y2 = y + random->nextInt(4) - random->nextInt(4);
int z2 = z + random->nextInt(8) - random->nextInt(8);
if (level->isEmptyTile(x2, y2, z2)) {
if (Tile::tiles[tile]->canSurvive(level, x2, y2, z2)) {
level->setTileAndDataNoUpdate(x2, y2, z2, tile, type);
}
}
}
return true;
}
private:
int tile;
int type;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__TallgrassFeature_H__*/

View File

@@ -0,0 +1,74 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__TreeFeature_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__TreeFeature_H__
//package net.minecraft.world.level.levelgen.feature;
#include "Feature.h"
#include "../../../../util/Random.h"
#include "../../Level.h"
#include "../../tile/TreeTile.h"
class TreeFeature: public Feature
{
typedef Feature super;
public:
TreeFeature(bool doUpdate, int trunkType = TreeTile::NORMAL_TRUNK)
: super(doUpdate),
trunkType(trunkType)
{
}
bool place(Level* level, Random* random, int x, int y, int z) {
int treeHeight = random->nextInt(3) + 4;
bool free = true;
if (y < 1 || y + treeHeight + 1 > Level::DEPTH) return false;
for (int yy = y; yy <= y + 1 + treeHeight; yy++) {
int r = 1;
if (yy == y) r = 0;
if (yy >= y + 1 + treeHeight - 2) r = 2;
for (int xx = x - r; xx <= x + r && free; xx++) {
for (int zz = z - r; zz <= z + r && free; zz++) {
if (yy >= 0 && yy < Level::DEPTH) {
int tt = level->getTile(xx, yy, zz);
if (tt != 0 && tt != ((Tile*)Tile::leaves)->id) free = false;
} else {
free = false;
}
}
}
}
if (!free) return false;
int belowTile = level->getTile(x, y - 1, z);
if ((belowTile != ((Tile*)Tile::grass)->id && belowTile != Tile::dirt->id) || y >= Level::DEPTH - treeHeight - 1) return false;
placeBlock(level, x, y - 1, z, Tile::dirt->id);
for (int yy = y - 3 + treeHeight; yy <= y + treeHeight; yy++) {
int yo = yy - (y + treeHeight);
int offs = 1 - yo / 2;
for (int xx = x - offs; xx <= x + offs; xx++) {
int xo = xx - (x);
for (int zz = z - offs; zz <= z + offs; zz++) {
int zo = zz - (z);
if (std::abs(xo) == offs && std::abs(zo) == offs && (random->nextInt(2) == 0 || yo == 0)) continue;
if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, ((Tile*)Tile::leaves)->id);
}
}
}
for (int hh = 0; hh < treeHeight; hh++) {
int t = level->getTile(x, y + hh, z);
if (t == 0 || t == ((Tile*)Tile::leaves)->id) placeBlock(level, x, y + hh, z, Tile::treeTrunk->id, trunkType);
}
return true;
}
private:
int trunkType;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_FEATURE__TreeFeature_H__*/

View File

@@ -0,0 +1,205 @@
#include "ImprovedNoise.h"
#include "../../../../util/Random.h"
ImprovedNoise::ImprovedNoise()
{
Random random(1);
init(&random);
}
ImprovedNoise::ImprovedNoise( Random* random )
{
init(random);
}
void ImprovedNoise::init( Random* random )
{
xo = random->nextFloat() * 256.f;
yo = random->nextFloat() * 256.f;
zo = random->nextFloat() * 256.f;
for (int i = 0; i < 256; i++) {
p[i] = i;
}
for (int i = 0; i < 256; i++) {
int j = random->nextInt(256 - i) + i;
int tmp = p[i];
p[i] = p[j];
p[j] = tmp;
p[i + 256] = p[i];
}
}
float ImprovedNoise::noise( float _x, float _y, float _z )
{
float x = _x + xo;
float y = _y + yo;
float z = _z + zo;
int xf = (int) x;
int yf = (int) y;
int zf = (int) z;
if (x < xf) xf--;
if (y < yf) yf--;
if (z < zf) zf--;
int X = xf & 255, // FIND UNIT CUBE THAT
Y = yf & 255, // CONTAINS POINT.
Z = zf & 255;
x -= xf; // FIND RELATIVE X,Y,Z
y -= yf; // OF POINT IN CUBE.
z -= zf;
float u = x * x * x * (x * (x * 6 - 15) + 10), // COMPUTE FADE CURVES
v = y * y * y * (y * (y * 6 - 15) + 10), // FOR EACH OF X,Y,Z.
w = z * z * z * (z * (z * 6 - 15) + 10);
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF
B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS,
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD
grad(p[BA], x - 1, y, z)), // BLENDED
lerp(u, grad(p[AB], x, y - 1, z), // RESULTS
grad(p[BB], x - 1, y - 1, z))),// FROM 8
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS
grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
}
const float ImprovedNoise::lerp( float t, float a, float b )
{
return a + t * (b - a);
}
const float ImprovedNoise::grad2( int hash, float x, float z )
{
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
float u = (1-((h&8)>>3))*x, // INTO 12 GRADIENT DIRECTIONS.
v = h < 4 ? 0 : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
const float ImprovedNoise::grad( int hash, float x, float y, float z )
{
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
float u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
float ImprovedNoise::getValue( float x, float y )
{
return noise(x, y, 0);
}
float ImprovedNoise::getValue( float x, float y, float z )
{
return noise(x, y, z);
}
void ImprovedNoise::add( float* buffer, float _x, float _y, float _z, int xSize, int ySize, int zSize, float xs, float ys, float zs, float pow )
{
if (ySize==1) {
int A = 0, AA = 0, B = 0, BA = 0;
float vv0 = 0, vv2 = 0;
int pp = 0;
float scale = 1.0f / pow;
for (int xx = 0; xx < xSize; xx++) {
float x = (_x + xx) * xs + xo;
int xf = (int) x;
if (x < xf) xf--;
int X = xf & 255;
x -= xf;
float u = x * x * x * (x * (x * 6 - 15) + 10);
for (int zz = 0; zz < zSize; zz++) {
float z = (_z + zz) * zs + zo;
int zf = (int) z;
if (z < zf) zf--;
int Z = zf & 255;
z -= zf;
float w = z * z * z * (z * (z * 6 - 15) + 10);
A = p[X] + 0;
AA = p[A] + Z;
B = p[X + 1] + 0;
BA = p[B] + Z;
vv0 = lerp(u, grad2(p[AA], x, z), grad(p[BA], x - 1, 0, z));
vv2 = lerp(u, grad(p[AA + 1], x, 0, z - 1), grad(p[BA + 1], x - 1, 0, z - 1));
float val = lerp(w, vv0, vv2);
buffer[pp++] += val * scale;
}
}
return;
}
int pp = 0;
float scale = 1 / pow;
int yOld = -1;
int A = 0, AA = 0, AB = 0, B = 0, BA = 0, BB = 0;
float vv0 = 0, vv1 = 0, vv2 = 0, vv3 = 0;
for (int xx = 0; xx < xSize; xx++) {
float x = (_x + xx) * xs + xo;
int xf = (int) x;
if (x < xf) xf--;
int X = xf & 255;
x -= xf;
float u = x * x * x * (x * (x * 6 - 15) + 10);
for (int zz = 0; zz < zSize; zz++) {
float z = (_z + zz) * zs + zo;
int zf = (int) z;
if (z < zf) zf--;
int Z = zf & 255;
z -= zf;
float w = z * z * z * (z * (z * 6 - 15) + 10);
for (int yy = 0; yy < ySize; yy++) {
float y = (_y + yy) * ys + yo;
int yf = (int) y;
if (y < yf) yf--;
int Y = yf & 255;
y -= yf;
float v = y * y * y * (y * (y * 6 - 15) + 10);
if (yy == 0 || Y != yOld) {
yOld = Y;
A = p[X] + Y;
AA = p[A] + Z;
AB = p[A + 1] + Z;
B = p[X + 1] + Y;
BA = p[B] + Z;
BB = p[B + 1] + Z;
vv0 = lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z));
vv1 = lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z));
vv2 = lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1));
vv3 = lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1));
}
float v0 = lerp(v, vv0, vv1);
float v1 = lerp(v, vv2, vv3);
float val = lerp(w, v0, v1);
buffer[pp++] += val * scale;
}
}
}
}
int ImprovedNoise::hashCode() {
int x = 4711;
for (int i = 0; i < 512; ++i)
x = x * 37 + p[i];
return x;
}

View File

@@ -0,0 +1,38 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__ImprovedNoise_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__ImprovedNoise_H__
//package net.minecraft.world.level.levelgen.synth;
#include "Synth.h"
class Random;
class ImprovedNoise: public Synth
{
public:
ImprovedNoise();
ImprovedNoise(Random* random);
void init(Random* random);
float noise(float _x, float _y, float _z);
const float lerp(float t, float a, float b);
const float grad2(int hash, float x, float z);
const float grad(int hash, float x, float y, float z);
float getValue(float x, float y);
float getValue(float x, float y, float z);
void add(float* buffer, float _x, float _y, float _z, int xSize, int ySize, int zSize, float xs, float ys, float zs, float pow);
int hashCode();
float scale;
float xo, yo, zo;
private:
int p[512];
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__ImprovedNoise_H__*/

View File

@@ -0,0 +1,88 @@
#include "PerlinNoise.h"
#include "ImprovedNoise.h"
void PerlinNoise::init( int levels )
{
this->levels = levels;
noiseLevels = new ImprovedNoise* [levels];
for (int i = 0; i < levels; i++) {
noiseLevels[i] = new ImprovedNoise(_rndPtr);
}
}
PerlinNoise::~PerlinNoise()
{
for (int i = 0; i < levels; ++i)
delete noiseLevels[i];
delete[] noiseLevels;
}
PerlinNoise::PerlinNoise( int levels )
{
_rndPtr = &_random;
init(levels);
}
PerlinNoise::PerlinNoise( Random* random, int levels )
{
_rndPtr = random;
init(levels);
}
float PerlinNoise::getValue( float x, float y )
{
float value = 0;
float pow = 1;
for (int i = 0; i < levels; i++) {
value += noiseLevels[i]->getValue(x * pow, y * pow) / pow;
pow /= 2;
}
return value;
}
float PerlinNoise::getValue( float x, float y, float z )
{
float value = 0;
float pow = 1;
for (int i = 0; i < levels; i++) {
value += noiseLevels[i]->getValue(x * pow, y * pow, z * pow) / pow;
pow /= 2;
}
return value;
}
float* PerlinNoise::getRegion( float* buffer, float x, float y, float z, int xSize, int ySize, int zSize, float xScale, float yScale, float zScale )
{
const int size = xSize * ySize * zSize;
if (buffer == 0) {
buffer = new float[size];
}
for (int i = 0; i < size; i++)
buffer[i] = 0;
float pow = 1;
for (int i = 0; i < levels; i++) {
noiseLevels[i]->add(buffer, x, y, z, xSize, ySize, zSize, xScale * pow, yScale * pow, zScale * pow, pow);
pow /= 2;
}
return buffer;
}
float* PerlinNoise::getRegion( float* sr, int x, int z, int xSize, int zSize, float xScale, float zScale, float pow )
{
return getRegion(sr, (float)x, 10.0f, (float)z, xSize, 1, zSize, xScale, 1, zScale);
}
int PerlinNoise::hashCode() {
int x = 4711;
for (int i = 0; i < levels; ++i)
x *= noiseLevels[i]->hashCode();
return x;
}

View File

@@ -0,0 +1,37 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__PerlinNoise_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__PerlinNoise_H__
//package net.minecraft.world.level.levelgen.synth;
#include "../../../../util/Random.h"
#include "Synth.h"
class ImprovedNoise;
class PerlinNoise: public Synth
{
public:
PerlinNoise(int levels);
PerlinNoise(Random* random, int levels);
~PerlinNoise();
float getValue(float x, float y);
float getValue(float x, float y, float z);
//float[] getRegion(float[] buffer, float x, float y, float z, int xSize, int ySize, int zSize, float xScale, float yScale, float zScale) {
float* getRegion(float* buffer, float x, float y, float z, int xSize, int ySize, int zSize, float xScale, float yScale, float zScale);
float* getRegion(float* sr, int x, int z, int xSize, int zSize, float xScale, float zScale, float pow);
int hashCode();
private:
ImprovedNoise** noiseLevels;
int levels;
Random _random;
Random* _rndPtr;
void init(int levels);
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__PerlinNoise_H__*/

View File

@@ -0,0 +1,21 @@
#include "Synth.h"
Synth::~Synth()
{
}
int Synth::getDataSize( int width, int height )
{
return width * height * sizeof(float);
}
void Synth::create( int width, int height, float* result )
{
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
result[x + y * width] = getValue((float)x, (float)y);
}
}
}

View File

@@ -0,0 +1,18 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__Synth_H__
#define NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__Synth_H__
//package net.minecraft.world.level.levelgen.synth;
class Synth
{
public:
virtual ~Synth();
int getDataSize(int width, int height);
virtual float getValue(float x, float y) = 0;
void create(int width, int height, float* result);
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_LEVELGEN_SYNTH__Synth_H__*/

View File

@@ -0,0 +1,23 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_MATERIAL__DecorationMaterial_H__
#define NET_MINECRAFT_WORLD_LEVEL_MATERIAL__DecorationMaterial_H__
//package net.minecraft.world.level.material;
#include "Material.h"
class DecorationMaterial: public Material
{
public:
bool isSolid() const {
return false;
}
bool blocksLight() const {
return false;
}
bool blocksMotion() const {
return false;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_MATERIAL__DecorationMaterial_H__*/

View File

@@ -0,0 +1,27 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_MATERIAL__GasMaterial_H__
#define NET_MINECRAFT_WORLD_LEVEL_MATERIAL__GasMaterial_H__
//package net.minecraft.world.level.material;
#include "Material.h"
class GasMaterial: public Material
{
public:
GasMaterial() {
replaceable();
}
bool isSolid() const {
return false;
}
bool blocksLight() const {
return false;
}
bool blocksMotion() const {
return false;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_MATERIAL__GasMaterial_H__*/

View File

@@ -0,0 +1,27 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_MATERIAL__LiquidMaterial_H__
#define NET_MINECRAFT_WORLD_LEVEL_MATERIAL__LiquidMaterial_H__
//package net.minecraft.world.level.material;
#include "Material.h"
class LiquidMaterial: public Material
{
public:
LiquidMaterial() {
replaceable();
}
bool isLiquid() const {
return true;
}
bool blocksMotion() const {
return false;
}
bool isSolid() const {
return false;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_MATERIAL__LiquidMaterial_H__*/

View File

@@ -0,0 +1,99 @@
#include "Material.h"
#include "GasMaterial.h"
#include "LiquidMaterial.h"
#include "DecorationMaterial.h"
#include "WebMaterial.h"
#include <cstdlib>
const Material* Material::air = NULL;
const Material* Material::dirt = NULL;
const Material* Material::wood = NULL;
const Material* Material::stone = NULL;
const Material* Material::metal = NULL;
const Material* Material::water = NULL;
const Material* Material::lava = NULL;
const Material* Material::leaves = NULL;
const Material* Material::plant = NULL;
const Material* Material::replaceable_plant = NULL;
const Material* Material::sponge = NULL;
const Material* Material::cloth = NULL;
const Material* Material::fire = NULL;
const Material* Material::sand = NULL;
const Material* Material::decoration= NULL;
const Material* Material::glass = NULL;
const Material* Material::explosive = NULL;
const Material* Material::coral = NULL;
const Material* Material::ice = NULL;
const Material* Material::topSnow = NULL;
const Material* Material::snow = NULL;
const Material* Material::cactus = NULL;
const Material* Material::clay = NULL;
const Material* Material::vegetable = NULL;
const Material* Material::portal = NULL;
const Material* Material::cake = NULL;
const Material* Material::web = NULL;
/*static*/
void Material::initMaterials()
{
air = new GasMaterial();
dirt = new Material();
wood = (new Material())->flammable();
stone = (new Material())->notAlwaysDestroyable();
metal = (new Material())->notAlwaysDestroyable();
water = new LiquidMaterial();
lava = new LiquidMaterial();
leaves = (new Material())->flammable()->neverBuildable();
plant = new DecorationMaterial();
replaceable_plant = (new DecorationMaterial())->replaceable()->flammable();
sponge = new Material();
cloth = (new Material())->flammable();
fire = new GasMaterial();
sand = new Material();
decoration= new DecorationMaterial();
glass = (new Material())->neverBuildable();
explosive = (new Material())->flammable()->neverBuildable();
coral = new Material();
ice = (new Material())->neverBuildable();
topSnow = (new DecorationMaterial())->neverBuildable()->notAlwaysDestroyable()->replaceable();
snow = (new Material())->notAlwaysDestroyable();
cactus = (new Material())->neverBuildable();
clay = new Material();
vegetable = new Material();
portal = new Material();
cake = new Material();
web = (new WebMaterial());
}
#define SAFEDEL(x) if (x) { delete x; x = NULL; }
/*static*/
void Material::teardownMaterials() {
SAFEDEL(air);
SAFEDEL(dirt);
SAFEDEL(wood);
SAFEDEL(stone);
SAFEDEL(metal);
SAFEDEL(water);
SAFEDEL(lava);
SAFEDEL(leaves);
SAFEDEL(plant);
SAFEDEL(replaceable_plant);
SAFEDEL(sponge);
SAFEDEL(cloth);
SAFEDEL(fire);
SAFEDEL(sand);
SAFEDEL(decoration);
SAFEDEL(glass);
SAFEDEL(explosive);
SAFEDEL(coral);
SAFEDEL(ice);
SAFEDEL(topSnow);
SAFEDEL(snow);
SAFEDEL(cactus);
SAFEDEL(clay);
SAFEDEL(vegetable);
SAFEDEL(portal);
SAFEDEL(cake);
SAFEDEL(web);
}

View File

@@ -0,0 +1,116 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_MATERIAL__Material_H__
#define NET_MINECRAFT_WORLD_LEVEL_MATERIAL__Material_H__
//package net.minecraft.world.level.material;
class Material
{
public:
static const Material* air;
static const Material* dirt;
static const Material* wood;
static const Material* stone;
static const Material* metal;
static const Material* water;
static const Material* lava;
static const Material* leaves;
static const Material* plant;
static const Material* replaceable_plant;
static const Material* sponge;
static const Material* cloth;
static const Material* fire;
static const Material* sand;
static const Material* decoration;
static const Material* glass;
static const Material* explosive;
static const Material* coral;
static const Material* ice;
static const Material* topSnow;
static const Material* snow;
static const Material* cactus;
static const Material* clay;
static const Material* vegetable;
static const Material* portal;
static const Material* cake;
static const Material* web;
static void initMaterials();
static void teardownMaterials();
virtual bool isLiquid() const {
return false;
}
virtual bool letsWaterThrough() const {
return (!isLiquid() && !isSolid());
}
virtual bool isSolid() const {
return true;
}
virtual bool blocksLight() const {
return true;
}
virtual bool isSolidBlocking() const {
if (_neverBuildable) return false;
return blocksMotion();
}
virtual bool isAlwaysDestroyable() const {
// these materials will always drop resources when destroyed,
// regardless of player's equipment
return _isAlwaysDestroyable;
}
virtual bool blocksMotion() const {
return true;
}
virtual bool isFlammable() const {
return _flammable;
}
virtual bool isReplaceable() const {
return _replaceable;
}
virtual ~Material () {}
protected:
Material()
: _flammable(false),
_neverBuildable(false),
_isAlwaysDestroyable(true),
_replaceable(false)
{}
Material* flammable() {
_flammable = true;
return this;
}
Material* neverBuildable() {
_neverBuildable = true;
return this;
}
Material* notAlwaysDestroyable() {
_isAlwaysDestroyable = false;
return this;
}
Material* replaceable() {
_replaceable = true;
return this;
}
private:
bool _flammable;
bool _neverBuildable;
bool _isAlwaysDestroyable;
bool _replaceable;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_MATERIAL__Material_H__*/

View File

@@ -0,0 +1,19 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_MATERIAL__WebMaterial_H__
#define NET_MINECRAFT_WORLD_LEVEL_MATERIAL__WebMaterial_H__
//package net.minecraft.world.level.material;
#include "Material.h"
class WebMaterial: public Material
{
public:
WebMaterial() {
notAlwaysDestroyable();
}
bool blocksMotion() const {
return false;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_MATERIAL__WebMaterial_H__*/

View File

@@ -0,0 +1,201 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__BinaryHeap_H__
#define NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__BinaryHeap_H__
//package net.minecraft.world.level->pathfinder;
#include "Node.h"
#include <vector>
class BinaryHeap
{
public:
BinaryHeap()
: _size(0),
_maxSize(1024)
{
_heap = new Node*[_maxSize];
//heap.reserve(1024);
}
~BinaryHeap() {
// @todo: figure out who's managing the memory
delete[] _heap;
}
Node* insert(Node* node)
{
if (node->heapIdx>=0) {
LOGE("BinaryHeap::insert. Node already added!\n");
}
if (_size == _maxSize)
{
Node** newHeap = new Node*[_maxSize = _size << 1];
for (int i = 0; i < _size; ++i)
newHeap[i] = _heap[i];
//System.arraycopy(heap, 0, newHeap, 0, size);
delete[] _heap;
_heap = newHeap;
}
// Insert at end and bubble up.
_heap[_size] = node;
//heap.push_back(node);
node->heapIdx = _size;
upHeap(_size++);
return node;
}
void clear() {
_size = 0;
}
Node* pop()
{
Node* popped = _heap[0];
_heap[0] = _heap[--_size];
_heap[_size] = NULL;
//heap.pop_back(); //?
if (_size > 0) downHeap(0);
popped->heapIdx=-1;
return popped;
}
void remove(Node* node)
{
// This is what node->heapIdx is for.
_heap[node->heapIdx] = _heap[--_size];
_heap[_size] = NULL;
//heap.pop_back(); //?
if (_size > node->heapIdx)
{
if (_heap[node->heapIdx]->f < node->f)
{
upHeap(node->heapIdx);
}
else
{
downHeap(node->heapIdx);
}
}
// Just as a precaution: should make stuff blow up if the node is abused.
node->heapIdx = -1;
}
void changeCost(Node* node, float newCost)
{
float oldCost = node->f;
node->f = newCost;
if (newCost < oldCost)
{
upHeap(node->heapIdx);
}
else
{
downHeap(node->heapIdx);
}
}
int size()
{
return _size;
}
bool isEmpty() {
return _size==0;
}
private:
void upHeap(int idx)
{
Node* node = _heap[idx];
float cost = node->f;
while (idx > 0)
{
int parentIdx = (idx - 1) >> 1;
Node* parent = _heap[parentIdx];
if (cost < parent->f)
{
//LOGI("idx1: %d\n", idx);
_heap[idx] = parent;
parent->heapIdx = idx;
idx = parentIdx;
}
else break;
}
//LOGI("idx2: %d\n", idx);
_heap[idx] = node;
node->heapIdx = idx;
}
void downHeap(int idx)
{
Node* node = _heap[idx];
float cost = node->f;
while (true)
{
int leftIdx = 1 + (idx << 1);
int rightIdx = leftIdx + 1;
if (leftIdx >= _size) break;
// We definitely have a left child.
Node* leftNode = _heap[leftIdx];
float leftCost = leftNode->f;
// We may have a right child.
Node* rightNode;
float rightCost;
if (rightIdx >= _size)
{
// Only need to compare with left.
rightNode = NULL;
rightCost = FLT_MAX;//.POSITIVE_INFINITY;
}
else
{
rightNode = _heap[rightIdx];
rightCost = rightNode->f;
}
// Find the smallest of the three costs: the corresponding node
// should be the parent.
if (leftCost < rightCost)
{
if (leftCost < cost)
{
_heap[idx] = leftNode;
leftNode->heapIdx = idx;
//LOGI("idx3: %d\n", idx);
idx = leftIdx;
}
else break;
}
else
{
if (rightCost < cost)
{
_heap[idx] = rightNode;
rightNode->heapIdx = idx;
//LOGI("idx4: %d\n", idx);
idx = rightIdx;
}
else break;
}
}
//LOGI("idx5: %d\n", idx);
_heap[idx] = node;
node->heapIdx = idx;
}
Node** _heap;
int _size;
int _maxSize;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__BinaryHeap_H__*/

View File

@@ -0,0 +1,79 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__Node_H__
#define NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__Node_H__
//package net.minecraft.world.level.pathfinder;
#include "../../../util/Mth.h"
#include <string>
class Node
{
public:
Node(int x = 0, int y = 0, int z = 0)
: x(x),
y(y),
z(z),
heapIdx(-1),
g(0), h(0), f(0),
cameFrom(NULL),
closed(false),
hash(createHash(x,y,z))
{
}
static int createHash(const int x, const int y, const int z) {
return (y & 0xff) | ((x & 0x7fff) << 8) | ((z & 0x7fff) << 24) | ((x < 0) ? 0x0080000000 : 0) | ((z < 0) ? 0x0000008000 : 0);
}
float distanceTo(Node* to) const {
float xd = (float)(to->x - x);
float yd = (float)(to->y - y);
float zd = (float)(to->z - z);
return Mth::sqrt(xd * xd + yd * yd + zd * zd);
}
bool operator==(const Node& rhs) const {
return hash == rhs.hash && x == rhs.x && y == rhs.y && z == rhs.z;
}
int hashCode() const {
return hash;
}
bool inOpenSet() const {
return heapIdx >= 0;
}
std::string toString() const {
return "Node::toString not implemented";//x + ", " + y + ", " + z;
}
public:
int heapIdx;
float g, h, f;
Node* cameFrom;
short x, y, z;
bool closed;
private:
int hash;
};
class TNode {
public:
TNode(Node* node)
: node(node)
{}
bool operator==(const TNode& rhs) const {
return node->operator==(*rhs.node);
}
bool operator<(const TNode& rhs) const {
if (node->z != rhs.node->z) return node->z < rhs.node->z;
if (node->x != rhs.node->x) return node->x < rhs.node->x;
return node->y < rhs.node->y;
}
Node* node;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__Node_H__*/

View File

@@ -0,0 +1,134 @@
#include "Path.h"
int Path::p = 0;
Path::Path()
: nodes(NULL),
length(0),
index(0),
id(++p)
{
}
Path::~Path()
{
destroy();
}
bool Path::isEmpty() const
{
return length == 0 || nodes == NULL;
}
void Path::copyNodes( Node** nodes, int length )
{
destroy();
this->length = length;
this->nodes = new Node*[length];
for (int i = 0; i < length; ++i)
this->nodes[i] = new Node(*nodes[i]);
}
void Path::destroy()
{
if (nodes) {
for (int i = 0; i < length; ++i)
delete nodes[i];
delete[] nodes;
nodes = NULL;
index = length = 0;
}
}
Node* Path::currentPos()
{
return nodes[index];
}
Vec3 Path::currentPos( Entity* e ) const
{
return getPos(e, index);
}
void Path::next()
{
index++;
}
void Path::setSize( int size )
{
length = size;
}
int Path::getSize() const
{
return length;
}
bool Path::isDone() const
{
return index >= length;
}
Node* Path::last() const
{
if (length > 0) {
return nodes[length - 1];
}
return NULL;
}
Node* Path::get( int i ) const
{
return nodes[i];
}
int Path::getIndex() const
{
return index;
}
void Path::setIndex( int index )
{
this->index = index;
}
Vec3 Path::getPos( Entity* e, int index ) const
{
float x = nodes[index]->x + (int) (e->bbWidth + 1) * 0.5f;
float z = nodes[index]->z + (int) (e->bbWidth + 1) * 0.5f;
float y = nodes[index]->y;
return Vec3(x, y, z);
}
bool Path::sameAs( const Path* path ) const
{
if (!path) return false;
if (path->length != length) return false;
for (int i = 0; i < length; ++i) {
Node& node = *path->nodes[i];
if (nodes[i]->x != node.x || nodes[i]->y != node.y || nodes[i]->z != node.z)
return false;
}
return true;
}
bool Path::endsIn( const Vec3& pos ) const
{
const Node* end = last();
if (end == NULL) return false;
return end->x == Mth::floor(pos.x)
&& end->y == Mth::floor(pos.y)
&& end->z == Mth::floor(pos.z);
}
bool Path::endsInXZ( const Vec3& pos ) const
{
const Node* end = last();
if (end == NULL) return false;
return end->x == Mth::floor(pos.x)
&& end->z == Mth::floor(pos.z);
}

View File

@@ -0,0 +1,53 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__Path_H__
#define NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__Path_H__
//package net.minecraft.world.level.pathfinder;
#include "Node.h"
#include "../../phys/Vec3.h"
#include "../../entity/Entity.h"
class Path
{
public:
Path();
~Path();
void copyNodes(Node** nodes, int length);
void destroy();
void next();
void setSize(int size);
int getSize() const;
bool isEmpty() const;
bool isDone() const;
Node* last() const;
Node* get(int i) const;
int getIndex() const;
void setIndex(int index);
Vec3 currentPos(Entity* e) const;
Node* currentPos();
Vec3 getPos(Entity* e, int index) const;
bool sameAs(const Path* path) const;
bool endsIn(const Vec3& pos) const;
bool endsInXZ(const Vec3& pos) const;
int id;
private:
Node** nodes;
int length;
int index;
static int p;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__Path_H__*/

View File

@@ -0,0 +1,394 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__PathFinder_H__
#define NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__PathFinder_H__
//package net.minecraft.world.level.pathfinder;
#include "../LevelSource.h"
#include "../material/Material.h"
#include "../tile/DoorTile.h"
#include "../../entity/Entity.h"
#include "../../../util/Mth.h"
#include <map>
#include "BinaryHeap.h"
#include "Node.h"
#include "Path.h"
static int __created;
static int __maxCreated = 0;
static const int MAX_NODES = 2048;
class FreeCache {
public:
FreeCache()
: cache(w * w * h)
{}
void setCenterPos(int x, int y, int z) {
bx = x - w/2;
by = y - h/2;
bz = z - w/2;
}
int getValue(int x, int y, int z) {
return cache.get(_index(x, y, z));
}
void setValue(int x, int y, int z, int value) {
cache.set(_index(x, y, z), value);
}
void clear() {
cache.setAll(0);
}
__inline int _index(int x, int y, int z) {
return (x-bz) | ((z-bz) << ShiftZ) | ((y-by) << ShiftY);
}
private:
int bx, by, bz;
DataLayer cache;
static const int w = 64, h = 32;
static const int ShiftY = 10, ShiftZ = 5;
};
class PathFinder
{
typedef std::map<int, TNode> NodeMap;
public:
PathFinder()
: level(NULL),
canOpenDoors(false),
avoidWater(false)
{
}
PathFinder(LevelSource* level)
: canOpenDoors(false),
avoidWater(false)
{
setLevelSource(level);
}
void setLevelSource(LevelSource* level) {
this->level = level;
}
bool findPath(Path* path, Entity* from, Entity* to, float maxDist) {
return findPath(*path, from, to->x, to->bb.y0, to->z, maxDist);
}
bool findPath(Path* path, Entity* from, int x, int y, int z, float maxDist) {
return findPath(*path, from, x + 0.5f, y + 0.5f, z + 0.5f, maxDist);
}
private:
bool findPath(Path& path, Entity* e, float xt, float yt, float zt, float maxDist) {
//openSet.clear();
//LOGI("<--------------------->\n");
static Stopwatch w;
w.start();
// @attn @fix: this is danger!
nodes.clear();
_nodeIndex = 0;
// Calculate the From node
bool resetAvoidWater = avoidWater;
int startY;
if (e->isInWater()) {
startY = (int) (e->bb.y0);
int tileId = level->getTile(Mth::floor(e->x), startY, Mth::floor(e->z));
while (tileId == Tile::water->id || tileId == Tile::calmWater->id) {
++startY;
tileId = level->getTile(Mth::floor(e->x), startY, Mth::floor(e->z));
}
resetAvoidWater = avoidWater;
avoidWater = false;
} else startY = Mth::floor(e->bb.y0 + 0.5f);
Node* from = getNode(Mth::floor(e->bb.x0), startY, Mth::floor(e->bb.z0));
// Try finding a To node that doesn't have air below
const int xx0 = Mth::floor(xt - e->bbWidth / 2);
const int yy0 = Mth::floor(yt);
const int zz0 = Mth::floor(zt - e->bbWidth / 2);
Node* to = NULL;
if (level->getTile(xx0, yy0-1, zz0)) {
to = getNode(xx0, yy0, zz0);
} else {
const int xx1 = Mth::floor(xt + e->bbWidth /2);
const int zz1 = Mth::floor(zt + e->bbWidth /2);
for (int xx = xx0; xx <= xx1; ++xx)
for (int zz = zz0; zz <= zz1; ++zz) {
if (level->getTile(xx, yy0-1, zz) != 0) {
to = getNode(xx, yy0, zz);
break;
}
}
if (!to) { // Find the first non-air tile below
int yy = yy0;
while(!level->getTile(xx0, yy-1, zz0) && yy > 0)
--yy;
to = getNode(xx0, yy, zz0);
}
}
Node size(Mth::floor((e->bbWidth + 1)), Mth::floor((e->bbHeight + 1)), Mth::floor((e->bbWidth + 1)));
bool out = findPath(path, e, from, to, &size, maxDist);
w.stop();
//w.printEvery(1, "Pathfinder");
// Clear excessive Nodes that was created this round
if (_nodeIndex >= MAX_NODES) {
for (unsigned int i = 0; i < _pending.size(); ++i)
delete _pending[i];
_pending.clear();
}
return out;
}
// function A*(start,goal)
bool findPath(Path& path, Entity* e, Node* from, Node* to, const Node* size, float maxDist) {
//static int _x = 0;
__created = 0;
from->g = 0;
from->h = from->distanceTo(to);
from->f = from->h;
openSet.clear();
openSet.insert(from);
Node* closest = from;
while (!openSet.isEmpty()) {
//LOGI("size1: %d\n", openSet.size());
Node* x = openSet.pop();
//LOGI("size2: %d\n", openSet.size());
//if (x->x == to->x && x->y == to->y && x->z == to->z) {
if (*x == *to) {
//LOGI(">>> %p, %p : %d, %d\n", x, to, x->hashCode(), to->hashCode());
if (__created > __maxCreated) {
__maxCreated = __created;
for (int i = 0; i < 1; ++i) LOGI("\tNEW MAX: Created %d nodes\n", __created);
}
reconstruct_path(path, from, to); //@fix?
return true;
}
if (x->distanceTo(to) < closest->distanceTo(to)) {
//LOGI("closer!\n");
closest = x;
}
x->closed = true;
int neighborCount = getNeighbors(e, x, size, to, maxDist);
for (int i = 0; i < neighborCount; i++) {
Node* y = neighbors[i];
if (y->closed) continue;
float tentative_g_score = x->g + x->distanceTo(y);
if (!y->inOpenSet() || tentative_g_score < y->g) {
//if (!openSet.has(y) || tentative_g_score < y->g) {
y->cameFrom = x;
y->g = tentative_g_score;
y->h = y->distanceTo(to);
if (y->inOpenSet()) {
//if (openSet.has(y)) {
openSet.changeCost(y, y->g + y->h);
//delete y;
} else {
y->f = y->g + y->h;
openSet.insert(y);
}
} //else delete y;
//bool isBetter = false;
//float tentative_g_score = x->g + x->distanceTo(y);
//if (!y->inOpenSet()) {
// openSet.insert(y);
// y->h = y->distanceTo(to);
// isBetter = true;
//} else if (tentative_g_score < y->g) {
// isBetter = true;
//}
//if (isBetter) {
// //y->f = y->g + y->h;
// y->cameFrom = x;
// y->g = tentative_g_score;
// openSet.changeCost(y, y->g + y->h);
//}
}
}
if (__created > __maxCreated) {
__maxCreated = __created;
for (int i = 0; i < 1; ++i) LOGI("\tNEW MAX: Created %d nodes\n", __created);
}
if (closest == from)
return false;
reconstruct_path(path, from, closest); //@fix?
return true;
}
int getNeighbors(Entity* entity, Node* pos, const Node* size, Node* target, float maxDist) {
int p = 0;
//LOGI("Getting neighbours for: (%d, %d, %d)\n", pos->x, pos->y, pos->z);
int jumpSize = 0;
if (isFree(entity, pos->x, pos->y + 1, pos->z, size) == TYPE_OPEN) jumpSize = 1;
Node* n = getNode(entity, pos->x, pos->y, pos->z + 1, size, jumpSize);
Node* w = getNode(entity, pos->x - 1, pos->y, pos->z, size, jumpSize);
Node* e = getNode(entity, pos->x + 1, pos->y, pos->z, size, jumpSize);
Node* s = getNode(entity, pos->x, pos->y, pos->z - 1, size, jumpSize);
if (n != NULL && !n->closed && n->distanceTo(target) < maxDist) neighbors[p++] = n;
if (w != NULL && !w->closed && w->distanceTo(target) < maxDist) neighbors[p++] = w;
if (e != NULL && !e->closed && e->distanceTo(target) < maxDist) neighbors[p++] = e;
if (s != NULL && !s->closed && s->distanceTo(target) < maxDist) neighbors[p++] = s;
return p;
}
Node* getNode(Entity* entity, int x, int y, int z, const Node* size, int jumpSize) {
Node* best = NULL;
int pathType = isFree(entity, x, y, z, size);
if (pathType == TYPE_WALKABLE) return getNode(x, y, z);
if (pathType == TYPE_OPEN) best = getNode(x, y, z);
if (best == NULL && jumpSize > 0 && pathType != TYPE_FENCE && isFree(entity, x, y + jumpSize, z, size) == TYPE_OPEN) {
best = getNode(x, y + jumpSize, z);
y += jumpSize;
}
if (best != NULL) {
int drop = 0;
int cost = 0;
while (y > 0) {
cost = isFree(entity, x, y - 1, z, size);
if (avoidWater && cost == TYPE_WATER) return NULL;
if (cost != TYPE_OPEN) break;
// fell too far?
if (++drop >= 4) return NULL;
if (--y > 0) best = getNode(x, y, z);
}
// fell into lava?
if (cost == TYPE_LAVA) return NULL;
}
return best;
}
Node* getNode(int x, int y, int z) {
int i = Node::createHash(x, y, z);
NodeMap::iterator it = nodes.find(i);
if (it == nodes.end()){
Node* node = new_Node(x, y, z);
++__created;
nodes.insert(std::make_pair(i, TNode(node)));
return node;
}
return it->second.node;
}
static const int TYPE_FENCE = 1;
static const int TYPE_LAVA = 2;
static const int TYPE_WATER = 3;
static const int TYPE_BLOCKED = 4;
static const int TYPE_OPEN = 5;
static const int TYPE_WALKABLE = 6;
int isFree(Entity* entity, int x, int y, int z, const Node* size) {
bool walkable = false;
//LOGI("isfree: [%d, %d, %d]\n", x, y, z);
for (int xx = x; xx < x + size->x; xx++) {
for (int yy = y; yy < y + size->y; yy++) {
for (int zz = z; zz < z + size->z; zz++) {
int tileId = level->getTile(xx, yy, zz);
if (tileId <= 0) continue;
if (tileId == Tile::door_iron->id || tileId == Tile::door_wood->id) {
//LOGI("canOpenDoors? %d : %d\n", canOpenDoors, DoorTile::isOpen(level->getData(xx, yy, zz)));
if (tileId == Tile::door_wood->id && canOpenDoors)
continue;
int data = level->getData(xx, yy, zz);
if (!DoorTile::isOpen(entity->level, xx, yy, zz)) {
return TYPE_BLOCKED;
}
else
continue;
}
else if (tileId == Tile::water->id || tileId == Tile::calmWater->id) {
if (avoidWater) {
return TYPE_WATER;
}
walkable = true;
}
else if (tileId == Tile::fence->id || tileId == Tile::fenceGate->id) {
return TYPE_FENCE;
}
const Material* m = Tile::tiles[tileId]->material;
if (m->blocksMotion()) {
return TYPE_BLOCKED;
} else walkable = true;
if (m == Material::lava) {
return TYPE_LAVA;
}
}
}
}
return TYPE_OPEN;
}
// function reconstruct_path(came_from,current_node)
void reconstruct_path(Path& path, Node* from, Node* to) {
int count = 1;
Node* n = to;
while (n->cameFrom != NULL) {
count++;
n = n->cameFrom;
}
int size = count;
Node** nodes = new Node*[size]; //@todo: have one long static array for this
n = to;
nodes[--count] = n;
while (n->cameFrom != NULL) {
n = n->cameFrom;
nodes[--count] = n;
}
//LOGI("Setting %p nodes to path %p\n", nodes, &path);
path.copyNodes(nodes, size);
delete[] nodes;
}
Node* new_Node(int x, int y, int z) {
//return new Node(x, y, z);
if (++_nodeIndex >= MAX_NODES) {
Node* out = new Node(x, y, z);
_pending.push_back( out );
return out;
}
Node& n = _nodes[_nodeIndex-1];
n = Node(x, y, z);
return &n;
}
LevelSource* level;
BinaryHeap openSet;
NodeMap nodes;
Node _nodes[MAX_NODES];
std::vector<Node*> _pending;
int _nodeIndex;
Node* neighbors[32];
public:
bool canOpenDoors;
bool avoidWater;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_PATHFINDER__PathFinder_H__*/

View File

@@ -0,0 +1,632 @@
#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION)
#include "LevelData.h"
#include "RegionFile.h"
#include "ExternalFileLevelStorage.h"
#include "FolderMethods.h"
#include "../chunk/LevelChunk.h"
#include "../Level.h"
#include "../LevelConstants.h"
#include "../tile/TreeTile.h"
#include "../../entity/EntityFactory.h"
#include "../../../nbt/NbtIo.h"
#include "../../../util/RakDataIO.h"
#include "../../../raknet/GetTime.h"
#include "../tile/entity/TileEntity.h"
static const int ChunkVersion_Light = 1;
static const int ChunkVersion_Entity = 2;
const char* const fnLevelDatOld = "level.dat_old";
const char* const fnLevelDatNew = "level.dat_new";
const char* const fnLevelDat = "level.dat";
const char* const fnPlayerDat = "player.dat";
//
// Helpers for converting old levels to newer
//
class LevelConverters
{
public:
// Replacing old Cloth (id based) with new Cloth (data based)
static bool v1_ClothIdToClothData(LevelChunk* c) {
bool changed = false;
unsigned char* blocks = c->getBlockData();
unsigned char newTile = Tile::cloth->id;
for (int i = 0; i < 16*16*128; ++i) {
unsigned char oldTile = blocks[i];
//Tile::cloth_00 to Tile::cloth_61
if (oldTile >= 101 && oldTile <= 115) {
int color = 0xf - (oldTile - 101);
blocks[i] = newTile;
c->data.set(i, color);
changed = true;
}
}
return changed;
}
// Replacing unavailable blocks with "Update!" blocks
static bool ReplaceUnavailableBlocks(LevelChunk* c) {
//int st = getTimeMs();
bool changed = false;
unsigned char* blocks = c->getBlockData();
for (int i = 0; i < 16*16*128; ++i) {
unsigned char oldTile = blocks[i];
unsigned char newTile = Tile::transformToValidBlockId(oldTile);
if (oldTile != newTile) {
blocks[i] = newTile;
changed = true;
}
}
//int et = getTimeMs();
//LOGI("time: %d\n", et - st);
return changed;
}
//static bool ConvertPlayerDatToLevelDat() {
// return false;
//}
};
ExternalFileLevelStorage::ExternalFileLevelStorage(const std::string& levelId, const std::string& fullPath)
: levelId(levelId),
levelPath(fullPath),
loadedLevelData(NULL),
regionFile(NULL),
entitiesFile(NULL),
tickCount(0),
lastSavedEntitiesTick(-999999),
level(NULL),
loadedStorageVersion(SharedConstants::StorageVersion)
{
createFolderIfNotExists(levelPath.c_str());
std::string datFileName = levelPath + "/" + fnLevelDat;
std::string levelFileName = levelPath + "/" + fnPlayerDat;
loadedLevelData = new LevelData();
if (readLevelData(levelPath, *loadedLevelData))
{
loadedStorageVersion = loadedLevelData->getStorageVersion();
readPlayerData(levelFileName, *loadedLevelData);
} else {
delete loadedLevelData;
loadedLevelData = NULL;
}
}
ExternalFileLevelStorage::~ExternalFileLevelStorage()
{
delete regionFile;
delete loadedLevelData;
}
void ExternalFileLevelStorage::saveLevelData(LevelData& levelData, std::vector<Player*>* players) {
ExternalFileLevelStorage::saveLevelData(levelPath, levelData, players);
}
void ExternalFileLevelStorage::saveLevelData( const std::string& levelPath, LevelData& levelData, std::vector<Player*>* players )
{
std::string directory = levelPath + "/";
std::string tmpFile = directory + fnLevelDatNew;
std::string datFile = directory + fnLevelDat;
std::string oldFile = directory + fnLevelDatOld;
levelData.setStorageVersion(SharedConstants::StorageVersion);
if (!writeLevelData(tmpFile, levelData, players))
return;
// Remove old backup
remove(oldFile.c_str());
// If it exists, move the previous save to backup (and possibly delete it)
if (exists(datFile.c_str())) {
if (rename(datFile.c_str(), oldFile.c_str())) {
LOGE("Error@saveLevelData: Couldn't move savefile to level.dat_old\n");
return;
}
remove(datFile.c_str());
}
// Move the new save to level.dat
if (rename(tmpFile.c_str(), datFile.c_str())) {
LOGE("Error@saveLevelData: Couldn't move new file to level.dat\n");
return;
}
// Remove the temporary save, if the rename didn't do it
remove(tmpFile.c_str());
}
LevelData* ExternalFileLevelStorage::prepareLevel(Level* _level)
{
level = _level;
return loadedLevelData;
}
bool ExternalFileLevelStorage::readLevelData(const std::string& directory, LevelData& levelData)
{
// Try to load level.dat
std::string datFilename = directory + "/" + fnLevelDat;
FILE* file = fopen(datFilename.c_str(), "rb");
// If that fails, try to load level.dat_old
if (!file) {
datFilename = directory + "/" + fnLevelDatOld;
file = fopen(datFilename.c_str(), "rb");
}
if (!file)
return false;
int version = 0;
int size = 0;
unsigned char* data = NULL;
do {
if (fread(&version, sizeof(version), 1, file) != 1)
{
break;
}
if (fread(&size, sizeof(size), 1, file) != 1)
{
break;
}
int left = getRemainingFileSize(file);
if (size > left || size <= 0)
break;
data = new unsigned char[size];
if (fread(data, 1, size, file) != size)
{
break;
}
if (version == 1) {
RakNet::BitStream bitStream(data, size, false);
levelData.v1_read(bitStream, version);
} else if (version >= 2) {
//LOGI("---> Trying to load level with version %d\n", version);
RakNet::BitStream bitStream(data, size, false);
RakDataInput stream(bitStream);
//LOGI("dat: %s\n", datFileName.c_str());
CompoundTag* tag = NbtIo::read(&stream);
if (tag) {
levelData.getTagData(tag);
tag->deleteChildren();
delete tag;
}
//LOGI("<--- Finished reading level tag: %p\n", tag);
}
} while (false);
fclose(file);
delete [] data;
return true;
}
bool ExternalFileLevelStorage::writeLevelData(const std::string& datFileName, LevelData& levelData, const std::vector<Player*>* players)
{
LOGI("Writing down level seed as: %ld\n", levelData.getSeed());
//return true;
// Write level info
FILE* file = fopen(datFileName.c_str(), "wb");
if (!file)
return false;
//if (levelData.getStorageVersion() == 1) {
RakNet::BitStream data;
if (levelData.getStorageVersion() == 1)
levelData.v1_write(data);
else {
RakDataOutput buf(data);
//LOGI("---> Trying to write level with version %d\n", version);
CompoundTag* tag = NULL;
if (players && !players->empty())
tag = levelData.createTag(*players);
else
tag = levelData.createTag();
NbtIo::write(tag, &buf);
tag->deleteChildren();
delete tag;
//LOGI("<--- Finished writing level data. Size: %d\n", fdout.bytesWritten);
}
int version = levelData.getStorageVersion(); // 1
fwrite(&version, sizeof(version), 1, file);
int size = data.GetNumberOfBytesUsed();
fwrite(&size, sizeof(size), 1, file);
fwrite(data.GetData(), 1, size, file);
fclose(file);
return true;
}
bool ExternalFileLevelStorage::readPlayerData(const std::string& filename, LevelData& dest)
{
FILE* fp = fopen(filename.c_str(), "rb");
if (!fp)
return false;
do {
int version;
if (fread(&version, 4, 1, fp) != 1)
break;
int size;
if (fread(&size, 4, 1, fp) != 1)
break;
if (version == 1) {
if (fread(&dest.playerData, 1, sizeof(dest.playerData), fp) != size)
break;
// Fix coordinates
Vec3& pos = dest.playerData.pos;
if (pos.x < 0.5f) pos.x = 0.5f;
if (pos.z < 0.5f) pos.z = 0.5f;
if (pos.x > (LEVEL_WIDTH - 0.5f)) pos.x = LEVEL_WIDTH - 0.5f;
if (pos.z > (LEVEL_DEPTH - 0.5f)) pos.z = LEVEL_DEPTH - 0.5f;
if (pos.y < 0) pos.y = 64;
dest.playerDataVersion = version;
}
} while (false);
fclose(fp);
return true;
}
void ExternalFileLevelStorage::tick()
{
tickCount++;
if ((tickCount % 50) == 0 && level)
{
// look for chunks that needs to be saved
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 (chunk && chunk->unsaved)
{
int pos = x + z * CHUNK_CACHE_WIDTH;
UnsavedChunkList::iterator prev = unsavedChunkList.begin();
for ( ; prev != unsavedChunkList.end(); ++prev)
{
if ((*prev).pos == pos)
{
// the chunk has been modified again, so update its time
(*prev).addedToList = RakNet::GetTimeMS();
break;
}
}
if (prev == unsavedChunkList.end())
{
UnsavedLevelChunk unsaved;
unsaved.pos = pos;
unsaved.addedToList = RakNet::GetTimeMS();
unsaved.chunk = chunk;
unsavedChunkList.push_back(unsaved);
}
chunk->unsaved = false; // not actually saved, but in our working list at least
}
}
}
savePendingUnsavedChunks(2);
}
if (tickCount - lastSavedEntitiesTick > (60 * SharedConstants::TicksPerSecond)) {
saveEntities(level, NULL);
}
}
void ExternalFileLevelStorage::save(Level* level, LevelChunk* levelChunk)
{
if (!regionFile)
{
regionFile = new RegionFile(levelPath);
if (!regionFile->open())
{
delete regionFile;
regionFile = NULL;
return;
}
}
// Write chunk
RakNet::BitStream chunkData;
chunkData.Write((const char*)levelChunk->getBlockData(), CHUNK_BLOCK_COUNT);
chunkData.Write((const char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2);
chunkData.Write((const char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2);
chunkData.Write((const char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2);
chunkData.Write((const char*)levelChunk->updateMap, CHUNK_COLUMNS);
regionFile->writeChunk(levelChunk->x, levelChunk->z, chunkData);
// Write entities
//LOGI("Saved chunk (%d, %d)\n", levelChunk->x, levelChunk->z);
}
LevelChunk* ExternalFileLevelStorage::load(Level* level, int x, int z)
{
if (!regionFile)
{
regionFile = new RegionFile(levelPath);
if (!regionFile->open())
{
delete regionFile;
regionFile = NULL;
return NULL;
}
}
RakNet::BitStream* chunkData = NULL;
if (!regionFile->readChunk(x, z, &chunkData))
{
//LOGI("Failed to read data for %d, %d\n", x, z);
return NULL;
}
chunkData->ResetReadPointer();
unsigned char* blockIds = new unsigned char[CHUNK_BLOCK_COUNT];
chunkData->Read((char*)blockIds, CHUNK_BLOCK_COUNT);
LevelChunk* levelChunk = new LevelChunk(level, blockIds, x, z);
chunkData->Read((char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2);
if (loadedStorageVersion >= ChunkVersion_Light) {
chunkData->Read((char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2);
chunkData->Read((char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2);
}
chunkData->Read((char*)levelChunk->updateMap, CHUNK_COLUMNS);
// This will be difficult to maintain.. Storage version could be per chunk
// too (but probably better to just read all -> write all, so that all
// chunks got same version anyway)
//if (loadedStorageVersion >= ChunkVersion_Entity) {
// int dictSize;
// chunkData->Read(dictSize);
// RakDataInput dis(*chunkData);
// Tag* tmp = Tag::readNamedTag(&dis);
// if (tmp && tmp->getId() == Tag::TAG_Compound) {
// CompoundTag* tag = (CompoundTag*) tmp;
// delete tmp;
// }
//}
delete [] chunkData->GetData();
delete chunkData;
//bool dbg = (x == 7 && z == 9);
//int t = 0;
//for (int i = 0; i < CHUNK_COLUMNS; ++i) {
// char bits = levelChunk->updateMap[i];
// t += (bits != 0);
// int xx = x * 16 + i%16;
// int zz = z * 16 + i/16;
// if (dbg && xx == 125 && zz == 152) {
// LOGI("xz: %d, %d: %d\n", xx, zz, bits);
// for (int j = 0; j < 8; ++j) {
// if (bits & (1 << j)) {
// LOGI("%d - %d\n", j << 4, ((j+1) << 4) - 1);
// }
// }
// }
//}
//
// Convert LevelChunks here if necessary
//
//LOGI("level version: %d: upd: %d - (%d, %d)\n", loadedStorageVersion, t, x, z);
bool changed = false;
// Loaded level has old Cloth types (one Tile* per color)
if (loadedStorageVersion == 1)
changed |= LevelConverters::v1_ClothIdToClothData(levelChunk);
// Loaded level is newer than our level - replace all unavailable block types
//if (loadedStorageVersion > SharedConstants::StorageVersion)
changed |= LevelConverters::ReplaceUnavailableBlocks(levelChunk);
levelChunk->recalcHeightmap();
levelChunk->unsaved = changed;
levelChunk->terrainPopulated = true;
levelChunk->createdFromSave = true;
return levelChunk;
}
void ExternalFileLevelStorage::saveEntities( Level* level, LevelChunk* levelChunk )
{
lastSavedEntitiesTick = tickCount;
int count = 0;
float st = getTimeS();
// Version 1: Save ALL Entities for all chunks in one structure
EntityList& entities = level->entities;
ListTag* entityTags = new ListTag();
for (unsigned int i = 0; i < entities.size(); ++i) {
Entity* e = entities[i];
CompoundTag* tag = new CompoundTag();
if (e->save(tag)) {
count++;
entityTags->add(tag);
} else
delete tag;
}
// Version 1: Save ALL TileEntities for all chunks in one structure
TileEntityList& tileEntities = level->tileEntities;
//TileEntityList keep, dontKeep;
//partitionTileEntities
ListTag* tileEntityTags = new ListTag();
for (unsigned int i = 0; i < tileEntities.size(); ++i) {
TileEntity* e = tileEntities[i];
if (!e->shouldSave()) continue;
CompoundTag* tag = new CompoundTag();
if (e->save(tag)) {
count++;
tileEntityTags->add(tag);
} else
delete tag;
}
CompoundTag base;
base.put("Entities", entityTags);
base.put("TileEntities", tileEntityTags);
RakNet::BitStream stream;
RakDataOutput dos(stream);
NbtIo::write(&base, &dos);
int numBytes = stream.GetNumberOfBytesUsed();
FILE* fp = fopen((levelPath + "/entities.dat").c_str(), "wb");
if (fp) {
int version = 1;
fwrite("ENT\0", 1, 4, fp);
fwrite(&version, sizeof(int), 1, fp);
fwrite(&numBytes, sizeof(int), 1, fp);
fwrite(stream.GetData(), 1, numBytes, fp);
fclose(fp);
}
base.deleteChildren();
float tt = getTimeS() - st;
LOGI("Time to save %d entities: %f s. Size: %d bytes\n", count, tt, numBytes);
}
void ExternalFileLevelStorage::loadEntities(Level* level, LevelChunk* chunk) {
lastSavedEntitiesTick = tickCount;
FILE* fp = fopen((levelPath + "/entities.dat").c_str(), "rb");
if (fp) {
char header[5];
int version, numBytes;
fread(header, 1, 4, fp);
fread(&version, sizeof(int), 1, fp);
fread(&numBytes, sizeof(int), 1, fp);
int left = getRemainingFileSize(fp);
if (numBytes <= left && numBytes > 0) {
unsigned char* buf = new unsigned char[numBytes];
fread(buf, 1, numBytes, fp);
RakNet::BitStream stream(buf, numBytes, false);
RakDataInput dis(stream);
CompoundTag* tag = NbtIo::read(&dis);
//
// Read Entity:es
//
if (tag->contains("Entities", Tag::TAG_List)) {
ListTag* entityTags = tag->getList("Entities");
for (int i = 0; i < entityTags->size(); ++i) {
Tag* _et = entityTags->get(i);
if (!_et || _et->getId() != Tag::TAG_Compound) {
LOGE("Entity tag is either NULL or not a compoundTag: %p : %d!\n", _et, _et?_et->getId() : -1);
continue;
}
CompoundTag* et = (CompoundTag*)_et;
if (Entity* e = EntityFactory::loadEntity(et, level)) {
level->addEntity(e);
}
}
}
//
// Read TileEntity:s
//
if (tag->contains("TileEntities", Tag::TAG_List)) {
ListTag* tileEntityTags = tag->getList("TileEntities");
for (int i = 0; i < tileEntityTags->size(); ++i) {
Tag* _et = tileEntityTags->get(i);
if (!_et || _et->getId() != Tag::TAG_Compound) {
LOGE("TileEntity tag is either NULL or not a compoundTag: %p : %d!\n", _et, _et?_et->getId() : -1);
continue;
}
CompoundTag* et = (CompoundTag*)_et;
if (TileEntity* e = TileEntity::loadStatic(et)) {
LevelChunk* chunk = level->getChunkAt(e->x, e->z);
if (chunk && !chunk->hasTileEntityAt(e)) {
LOGI("Adding TileEntity %d to %d, %d, %d\n", e->type, e->x, e->y, e->z);
chunk->addTileEntity(e);
} else {
if (!chunk)
LOGE("Couldn't find chunk at %d, %d to add %d\n", e->x, e->z, e->type);
else
LOGE("Already have TileEntity at %d, %d to add %d\n", e->x, e->z, e->type);
delete e;
}
}
}
}
tag->deleteChildren();
delete tag;
delete[] buf;
}
LOGI("header: %s, version: %d, bytes: %d (remaining: %d)\n", header, version, numBytes, left);
//fread(stream.GetData(), 1, numBytes, fp);
fclose(fp);
}
}
void ExternalFileLevelStorage::saveGame(Level* level) {
saveEntities(level, NULL);
}
int ExternalFileLevelStorage::savePendingUnsavedChunks( int maxCount ) {
if (maxCount < 0)
maxCount = unsavedChunkList.size();
int count = 0;
while (++count <= maxCount && !unsavedChunkList.empty()) {
UnsavedChunkList::iterator it = unsavedChunkList.begin();
UnsavedChunkList::iterator remove = unsavedChunkList.begin();
UnsavedLevelChunk* oldest = &(*it);
for ( ; it != unsavedChunkList.end(); ++it) {
if ((*it).addedToList < oldest->addedToList) {
oldest = &(*it);
remove = it;
}
}
LevelChunk* chunk = oldest->chunk;
unsavedChunkList.erase(remove);
save(level, chunk);
}
return count;
}
void ExternalFileLevelStorage::saveAll( Level* level, std::vector<LevelChunk*>& levelChunks ) {
ChunkStorage::saveAll(level, levelChunks);
int numChunks = savePendingUnsavedChunks(-1);
LOGI("Saving %d additional chunks.\n", numChunks);
}
#endif /*DEMO_MODE*/

View File

@@ -0,0 +1,88 @@
#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION)
#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__
#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__
//package net.minecraft.world.level.storage;
#include <vector>
#include <list>
//#include "com/mojang/nbt/CompoundTag.h"
#include "LevelStorage.h"
#include "../chunk/storage/ChunkStorage.h"
class Player;
class Dimension;
class RegionFile;
typedef struct UnsavedLevelChunk
{
int pos;
RakNet::TimeMS addedToList;
LevelChunk* chunk;
} UnsavedLevelChunk;
typedef std::list<UnsavedLevelChunk> UnsavedChunkList;
/*public*/
class ExternalFileLevelStorage:
public LevelStorage,
public ChunkStorage
//public PlayerIO
{
public:
ExternalFileLevelStorage(const std::string& levelId, const std::string& fullPath);
virtual ~ExternalFileLevelStorage();
LevelData* prepareLevel(Level* level);
//throws LevelConflictException
void checkSession() {}
ChunkStorage* createChunkStorage(Dimension* dimension) { return this; }
void saveLevelData(LevelData& levelData, std::vector<Player*>* players);
// PlayerIO getPlayerIO() { return this; }
// CompoundTag loadPlayerDataTag(std::string playerName) { return NULL; }
void closeAll() {}
static bool readLevelData(const std::string& directory, LevelData& dest);
static bool readPlayerData(const std::string& filename, LevelData& dest);
static bool writeLevelData(const std::string& datFileName, LevelData& dest, const std::vector<Player*>* players);
static void saveLevelData(const std::string& directory, LevelData& levelData, std::vector<Player*>* players);
int savePendingUnsavedChunks(int maxCount);
//
// ChunkStorage methods
//
virtual LevelChunk* load(Level* level, int x, int z);
void save(Level* level, LevelChunk* levelChunk);
// @note, loadEntities and saveEntities dont use second parameter
void loadEntities(Level* level, LevelChunk* levelChunk);
void saveEntities(Level* level, LevelChunk* levelChunk);
void saveGame(Level* level);
void saveAll(Level* level, std::vector<LevelChunk*>& levelChunks);
virtual void tick();
virtual void flush() {}
private:
std::string levelId;
std::string levelPath;
LevelData* loadedLevelData;
RegionFile* regionFile;
RegionFile* entitiesFile;
Level* level;
int tickCount;
int loadedStorageVersion;
UnsavedChunkList unsavedChunkList;
int lastSavedEntitiesTick;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__*/
#endif /*DEMO_MODE*/

View File

@@ -0,0 +1,193 @@
#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION)
#include "LevelData.h"
#include "ExternalFileLevelStorageSource.h"
#include "ExternalFileLevelStorage.h"
#include "FolderMethods.h"
#include "../../../platform/file.h"
#include "../../../util/StringUtils.h"
#include <cstdio>
#include <sys/types.h>
#ifdef __APPLE__
#include "MoveFolder.h"
#endif
static const char ILLEGAL_FILE_CHARACTERS[] = {
'/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':'
};
ExternalFileLevelStorageSource::ExternalFileLevelStorageSource(const std::string& externalPath, const std::string& temporaryFilesPath)
: _hasTempDirectory(temporaryFilesPath != externalPath)
{
#ifndef STANDALONE_SERVER
const char* p0 = "/games";
const char* p1 = "/com.mojang";
const char* p2 = "/minecraftWorlds";
const char* tree[] = {
p0, p1, p2
};
int treeLength = sizeof(tree) / sizeof(tree[0]);
createTree(externalPath.c_str(), tree, treeLength);
if (hasTempDirectory())
createTree(temporaryFilesPath.c_str(), tree, treeLength);
basePath = externalPath + p0 + p1 + p2;
tmpBasePath = temporaryFilesPath + p0 + p1 + p2;
#else
basePath = externalPath;
tmpBasePath = temporaryFilesPath;
#endif
}
void ExternalFileLevelStorageSource::addLevelSummaryIfExists(LevelSummaryList& dest, const char* dirName)
{
std::string directory = basePath;
directory += "/";
directory += dirName;
LevelData levelData;
if (ExternalFileLevelStorage::readLevelData(directory, levelData))
{
LevelSummary summary;
summary.id = dirName;
summary.name = levelData.levelName;
summary.lastPlayed = levelData.getLastPlayed();
summary.sizeOnDisk = (unsigned int)levelData.getSizeOnDisk();
summary.gameType = levelData.getGameType();
dest.push_back(summary);
}
}
void ExternalFileLevelStorageSource::getLevelList(LevelSummaryList& dest)
{
#ifdef WIN32
WIN32_FIND_DATAA fileData;
HANDLE hFind;
std::string searchString = basePath;
searchString += "/*";
hFind = FindFirstFileA(searchString.c_str(), &fileData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
addLevelSummaryIfExists(dest, fileData.cFileName);
} while (FindNextFileA(hFind, &fileData));
FindClose(hFind);
}
#else
DIR *dp;
struct dirent *dirp;
if((dp = opendir(basePath.c_str())) == NULL) {
LOGI("Error listing base folder %s: %d", basePath.c_str(), _errno());
return;
}
while ((dirp = readdir(dp)) != NULL) {
if (dirp->d_type == DT_DIR)
{
addLevelSummaryIfExists(dest, dirp->d_name);
}
}
closedir(dp);
#endif
}
LevelStorage* ExternalFileLevelStorageSource::selectLevel(const std::string& levelId, bool createPlayerDir) {
return new ExternalFileLevelStorage(levelId, getFullPath(levelId));
}
void ExternalFileLevelStorageSource::deleteLevel( const std::string& levelId )
{
std::string path = getFullPath(levelId);
if (!DeleteDirectory(path)) { // If we couldn't delete whole folder, try to remove chunks..
remove((path + "/chunks.dat").c_str());
remove((path + "/player.dat").c_str());
remove((path + "/level.dat").c_str());
}
}
static std::string getUniqueLevelName(const LevelSummaryList& levels, const std::string& level )
{
std::set<std::string> Set;
for (unsigned int i = 0; i < levels.size(); ++i)
Set.insert(levels[i].id);
std::string s = level;
while ( Set.find(s) != Set.end() )
s += "-";
return s;
}
void ExternalFileLevelStorageSource::renameLevel( const std::string& oldLevelId_, const std::string& newLevelName_ )
{
#define _renFULLPATH(s) ((basePath + "/" + s).c_str())
bool isTempFile = (TempLevelId == oldLevelId_);
std::string oldFolder = getFullPath(oldLevelId_);
if (_access(oldFolder.c_str(), 0) != 0) {
LOGI("Couldn't access %s\n", oldFolder.c_str());
return;
}
std::string levelName = Util::stringTrim(newLevelName_);
std::string levelId = levelName;
for (int i = 0; i < sizeof(ILLEGAL_FILE_CHARACTERS) / sizeof(char); ++i)
levelId = Util::stringReplace(levelId, std::string(1, ILLEGAL_FILE_CHARACTERS[i]), "");
LevelSummaryList levels;
getLevelList(levels);
levelId = getUniqueLevelName(levels, levelId);
bool couldRename = false;
if (hasTempDirectory() && isTempFile) {
#ifdef __APPLE__
std::string newFolder = basePath + "/" + levelId;
moveFolder(oldFolder, newFolder);
couldRename = (_access(newFolder.c_str(), 0) == 0);
#endif
}
couldRename = couldRename || rename(_renFULLPATH(oldLevelId_), _renFULLPATH(levelId)) == 0;
if (!couldRename) // != 0: fail
levelId = oldLevelId_; // Try to rewrite the level name anyway
// Rename the level name and write back to file
LevelData levelData;
ExternalFileLevelStorage::readLevelData(_renFULLPATH(levelId), levelData);
levelData.setLevelName(newLevelName_);
ExternalFileLevelStorage::saveLevelData(_renFULLPATH(levelId), levelData, NULL);
}
std::string ExternalFileLevelStorageSource::getName()
{
return "External File Level Storage";
}
LevelData* ExternalFileLevelStorageSource::getDataTagFor( const std::string& levelId )
{
return NULL;
}
bool ExternalFileLevelStorageSource::isNewLevelIdAcceptable( const std::string& levelId )
{
return true;
}
std::string ExternalFileLevelStorageSource::getFullPath(const std::string& levelId) {
return ((TempLevelId == levelId)? tmpBasePath : basePath) + "/" + levelId;
}
#endif /*DEMO_MODE*/

View File

@@ -0,0 +1,45 @@
#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION)
#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__
#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__
//package net.minecraft.world.level.storage;
#include "LevelStorageSource.h"
#include "MemoryLevelStorage.h"
class ProgressListener;
class ExternalFileLevelStorageSource: public LevelStorageSource
{
public:
ExternalFileLevelStorageSource(const std::string& externalPath, const std::string& temporaryFilesPath);
std::string getName();
void getLevelList(LevelSummaryList& dest);
LevelStorage* selectLevel(const std::string& levelId, bool createPlayerDir);
LevelData* getDataTagFor(const std::string& levelId);
bool isNewLevelIdAcceptable(const std::string& levelId);
void clearAll() {}
void deleteLevel(const std::string& levelId);
void renameLevel(const std::string& levelId, const std::string& newLevelName);
bool isConvertible(const std::string& levelId) { return false; }
bool requiresConversion(const std::string& levelId) { return false; }
bool convertLevel(const std::string& levelId, ProgressListener* progress) { return false; }
private:
void addLevelSummaryIfExists(LevelSummaryList& dest, const char* dirName);
bool hasTempDirectory() { return _hasTempDirectory; }
std::string getFullPath(const std::string& levelId);
std::string basePath;
std::string tmpBasePath;
bool _hasTempDirectory;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__*/
#endif /*DEMO_MODE*/

View File

@@ -0,0 +1,77 @@
#include "FolderMethods.h"
#include <string>
#ifndef WIN32
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
int _mkdir( const char* name ) {
return mkdir(name, 0755);
}
int _access( const char* name, int mode ) {
return access(name, mode);
}
int _errno() {
return errno;
}
#else
#include <io.h>
#include <direct.h>
#include <windows.h>
#endif
bool exists(const char* name) {
return _access(name, 0) == 0;
}
bool createFolderIfNotExists( const char* name ) {
if (exists(name))
return true;
int errorCode = 0;
if ((errorCode = _mkdir(name)) != 0) {
LOGI("FAILED to create folder %s, %d! Escape plan?\n", name, _errno());
return false;
}
LOGI("Created folder %s\n", name);
return true;
}
int getRemainingFileSize( FILE* fp ) {
if (!fp) return 0;
int current = ftell(fp);
fseek(fp, 0, SEEK_END);
int end = ftell(fp);
fseek(fp, current, SEEK_SET);
return end - current;
}
int getFileSize( const char* filename ) {
FILE* fp = fopen(filename, "rb");
if (!fp)
return -1;
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fclose(fp);
return size;
}
bool createTree( const char* base, const char* tree[], int treeLength ) {
if (!createFolderIfNotExists(base))
return false;
std::string p(base);
for (int i = 0; i < treeLength; ++i && tree[i]) {
p += tree[i];
if (!createFolderIfNotExists(p.c_str()))
return false;
}
return true;
}

View File

@@ -0,0 +1,22 @@
#ifndef _MINECRAFT_FOLDERMETHODS_H_
#define _MINECRAFT_FOLDERMETHODS_H_
#include "../../../platform/log.h"
#ifdef WIN32
#include <io.h>
#else
int _mkdir(const char* name);
int _access(const char* name, int mode);
int _errno();
#endif
bool exists(const char* name);
bool createFolderIfNotExists(const char* name);
int getRemainingFileSize(FILE* fp);
int getFileSize(const char* filename);
bool createTree(const char* base, const char* tree[], int treeLength);
#endif

View File

@@ -0,0 +1,364 @@
#include "LevelData.h"
LevelData::LevelData()
: xSpawn(128),
ySpawn(64),
zSpawn(128),
seed(0),
lastPlayed(0),
generatorVersion(SharedConstants::GeneratorVersion),
time(0),
dimension(Dimension::NORMAL),
playerDataVersion(-1),
storageVersion(0),
gameType(GameType::Default),
loadedPlayerTag(NULL)
{
//LOGI("ctor 1: %p\n", this);
spawnMobs = (gameType == GameType::Survival);
}
LevelData::LevelData( const LevelSettings& settings, const std::string& levelName, int generatorVersion /*= -1*/ )
: seed(settings.getSeed()),
gameType(settings.getGameType()),
levelName(levelName),
xSpawn(128),
ySpawn(64),
zSpawn(128),
lastPlayed(0),
time(0),
dimension(Dimension::NORMAL),
playerDataVersion(-1),
loadedPlayerTag(NULL)
{
//LOGI("ctor 2: %p\n", this);
if (generatorVersion < 0)
generatorVersion = SharedConstants::GeneratorVersion;
this->generatorVersion = generatorVersion;
spawnMobs = (gameType == GameType::Survival);
}
LevelData::LevelData( CompoundTag* tag )
: loadedPlayerTag(NULL)
{
//LOGI("ctor 3: %p (%p)\n", this, tag);
getTagData(tag);
}
LevelData::LevelData( const LevelData& rhs )
: seed(rhs.seed),
gameType(rhs.gameType),
levelName(rhs.levelName),
xSpawn(rhs.xSpawn),
ySpawn(rhs.ySpawn),
zSpawn(rhs.zSpawn),
lastPlayed(rhs.lastPlayed),
time(rhs.time),
dimension(rhs.dimension),
storageVersion(rhs.storageVersion),
playerDataVersion(rhs.playerDataVersion),
generatorVersion(rhs.generatorVersion),
spawnMobs(rhs.spawnMobs),
loadedPlayerTag(NULL),
playerData(rhs.playerData)
{
//LOGI("c-ctor: %p (%p)\n", this, &rhs);
setPlayerTag(rhs.loadedPlayerTag);
//PlayerData playerData;
}
LevelData& LevelData::operator=( const LevelData& rhs )
{
//LOGI("as-op: %p (%p)\n", this, &rhs);
if (this != &rhs) {
seed = rhs.seed;
gameType = rhs.gameType;
levelName = rhs.levelName;
xSpawn = rhs.xSpawn;
ySpawn = rhs.ySpawn;
zSpawn = rhs.zSpawn;
lastPlayed = rhs.lastPlayed;
time = rhs.time;
dimension = rhs.dimension;
spawnMobs = rhs.spawnMobs;
playerData = rhs.playerData;
playerDataVersion = rhs.playerDataVersion;
generatorVersion = rhs.generatorVersion;
storageVersion = rhs.storageVersion;
setPlayerTag(rhs.loadedPlayerTag);
}
return *this;
}
LevelData::~LevelData()
{
//LOGI("dtor: %p\n", this);
setPlayerTag(NULL);
}
void LevelData::v1_write( RakNet::BitStream& bitStream )
{
bitStream.Write(seed);
bitStream.Write(xSpawn);
bitStream.Write(ySpawn);
bitStream.Write(zSpawn);
bitStream.Write(time);
bitStream.Write(sizeOnDisk);
bitStream.Write(getEpochTimeS());
RakNet::RakString rakName = levelName.c_str();
bitStream.Write(rakName);
//LOGI("WBS: %d, %d, %d, %d, %d, %d\n", seed, xSpawn, ySpawn, zSpawn, time, sizeOnDisk);
}
void LevelData::v1_read( RakNet::BitStream& bitStream, int storageVersion )
{
this->storageVersion = storageVersion;
bitStream.Read(seed);
bitStream.Read(xSpawn);
bitStream.Read(ySpawn);
bitStream.Read(zSpawn);
bitStream.Read(time);
bitStream.Read(sizeOnDisk);
bitStream.Read(lastPlayed);
RakNet::RakString rakName;
bitStream.Read(rakName);
levelName = rakName.C_String();
//LOGI("RBS: %d, %d, %d, %d, %d, %d\n", seed, xSpawn, ySpawn, zSpawn, time, sizeOnDisk);
}
// Caller's responsibility to destroy this Tag
CompoundTag* LevelData::createTag()
{
CompoundTag* tag = new CompoundTag();
CompoundTag* player = loadedPlayerTag? (CompoundTag*)loadedPlayerTag->copy() : NULL;
setTagData(tag, player);
return tag;
}
CompoundTag* LevelData::createTag( const std::vector<Player*>& players )
{
CompoundTag* tag = new CompoundTag();
Player* player = NULL;
CompoundTag* playerTag = NULL;
if (!players.empty()) player = players[0];
if (player != NULL) {
playerTag = new CompoundTag();
player->saveWithoutId(playerTag);
}
setTagData(tag, playerTag);
return tag;
}
void LevelData::setTagData( CompoundTag* tag, CompoundTag* playerTag )
{
if (!tag) return;
tag->putLong("RandomSeed", seed);
tag->putInt("GameType", gameType);
tag->putInt("SpawnX", xSpawn);
tag->putInt("SpawnY", ySpawn);
tag->putInt("SpawnZ", zSpawn);
tag->putLong("Time", time);
tag->putLong("SizeOnDisk", sizeOnDisk);
tag->putLong("LastPlayed", getEpochTimeS());
tag->putString("LevelName", levelName);
tag->putInt("StorageVersion", storageVersion);
tag->putInt("Platform", 2);
if (playerTag != NULL) {
tag->putCompound("Player", playerTag);
}
}
void LevelData::getTagData( const CompoundTag* tag )
{
if (!tag) return;
seed = (long)tag->getLong("RandomSeed");
gameType = tag->getInt("GameType");
xSpawn = tag->getInt("SpawnX");
ySpawn = tag->getInt("SpawnY");
zSpawn = tag->getInt("SpawnZ");
time = (long)tag->getLong("Time");
lastPlayed = (int)tag->getLong("LastPlayed");
sizeOnDisk = (int)tag->getLong("SizeOnDisk");
levelName = tag->getString("LevelName");
storageVersion = tag->getInt("StorageVersion");
spawnMobs = (gameType == GameType::Survival);
if (tag->contains("Player", Tag::TAG_Compound)) {
setPlayerTag(tag->getCompound("Player"));
//dimension = loadedPlayerTag.getInt("Dimension");
}
}
void LevelData::setPlayerTag( CompoundTag* tag )
{
if (loadedPlayerTag) {
loadedPlayerTag->deleteChildren();
delete loadedPlayerTag;
loadedPlayerTag = NULL;
}
if (tag)
loadedPlayerTag = (CompoundTag*)tag->copy();
}
long LevelData::getSeed() const
{
return seed;
}
int LevelData::getXSpawn() const
{
return xSpawn;
}
int LevelData::getYSpawn() const
{
return ySpawn;
}
int LevelData::getZSpawn() const
{
return zSpawn;
}
long LevelData::getTime() const
{
return time;
}
long LevelData::getSizeOnDisk() const
{
return sizeOnDisk;
}
CompoundTag* LevelData::getLoadedPlayerTag()
{
return loadedPlayerTag;
}
void LevelData::setLoadedPlayerTo( Player* p )
{
if (playerDataVersion == 1)
playerData.loadPlayer(p);
}
int LevelData::getDimension()
{
return dimension;
}
void LevelData::setSeed( long seed )
{
this->seed = seed;
}
void LevelData::setXSpawn( int xSpawn )
{
this->xSpawn = xSpawn;
}
void LevelData::setYSpawn( int ySpawn )
{
this->ySpawn = ySpawn;
}
void LevelData::setZSpawn( int zSpawn )
{
this->zSpawn = zSpawn;
}
void LevelData::setTime( long time )
{
this->time = time;
}
void LevelData::setSizeOnDisk( long sizeOnDisk )
{
this->sizeOnDisk = sizeOnDisk;
}
void LevelData::setLoadedPlayerTag( CompoundTag* playerTag )
{
LOGI("set-p: %p (%p <- %p)\n", this, loadedPlayerTag, playerTag);
if (loadedPlayerTag) {
loadedPlayerTag->deleteChildren();
delete loadedPlayerTag;
}
loadedPlayerTag = playerTag;
}
void LevelData::setDimension( int dimension )
{
this->dimension = dimension;
}
void LevelData::setSpawn( int xSpawn, int ySpawn, int zSpawn )
{
this->xSpawn = xSpawn;
this->ySpawn = ySpawn;
this->zSpawn = zSpawn;
}
std::string LevelData::getLevelName()
{
return levelName;
}
void LevelData::setLevelName( const std::string& levelName )
{
this->levelName = levelName;
}
int LevelData::getGeneratorVersion() const
{
return generatorVersion;
}
void LevelData::setGeneratorVersion( int version )
{
this->generatorVersion = version;
}
long LevelData::getLastPlayed() const
{
return lastPlayed;
}
int LevelData::getStorageVersion() const
{
return storageVersion;
}
void LevelData::setStorageVersion( int version )
{
storageVersion = version;
}
int LevelData::getGameType() const
{
return gameType;
}
void LevelData::setGameType( int type )
{
gameType = type;
}
bool LevelData::getSpawnMobs() const
{
return spawnMobs;
}
void LevelData::setSpawnMobs( bool doSpawn )
{
spawnMobs = doSpawn;
}

View File

@@ -0,0 +1,97 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelData_H__
#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelData_H__
//package net.minecraft.world.level.storage;
#include <string>
#include "PlayerData.h"
#include "../LevelSettings.h"
#include "../dimension/Dimension.h"
// sorry for RakNet dependency, but I really like using BitStream
#include "../../../raknet/BitStream.h"
#include "../../../platform/time.h"
#include "../../../nbt/CompoundTag.h"
class LevelData
{
public:
LevelData();
LevelData(const LevelSettings& settings, const std::string& levelName, int generatorVersion = -1);
LevelData(CompoundTag* tag);
LevelData(const LevelData& rhs);
LevelData& operator=(const LevelData& rhs);
~LevelData();
void v1_write(RakNet::BitStream& bitStream);
void v1_read(RakNet::BitStream& bitStream, int storageVersion);
// Caller's responsibility to destroy this Tag
CompoundTag* createTag();
CompoundTag* createTag(const std::vector<Player*>& players);
void getTagData(const CompoundTag* tag);
void setTagData(CompoundTag* tag, CompoundTag* playerTag);
long getSeed() const;
int getXSpawn() const;
int getYSpawn() const;
int getZSpawn() const;
long getTime() const;
long getSizeOnDisk() const;
void setPlayerTag(CompoundTag* tag);
CompoundTag* getLoadedPlayerTag();
void setLoadedPlayerTo(Player* p);
int getDimension();
void setSeed(long seed);
void setXSpawn(int xSpawn);
void setYSpawn(int ySpawn);
void setZSpawn(int zSpawn);
void setSpawn(int xSpawn, int ySpawn, int zSpawn);
void setTime(long time);
void setSizeOnDisk(long sizeOnDisk);
void setLoadedPlayerTag(CompoundTag* playerTag);
void setDimension(int dimension);
std::string getLevelName();
void setLevelName(const std::string& levelName);
int getGeneratorVersion() const;
void setGeneratorVersion(int version);
long getLastPlayed() const;
int getStorageVersion() const;
void setStorageVersion(int version);
int getGameType() const;
void setGameType(int type);
bool getSpawnMobs() const;
void setSpawnMobs(bool doSpawn);
public:
PlayerData playerData;
int playerDataVersion;
std::string levelName;
private:
long seed;
int xSpawn;
int ySpawn;
int zSpawn;
long time;
int lastPlayed;
long sizeOnDisk;
CompoundTag* loadedPlayerTag;
int dimension;
int gameType;
int storageVersion;
bool spawnMobs;
//@note: This version is never written or loaded to disk. The only purpose
// is to use it in the level generator on server and clients.
int generatorVersion;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelData_H__*/

View File

@@ -0,0 +1,39 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelStorage_H__
#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelStorage_H__
//package net.minecraft.world.level.storage;
#include <vector>
#include <string>
class LevelData;
class ChunkStorage;
class Dimension;
class Player;
class Level;
class LevelChunk;
class LevelStorage
{
public:
virtual ~LevelStorage() {}
virtual LevelData* prepareLevel(Level* level) = 0;
virtual ChunkStorage* createChunkStorage(Dimension* dimension) = 0;
virtual void saveLevelData(LevelData& levelData, std::vector<Player*>* players) = 0;
virtual void saveLevelData(LevelData& levelData) {
saveLevelData(levelData, NULL);
}
virtual void closeAll() = 0;
virtual void saveGame(Level* level) {}
virtual void loadEntities(Level* level, LevelChunk* levelChunk) {}
//void checkSession() throws LevelConflictException;
//PlayerIO getPlayerIO();
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelStorage_H__*/

View File

@@ -0,0 +1,3 @@
#include "LevelStorageSource.h"
const std::string LevelStorageSource::TempLevelId = "_LastJoinedServer";

View File

@@ -0,0 +1,60 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelStorageSource_H__
#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelStorageSource_H__
//package net.minecraft.world.level.storage;
#include <string>
#include <vector>
class ProgressListener;
class LevelData;
class LevelStorage;
struct LevelSummary
{
std::string id;
std::string name;
int lastPlayed;
int gameType;
unsigned int sizeOnDisk;
bool operator<(const LevelSummary& rhs) const {
return lastPlayed > rhs.lastPlayed;
}
};
typedef std::vector<LevelSummary> LevelSummaryList;
class LevelStorageSource
{
public:
static const std::string TempLevelId;
virtual ~LevelStorageSource() {}
virtual std::string getName() = 0;
virtual void getLevelList(LevelSummaryList& dest) {};
virtual LevelData* getDataTagFor(const std::string& levelId) = 0;
virtual LevelStorage* selectLevel(const std::string& levelId, bool createPlayerDir) = 0;
/**
* Tests if a levelId can be used to store a level. For example, a levelId
* can't be called COM1 on Windows systems, because that is a reserved file
* handle.
* <p>
* Also, a new levelId may not overwrite an existing one.
*
* @param levelId
* @return
*/
virtual bool isNewLevelIdAcceptable(const std::string& levelId) = 0;
virtual void clearAll() = 0;
virtual void deleteLevel(const std::string& levelId) = 0;
virtual void renameLevel(const std::string& levelId, const std::string& newLevelName) = 0;
virtual bool isConvertible(const std::string& levelId) = 0;
virtual bool requiresConversion(const std::string& levelId) = 0;
virtual bool convertLevel(const std::string& levelId, ProgressListener* progress) = 0;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__LevelStorageSource_H__*/

View File

@@ -0,0 +1,53 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__MemoryLevelStorage_H__
#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__MemoryLevelStorage_H__
//package net.minecraft.world.level.storage;
#include <vector>
#include "LevelStorage.h"
#include "../chunk/storage/MemoryChunkStorage.h"
class Player;
class Dimension;
class MemoryLevelStorage: public LevelStorage //public PlayerIO
{
public:
MemoryLevelStorage()
: _storage(NULL)
{}
~MemoryLevelStorage() {
delete _storage;
}
LevelData* prepareLevel(Level* level) {
return NULL;
}
void checkSession() //throws LevelConflictException
{}
ChunkStorage* createChunkStorage(Dimension* dimension) {
if (_storage) {
LOGW(">WARNING< Creating a MemoryChunkStorage over another (#%p). A memory leak will occur.\n", _storage);
}
return _storage = new MemoryChunkStorage();
}
void saveLevelData(LevelData& levelData, std::vector<Player*>* players) {}
void closeAll() {}
void save(Player* player) {}
void load(Player* player) {}
/* CompoundTag loadPlayerDataTag(std::string playerName) {
return NULL;
} */
MemoryChunkStorage* _storage;
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__MemoryLevelStorage_H__*/

View File

@@ -0,0 +1,58 @@
#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__MemoryLevelStorageSource_H__
#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__MemoryLevelStorageSource_H__
//package net.minecraft.world.level.storage;
#include "LevelStorageSource.h"
#include "MemoryLevelStorage.h"
class ProgressListener;
class MemoryLevelStorageSource: public LevelStorageSource
{
public:
MemoryLevelStorageSource() {
}
std::string getName() {
return "Memory Storage";
}
LevelStorage* selectLevel(const std::string& levelId, bool createPlayerDir) {
return new MemoryLevelStorage();
}
//List<LevelSummary> getLevelList() {
// return /*new*/ ArrayList<LevelSummary>();
//}
void clearAll() {
}
LevelData* getDataTagFor(const std::string& levelId) {
return NULL;
}
bool isNewLevelIdAcceptable(const std::string& levelId) {
return true;
}
void deleteLevel(const std::string& levelId) {
}
void renameLevel(const std::string& levelId, const std::string& newLevelName) {
}
bool isConvertible(const std::string& levelId) {
return false;
}
bool requiresConversion(const std::string& levelId) {
return false;
}
bool convertLevel(const std::string& levelId, ProgressListener* progress) {
return false;
}
};
#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__MemoryLevelStorageSource_H__*/

View File

@@ -0,0 +1,8 @@
#ifndef MOVEFOLDER_H__
#define MOVEFOLDER_H__
#include <string>
void moveFolder(const std::string& src, const std::string& dst);
#endif /*MOVEFOLDER_H__*/

View File

@@ -0,0 +1,11 @@
#include "MoveFolder.h"
void moveFolder(const std::string& src, const std::string& dst) {
NSError* error = NULL;
[[NSFileManager defaultManager]
moveItemAtPath:[NSString stringWithUTF8String:src.c_str()]
toPath:[NSString stringWithUTF8String:dst.c_str()] error:&error];
if (error)
NSLog(@"Error: %@\n: %@\n", [error description], [error debugDescription]);
}

Some files were not shown because too many files have changed in this diff Show More