the whole game
This commit is contained in:
49
src/world/level/ChunkPos.h
Executable file
49
src/world/level/ChunkPos.h
Executable 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
164
src/world/level/Explosion.cpp
Executable 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
38
src/world/level/Explosion.h
Executable 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
36
src/world/level/FoliageColor.h
Executable 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
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
343
src/world/level/Level.h
Executable 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__*/
|
||||
14
src/world/level/LevelConstants.h
Executable file
14
src/world/level/LevelConstants.h
Executable 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
43
src/world/level/LevelListener.h
Executable 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
58
src/world/level/LevelSettings.h
Executable 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
36
src/world/level/LevelSource.h
Executable 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
4
src/world/level/LightLayer.cpp
Executable 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
20
src/world/level/LightLayer.h
Executable 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
194
src/world/level/LightUpdate.cpp
Executable 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
31
src/world/level/LightUpdate.h
Executable 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
284
src/world/level/MobSpawner.cpp
Executable 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
41
src/world/level/MobSpawner.h
Executable 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
140
src/world/level/Region.cpp
Executable 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
39
src/world/level/Region.h
Executable 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__*/
|
||||
29
src/world/level/TickNextTickData.cpp
Executable file
29
src/world/level/TickNextTickData.cpp
Executable 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;
|
||||
}
|
||||
25
src/world/level/TickNextTickData.h
Executable file
25
src/world/level/TickNextTickData.h
Executable 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
44
src/world/level/TilePos.h
Executable 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
229
src/world/level/biome/Biome.cpp
Executable 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
95
src/world/level/biome/Biome.h
Executable 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__*/
|
||||
11
src/world/level/biome/BiomeInclude.h
Executable file
11
src/world/level/biome/BiomeInclude.h
Executable 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__*/
|
||||
178
src/world/level/biome/BiomeSource.cpp
Executable file
178
src/world/level/biome/BiomeSource.cpp
Executable 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;
|
||||
//}
|
||||
62
src/world/level/biome/BiomeSource.h
Executable file
62
src/world/level/biome/BiomeSource.h
Executable 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__*/
|
||||
11
src/world/level/biome/FlatBiome.h
Executable file
11
src/world/level/biome/FlatBiome.h
Executable 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__*/
|
||||
24
src/world/level/biome/ForestBiome.h
Executable file
24
src/world/level/biome/ForestBiome.h
Executable 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__*/
|
||||
21
src/world/level/biome/RainforestBiome.h
Executable file
21
src/world/level/biome/RainforestBiome.h
Executable 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__*/
|
||||
11
src/world/level/biome/SwampBiome.h
Executable file
11
src/world/level/biome/SwampBiome.h
Executable 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__*/
|
||||
22
src/world/level/biome/TaigaBiome.h
Executable file
22
src/world/level/biome/TaigaBiome.h
Executable 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__*/
|
||||
264
src/world/level/chunk/ChunkCache.h
Executable file
264
src/world/level/chunk/ChunkCache.h
Executable file
@@ -0,0 +1,264 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include "ChunkSource.h"
|
||||
#include "storage/ChunkStorage.h"
|
||||
#include "EmptyLevelChunk.h"
|
||||
#include "../Level.h"
|
||||
#include "../LevelConstants.h"
|
||||
|
||||
class ChunkCache: public ChunkSource {
|
||||
//static const int CHUNK_CACHE_WIDTH = CHUNK_CACHE_WIDTH; // WAS 32;
|
||||
static const int MAX_SAVES = 2;
|
||||
public:
|
||||
ChunkCache(Level* level_, ChunkStorage* storage_, ChunkSource* source_)
|
||||
: xLast(-999999999),
|
||||
zLast(-999999999),
|
||||
last(NULL),
|
||||
level(level_),
|
||||
storage(storage_),
|
||||
source(source_)
|
||||
{
|
||||
isChunkCache = true;
|
||||
//emptyChunk = new EmptyLevelChunk(level_, emptyChunkBlocks, 0, 0);
|
||||
emptyChunk = new EmptyLevelChunk(level_, NULL, 0, 0);
|
||||
memset(chunks, 0, sizeof(LevelChunk*) * CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH);
|
||||
}
|
||||
|
||||
~ChunkCache() {
|
||||
delete source;
|
||||
delete emptyChunk;
|
||||
|
||||
for (int i = 0; i < CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; i++)
|
||||
{
|
||||
if (chunks[i])
|
||||
{
|
||||
chunks[i]->deleteBlockData();
|
||||
delete chunks[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool fits(int x, int z) {
|
||||
return (x >= 0 && z >= 0 && x < CHUNK_CACHE_WIDTH && z < CHUNK_CACHE_WIDTH);
|
||||
}
|
||||
|
||||
bool hasChunk(int x, int z) {
|
||||
// with a fixed world size, chunks outside the fitting area are always available (emptyChunks)
|
||||
if (!fits(x, z)) return true;
|
||||
|
||||
if (x == xLast && z == zLast && last != NULL) {
|
||||
return true;
|
||||
}
|
||||
int xs = x & (CHUNK_CACHE_WIDTH - 1);
|
||||
int zs = z & (CHUNK_CACHE_WIDTH - 1);
|
||||
int slot = xs + zs * CHUNK_CACHE_WIDTH;
|
||||
return chunks[slot] != NULL && (chunks[slot] == emptyChunk || chunks[slot]->isAt(x, z));
|
||||
}
|
||||
|
||||
LevelChunk* create(int x, int z) {
|
||||
return getChunk(x, z);
|
||||
}
|
||||
|
||||
LevelChunk* getChunk(int x, int z) {
|
||||
//static Stopwatch sw;
|
||||
//sw.start();
|
||||
|
||||
if (x == xLast && z == zLast && last != NULL) {
|
||||
return last;
|
||||
}
|
||||
if (!fits(x, z)) return emptyChunk;
|
||||
//if (!level->isFindingSpawn && !fits(x, z)) return emptyChunk;
|
||||
int xs = x & (CHUNK_CACHE_WIDTH - 1);
|
||||
int zs = z & (CHUNK_CACHE_WIDTH - 1);
|
||||
int slot = xs + zs * CHUNK_CACHE_WIDTH;
|
||||
if (!hasChunk(x, z)) {
|
||||
if (chunks[slot] != NULL) {
|
||||
chunks[slot]->unload();
|
||||
save(chunks[slot]);
|
||||
saveEntities(chunks[slot]);
|
||||
}
|
||||
|
||||
LevelChunk* newChunk = load(x, z);
|
||||
bool updateLights = false;
|
||||
if (newChunk == NULL) {
|
||||
if (source == NULL) {
|
||||
newChunk = emptyChunk;
|
||||
} else {
|
||||
newChunk = source->getChunk(x, z);
|
||||
}
|
||||
} else {
|
||||
//return emptyChunk;
|
||||
updateLights = true;
|
||||
}
|
||||
chunks[slot] = newChunk;
|
||||
newChunk->lightLava();
|
||||
|
||||
if (updateLights)
|
||||
{
|
||||
for (int cx = 0; cx < 16; cx++)
|
||||
{
|
||||
for (int cz = 0; cz < 16; cz++)
|
||||
{
|
||||
int height = level->getHeightmap(cx + x * 16, cz + z * 16);
|
||||
for (int cy = height; cy >= 0; cy--)
|
||||
{
|
||||
level->updateLight(LightLayer::Sky, cx + x * 16, cy, cz + z * 16, cx + x * 16, cy, cz + z * 16);
|
||||
level->updateLight(LightLayer::Block, cx + x * 16 - 1, cy, cz + z * 16 - 1, cx + x * 16 + 1, cy, cz + z * 16 + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//level->updateLight(LightLayer::Sky, x * 16, 0, z * 16, x * 16 + 15, 128, z * 16 + 15);
|
||||
//level->updateLight(LightLayer::Block, x * 16, 0, z * 16, x * 16 + 15, 128, z * 16 + 15);
|
||||
}
|
||||
|
||||
if (chunks[slot] != NULL) {
|
||||
chunks[slot]->load();
|
||||
}
|
||||
|
||||
if (!chunks[slot]->terrainPopulated && hasChunk(x + 1, z + 1) && hasChunk(x, z + 1) && hasChunk(x + 1, z)) postProcess(this, x, z);
|
||||
if (hasChunk(x - 1, z) && !getChunk(x - 1, z)->terrainPopulated && hasChunk(x - 1, z + 1) && hasChunk(x, z + 1) && hasChunk(x - 1, z)) postProcess(this, x - 1, z);
|
||||
if (hasChunk(x, z - 1) && !getChunk(x, z - 1)->terrainPopulated && hasChunk(x + 1, z - 1) && hasChunk(x, z - 1) && hasChunk(x + 1, z)) postProcess(this, x, z - 1);
|
||||
if (hasChunk(x - 1, z - 1) && !getChunk(x - 1, z - 1)->terrainPopulated && hasChunk(x - 1, z - 1) && hasChunk(x, z - 1) && hasChunk(x - 1, z)) postProcess(this, x - 1, z - 1);
|
||||
}
|
||||
xLast = x;
|
||||
zLast = z;
|
||||
last = chunks[slot];
|
||||
|
||||
//sw.stop();
|
||||
//sw.printEvery(500000, "ChunkCache::load: ");
|
||||
|
||||
return chunks[slot];
|
||||
}
|
||||
|
||||
Biome::MobList getMobsAt(const MobCategory& mobCategory, int x, int y, int z) {
|
||||
return source->getMobsAt(mobCategory, x, y, z);
|
||||
}
|
||||
|
||||
void postProcess(ChunkSource* parent, int x, int z) {
|
||||
if (!fits(x, z)) return;
|
||||
LevelChunk* chunk = getChunk(x, z);
|
||||
if (!chunk->terrainPopulated) {
|
||||
chunk->terrainPopulated = true;
|
||||
if (source != NULL) {
|
||||
source->postProcess(parent, x, z);
|
||||
chunk->clearUpdateMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//bool save(bool force, ProgressListener progressListener) {
|
||||
// int saves = 0;
|
||||
// int count = 0;
|
||||
// if (progressListener != NULL) {
|
||||
// for (int i = 0; i < chunks.length; i++) {
|
||||
// if (chunks[i] != NULL && chunks[i].shouldSave(force)) {
|
||||
// count++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// int cc = 0;
|
||||
// for (int i = 0; i < chunks.length; i++) {
|
||||
// if (chunks[i] != NULL) {
|
||||
// if (force && !chunks[i].dontSave) saveEntities(chunks[i]);
|
||||
// if (chunks[i].shouldSave(force)) {
|
||||
// save(chunks[i]);
|
||||
// chunks[i].unsaved = false;
|
||||
// if (++saves == MAX_SAVES && !force) return false;
|
||||
// if (progressListener != NULL) {
|
||||
// if (++cc % 10 == 0) {
|
||||
// progressListener.progressStagePercentage(cc * 100 / count);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (force) {
|
||||
// if (storage == NULL) return true;
|
||||
// storage.flush();
|
||||
// }
|
||||
// return true;
|
||||
//}
|
||||
|
||||
bool tick() {
|
||||
if (storage != NULL) storage->tick();
|
||||
return source->tick();
|
||||
}
|
||||
|
||||
bool shouldSave() {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string gatherStats() {
|
||||
return "ChunkCache: 1024";
|
||||
}
|
||||
|
||||
void saveAll(bool onlyUnsaved) {
|
||||
if (storage != NULL) {
|
||||
std::vector<LevelChunk*> chunks;
|
||||
for (int z = 0; z < CHUNK_CACHE_WIDTH; ++z)
|
||||
for (int x = 0; x < CHUNK_CACHE_WIDTH; ++x) {
|
||||
LevelChunk* chunk = level->getChunk(x, z);
|
||||
if (!onlyUnsaved || chunk->shouldSave(false))
|
||||
chunks.push_back( chunk );
|
||||
}
|
||||
storage->saveAll(level, chunks);
|
||||
}
|
||||
}
|
||||
private:
|
||||
LevelChunk* load(int x, int z) {
|
||||
if (storage == NULL) return emptyChunk;
|
||||
if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH)
|
||||
{
|
||||
return emptyChunk;
|
||||
}
|
||||
//try {
|
||||
LevelChunk* levelChunk = storage->load(level, x, z);
|
||||
if (levelChunk != NULL) {
|
||||
levelChunk->lastSaveTime = level->getTime();
|
||||
}
|
||||
return levelChunk;
|
||||
//} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return emptyChunk;
|
||||
//}
|
||||
}
|
||||
|
||||
void saveEntities(LevelChunk* levelChunk) {
|
||||
if (storage == NULL) return;
|
||||
//try {
|
||||
storage->saveEntities(level, levelChunk);
|
||||
//} catch (Error e) {
|
||||
// e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
|
||||
void save(LevelChunk* levelChunk) {
|
||||
if (storage == NULL) return;
|
||||
//try {
|
||||
levelChunk->lastSaveTime = level->getTime();
|
||||
storage->save(level, levelChunk);
|
||||
//} catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
//}
|
||||
}
|
||||
|
||||
public:
|
||||
int xLast;
|
||||
int zLast;
|
||||
private:
|
||||
//unsigned char emptyChunkBlocks[LevelChunk::ChunkBlockCount];
|
||||
LevelChunk* emptyChunk;
|
||||
ChunkSource* source;
|
||||
ChunkStorage* storage;
|
||||
LevelChunk* chunks[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
Level* level;
|
||||
|
||||
LevelChunk* last;
|
||||
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkCache_H__*/
|
||||
46
src/world/level/chunk/ChunkSource.h
Executable file
46
src/world/level/chunk/ChunkSource.h
Executable file
@@ -0,0 +1,46 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkSource_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkSource_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include <string>
|
||||
#include "../biome/Biome.h"
|
||||
|
||||
class ProgressListener;
|
||||
class LevelChunk;
|
||||
|
||||
class ChunkSource
|
||||
{
|
||||
public:
|
||||
bool isChunkCache;
|
||||
|
||||
ChunkSource()
|
||||
: isChunkCache(false)
|
||||
{}
|
||||
|
||||
virtual ~ChunkSource(){}
|
||||
|
||||
virtual bool hasChunk(int x, int y) = 0;
|
||||
|
||||
virtual LevelChunk* getChunk(int x, int z) = 0;
|
||||
|
||||
virtual LevelChunk* create(int x, int z) = 0;
|
||||
|
||||
virtual void postProcess(ChunkSource* parent, int x, int z) = 0;
|
||||
|
||||
//virtual bool save(bool force, ProgressListener* progressListener) = 0;
|
||||
|
||||
virtual bool tick() = 0;
|
||||
|
||||
virtual bool shouldSave() = 0;
|
||||
virtual void saveAll(bool onlyUnsaved) {}
|
||||
|
||||
virtual Biome::MobList getMobsAt(const MobCategory& mobCategory, int x, int y, int z) = 0;
|
||||
|
||||
/**
|
||||
* Returns some stats that are rendered when the user holds F3.
|
||||
*/
|
||||
virtual std::string gatherStats() = 0;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__ChunkSource_H__*/
|
||||
75
src/world/level/chunk/DataLayer.h
Executable file
75
src/world/level/chunk/DataLayer.h
Executable file
@@ -0,0 +1,75 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__DataLayer_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__DataLayer_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include <cstring>
|
||||
|
||||
class DataLayer
|
||||
{
|
||||
public:
|
||||
DataLayer()
|
||||
: data(NULL),
|
||||
length(0)
|
||||
{}
|
||||
|
||||
DataLayer(int length) {
|
||||
this->length = length >> 1;
|
||||
data = new unsigned char[this->length];
|
||||
setAll(0);
|
||||
slotMax = this->length;
|
||||
}
|
||||
|
||||
DataLayer(unsigned char* data, int length) {
|
||||
this->length = length >> 1;
|
||||
this->data = data;
|
||||
}
|
||||
|
||||
~DataLayer() {
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
int get(int x, int y, int z) {
|
||||
return get(x << 11 | z << 7 | y);
|
||||
}
|
||||
|
||||
void set(int x, int y, int z, int val) {
|
||||
set(x << 11 | z << 7 | y, val);
|
||||
}
|
||||
|
||||
__inline int get(int pos) {
|
||||
int slot = pos >> 1;
|
||||
int part = pos & 1;
|
||||
|
||||
if (part == 0) {
|
||||
return data[slot] & 0xf;
|
||||
} else {
|
||||
return (data[slot] >> 4) & 0xf;
|
||||
}
|
||||
}
|
||||
__inline void set(int pos, int val) {
|
||||
int slot = pos >> 1;
|
||||
int part = pos & 1;
|
||||
|
||||
if (part == 0) {
|
||||
data[slot] = ((data[slot] & 0xf0) | (val & 0xf));
|
||||
} else {
|
||||
data[slot] = ((data[slot] & 0x0f) | ((val & 0xf) << 4));
|
||||
}
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return data != NULL;
|
||||
}
|
||||
|
||||
void setAll(int br) {
|
||||
unsigned char val = (br & (br << 4));
|
||||
memset(data, val, length);
|
||||
}
|
||||
|
||||
unsigned char* data;
|
||||
int length;
|
||||
int slotMax;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__DataLayer_H__*/
|
||||
196
src/world/level/chunk/EmptyLevelChunk.h
Executable file
196
src/world/level/chunk/EmptyLevelChunk.h
Executable file
@@ -0,0 +1,196 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__EmptyLevelChunk_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__EmptyLevelChunk_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
/* import java.util.* */
|
||||
|
||||
//#include "world/entity/Entity.h"
|
||||
/* import net.minecraft.world.level.* */
|
||||
//#include "world/level/tile/entity/TileEntity.h"
|
||||
//#include "world/phys/AABB.h"
|
||||
|
||||
#include "LevelChunk.h"
|
||||
#include "../tile/Tile.h"
|
||||
#include "../Level.h"
|
||||
|
||||
class EmptyLevelChunk: public LevelChunk
|
||||
{
|
||||
public:
|
||||
EmptyLevelChunk(Level* level, int x, int z)
|
||||
: LevelChunk(level, x, z)
|
||||
{
|
||||
dontSave = true;
|
||||
}
|
||||
|
||||
EmptyLevelChunk(Level* level, unsigned char* blocks, int x, int z)
|
||||
: LevelChunk(level, blocks, x, z)
|
||||
{
|
||||
dontSave = true;
|
||||
}
|
||||
|
||||
bool isAt(int x, int z) {
|
||||
return x == this->x && z == this->z;
|
||||
}
|
||||
|
||||
int getHeightmap(int x, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void recalcBlockLights() {
|
||||
}
|
||||
|
||||
void recalcHeightmapOnly() {
|
||||
return;
|
||||
}
|
||||
|
||||
void recalcHeightmap() {
|
||||
return;
|
||||
}
|
||||
|
||||
void lightLava() {
|
||||
return;
|
||||
}
|
||||
|
||||
int getTile(int x, int y, int z) {
|
||||
//if (y <= 1)
|
||||
//{
|
||||
// return Tile::unbreakable->id;
|
||||
//}
|
||||
//else if (y < 64)
|
||||
//{
|
||||
// return Tile::water->id;
|
||||
//}
|
||||
//return 0;
|
||||
return Tile::invisible_bedrock->id;
|
||||
}
|
||||
|
||||
bool setTileAndData(int x, int y, int z, int _tile, int _data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setTile(int x, int y, int z, int _tile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int getData(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setData(int x, int y, int z, int val) {
|
||||
return;
|
||||
}
|
||||
|
||||
int getBrightness(const LightLayer& layer, int x, int y, int z) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
void setBrightness(const LightLayer& layer, int x, int y, int z, int brightness) {
|
||||
return;
|
||||
}
|
||||
|
||||
int getRawBrightness(int x, int y, int z, int skyDampen) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
void addEntity(Entity* e) {
|
||||
return;
|
||||
}
|
||||
|
||||
void removeEntity(Entity* e) {
|
||||
return;
|
||||
}
|
||||
|
||||
void removeEntity(Entity* e, int yc) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isSkyLit(int x, int y, int z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void skyBrightnessChanged() {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
TileEntity getTileEntity(int x, int y, int z) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void addTileEntity(TileEntity te) {
|
||||
return;
|
||||
}
|
||||
|
||||
void setTileEntity(int x, int y, int z, TileEntity tileEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
void removeTileEntity(int x, int y, int z) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
void load() {
|
||||
return;
|
||||
}
|
||||
|
||||
void unload() {
|
||||
return;
|
||||
}
|
||||
|
||||
void markUnsaved() {
|
||||
return;
|
||||
}
|
||||
|
||||
void getEntities(Entity* except, const AABB& bb, std::vector<Entity*>& es) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
void getEntitiesOfClass(Class<? extends Entity> baseClass, AABB bb, List<Entity> es) {
|
||||
return;
|
||||
}
|
||||
|
||||
int countEntities() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool shouldSave(bool force) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
void setBlocks(unsigned char* newBlocks, int sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
int getBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p) {
|
||||
int xs = x1 - x0;
|
||||
int ys = y1 - y0;
|
||||
int zs = z1 - z0;
|
||||
|
||||
int s = xs * ys * zs;
|
||||
int len = s + s / 2 * 3;
|
||||
|
||||
memset(data + p, Tile::invisible_bedrock->id, len); //Arrays.fill(data, p, p + len, (char) 0);
|
||||
return len;
|
||||
}
|
||||
|
||||
int setBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p) {
|
||||
int xs = x1 - x0;
|
||||
int ys = y1 - y0;
|
||||
int zs = z1 - z0;
|
||||
|
||||
int s = xs * ys * zs;
|
||||
return s + s / 2 * 3;
|
||||
}
|
||||
|
||||
Random getRandom(long l) {
|
||||
return /*new*/ Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l);
|
||||
}
|
||||
|
||||
bool isEmpty() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__EmptyLevelChunk_H__*/
|
||||
713
src/world/level/chunk/LevelChunk.cpp
Executable file
713
src/world/level/chunk/LevelChunk.cpp
Executable file
@@ -0,0 +1,713 @@
|
||||
#include "LevelChunk.h"
|
||||
#include "../LightLayer.h"
|
||||
#include "../tile/Tile.h"
|
||||
#include "../Level.h"
|
||||
#include "../dimension/Dimension.h"
|
||||
#include "../../phys/AABB.h"
|
||||
#include "../../entity/Entity.h"
|
||||
#include "../TilePos.h"
|
||||
#include "../tile/entity/TileEntity.h"
|
||||
#include "../tile/EntityTile.h"
|
||||
#include "../LevelConstants.h"
|
||||
|
||||
/*static*/
|
||||
bool LevelChunk::touchedSky = false;
|
||||
|
||||
LevelChunk::LevelChunk( Level* level, int x, int z )
|
||||
: level(level),
|
||||
x(x),
|
||||
z(z),
|
||||
xt(x * CHUNK_WIDTH),
|
||||
zt(z * CHUNK_DEPTH)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LevelChunk::LevelChunk( Level* level, unsigned char* blocks, int x, int z )
|
||||
: level(level),
|
||||
x(x),
|
||||
z(z),
|
||||
xt(x * CHUNK_WIDTH),
|
||||
zt(z * CHUNK_DEPTH),
|
||||
blocks(blocks),
|
||||
data(ChunkBlockCount),
|
||||
skyLight(ChunkBlockCount),
|
||||
blockLight(ChunkBlockCount),
|
||||
blocksLength(ChunkBlockCount)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LevelChunk::~LevelChunk()
|
||||
{
|
||||
//delete blocks;
|
||||
}
|
||||
|
||||
void LevelChunk::init()
|
||||
{
|
||||
terrainPopulated = false;
|
||||
dontSave = false;
|
||||
unsaved = false;
|
||||
lastSaveHadEntities = false;
|
||||
createdFromSave = false;
|
||||
lastSaveTime = 0;
|
||||
memset(heightmap, 0, 256);
|
||||
memset(updateMap, 0, 256);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
bool LevelChunk::setTileAndData(int x, int y, int z, int tile_, int data_) {
|
||||
|
||||
int tile = tile_ & 0xff;
|
||||
|
||||
int oldHeight = heightmap[z << 4 | x];
|
||||
|
||||
int old = blocks[x << 11 | z << 7 | y];
|
||||
if (old == tile && data.get(x, y, z) == data_) return false;
|
||||
int xOffs = xt + x;
|
||||
int zOffs = zt + z;
|
||||
blocks[x << 11 | z << 7 | y] = (unsigned char) tile;
|
||||
if (old != 0) {
|
||||
if (!level->isClientSide) {
|
||||
Tile::tiles[old]->onRemove(level, xOffs, y, zOffs);
|
||||
} else if (old != tile && Tile::isEntityTile[old]) {
|
||||
level->removeTileEntity(xOffs, y, zOffs);
|
||||
}
|
||||
}
|
||||
data.set(x, y, z, data_);
|
||||
|
||||
if (!level->dimension->hasCeiling) {
|
||||
if (Tile::lightBlock[tile] != 0) {
|
||||
if (y >= oldHeight) {
|
||||
recalcHeight(x, y + 1, z);
|
||||
}
|
||||
} else {
|
||||
if (y == oldHeight - 1) {
|
||||
recalcHeight(x, y, z);
|
||||
}
|
||||
}
|
||||
level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
}
|
||||
|
||||
level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
lightGaps(x, z);
|
||||
|
||||
if (!level->isClientSide && tile != 0) {
|
||||
Tile::tiles[tile]->onPlace(level, xOffs, y, zOffs);
|
||||
}
|
||||
|
||||
this->unsaved = true;
|
||||
this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*public*/
|
||||
bool LevelChunk::setTile(int x, int y, int z, int tile_) {
|
||||
|
||||
int tile = tile_ & 0xff;
|
||||
int oldHeight = heightmap[z << 4 | x] & 0xff;
|
||||
|
||||
int old = blocks[x << 11 | z << 7 | y] & 0xff;
|
||||
if (old == tile_) return false;
|
||||
int xOffs = xt + x;
|
||||
int zOffs = zt + z;
|
||||
blocks[x << 11 | z << 7 | y] = (unsigned char) (tile & 0xff);
|
||||
if (old != 0) {
|
||||
Tile::tiles[old]->onRemove(level, xOffs, y, zOffs);
|
||||
}
|
||||
data.set(x, y, z, 0);
|
||||
|
||||
if (Tile::lightBlock[tile & 0xff] != 0) {
|
||||
if (y >= oldHeight) {
|
||||
recalcHeight(x, y + 1, z);
|
||||
}
|
||||
} else {
|
||||
if (y == oldHeight - 1) {
|
||||
recalcHeight(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs);
|
||||
lightGaps(x, z);
|
||||
|
||||
if (tile_ != 0) {
|
||||
if (!level->isClientSide) Tile::tiles[tile_]->onPlace(level, xOffs, y, zOffs);
|
||||
}
|
||||
|
||||
this->unsaved = true;
|
||||
this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift));
|
||||
return true;
|
||||
}
|
||||
|
||||
void LevelChunk::setTileRaw(int x, int y, int z, int tile) {
|
||||
blocks[x << 11 | z << 7 | y] = tile;
|
||||
}
|
||||
|
||||
/*public*/
|
||||
int LevelChunk::getData(int x, int y, int z) {
|
||||
return data.get(x, y, z);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
void LevelChunk::recalcHeightmapOnly() {
|
||||
int min = Level::DEPTH - 1;
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int y = Level::DEPTH - 1;
|
||||
int p = x << 11 | z << 7;
|
||||
while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0)
|
||||
y--;
|
||||
heightmap[z << 4 | x] = (char) y;
|
||||
if (y < min) min = y;
|
||||
}
|
||||
|
||||
this->minHeight = min;
|
||||
//this->unsaved = true;
|
||||
}
|
||||
|
||||
/*public?*/
|
||||
void LevelChunk::recalcHeightmap() {
|
||||
int min = Level::DEPTH - 1;
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int y = Level::DEPTH - 1;
|
||||
int p = x << 11 | z << 7;
|
||||
while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0)
|
||||
y--;
|
||||
heightmap[z << 4 | x] = (char) y;
|
||||
if (y < min) min = y;
|
||||
|
||||
if (!level->dimension->hasCeiling) {
|
||||
int br = Level::MAX_BRIGHTNESS;
|
||||
int yy = Level::DEPTH - 1;
|
||||
do {
|
||||
br -= Tile::lightBlock[blocks[p + yy] & 0xff];
|
||||
if (br > 0) {
|
||||
skyLight.set(x, yy, z, br);
|
||||
}
|
||||
yy--;
|
||||
} while (yy > 0 && br > 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this->minHeight = min;
|
||||
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int z = 0; z < 16; z++) {
|
||||
lightGaps(x, z);
|
||||
}
|
||||
|
||||
//this->unsaved = true;
|
||||
}
|
||||
|
||||
/*private*/
|
||||
void LevelChunk::recalcHeight(int x, int yStart, int z) {
|
||||
int yOld = heightmap[z << 4 | x] & 0xff;
|
||||
int y = yOld;
|
||||
if (yStart > yOld) y = yStart;
|
||||
|
||||
int p = x << 11 | z << 7;
|
||||
while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0)
|
||||
y--;
|
||||
if (y == yOld) return;
|
||||
|
||||
const int xOffs = xt + x;
|
||||
const int zOffs = zt + z;
|
||||
level->lightColumnChanged(xOffs, zOffs, y, yOld);
|
||||
heightmap[z << 4 | x] = (char) y;
|
||||
|
||||
if (y < minHeight) {
|
||||
minHeight = y;
|
||||
} else {
|
||||
int min = Level::DEPTH - 1;
|
||||
for (int _x = 0; _x < 16; _x++)
|
||||
for (int _z = 0; _z < 16; _z++) {
|
||||
if ((heightmap[_z << 4 | _x] & 0xff) < min) min = (heightmap[_z << 4 | _x] & 0xff);
|
||||
}
|
||||
this->minHeight = min;
|
||||
}
|
||||
|
||||
if (y < yOld) {
|
||||
for (int yy = y; yy < yOld; yy++) {
|
||||
skyLight.set(x, yy, z, 15);
|
||||
}
|
||||
} else {
|
||||
level->updateLight(LightLayer::Sky, xOffs, yOld, zOffs, xOffs, y, zOffs);
|
||||
for (int yy = yOld; yy < y; yy++) {
|
||||
skyLight.set(x, yy, z, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int br = 15;
|
||||
int y0 = y;
|
||||
while (y > 0 && br > 0) {
|
||||
y--;
|
||||
int block = Tile::lightBlock[getTile(x, y, z)];
|
||||
if (block == 0) block = 1;
|
||||
br -= block;
|
||||
if (br < 0) br = 0;
|
||||
skyLight.set(x, y, z, br);
|
||||
}
|
||||
while (y > 0 && Tile::lightBlock[getTile(x, y - 1, z)] == 0)
|
||||
y--;
|
||||
if (y != y0) {
|
||||
level->updateLight(LightLayer::Sky, xOffs - 1, y, zOffs - 1, xOffs + 1, y0, zOffs + 1);
|
||||
}
|
||||
|
||||
//this->unsaved = true;
|
||||
}
|
||||
|
||||
/*public*/
|
||||
void LevelChunk::skyBrightnessChanged() {
|
||||
// int x0 = xt;
|
||||
// int y0 = this->minHeight - 16;
|
||||
// int z0 = zt;
|
||||
// int x1 = xt + 16;
|
||||
// int y1 = Level::DEPTH - 1;
|
||||
// int z1 = zt + 16;
|
||||
|
||||
//level->setTilesDirty(x0, y0, z0, x1, y1, z1);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
bool LevelChunk::shouldSave(bool force) {
|
||||
if (dontSave) return false;
|
||||
/*
|
||||
if (force) {
|
||||
if (lastSaveHadEntities && level->getTime() != lastSaveTime) return true;
|
||||
} else {
|
||||
if (lastSaveHadEntities && level->getTime() >= lastSaveTime + 20 * 30) return true;
|
||||
}
|
||||
*/
|
||||
|
||||
return unsaved;
|
||||
}
|
||||
|
||||
/*public*/
|
||||
void LevelChunk::setBlocks(unsigned char* newBlocks, int sub) { //@byte[]
|
||||
LOGI("LevelChunk::setBlocks\n");
|
||||
for (int i = 0; i < 128 * 16 * 4; i++) {
|
||||
blocks[sub * 128 * 16 * 4 + i] = newBlocks[i];
|
||||
}
|
||||
|
||||
for (int x = sub * 4; x < sub * 4 + 4; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
recalcHeight(x, 0, z);
|
||||
}
|
||||
}
|
||||
|
||||
level->updateLight(LightLayer::Sky, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16);
|
||||
level->updateLight(LightLayer::Block, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16);
|
||||
|
||||
//for (int x = sub * 4; x < sub * 4 + 4; x++) {
|
||||
// for (int z = 0; z < 16; z++) {
|
||||
// lightGaps(x, z);
|
||||
// }
|
||||
//}
|
||||
level->setTilesDirty(xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
Random LevelChunk::getRandom(long l) {
|
||||
return /*new*/ Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l);
|
||||
}
|
||||
|
||||
/*private*/
|
||||
void LevelChunk::lightGap( int x, int z, int source )
|
||||
{
|
||||
int height = level->getHeightmap(x, z);
|
||||
if (height > source) {
|
||||
level->updateLight(LightLayer::Sky, x, source, z, x, height, z);
|
||||
} else if (height < source) {
|
||||
level->updateLight(LightLayer::Sky, x, height, z, x, source, z);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::clearUpdateMap()
|
||||
{
|
||||
memset(updateMap, 0x0, 256);
|
||||
unsaved = false;
|
||||
}
|
||||
|
||||
void LevelChunk::deleteBlockData()
|
||||
{
|
||||
delete [] blocks;
|
||||
blocks = NULL;
|
||||
}
|
||||
|
||||
bool LevelChunk::isAt( int x, int z )
|
||||
{
|
||||
return x == this->x && z == this->z;
|
||||
}
|
||||
|
||||
int LevelChunk::getHeightmap( int x, int z )
|
||||
{
|
||||
return heightmap[z << 4 | x] & 0xff;
|
||||
}
|
||||
|
||||
void LevelChunk::recalcBlockLights()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LevelChunk::lightGaps( int x, int z )
|
||||
{
|
||||
int height = getHeightmap(x, z);
|
||||
|
||||
int xOffs = xt + x;
|
||||
int zOffs = zt + z;
|
||||
lightGap(xOffs - 1, zOffs, height);
|
||||
lightGap(xOffs + 1, zOffs, height);
|
||||
lightGap(xOffs, zOffs - 1, height);
|
||||
lightGap(xOffs, zOffs + 1, height);
|
||||
}
|
||||
|
||||
int LevelChunk::getTile( int x, int y, int z )
|
||||
{
|
||||
return blocks[x << 11 | z << 7 | y] & 0xff;
|
||||
}
|
||||
|
||||
void LevelChunk::setData( int x, int y, int z, int val )
|
||||
{
|
||||
//this->unsaved = true;
|
||||
data.set(x, y, z, val);
|
||||
}
|
||||
|
||||
int LevelChunk::getBrightness( const LightLayer& layer, int x, int y, int z )
|
||||
{
|
||||
if (&layer == &LightLayer::Sky) return skyLight.get(x, y, z);
|
||||
else if (&layer == &LightLayer::Block) return blockLight.get(x, y, z);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void LevelChunk::setBrightness( const LightLayer& layer, int x, int y, int z, int brightness )
|
||||
{
|
||||
//this->unsaved = true;
|
||||
if (&layer == &LightLayer::Sky) skyLight.set(x, y, z, brightness);
|
||||
else if (&layer == &LightLayer::Block) blockLight.set(x, y, z, brightness);
|
||||
else return;
|
||||
}
|
||||
|
||||
int LevelChunk::getRawBrightness( int x, int y, int z, int skyDampen )
|
||||
{
|
||||
int light = skyLight.get(x, y, z);
|
||||
if (light > 0) LevelChunk::touchedSky = true;
|
||||
light -= skyDampen;
|
||||
int block = blockLight.get(x, y, z);
|
||||
if (block > light) light = block;
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
void LevelChunk::addEntity( Entity* e )
|
||||
{
|
||||
lastSaveHadEntities = true;
|
||||
|
||||
int xc = Mth::floor(e->x / 16);
|
||||
int zc = Mth::floor(e->z / 16);
|
||||
if (xc != this->x || zc != this->z) {
|
||||
LOGE("ERR: WRONG LOCATION : %d, %d, %d, %d", xc, x, zc, z);
|
||||
//Thread.dumpStack();
|
||||
}
|
||||
int yc = Mth::floor(e->y / 16);
|
||||
if (yc < 0) yc = 0;
|
||||
if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1;
|
||||
e->inChunk = true;
|
||||
e->xChunk = x;
|
||||
e->yChunk = yc;
|
||||
e->zChunk = z;
|
||||
entityBlocks[yc].push_back(e);
|
||||
}
|
||||
|
||||
void LevelChunk::removeEntity( Entity* e )
|
||||
{
|
||||
removeEntity(e, e->yChunk);
|
||||
}
|
||||
|
||||
void LevelChunk::removeEntity( Entity* e, int yc )
|
||||
{
|
||||
if (yc < 0) yc = 0;
|
||||
if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1;
|
||||
|
||||
EntityList::iterator newEnd = std::remove( entityBlocks[yc].begin(), entityBlocks[yc].end(), e);
|
||||
entityBlocks[yc].erase(newEnd, entityBlocks[yc].end());
|
||||
}
|
||||
|
||||
bool LevelChunk::isSkyLit( int x, int y, int z )
|
||||
{
|
||||
return y >= (heightmap[z << 4 | x] & 0xff);
|
||||
}
|
||||
|
||||
void LevelChunk::load()
|
||||
{
|
||||
loaded = true;
|
||||
/* level->tileEntityList.addAll(tileEntities.values());
|
||||
for (int i = 0; i < entityBlocks.length; i++) {
|
||||
level->addEntities(entityBlocks[i]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void LevelChunk::unload()
|
||||
{
|
||||
loaded = false;
|
||||
/* level->tileEntityList.removeAll(tileEntities.values());
|
||||
for (int i = 0; i < entityBlocks.length; i++) {
|
||||
level->removeEntities(entityBlocks[i]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void LevelChunk::markUnsaved()
|
||||
{
|
||||
this->unsaved = true;
|
||||
}
|
||||
|
||||
void LevelChunk::getEntities( Entity* except, const AABB& bb, std::vector<Entity*>& es )
|
||||
{
|
||||
int yc0 = Mth::floor((bb.y0 - 2) / 16);
|
||||
int yc1 = Mth::floor((bb.y1 + 2) / 16);
|
||||
if (yc0 < 0) yc0 = 0;
|
||||
if (yc1 >= EntityBlocksArraySize) yc1 = EntityBlocksArraySize - 1;
|
||||
for (int yc = yc0; yc <= yc1; yc++) {
|
||||
std::vector<Entity*>& entities = entityBlocks[yc];
|
||||
for (unsigned int i = 0; i < entities.size(); i++) {
|
||||
Entity* e = entities[i];
|
||||
if (e != except && e->bb.intersects(bb)){
|
||||
es.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::getEntitiesOfType( int entityType, const AABB& bb, EntityList& list )
|
||||
{
|
||||
int yc0 = Mth::floor((bb.y0 - 2) / 16);
|
||||
int yc1 = Mth::floor((bb.y1 + 2) / 16);
|
||||
if (yc0 < 0) {
|
||||
yc0 = 0;
|
||||
} else if (yc0 >= EntityBlocksArraySize) {
|
||||
yc0 = EntityBlocksArraySize - 1;
|
||||
}
|
||||
if (yc1 >= EntityBlocksArraySize) {
|
||||
yc1 = EntityBlocksArraySize - 1;
|
||||
} else if (yc1 < 0) {
|
||||
yc1 = 0;
|
||||
}
|
||||
for (int yc = yc0; yc <= yc1; yc++) {
|
||||
std::vector<Entity*>& entities = entityBlocks[yc];
|
||||
for (unsigned int i = 0; i < entities.size(); i++) {
|
||||
Entity* e = entities[i];
|
||||
if (e->getEntityTypeId() == entityType)
|
||||
list.push_back(e);
|
||||
//if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::getEntitiesOfClass( int type, const AABB& bb, EntityList& list )
|
||||
{
|
||||
int yc0 = Mth::floor((bb.y0 - 2) / 16);
|
||||
int yc1 = Mth::floor((bb.y1 + 2) / 16);
|
||||
if (yc0 < 0) {
|
||||
yc0 = 0;
|
||||
} else if (yc0 >= EntityBlocksArraySize) {
|
||||
yc0 = EntityBlocksArraySize - 1;
|
||||
}
|
||||
if (yc1 >= EntityBlocksArraySize) {
|
||||
yc1 = EntityBlocksArraySize - 1;
|
||||
} else if (yc1 < 0) {
|
||||
yc1 = 0;
|
||||
}
|
||||
for (int yc = yc0; yc <= yc1; yc++) {
|
||||
std::vector<Entity*>& entities = entityBlocks[yc];
|
||||
for (unsigned int i = 0; i < entities.size(); i++) {
|
||||
Entity* e = entities[i];
|
||||
if (e->getCreatureBaseType() == type)
|
||||
list.push_back(e);
|
||||
//if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int LevelChunk::countEntities()
|
||||
{
|
||||
int entityCount = 0;
|
||||
for (int yc = 0; yc < EntityBlocksArraySize; yc++) {
|
||||
entityCount += entityBlocks[yc].size();
|
||||
}
|
||||
return entityCount;
|
||||
}
|
||||
|
||||
//@note: @todo @te Verify
|
||||
TileEntity* LevelChunk::getTileEntity(int x, int y, int z) {
|
||||
TilePos pos(x, y, z);
|
||||
TEMap::iterator cit = tileEntities.find(pos);
|
||||
TileEntity* tileEntity = NULL;
|
||||
//bool ex = cit != tileEntities.end();
|
||||
//LOGI("Getting tile entity @ %d, %d, %d. Already existing? %d (%p)\n", x, y, z, ex, ex?cit->second:0);
|
||||
if (cit == tileEntities.end())
|
||||
{
|
||||
int t = getTile(x, y, z);
|
||||
if (t <= 0 || !Tile::isEntityTile[t])
|
||||
return NULL;
|
||||
|
||||
if (tileEntity == NULL) {
|
||||
tileEntity = ((EntityTile*) Tile::tiles[t])->newTileEntity();
|
||||
level->setTileEntity(xt + x, y, zt + z, tileEntity);
|
||||
}
|
||||
// @attn @bug @fix: Don't go via level->setTileEntity since we
|
||||
// know this tile is loaded if we are here
|
||||
//cit = tileEntities.find(pos);
|
||||
//tileEntity = (cit != tileEntities.end())? cit->second : NULL;
|
||||
}
|
||||
else {
|
||||
tileEntity = cit->second;
|
||||
}
|
||||
if (tileEntity != NULL && tileEntity->isRemoved()) {
|
||||
tileEntities.erase(cit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tileEntity;
|
||||
}
|
||||
|
||||
bool LevelChunk::hasTileEntityAt( int x, int y, int z )
|
||||
{
|
||||
return tileEntities.find(TilePos(x, y, z)) != tileEntities.end();
|
||||
}
|
||||
bool LevelChunk::hasTileEntityAt( TileEntity* te )
|
||||
{
|
||||
return tileEntities.find(TilePos(te->x & 15, te->y, te->z & 15)) != tileEntities.end();
|
||||
}
|
||||
|
||||
void LevelChunk::addTileEntity(TileEntity* te) {
|
||||
|
||||
int xx = te->x - xt;
|
||||
int yy = te->y;
|
||||
int zz = te->z - zt;
|
||||
setTileEntity(xx, yy, zz, te);
|
||||
if (loaded) {
|
||||
level->tileEntities.push_back(te);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelChunk::setTileEntity(int x, int y, int z, TileEntity* tileEntity)
|
||||
{
|
||||
tileEntity->setLevelAndPos(level, xt + x, y, zt + z);
|
||||
int t = getTile(x, y, z);
|
||||
if (t == 0 || !Tile::isEntityTile[t]) {
|
||||
LOGW("Attempted to place a tile entity where there was no entity tile! %d, %d, %d\n",
|
||||
tileEntity->x, tileEntity->y, tileEntity->z);
|
||||
return;
|
||||
}
|
||||
|
||||
tileEntity->clearRemoved();
|
||||
tileEntities.insert(std::make_pair(TilePos(x, y, z), tileEntity));
|
||||
}
|
||||
|
||||
void LevelChunk::removeTileEntity(int x, int y, int z) {
|
||||
if (loaded) {
|
||||
TilePos pos(x, y, z);
|
||||
TEMap::iterator cit = tileEntities.find(pos);
|
||||
if (cit != tileEntities.end()) {
|
||||
cit->second->setRemoved();
|
||||
|
||||
if (!level->isClientSide) {
|
||||
for (unsigned int i = 0; i < level->players.size(); ++i) {
|
||||
level->players[i]->tileEntityDestroyed(cit->second->runningId);
|
||||
}
|
||||
}
|
||||
tileEntities.erase(cit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LevelChunk::getBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p )
|
||||
{
|
||||
int len = y1 - y0;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = x << 11 | z << 7 | y0;
|
||||
memcpy(data + p, blocks + slot, len); //System.arraycopy(blocks, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(data + p, this->data.data + slot, len); //System.arraycopy(this->data.data, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(data + p, blockLight.data + slot, len); //System.arraycopy(blockLight.data, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(data + p, skyLight.data + slot, len); //System.arraycopy(skyLight.data, slot, data, p, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int LevelChunk::setBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p )
|
||||
{
|
||||
int len = y1 - y0;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = x << 11 | z << 7 | y0;
|
||||
memcpy(blocks + slot, data + p, len); //System.arraycopy(data, p, blocks, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
recalcHeightmapOnly();
|
||||
|
||||
len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(this->data.data + slot, data + p, len); //System.arraycopy(data, p, this->data.data, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(blockLight.data + slot, data + p, len); //System.arraycopy(data, p, blockLight.data, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
//len = (y1 - y0) / 2;
|
||||
for (int x = x0; x < x1; x++)
|
||||
for (int z = z0; z < z1; z++) {
|
||||
int slot = (x << 11 | z << 7 | y0) >> 1;
|
||||
memcpy(skyLight.data + slot, data + p, len); //System.arraycopy(data, p, skyLight.data, slot, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
bool LevelChunk::isEmpty()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const LevelChunk::TEMap& LevelChunk::getTileEntityMap() const {
|
||||
return tileEntities;
|
||||
}
|
||||
142
src/world/level/chunk/LevelChunk.h
Executable file
142
src/world/level/chunk/LevelChunk.h
Executable file
@@ -0,0 +1,142 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK__LevelChunk_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK__LevelChunk_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk;
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "DataLayer.h"
|
||||
#include "../LevelConstants.h"
|
||||
#include "../../../util/Random.h"
|
||||
#include "../TilePos.h"
|
||||
|
||||
class Level;
|
||||
class Entity;
|
||||
class LightLayer;
|
||||
class AABB;
|
||||
class TileEntity;
|
||||
typedef std::vector<Entity*> EntityList;
|
||||
|
||||
class LevelChunk
|
||||
{
|
||||
public:
|
||||
typedef std::map<TilePos, TileEntity*> TEMap;
|
||||
typedef TEMap::const_iterator TEMapCIterator;
|
||||
|
||||
LevelChunk(Level* level, int x, int z);
|
||||
LevelChunk(Level* level, unsigned char* blocks, int x, int z);
|
||||
virtual ~LevelChunk();
|
||||
|
||||
void init(); // @todo virtual?;
|
||||
|
||||
// Clears the update map. This should be called when the chunk is
|
||||
// identical to the data generated by the level generator. It is
|
||||
// used to identify which parts of the chunk to transfer in multiplayer.
|
||||
void clearUpdateMap();
|
||||
|
||||
void deleteBlockData();
|
||||
|
||||
virtual bool isAt(int x, int z);
|
||||
|
||||
virtual int getHeightmap(int x, int z);
|
||||
|
||||
virtual void recalcHeightmap();
|
||||
virtual void recalcHeightmapOnly();
|
||||
|
||||
unsigned char* getBlockData() { return blocks; }
|
||||
|
||||
virtual int getBrightness(const LightLayer& layer, int x, int y, int z);
|
||||
virtual void setBrightness(const LightLayer& layer, int x, int y, int z, int brightness);
|
||||
virtual int getRawBrightness(int x, int y, int z, int skyDampen);
|
||||
|
||||
virtual void addEntity(Entity* e);
|
||||
virtual void removeEntity(Entity* e);
|
||||
virtual void removeEntity(Entity* e, int yc);
|
||||
|
||||
virtual void getEntitiesOfClass( int type, const AABB& bb, EntityList& list );
|
||||
virtual void getEntitiesOfType(int entityType, const AABB& bb, EntityList& list);
|
||||
|
||||
//
|
||||
// TileEntity
|
||||
//
|
||||
TileEntity* getTileEntity(int x, int y, int z);
|
||||
//bool hasOtherTileEntity(int x, int y, int z, TileEntity* e);
|
||||
bool hasTileEntityAt(int x, int y, int z);
|
||||
bool hasTileEntityAt(TileEntity* te);
|
||||
void addTileEntity(TileEntity* te);
|
||||
void setTileEntity(int x, int y, int z, TileEntity* tileEntity);
|
||||
void removeTileEntity(int x, int y, int z);
|
||||
|
||||
virtual bool isSkyLit(int x, int y, int z);
|
||||
virtual void lightLava() {}
|
||||
virtual void recalcBlockLights();
|
||||
virtual void skyBrightnessChanged();
|
||||
|
||||
virtual void load();
|
||||
virtual void unload();
|
||||
|
||||
virtual bool shouldSave(bool force);
|
||||
virtual void markUnsaved();
|
||||
|
||||
virtual int countEntities();
|
||||
virtual void getEntities(Entity* except, const AABB& bb, std::vector<Entity*>& es);
|
||||
|
||||
virtual int getTile(int x, int y, int z);
|
||||
virtual bool setTile(int x, int y, int z, int tile_);
|
||||
void setTileRaw(int x, int y, int z, int tile);
|
||||
virtual bool setTileAndData(int x, int y, int z, int tile_, int data_);
|
||||
|
||||
virtual int getData(int x, int y, int z);
|
||||
virtual void setData(int x, int y, int z, int val);
|
||||
|
||||
virtual void setBlocks(unsigned char* newBlocks, int sub);
|
||||
|
||||
virtual int getBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p);
|
||||
virtual int setBlocksAndData(unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p);
|
||||
|
||||
virtual Random getRandom(long l);
|
||||
|
||||
virtual bool isEmpty();
|
||||
const TEMap& getTileEntityMap() const;
|
||||
private:
|
||||
void lightGap(int x, int z, int source);
|
||||
void lightGaps(int x, int z);
|
||||
|
||||
void recalcHeight(int x, int yStart, int z);
|
||||
public:
|
||||
static bool touchedSky;
|
||||
static const int ChunkBlockCount = CHUNK_BLOCK_COUNT;
|
||||
static const int ChunkSize = ChunkBlockCount;
|
||||
static const int UpdateMapBitShift = 4; // power of (LEVEL_HEIGHT / 8) == 16
|
||||
|
||||
int blocksLength; // ? needed or not? (i.e. are all chunks the same size?)
|
||||
|
||||
bool loaded;
|
||||
Level* level;
|
||||
DataLayer data;
|
||||
DataLayer skyLight;
|
||||
DataLayer blockLight;
|
||||
|
||||
char heightmap[CHUNK_COLUMNS];
|
||||
unsigned char updateMap[CHUNK_COLUMNS]; // marks regions within block columns that have been modified
|
||||
int minHeight;
|
||||
|
||||
const int x, z;
|
||||
const int xt, zt;
|
||||
|
||||
bool terrainPopulated;
|
||||
bool unsaved;
|
||||
bool dontSave;
|
||||
bool createdFromSave;
|
||||
bool lastSaveHadEntities;
|
||||
long lastSaveTime;
|
||||
protected:
|
||||
unsigned char* blocks;
|
||||
|
||||
static const int EntityBlocksArraySize = 128/16;
|
||||
std::vector<Entity*> entityBlocks[EntityBlocksArraySize];
|
||||
|
||||
TEMap tileEntities;
|
||||
};
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK__LevelChunk_H__*/
|
||||
30
src/world/level/chunk/storage/ChunkStorage.h
Executable file
30
src/world/level/chunk/storage/ChunkStorage.h
Executable file
@@ -0,0 +1,30 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__ChunkStorage_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__ChunkStorage_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk.storage;
|
||||
|
||||
class Level;
|
||||
class LevelChunk;
|
||||
|
||||
/**@todo: load, save* threw exceptions - I think we need to substitute
|
||||
it for something else since it hasn't very good support on
|
||||
all embedded devices */
|
||||
|
||||
/*was-interface*/
|
||||
class ChunkStorage {
|
||||
public:
|
||||
virtual ~ChunkStorage() {}
|
||||
virtual LevelChunk* load(Level* level, int x, int z) {
|
||||
return NULL;
|
||||
}
|
||||
virtual void save(Level* level, LevelChunk* levelChunk) {}
|
||||
virtual void saveEntities(Level* level, LevelChunk* levelChunk) {}
|
||||
virtual void saveAll(Level* level, std::vector<LevelChunk*>& levelChunks) {
|
||||
for (unsigned int i = 0; i < levelChunks.size(); ++i) save(level, levelChunks[i]);
|
||||
}
|
||||
|
||||
virtual void tick() {}
|
||||
virtual void flush() {}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__ChunkStorage_H__*/
|
||||
10
src/world/level/chunk/storage/MemoryChunkStorage.h
Executable file
10
src/world/level/chunk/storage/MemoryChunkStorage.h
Executable file
@@ -0,0 +1,10 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__MemoryChunkStorage_H__
|
||||
#define NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__MemoryChunkStorage_H__
|
||||
|
||||
//package net.minecraft.world.level.chunk.storage;
|
||||
|
||||
#include "ChunkStorage.h"
|
||||
|
||||
class MemoryChunkStorage: public ChunkStorage {};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_LEVEL_CHUNK_STORAGE__MemoryChunkStorage_H__*/
|
||||
140
src/world/level/dimension/Dimension.cpp
Executable file
140
src/world/level/dimension/Dimension.cpp
Executable 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);
|
||||
}
|
||||
64
src/world/level/dimension/Dimension.h
Executable file
64
src/world/level/dimension/Dimension.h
Executable 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__*/
|
||||
41
src/world/level/dimension/NormalDayCycleDimension.h
Executable file
41
src/world/level/dimension/NormalDayCycleDimension.h
Executable 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__*/
|
||||
168
src/world/level/levelgen/CanyonFeature.cpp
Executable file
168
src/world/level/levelgen/CanyonFeature.cpp
Executable 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
|
||||
19
src/world/level/levelgen/CanyonFeature.h
Executable file
19
src/world/level/levelgen/CanyonFeature.h
Executable 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__*/
|
||||
176
src/world/level/levelgen/DungeonFeature.cpp
Executable file
176
src/world/level/levelgen/DungeonFeature.cpp
Executable 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
|
||||
23
src/world/level/levelgen/DungeonFeature.h
Executable file
23
src/world/level/levelgen/DungeonFeature.h
Executable 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__*/
|
||||
0
src/world/level/levelgen/LargeCaveFeature.cpp
Executable file
0
src/world/level/levelgen/LargeCaveFeature.cpp
Executable file
180
src/world/level/levelgen/LargeCaveFeature.h
Executable file
180
src/world/level/levelgen/LargeCaveFeature.h
Executable 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__*/
|
||||
27
src/world/level/levelgen/LargeFeature.cpp
Executable file
27
src/world/level/levelgen/LargeFeature.cpp
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
src/world/level/levelgen/LargeFeature.h
Executable file
27
src/world/level/levelgen/LargeFeature.h
Executable 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__*/
|
||||
723
src/world/level/levelgen/RandomLevelSource.cpp
Executable file
723
src/world/level/levelgen/RandomLevelSource.cpp
Executable 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;
|
||||
}
|
||||
125
src/world/level/levelgen/RandomLevelSource.h
Executable file
125
src/world/level/levelgen/RandomLevelSource.h
Executable 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__*/
|
||||
13
src/world/level/levelgen/TownFeature.h
Executable file
13
src/world/level/levelgen/TownFeature.h
Executable 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__*/
|
||||
75
src/world/level/levelgen/feature/BirchFeature.h
Executable file
75
src/world/level/levelgen/feature/BirchFeature.h
Executable 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__*/
|
||||
35
src/world/level/levelgen/feature/CactusFeature.h
Executable file
35
src/world/level/levelgen/feature/CactusFeature.h
Executable 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__*/
|
||||
63
src/world/level/levelgen/feature/ClayFeature.h
Executable file
63
src/world/level/levelgen/feature/ClayFeature.h
Executable 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__*/
|
||||
26
src/world/level/levelgen/feature/Feature.cpp
Executable file
26
src/world/level/levelgen/feature/Feature.cpp
Executable 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);
|
||||
}
|
||||
}
|
||||
23
src/world/level/levelgen/feature/Feature.h
Executable file
23
src/world/level/levelgen/feature/Feature.h
Executable 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__*/
|
||||
14
src/world/level/levelgen/feature/FeatureInclude.h
Executable file
14
src/world/level/levelgen/feature/FeatureInclude.h
Executable 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__*/
|
||||
35
src/world/level/levelgen/feature/FlowerFeature.h
Executable file
35
src/world/level/levelgen/feature/FlowerFeature.h
Executable 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__*/
|
||||
127
src/world/level/levelgen/feature/LakeFeature.h
Executable file
127
src/world/level/levelgen/feature/LakeFeature.h
Executable 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__*/
|
||||
77
src/world/level/levelgen/feature/OreFeature.h
Executable file
77
src/world/level/levelgen/feature/OreFeature.h
Executable 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__*/
|
||||
92
src/world/level/levelgen/feature/PineFeature.h
Executable file
92
src/world/level/levelgen/feature/PineFeature.h
Executable 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__*/
|
||||
40
src/world/level/levelgen/feature/ReedsFeature.h
Executable file
40
src/world/level/levelgen/feature/ReedsFeature.h
Executable 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__*/
|
||||
50
src/world/level/levelgen/feature/SpringFeature.h
Executable file
50
src/world/level/levelgen/feature/SpringFeature.h
Executable 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__*/
|
||||
101
src/world/level/levelgen/feature/SpruceFeature.h
Executable file
101
src/world/level/levelgen/feature/SpruceFeature.h
Executable 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__*/
|
||||
40
src/world/level/levelgen/feature/TallgrassFeature.h
Executable file
40
src/world/level/levelgen/feature/TallgrassFeature.h
Executable 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__*/
|
||||
74
src/world/level/levelgen/feature/TreeFeature.h
Executable file
74
src/world/level/levelgen/feature/TreeFeature.h
Executable 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__*/
|
||||
205
src/world/level/levelgen/synth/ImprovedNoise.cpp
Executable file
205
src/world/level/levelgen/synth/ImprovedNoise.cpp
Executable 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;
|
||||
}
|
||||
|
||||
38
src/world/level/levelgen/synth/ImprovedNoise.h
Executable file
38
src/world/level/levelgen/synth/ImprovedNoise.h
Executable 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__*/
|
||||
88
src/world/level/levelgen/synth/PerlinNoise.cpp
Executable file
88
src/world/level/levelgen/synth/PerlinNoise.cpp
Executable 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;
|
||||
}
|
||||
|
||||
37
src/world/level/levelgen/synth/PerlinNoise.h
Executable file
37
src/world/level/levelgen/synth/PerlinNoise.h
Executable 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__*/
|
||||
21
src/world/level/levelgen/synth/Synth.cpp
Executable file
21
src/world/level/levelgen/synth/Synth.cpp
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
src/world/level/levelgen/synth/Synth.h
Executable file
18
src/world/level/levelgen/synth/Synth.h
Executable 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__*/
|
||||
23
src/world/level/material/DecorationMaterial.h
Executable file
23
src/world/level/material/DecorationMaterial.h
Executable 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__*/
|
||||
27
src/world/level/material/GasMaterial.h
Executable file
27
src/world/level/material/GasMaterial.h
Executable 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__*/
|
||||
27
src/world/level/material/LiquidMaterial.h
Executable file
27
src/world/level/material/LiquidMaterial.h
Executable 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__*/
|
||||
99
src/world/level/material/Material.cpp
Executable file
99
src/world/level/material/Material.cpp
Executable 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);
|
||||
}
|
||||
116
src/world/level/material/Material.h
Executable file
116
src/world/level/material/Material.h
Executable 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__*/
|
||||
19
src/world/level/material/WebMaterial.h
Executable file
19
src/world/level/material/WebMaterial.h
Executable 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__*/
|
||||
201
src/world/level/pathfinder/BinaryHeap.h
Executable file
201
src/world/level/pathfinder/BinaryHeap.h
Executable 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__*/
|
||||
79
src/world/level/pathfinder/Node.h
Executable file
79
src/world/level/pathfinder/Node.h
Executable 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__*/
|
||||
134
src/world/level/pathfinder/Path.cpp
Executable file
134
src/world/level/pathfinder/Path.cpp
Executable 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);
|
||||
}
|
||||
53
src/world/level/pathfinder/Path.h
Executable file
53
src/world/level/pathfinder/Path.h
Executable 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__*/
|
||||
394
src/world/level/pathfinder/PathFinder.h
Executable file
394
src/world/level/pathfinder/PathFinder.h
Executable 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__*/
|
||||
632
src/world/level/storage/ExternalFileLevelStorage.cpp
Executable file
632
src/world/level/storage/ExternalFileLevelStorage.cpp
Executable 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*/
|
||||
88
src/world/level/storage/ExternalFileLevelStorage.h
Executable file
88
src/world/level/storage/ExternalFileLevelStorage.h
Executable 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*/
|
||||
193
src/world/level/storage/ExternalFileLevelStorageSource.cpp
Executable file
193
src/world/level/storage/ExternalFileLevelStorageSource.cpp
Executable 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*/
|
||||
45
src/world/level/storage/ExternalFileLevelStorageSource.h
Executable file
45
src/world/level/storage/ExternalFileLevelStorageSource.h
Executable 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*/
|
||||
77
src/world/level/storage/FolderMethods.cpp
Executable file
77
src/world/level/storage/FolderMethods.cpp
Executable 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;
|
||||
}
|
||||
22
src/world/level/storage/FolderMethods.h
Executable file
22
src/world/level/storage/FolderMethods.h
Executable 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
|
||||
364
src/world/level/storage/LevelData.cpp
Executable file
364
src/world/level/storage/LevelData.cpp
Executable 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;
|
||||
}
|
||||
97
src/world/level/storage/LevelData.h
Executable file
97
src/world/level/storage/LevelData.h
Executable 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__*/
|
||||
39
src/world/level/storage/LevelStorage.h
Executable file
39
src/world/level/storage/LevelStorage.h
Executable 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__*/
|
||||
3
src/world/level/storage/LevelStorageSource.cpp
Executable file
3
src/world/level/storage/LevelStorageSource.cpp
Executable file
@@ -0,0 +1,3 @@
|
||||
#include "LevelStorageSource.h"
|
||||
|
||||
const std::string LevelStorageSource::TempLevelId = "_LastJoinedServer";
|
||||
60
src/world/level/storage/LevelStorageSource.h
Executable file
60
src/world/level/storage/LevelStorageSource.h
Executable 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__*/
|
||||
53
src/world/level/storage/MemoryLevelStorage.h
Executable file
53
src/world/level/storage/MemoryLevelStorage.h
Executable 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__*/
|
||||
58
src/world/level/storage/MemoryLevelStorageSource.h
Executable file
58
src/world/level/storage/MemoryLevelStorageSource.h
Executable 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__*/
|
||||
8
src/world/level/storage/MoveFolder.h
Executable file
8
src/world/level/storage/MoveFolder.h
Executable 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__*/
|
||||
11
src/world/level/storage/MoveFolder.mm
Executable file
11
src/world/level/storage/MoveFolder.mm
Executable 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
Reference in New Issue
Block a user