#ifndef NET_MINECRAFT_WORLD_LEVEL_TILE__LeafTile_H__ #define NET_MINECRAFT_WORLD_LEVEL_TILE__LeafTile_H__ //package net.minecraft.world.level.tile; #include "TransparentTile.h" #include "../Level.h" #include "../material/Material.h" #include "../../item/Item.h" #include "../../item/ItemInstance.h" #include "../FoliageColor.h" #include "../LevelSource.h" #include "../biome/BiomeSource.h" class Entity; class LeafTile: public TransparentTile { typedef TransparentTile super; public: static const int LEAF_TYPE_MASK = 3; static const int REQUIRED_WOOD_RANGE = 4; //@attn @note: PERSISTENT_LEAF_BIT and UPDATE_LEAF_BIT are reversed // here, compared to desktop version static const int PERSISTENT_LEAF_BIT = 8; // player-placed static const int UPDATE_LEAF_BIT = 4; static const int NORMAL_LEAF = 0; static const int EVERGREEN_LEAF = 1; static const int BIRCH_LEAF = 2; LeafTile(int id, int tex) : super(id, tex, Material::leaves, false), oTex(tex), checkBuffer(NULL) { setTicking(true); } ~LeafTile() { if (checkBuffer != NULL) delete[] checkBuffer; } int getRenderLayer() { return isSolidRender()? Tile::RENDERLAYER_OPAQUE : Tile::RENDERLAYER_ALPHATEST; } int getColor(LevelSource* level, int x, int y, int z) { int data = (level->getData(x, y, z) & LEAF_TYPE_MASK); if (data == EVERGREEN_LEAF) { return FoliageColor::getEvergreenColor(); } if (data == BIRCH_LEAF) { return FoliageColor::getBirchColor(); } if (!FoliageColor::useTint){ return FoliageColor::getDefaultColor(); } // return FoliageColor::getDefaultColor(); we need to hook this up with OPTION_FOLIAGE_TINT level->getBiomeSource()->getBiomeBlock(x, z, 1, 1); float temperature = level->getBiomeSource()->temperatures[0]; float rainfall = level->getBiomeSource()->downfalls[0]; return FoliageColor::get(temperature, rainfall); } void onRemove(Level* level, int x, int y, int z) { int r = 1; int r2 = r + 1; if (level->hasChunksAt(x - r2, y - r2, z - r2, x + r2, y + r2, z + r2)) { for (int xo = -r; xo <= r; xo++) for (int yo = -r; yo <= r; yo++) for (int zo = -r; zo <= r; zo++) { int t = level->getTile(x + xo, y + yo, z + zo); if (t == Tile::leaves->id) { int currentData = level->getData(x + xo, y + yo, z + zo); level->setDataNoUpdate(x + xo, y + yo, z + zo, currentData | UPDATE_LEAF_BIT); } } } } int* checkBuffer; //@todo Rewrite this? void tick(Level* level, int x, int y, int z, Random* random) { if (level->isClientSide) return; int currentData = level->getData(x, y, z); if ((currentData & UPDATE_LEAF_BIT) != 0 && (currentData & PERSISTENT_LEAF_BIT) == 0) { const int r = LeafTile::REQUIRED_WOOD_RANGE; int r2 = r + 1; const int W = 32; const int WW = W * W; const int WO = W / 2; if (!checkBuffer) { checkBuffer = new int[W * W * W]; } if (level->hasChunksAt(x - r2, y - r2, z - r2, x + r2, y + r2, z + r2)) { for (int xo = -r; xo <= r; xo++) for (int yo = -r; yo <= r; yo++) for (int zo = -r; zo <= r; zo++) { int t = level->getTile(x + xo, y + yo, z + zo); if (t == Tile::treeTrunk->id) { checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = 0; } else if (t == Tile::leaves->id) { checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = -2; } else { checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = -1; } } for (int i = 1; i <= LeafTile::REQUIRED_WOOD_RANGE; i++) { for (int xo = -r; xo <= r; xo++) for (int yo = -r; yo <= r; yo++) for (int zo = -r; zo <= r; zo++) { if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] == i - 1) { if (checkBuffer[(xo + WO - 1) * WW + (yo + WO) * W + (zo + WO)] == -2) { checkBuffer[(xo + WO - 1) * WW + (yo + WO) * W + (zo + WO)] = i; } if (checkBuffer[(xo + WO + 1) * WW + (yo + WO) * W + (zo + WO)] == -2) { checkBuffer[(xo + WO + 1) * WW + (yo + WO) * W + (zo + WO)] = i; } if (checkBuffer[(xo + WO) * WW + (yo + WO - 1) * W + (zo + WO)] == -2) { checkBuffer[(xo + WO) * WW + (yo + WO - 1) * W + (zo + WO)] = i; } if (checkBuffer[(xo + WO) * WW + (yo + WO + 1) * W + (zo + WO)] == -2) { checkBuffer[(xo + WO) * WW + (yo + WO + 1) * W + (zo + WO)] = i; } if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO - 1)] == -2) { checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO - 1)] = i; } if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO + 1)] == -2) { checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO + 1)] = i; } } } } } int mid = checkBuffer[(WO) * WW + (WO) * W + (WO)]; if (mid >= 0) { level->setDataNoUpdate(x, y, z, currentData & ~UPDATE_LEAF_BIT); } else { die(level, x, y, z); } } } void playerDestroy(Level* level, Player* player, int x, int y, int z, int data) { if (!level->isClientSide) { ItemInstance* item = player->inventory->getSelected(); if (item && item->id == ((Item*)Item::shears)->id) { // drop leaf block instead of sapling popResource(level, x, y, z, ItemInstance(Tile::leaves->id, 1, data & LEAF_TYPE_MASK)); return; } } super::playerDestroy(level, player, x, y, z, data); } int getResourceCount(Random* random) { return random->nextInt(20) == 0 ? 1 : 0; } int getResource(int data, Random* random) { return Tile::sapling->id; } void spawnResources(Level* level, int x, int y, int z, int data, float odds) { if (!level->isClientSide) { int chance = 20; if (level->random.nextInt(chance) == 0) { int type = getResource(data, &level->random); popResource(level, x, y, z, ItemInstance(type, 1, getSpawnResourcesAuxValue(data))); } if ((data & LEAF_TYPE_MASK) == NORMAL_LEAF && level->random.nextInt(200) == 0) { popResource(level, x, y, z, ItemInstance(Item::apple, 1, 0)); } } } bool isSolidRender() { return !allowSame; } int getTexture(int face, int data) { if ((data & LEAF_TYPE_MASK) == EVERGREEN_LEAF) { return (this == Tile::leaves)? tex + 5 * 16 : tex - 16; } return tex; } void setFancy(bool fancyGraphics) { allowSame = fancyGraphics; tex = oTex + (fancyGraphics ? 0 : 1); } protected: int getSpawnResourcesAuxValue(int data) { return data & LEAF_TYPE_MASK; } private: void die(Level* level, int x, int y, int z) { spawnResources(level, x, y, z, level->getData(x, y, z) & LEAF_TYPE_MASK, 0); level->setTile(x, y, z, 0); } int oTex; }; #endif /*NET_MINECRAFT_WORLD_LEVEL_TILE__LeafTile_H__*/