diff --git a/Minecraft.World/Level/BaseMobSpawner.cpp b/Minecraft.World/Level/BaseMobSpawner.cpp new file mode 100644 index 000000000..522290eec --- /dev/null +++ b/Minecraft.World/Level/BaseMobSpawner.cpp @@ -0,0 +1,362 @@ +#include "../Platform/stdafx.h" +#include "../Headers/net.minecraft.world.entity.h" +#include "../Headers/net.minecraft.world.entity.item.h" +#include "../Headers/net.minecraft.world.level.h" +#include "../Headers/net.minecraft.world.level.tile.h" +#include "../Headers/net.minecraft.world.phys.h" +#include "BaseMobSpawner.h" + +BaseMobSpawner::BaseMobSpawner() { + spawnPotentials = NULL; + spawnDelay = 20; + entityId = L"Pig"; + nextSpawnData = NULL; + spin = oSpin = 0.0; + + minSpawnDelay = SharedConstants::TICKS_PER_SECOND * 10; + maxSpawnDelay = SharedConstants::TICKS_PER_SECOND * 40; + spawnCount = 4; + displayEntity = nullptr; + maxNearbyEntities = 6; + requiredPlayerRange = 16; + spawnRange = 4; +} + +BaseMobSpawner::~BaseMobSpawner() { + if (spawnPotentials) { + for (AUTO_VAR(it, spawnPotentials->begin()); + it != spawnPotentials->end(); ++it) { + delete *it; + } + delete spawnPotentials; + } +} + +std::wstring BaseMobSpawner::getEntityId() { + if (getNextSpawnData() == NULL) { + if (entityId.compare(L"Minecart") == 0) { + entityId = L"MinecartRideable"; + } + return entityId; + } else { + return getNextSpawnData()->type; + } +} + +void BaseMobSpawner::setEntityId(const std::wstring& entityId) { + this->entityId = entityId; +} + +bool BaseMobSpawner::isNearPlayer() { + return getLevel()->getNearestPlayer(getX() + 0.5, getY() + 0.5, + getZ() + 0.5, + requiredPlayerRange) != NULL; +} + +void BaseMobSpawner::tick() { + if (!isNearPlayer()) { + return; + } + + if (getLevel()->isClientSide) { + double xP = getX() + getLevel()->random->nextFloat(); + double yP = getY() + getLevel()->random->nextFloat(); + double zP = getZ() + getLevel()->random->nextFloat(); + getLevel()->addParticle(eParticleType_smoke, xP, yP, zP, 0, 0, 0); + getLevel()->addParticle(eParticleType_flame, xP, yP, zP, 0, 0, 0); + + if (spawnDelay > 0) spawnDelay--; + oSpin = spin; + spin = (int)(spin + 1000 / (spawnDelay + 200.0f)) % 360; + } else { + if (spawnDelay == -1) delay(); + + if (spawnDelay > 0) { + spawnDelay--; + return; + } + + bool _delay = false; + + for (int c = 0; c < spawnCount; c++) { + std::shared_ptr entity = + EntityIO::newEntity(getEntityId(), getLevel()); + if (entity == NULL) return; + + int nearBy = + getLevel() + ->getEntitiesOfClass( + typeid(entity.get()), + AABB::newTemp(getX(), getY(), getZ(), getX() + 1, + getY() + 1, getZ() + 1) + ->grow(spawnRange * 2, 4, spawnRange * 2)) + ->size(); + if (nearBy >= maxNearbyEntities) { + delay(); + return; + } + + double xp = getX() + (getLevel()->random->nextDouble() - + getLevel()->random->nextDouble()) * + spawnRange; + double yp = getY() + getLevel()->random->nextInt(3) - 1; + double zp = getZ() + (getLevel()->random->nextDouble() - + getLevel()->random->nextDouble()) * + spawnRange; + std::shared_ptr mob = + entity->instanceof(eTYPE_MOB) + ? std::dynamic_pointer_cast(entity) + : nullptr; + + entity->moveTo(xp, yp, zp, getLevel()->random->nextFloat() * 360, + 0); + + if (mob == NULL || mob->canSpawn()) { + loadDataAndAddEntity(entity); + getLevel()->levelEvent(LevelEvent::PARTICLES_MOBTILE_SPAWN, + getX(), getY(), getZ(), 0); + + if (mob != NULL) { + mob->spawnAnim(); + } + + _delay = true; + } + } + + if (_delay) delay(); + } +} + +std::shared_ptr BaseMobSpawner::loadDataAndAddEntity( + std::shared_ptr entity) { + if (getNextSpawnData() != NULL) { + CompoundTag* data = new CompoundTag(); + entity->save(data); + + std::vector* tags = getNextSpawnData()->tag->getAllTags(); + for (AUTO_VAR(it, tags->begin()); it != tags->end(); ++it) { + Tag* tag = *it; + data->put(tag->getName(), tag->copy()); + } + delete tags; + + entity->load(data); + if (entity->level != NULL) entity->level->addEntity(entity); + + // add mounts + std::shared_ptr rider = entity; + while (data->contains(Entity::RIDING_TAG)) { + CompoundTag* ridingTag = data->getCompound(Entity::RIDING_TAG); + std::shared_ptr mount = + EntityIO::newEntity(ridingTag->getString(L"id"), entity->level); + if (mount != NULL) { + CompoundTag* mountData = new CompoundTag(); + mount->save(mountData); + + std::vector* ridingTags = ridingTag->getAllTags(); + for (AUTO_VAR(it, ridingTags->begin()); it != ridingTags->end(); + ++it) { + Tag* tag = *it; + mountData->put(tag->getName(), tag->copy()); + } + delete ridingTags; + mount->load(mountData); + mount->moveTo(rider->x, rider->y, rider->z, rider->yRot, + rider->xRot); + + if (entity->level != NULL) entity->level->addEntity(mount); + rider->ride(mount); + } + rider = mount; + data = ridingTag; + } + + } else if (entity->instanceof(eTYPE_LIVINGENTITY) && + entity->level != NULL) { + std::dynamic_pointer_cast(entity)->finalizeMobSpawn(NULL); + getLevel()->addEntity(entity); + } + + return entity; +} + +void BaseMobSpawner::delay() { + if (maxSpawnDelay <= minSpawnDelay) { + spawnDelay = minSpawnDelay; + } else { + spawnDelay = minSpawnDelay + + getLevel()->random->nextInt(maxSpawnDelay - minSpawnDelay); + } + + if ((spawnPotentials != NULL) && (spawnPotentials->size() > 0)) { + setNextSpawnData((SpawnData*)WeighedRandom::getRandomItem( + (Random*)getLevel()->random, + (std::vector*)spawnPotentials)); + } + + broadcastEvent(EVENT_SPAWN); +} + +void BaseMobSpawner::load(CompoundTag* tag) { + entityId = tag->getString(L"EntityId"); + spawnDelay = tag->getShort(L"Delay"); + + if (tag->contains(L"SpawnPotentials")) { + spawnPotentials = new std::vector(); + ListTag* potentials = + (ListTag*)tag->getList(L"SpawnPotentials"); + + for (int i = 0; i < potentials->size(); i++) { + spawnPotentials->push_back(new SpawnData(potentials->get(i))); + } + } else { + spawnPotentials = NULL; + } + + if (tag->contains(L"SpawnData")) { + setNextSpawnData( + new SpawnData(tag->getCompound(L"SpawnData"), entityId)); + } else { + setNextSpawnData(NULL); + } + + if (tag->contains(L"MinSpawnDelay")) { + minSpawnDelay = tag->getShort(L"MinSpawnDelay"); + maxSpawnDelay = tag->getShort(L"MaxSpawnDelay"); + spawnCount = tag->getShort(L"SpawnCount"); + } + + if (tag->contains(L"MaxNearbyEntities")) { + maxNearbyEntities = tag->getShort(L"MaxNearbyEntities"); + requiredPlayerRange = tag->getShort(L"RequiredPlayerRange"); + } + + if (tag->contains(L"SpawnRange")) spawnRange = tag->getShort(L"SpawnRange"); + + if (getLevel() != NULL && getLevel()->isClientSide) { + displayEntity = nullptr; + } +} + +void BaseMobSpawner::save(CompoundTag* tag) { + tag->putString(L"EntityId", getEntityId()); + tag->putShort(L"Delay", (short)spawnDelay); + tag->putShort(L"MinSpawnDelay", (short)minSpawnDelay); + tag->putShort(L"MaxSpawnDelay", (short)maxSpawnDelay); + tag->putShort(L"SpawnCount", (short)spawnCount); + tag->putShort(L"MaxNearbyEntities", (short)maxNearbyEntities); + tag->putShort(L"RequiredPlayerRange", (short)requiredPlayerRange); + tag->putShort(L"SpawnRange", (short)spawnRange); + + if (getNextSpawnData() != NULL) { + tag->putCompound(L"SpawnData", + (CompoundTag*)getNextSpawnData()->tag->copy()); + } + + if (getNextSpawnData() != NULL || + (spawnPotentials != NULL && spawnPotentials->size() > 0)) { + ListTag* list = new ListTag(); + + if (spawnPotentials != NULL && spawnPotentials->size() > 0) { + for (AUTO_VAR(it, spawnPotentials->begin()); + it != spawnPotentials->end(); ++it) { + SpawnData* data = *it; + list->add(data->save()); + } + } else { + list->add(getNextSpawnData()->save()); + } + + tag->put(L"SpawnPotentials", list); + } +} + +std::shared_ptr BaseMobSpawner::getDisplayEntity() { + if (displayEntity == NULL) { + std::shared_ptr e = EntityIO::newEntity(getEntityId(), NULL); + e = loadDataAndAddEntity(e); + displayEntity = e; + } + + return displayEntity; +} + +bool BaseMobSpawner::onEventTriggered(int id) { + if (id == EVENT_SPAWN && getLevel()->isClientSide) { + spawnDelay = minSpawnDelay; + return true; + } + return false; +} + +BaseMobSpawner::SpawnData* BaseMobSpawner::getNextSpawnData() { + return nextSpawnData; +} + +void BaseMobSpawner::setNextSpawnData(SpawnData* nextSpawnData) { + this->nextSpawnData = nextSpawnData; +} + +BaseMobSpawner::SpawnData::SpawnData(CompoundTag* base) + : WeighedRandomItem(base->getInt(L"Weight")) { + CompoundTag* tag = base->getCompound(L"Properties"); + std::wstring _type = base->getString(L"Type"); + + if (_type.compare(L"Minecart") == 0) { + if (tag != NULL) { + switch (tag->getInt(L"Type")) { + case Minecart::TYPE_CHEST: + type = L"MinecartChest"; + break; + case Minecart::TYPE_FURNACE: + type = L"MinecartFurnace"; + break; + case Minecart::TYPE_RIDEABLE: + type = L"MinecartRideable"; + break; + } + } else { + type = L"MinecartRideable"; + } + } + + this->tag = tag; + this->type = _type; +} + +BaseMobSpawner::SpawnData::SpawnData(CompoundTag* tag, std::wstring _type) + : WeighedRandomItem(1) { + if (_type.compare(L"Minecart") == 0) { + if (tag != NULL) { + switch (tag->getInt(L"Type")) { + case Minecart::TYPE_CHEST: + _type = L"MinecartChest"; + break; + case Minecart::TYPE_FURNACE: + _type = L"MinecartFurnace"; + break; + case Minecart::TYPE_RIDEABLE: + _type = L"MinecartRideable"; + break; + } + } else { + _type = L"MinecartRideable"; + } + } + + this->tag = tag; + this->type = _type; +} + +BaseMobSpawner::SpawnData::~SpawnData() { delete tag; } + +CompoundTag* BaseMobSpawner::SpawnData::save() { + CompoundTag* result = new CompoundTag(); + + result->putCompound(L"Properties", tag); + result->putString(L"Type", type); + result->putInt(L"Weight", randomWeight); + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/Level/BaseMobSpawner.h b/Minecraft.World/Level/BaseMobSpawner.h new file mode 100644 index 000000000..334e8a078 --- /dev/null +++ b/Minecraft.World/Level/BaseMobSpawner.h @@ -0,0 +1,69 @@ +#pragma once + +#include "../Util/WeighedRandom.h" + +class BaseMobSpawner { +public: + class SpawnData : public WeighedRandomItem { + public: + CompoundTag* tag; + std::wstring type; + + SpawnData(CompoundTag* base); + SpawnData(CompoundTag* tag, std::wstring type); + ~SpawnData(); + + virtual CompoundTag* save(); + }; + +private: + static const int EVENT_SPAWN = 1; + +public: + int spawnDelay; + +private: + std::wstring entityId; + std::vector* spawnPotentials; + SpawnData* nextSpawnData; + +public: + double spin, oSpin; + +private: + int minSpawnDelay; + int maxSpawnDelay; + int spawnCount; + std::shared_ptr displayEntity; + int maxNearbyEntities; + int requiredPlayerRange; + int spawnRange; + +public: + BaseMobSpawner(); + ~BaseMobSpawner(); + + virtual std::wstring getEntityId(); + virtual void setEntityId(const std::wstring& entityId); + virtual bool isNearPlayer(); + virtual void tick(); + virtual std::shared_ptr loadDataAndAddEntity( + std::shared_ptr entity); + +private: + virtual void delay(); + +public: + virtual void load(CompoundTag* tag); + virtual void save(CompoundTag* tag); + virtual std::shared_ptr getDisplayEntity(); + virtual bool onEventTriggered(int id); + virtual SpawnData* getNextSpawnData(); + virtual void setNextSpawnData(SpawnData* nextSpawnData); + + virtual void broadcastEvent(int id) = 0; + virtual Level* getLevel() = 0; + virtual int getX() = 0; + virtual int getY() = 0; + virtual int getZ() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/Level/Calendar.cpp b/Minecraft.World/Level/Calendar.cpp new file mode 100644 index 000000000..b978fee26 --- /dev/null +++ b/Minecraft.World/Level/Calendar.cpp @@ -0,0 +1,17 @@ +#include "../Platform/stdafx.h" +#include "Calendar.h" +#include + +unsigned int Calendar::GetDayOfMonth() { + time_t t = time(0); + struct tm* now = localtime(&t); + + return now->tm_mday; +} + +unsigned int Calendar::GetMonth() { + time_t t = time(0); + struct tm* now = localtime(&t); + + return now->tm_mon; +} \ No newline at end of file diff --git a/Minecraft.World/Level/Calendar.h b/Minecraft.World/Level/Calendar.h new file mode 100644 index 000000000..3c6410174 --- /dev/null +++ b/Minecraft.World/Level/Calendar.h @@ -0,0 +1,9 @@ +#pragma once + +class Calendar { +public: + Calendar(); + + static unsigned int GetDayOfMonth(); + static unsigned int GetMonth(); +}; \ No newline at end of file diff --git a/Minecraft.World/Level/ChunkPos.cpp b/Minecraft.World/Level/ChunkPos.cpp index e527b6a12..bf479e109 100644 --- a/Minecraft.World/Level/ChunkPos.cpp +++ b/Minecraft.World/Level/ChunkPos.cpp @@ -4,14 +4,14 @@ ChunkPos::ChunkPos(int x, int z) : x(x), z(z) {} -__int64 ChunkPos::hashCode(int x, int z) { - __int64 xx = x; - __int64 zz = z; +int64_t ChunkPos::hashCode(int x, int z) { + int64_t xx = x; + int64_t zz = z; return (xx & 0xffffffffl) | ((zz & 0xffffffffl) << 32l); } int ChunkPos::hashCode() { - __int64 hash = hashCode(x, z); + int64_t hash = hashCode(x, z); int h1 = (int)(hash); int h2 = (int)(hash >> 32l); return h1 ^ h2; @@ -49,7 +49,7 @@ std::wstring ChunkPos::toString() { return L"[" + _toString(x) + L", " + _toString(z) + L"]"; } -__int64 ChunkPos::hash_fnct(const ChunkPos& k) { return k.hashCode(k.x, k.z); } +int64_t ChunkPos::hash_fnct(const ChunkPos& k) { return k.hashCode(k.x, k.z); } bool ChunkPos::eq_test(const ChunkPos& x, const ChunkPos& y) { return x.x == y.x && x.z == y.z; diff --git a/Minecraft.World/Level/ChunkPos.h b/Minecraft.World/Level/ChunkPos.h index cfdae48f5..9a2eabca4 100644 --- a/Minecraft.World/Level/ChunkPos.h +++ b/Minecraft.World/Level/ChunkPos.h @@ -10,7 +10,7 @@ public: ChunkPos(int x, int z); - static __int64 hashCode(int x, int z); + static int64_t hashCode(int x, int z); int hashCode(); double distanceToSqr(std::shared_ptr e); @@ -22,7 +22,7 @@ public: TilePos getMiddleBlockPosition(int y); std::wstring toString(); - static __int64 hash_fnct(const ChunkPos& k); + static int64_t hash_fnct(const ChunkPos& k); static bool eq_test(const ChunkPos& x, const ChunkPos& y); bool operator==(const ChunkPos& k) const { return (this->x == k.x) && (this->z == k.z); @@ -35,7 +35,7 @@ public: }; struct ChunkPosKeyHash { - __int64 operator()(const ChunkPos& k) const { + int64_t operator()(const ChunkPos& k) const { return ChunkPos::hash_fnct(k); } }; diff --git a/Minecraft.World/Level/ChunkSource.h b/Minecraft.World/Level/ChunkSource.h index 42f5b25db..335ef94f6 100644 --- a/Minecraft.World/Level/ChunkSource.h +++ b/Minecraft.World/Level/ChunkSource.h @@ -8,6 +8,12 @@ class TilePos; #ifdef _LARGE_WORLDS // 4J Stu - Our default map (at zoom level 3) is 1024x1024 blocks (or 64 chunks) #define LEVEL_MAX_WIDTH (5 * 64) //(6*54) + +#define LEVEL_WIDTH_CLASSIC 54 +#define LEVEL_WIDTH_SMALL 64 +#define LEVEL_WIDTH_MEDIUM (3 * 64) +#define LEVEL_WIDTH_LARGE (5 * 64) + #else #define LEVEL_MAX_WIDTH 54 #endif @@ -19,6 +25,12 @@ class TilePos; // overworld #ifdef _LARGE_WORLDS #define HELL_LEVEL_MAX_SCALE 8 + +#define HELL_LEVEL_SCALE_CLASSIC 3 +#define HELL_LEVEL_SCALE_SMALL 3 +#define HELL_LEVEL_SCALE_MEDIUM 6 +#define HELL_LEVEL_SCALE_LARGE 8 + #else #define HELL_LEVEL_MAX_SCALE 3 #endif @@ -39,6 +51,11 @@ class ChunkSource { public: // 4J Added so that we can store the maximum dimensions of this world int m_XZSize; +#ifdef _LARGE_WORLDS + bool m_classicEdgeMoat; + bool m_smallEdgeMoat; + bool m_mediumEdgeMoat; +#endif public: virtual ~ChunkSource() {} @@ -69,4 +86,12 @@ public: virtual TilePos* findNearestMapFeature(Level* level, const std::wstring& featureName, int x, int y, int z) = 0; + + /** + * Recreates "logic structures" for a chunk that has been loaded from disk. + * For example, fortress bridges in the Nether. + */ + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ) = 0; + + // virtual void flushSave() = 0; // 4J removed }; diff --git a/Minecraft.World/Level/CustomLevelSource.cpp b/Minecraft.World/Level/CustomLevelSource.cpp index 428dd7a6a..a2b774fe9 100644 --- a/Minecraft.World/Level/CustomLevelSource.cpp +++ b/Minecraft.World/Level/CustomLevelSource.cpp @@ -1,5 +1,4 @@ #include "../Platform/stdafx.h" -#include "../Util/PortableFileIO.h" #include "../Headers/net.minecraft.world.level.h" #include "../Headers/net.minecraft.world.level.biome.h" #include "../Headers/net.minecraft.world.level.levelgen.h" @@ -8,12 +7,13 @@ #include "../Headers/net.minecraft.world.level.levelgen.synth.h" #include "../Headers/net.minecraft.world.level.tile.h" #include "../Headers/net.minecraft.world.level.storage.h" +#include "../Headers/net.minecraft.world.entity.h" #include "CustomLevelSource.h" const double CustomLevelSource::SNOW_SCALE = 0.3; const double CustomLevelSource::SNOW_CUTOFF = 0.5; -CustomLevelSource::CustomLevelSource(Level* level, __int64 seed, +CustomLevelSource::CustomLevelSource(Level* level, int64_t seed, bool generateStructures) : generateStructures(generateStructures) { #ifdef _OVERRIDE_HEIGHTMAP @@ -21,55 +21,86 @@ CustomLevelSource::CustomLevelSource(Level* level, __int64 seed, m_heightmapOverride = byteArray((m_XZSize * 16) * (m_XZSize * 16)); -#ifdef _WINDOWS64 - const std::wstring path = L"GameRules\\heightmap.bin"; +#ifdef _UNICODE + std::wstring path = L"GAME:\\GameRules\\heightmap.bin"; + #else - const std::wstring path = L"GAME:\\GameRules\\heightmap.bin"; +#ifdef _WINDOWS64 + std::string path = "GameRules\\heightmap.bin"; +#else + std::string path = "GAME:\\GameRules\\heightmap.bin"; #endif - const PortableFileIO::BinaryReadResult heightmapReadResult = - PortableFileIO::ReadBinaryFile(path, m_heightmapOverride.data, - m_heightmapOverride.length); - if (heightmapReadResult.status == - PortableFileIO::BinaryReadStatus::not_found) { +#endif + HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) { app.FatalLoadError(); + DWORD error = GetLastError(); assert(false); - } else if (heightmapReadResult.status == - PortableFileIO::BinaryReadStatus::too_large) { - app.DebugPrintf("Heightmap binary is too large!!\n"); - __debugbreak(); - } else if (heightmapReadResult.status != - PortableFileIO::BinaryReadStatus::ok) { - app.FatalLoadError(); + } else { +#ifdef _DURANGO + __debugbreak(); // TODO + DWORD bytesRead, dwFileSize = 0; +#else + DWORD bytesRead, dwFileSize = GetFileSize(file, NULL); +#endif + if (dwFileSize > m_heightmapOverride.length) { + app.DebugPrintf("Heightmap binary is too large!!\n"); + __debugbreak(); + } + BOOL bSuccess = ReadFile(file, m_heightmapOverride.data, dwFileSize, + &bytesRead, NULL); + + if (bSuccess == FALSE) { + app.FatalLoadError(); + } + CloseHandle(file); } m_waterheightOverride = byteArray((m_XZSize * 16) * (m_XZSize * 16)); -#ifdef _WINDOWS64 - const std::wstring waterHeightPath = L"GameRules\\waterheight.bin"; +#ifdef _UNICODE + std::wstring waterHeightPath = L"GAME:\\GameRules\\waterheight.bin"; + #else - const std::wstring waterHeightPath = L"GAME:\\GameRules\\waterheight.bin"; +#ifdef _WINDOWS64 + std::string waterHeightPath = "GameRules\\waterheight.bin"; +#else + std::string waterHeightPath = "GAME:\\GameRules\\waterheight.bin"; #endif - const PortableFileIO::BinaryReadResult waterHeightReadResult = - PortableFileIO::ReadBinaryFile(waterHeightPath, - m_waterheightOverride.data, - m_waterheightOverride.length); - if (waterHeightReadResult.status == - PortableFileIO::BinaryReadStatus::not_found) { +#endif + file = CreateFile(waterHeightPath.c_str(), GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) { + DWORD error = GetLastError(); + // assert(false); memset(m_waterheightOverride.data, level->seaLevel, m_waterheightOverride.length); - } else if (waterHeightReadResult.status == - PortableFileIO::BinaryReadStatus::too_large) { - app.DebugPrintf("waterheight binary is too large!!\n"); - __debugbreak(); - } else if (waterHeightReadResult.status != - PortableFileIO::BinaryReadStatus::ok) { - app.FatalLoadError(); + } else { +#ifdef _DURANGO + __debugbreak(); // TODO + DWORD bytesRead, dwFileSize = 0; +#else + DWORD bytesRead, dwFileSize = GetFileSize(file, NULL); +#endif + if (dwFileSize > m_waterheightOverride.length) { + app.DebugPrintf("waterheight binary is too large!!\n"); + __debugbreak(); + } + BOOL bSuccess = ReadFile(file, m_waterheightOverride.data, dwFileSize, + &bytesRead, NULL); + + if (bSuccess == FALSE) { + app.FatalLoadError(); + } + CloseHandle(file); } caveFeature = new LargeCaveFeature(); strongholdFeature = new StrongholdFeature(); - villageFeature = new VillageFeature(0, m_XZSize); + villageFeature = new VillageFeature(m_XZSize); mineShaftFeature = new MineShaftFeature(); + scatteredFeature = new RandomScatteredLargeFeature(); canyonFeature = new CanyonFeature(); this->level = level; @@ -90,6 +121,8 @@ CustomLevelSource::~CustomLevelSource() { delete mineShaftFeature; delete canyonFeature; + this->level = level; + delete random; delete perlinNoise3; #endif @@ -169,9 +202,9 @@ void CustomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { // 4J - this comparison used to just be with 0.0f // but is now varied by block above if (yc * CHUNK_HEIGHT + y < mapHeight) { - tileId = (std::uint8_t)Tile::rock_Id; + tileId = (uint8_t)Tile::stone_Id; } else if (yc * CHUNK_HEIGHT + y < waterHeight) { - tileId = (std::uint8_t)Tile::calmWater_Id; + tileId = (uint8_t)Tile::calmWater_Id; } // 4J - more extra code to make sure that the column @@ -185,7 +218,7 @@ void CustomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { // the edge of the world if (yc * CHUNK_HEIGHT + y <= (level->getSeaLevel() - 10)) - tileId = Tile::rock_Id; + tileId = Tile::stone_Id; else if (yc * CHUNK_HEIGHT + y < level->getSeaLevel()) tileId = Tile::calmWater_Id; @@ -245,8 +278,8 @@ void CustomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, int run = -1; - std::uint8_t top = b->topMaterial; - std::uint8_t material = b->material; + uint8_t top = b->topMaterial; + uint8_t material = b->material; LevelGenerationOptions* lgo = app.getLevelGenerationOptions(); if (lgo != NULL) { @@ -270,17 +303,17 @@ void CustomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, // if (y <= 0 + // random->nextInt(5)) { - blocks[offs] = (std::uint8_t)Tile::unbreakable_Id; + blocks[offs] = (uint8_t)Tile::unbreakable_Id; } else { int old = blocks[offs]; if (old == 0) { run = -1; - } else if (old == Tile::rock_Id) { + } else if (old == Tile::stone_Id) { if (run == -1) { if (runDepth <= 0) { top = 0; - material = (std::uint8_t)Tile::rock_Id; + material = (uint8_t)Tile::stone_Id; } else if (y >= waterHeight - 4 && y <= waterHeight + 1) { top = b->topMaterial; @@ -292,9 +325,9 @@ void CustomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, if (y < waterHeight && top == 0) { if (temp < 0.15f) - top = (std::uint8_t)Tile::ice_Id; + top = (uint8_t)Tile::ice_Id; else - top = (std::uint8_t)Tile::calmWater_Id; + top = (uint8_t)Tile::calmWater_Id; } run = runDepth; @@ -310,7 +343,7 @@ void CustomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, // runs if (run == 0 && material == Tile::sand_Id) { run = random->nextInt(4); - material = (std::uint8_t)Tile::sandStone_Id; + material = (uint8_t)Tile::sandStone_Id; } } } @@ -338,8 +371,8 @@ LevelChunk* CustomLevelSource::getChunk(int xOffs, int zOffs) { // 4J - now allocating this with a physical alloc & bypassing general memory // management so that it will get cleanly freed int blocksSize = Level::maxBuildHeight * 16 * 16; - std::uint8_t* tileData = (std::uint8_t*)XPhysicalAlloc( - blocksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); + uint8_t* tileData = (uint8_t*)XPhysicalAlloc(blocksSize, MAXULONG_PTR, 4096, + PAGE_READWRITE); XMemSet128(tileData, 0, blocksSize); byteArray blocks = byteArray(tileData, blocksSize); // byteArray blocks = byteArray(16 * level->depth * 16); @@ -368,6 +401,7 @@ LevelChunk* CustomLevelSource::getChunk(int xOffs, int zOffs) { mineShaftFeature->apply(this, level, xOffs, zOffs, blocks); villageFeature->apply(this, level, xOffs, zOffs, blocks); strongholdFeature->apply(this, level, xOffs, zOffs, blocks); + scatteredFeature->apply(this, level, xOffs, zOffs, blocks); } // canyonFeature.apply(this, level, xOffs, zOffs, blocks); // townFeature.apply(this, level, xOffs, zOffs, blocks); @@ -451,19 +485,21 @@ void CustomLevelSource::calcWaterDepths(ChunkSource* parent, int xt, int zt) { int od = level->getData(xp + x2, y, zp + z2); if (od < 7 && od < d) { - level->setData(xp + x2, y, zp + z2, - d); + level->setData( + xp + x2, y, zp + z2, d, + Tile::UPDATE_CLIENTS); } } } } } if (hadWater) { - level->setTileAndDataNoUpdate( - xp, y, zp, Tile::calmWater_Id, 7); + level->setTileAndData(xp, y, zp, Tile::calmWater_Id, + 7, Tile::UPDATE_CLIENTS); for (int y2 = 0; y2 < y; y2++) { - level->setTileAndDataNoUpdate( - xp, y2, zp, Tile::calmWater_Id, 8); + level->setTileAndData(xp, y2, zp, + Tile::calmWater_Id, 8, + Tile::UPDATE_CLIENTS); } } } @@ -489,8 +525,8 @@ void CustomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { } pprandom->setSeed(level->getSeed()); - __int64 xScale = pprandom->nextLong() / 2 * 2 + 1; - __int64 zScale = pprandom->nextLong() / 2 * 2 + 1; + int64_t xScale = pprandom->nextLong() / 2 * 2 + 1; + int64_t zScale = pprandom->nextLong() / 2 * 2 + 1; pprandom->setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); bool hasVillage = false; @@ -500,6 +536,7 @@ void CustomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { mineShaftFeature->postProcess(level, pprandom, xt, zt); hasVillage = villageFeature->postProcess(level, pprandom, xt, zt); strongholdFeature->postProcess(level, pprandom, xt, zt); + scatteredFeature->postProcess(level, random, xt, zt); } PIXEndNamedEvent(); @@ -562,14 +599,16 @@ void CustomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { int y = level->getTopRainBlock(xo + x, zo + z); if (level->shouldFreezeIgnoreNeighbors(x + xo, y - 1, z + zo)) { - level->setTileNoUpdate( - x + xo, y - 1, z + zo, - Tile::ice_Id); // 4J - changed from setTile, otherwise we - // end up creating a *lot* of dynamic water - // tiles as these ice tiles are set + level->setTileAndData( + x + xo, y - 1, z + zo, Tile::ice_Id, 0, + Tile::UPDATE_INVISIBLE); // 4J - changed from setTile, + // otherwise we end up creating a + // *lot* of dynamic water tiles as + // these ice tiles are set } if (level->shouldSnow(x + xo, y, z + zo)) { - level->setTile(x + xo, y, z + zo, Tile::topSnow_Id); + level->setTileAndData(x + xo, y, z + zo, Tile::topSnow_Id, 0, + Tile::UPDATE_CLIENTS); } } } @@ -595,6 +634,10 @@ std::vector* CustomLevelSource::getMobsAt( if (biome == NULL) { return NULL; } + if (mobCategory == MobCategory::monster && + scatteredFeature->isSwamphut(x, y, z)) { + return scatteredFeature->getSwamphutEnemies(); + } return biome->getMobs(mobCategory); #else return NULL; @@ -610,3 +653,15 @@ TilePos* CustomLevelSource::findNearestMapFeature( #endif return NULL; } + +void CustomLevelSource::recreateLogicStructuresForChunk(int chunkX, + int chunkZ) { + if (generateStructures) { +#ifdef _OVERRIDE_HEIGHTMAP + mineShaftFeature->apply(this, level, chunkX, chunkZ, NULL); + villageFeature->apply(this, level, chunkX, chunkZ, NULL); + strongholdFeature->apply(this, level, chunkX, chunkZ, NULL); + scatteredFeature->apply(this, level, chunkX, chunkZ, NULL); +#endif + } +} \ No newline at end of file diff --git a/Minecraft.World/Level/CustomLevelSource.h b/Minecraft.World/Level/CustomLevelSource.h index 2d7980d08..65a38fadf 100644 --- a/Minecraft.World/Level/CustomLevelSource.h +++ b/Minecraft.World/Level/CustomLevelSource.h @@ -11,6 +11,7 @@ class LargeFeature; class StrongholdFeature; class VillageFeature; class MineShaftFeature; +class RandomScatteredLargeFeature; class CustomLevelSource : public ChunkSource { public: @@ -29,6 +30,7 @@ private: StrongholdFeature* strongholdFeature; VillageFeature* villageFeature; MineShaftFeature* mineShaftFeature; + RandomScatteredLargeFeature* scatteredFeature; LargeFeature* canyonFeature; Level* level; #endif @@ -40,7 +42,7 @@ private: const bool generateStructures; public: - CustomLevelSource(Level* level, __int64 seed, bool generateStructures); + CustomLevelSource(Level* level, int64_t seed, bool generateStructures); ~CustomLevelSource(); public: @@ -76,4 +78,5 @@ public: virtual TilePos* findNearestMapFeature(Level* level, const std::wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/Level/DerivedLevelData.cpp b/Minecraft.World/Level/DerivedLevelData.cpp index d97943579..fef8fefa1 100644 --- a/Minecraft.World/Level/DerivedLevelData.cpp +++ b/Minecraft.World/Level/DerivedLevelData.cpp @@ -17,7 +17,7 @@ CompoundTag* DerivedLevelData::createTag( return wrapped->createTag(players); } -__int64 DerivedLevelData::getSeed() { return wrapped->getSeed(); } +int64_t DerivedLevelData::getSeed() { return wrapped->getSeed(); } int DerivedLevelData::getXSpawn() { return wrapped->getXSpawn(); } @@ -25,9 +25,11 @@ int DerivedLevelData::getYSpawn() { return wrapped->getYSpawn(); } int DerivedLevelData::getZSpawn() { return wrapped->getZSpawn(); } -__int64 DerivedLevelData::getTime() { return wrapped->getTime(); } +int64_t DerivedLevelData::getGameTime() { return wrapped->getGameTime(); } -__int64 DerivedLevelData::getSizeOnDisk() { return wrapped->getSizeOnDisk(); } +int64_t DerivedLevelData::getDayTime() { return wrapped->getDayTime(); } + +int64_t DerivedLevelData::getSizeOnDisk() { return wrapped->getSizeOnDisk(); } CompoundTag* DerivedLevelData::getLoadedPlayerTag() { return wrapped->getLoadedPlayerTag(); @@ -39,7 +41,7 @@ std::wstring DerivedLevelData::getLevelName() { int DerivedLevelData::getVersion() { return wrapped->getVersion(); } -__int64 DerivedLevelData::getLastPlayed() { return wrapped->getLastPlayed(); } +int64_t DerivedLevelData::getLastPlayed() { return wrapped->getLastPlayed(); } bool DerivedLevelData::isThundering() { return wrapped->isThundering(); } @@ -51,7 +53,7 @@ int DerivedLevelData::getRainTime() { return wrapped->getRainTime(); } GameType* DerivedLevelData::getGameType() { return wrapped->getGameType(); } -void DerivedLevelData::setSeed(__int64 seed) {} +void DerivedLevelData::setSeed(int64_t seed) {} void DerivedLevelData::setXSpawn(int xSpawn) {} @@ -59,9 +61,11 @@ void DerivedLevelData::setYSpawn(int ySpawn) {} void DerivedLevelData::setZSpawn(int zSpawn) {} -void DerivedLevelData::setTime(__int64 time) {} +void DerivedLevelData::setGameTime(int64_t time) {} -void DerivedLevelData::setSizeOnDisk(__int64 sizeOnDisk) {} +void DerivedLevelData::setDayTime(int64_t time) {} + +void DerivedLevelData::setSizeOnDisk(int64_t sizeOnDisk) {} void DerivedLevelData::setLoadedPlayerTag(CompoundTag* loadedPlayerTag) {} @@ -103,6 +107,8 @@ bool DerivedLevelData::isInitialized() { return wrapped->isInitialized(); } void DerivedLevelData::setInitialized(bool initialized) {} +GameRules* DerivedLevelData::getGameRules() { return wrapped->getGameRules(); } + int DerivedLevelData::getXZSize() { return wrapped->getXZSize(); } int DerivedLevelData::getHellScale() { return wrapped->getHellScale(); } diff --git a/Minecraft.World/Level/DerivedLevelData.h b/Minecraft.World/Level/DerivedLevelData.h index 0c633d176..d6c5838af 100644 --- a/Minecraft.World/Level/DerivedLevelData.h +++ b/Minecraft.World/Level/DerivedLevelData.h @@ -2,6 +2,8 @@ #include "LevelData.h" +class GameRules; + class DerivedLevelData : public LevelData { private: LevelData* wrapped; @@ -15,27 +17,29 @@ protected: public: CompoundTag* createTag(); CompoundTag* createTag(std::vector >* players); - __int64 getSeed(); + int64_t getSeed(); int getXSpawn(); int getYSpawn(); int getZSpawn(); - __int64 getTime(); - __int64 getSizeOnDisk(); + int64_t getGameTime(); + int64_t getDayTime(); + int64_t getSizeOnDisk(); CompoundTag* getLoadedPlayerTag(); std::wstring getLevelName(); int getVersion(); - __int64 getLastPlayed(); + int64_t getLastPlayed(); bool isThundering(); int getThunderTime(); bool isRaining(); int getRainTime(); GameType* getGameType(); - void setSeed(__int64 seed); + void setSeed(int64_t seed); void setXSpawn(int xSpawn); void setYSpawn(int ySpawn); void setZSpawn(int zSpawn); - void setTime(__int64 time); - void setSizeOnDisk(__int64 sizeOnDisk); + void setGameTime(int64_t time); + void setDayTime(int64_t time); + void setSizeOnDisk(int64_t sizeOnDisk); void setLoadedPlayerTag(CompoundTag* loadedPlayerTag); void setDimension(int dimension); void setSpawn(int xSpawn, int ySpawn, int zSpawn); @@ -54,6 +58,7 @@ public: void setAllowCommands(bool allowCommands); bool isInitialized(); void setInitialized(bool initialized); + GameRules* getGameRules(); int getXZSize(); // 4J Added int getHellScale(); // 4J Addded }; diff --git a/Minecraft.World/Level/Dimensions/Dimension.cpp b/Minecraft.World/Level/Dimensions/Dimension.cpp index ce97f0872..a4447878c 100644 --- a/Minecraft.World/Level/Dimensions/Dimension.cpp +++ b/Minecraft.World/Level/Dimensions/Dimension.cpp @@ -1,4 +1,5 @@ #include "../../Platform/stdafx.h" +#include "../../Headers/net.minecraft.world.level.levelgen.flat.h" #include "../../Headers/net.minecraft.world.level.levelgen.h" #include "../../Headers/net.minecraft.world.level.h" #include "../../Headers/net.minecraft.world.level.storage.h" @@ -13,9 +14,13 @@ #include "../../../Minecraft.Client/Minecraft.h" #include "../../../Minecraft.Client/Platform/Common/Colours/ColourTable.h" +const float Dimension::MOON_BRIGHTNESS_PER_PHASE[8] = { + 1.0f, 0.75f, 0.5f, 0.25f, 0, 0.25f, 0.5f, 0.75f}; + void Dimension::init(Level* level) { this->level = level; - this->levelType = level->getLevelData()->getGenerator(); + levelType = level->getLevelData()->getGenerator(); + levelTypeOptions = level->getLevelData()->getGeneratorOptions(); init(); updateLightRamp(); } @@ -35,12 +40,16 @@ void Dimension::init() { // file if (app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & - (1L << eDebugSetting_EnableHeightWaterBiomeOverride)) { + (1L << eDebugSetting_EnableBiomeOverride)) { biomeSource = new BiomeSource(level); } else #endif if (level->getLevelData()->getGenerator() == LevelType::lvl_flat) { - biomeSource = new FixedBiomeSource(Biome::plains, 0.5f, 0.5f); + FlatGeneratorInfo* generator = FlatGeneratorInfo::fromValue( + level->getLevelData()->getGeneratorOptions()); + biomeSource = new FixedBiomeSource(Biome::biomes[generator->getBiome()], + 0.5f, 0.5f); + delete generator; } else { biomeSource = new BiomeSource(level); } @@ -51,6 +60,7 @@ Dimension::Dimension() { hasCeiling = false; brightnessRamp = new float[Level::MAX_BRIGHTNESS + 1]; id = 0; + levelTypeOptions = L""; } Dimension::~Dimension() { @@ -65,7 +75,7 @@ ChunkSource* Dimension::createRandomLevelSource() const { // file if (app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & - (1L << eDebugSetting_EnableHeightWaterBiomeOverride)) { + (1L << eDebugSetting_EnableHeightWaterOverride)) { return new CustomLevelSource( level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures()); @@ -99,7 +109,7 @@ bool Dimension::isValidSpawn(int x, int z) const { return true; } -float Dimension::getTimeOfDay(__int64 time, float a) const { +float Dimension::getTimeOfDay(int64_t time, float a) const { int dayStep = (int)(time % Level::TICKS_PER_DAY); float td = (dayStep + a) / Level::TICKS_PER_DAY - 0.25f; if (td < 0) td += 1; @@ -110,7 +120,7 @@ float Dimension::getTimeOfDay(__int64 time, float a) const { return td; } -int Dimension::getMoonPhase(__int64 time, float a) const { +int Dimension::getMoonPhase(int64_t time) const { return ((int)(time / Level::TICKS_PER_DAY)) % 8; } diff --git a/Minecraft.World/Level/Dimensions/Dimension.h b/Minecraft.World/Level/Dimensions/Dimension.h index a9e342c59..b5d1f4674 100644 --- a/Minecraft.World/Level/Dimensions/Dimension.h +++ b/Minecraft.World/Level/Dimensions/Dimension.h @@ -11,8 +11,11 @@ class LevelType; class Dimension { public: + static const float MOON_BRIGHTNESS_PER_PHASE[8]; + Level* level; LevelType* levelType; + std::wstring levelTypeOptions; BiomeSource* biomeSource; bool ultraWarm; bool hasCeiling; @@ -34,8 +37,8 @@ public: virtual bool isValidSpawn(int x, int z) const; - virtual float getTimeOfDay(__int64 time, float a) const; - virtual int getMoonPhase(__int64 time, float a) const; + virtual float getTimeOfDay(int64_t time, float a) const; + virtual int getMoonPhase(int64_t time) const; virtual bool isNaturalDimension(); private: diff --git a/Minecraft.World/Level/Dimensions/HellDimension.cpp b/Minecraft.World/Level/Dimensions/HellDimension.cpp index 21639afde..f2869a58b 100644 --- a/Minecraft.World/Level/Dimensions/HellDimension.cpp +++ b/Minecraft.World/Level/Dimensions/HellDimension.cpp @@ -56,7 +56,7 @@ bool HellDimension::isNaturalDimension() { return false; } bool HellDimension::isValidSpawn(int x, int z) const { return false; } -float HellDimension::getTimeOfDay(__int64 time, float a) const { return 0.5f; } +float HellDimension::getTimeOfDay(int64_t time, float a) const { return 0.5f; } bool HellDimension::mayRespawn() const { return false; } diff --git a/Minecraft.World/Level/Dimensions/HellDimension.h b/Minecraft.World/Level/Dimensions/HellDimension.h index 863398cbc..93f374687 100644 --- a/Minecraft.World/Level/Dimensions/HellDimension.h +++ b/Minecraft.World/Level/Dimensions/HellDimension.h @@ -13,7 +13,7 @@ public: virtual ChunkSource* createRandomLevelSource() const; virtual bool isNaturalDimension(); virtual bool isValidSpawn(int x, int y) const; - virtual float getTimeOfDay(__int64 time, float a) const; + virtual float getTimeOfDay(int64_t time, float a) const; virtual bool mayRespawn() const; virtual bool isFoggyAt(int x, int z); diff --git a/Minecraft.World/Level/Dimensions/SkyIslandDimension.cpp b/Minecraft.World/Level/Dimensions/SkyIslandDimension.cpp index 7715de778..74ebb817a 100644 --- a/Minecraft.World/Level/Dimensions/SkyIslandDimension.cpp +++ b/Minecraft.World/Level/Dimensions/SkyIslandDimension.cpp @@ -14,7 +14,7 @@ ChunkSource* SkyIslandDimension::createRandomLevelSource() const { return new SkyIslandRandomLevelSource(level, level->getSeed()); } -float SkyIslandDimension::getTimeOfDay(__int64 time, float a) const { +float SkyIslandDimension::getTimeOfDay(int64_t time, float a) const { return 0.0f; } diff --git a/Minecraft.World/Level/Dimensions/TheEndDimension.cpp b/Minecraft.World/Level/Dimensions/TheEndDimension.cpp index 50c09e1e7..9ffba3f97 100644 --- a/Minecraft.World/Level/Dimensions/TheEndDimension.cpp +++ b/Minecraft.World/Level/Dimensions/TheEndDimension.cpp @@ -17,7 +17,7 @@ ChunkSource* TheEndDimension::createRandomLevelSource() const { return new TheEndLevelRandomLevelSource(level, level->getSeed()); } -float TheEndDimension::getTimeOfDay(__int64 time, float a) const { +float TheEndDimension::getTimeOfDay(int64_t time, float a) const { return 0.0f; } diff --git a/Minecraft.World/Level/Dimensions/TheEndDimension.h b/Minecraft.World/Level/Dimensions/TheEndDimension.h index 52e9824ee..c6c601e99 100644 --- a/Minecraft.World/Level/Dimensions/TheEndDimension.h +++ b/Minecraft.World/Level/Dimensions/TheEndDimension.h @@ -5,7 +5,7 @@ class TheEndDimension : public Dimension { public: virtual void init(); virtual ChunkSource* createRandomLevelSource() const; - virtual float getTimeOfDay(__int64 time, float a) const; + virtual float getTimeOfDay(int64_t time, float a) const; virtual float* getSunriseColor(float td, float a); virtual Vec3* getFogColor(float td, float a) const; virtual bool hasGround(); diff --git a/Minecraft.World/Level/EmptyLevelChunk.cpp b/Minecraft.World/Level/EmptyLevelChunk.cpp index a0fad8077..addbb0992 100644 --- a/Minecraft.World/Level/EmptyLevelChunk.cpp +++ b/Minecraft.World/Level/EmptyLevelChunk.cpp @@ -102,14 +102,17 @@ void EmptyLevelChunk::load() {} void EmptyLevelChunk::unload(bool unloadTileEntities) // 4J - added parameter {} +bool EmptyLevelChunk::containsPlayer() { return false; } + void EmptyLevelChunk::markUnsaved() {} void EmptyLevelChunk::getEntities(std::shared_ptr except, AABB bb, - std::vector >& es) {} + std::vector >& es, + EntitySelector* selector) {} void EmptyLevelChunk::getEntitiesOfClass( const std::type_info& ec, AABB bb, - std::vector >& es) {} + std::vector >& es, EntitySelector* selector) {} int EmptyLevelChunk::countEntities() { return 0; } @@ -157,7 +160,7 @@ bool EmptyLevelChunk::testSetBlocksAndData(byteArray data, int x0, int y0, return false; } -Random* EmptyLevelChunk::getRandom(__int64 l) { +Random* EmptyLevelChunk::getRandom(int64_t l) { return new Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l); diff --git a/Minecraft.World/Level/EmptyLevelChunk.h b/Minecraft.World/Level/EmptyLevelChunk.h index 6f32dfcd2..5c64f9c8c 100644 --- a/Minecraft.World/Level/EmptyLevelChunk.h +++ b/Minecraft.World/Level/EmptyLevelChunk.h @@ -42,11 +42,14 @@ public: void removeTileEntity(int x, int y, int z); void load(); void unload(bool unloadTileEntities); // 4J - added parameter + bool containsPlayer(); // 4J added void markUnsaved(); void getEntities(std::shared_ptr except, AABB bb, - std::vector >& es); + std::vector >& es, + EntitySelector* selector); void getEntitiesOfClass(const std::type_info& ec, AABB bb, - std::vector >& es); + std::vector >& es, + EntitySelector* selector); int countEntities(); bool shouldSave(bool force); void setBlocks(byteArray newBlocks, int sub); @@ -58,7 +61,7 @@ public: bool includeLighting = true); // 4J - added includeLighting parameter bool testSetBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int p); // 4J added - Random* getRandom(__int64 l); + Random* getRandom(int64_t l); bool isEmpty(); virtual void reSyncLighting() {}; // 4J added }; diff --git a/Minecraft.World/Level/Events/LevelEvent.h b/Minecraft.World/Level/Events/LevelEvent.h index c9fea56e8..e0ea5a017 100644 --- a/Minecraft.World/Level/Events/LevelEvent.h +++ b/Minecraft.World/Level/Events/LevelEvent.h @@ -33,6 +33,7 @@ public: static const int PARTICLES_POTION_SPLASH = 2002; static const int PARTICLES_EYE_OF_ENDER_DEATH = 2003; static const int PARTICLES_MOBTILE_SPAWN = 2004; + static const int PARTICLES_PLANT_GROWTH = 2005; // static const int ENDERDRAGON_KILLED = 9000; // 4J Added to signal the the // enderdragon was killed diff --git a/Minecraft.World/Level/Events/LevelListener.h b/Minecraft.World/Level/Events/LevelListener.h index d4e6e4b5e..bb6bd6815 100644 --- a/Minecraft.World/Level/Events/LevelListener.h +++ b/Minecraft.World/Level/Events/LevelListener.h @@ -15,16 +15,17 @@ public: virtual void allChanged() = 0; - // virtual void playSound(const std::wstring& name, double x, double y, - // double z, float volume, float pitch) = 0; + // virtual void playSound(const wstring& name, double x, double y, double z, + // float volume, float pitch) = 0; virtual void playSound(int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist = 16.0f) = 0; - virtual void playSound(std::shared_ptr entity, int iSound, double x, - double y, double z, float volume, float pitch, - float fSoundClipDist = 16.0f) = 0; + virtual void playSoundExceptPlayer(std::shared_ptr player, + int iSound, double x, double y, double z, + float volume, float pitch, + float fSoundClipDist = 16.0f) = 0; - // 4J removed - virtual void addParticle(const std::wstring& name, double x, + // 4J removed - virtual void addParticle(const wstring& name, double x, // double y, double z, double xa, double ya, double za) = 0; virtual void addParticle(ePARTICLE_TYPE name, double x, double y, double z, @@ -43,7 +44,8 @@ public: virtual void playStreamingMusic(const std::wstring& name, int x, int y, int z) = 0; - + virtual void globalLevelEvent(int type, int sourceX, int sourceY, + int sourceZ, int data) = 0; virtual void levelEvent(std::shared_ptr source, int type, int x, int y, int z, int data) = 0; diff --git a/Minecraft.World/Level/Events/VillageSiege.cpp b/Minecraft.World/Level/Events/VillageSiege.cpp index 97c9b6646..3b623da8c 100644 --- a/Minecraft.World/Level/Events/VillageSiege.cpp +++ b/Minecraft.World/Level/Events/VillageSiege.cpp @@ -125,7 +125,7 @@ bool VillageSiege::trySpawn() { // try { mob = std::shared_ptr(new Zombie(level)); - mob->finalizeMobSpawn(); + mob->finalizeMobSpawn(NULL); mob->setVillager(false); } // catch (Exception e) { diff --git a/Minecraft.World/Level/Explosion.cpp b/Minecraft.World/Level/Explosion.cpp index 387865028..e3718a552 100644 --- a/Minecraft.World/Level/Explosion.cpp +++ b/Minecraft.World/Level/Explosion.cpp @@ -1,5 +1,7 @@ #include "../Platform/stdafx.h" #include "../Headers/net.minecraft.world.entity.h" +#include "../Headers/net.minecraft.world.entity.item.h" +#include "../Headers/net.minecraft.world.item.enchantment.h" #include "../Headers/net.minecraft.world.level.h" #include "../Headers/net.minecraft.world.level.tile.h" #include "../Headers/net.minecraft.world.phys.h" @@ -64,12 +66,18 @@ void Explosion::explode() { int zt = Mth::floor(zp); int t = level->getTile(xt, yt, zt); if (t > 0) { - remainingPower -= - (Tile::tiles[t]->getExplosionResistance(source) + - 0.3f) * - stepSize; + Tile* tile = Tile::tiles[t]; + float resistance = + source != NULL + ? source->getTileExplosionResistance( + this, level, xt, yt, zt, tile) + : tile->getExplosionResistance(source); + remainingPower -= (resistance + 0.3f) * stepSize; } - if (remainingPower > 0) { + if (remainingPower > 0 && + (source == NULL || + source->shouldTileExplode(this, level, xt, yt, zt, t, + remainingPower))) { toBlow.insert(TilePos(xt, yt, zt)); } @@ -141,17 +149,19 @@ void Explosion::explode() { double sp = level->getSeenPercent(center, e->bb); double pow = (1 - dist) * sp; if (canDamage) - e->hurt(DamageSource::explosion, + e->hurt(DamageSource::explosion(this), (int)((pow * pow + pow) / 2 * 8 * r + 1)); - double push = pow; - e->xd += xa * push; - e->yd += ya * push; - e->zd += za * push; + double kbPower = + ProtectionEnchantment::getExplosionKnockbackAfterDampener(e, + pow); + e->xd += xa * kbPower; + e->yd += ya * kbPower; + e->zd += za * kbPower; - std::shared_ptr player = - std::dynamic_pointer_cast(e); - if (player != NULL) { + if (e->instanceof(eTYPE_PLAYER)) { + std::shared_ptr player = + std::dynamic_pointer_cast(e); // app.DebugPrintf("Adding player knockback (%f,%f,%f)\n", xa * // pow, ya * pow, za * pow); hitPlayers.insert(playerVec3Map::value_type( @@ -171,72 +181,84 @@ void Explosion::finalizeExplosion( x, y, z, eSoundType_RANDOM_EXPLODE, 4, (1 + (level->random->nextFloat() - level->random->nextFloat()) * 0.2f) * 0.7f); - level->addParticle(eParticleType_hugeexplosion, x, y, z, 0, 0, 0); + if (r < 2 || !destroyBlocks) { + level->addParticle(eParticleType_largeexplode, x, y, z, 1.0f, 0, 0); + } else { + level->addParticle(eParticleType_hugeexplosion, x, y, z, 1.0f, 0, 0); + } // 4J - use pointer to vector directly passed in if this is available - used // to speed up calling this from an incoming packet std::vector* toBlowArray = toBlowDirect ? toBlowDirect : new std::vector(toBlow.begin(), toBlow.end()); - // toBlowArray.addAll(toBlow); - // TODO 4J Stu - Reverse iterator - PIXBeginNamedEvent(0, "Finalizing explosion size %d", toBlow.size()); - app.DebugPrintf("Finalizing explosion size %d\n", toBlow.size()); - static const int MAX_EXPLODE_PARTICLES = 50; - // 4J - try and make at most MAX_EXPLODE_PARTICLES pairs of particles - int fraction = (int)toBlowArray->size() / MAX_EXPLODE_PARTICLES; - if (fraction == 0) fraction = 1; - size_t j = toBlowArray->size() - 1; - // for (size_t j = toBlowArray->size() - 1; j >= 0; j--) - for (AUTO_VAR(it, toBlowArray->rbegin()); it != toBlowArray->rend(); ++it) { - TilePos* tp = &(*it); //&toBlowArray->at(j); - int xt = tp->x; - int yt = tp->y; - int zt = tp->z; - // if (xt >= 0 && yt >= 0 && zt >= 0 && xt < width && yt < depth && - // zt < height) { - int t = level->getTile(xt, yt, zt); + if (destroyBlocks) { + // toBlowArray.addAll(toBlow); + // TODO 4J Stu - Reverse iterator + PIXBeginNamedEvent(0, "Finalizing explosion size %d", toBlow.size()); + app.DebugPrintf("Finalizing explosion size %d\n", toBlow.size()); + static const int MAX_EXPLODE_PARTICLES = 50; + // 4J - try and make at most MAX_EXPLODE_PARTICLES pairs of particles + int fraction = (int)toBlowArray->size() / MAX_EXPLODE_PARTICLES; + if (fraction == 0) fraction = 1; + size_t j = toBlowArray->size() - 1; + // for (size_t j = toBlowArray->size() - 1; j >= 0; j--) + for (AUTO_VAR(it, toBlowArray->rbegin()); it != toBlowArray->rend(); + ++it) { + TilePos* tp = &(*it); //&toBlowArray->at(j); + int xt = tp->x; + int yt = tp->y; + int zt = tp->z; + // if (xt >= 0 && yt >= 0 && zt >= 0 && xt < width && yt < depth && + // zt < height) { + int t = level->getTile(xt, yt, zt); - if (generateParticles) { - if ((j % fraction) == 0) { - double xa = xt + level->random->nextFloat(); - double ya = yt + level->random->nextFloat(); - double za = zt + level->random->nextFloat(); + if (generateParticles) { + if ((j % fraction) == 0) { + double xa = xt + level->random->nextFloat(); + double ya = yt + level->random->nextFloat(); + double za = zt + level->random->nextFloat(); - double xd = xa - x; - double yd = ya - y; - double zd = za - z; + double xd = xa - x; + double yd = ya - y; + double zd = za - z; - double dd = sqrt(xd * xd + yd * yd + zd * zd); + double dd = sqrt(xd * xd + yd * yd + zd * zd); - xd /= dd; - yd /= dd; - zd /= dd; + xd /= dd; + yd /= dd; + zd /= dd; - double speed = 0.5 / (dd / r + 0.1); - speed *= - (level->random->nextFloat() * level->random->nextFloat() + - 0.3f); - xd *= speed; - yd *= speed; - zd *= speed; + double speed = 0.5 / (dd / r + 0.1); + speed *= (level->random->nextFloat() * + level->random->nextFloat() + + 0.3f); + xd *= speed; + yd *= speed; + zd *= speed; - level->addParticle(eParticleType_explode, (xa + x * 1) / 2, - (ya + y * 1) / 2, (za + z * 1) / 2, xd, yd, - zd); - level->addParticle(eParticleType_smoke, xa, ya, za, xd, yd, zd); + level->addParticle(eParticleType_explode, (xa + x * 1) / 2, + (ya + y * 1) / 2, (za + z * 1) / 2, xd, + yd, zd); + level->addParticle(eParticleType_smoke, xa, ya, za, xd, yd, + zd); + } } - } - if (t > 0) { - Tile::tiles[t]->spawnResources(level, xt, yt, zt, - level->getData(xt, yt, zt), 0.3f, 0); - level->setTile(xt, yt, zt, 0); - Tile::tiles[t]->wasExploded(level, xt, yt, zt); - } - // } + if (t > 0) { + Tile* tile = Tile::tiles[t]; - --j; + if (tile->dropFromExplosion(this)) { + tile->spawnResources(level, xt, yt, zt, + level->getData(xt, yt, zt), 1.0f / r, + 0); + } + level->setTileAndData(xt, yt, zt, 0, 0, Tile::UPDATE_ALL); + tile->wasExploded(level, xt, yt, zt, this); + } + + --j; + } } if (fire) { @@ -250,7 +272,7 @@ void Explosion::finalizeExplosion( 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->setTile(xt, yt, zt, Tile::fire_Id); + level->setTileAndUpdate(xt, yt, zt, Tile::fire_Id); } } } @@ -267,4 +289,13 @@ Vec3* Explosion::getHitPlayerKnockback(std::shared_ptr player) { if (it == hitPlayers.end()) return Vec3::newTemp(0.0, 0.0, 0.0); return it->second; +} + +std::shared_ptr Explosion::getSourceMob() { + if (source == NULL) return nullptr; + if (source->instanceof(eTYPE_PRIMEDTNT)) + return std::dynamic_pointer_cast(source)->getOwner(); + if (source->instanceof(eTYPE_LIVINGENTITY)) + return std::dynamic_pointer_cast(source); + return nullptr; } \ No newline at end of file diff --git a/Minecraft.World/Level/Explosion.h b/Minecraft.World/Level/Explosion.h index 39c1e96a6..46c67f272 100644 --- a/Minecraft.World/Level/Explosion.h +++ b/Minecraft.World/Level/Explosion.h @@ -43,4 +43,5 @@ public: NULL); // 4J - added toBlow parameter playerVec3Map* getHitPlayers(); Vec3* getHitPlayerKnockback(std::shared_ptr player); + std::shared_ptr getSourceMob(); }; \ No newline at end of file diff --git a/Minecraft.World/Level/GameRules.cpp b/Minecraft.World/Level/GameRules.cpp new file mode 100644 index 000000000..08436a330 --- /dev/null +++ b/Minecraft.World/Level/GameRules.cpp @@ -0,0 +1,191 @@ +#include "../Platform/stdafx.h" + +#include "GameRules.h" + +// 4J: GameRules isn't in use anymore, just routes any requests to app game host +// options, kept things commented out for context + +const int GameRules::RULE_DOFIRETICK = 0; +const int GameRules::RULE_MOBGRIEFING = 1; +const int GameRules::RULE_KEEPINVENTORY = 2; +const int GameRules::RULE_DOMOBSPAWNING = 3; +const int GameRules::RULE_DOMOBLOOT = 4; +const int GameRules::RULE_DOTILEDROPS = 5; +// const int GameRules::RULE_COMMANDBLOCKOUTPUT = 6; +const int GameRules::RULE_NATURAL_REGENERATION = 7; +const int GameRules::RULE_DAYLIGHT = 8; + +GameRules::GameRules() { + /*registerRule(RULE_DOFIRETICK, L"1"); + registerRule(RULE_MOBGRIEFING, L"1"); + registerRule(RULE_KEEPINVENTORY, L"0"); + registerRule(RULE_DOMOBSPAWNING, L"1"); + registerRule(RULE_DOMOBLOOT, L"1"); + registerRule(RULE_DOTILEDROPS, L"1"); + registerRule(RULE_COMMANDBLOCKOUTPUT, L"1"); + registerRule(RULE_NATURAL_REGENERATION, L"1"); + registerRule(RULE_DAYLIGHT, L"1");*/ +} + +GameRules::~GameRules() { + /*for(AUTO_VAR(it,rules.begin()); it != rules.end(); ++it) + { + delete it->second; + }*/ +} + +bool GameRules::getBoolean(const int rule) { + switch (rule) { + case GameRules::RULE_DOFIRETICK: + return app.GetGameHostOption(eGameHostOption_FireSpreads); + case GameRules::RULE_MOBGRIEFING: + return app.GetGameHostOption(eGameHostOption_MobGriefing); + case GameRules::RULE_KEEPINVENTORY: + return app.GetGameHostOption(eGameHostOption_KeepInventory); + case GameRules::RULE_DOMOBSPAWNING: + return app.GetGameHostOption(eGameHostOption_DoMobSpawning); + case GameRules::RULE_DOMOBLOOT: + return app.GetGameHostOption(eGameHostOption_DoMobLoot); + case GameRules::RULE_DOTILEDROPS: + return app.GetGameHostOption(eGameHostOption_DoTileDrops); + case GameRules::RULE_NATURAL_REGENERATION: + return app.GetGameHostOption(eGameHostOption_NaturalRegeneration); + case GameRules::RULE_DAYLIGHT: + return app.GetGameHostOption(eGameHostOption_DoDaylightCycle); + default: + assert(0); + return false; + } +} + +/* +void GameRules::registerRule(const std::wstring &name, const std::wstring +&startValue) +{ + rules[name] = new GameRule(startValue); +} + +void GameRules::set(const std::wstring &ruleName, const std::wstring &newValue) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + gameRule->set(newValue); + } + else + { + registerRule(ruleName, newValue); + } +} + +std::wstring GameRules::get(const std::wstring &ruleName) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + return gameRule->get(); + } + return L""; +} + +int GameRules::getInt(const std::wstring &ruleName) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + return gameRule->getInt(); + } + return 0; +} + +double GameRules::getDouble(const std::wstring &ruleName) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + return gameRule->getDouble(); + } + return 0; +} + +CompoundTag *GameRules::createTag() +{ + CompoundTag *result = new CompoundTag(L"GameRules"); + + for(AUTO_VAR(it,rules.begin()); it != rules.end(); ++it) + { + GameRule *gameRule = it->second; + result->putString(it->first, gameRule->get()); + } + + return result; +} + +void GameRules::loadFromTag(CompoundTag *tag) +{ + vector *allTags = tag->getAllTags(); + for (AUTO_VAR(it, allTags->begin()); it != allTags->end(); ++it) + { + Tag *ruleTag = *it; + std::wstring ruleName = ruleTag->getName(); + std::wstring value = tag->getString(ruleTag->getName()); + + set(ruleName, value); + } + delete allTags; +} + +// Need to delete returned vector. +vector *GameRules::getRuleNames() +{ + vector *out = new vector(); + for (AUTO_VAR(it, rules.begin()); it != rules.end(); it++) +out->push_back(it->first); return out; +} + +bool GameRules::contains(const std::wstring &rule) +{ + AUTO_VAR(it, rules.find(rule)); + return it != rules.end(); +} + +GameRules::GameRule::GameRule(const std::wstring &startValue) +{ + value = L""; + booleanValue = false; + intValue = 0; + doubleValue = 0.0; + set(startValue); +} + +void GameRules::GameRule::set(const std::wstring &newValue) +{ + value = newValue; + booleanValue = _fromString(newValue); + intValue = _fromString(newValue); + doubleValue = _fromString(newValue); +} + +std::wstring GameRules::GameRule::get() +{ + return value; +} + +bool GameRules::GameRule::getBoolean() +{ + return booleanValue; +} + +int GameRules::GameRule::getInt() +{ + return intValue; +} + +double GameRules::GameRule::getDouble() +{ + return doubleValue; +}*/ \ No newline at end of file diff --git a/Minecraft.World/Level/GameRules.h b/Minecraft.World/Level/GameRules.h new file mode 100644 index 000000000..d41080771 --- /dev/null +++ b/Minecraft.World/Level/GameRules.h @@ -0,0 +1,54 @@ +#pragma once + +class GameRules { +private: + class GameRule { + private: + std::wstring value; + bool booleanValue; + int intValue; + double doubleValue; + + public: + GameRule(const std::wstring& startValue); + + void set(const std::wstring& newValue); + std::wstring get(); + bool getBoolean(); + int getInt(); + double getDouble(); + }; + +public: + // 4J: Originally strings + // default rules + static const int RULE_DOFIRETICK; + static const int RULE_MOBGRIEFING; + static const int RULE_KEEPINVENTORY; + static const int RULE_DOMOBSPAWNING; + static const int RULE_DOMOBLOOT; + static const int RULE_DOTILEDROPS; + static const int RULE_COMMANDBLOCKOUTPUT; + static const int RULE_NATURAL_REGENERATION; + static const int RULE_DAYLIGHT; + +private: + std::unordered_map rules; + +public: + GameRules(); + ~GameRules(); + + bool getBoolean(const int rule); + + // 4J: Removed unused functions + /*void set(const std::wstring &ruleName, const std::wstring &newValue); + void registerRule(const std::wstring &name, const std::wstring &startValue); + std::wstring get(const std::wstring &ruleName); + int getInt(const std::wstring &ruleName); + double getDouble(const std::wstring &ruleName); + CompoundTag *createTag(); + void loadFromTag(CompoundTag *tag); + vector *getRuleNames(); + bool contains(const std::wstring &rule);*/ +}; \ No newline at end of file diff --git a/Minecraft.World/Level/Level.cpp b/Minecraft.World/Level/Level.cpp index ebd444b9a..8a88dd68f 100644 --- a/Minecraft.World/Level/Level.cpp +++ b/Minecraft.World/Level/Level.cpp @@ -18,14 +18,11 @@ #include "../Headers/net.minecraft.world.level.levelgen.h" #include "../Headers/net.minecraft.world.level.storage.h" #include "../Headers/net.minecraft.world.level.pathfinder.h" +#include "../Headers/net.minecraft.world.level.redstone.h" +#include "../Headers/net.minecraft.world.scores.h" #include "../Headers/net.minecraft.world.phys.h" -#include "ChunkPos.h" #include "Explosion.h" #include "Events/LevelListener.h" -#include "../Util/LightLayer.h" -#include "../Blocks/MobSpawner.h" -#include "Storage/Region.h" -#include "TickNextTickData.h" #include "Level.h" #include "../Util/ThreadName.h" #include "../Util/WeighedRandom.h" @@ -41,6 +38,7 @@ #include "../../Minecraft.Client/Textures/Packs/DLCTexturePack.h" #include "../../Minecraft.Client/Platform/Common/DLC/DLCPack.h" #include "../../Minecraft.Client/Platform/PS3/PS3Extras/ShutdownManager.h" +#include "../../Minecraft.Client/MinecraftServer.h" #include namespace { @@ -140,15 +138,72 @@ void Level::destroyLightingCache() { XPhysicalFree(cache); } -void Level::initCache(lightCache_t* cache) { +inline int GetIndex(int x, int y, int z) { + return ((x & 15) << 8) | ((y & 15) << 4) | (z & 15); +} + +void Level::initCachePartial(lightCache_t* cache, int xc, int yc, int zc) { cachewritten = false; if (cache == NULL) return; + int idx; + if (!(yc & 0xffffff00)) { + idx = GetIndex(xc, yc, zc); + cache[idx] = 0; + idx = GetIndex(xc - 1, yc, zc); + cache[idx] = 0; + idx = GetIndex(xc + 1, yc, zc); + cache[idx] = 0; + idx = GetIndex(xc, yc, zc - 1); + cache[idx] = 0; + idx = GetIndex(xc, yc, zc + 1); + cache[idx] = 0; + } + if (!((yc - 1) & 0xffffff00)) { + idx = GetIndex(xc, yc - 1, zc); + cache[idx] = 0; + } + if (!((yc + 1) & 0xffffff00)) { + idx = GetIndex(xc, yc + 1, zc); + cache[idx] = 0; + } +} + +void Level::initCacheComplete(lightCache_t* cache, int xc, int yc, int zc) { + lightCache_t old[7]; + if (!(yc & 0xffffff00)) { + old[0] = cache[GetIndex(xc, yc, zc)]; + old[1] = cache[GetIndex(xc - 1, yc, zc)]; + old[2] = cache[GetIndex(xc + 1, yc, zc)]; + old[5] = cache[GetIndex(xc, yc, zc - 1)]; + old[6] = cache[GetIndex(xc, yc, zc + 1)]; + } + if (!((yc - 1) & 0xffffff00)) { + old[3] = cache[GetIndex(xc, yc - 1, zc)]; + } + if (!((yc + 1) & 0xffffff00)) { + old[4] = cache[GetIndex(xc, yc + 1, zc)]; + } + XMemSet128(cache, 0, 16 * 16 * 16 * sizeof(lightCache_t)); + + if (!(yc & 0xffffff00)) { + cache[GetIndex(xc, yc, zc)] = old[0]; + cache[GetIndex(xc - 1, yc, zc)] = old[1]; + cache[GetIndex(xc + 1, yc, zc)] = old[2]; + cache[GetIndex(xc, yc, zc - 1)] = old[5]; + cache[GetIndex(xc, yc, zc + 1)] = old[6]; + } + if (!((yc - 1) & 0xffffff00)) { + cache[GetIndex(xc, yc - 1, zc)] = old[3]; + } + if (!((yc + 1) & 0xffffff00)) { + cache[GetIndex(xc, yc + 1, zc)] = old[4]; + } } // Set a brightness value, going through the cache if enabled for this thread -void inline Level::setBrightnessCached(lightCache_t* cache, __uint64* cacheUse, +void inline Level::setBrightnessCached(lightCache_t* cache, uint64_t* cacheUse, LightLayer::variety layer, int x, int y, int z, int brightness) { if (cache == NULL) { @@ -162,8 +217,8 @@ void inline Level::setBrightnessCached(lightCache_t* cache, __uint64* cacheUse, ((x & 0x3f0) << 6) | ((y & 0x0f0) << 2) | ((z & 0x3f0) >> 4); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z - posbits |= ((((__uint64)x) & 0x3FFFC00L) << 38) | - ((((__uint64)z) & 0x3FFFC00L) << 22); + posbits |= ((((uint64_t)x) & 0x3FFFC00L) << 38) | + ((((uint64_t)z) & 0x3FFFC00L) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -222,8 +277,8 @@ inline int Level::getBrightnessCached(lightCache_t* cache, ((x & 0x3f0) << 6) | ((y & 0x0f0) << 2) | ((z & 0x3f0) >> 4); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z - posbits |= ((((__uint64)x) & 0x3FFFC00L) << 38) | - ((((__uint64)z) & 0x3FFFC00L) << 22); + posbits |= ((((uint64_t)x) & 0x3FFFC00L) << 38) | + ((((uint64_t)z) & 0x3FFFC00L) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -281,8 +336,8 @@ inline int Level::getEmissionCached(lightCache_t* cache, int ct, int x, int y, ((x & 0x3f0) << 6) | ((y & 0x0f0) << 2) | ((z & 0x3f0) >> 4); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z - posbits |= ((((__uint64)x) & 0x3FFFC00) << 38) | - ((((__uint64)z) & 0x3FFFC00) << 22); + posbits |= ((((uint64_t)x) & 0x3FFFC00) << 38) | + ((((uint64_t)z) & 0x3FFFC00) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -349,8 +404,8 @@ inline int Level::getBlockingCached(lightCache_t* cache, ((x & 0x3f0) << 6) | ((y & 0x0f0) << 2) | ((z & 0x3f0) >> 4); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z - posbits |= ((((__uint64)x) & 0x3FFFC00L) << 38) | - ((((__uint64)z) & 0x3FFFC00L) << 22); + posbits |= ((((uint64_t)x) & 0x3FFFC00L) << 38) | + ((((uint64_t)z) & 0x3FFFC00L) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -411,7 +466,7 @@ inline int Level::getBlockingCached(lightCache_t* cache, // renderer know what has been updated (2) it lets the lighting actually // complete before we get any visual representation of the update, otherwise we // end up seeing some strange partial updates -void Level::flushCache(lightCache_t* cache, __uint64 cacheUse, +void Level::flushCache(lightCache_t* cache, uint64_t cacheUse, LightLayer::variety layer) { // cacheUse has a single bit for each x, y and z to say whether anything // with that x, y or z has been written to @@ -494,11 +549,7 @@ void Level::_init() { oThunderLevel = thunderLevel = 0.0f; - lightningTime = 0; - - lightningBoltTime = 0; - - noNeighborUpdate = false; + skyFlashTime = 0; difficulty = 0; @@ -528,11 +579,10 @@ void Level::_init() { InitializeCriticalSection(&m_entitiesCS); InitializeCriticalSection(&m_tileEntityListCS); - m_timeOfDayOverride = -1; - updatingTileEntities = false; villageSiege = new VillageSiege(this); + scoreboard = new Scoreboard(); toCheckLevel = new int[32 * 32 * 32]; // 4J - brought forward from 1.8.2 InitializeCriticalSectionAndSpinCount( @@ -568,14 +618,14 @@ Level::Level(std::shared_ptr levelStorage, : seaLevel(constSeaLevel) { _init(); this->levelStorage = - levelStorage; // std::shared_ptr(levelStorage); + levelStorage; // shared_ptr(levelStorage); this->dimension = dimension; - this->levelData = new LevelData(levelSettings, name); + levelData = new LevelData(levelSettings, name); if (!this->levelData->useNewSeaLevel()) seaLevel = Level::genDepth / 2; // 4J added - sea level is one unit lower since 1.8.2, // maintain older height for old levels - this->savedDataStorage = new SavedDataStorage(levelStorage.get()); + savedDataStorage = new SavedDataStorage(levelStorage.get()); std::shared_ptr savedVillages = std::dynamic_pointer_cast( @@ -596,34 +646,6 @@ Level::Level(std::shared_ptr levelStorage, prepareWeather(); } -Level::Level(Level* level, Dimension* dimension) : seaLevel(constSeaLevel) { - _init(); - this->levelStorage = level->levelStorage; - this->levelData = new LevelData(level->levelData); - if (!this->levelData->useNewSeaLevel()) - seaLevel = Level::genDepth / - 2; // 4J added - sea level is one unit lower since 1.8.2, - // maintain older height for old levels - this->savedDataStorage = new SavedDataStorage(levelStorage.get()); - - std::shared_ptr savedVillages = - std::dynamic_pointer_cast( - savedDataStorage->get(typeid(Villages), Villages::VILLAGE_FILE_ID)); - if (savedVillages == NULL) { - villages = std::shared_ptr(new Villages(this)); - savedDataStorage->set(Villages::VILLAGE_FILE_ID, villages); - } else { - villages = savedVillages; - villages->setLevel(this); - } - - this->dimension = dimension; - dimension->init(this); - chunkSource = NULL; - updateSkyBrightness(); - prepareWeather(); -} - Level::Level(std::shared_ptr levelStorage, const std::wstring& levelName, LevelSettings* levelSettings) : seaLevel(constSeaLevel) { @@ -643,8 +665,8 @@ void Level::_init(std::shared_ptr levelStorage, Dimension* fixedDimension, bool doCreateChunkSource) { _init(); this->levelStorage = - levelStorage; // std::shared_ptr(levelStorage); - this->savedDataStorage = new SavedDataStorage(levelStorage.get()); + levelStorage; // shared_ptr(levelStorage); + savedDataStorage = new SavedDataStorage(levelStorage.get()); std::shared_ptr savedVillages = std::dynamic_pointer_cast( @@ -707,6 +729,8 @@ Level::~Level() { delete chunkSource; delete levelData; delete toCheckLevel; + delete scoreboard; + delete villageSiege; if (!isClientSide) { NotGateTile::removeLevelReferences(this); // 4J added @@ -726,8 +750,8 @@ Level::~Level() { // LevelRenderer /* for(int i = 0; i < listeners.size(); i++) - delete listeners[i]; - */ + delete listeners[i]; + */ } void Level::initializeLevel(LevelSettings* settings) { @@ -787,6 +811,15 @@ int Level::getTileRenderShape(int x, int y, int z) { return Tile::SHAPE_INVISIBLE; } +// 4J Added to slightly optimise and avoid getTile call if we already know the +// tile +int Level::getTileRenderShape(int t) { + if (Tile::tiles[t] != NULL) { + return Tile::tiles[t]->getRenderShape(); + } + return Tile::SHAPE_INVISIBLE; +} + bool Level::hasChunkAt(int x, int y, int z) { if (y < minBuildHeight || y >= maxBuildHeight) return false; return hasChunk(x >> 4, z >> 4); @@ -849,12 +882,8 @@ LevelChunk* Level::getChunk(int x, int z) { return this->chunkSource->getChunk(x, z); } -bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data) { - return setTileAndDataNoUpdate(x, y, z, tile, data, true); -} - -bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data, - bool informClients) { +bool Level::setTileAndData(int x, int y, int z, int tile, int data, + int updateFlags) { if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) { return false; @@ -862,50 +891,39 @@ bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data, if (y < 0) return false; if (y >= maxBuildHeight) return false; LevelChunk* c = getChunk(x >> 4, z >> 4); - // 4J - changes for lighting brought forward from 1.8.2 + + int oldTile = 0; + if ((updateFlags & Tile::UPDATE_NEIGHBORS) != 0) { + oldTile = c->getTile(x & 15, y, z & 15); + } bool result; #ifndef _CONTENT_PACKAGE int old = c->getTile(x & 15, y, z & 15); int olddata = c->getData(x & 15, y, z & 15); #endif result = c->setTileAndData(x & 15, y, z & 15, tile, data); + if (updateFlags != Tile::UPDATE_INVISIBLE_NO_LIGHT) { #ifndef _CONTENT_PACKAGE - PIXBeginNamedEvent(0, "Checking light %d %d %d", x, y, z); - PIXBeginNamedEvent(0, "was %d, %d now %d, %d", old, olddata, tile, data); + PIXBeginNamedEvent(0, "Checking light %d %d %d", x, y, z); + PIXBeginNamedEvent(0, "was %d, %d now %d, %d", old, olddata, tile, + data); #endif - this->checkLight(x, y, z); - PIXEndNamedEvent(); - PIXEndNamedEvent(); - if (informClients && result && (isClientSide || c->seenByPlayer)) - sendTileUpdated(x, y, z); - return result; -} - -bool Level::setTileNoUpdate(int x, int y, int z, int tile) { - if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || - z >= MAX_LEVEL_SIZE) { - return false; + checkLight(x, y, z); + PIXEndNamedEvent(); + PIXEndNamedEvent(); } - if (y < 0) return false; - if (y >= maxBuildHeight) return false; - LevelChunk* c = getChunk(x >> 4, z >> 4); - // 4J - changes for lighting brought forward from 1.8.2 - bool result = c->setTile(x & 15, y, z & 15, tile); - this->checkLight(x, y, z); - if (result && (isClientSide || c->seenByPlayer)) sendTileUpdated(x, y, z); - return result; -} - -bool Level::setTileNoUpdateNoLightCheck(int x, int y, int z, int tile) { - if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || - z >= MAX_LEVEL_SIZE) { - return false; + if (result) { + if ((updateFlags & Tile::UPDATE_CLIENTS) != 0 && + !(isClientSide && (updateFlags & Tile::UPDATE_INVISIBLE) != 0)) { + sendTileUpdated(x, y, z); + } + if (!isClientSide && (updateFlags & Tile::UPDATE_NEIGHBORS) != 0) { + tileUpdated(x, y, z, oldTile); + Tile* tobj = Tile::tiles[tile]; + if (tobj != NULL && tobj->hasAnalogOutputSignal()) + updateNeighbourForOutputSignal(x, y, z, tile); + } } - if (y < 0) return false; - if (y >= maxBuildHeight) return false; - LevelChunk* c = getChunk(x >> 4, z >> 4); - // 4J - changes for lighting brought forward from 1.8.2 - bool result = c->setTile(x & 15, y, z & 15, tile); return result; } @@ -928,15 +946,9 @@ int Level::getData(int x, int y, int z) { return c->getData(x, y, z); } -void Level::setData(int x, int y, int z, int data, - bool forceUpdate /*=false*/) // 4J added forceUpdate +bool Level::setData(int x, int y, int z, int data, int updateFlags, + bool forceUpdate /*=false*/) // 4J added forceUpdate) { - if (setDataNoUpdate(x, y, z, data) || forceUpdate) { - tileUpdated(x, y, z, getTile(x, y, z)); - } -} - -bool Level::setDataNoUpdate(int x, int y, int z, int data) { if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) { return false; @@ -961,26 +973,62 @@ bool Level::setDataNoUpdate(int x, int y, int z, int data) { bool maskedBitsChanged; bool result = c->setData(cx, y, cz, data, importantMask, &maskedBitsChanged); - if (result && (isClientSide || - (c->seenByPlayer && sendTileData && maskedBitsChanged))) - sendTileUpdated(x, y, z); + if (result || forceUpdate) { + int tile = c->getTile(cx, y, cz); + if (forceUpdate || + ((updateFlags & Tile::UPDATE_CLIENTS) != 0 && + !(isClientSide && (updateFlags & Tile::UPDATE_INVISIBLE) != 0))) { + sendTileUpdated(x, y, z); + } + if (!isClientSide && + (forceUpdate || (updateFlags & Tile::UPDATE_NEIGHBORS) != 0)) { + tileUpdated(x, y, z, tile); + Tile* tobj = Tile::tiles[tile]; + if (tobj != NULL && tobj->hasAnalogOutputSignal()) + updateNeighbourForOutputSignal(x, y, z, tile); + } + } return result; } -bool Level::setTile(int x, int y, int z, int tile) { - if (setTileNoUpdate(x, y, z, tile)) { - tileUpdated(x, y, z, tile); - return true; +/** + * Sets a tile to air without dropping resources or showing any animation. + * + * @param x + * @param y + * @param z + * @return + */ +bool Level::removeTile(int x, int y, int z) { + return setTileAndData(x, y, z, 0, 0, Tile::UPDATE_ALL); +} + +/** + * Sets a tile to air and plays a destruction animation, with option to also + * drop resources. + * + * @param x + * @param y + * @param z + * @param dropResources + * @return True if anything was changed + */ +bool Level::destroyTile(int x, int y, int z, bool dropResources) { + int tile = getTile(x, y, z); + if (tile > 0) { + int data = getData(x, y, z); + levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, + tile + (data << Tile::TILE_NUM_SHIFT)); + if (dropResources) { + Tile::tiles[tile]->spawnResources(this, x, y, z, data, 0); + } + return setTileAndData(x, y, z, 0, 0, Tile::UPDATE_ALL); } return false; } -bool Level::setTileAndData(int x, int y, int z, int tile, int data) { - if (setTileAndDataNoUpdate(x, y, z, tile, data)) { - tileUpdated(x, y, z, tile); - return true; - } - return false; +bool Level::setTileAndUpdate(int x, int y, int z, int tile) { + return setTileAndData(x, y, z, tile, 0, Tile::UPDATE_ALL); } void Level::sendTileUpdated(int x, int y, int z) { @@ -991,7 +1039,7 @@ void Level::sendTileUpdated(int x, int y, int z) { } void Level::tileUpdated(int x, int y, int z, int tile) { - this->updateNeighborsAt(x, y, z, tile); + updateNeighborsAt(x, y, z, tile); } void Level::lightColumnChanged(int x, int z, int y0, int y1) { @@ -1031,19 +1079,6 @@ void Level::setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1) { } } -void Level::swap(int x1, int y1, int z1, int x2, int y2, int z2) { - int t1 = getTile(x1, y1, z1); - int d1 = getData(x1, y1, z1); - int t2 = getTile(x2, y2, z2); - int d2 = getData(x2, y2, z2); - - setTileAndDataNoUpdate(x1, y1, z1, t2, d2); - setTileAndDataNoUpdate(x2, y2, z2, t1, d1); - - updateNeighborsAt(x1, y1, z1, t2); - updateNeighborsAt(x2, y2, z2, t1); -} - void Level::updateNeighborsAt(int x, int y, int z, int tile) { neighborChanged(x - 1, y, z, tile); neighborChanged(x + 1, y, z, tile); @@ -1053,10 +1088,28 @@ void Level::updateNeighborsAt(int x, int y, int z, int tile) { neighborChanged(x, y, z + 1, tile); } +void Level::updateNeighborsAtExceptFromFacing(int x, int y, int z, int tile, + int skipFacing) { + if (skipFacing != Facing::WEST) neighborChanged(x - 1, y, z, tile); + if (skipFacing != Facing::EAST) neighborChanged(x + 1, y, z, tile); + if (skipFacing != Facing::DOWN) neighborChanged(x, y - 1, z, tile); + if (skipFacing != Facing::UP) neighborChanged(x, y + 1, z, tile); + if (skipFacing != Facing::NORTH) neighborChanged(x, y, z - 1, tile); + if (skipFacing != Facing::SOUTH) neighborChanged(x, y, z + 1, tile); +} + void Level::neighborChanged(int x, int y, int z, int type) { - if (noNeighborUpdate || isClientSide) return; - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL) tile->neighborChanged(this, x, y, z, type); + if (isClientSide) return; + int id = getTile(x, y, z); + Tile* tile = Tile::tiles[id]; + + if (tile != NULL) { + tile->neighborChanged(this, x, y, z, type); + } +} + +bool Level::isTileToBeTickedAt(int x, int y, int z, int tileId) { + return false; } bool Level::canSeeSky(int x, int y, int z) { @@ -1081,23 +1134,17 @@ int Level::getRawBrightness(int x, int y, int z, bool propagate) { if (propagate) { int id = getTile(x, y, z); - switch (id) { - case Tile::stoneSlabHalf_Id: - case Tile::woodSlabHalf_Id: - case Tile::farmland_Id: - case Tile::stairs_stone_Id: - case Tile::stairs_wood_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; - } break; + if (Tile::propagate[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; } } @@ -1138,6 +1185,17 @@ int Level::getHeightmap(int x, int z) { return c->getHeightmap(x & 15, z & 15); } +int Level::getLowestHeightmap(int x, int z) { + if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || + z >= MAX_LEVEL_SIZE) { + return 0; + } + if (!hasChunk(x >> 4, z >> 4)) return 0; + + LevelChunk* c = getChunk(x >> 4, z >> 4); + return c->lowestHeightmap; +} + void Level::updateLightIfOtherThan(LightLayer::variety layer, int x, int y, int z, int expected) { if (dimension->hasCeiling && layer == LightLayer::Sky) return; @@ -1347,7 +1405,7 @@ float Level::getBrightness(int x, int y, int z) { return dimension->brightnessRamp[getRawBrightness(x, y, z)]; } -bool Level::isDay() { return this->skyDarken < 4; } +bool Level::isDay() { return skyDarken < 4; } HitResult* Level::clip(Vec3* a, Vec3* b) { return clip(a, b, false, false); } @@ -1493,8 +1551,8 @@ HitResult* Level::clip(Vec3* a, Vec3* b, bool liquid, bool solidOnly) { return NULL; } -void Level::playSound(std::shared_ptr entity, int iSound, float volume, - float pitch) { +void Level::playEntitySound(std::shared_ptr entity, int iSound, + float volume, float pitch) { if (entity == NULL) return; AUTO_VAR(itEnd, listeners.end()); for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) { @@ -1502,7 +1560,7 @@ void Level::playSound(std::shared_ptr entity, int iSound, float volume, if (entity->GetType() == eTYPE_SERVERPLAYER) { // app.DebugPrintf("ENTITY is serverplayer\n"); - (*it)->playSound(entity, iSound, entity->x, + (*it)->playSound(iSound, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); } else { @@ -1513,7 +1571,18 @@ void Level::playSound(std::shared_ptr entity, int iSound, float volume, } } -// void Level::playSound(double x, double y, double z, const std::wstring& name, +void Level::playPlayerSound(std::shared_ptr entity, int iSound, + float volume, float pitch) { + if (entity == NULL) return; + AUTO_VAR(itEnd, listeners.end()); + for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) { + (*it)->playSoundExceptPlayer(entity, iSound, entity->x, + entity->y - entity->heightOffset, + entity->z, volume, pitch); + } +} + +// void Level::playSound(double x, double y, double z, const wstring& name, // float volume, float pitch) void Level::playSound(double x, double y, double z, int iSound, float volume, float pitch, float fClipSoundDist) { @@ -1524,7 +1593,8 @@ void Level::playSound(double x, double y, double z, int iSound, float volume, } void Level::playLocalSound(double x, double y, double z, int iSound, - float volume, float pitch, float fClipSoundDist) {} + float volume, float pitch, bool distanceDelay, + float fClipSoundDist) {} void Level::playStreamingMusic(const std::wstring& name, int x, int y, int z) { AUTO_VAR(itEnd, listeners.end()); @@ -1533,17 +1603,17 @@ void Level::playStreamingMusic(const std::wstring& name, int x, int y, int z) { } } -void Level::playMusic(double x, double y, double z, const std::wstring& string, - float volume) {} +void Level::playMusic(double x, double y, double z, + const std::wstring& std::string, float volume) {} // 4J removed - /* -void Level::addParticle(const std::wstring& id, double x, double y, double z, -double xd, double yd, double zd) +void Level::addParticle(const wstring& id, double x, double y, double z, double +xd, double yd, double zd) { - AUTO_VAR(itEnd, listeners.end()); - for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) - (*it)->addParticle(id, x, y, z, xd, yd, zd); +AUTO_VAR(itEnd, listeners.end()); +for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) +(*it)->addParticle(id, x, y, z, xd, yd, zd); } */ @@ -1570,13 +1640,13 @@ bool Level::addEntity(std::shared_ptr e) { return false; } - bool forced = false; - if (std::dynamic_pointer_cast(e) != NULL) { + bool forced = e->forcedLoading; + if (e->instanceof(eTYPE_PLAYER)) { forced = true; } if (forced || hasChunk(xc, zc)) { - if (std::dynamic_pointer_cast(e) != NULL) { + if (e->instanceof(eTYPE_PLAYER)) { std::shared_ptr player = std::dynamic_pointer_cast(e); @@ -1636,7 +1706,7 @@ void Level::removeEntity(std::shared_ptr e) { e->ride(nullptr); } e->remove(); - if (std::dynamic_pointer_cast(e) != NULL) { + if (e->instanceof(eTYPE_PLAYER)) { std::vector >::iterator it = players.begin(); std::vector >::iterator itEnd = players.end(); while (it != itEnd && *it != std::dynamic_pointer_cast(e)) it++; @@ -1655,7 +1725,7 @@ void Level::removeEntity(std::shared_ptr e) { void Level::removeEntityImmediately(std::shared_ptr e) { e->remove(); - if (std::dynamic_pointer_cast(e) != NULL) { + if (e->instanceof(eTYPE_PLAYER)) { std::vector >::iterator it = players.begin(); std::vector >::iterator itEnd = players.end(); while (it != itEnd && *it != std::dynamic_pointer_cast(e)) it++; @@ -1702,7 +1772,8 @@ void Level::removeListener(LevelListener* listener) { // 4J - added noEntities and blockAtEdge parameter AABBList* Level::getCubes(std::shared_ptr source, AABB* box, - bool noEntities, bool blockAtEdge) { + bool noEntities /* = false*/, + bool blockAtEdge /* = false*/) { boxes.clear(); int x0 = Mth::floor(box->x0); int x1 = Mth::floor(box->x1 + 1); @@ -1720,7 +1791,7 @@ AABBList* Level::getCubes(std::shared_ptr source, AABB* box, if (blockAtEdge && ((x < minxz) || (x >= maxxz) || (z < minxz) || (z >= maxxz))) { for (int y = y0 - 1; y < y1; y++) { - Tile::rock->addAABBs(this, x, y, z, box, &boxes, source); + Tile::stone->addAABBs(this, x, y, z, box, &boxes, source); } } else { if (hasChunkAt(x, 64, z)) { @@ -1740,7 +1811,7 @@ AABBList* Level::getCubes(std::shared_ptr source, AABB* box, for (int y = y0 - 1; y < 0; y++) { for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { - Tile::rock->addAABBs(this, x, y, z, box, &boxes, source); + Tile::stone->addAABBs(this, x, y, z, box, &boxes, source); } } } @@ -1750,7 +1821,7 @@ AABBList* Level::getCubes(std::shared_ptr source, AABB* box, for (int y = maxMovementHeight; y < y1; y++) { for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { - Tile::rock->addAABBs(this, x, y, z, box, &boxes, source); + Tile::stone->addAABBs(this, x, y, z, box, &boxes, source); } } } @@ -1788,7 +1859,7 @@ AABBList* Level::getCubes(std::shared_ptr source, AABB* box, // 4J Stu - Brought forward from 12w36 to fix #46282 - TU5: Gameplay: Exiting // the minecart in a tight corridor damages the player -AABBList* Level::getTileCubes(AABB* box, bool blockAtEdge) { +AABBList* Level::getTileCubes(AABB* box, bool blockAtEdge /* = false */) { return getCubes(nullptr, box, true, blockAtEdge); // boxes.clear(); // int x0 = Mth::floor(box->x0); @@ -1893,8 +1964,8 @@ Vec3* Level::getSkyColor(std::shared_ptr source, float a) { b = b * ba + mid * (1 - ba); } - if (lightningBoltTime > 0) { - float f = (lightningBoltTime - a); + if (skyFlashTime > 0) { + float f = (skyFlashTime - a); if (f > 1) f = 1; f = f * 0.45f; r = r * (1 - f) + 0.8f * f; @@ -1915,16 +1986,17 @@ float Level::getTimeOfDay(float a) { // 4J Added if so we can override timeOfDay without changing the time that // affects ticking of things - if (m_timeOfDayOverride >= 0) { - return dimension->getTimeOfDay(m_timeOfDayOverride, a); - } else { - return dimension->getTimeOfDay(levelData->getTime(), a); - ; - } + return dimension->getTimeOfDay(levelData->getDayTime(), a); + ; } -int Level::getMoonPhase(float a) { - return dimension->getMoonPhase(levelData->getTime(), a); +int Level::getMoonPhase() { + return dimension->getMoonPhase(levelData->getDayTime()); +} + +float Level::getMoonBrightness() { + return Dimension::MOON_BRIGHTNESS_PER_PHASE[dimension->getMoonPhase( + levelData->getDayTime())]; } float Level::getSunAngle(float a) { @@ -2030,24 +2102,26 @@ float Level::getStarBrightness(float a) { void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay) {} -void Level::forceAddTileTick(int x, int y, int z, int tileId, int tickDelay) {} +void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay, + int priorityTilt) {} + +void Level::forceAddTileTick(int x, int y, int z, int tileId, int tickDelay, + int prioTilt) {} void Level::tickEntities() { - // for (int i = 0; i < globalEntities.size(); i++) std::vector >::iterator itGE = globalEntities.begin(); while (itGE != globalEntities.end()) { - std::shared_ptr e = *itGE; // globalEntities.at(i); + std::shared_ptr e = *itGE; + e->tickCount++; e->tick(); if (e->removed) { - // globalEntities.remove(i--); itGE = globalEntities.erase(itGE); } else { itGE++; } } - // entities.removeAll(entitiesToRemove); EnterCriticalSection(&m_entitiesCS); for (AUTO_VAR(it, entities.begin()); it != entities.end();) { @@ -2107,8 +2181,7 @@ void Level::tickEntities() { if (!e->removed) { #ifndef _FINAL_BUILD if (!(app.DebugSettingsOn() && app.GetMobsDontTickEnabled() && - (std::dynamic_pointer_cast(e) != NULL) && - (std::dynamic_pointer_cast(e) == NULL))) + e->instanceof(eTYPE_MOB) && !e->instanceof(eTYPE_PLAYER))) #endif { tick(e); @@ -2143,7 +2216,7 @@ void Level::tickEntities() { updatingTileEntities = true; for (AUTO_VAR(it, tileEntityList.begin()); it != tileEntityList.end();) { std::shared_ptr te = - *it; // tilestd::vector >.at(i); + *it; // tilevector >.at(i); if (!te->isRemoved() && te->hasLevel()) { if (hasChunkAt(te->x, te->y, te->z)) { #ifdef _LARGE_WORLDS @@ -2266,6 +2339,7 @@ void Level::tick(std::shared_ptr e, bool actual) { if (actual && e->inChunk) #endif { + e->tickCount++; if (e->riding != NULL) { e->rideTick(); } else { @@ -2442,8 +2516,8 @@ bool Level::checkAndHandleWater(AABB* box, Material* material, bool ok = false; Vec3* current = Vec3::newTemp(0, 0, 0); - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) + for (int x = x0; x < x1; x++) { + for (int y = y0; y < y1; y++) { for (int z = z0; z < z1; z++) { Tile* tile = Tile::tiles[getTile(x, y, z)]; if (tile != NULL && tile->material == material) { @@ -2455,7 +2529,9 @@ bool Level::checkAndHandleWater(AABB* box, Material* material, } } } - if (current->length() > 0) { + } + } + if (current->length() > 0 && e->isPushedByWater()) { current = current->normalize(); double pow = 0.014; e->xd += current->x * pow; @@ -2473,14 +2549,16 @@ bool Level::containsMaterial(AABB* box, Material* material) { int z0 = Mth::floor(box->z0); int z1 = Mth::floor(box->z1 + 1); - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) + for (int x = x0; x < x1; x++) { + for (int y = y0; y < y1; y++) { for (int z = z0; z < z1; z++) { Tile* tile = Tile::tiles[getTile(x, y, z)]; if (tile != NULL && tile->material == material) { return true; } } + } + } return false; } @@ -2492,8 +2570,8 @@ bool Level::containsLiquid(AABB* box, Material* material) { int z0 = Mth::floor(box->z0); int z1 = Mth::floor(box->z1 + 1); - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) + for (int x = x0; x < x1; x++) { + for (int y = y0; y < y1; y++) { for (int z = z0; z < z1; z++) { Tile* tile = Tile::tiles[getTile(x, y, z)]; if (tile != NULL && tile->material == material) { @@ -2507,6 +2585,8 @@ bool Level::containsLiquid(AABB* box, Material* material) { } } } + } + } return false; } @@ -2562,23 +2642,23 @@ bool Level::extinguishFire(std::shared_ptr player, int x, int y, int z, if (getTile(x, y, z) == Tile::fire_Id) { levelEvent(player, LevelEvent::SOUND_FIZZ, x, y, z, 0); - setTile(x, y, z, 0); + removeTile(x, y, z); return true; } return false; } /* -std::shared_ptr Level::findSubclassOf(Entity::Class *entityClass) +shared_ptr Level::findSubclassOf(Entity::Class *entityClass) { - return std::shared_ptr(); +return shared_ptr(); } */ std::wstring Level::gatherStats() { wchar_t buf[64]; EnterCriticalSection(&m_entitiesCS); - swprintf(buf, 64, L"All:%d", this->entities.size()); + swprintf(buf, 64, L"All:%d", entities.size()); LeaveCriticalSection(&m_entitiesCS); return std::wstring(buf); } @@ -2588,33 +2668,44 @@ std::wstring Level::gatherChunkSourceStats() { } std::shared_ptr Level::getTileEntity(int x, int y, int z) { - if (y >= Level::maxBuildHeight) { + if (y < minBuildHeight || y >= maxBuildHeight) { return nullptr; } - LevelChunk* lc = getChunk(x >> 4, z >> 4); - if (lc != NULL) return lc->getTileEntity(x & 15, y, z & 15); + std::shared_ptr tileEntity = nullptr; - if (lc != NULL) { - std::shared_ptr tileEntity = - lc->getTileEntity(x & 15, y, z & 15); - - if (tileEntity == NULL) { - EnterCriticalSection(&m_tileEntityListCS); - for (AUTO_VAR(it, pendingTileEntities.begin()); - it != pendingTileEntities.end(); it++) { - std::shared_ptr e = *it; - - if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) { - tileEntity = e; - break; - } + if (updatingTileEntities) { + EnterCriticalSection(&m_tileEntityListCS); + for (int i = 0; i < pendingTileEntities.size(); i++) { + std::shared_ptr e = pendingTileEntities.at(i); + if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) { + tileEntity = e; + break; } - LeaveCriticalSection(&m_tileEntityListCS); } - return tileEntity; + LeaveCriticalSection(&m_tileEntityListCS); } - return nullptr; + if (tileEntity == NULL) { + LevelChunk* lc = getChunk(x >> 4, z >> 4); + if (lc != NULL) { + tileEntity = lc->getTileEntity(x & 15, y, z & 15); + } + } + + if (tileEntity == NULL) { + EnterCriticalSection(&m_tileEntityListCS); + for (AUTO_VAR(it, pendingTileEntities.begin()); + it != pendingTileEntities.end(); it++) { + std::shared_ptr e = *it; + + if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) { + tileEntity = e; + break; + } + } + LeaveCriticalSection(&m_tileEntityListCS); + } + return tileEntity; } void Level::setTileEntity(int x, int y, int z, @@ -2625,6 +2716,19 @@ void Level::setTileEntity(int x, int y, int z, tileEntity->x = x; tileEntity->y = y; tileEntity->z = z; + + // avoid adding duplicates + for (AUTO_VAR(it, pendingTileEntities.begin()); + it != pendingTileEntities.end();) { + std::shared_ptr next = *it; + if (next->x == x && next->y == y && next->z == z) { + next->setRemoved(); + it = pendingTileEntities.erase(it); + } else { + ++it; + } + } + pendingTileEntities.push_back(tileEntity); } else { tileEntityList.push_back(tileEntity); @@ -2727,29 +2831,40 @@ bool Level::isSolidBlockingTileInLoadedChunk(int x, int y, int z, return tile->material->isSolidBlocking() && tile->isCubeShaped(); } -// 4J - brought forward from 1.3.2 +bool Level::isFullAABBTile(int x, int y, int z) { + int tile = getTile(x, y, z); + if (tile == 0 || Tile::tiles[tile] == NULL) { + return false; + } + AABB* aabb = Tile::tiles[tile]->getAABB(this, x, y, z); + return aabb != NULL && aabb->getSize() >= 1; +} + bool Level::isTopSolidBlocking(int x, int y, int z) { // Temporary workaround until tahgs per-face solidity is finished Tile* tile = Tile::tiles[getTile(x, y, z)]; + return isTopSolidBlocking(tile, getData(x, y, z)); +} + +bool Level::isTopSolidBlocking(Tile* tile, int data) { if (tile == NULL) return false; if (tile->material->isSolidBlocking() && tile->isCubeShaped()) return true; if (dynamic_cast(tile) != NULL) { - return (getData(x, y, z) & StairTile::UPSIDEDOWN_BIT) == - StairTile::UPSIDEDOWN_BIT; + return (data & StairTile::UPSIDEDOWN_BIT) == StairTile::UPSIDEDOWN_BIT; } if (dynamic_cast(tile) != NULL) { - return (getData(x, y, z) & HalfSlabTile::TOP_SLOT_BIT) == + return (data & HalfSlabTile::TOP_SLOT_BIT) == HalfSlabTile::TOP_SLOT_BIT; } + if (dynamic_cast(tile) != NULL) return true; if (dynamic_cast(tile) != NULL) - return (getData(x, y, z) & TopSnowTile::HEIGHT_MASK) == - TopSnowTile::MAX_HEIGHT + 1; + return (data & TopSnowTile::HEIGHT_MASK) == TopSnowTile::MAX_HEIGHT + 1; return false; } void Level::updateSkyBrightness() { - int newDark = this->getOldSkyDarken(1); + int newDark = getOldSkyDarken(1); if (newDark != skyDarken) { skyDarken = newDark; } @@ -2768,9 +2883,9 @@ void Level::tick() { void Level::prepareWeather() { if (levelData->isRaining()) { - this->rainLevel = 1; + rainLevel = 1; if (levelData->isThundering()) { - this->thunderLevel = 1; + thunderLevel = 1; } } } @@ -2793,10 +2908,6 @@ void Level::tickWeather() { } #endif - if (lightningTime > 0) { - lightningTime--; - } - int thunderTime = levelData->getThunderTime(); if (thunderTime <= 0) { if (levelData->isThundering()) { @@ -2830,9 +2941,9 @@ void Level::tickWeather() { levelData->setRaining(!levelData->isRaining()); } /* if( !levelData->isRaining() ) - { - levelData->setRaining(true); - }*/ + { + levelData->setRaining(true); + }*/ } oRainLevel = rainLevel; @@ -2924,8 +3035,8 @@ void Level::buildAndPrepareChunksToPoll() { void Level::tickClientSideTiles(int xo, int zo, LevelChunk* lc) { // lc->tick(); // 4J - brought this lighting update forward from 1.8.2 - if (delayUntilNextMoodSound == 0) { - randValue = (unsigned)randValue * 3 + (unsigned)addend; + if (delayUntilNextMoodSound == 0 && !isClientSide) { + randValue = randValue * 3 + addend; int val = (randValue >> 2); int x = (val & 15); int z = ((val >> 8) & 15); @@ -2953,7 +3064,9 @@ void Level::tickClientSideTiles(int xo, int zo, LevelChunk* lc) { 0.8f + random->nextFloat() * 0.2f); #endif delayUntilNextMoodSound = - random->nextInt(20 * 60 * 10) + 20 * 60 * 5; + random->nextInt(SharedConstants::TICKS_PER_SECOND * 60 * + 10) + + SharedConstants::TICKS_PER_SECOND * 60 * 5; } } } @@ -3032,59 +3145,32 @@ void Level::checkLight( checkLight(LightLayer::Sky, x, y, z, force, false); checkLight(LightLayer::Block, x, y, z, force, rootOnlyEmissive); } -int Level::getExpectedSkyColor(lightCache_t* cache, int oc, int x, int y, int z, - int ct, int block) { - int expected = 0; - if (block == 255) return 0; // 4J added as optimisation - - if (canSeeSky(x, y, z)) { - expected = 15; - } else { - if (block == 0) block = 1; - - // 4J - changed this to attempt to get all 6 brightnesses of neighbours - // in a single call, as an optimisation - int b[6]; - b[0] = getBrightnessCached(cache, LightLayer::Sky, x - 1, y, z); - b[1] = getBrightnessCached(cache, LightLayer::Sky, x + 1, y, z); - b[2] = getBrightnessCached(cache, LightLayer::Sky, x, y - 1, z); - b[3] = getBrightnessCached(cache, LightLayer::Sky, x, y + 1, z); - b[4] = getBrightnessCached(cache, LightLayer::Sky, x, y, z - 1); - b[5] = getBrightnessCached(cache, LightLayer::Sky, x, y, z + 1); - for (int i = 0; i < 6; i++) { - if ((b[i] - block) > expected) expected = b[i] - block; - } +int Level::getExpectedLight(lightCache_t* cache, int x, int y, int z, + LightLayer::variety layer, bool propagatedOnly) { + if (layer == LightLayer::Sky && canSeeSky(x, y, z)) return MAX_BRIGHTNESS; + int id = getTile(x, y, z); + int result = layer == LightLayer::Sky ? 0 : Tile::lightEmission[id]; + int block = Tile::lightBlock[id]; + if (block >= MAX_BRIGHTNESS && Tile::lightEmission[id] > 0) block = 1; + if (block < 1) block = 1; + if (block >= MAX_BRIGHTNESS) { + return propagatedOnly ? 0 : getEmissionCached(cache, 0, x, y, z); } - return expected; -} + if (result >= MAX_BRIGHTNESS - 1) return result; -int Level::getExpectedBlockColor(lightCache_t* cache, int oc, int x, int y, - int z, int ct, int block, - bool propagatedOnly) { - int expected = propagatedOnly ? 0 : getEmissionCached(cache, ct, x, y, z); + for (int face = 0; face < 6; face++) { + int xx = x + Facing::STEP_X[face]; + int yy = y + Facing::STEP_Y[face]; + int zz = z + Facing::STEP_Z[face]; + int brightness = getBrightnessCached(cache, layer, xx, yy, zz) - block; - if (block >= 15) return expected; // 4J added as optimisation - - // 4J - changed this to attempt to get all 6 brightnesses of neighbours in a - // single call, as an optimisation - int b[6]; - b[0] = getBrightnessCached(cache, LightLayer::Block, x - 1, y, z); - b[1] = getBrightnessCached(cache, LightLayer::Block, x + 1, y, z); - b[2] = getBrightnessCached(cache, LightLayer::Block, x, y - 1, z); - b[3] = getBrightnessCached(cache, LightLayer::Block, x, y + 1, z); - b[4] = getBrightnessCached(cache, LightLayer::Block, x, y, z - 1); - b[5] = getBrightnessCached(cache, LightLayer::Block, x, y, z + 1); - for (int i = 0; i < 6; i++) { - if ((b[i] - block) > expected) expected = b[i] - block; + if (brightness > result) result = brightness; + if (result >= MAX_BRIGHTNESS - 1) return result; } - return expected; -} - -inline int GetIndex(int x, int y, int z) { - return ((x & 15) << 8) | ((y & 15) << 4) | (z & 15); + return result; } // 4J - Made changes here so that lighting goes through a cache, if enabled for @@ -3106,7 +3192,7 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, #if 0 ///////////////////////////////////////////////////////////////////////////////////////////// - // Get the frequency of the timer + // Get the frequency of the timer LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime1, qwDeltaTime2; float fElapsedTime1 = 0.0f; float fElapsedTime2 = 0.0f; @@ -3119,36 +3205,7 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, EnterCriticalSection(&m_checkLightCS); -#ifdef __PSVITA__ - // AP - only clear the one array element required to check if something has - // changed - cachewritten = false; - if (cache != NULL) { - int idx; - if (!(yc & 0xffffff00)) { - idx = GetIndex(xc, yc, zc); - cache[idx] = 0; - idx = GetIndex(xc - 1, yc, zc); - cache[idx] = 0; - idx = GetIndex(xc + 1, yc, zc); - cache[idx] = 0; - idx = GetIndex(xc, yc, zc - 1); - cache[idx] = 0; - idx = GetIndex(xc, yc, zc + 1); - cache[idx] = 0; - } - if (!((yc - 1) & 0xffffff00)) { - idx = GetIndex(xc, yc - 1, zc); - cache[idx] = 0; - } - if (!((yc + 1) & 0xffffff00)) { - idx = GetIndex(xc, yc + 1, zc); - cache[idx] = 0; - } - } -#else - initCache(cache); -#endif + initCachePartial(cache, xc, yc, zc); // If we're in cached mode, then use memory allocated after the cached data // itself for the toCheck array, in an attempt to make both that & the other @@ -3161,8 +3218,8 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, toCheck = (int*)(cache + (16 * 16 * 16)); } - int tcp = 0; - int tcc = 0; + int checkedPosition = 0; + int toCheckCount = 0; // int darktcc = 0; // 4J - added @@ -3177,68 +3234,19 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, // toCheck array) on L2 to try and stop any cached data getting knocked out // of L2 by other non-cached reads (or vice-versa) // if( cache ) XLockL2(XLOCKL2_INDEX_TITLE, cache, 128 * 1024, - //XLOCKL2_LOCK_SIZE_1_WAY, 0 ); + // XLOCKL2_LOCK_SIZE_1_WAY, 0 ); { - int cc = getBrightnessCached(cache, layer, xc, yc, zc); - int ex = 0; - { - int ct = 0; - int block = getBlockingCached(cache, layer, &ct, xc, yc, zc); - if (block == 0) block = 1; + int centerCurrent = getBrightnessCached(cache, layer, xc, yc, zc); + int centerExpected = getExpectedLight(cache, xc, yc, zc, layer, false); - int expected = 0; - if (layer == LightLayer::Sky) { - expected = - getExpectedSkyColor(cache, cc, xc, yc, zc, ct, block); - } else { - expected = getExpectedBlockColor(cache, cc, xc, yc, zc, ct, - block, false); - } - - ex = expected; + if (centerExpected != centerCurrent && cache) { + initCacheComplete(cache, xc, yc, zc); } -#ifdef __PSVITA__ - // AP - we only need to memset the entire array if we discover something - // has changed - if (ex != cc && cache) { - lightCache_t old[7]; - if (!(yc & 0xffffff00)) { - old[0] = cache[GetIndex(xc, yc, zc)]; - old[1] = cache[GetIndex(xc - 1, yc, zc)]; - old[2] = cache[GetIndex(xc + 1, yc, zc)]; - old[5] = cache[GetIndex(xc, yc, zc - 1)]; - old[6] = cache[GetIndex(xc, yc, zc + 1)]; - } - if (!((yc - 1) & 0xffffff00)) { - old[3] = cache[GetIndex(xc, yc - 1, zc)]; - } - if (!((yc + 1) & 0xffffff00)) { - old[4] = cache[GetIndex(xc, yc + 1, zc)]; - } - - XMemSet128(cache, 0, 16 * 16 * 16 * sizeof(lightCache_t)); - - if (!(yc & 0xffffff00)) { - cache[GetIndex(xc, yc, zc)] = old[0]; - cache[GetIndex(xc - 1, yc, zc)] = old[1]; - cache[GetIndex(xc + 1, yc, zc)] = old[2]; - cache[GetIndex(xc, yc, zc - 1)] = old[5]; - cache[GetIndex(xc, yc, zc + 1)] = old[6]; - } - if (!((yc - 1) & 0xffffff00)) { - cache[GetIndex(xc, yc - 1, zc)] = old[3]; - } - if (!((yc + 1) & 0xffffff00)) { - cache[GetIndex(xc, yc + 1, zc)] = old[4]; - } - } -#endif - - if (ex > cc) { - toCheck[tcc++] = ((32)) + ((32) << 6) + ((32) << 12); - } else if (ex < cc) { + if (centerExpected > centerCurrent) { + toCheck[toCheckCount++] = 32 | (32 << 6) | (32 << 12); + } else if (centerExpected < centerCurrent) { // 4J - added tcn. This is the code that is run when checkLight has // been called for a light source that has got darker / turned off. // In the original version, after zeroing tiles brightnesses that @@ -3251,35 +3259,30 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, // original light source we are turning off) int tcn = 0; if (layer == LightLayer::Block || true) { - toCheck[tcc++] = - ((32)) + ((32) << 6) + ((32) << 12) + (cc << 18); - while (tcp < tcc) { - int p = toCheck[tcp++]; + toCheck[toCheckCount++] = + 32 | (32 << 6) | (32 << 12) | (centerCurrent << 18); + while (checkedPosition < toCheckCount) { + int p = toCheck[checkedPosition++]; int x = ((p) & 63) - 32 + xc; int y = ((p >> 6) & 63) - 32 + yc; int z = ((p >> 12) & 63) - 32 + zc; - int cexp = ((p >> 18) & 15); - int o = getBrightnessCached(cache, layer, x, y, z); - if (o == cexp) { + int expected = ((p >> 18) & 15); + int current = getBrightnessCached(cache, layer, x, y, z); + if (current == expected) { setBrightnessCached(cache, &cacheUse, layer, x, y, z, 0); // cexp--; // 4J - removed, change // from 1.2.3 - if (cexp > 0) { - int xd = x - xc; - int yd = y - yc; - int zd = z - zc; - if (xd < 0) xd = -xd; - if (yd < 0) yd = -yd; - if (zd < 0) zd = -zd; + if (expected > 0) { + int xd = Mth::abs(x - xc); + int yd = Mth::abs(y - yc); + int zd = Mth::abs(z - zc); if (xd + yd + zd < 17) { bool edge = false; - for (int j = 0; j < 6; j++) { - int flip = j % 2 * 2 - 1; - - int xx = x + ((j / 2) % 3 / 2) * flip; - int yy = y + ((j / 2 + 1) % 3 / 2) * flip; - int zz = z + ((j / 2 + 2) % 3 / 2) * flip; + for (int face = 0; face < 6; face++) { + int xx = x + Facing::STEP_X[face]; + int yy = y + Facing::STEP_Y[face]; + int zz = z + Facing::STEP_Z[face]; // 4J - added - don't let this lighting // creep out of the normal fixed world and @@ -3290,28 +3293,28 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, if ((yy < 0) || (yy >= maxBuildHeight)) continue; - o = getBrightnessCached(cache, layer, xx, - yy, zz); // 4J - some changes here brought forward // from 1.2.3 - int block = getBlockingCached( - cache, layer, NULL, xx, yy, zz); - if (block == 0) block = 1; - if ((o == cexp - block) && - (tcc < + int block = std::max( + 1, getBlockingCached(cache, layer, NULL, + xx, yy, zz)); + current = getBrightnessCached(cache, layer, + xx, yy, zz); + if ((current == expected - block) && + (toCheckCount < (32 * 32 * 32))) // 4J - 32 * 32 * 32 // was toCheck.length { - toCheck[tcc++] = - (((xx - xc) + 32)) + - (((yy - yc) + 32) << 6) + - (((zz - zc) + 32) << 12) + - ((cexp - block) << 18); + toCheck[toCheckCount++] = + (xx - xc + 32) | + ((yy - yc + 32) << 6) | + ((zz - zc + 32) << 12) | + ((expected - block) << 18); } else { // 4J - added - keep track of which // tiles form the edge of the region we // are zeroing - if (o > (cexp - block)) { + if (current > (expected - block)) { edge = true; } } @@ -3328,18 +3331,18 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, } } } - tcp = 0; + checkedPosition = 0; // darktcc = tcc; ///////////////////////////////////////////////////// - tcc = tcn; // 4J added - we've moved all the edge tiles to the - // start of the array, so only need to process these - // now. The original processes all tcc tiles again in - // the next section + toCheckCount = tcn; // 4J added - we've moved all the edge tiles to + // the start of the array, so only need to + // process these now. The original processes + // all tcc tiles again in the next section } } - while (tcp < tcc) { - int p = toCheck[tcp++]; + while (checkedPosition < toCheckCount) { + int p = toCheck[checkedPosition++]; int x = ((p) & 63) - 32 + xc; int y = ((p >> 6) & 63) - 32 + yc; int z = ((p >> 12) & 63) - 32 + zc; @@ -3353,90 +3356,79 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, continue; } } + int current = getBrightnessCached(cache, layer, x, y, z); - int c = getBrightnessCached(cache, layer, x, y, z); - int ct = 0; - int block = getBlockingCached(cache, layer, &ct, x, y, z); - if (block == 0) block = 1; - - int expected = 0; - if (layer == LightLayer::Sky) { - expected = getExpectedSkyColor(cache, c, x, y, z, ct, block); - } else { - // If rootOnlyEmissive flag is set, then only consider the starting - // tile to be possibly emissive. - bool propagatedOnly = false; + // If rootOnlyEmissive flag is set, then only consider the starting tile + // to be possibly emissive. + bool propagatedOnly = false; + if (layer == LightLayer::Block) { if (rootOnlyEmissive) { propagatedOnly = (x != xc) || (y != yc) || (z != zc); } - expected = getExpectedBlockColor(cache, c, x, y, z, ct, block, - propagatedOnly); } + int expected = getExpectedLight(cache, x, y, z, layer, propagatedOnly); - if (expected != c) { + if (expected != current) { setBrightnessCached(cache, &cacheUse, layer, x, y, z, expected); - if (expected > c) { - int xd = x - xc; - int yd = y - yc; - int zd = z - zc; - if (xd < 0) xd = -xd; - if (yd < 0) yd = -yd; - if (zd < 0) zd = -zd; - if (xd + yd + zd < 17 && - tcc < (32 * 32 * 32) - - 6) // 4J - 32 * 32 * 32 was toCheck.length - { + if (expected > current) { + int xd = abs(x - xc); + int yd = abs(y - yc); + int zd = abs(z - zc); + bool withinBounds = + toCheckCount < + (32 * 32 * 32) - 6; // 4J - 32 * 32 * 32 was toCheck.length + if (xd + yd + zd < 17 && withinBounds) { // 4J - added extra checks here to stop lighting updates // moving out of the actual fixed world and into the // infinite water chunks if ((x - 1) >= minXZ) { if (getBrightnessCached(cache, layer, x - 1, y, z) < expected) - toCheck[tcc++] = (((x - 1 - xc) + 32)) + - (((y - yc) + 32) << 6) + - (((z - zc) + 32) << 12); + toCheck[toCheckCount++] = (((x - 1 - xc) + 32)) + + (((y - yc) + 32) << 6) + + (((z - zc) + 32) << 12); } if ((x + 1) <= maxXZ) { if (getBrightnessCached(cache, layer, x + 1, y, z) < expected) - toCheck[tcc++] = (((x + 1 - xc) + 32)) + - (((y - yc) + 32) << 6) + - (((z - zc) + 32) << 12); + toCheck[toCheckCount++] = (((x + 1 - xc) + 32)) + + (((y - yc) + 32) << 6) + + (((z - zc) + 32) << 12); } if ((y - 1) >= 0) { if (getBrightnessCached(cache, layer, x, y - 1, z) < expected) - toCheck[tcc++] = (((x - xc) + 32)) + - (((y - 1 - yc) + 32) << 6) + - (((z - zc) + 32) << 12); + toCheck[toCheckCount++] = + (((x - xc) + 32)) + (((y - 1 - yc) + 32) << 6) + + (((z - zc) + 32) << 12); } if ((y + 1) < maxBuildHeight) { if (getBrightnessCached(cache, layer, x, y + 1, z) < expected) - toCheck[tcc++] = (((x - xc) + 32)) + - (((y + 1 - yc) + 32) << 6) + - (((z - zc) + 32) << 12); + toCheck[toCheckCount++] = + (((x - xc) + 32)) + (((y + 1 - yc) + 32) << 6) + + (((z - zc) + 32) << 12); } if ((z - 1) >= minXZ) { if (getBrightnessCached(cache, layer, x, y, z - 1) < expected) - toCheck[tcc++] = (((x - xc) + 32)) + - (((y - yc) + 32) << 6) + - (((z - 1 - zc) + 32) << 12); + toCheck[toCheckCount++] = + (((x - xc) + 32)) + (((y - yc) + 32) << 6) + + (((z - 1 - zc) + 32) << 12); } if ((z + 1) <= maxXZ) { if (getBrightnessCached(cache, layer, x, y, z + 1) < expected) - toCheck[tcc++] = (((x - xc) + 32)) + - (((y - yc) + 32) << 6) + - (((z + 1 - zc) + 32) << 12); + toCheck[toCheckCount++] = + (((x - xc) + 32)) + (((y - yc) + 32) << 6) + + (((z + 1 - zc) + 32) << 12); } } } } } -// if( cache ) XUnlockL2(XLOCKL2_INDEX_TITLE); + // if( cache ) XUnlockL2(XLOCKL2_INDEX_TITLE); #if 0 QueryPerformanceCounter( &qwNewTime ); qwDeltaTime1.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; @@ -3471,6 +3463,11 @@ std::vector* Level::fetchTicksInChunk(LevelChunk* chunk, std::vector >* Level::getEntities( std::shared_ptr except, AABB* bb) { + return getEntities(except, bb, NULL); +} + +std::vector >* Level::getEntities( + std::shared_ptr except, AABB* bb, const EntitySelector* selector) { MemSect(40); es.clear(); int xc0 = Mth::floor((bb->x0 - 2) / 16); @@ -3491,7 +3488,7 @@ std::vector >* Level::getEntities( for (int xc = xc0; xc <= xc1; xc++) for (int zc = zc0; zc <= zc1; zc++) { if (hasChunk(xc, zc)) { - getChunk(xc, zc)->getEntities(except, bb, es); + getChunk(xc, zc)->getEntities(except, bb, es, selector); } } MemSect(0); @@ -3509,6 +3506,11 @@ std::vector >* Level::getEntities( std::vector >* Level::getEntitiesOfClass( const std::type_info& baseClass, AABB* bb) { + return getEntitiesOfClass(baseClass, bb, NULL); +} + +std::vector >* Level::getEntitiesOfClass( + const std::type_info& baseClass, AABB* bb, const EntitySelector* selector) { int xc0 = Mth::floor((bb->x0 - 2) / 16); int xc1 = Mth::floor((bb->x1 + 2) / 16); int zc0 = Mth::floor((bb->z0 - 2) / 16); @@ -3526,12 +3528,14 @@ std::vector >* Level::getEntitiesOfClass( #endif #endif - for (int xc = xc0; xc <= xc1; xc++) + for (int xc = xc0; xc <= xc1; xc++) { for (int zc = zc0; zc <= zc1; zc++) { if (hasChunk(xc, zc)) { - getChunk(xc, zc)->getEntitiesOfClass(baseClass, bb, *es); + getChunk(xc, zc)->getEntitiesOfClass(baseClass, bb, *es, + selector); } } + } #ifdef __PSVITA__ #ifdef _ENTITIES_RW_SECTION @@ -3621,7 +3625,7 @@ unsigned int Level::countInstanceOf( count++; } } else { - if (e->GetType() & clas) count++; + if (e->instanceof(clas)) count++; } } LeaveCriticalSection(&m_entitiesCS); @@ -3647,9 +3651,7 @@ unsigned int Level::countInstanceOfInRange(eINSTANCEOF clas, bool singleType, count++; } } else { - if (e->GetType() & clas) { - count++; - } + if (e->instanceof(clas)) count++; } } LeaveCriticalSection(&m_entitiesCS); @@ -3696,7 +3698,8 @@ void Level::removeEntities(std::vector >* list) { } bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, - int face, std::shared_ptr ignoreEntity) { + int face, std::shared_ptr ignoreEntity, + std::shared_ptr item) { int targetType = getTile(x, y, z); Tile* targetTile = Tile::tiles[targetType]; @@ -3708,13 +3711,14 @@ bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, if (targetTile != NULL && (targetTile == Tile::water || targetTile == Tile::calmWater || targetTile == Tile::lava || targetTile == Tile::calmLava || - targetTile == Tile::fire || targetTile->material->isReplaceable())) + targetTile == Tile::fire || targetTile->material->isReplaceable())) { targetTile = NULL; + } if (targetTile != NULL && targetTile->material == Material::decoration && tile == Tile::anvil) return true; if (tileId > 0 && targetTile == NULL) { - if (tile->mayPlace(this, x, y, z, face)) { + if (tile->mayPlace(this, x, y, z, face, item)) { return true; } } @@ -3737,7 +3741,7 @@ Path* Level::findPath(std::shared_ptr from, std::shared_ptr to, int x2 = x + r; int y2 = y + r; int z2 = z + r; - Region region = Region(this, x1, y1, z1, x2, y2, z2); + Region region = Region(this, x1, y1, z1, x2, y2, z2, 0); Path* path = (PathFinder(®ion, canPassDoors, canOpenDoors, avoidWater, canFloat)) .findPath(from.get(), to.get(), maxDist); @@ -3758,48 +3762,73 @@ Path* Level::findPath(std::shared_ptr from, int xBest, int yBest, int x2 = x + r; int y2 = y + r; int z2 = z + r; - Region region = Region(this, x1, y1, z1, x2, y2, z2); + Region region = Region(this, x1, y1, z1, x2, y2, z2, 0); Path* path = (PathFinder(®ion, canPassDoors, canOpenDoors, avoidWater, canFloat)) .findPath(from.get(), xBest, yBest, zBest, maxDist); return path; } -bool Level::getDirectSignal(int x, int y, int z, int dir) { +int Level::getDirectSignal(int x, int y, int z, int dir) { int t = getTile(x, y, z); - if (t == 0) return false; + if (t == 0) return Redstone::SIGNAL_NONE; return Tile::tiles[t]->getDirectSignal(this, x, y, z, dir); } -bool Level::hasDirectSignal(int x, int y, int z) { - if (getDirectSignal(x, y - 1, z, 0)) return true; - if (getDirectSignal(x, y + 1, z, 1)) return true; - if (getDirectSignal(x, y, z - 1, 2)) return true; - if (getDirectSignal(x, y, z + 1, 3)) return true; - if (getDirectSignal(x - 1, y, z, 4)) return true; - if (getDirectSignal(x + 1, y, z, 5)) return true; - return false; +int Level::getDirectSignalTo(int x, int y, int z) { + int result = Redstone::SIGNAL_NONE; + result = std::max(result, getDirectSignal(x, y - 1, z, 0)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = std::max(result, getDirectSignal(x, y + 1, z, 1)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = std::max(result, getDirectSignal(x, y, z - 1, 2)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = std::max(result, getDirectSignal(x, y, z + 1, 3)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = std::max(result, getDirectSignal(x - 1, y, z, 4)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = std::max(result, getDirectSignal(x + 1, y, z, 5)); + if (result >= Redstone::SIGNAL_MAX) return result; + return result; } -bool Level::getSignal(int x, int y, int z, int dir) { +bool Level::hasSignal(int x, int y, int z, int dir) { + return getSignal(x, y, z, dir) > Redstone::SIGNAL_NONE; +} + +int Level::getSignal(int x, int y, int z, int dir) { if (isSolidBlockingTile(x, y, z)) { - return hasDirectSignal(x, y, z); + return getDirectSignalTo(x, y, z); } int t = getTile(x, y, z); - if (t == 0) return false; + if (t == 0) return Redstone::SIGNAL_NONE; return Tile::tiles[t]->getSignal(this, x, y, z, dir); } bool Level::hasNeighborSignal(int x, int y, int z) { - if (getSignal(x, y - 1, z, 0)) return true; - if (getSignal(x, y + 1, z, 1)) return true; - if (getSignal(x, y, z - 1, 2)) return true; - if (getSignal(x, y, z + 1, 3)) return true; - if (getSignal(x - 1, y, z, 4)) return true; - if (getSignal(x + 1, y, z, 5)) return true; + if (getSignal(x, y - 1, z, 0) > 0) return true; + if (getSignal(x, y + 1, z, 1) > 0) return true; + if (getSignal(x, y, z - 1, 2) > 0) return true; + if (getSignal(x, y, z + 1, 3) > 0) return true; + if (getSignal(x - 1, y, z, 4) > 0) return true; + if (getSignal(x + 1, y, z, 5) > 0) return true; return false; } +int Level::getBestNeighborSignal(int x, int y, int z) { + int best = Redstone::SIGNAL_NONE; + + for (int i = 0; i < 6; i++) { + int signal = getSignal(x + Facing::STEP_X[i], y + Facing::STEP_Y[i], + z + Facing::STEP_Z[i], i); + + if (signal >= Redstone::SIGNAL_MAX) return Redstone::SIGNAL_MAX; + if (signal > best) best = signal; + } + + return best; +} + // 4J Stu - Added maxYDist param std::shared_ptr Level::getNearestPlayer(std::shared_ptr source, double maxDist, @@ -3865,7 +3894,9 @@ std::shared_ptr Level::getNearestAttackablePlayer(double x, double y, for (AUTO_VAR(it, players.begin()); it != itEnd; it++) { std::shared_ptr p = *it; - if (p->abilities.invulnerable) { + // 4J Stu - Added privilege check + if (p->abilities.invulnerable || !p->isAlive() || + p->hasInvisiblePrivilege()) { continue; } @@ -3885,11 +3916,8 @@ std::shared_ptr Level::getNearestAttackablePlayer(double x, double y, visibleDist *= (.7f * coverPercentage); } - // 4J Stu - Added check that this player is still alive and privilege - // check if ((visibleDist < 0 || dist < visibleDist * visibleDist) && - (best == -1 || dist < best) && p->isAlive() && - !p->hasInvisiblePrivilege()) { + (best == -1 || dist < best)) { best = dist; result = p; } @@ -3900,7 +3928,7 @@ std::shared_ptr Level::getNearestAttackablePlayer(double x, double y, std::shared_ptr Level::getPlayerByName(const std::wstring& name) { AUTO_VAR(itEnd, players.end()); for (AUTO_VAR(it, players.begin()); it != itEnd; it++) { - if (name.compare((*it)->name) == 0) { + if (name.compare((*it)->getName()) == 0) { return *it; // players.at(i); } } @@ -4010,25 +4038,14 @@ void Level::disconnect(bool sendDisconnect /*= true*/) {} void Level::checkSession() { levelStorage->checkSession(); } -void Level::setTime(__int64 time) { +void Level::setGameTime(int64_t time) { // 4J : WESTY : Added to track game time played by players for other awards. if (time != 0) // Ignore setting time to 0, done at level start and during // tutorial. { // Determine step in time and ensure it is reasonable ( we only have an // int to store the player stat). - __int64 timeDiff = time - levelData->getTime(); - - // debug setting added to keep it at day time -#ifndef _FINAL_BUILD - if (app.DebugSettingsOn()) { - if (app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & - (1L << eDebugSetting_FreezeTime)) { - timeDiff = 0; - time = levelData->getTime(); - } - } -#endif + int64_t timeDiff = time - levelData->getGameTime(); if (timeDiff < 0) { timeDiff = 0; @@ -4043,7 +4060,7 @@ void Level::setTime(__int64 time) { } // Apply stat to each player. - if (timeDiff > 0 && levelData->getTime() != -1) { + if (timeDiff > 0 && levelData->getGameTime() != -1) { AUTO_VAR(itEnd, players.end()); for (std::vector >::iterator it = players.begin(); @@ -4054,14 +4071,16 @@ void Level::setTime(__int64 time) { } } - this->levelData->setTime(time); + levelData->setGameTime(time); } -void Level::setOverrideTimeOfDay(__int64 time) { m_timeOfDayOverride = time; } +int64_t Level::getSeed() { return levelData->getSeed(); } -__int64 Level::getSeed() { return levelData->getSeed(); } +int64_t Level::getGameTime() { return levelData->getGameTime(); } -__int64 Level::getTime() { return levelData->getTime(); } +int64_t Level::getDayTime() { return levelData->getDayTime(); } + +void Level::setDayTime(int64_t newTime) { levelData->setDayTime(newTime); } Pos* Level::getSharedSpawnPos() { return new Pos(levelData->getXSpawn(), levelData->getYSpawn(), @@ -4080,7 +4099,7 @@ void Level::ensureAdded(std::shared_ptr entity) { int r = 2; for (int x = xc - r; x <= xc + r; x++) { for (int z = zc - r; z <= zc + r; z++) { - this->getChunk(x, z); + getChunk(x, z); } } @@ -4109,6 +4128,8 @@ LevelStorage* Level::getLevelStorage() { return levelStorage.get(); } LevelData* Level::getLevelData() { return levelData; } +GameRules* Level::getGameRules() { return levelData->getGameRules(); } + void Level::updateSleepingPlayerList() {} float Level::getThunderLevel(float a) { @@ -4121,7 +4142,7 @@ float Level::getRainLevel(float a) { } void Level::setRainLevel(float rainLevel) { - this->oRainLevel = rainLevel; + oRainLevel = rainLevel; this->rainLevel = rainLevel; } @@ -4166,15 +4187,13 @@ int Level::getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, centreZC, scale); } -// void Level::globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, -// int data) -// { -// auto itEnd = listeners.end(); -// for (auto it = listeners.begin(); it != itEnd; it++) -// { -// (*it)->globalLevelEvent(type, sourceX, sourceY, sourceZ, data); -// } -// } +void Level::globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, + int data) { + AUTO_VAR(itEnd, listeners.end()); + for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) { + (*it)->globalLevelEvent(type, sourceX, sourceY, sourceZ, data); + } +} void Level::levelEvent(int type, int x, int y, int z, int data) { levelEvent(nullptr, type, x, y, z, data); @@ -4194,15 +4213,17 @@ int Level::getHeight() { return dimension->hasCeiling ? genDepth : maxBuildHeight; } +Tickable* Level::makeSoundUpdater(std::shared_ptr minecart) { + return NULL; +} + Random* Level::getRandomFor(int x, int z, int blend) { - __int64 seed = (x * 341873128712l + z * 132897987541l) + + int64_t seed = (x * 341873128712l + z * 132897987541l) + getLevelData()->getSeed() + blend; random->setSeed(seed); return random; } -bool Level::updateLights() { return false; } - TilePos* Level::findNearestMapFeature(const std::wstring& featureName, int x, int y, int z) { return getChunkSource()->findNearestMapFeature(this, featureName, x, y, z); @@ -4224,6 +4245,64 @@ void Level::destroyTileProgress(int id, int x, int y, int z, int progress) { } } +void Level::createFireworks(double x, double y, double z, double xd, double yd, + double zd, CompoundTag* infoTag) {} + +Scoreboard* Level::getScoreboard() { return scoreboard; } + +void Level::updateNeighbourForOutputSignal(int x, int y, int z, int source) { + for (int dir = 0; dir < 4; dir++) { + int xx = x + Direction::STEP_X[dir]; + int zz = z + Direction::STEP_Z[dir]; + int id = getTile(xx, y, zz); + if (id == 0) continue; + Tile* tile = Tile::tiles[id]; + + if (Tile::comparator_off->isSameDiode(id)) { + tile->neighborChanged(this, xx, y, zz, source); + } else if (Tile::isSolidBlockingTile(id)) { + xx += Direction::STEP_X[dir]; + zz += Direction::STEP_Z[dir]; + id = getTile(xx, y, zz); + tile = Tile::tiles[id]; + + if (Tile::comparator_off->isSameDiode(id)) { + tile->neighborChanged(this, xx, y, zz, source); + } + } + } +} + +float Level::getDifficulty(double x, double y, double z) { + return getDifficulty(Mth::floor(x), Mth::floor(y), Mth::floor(z)); +} + +/** + * Returns a difficulty scaled from 0 (easiest) to 1 (normal), may overflow + * to 1.5 (hardest) if allowed by player. + */ +float Level::getDifficulty(int x, int y, int z) { + float result = 0; + bool isHard = difficulty == Difficulty::HARD; + + if (hasChunkAt(x, y, z)) { + float moonBrightness = getMoonBrightness(); + + result += Mth::clamp(getChunkAt(x, z)->inhabitedTime / + (TICKS_PER_DAY * 150.0f), + 0.0f, 1.0f) * + (isHard ? 1.0f : 0.75f); + result += moonBrightness * 0.25f; + } + + if (difficulty < Difficulty::NORMAL) { + result *= difficulty / 2.0f; + } + + return Mth::clamp(result, 0.0f, isHard ? 1.5f : 1.0f); + ; +} + bool Level::useNewSeaLevel() { return levelData->useNewSeaLevel(); } bool Level::getHasBeenInCreative() { return levelData->getHasBeenInCreative(); } @@ -4282,7 +4361,7 @@ void Level::decrementUnsavedChunkCount() { --m_unsavedChunkCount; } bool Level::canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType) { int count = 0; int max = 0; - if (spawnType == eSpawnType_Egg) { + if (spawnType == eSpawnType_Egg || spawnType == eSpawnType_Portal) { switch (type) { case eTYPE_VILLAGER: count = countInstanceOf(eTYPE_VILLAGER, true); @@ -4312,15 +4391,34 @@ bool Level::canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType) { count = countInstanceOf(eTYPE_VILLAGERGOLEM, true); max = MobCategory::MAX_XBOX_IRONGOLEM; break; + case eTYPE_WITHERBOSS: + count = countInstanceOf(eTYPE_WITHERBOSS, true) + + countInstanceOf(eTYPE_ENDERDRAGON, true); + max = MobCategory::MAX_CONSOLE_BOSS; + break; default: if ((type & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) == eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) { count = countInstanceOf(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, false); max = MobCategory::MAX_XBOX_ANIMALS_WITH_SPAWN_EGG; - } else if ((type & eTYPE_MONSTER) == eTYPE_MONSTER) { - count = countInstanceOf(eTYPE_MONSTER, false); + } + // 4J: Use eTYPE_ENEMY instead of monster (slimes and ghasts + // aren't monsters) + else if (Entity::instanceof(type, eTYPE_ENEMY)) { + count = countInstanceOf(eTYPE_ENEMY, false); max = MobCategory::MAX_XBOX_MONSTERS_WITH_SPAWN_EGG; + } else if ((type & eTYPE_AMBIENT) == eTYPE_AMBIENT) { + count = countInstanceOf(eTYPE_AMBIENT, false); + max = MobCategory::MAX_AMBIENT_WITH_SPAWN_EGG; + } + // 4J: Added minecart and boats + else if (Entity::instanceof(type, eTYPE_MINECART)) { + count = countInstanceOf(eTYPE_MINECART, false); + max = Level::MAX_CONSOLE_MINECARTS; + } else if (Entity::instanceof(type, eTYPE_BOAT)) { + count = countInstanceOf(eTYPE_BOAT, true); + max = Level::MAX_XBOX_BOATS; } }; } else if (spawnType == eSpawnType_Breed) { @@ -4352,5 +4450,6 @@ bool Level::canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType) { break; } } - return count < max; -} + // 4J: Interpret 0 as no limit + return max == 0 || count < max; +} \ No newline at end of file diff --git a/Minecraft.World/Level/Level.h b/Minecraft.World/Level/Level.h index 86f4de546..ea06e2468 100644 --- a/Minecraft.World/Level/Level.h +++ b/Minecraft.World/Level/Level.h @@ -46,6 +46,11 @@ class LevelSettings; class Biome; class Villages; class VillageSiege; +class Tickable; +class Minecart; +class EntitySelector; +class Scoreboard; +class GameRules; class Level : public LevelSource { public: @@ -138,11 +143,10 @@ public: protected: float oRainLevel, rainLevel; float oThunderLevel, thunderLevel; - int lightningTime; public: - int lightningBoltTime; - bool noNeighborUpdate; + int skyFlashTime; + int difficulty; Random* random; bool isNew; @@ -168,6 +172,13 @@ public: std::shared_ptr villages; VillageSiege* villageSiege; +private: + // 4J - Calendar is now static + // Calendar *calendar; + +protected: + Scoreboard* scoreboard; + public: Biome* getBiome(int x, int z); // 4J - brought forward from 1.2.3 virtual BiomeSource* getBiomeSource(); @@ -183,7 +194,6 @@ public: Level(std::shared_ptr levelStorage, const std::wstring& name, Dimension* dimension, LevelSettings* levelSettings, bool doCreateChunkSource = true); - Level(Level* level, Dimension* dimension); Level(std::shared_ptr levelStorage, const std::wstring& levelName, LevelSettings* levelSettings); Level(std::shared_ptr levelStorage, @@ -209,6 +219,8 @@ public: bool isEmptyTile(int x, int y, int z); virtual bool isEntityTile(int x, int y, int z); int getTileRenderShape(int x, int y, int z); + int getTileRenderShape(int t); // 4J Added to slightly optimise and avoid + // getTile call if we already know the 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); @@ -224,40 +236,34 @@ public: public: LevelChunk* getChunkAt(int x, int z); LevelChunk* getChunk(int x, int z); - virtual bool setTileAndDataNoUpdate(int x, int y, int z, int tile, - int data); - virtual bool setTileAndDataNoUpdate(int x, int y, int z, int tile, int data, - bool informClients); - virtual bool setTileNoUpdate(int x, int y, int z, int tile); - bool setTileNoUpdateNoLightCheck(int x, int y, int z, - int tile); // 4J added + virtual bool setTileAndData(int x, int y, int z, int tile, int data, + int updateFlags); Material* getMaterial(int x, int y, int z); virtual int getData(int x, int y, int z); - void setData(int x, int y, int z, int data, - bool forceUpdate = false); // 4J added forceUpdate - virtual bool setDataNoUpdate(int x, int y, int z, int data); - bool setTile(int x, int y, int z, int tile); - bool setTileAndData(int x, int y, int z, int tile, int data); - void sendTileUpdated(int x, int y, int z); + virtual bool setData(int x, int y, int z, int data, int updateFlags, + bool forceUpdate = false); // 4J added forceUpdate + virtual bool removeTile(int x, int y, int z); + virtual bool destroyTile(int x, int y, int z, bool dropResources); + virtual bool setTileAndUpdate(int x, int y, int z, int tile); + virtual void sendTileUpdated(int x, int y, int z); public: virtual void tileUpdated(int x, int y, int z, int tile); 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); - void swap(int x1, int y1, int z1, int x2, int y2, int z2); void updateNeighborsAt(int x, int y, int z, int tile); - -private: + void updateNeighborsAtExceptFromFacing(int x, int y, int z, int tile, + int skipFacing); void neighborChanged(int x, int y, int z, int type); - -public: + virtual bool isTileToBeTickedAt(int x, int y, int z, int tileId); bool canSeeSky(int x, int y, int z); int getDaytimeRawBrightness(int x, int y, int z); int getRawBrightness(int x, int y, int z); int getRawBrightness(int x, int y, int z, bool propagate); bool isSkyLit(int x, int y, int z); int getHeightmap(int x, int z); + int getLowestHeightmap(int x, int z); void updateLightIfOtherThan(LightLayer::variety layer, int x, int y, int z, int expected); int getBrightnessPropagate(LightLayer::variety layer, int x, int y, int z, @@ -272,11 +278,11 @@ public: int z, int brightness); // 4J added #ifdef _LARGE_WORLDS - typedef __uint64 lightCache_t; + typedef uint64_t lightCache_t; #else typedef unsigned int lightCache_t; #endif - inline void setBrightnessCached(lightCache_t* cache, __uint64* cacheUse, + inline void setBrightnessCached(lightCache_t* cache, uint64_t* cacheUse, LightLayer::variety layer, int x, int y, int z, int brightness); inline int getBrightnessCached(lightCache_t* cache, @@ -286,8 +292,9 @@ public: int z); inline int getBlockingCached(lightCache_t* cache, LightLayer::variety layer, int* ct, int x, int y, int z); - void initCache(lightCache_t* cache); - void flushCache(lightCache_t* cache, __uint64 cacheUse, + void initCachePartial(lightCache_t* cache, int xc, int yc, int zc); + void initCacheComplete(lightCache_t* cache, int xc, int yc, int zc); + void flushCache(lightCache_t* cache, uint64_t cacheUse, LightLayer::variety layer); bool cachewritten; @@ -295,10 +302,10 @@ public: static const int BLOCKING_SHIFT = 20; static const int EMISSION_SHIFT = 16; #ifdef _LARGE_WORLDS - static const __int64 LIGHTING_WRITEBACK = 0x80000000LL; - static const __int64 EMISSION_VALID = 0x40000000LL; - static const __int64 BLOCKING_VALID = 0x20000000LL; - static const __int64 LIGHTING_VALID = 0x10000000LL; + static const int64_t LIGHTING_WRITEBACK = 0x80000000LL; + static const int64_t EMISSION_VALID = 0x40000000LL; + static const int64_t BLOCKING_VALID = 0x20000000LL; + static const int64_t LIGHTING_VALID = 0x10000000LL; static const lightCache_t POSITION_MASK = 0xffffffff0000ffffLL; #else static const int LIGHTING_WRITEBACK = 0x80000000; @@ -320,19 +327,21 @@ public: HitResult* clip(Vec3* a, Vec3* b, bool liquid); HitResult* clip(Vec3* a, Vec3* b, bool liquid, bool solidOnly); - virtual void playSound(std::shared_ptr entity, int iSound, - float volume, float pitch); + virtual void playEntitySound(std::shared_ptr entity, int iSound, + float volume, float pitch); + virtual void playPlayerSound(std::shared_ptr entity, int iSound, + float volume, float pitch); virtual void playSound(double x, double y, double z, int iSound, float volume, float pitch, float fClipSoundDist = 16.0f); virtual void playLocalSound(double x, double y, double z, int iSound, - float volume, float pitch, + float volume, float pitch, bool distanceDelay, float fClipSoundDist = 16.0f); void playStreamingMusic(const std::wstring& name, int x, int y, int z); - void playMusic(double x, double y, double z, const std::wstring& string, - float volume); + void playMusic(double x, double y, double z, + const std::wstring& std::string, float volume); // 4J removed - void addParticle(const std::wstring& id, double x, double y, // double z, double xd, double yd, double zd); void addParticle(ePARTICLE_TYPE id, double x, double y, double z, double xd, @@ -358,17 +367,16 @@ public: AABBList* getCubes( std::shared_ptr source, AABB* box, bool noEntities = false, bool blockAtEdge = - false); // 4J - added noEntities & blockAtEdge parameters + false); // 4J: Added noEntities & blockAtEdge parameters AABBList* getTileCubes( - AABB* box, - bool blockAtEdge); // 4J Stu - Brought forward from 12w36 to fix #46282 - // - TU5: Gameplay: Exiting the minecart in a tight - // corridor damages the player + AABB* box, bool blockAtEdge = + false); // 4J: Added noEntities & blockAtEdge parameters int getOldSkyDarken(float a); // 4J - change brought forward from 1.8.2 float getSkyDarken(float a); // 4J - change brought forward from 1.8.2 Vec3* getSkyColor(std::shared_ptr source, float a); float getTimeOfDay(float a); - int getMoonPhase(float a); + int getMoonPhase(); + float getMoonBrightness(); float getSunAngle(float a); Vec3* getCloudColor(float a); Vec3* getFogColor(float a); @@ -380,8 +388,10 @@ public: float getStarBrightness(float a); virtual void addToTickNextTick(int x, int y, int z, int tileId, int tickDelay); + virtual void addToTickNextTick(int x, int y, int z, int tileId, + int tickDelay, int priorityTilt); virtual void forceAddTileTick(int x, int y, int z, int tileId, - int tickDelay); + int tickDelay, int prioTilt); virtual void tickEntities(); void addAllPendingTileEntities( std::vector >& entities); @@ -420,8 +430,10 @@ public: virtual bool isSolidBlockingTile(int x, int y, int z); bool isSolidBlockingTileInLoadedChunk(int x, int y, int z, bool valueIfNotLoaded); + bool isFullAABBTile(int x, int y, int z); virtual bool isTopSolidBlocking(int x, int y, int z); // 4J - brought forward from 1.3.2 + bool isTopSolidBlocking(Tile* tile, int data); protected: bool spawnEnemies; @@ -477,11 +489,9 @@ public: false); // 4J added force, rootOnlySource parameters private: int* toCheckLevel; - int getExpectedSkyColor(lightCache_t* cache, int oc, int x, int y, int z, - int ct, int block); - int getExpectedBlockColor(lightCache_t* cache, int oc, int x, int y, int z, - int ct, int block, - bool propagatedOnly); // 4J added parameter + int getExpectedLight(lightCache_t* cache, int x, int y, int z, + LightLayer::variety layer, bool propagatedOnly); + public: void checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool force = false, @@ -501,11 +511,18 @@ public: std::vector >* getEntities( std::shared_ptr except, AABB* bb); + std::vector >* getEntities( + std::shared_ptr except, AABB* bb, + const EntitySelector* selector); std::vector >* getEntitiesOfClass( const std::type_info& baseClass, AABB* bb); + std::vector >* getEntitiesOfClass( + const std::type_info& baseClass, AABB* bb, + const EntitySelector* selector); std::shared_ptr getClosestEntityOfClass( const std::type_info& baseClass, AABB* bb, std::shared_ptr source); + virtual std::shared_ptr getEntity(int entityId) = 0; std::vector > getAllEntities(); void tileEntityChanged(int x, int y, int z, std::shared_ptr te); // unsigned int countInstanceOf(BaseObject::Class *clas); @@ -518,7 +535,8 @@ public: void addEntities(std::vector >* list); virtual void removeEntities(std::vector >* list); bool mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, - int face, std::shared_ptr ignoreEntity); + int face, std::shared_ptr ignoreEntity, + std::shared_ptr item); int getSeaLevel(); Path* findPath(std::shared_ptr from, std::shared_ptr to, float maxDist, bool canPassDoors, bool canOpenDoors, @@ -526,10 +544,12 @@ public: Path* findPath(std::shared_ptr from, int xBest, int yBest, int zBest, float maxDist, bool canPassDoors, bool canOpenDoors, bool avoidWater, bool canFloat); - 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); + int getDirectSignal(int x, int y, int z, int dir); + int getDirectSignalTo(int x, int y, int z); + bool hasSignal(int x, int y, int z, int dir); + int getSignal(int x, int y, int z, int dir); bool hasNeighborSignal(int x, int y, int z); + int getBestNeighborSignal(int x, int y, int z); // 4J Added maxYDist param std::shared_ptr getNearestPlayer(std::shared_ptr source, double maxDist, @@ -554,12 +574,11 @@ public: byteArray data, bool includeLighting = true); virtual void disconnect(bool sendDisconnect = true); void checkSession(); - void setTime(__int64 time); - void setOverrideTimeOfDay( - __int64 time); // 4J Added so we can override timeOfDay without - // changing tick time - __int64 getSeed(); - __int64 getTime(); + void setGameTime(int64_t time); + int64_t getSeed(); + int64_t getGameTime(); + int64_t getDayTime(); + void setDayTime(int64_t newTime); Pos* getSharedSpawnPos(); void setSpawnPos(int x, int y, int z); void setSpawnPos(Pos* spawnPos); @@ -571,6 +590,7 @@ public: virtual void tileEvent(int x, int y, int z, int tile, int b0, int b1); LevelStorage* getLevelStorage(); LevelData* getLevelData(); + GameRules* getGameRules(); virtual void updateSleepingPlayerList(); bool useNewSeaLevel(); // 4J added bool getHasBeenInCreative(); // 4J Added @@ -588,16 +608,26 @@ public: std::shared_ptr getSavedData(const std::type_info& clazz, const std::wstring& id); int getFreeAuxValueFor(const std::wstring& id); + void globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, + int data); void levelEvent(int type, int x, int y, int z, int data); void levelEvent(std::shared_ptr source, int type, int x, int y, int z, int data); int getMaxBuildHeight(); int getHeight(); + virtual Tickable* makeSoundUpdater(std::shared_ptr minecart); Random* getRandomFor(int x, int z, int blend); - bool updateLights(); virtual bool isAllEmpty(); double getHorizonHeight(); void destroyTileProgress(int id, int x, int y, int z, int progress); + // Calendar *getCalendar(); // 4J - Calendar is now static + virtual void createFireworks(double x, double y, double z, double xd, + double yd, double zd, CompoundTag* infoTag); + virtual Scoreboard* getScoreboard(); + virtual void updateNeighbourForOutputSignal(int x, int y, int z, + int source); + virtual float getDifficulty(double x, double y, double z); + virtual float getDifficulty(int x, int y, int z); TilePos* findNearestMapFeature(const std::wstring& featureName, int x, int y, int z); @@ -605,10 +635,6 @@ public: int getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, int centreZC, int scale); - // 4J added - - __int64 m_timeOfDayOverride; - // 4J - optimisation - keep direct reference of underlying cache here LevelChunk** chunkSourceCache; int chunkSourceXZSize; @@ -642,6 +668,7 @@ public: enum ESPAWN_TYPE { eSpawnType_Egg, eSpawnType_Breed, + eSpawnType_Portal, }; bool canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType); diff --git a/Minecraft.World/Level/LevelChunk.cpp b/Minecraft.World/Level/LevelChunk.cpp index ba8937cb5..9112f1348 100644 --- a/Minecraft.World/Level/LevelChunk.cpp +++ b/Minecraft.World/Level/LevelChunk.cpp @@ -11,10 +11,13 @@ #include "Storage/SparseLightStorage.h" #include "BlockReplacements.h" #include "LevelChunk.h" +#include "../Util/BasicTypeContainers.h" #include "../../Minecraft.Client/MinecraftServer.h" #include "../../Minecraft.Client/Level/ServerLevel.h" #include "../../Minecraft.Client/Network/ServerChunkCache.h" #include "../../Minecraft.Client/Rendering/GameRenderer.h" +#include "../Entities/ItemEntity.h" +#include "../Entities/Mobs/Minecart.h" #ifdef __PS3__ #include "../../Minecraft.Client/Platform/PS3/PS3Extras/C4JSpursJob.h" @@ -97,6 +100,9 @@ void LevelChunk::init(Level* level, int x, int z) { MemSect(0); + lowestHeightmap = 256; + inhabitedTime = 0; + // Optimisation brought forward from 1.8.2, change from int to unsigned char // & this special value changed from -999 to 255 for (int i = 0; i < 16 * 16; i++) { @@ -398,7 +404,7 @@ void LevelChunk::startSharingTilesAndData(int forceMs) { } else { // Only force if it has been more than forceMs milliseconds since we // last wanted to unshare this chunk - __int64 timenow = System::currentTimeMillis(); + int64_t timenow = System::currentTimeMillis(); if ((timenow - lastUnsharedTime) < forceMs) { LeaveCriticalSection(&m_csSharing); return; @@ -462,7 +468,7 @@ LevelChunk::~LevelChunk() { bool LevelChunk::isAt(int x, int z) { return x == this->x && z == this->z; } int LevelChunk::getHeightmap(int x, int z) { - return heightmap[(unsigned)z << 4 | x] & 0xff; + return heightmap[z << 4 | x] & 0xff; } int LevelChunk::getHighestSectionPosition() { @@ -555,6 +561,7 @@ void LevelChunk::recalcHeightmap() { byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); getBlockData(blockData); #endif + lowestHeightmap = Integer::MAX_VALUE; int min = Level::maxBuildHeight - 1; for (int x = 0; x < 16; x++) @@ -607,6 +614,7 @@ void LevelChunk::recalcHeightmap() { #endif heightmap[(unsigned)z << 4 | x] = (uint8_t)y; if (y < min) min = y; + if (y < lowestHeightmap) lowestHeightmap = y; if (!level->dimension->hasCeiling) { int br = Level::MAX_BRIGHTNESS; @@ -934,6 +942,7 @@ void LevelChunk::recalcHeight(int x, int yStart, int z) { y1 = y2; y2 = tmp; } + if (height < lowestHeightmap) lowestHeightmap = height; if (!level->dimension->hasCeiling) { PIXBeginNamedEvent(0, "Light gaps"); lightGap(xOffs - 1, zOffs, y1, y2); @@ -986,6 +995,15 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) { int old = blocks->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); int oldData = data->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); if (old == _tile && oldData == _data) return false; + // 4J Stu - Need to do this here otherwise double chests don't always + // work correctly + std::shared_ptr te = getTileEntity(x, y, z); + if (te != NULL) { + te->clearCache(); + } + + return false; + } int xOffs = this->x * 16 + x; int zOffs = this->z * 16 + z; if (old != 0 && !level->isClientSide) { @@ -1056,7 +1074,8 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) { blocks->set(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z, 0); // blocks[x << - //level->depthBitsPlusFour | z << level->depthBits | y] = 0; + // level->depthBitsPlusFour | z << level->depthBits | y] = + // 0; } } } @@ -1068,7 +1087,8 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) { Tile::tiles[_tile]->isEntityTile()) { std::shared_ptr te = getTileEntity(x, y, z); if (te == NULL) { - te = ((EntityTile*)Tile::tiles[_tile])->newTileEntity(level); + te = dynamic_cast(Tile::tiles[_tile]) + ->newTileEntity(level); // app.DebugPrintf("%s: Setting tile id %d, created tileEntity // type %d\n", level->isClientSide?"Client":"Server", _tile, // te->GetType()); @@ -1085,7 +1105,7 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) { // AP - changed the method of EntityTile detection cos it's well slow on // Vita mate // else if (old > 0 && dynamic_cast(Tile::tiles[old]) != - //NULL) + // NULL) else if (old > 0 && Tile::tiles[_tile] != NULL && Tile::tiles[_tile]->isEntityTile()) { std::shared_ptr te = getTileEntity(x, y, z); @@ -1137,6 +1157,9 @@ bool LevelChunk::setData(int x, int y, int z, int val, int mask, int LevelChunk::getBrightness(LightLayer::variety layer, int x, int y, int z) { if (layer == LightLayer::Sky) { + if (level->dimension->hasCeiling) { + return 0; + } SparseLightStorage* skyLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperSkyLight : lowerSkyLight; @@ -1229,7 +1252,7 @@ int LevelChunk::getRawBrightness(int x, int y, int z, int skyDampen) { level->dimension->hasCeiling ? 0 : skyLight->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); - if (light > 0) LevelChunk::touchedSky = true; + if (light > 0) touchedSky = true; light -= skyDampen; SparseLightStorage* blockLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperBlockLight @@ -1341,7 +1364,7 @@ std::shared_ptr LevelChunk::getTileEntity(int x, int y, int z) { // 4J Stu - Changed as we should not be using the [] accessor (causes an // insert when we don't want one) - // std::shared_ptr tileEntity = tileEntities[pos]; + // shared_ptr tileEntity = tileEntities[pos]; EnterCriticalSection(&m_csTileEntities); std::shared_ptr tileEntity = nullptr; AUTO_VAR(it, tileEntities.find(pos)); @@ -1366,7 +1389,8 @@ std::shared_ptr LevelChunk::getTileEntity(int x, int y, int z) { // if (tileEntity == NULL) //{ - tileEntity = ((EntityTile*)Tile::tiles[t])->newTileEntity(level); + tileEntity = + dynamic_cast(Tile::tiles[t])->newTileEntity(level); level->setTileEntity(this->x * 16 + x, y, this->z * 16 + z, tileEntity); //} @@ -1425,6 +1449,8 @@ void LevelChunk::setTileEntity(int x, int y, int z, "tile!\n"); return; } + AUTO_VAR(it, tileEntities.find(pos)); + if (it != tileEntities.end()) it->second->setRemoved(); tileEntity->clearRemoved(); @@ -1471,10 +1497,11 @@ void LevelChunk::load() { if (entityTags != NULL) { for (int i = 0; i < entityTags->size(); i++) { CompoundTag* teTag = entityTags->get(i); - std::shared_ptr te = + std::shared_ptr ent = EntityIO::loadStatic(teTag, level); - if (te != NULL) { - addEntity(te); + if (ent != NULL) { + ent->onLoadedFromSave(); + addEntity(ent); } } } @@ -1612,6 +1639,33 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter #endif } +bool LevelChunk::containsPlayer() { +#ifdef _ENTITIES_RW_SECTION + EnterCriticalRWSection(&m_csEntities, true); +#else + EnterCriticalSection(&m_csEntities); +#endif + for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) { + std::vector >* vecEntity = entityBlocks[i]; + for (int j = 0; j < vecEntity->size(); j++) { + if (vecEntity->at(j)->GetType() == eTYPE_SERVERPLAYER) { +#ifdef _ENTITIES_RW_SECTION + LeaveCriticalRWSection(&m_csEntities, true); +#else + LeaveCriticalSection(&m_csEntities); +#endif + return true; + } + } + } +#ifdef _ENTITIES_RW_SECTION + LeaveCriticalRWSection(&m_csEntities, true); +#else + LeaveCriticalSection(&m_csEntities); +#endif + return false; +} + #ifdef _LARGE_WORLDS bool LevelChunk::isUnloaded() { return m_bUnloaded; } #endif @@ -1619,7 +1673,8 @@ bool LevelChunk::isUnloaded() { return m_bUnloaded; } void LevelChunk::markUnsaved() { this->setUnsaved(true); } void LevelChunk::getEntities(std::shared_ptr except, AABB* bb, - std::vector >& es) { + std::vector >& es, + const EntitySelector* selector) { int yc0 = Mth::floor((bb->y0 - 2) / 16); int yc1 = Mth::floor((bb->y1 + 2) / 16); if (yc0 < 0) yc0 = 0; @@ -1636,14 +1691,16 @@ void LevelChunk::getEntities(std::shared_ptr except, AABB* bb, AUTO_VAR(itEnd, entities->end()); for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) { std::shared_ptr e = *it; // entities->at(i); - if (e != except && e->bb->intersects(bb)) { + if (e != except && e->bb->intersects(bb) && + (selector == NULL || selector->matches(e))) { es.push_back(e); std::vector >* subs = e->getSubEntities(); if (subs != NULL) { for (int j = 0; j < subs->size(); j++) { e = subs->at(j); - if (e != except && e->bb->intersects(bb)) { + if (e != except && e->bb->intersects(bb) && + (selector == NULL || selector->matches(e))) { es.push_back(e); } } @@ -1657,7 +1714,8 @@ void LevelChunk::getEntities(std::shared_ptr except, AABB* bb, } void LevelChunk::getEntitiesOfClass(const std::type_info& ec, AABB* bb, - std::vector >& es) { + std::vector >& es, + const EntitySelector* selector) { int yc0 = Mth::floor((bb->y0 - 2) / 16); int yc1 = Mth::floor((bb->y1 + 2) / 16); @@ -1687,25 +1745,30 @@ void LevelChunk::getEntitiesOfClass(const std::type_info& ec, AABB* bb, bool isAssignableFrom = false; // Some special cases where the base class is a general type that // our class may be derived from, otherwise do a direct comparison - // of std::type_info - if (ec == typeid(Player)) { - if (std::dynamic_pointer_cast(e) != NULL) - isAssignableFrom = true; - } else if (ec == typeid(Mob)) { - if (std::dynamic_pointer_cast(e) != NULL) - isAssignableFrom = true; - } else if (ec == typeid(Monster)) { - if (std::dynamic_pointer_cast(e) != NULL) - isAssignableFrom = true; - } else if (ec == typeid(Zombie)) { - if (std::dynamic_pointer_cast(e) != NULL) - isAssignableFrom = true; - } else { - Entity* entityPtr = e.get(); - if (entityPtr != NULL && ec == typeid(*entityPtr)) - isAssignableFrom = true; + // of type_info + if (ec == typeid(Player)) + isAssignableFrom = e->instanceof(eTYPE_PLAYER); + else if (ec == typeid(Entity)) + isAssignableFrom = e->instanceof(eTYPE_ENTITY); + else if (ec == typeid(Mob)) + isAssignableFrom = e->instanceof(eTYPE_MOB); + else if (ec == typeid(LivingEntity)) + isAssignableFrom = e->instanceof(eTYPE_LIVINGENTITY); + else if (ec == typeid(ItemEntity)) + isAssignableFrom = e->instanceof(eTYPE_ITEMENTITY); + else if (ec == typeid(Minecart)) + isAssignableFrom = e->instanceof(eTYPE_MINECART); + else if (ec == typeid(Monster)) + isAssignableFrom = e->instanceof(eTYPE_MONSTER); + else if (ec == typeid(Zombie)) + isAssignableFrom = e->instanceof(eTYPE_ZOMBIE); + else if (e != NULL && ec == typeid(*(e.get()))) + isAssignableFrom = true; + if (isAssignableFrom && e->bb->intersects(bb)) { + if (selector == NULL || selector->matches(e)) { + es.push_back(e); + } } - if (isAssignableFrom && e->bb->intersects(bb)) es.push_back(e); // 4J - note needs to be equivalent to // baseClass.isAssignableFrom(e.getClass()) } @@ -1736,10 +1799,13 @@ int LevelChunk::countEntities() { bool LevelChunk::shouldSave(bool force) { if (dontSave) return false; if (force) { - if (lastSaveHadEntities && level->getTime() != lastSaveTime) + if ((lastSaveHadEntities && level->getGameTime() != lastSaveTime) || + m_unsaved) { return true; + } } else { - if (lastSaveHadEntities && level->getTime() >= lastSaveTime + 20 * 30) + if (lastSaveHadEntities && + level->getGameTime() >= lastSaveTime + 20 * 30) return true; } @@ -1796,22 +1862,22 @@ int LevelChunk::getBlocksAndData(byteArray* data, int x0, int y0, int z0, } /* -for (int x = x0; x < x1; x++) + for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) ->> 1; int len = (y1 - y0) / 2; System::arraycopy(blockLight->data, slot, data, -p, len); p += len; + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> + 1; int len = (y1 - y0) / 2; System::arraycopy(blockLight->data, slot, data, + p, len); p += len; } -for (int x = x0; x < x1; x++) + for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) ->> 1; int len = (y1 - y0) / 2; System::arraycopy(skyLight->data, slot, data, p, -len); p += len; + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> + 1; int len = (y1 - y0) / 2; System::arraycopy(skyLight->data, slot, data, p, + len); p += len; } - */ + */ return p; } @@ -1890,13 +1956,13 @@ int LevelChunk::setBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, includeLighting ? NULL : tileUpdatedCallback, this, Level::COMPRESSED_CHUNK_SECTION_HEIGHT); /* -for (int x = x0; x < x1; x++) + for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) - { - int slot = x << level->depthBitsPlusFour | z << level->depthBits | y0; - int len = y1 - y0; - System::arraycopy(data, p, &blocks, slot, len); - p += len; + { + int slot = x << level->depthBitsPlusFour | z << level->depthBits | y0; + int len = y1 - y0; + System::arraycopy(data, p, &blocks, slot, len); + p += len; }*/ recalcHeightmapOnly(); @@ -1956,22 +2022,22 @@ for (int x = x0; x < x1; x++) } /* -for (int x = x0; x < x1; x++) + for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) ->> 1; int len = (y1 - y0) / 2; System::arraycopy(data, p, &blockLight->data, -slot, len); p += len; + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> + 1; int len = (y1 - y0) / 2; System::arraycopy(data, p, &blockLight->data, + slot, len); p += len; } -for (int x = x0; x < x1; x++) + for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) ->> 1; int len = (y1 - y0) / 2; System::arraycopy(data, p, &skyLight->data, slot, -len); p += len; + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> + 1; int len = (y1 - y0) / 2; System::arraycopy(data, p, &skyLight->data, + slot, len); p += len; } - */ + */ for (AUTO_VAR(it, tileEntities.begin()); it != tileEntities.end(); ++it) { it->second->clearCache(); @@ -1991,7 +2057,7 @@ len); p += len; void LevelChunk::setCheckAllLight() { checkLightPosition = 0; } -Random* LevelChunk::getRandom(__int64 l) { +Random* LevelChunk::getRandom(int64_t l) { return new Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l); @@ -2001,15 +2067,15 @@ bool LevelChunk::isEmpty() { return false; } void LevelChunk::attemptCompression() { // 4J - removed #if 0 - try { - ByteArrayOutputStream *baos = new ByteArrayOutputStream(); - GZIPOutputStream *gzos = new GZIPOutputStream(baos); - DataOutputStream *dos = new DataOutputStream(gzos); - dos.close(); - System.out.println("Compressed size: " + baos.toByteArray().length); - } catch (Exception e) { + try { + ByteArrayOutputStream *baos = new ByteArrayOutputStream(); + GZIPOutputStream *gzos = new GZIPOutputStream(baos); + DataOutputStream *dos = new DataOutputStream(gzos); + dos.close(); + System.out.println("Compressed size: " + baos.toByteArray().length); + } catch (Exception e) { - } + } #endif } @@ -2074,20 +2140,32 @@ bool LevelChunk::isYSpaceEmpty(int y1, int y2) { return false; // 4J Unused /*if (y1 < 0) { - y1 = 0; + y1 = 0; } if (y2 >= Level.maxBuildHeight) { - y2 = Level.maxBuildHeight - 1; + y2 = Level.maxBuildHeight - 1; } for (int y = y1; y <= y2; y += 16) { - LevelChunkSection section = sections[y >> 4]; - if (section != null && !section.isEmpty()) { - return false; - } + LevelChunkSection section = sections[y >> 4]; + if (section != null && !section.isEmpty()) { + return false; + } } return true;*/ } +// 4J Added +void LevelChunk::reloadBiomes() { + BiomeSource* biomeSource = level->dimension->biomeSource; + for (unsigned int x = 0; x < 16; ++x) { + for (unsigned int z = 0; z < 16; ++z) { + Biome* biome = + biomeSource->getBiome((this->x << 4) + x, (this->z << 4) + z); + biomes[(z << 4) | x] = (uint8_t)((biome->id) & 0xff); + } + } +} + Biome* LevelChunk::getBiome(int x, int z, BiomeSource* biomeSource) { int value = biomes[((unsigned)z << 4) | x] & 0xff; if (value == 0xff) { @@ -2422,9 +2500,13 @@ int LevelChunk::getBlocksAllocatedSize(int* count0, int* count1, int* count2, int LevelChunk::getHighestNonEmptyY() { int highestNonEmptyY = -1; - if (upperBlocks) - highestNonEmptyY = upperBlocks->getHighestNonEmptyY() + - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + if (upperBlocks) { + int upperNonEmpty = upperBlocks->getHighestNonEmptyY(); + if (upperNonEmpty >= 0) { + highestNonEmptyY = + upperNonEmpty + Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + } + } if (highestNonEmptyY < 0) highestNonEmptyY = lowerBlocks->getHighestNonEmptyY(); if (highestNonEmptyY < 0) highestNonEmptyY = 0; @@ -2510,7 +2592,7 @@ byteArray LevelChunk::getReorderedBlocksAndData(int x0, int y0, int z0, int xs, // // unsigned int offset = Level::CHUNK_TILE_COUNT; //// Don't bother reordering block data, block light or sky light as they - ///don't seem to make much difference + /// don't seem to make much difference // byteArray dataData = byteArray(rawBuffer.data+offset, // Level::HALF_CHUNK_TILE_COUNT); lc->getDataData(dataData); offset += // Level::HALF_CHUNK_TILE_COUNT; byteArray blockLightData = @@ -2564,7 +2646,7 @@ void LevelChunk::reorderBlocksAndDataToXZY(int y0, int xs, int ys, int zs, // setBlocksAndData(*data, x0, y0, z0, x1, y1, z1, p); //// If it is a full chunk, we'll need to rearrange into the order the rest - ///of the game expects + /// of the game expects // if( xs == 16 && ys == 128 && zs == 16 && ( ( x & 15 ) == 0 ) && ( y == 0 // ) && ( ( z & 15 ) == 0 ) ) //{ diff --git a/Minecraft.World/Level/LevelChunk.h b/Minecraft.World/Level/LevelChunk.h index d6535ed4c..0bb5b236b 100644 --- a/Minecraft.World/Level/LevelChunk.h +++ b/Minecraft.World/Level/LevelChunk.h @@ -4,6 +4,8 @@ class DataLayer; class TileEntity; class Random; class ChunkSource; +class EntitySelector; + #include "Storage/SparseLightStorage.h" #include "Storage/CompressedTileStorage.h" #include "Storage/SparseDataStorage.h" @@ -167,9 +169,11 @@ public: void stopSharingTilesAndData(); // 4J added virtual void reSyncLighting(); // 4J added void startSharingTilesAndData(int forceMs = 0); // 4J added - __int64 lastUnsharedTime; // 4J added - __int64 lastSaveTime; + int64_t lastUnsharedTime; // 4J added + int64_t lastSaveTime; bool seenByPlayer; + int lowestHeightmap; + int64_t inhabitedTime; #ifdef _LARGE_WORLDS bool m_bUnloaded; @@ -237,14 +241,17 @@ public: virtual void removeTileEntity(int x, int y, int z); virtual void load(); virtual void unload(bool unloadTileEntities); // 4J - added parameter + virtual bool containsPlayer(); // 4J - added #ifdef _LARGE_WORLDS virtual bool isUnloaded(); #endif virtual void markUnsaved(); virtual void getEntities(std::shared_ptr except, AABB* bb, - std::vector >& es); + std::vector >& es, + const EntitySelector* selector); virtual void getEntitiesOfClass(const std::type_info& ec, AABB* bb, - std::vector >& es); + std::vector >& es, + const EntitySelector* selector); virtual int countEntities(); virtual bool shouldSave(bool force); virtual int getBlocksAndData( @@ -260,7 +267,7 @@ public: int p); // 4J added virtual void setCheckAllLight(); - virtual Random* getRandom(__int64 l); + virtual Random* getRandom(int64_t l); virtual bool isEmpty(); virtual void attemptCompression(); @@ -285,6 +292,7 @@ public: void tick(); // 4J - lighting change brought forward from 1.8.2 ChunkPos* getPos(); bool isYSpaceEmpty(int y1, int y2); + void reloadBiomes(); // 4J added virtual Biome* getBiome(int x, int z, BiomeSource* biomeSource); byteArray getBiomes(); void setBiomes(byteArray biomes); diff --git a/Minecraft.World/Level/LevelData.cpp b/Minecraft.World/Level/LevelData.cpp index 3ddbaacc6..e2a937f47 100644 --- a/Minecraft.World/Level/LevelData.cpp +++ b/Minecraft.World/Level/LevelData.cpp @@ -24,6 +24,9 @@ LevelData::LevelData(CompoundTag* tag) { m_pGenerator = m_pGenerator->getReplacementForVersion(generatorVersion); } + + if (tag->contains(L"generatorOptions")) + generatorOptions = tag->getString(L"generatorOptions"); } gameType = GameType::byId(tag->getInt(L"GameType")); @@ -37,7 +40,12 @@ LevelData::LevelData(CompoundTag* tag) { xSpawn = tag->getInt(L"SpawnX"); ySpawn = tag->getInt(L"SpawnY"); zSpawn = tag->getInt(L"SpawnZ"); - time = tag->getLong(L"Time"); + gameTime = tag->getLong(L"Time"); + if (tag->contains(L"DayTime")) { + dayTime = tag->getLong(L"DayTime"); + } else { + dayTime = gameTime; + } lastPlayed = tag->getLong(L"LastPlayed"); sizeOnDisk = tag->getLong(L"SizeOnDisk"); levelName = tag->getString(L"LevelName"); @@ -60,6 +68,12 @@ LevelData::LevelData(CompoundTag* tag) { allowCommands = gameType == GameType::CREATIVE; } + // 4J: Game rules are now stored with app game host options + /*if (tag->contains(L"GameRules")) + { + gameRules.loadFromTag(tag->getCompound(L"GameRules")); + }*/ + newSeaLevel = tag->getBoolean( L"newSeaLevel"); // 4J added - only use new sea level for newly created // maps. This read defaults to false. (sea level @@ -95,6 +109,37 @@ LevelData::LevelData(CompoundTag* tag) { m_xzSize = tag->getInt(L"XZSize"); m_hellScale = tag->getInt(L"HellScale"); +#ifdef _LARGE_WORLDS + m_classicEdgeMoat = tag->getInt(L"ClassicMoat"); + m_smallEdgeMoat = tag->getInt(L"SmallMoat"); + m_mediumEdgeMoat = tag->getInt(L"MediumMoat"); + + int newWorldSize = app.GetGameNewWorldSize(); + int newHellScale = app.GetGameNewHellScale(); + m_hellScaleOld = m_hellScale; + m_xzSizeOld = m_xzSize; + if (newWorldSize > m_xzSize) { + bool bUseMoat = app.GetGameNewWorldSizeUseMoat(); + switch (m_xzSize) { + case LEVEL_WIDTH_CLASSIC: + m_classicEdgeMoat = bUseMoat; + break; + case LEVEL_WIDTH_SMALL: + m_smallEdgeMoat = bUseMoat; + break; + case LEVEL_WIDTH_MEDIUM: + m_mediumEdgeMoat = bUseMoat; + break; + default: + assert(0); + break; + } + assert(newWorldSize > m_xzSize); + m_xzSize = newWorldSize; + m_hellScale = newHellScale; + } +#endif + m_xzSize = std::min(m_xzSize, LEVEL_MAX_WIDTH); m_xzSize = std::max(m_xzSize, LEVEL_MIN_WIDTH); @@ -108,15 +153,38 @@ LevelData::LevelData(CompoundTag* tag) { hellXZSize = m_xzSize / m_hellScale; } +#ifdef _LARGE_WORLDS + // set the host option, in case it wasn't setup already + EGameHostOptionWorldSize hostOptionworldSize = e_worldSize_Unknown; + switch (m_xzSize) { + case LEVEL_WIDTH_CLASSIC: + hostOptionworldSize = e_worldSize_Classic; + break; + case LEVEL_WIDTH_SMALL: + hostOptionworldSize = e_worldSize_Small; + break; + case LEVEL_WIDTH_MEDIUM: + hostOptionworldSize = e_worldSize_Medium; + break; + case LEVEL_WIDTH_LARGE: + hostOptionworldSize = e_worldSize_Large; + break; + default: + assert(0); + break; + } + app.SetGameHostOption(eGameHostOption_WorldSize, hostOptionworldSize); +#endif + /* 4J - we don't store this anymore -if (tag->contains(L"Player")) + if (tag->contains(L"Player")) { loadedPlayerTag = tag->getCompound(L"Player"); dimension = loadedPlayerTag->getInt(L"Dimension"); -} + } else { - this->loadedPlayerTag = NULL; + this->loadedPlayerTag = NULL; } */ dimension = 0; @@ -124,46 +192,48 @@ if (tag->contains(L"Player")) LevelData::LevelData(LevelSettings* levelSettings, const std::wstring& levelName) { - this->seed = levelSettings->getSeed(); - this->gameType = levelSettings->getGameType(); - this->generateMapFeatures = levelSettings->isGenerateMapFeatures(); - this->spawnBonusChest = levelSettings->hasStartingBonusItems(); + seed = levelSettings->getSeed(); + gameType = levelSettings->getGameType(); + generateMapFeatures = levelSettings->isGenerateMapFeatures(); + spawnBonusChest = levelSettings->hasStartingBonusItems(); this->levelName = levelName; - this->m_pGenerator = levelSettings->getLevelType(); - this->hardcore = levelSettings->isHardcore(); + m_pGenerator = levelSettings->getLevelType(); + hardcore = levelSettings->isHardcore(); + generatorOptions = levelSettings->getLevelTypeOptions(); + allowCommands = levelSettings->getAllowCommands(); // 4J Stu - Default initers - this->xSpawn = 0; - this->ySpawn = 0; - this->zSpawn = 0; - this->time = -1; // 4J-JEV: Edited: To know when this is uninitialized. - this->lastPlayed = 0; - this->sizeOnDisk = 0; + xSpawn = 0; + ySpawn = 0; + zSpawn = 0; + dayTime = -1; // 4J-JEV: Edited: To know when this is uninitialized. + gameTime = -1; + lastPlayed = 0; + sizeOnDisk = 0; // this->loadedPlayerTag = NULL; // 4J - we don't store this anymore - this->dimension = 0; - this->version = 0; - this->rainTime = 0; - this->raining = false; - this->thunderTime = 0; - this->thundering = false; - this->allowCommands = levelSettings->getAllowCommands(); - this->initialized = false; - this->newSeaLevel = + dimension = 0; + version = 0; + rainTime = 0; + raining = false; + thunderTime = 0; + thundering = false; + initialized = false; + newSeaLevel = levelSettings ->useNewSeaLevel(); // 4J added - only use new sea level for newly // created maps (sea level changes in 1.8.2) - this->hasBeenInCreative = + hasBeenInCreative = levelSettings->getGameType() == GameType::CREATIVE; // 4J added // 4J-PB for the stronghold position - this->bStronghold = false; - this->xStronghold = 0; - this->yStronghold = 0; - this->zStronghold = 0; + bStronghold = false; + xStronghold = 0; + yStronghold = 0; + zStronghold = 0; - this->xStrongholdEndPortal = 0; - this->zStrongholdEndPortal = 0; - this->bStrongholdEndPortal = false; + xStrongholdEndPortal = 0; + zStrongholdEndPortal = 0; + bStrongholdEndPortal = false; m_xzSize = levelSettings->getXZSize(); m_hellScale = levelSettings->getHellScale(); @@ -179,46 +249,63 @@ LevelData::LevelData(LevelSettings* levelSettings, ++m_hellScale; hellXZSize = m_xzSize / m_hellScale; } +#ifdef _LARGE_WORLDS + m_hellScaleOld = m_hellScale; + m_xzSizeOld = m_xzSize; + m_classicEdgeMoat = false; + m_smallEdgeMoat = false; + m_mediumEdgeMoat = false; +#endif } LevelData::LevelData(LevelData* copy) { - this->seed = copy->seed; - this->m_pGenerator = copy->m_pGenerator; - this->gameType = copy->gameType; - this->generateMapFeatures = copy->generateMapFeatures; - this->spawnBonusChest = copy->spawnBonusChest; - this->xSpawn = copy->xSpawn; - this->ySpawn = copy->ySpawn; - this->zSpawn = copy->zSpawn; - this->time = copy->time; - this->lastPlayed = copy->lastPlayed; - this->sizeOnDisk = copy->sizeOnDisk; + seed = copy->seed; + m_pGenerator = copy->m_pGenerator; + generatorOptions = copy->generatorOptions; + gameType = copy->gameType; + generateMapFeatures = copy->generateMapFeatures; + spawnBonusChest = copy->spawnBonusChest; + xSpawn = copy->xSpawn; + ySpawn = copy->ySpawn; + zSpawn = copy->zSpawn; + gameTime = copy->gameTime; + dayTime = copy->dayTime; + lastPlayed = copy->lastPlayed; + sizeOnDisk = copy->sizeOnDisk; // this->loadedPlayerTag = copy->loadedPlayerTag; // 4J - // we don't store this anymore - this->dimension = copy->dimension; - this->levelName = copy->levelName; - this->version = copy->version; - this->rainTime = copy->rainTime; - this->raining = copy->raining; - this->thunderTime = copy->thunderTime; - this->thundering = copy->thundering; - this->hardcore = copy->hardcore; - this->allowCommands = copy->allowCommands; - this->initialized = copy->initialized; - this->newSeaLevel = copy->newSeaLevel; - this->hasBeenInCreative = copy->hasBeenInCreative; + dimension = copy->dimension; + levelName = copy->levelName; + version = copy->version; + rainTime = copy->rainTime; + raining = copy->raining; + thunderTime = copy->thunderTime; + thundering = copy->thundering; + hardcore = copy->hardcore; + allowCommands = copy->allowCommands; + initialized = copy->initialized; + newSeaLevel = copy->newSeaLevel; + hasBeenInCreative = copy->hasBeenInCreative; + gameRules = copy->gameRules; // 4J-PB for the stronghold position - this->bStronghold = copy->bStronghold; - this->xStronghold = copy->xStronghold; - this->yStronghold = copy->yStronghold; - this->zStronghold = copy->zStronghold; + bStronghold = copy->bStronghold; + xStronghold = copy->xStronghold; + yStronghold = copy->yStronghold; + zStronghold = copy->zStronghold; - this->xStrongholdEndPortal = copy->xStrongholdEndPortal; - this->zStrongholdEndPortal = copy->zStrongholdEndPortal; - this->bStrongholdEndPortal = copy->bStrongholdEndPortal; + xStrongholdEndPortal = copy->xStrongholdEndPortal; + zStrongholdEndPortal = copy->zStrongholdEndPortal; + bStrongholdEndPortal = copy->bStrongholdEndPortal; m_xzSize = copy->m_xzSize; m_hellScale = copy->m_hellScale; +#ifdef _LARGE_WORLDS + m_classicEdgeMoat = copy->m_classicEdgeMoat; + m_smallEdgeMoat = copy->m_smallEdgeMoat; + m_mediumEdgeMoat = copy->m_mediumEdgeMoat; + m_xzSizeOld = copy->m_xzSizeOld; + m_hellScaleOld = copy->m_hellScaleOld; +#endif } CompoundTag* LevelData::createTag() { @@ -239,13 +326,15 @@ void LevelData::setTagData(CompoundTag* tag) { tag->putLong(L"RandomSeed", seed); tag->putString(L"generatorName", m_pGenerator->getGeneratorName()); tag->putInt(L"generatorVersion", m_pGenerator->getVersion()); + tag->putString(L"generatorOptions", generatorOptions); tag->putInt(L"GameType", gameType->getId()); tag->putBoolean(L"MapFeatures", generateMapFeatures); tag->putBoolean(L"spawnBonusChest", spawnBonusChest); tag->putInt(L"SpawnX", xSpawn); tag->putInt(L"SpawnY", ySpawn); tag->putInt(L"SpawnZ", zSpawn); - tag->putLong(L"Time", time); + tag->putLong(L"Time", gameTime); + tag->putLong(L"DayTime", dayTime); tag->putLong(L"SizeOnDisk", sizeOnDisk); tag->putLong(L"LastPlayed", System::currentTimeMillis()); tag->putString(L"LevelName", levelName); @@ -257,6 +346,8 @@ void LevelData::setTagData(CompoundTag* tag) { tag->putBoolean(L"hardcore", hardcore); tag->putBoolean(L"allowCommands", allowCommands); tag->putBoolean(L"initialized", initialized); + // 4J: Game rules are now stored with app game host options + // tag->putCompound(L"GameRules", gameRules.createTag()); tag->putBoolean(L"newSeaLevel", newSeaLevel); tag->putBoolean(L"hasBeenInCreative", hasBeenInCreative); // store the stronghold position @@ -269,10 +360,16 @@ void LevelData::setTagData(CompoundTag* tag) { tag->putInt(L"StrongholdEndPortalX", xStrongholdEndPortal); tag->putInt(L"StrongholdEndPortalZ", zStrongholdEndPortal); tag->putInt(L"XZSize", m_xzSize); +#ifdef _LARGE_WORLDS + tag->putInt(L"ClassicMoat", m_classicEdgeMoat); + tag->putInt(L"SmallMoat", m_smallEdgeMoat); + tag->putInt(L"MediumMoat", m_mediumEdgeMoat); +#endif + tag->putInt(L"HellScale", m_hellScale); } -__int64 LevelData::getSeed() { return seed; } +int64_t LevelData::getSeed() { return seed; } int LevelData::getXSpawn() { return xSpawn; } @@ -288,9 +385,11 @@ int LevelData::getXStrongholdEndPortal() { return xStrongholdEndPortal; } int LevelData::getZStrongholdEndPortal() { return zStrongholdEndPortal; } -__int64 LevelData::getTime() { return time; } +int64_t LevelData::getGameTime() { return gameTime; } -__int64 LevelData::getSizeOnDisk() { return sizeOnDisk; } +int64_t LevelData::getDayTime() { return dayTime; } + +int64_t LevelData::getSizeOnDisk() { return sizeOnDisk; } CompoundTag* LevelData::getLoadedPlayerTag() { return NULL; // 4J - we don't store this anymore @@ -302,7 +401,7 @@ CompoundTag* LevelData::getLoadedPlayerTag() { // return dimension; //} -void LevelData::setSeed(__int64 seed) { this->seed = seed; } +void LevelData::setSeed(int64_t seed) { this->seed = seed; } void LevelData::setXSpawn(int xSpawn) { this->xSpawn = xSpawn; } @@ -338,9 +437,11 @@ void LevelData::setZStrongholdEndPortal(int zStrongholdEndPortal) { this->zStrongholdEndPortal = zStrongholdEndPortal; } -void LevelData::setTime(__int64 time) { this->time = time; } +void LevelData::setGameTime(int64_t time) { gameTime = time; } -void LevelData::setSizeOnDisk(__int64 sizeOnDisk) { +void LevelData::setDayTime(int64_t time) { dayTime = time; } + +void LevelData::setSizeOnDisk(int64_t sizeOnDisk) { this->sizeOnDisk = sizeOnDisk; } @@ -371,7 +472,7 @@ int LevelData::getVersion() { return version; } void LevelData::setVersion(int version) { this->version = version; } -__int64 LevelData::getLastPlayed() { return lastPlayed; } +int64_t LevelData::getLastPlayed() { return lastPlayed; } bool LevelData::isThundering() { return thundering; } @@ -405,7 +506,7 @@ void LevelData::setGameType(GameType* gameType) { // 4J Added hasBeenInCreative = hasBeenInCreative || (gameType == GameType::CREATIVE) || - app.GetGameHostOption(eGameHostOption_CheatsEnabled) > 0; + (app.GetGameHostOption(eGameHostOption_CheatsEnabled) > 0); } bool LevelData::useNewSeaLevel() { return newSeaLevel; } @@ -418,6 +519,12 @@ LevelType* LevelData::getGenerator() { return m_pGenerator; } void LevelData::setGenerator(LevelType* generator) { m_pGenerator = generator; } +std::wstring LevelData::getGeneratorOptions() { return generatorOptions; } + +void LevelData::setGeneratorOptions(const std::wstring& options) { + generatorOptions = options; +} + bool LevelData::isHardcore() { return hardcore; } bool LevelData::getAllowCommands() { return allowCommands; } @@ -432,6 +539,33 @@ void LevelData::setInitialized(bool initialized) { this->initialized = initialized; } +GameRules* LevelData::getGameRules() { return &gameRules; } + int LevelData::getXZSize() { return m_xzSize; } +#ifdef _LARGE_WORLDS +int LevelData::getXZSizeOld() { return m_xzSizeOld; } + +void LevelData::getMoatFlags(bool* bClassicEdgeMoat, bool* bSmallEdgeMoat, + bool* bMediumEdgeMoat) { + *bClassicEdgeMoat = m_classicEdgeMoat; + *bSmallEdgeMoat = m_smallEdgeMoat; + *bMediumEdgeMoat = m_mediumEdgeMoat; +} + +int LevelData::getXZHellSizeOld() { + int hellXZSizeOld = ceil((float)m_xzSizeOld / m_hellScaleOld); + + while (hellXZSizeOld > HELL_LEVEL_MAX_WIDTH && + m_hellScaleOld < HELL_LEVEL_MAX_SCALE) { + assert(0); // should never get in here? + ++m_hellScaleOld; + hellXZSizeOld = m_xzSize / m_hellScale; + } + + return hellXZSizeOld; +} + +#endif + int LevelData::getHellScale() { return m_hellScale; } diff --git a/Minecraft.World/Level/LevelData.h b/Minecraft.World/Level/LevelData.h index af065de6f..56101dc37 100644 --- a/Minecraft.World/Level/LevelData.h +++ b/Minecraft.World/Level/LevelData.h @@ -1,5 +1,7 @@ #pragma once +#include "GameRules.h" + class Player; class CompoundTag; class LevelSettings; @@ -10,14 +12,16 @@ class LevelData { friend class DerivedLevelData; private: - __int64 seed; + int64_t seed; LevelType* m_pGenerator; // = LevelType.normal; + std::wstring generatorOptions; int xSpawn; int ySpawn; int zSpawn; - __int64 time; - __int64 lastPlayed; - __int64 sizeOnDisk; + int64_t gameTime; + int64_t dayTime; + int64_t lastPlayed; + int64_t sizeOnDisk; // CompoundTag *loadedPlayerTag; // 4J removed int dimension; std::wstring levelName; @@ -37,7 +41,14 @@ private: bool hasBeenInCreative; // 4J added bool spawnBonusChest; // 4J added int m_xzSize; // 4J Added - int m_hellScale; // 4J Added +#ifdef _LARGE_WORLDS + int m_xzSizeOld; // 4J MGH Added, for expanding worlds + int m_hellScaleOld; + bool m_classicEdgeMoat; + bool m_smallEdgeMoat; + bool m_mediumEdgeMoat; +#endif + int m_hellScale; // 4J Added // 4J added int xStronghold; @@ -49,6 +60,8 @@ private: int zStrongholdEndPortal; bool bStrongholdEndPortal; + GameRules gameRules; + protected: LevelData(); @@ -66,8 +79,7 @@ protected: CompoundTag* tag); // 4J - removed CompoundTag *playerTag public: - virtual ~LevelData() {} - virtual __int64 getSeed(); + virtual int64_t getSeed(); virtual int getXSpawn(); virtual int getYSpawn(); virtual int getZSpawn(); @@ -75,11 +87,12 @@ public: virtual int getZStronghold(); virtual int getXStrongholdEndPortal(); virtual int getZStrongholdEndPortal(); - virtual __int64 getTime(); - virtual __int64 getSizeOnDisk(); + virtual int64_t getGameTime(); + virtual int64_t getDayTime(); + virtual int64_t getSizeOnDisk(); virtual CompoundTag* getLoadedPlayerTag(); // int getDimension(); // 4J Removed TU 9 as it's never accurate - virtual void setSeed(__int64 seed); + virtual void setSeed(int64_t seed); virtual void setXSpawn(int xSpawn); virtual void setYSpawn(int ySpawn); virtual void setZSpawn(int zSpawn); @@ -92,8 +105,9 @@ public: virtual void setXStrongholdEndPortal(int xStrongholdEndPortal); virtual void setZStrongholdEndPortal(int zStrongholdEndPortal); - virtual void setTime(__int64 time); - virtual void setSizeOnDisk(__int64 sizeOnDisk); + virtual void setGameTime(int64_t time); + virtual void setDayTime(int64_t time); + virtual void setSizeOnDisk(int64_t sizeOnDisk); virtual void setLoadedPlayerTag(CompoundTag* loadedPlayerTag); // void setDimension(int dimension); // 4J Removed TU 9 as it's never used virtual void setSpawn(int xSpawn, int ySpawn, int zSpawn); @@ -101,7 +115,7 @@ public: virtual void setLevelName(const std::wstring& levelName); virtual int getVersion(); virtual void setVersion(int version); - virtual __int64 getLastPlayed(); + virtual int64_t getLastPlayed(); virtual bool isThundering(); virtual void setThundering(bool thundering); virtual int getThunderTime(); @@ -119,11 +133,21 @@ public: virtual void setHasBeenInCreative(bool value); // 4J Added virtual LevelType* getGenerator(); virtual void setGenerator(LevelType* generator); + virtual std::wstring getGeneratorOptions(); + virtual void setGeneratorOptions(const std::wstring& options); virtual bool isHardcore(); virtual bool getAllowCommands(); virtual void setAllowCommands(bool allowCommands); virtual bool isInitialized(); virtual void setInitialized(bool initialized); - virtual int getXZSize(); // 4J Added + virtual GameRules* getGameRules(); + virtual int getXZSize(); // 4J Added +#ifdef _LARGE_WORLDS + virtual int getXZSizeOld(); // 4J Added + virtual void getMoatFlags(bool* bClassicEdgeMoat, bool* bSmallEdgeMoat, + bool* bMediumEdgeMoat); // 4J MGH - added + virtual int getXZHellSizeOld(); // 4J Added + +#endif virtual int getHellScale(); // 4J Addded }; diff --git a/Minecraft.World/Level/RandomLevelSource.cpp b/Minecraft.World/Level/RandomLevelSource.cpp index eaea7a427..61e8e3361 100644 --- a/Minecraft.World/Level/RandomLevelSource.cpp +++ b/Minecraft.World/Level/RandomLevelSource.cpp @@ -7,6 +7,7 @@ #include "../Headers/net.minecraft.world.level.levelgen.synth.h" #include "../Headers/net.minecraft.world.level.tile.h" #include "../Headers/net.minecraft.world.level.storage.h" +#include "../Headers/net.minecraft.world.entity.h" #include "RandomLevelSource.h" #ifdef __PS3__ @@ -17,19 +18,24 @@ static PerlinNoise_DataIn g_lperlinNoise2_SPU __attribute__((__aligned__(16))); static PerlinNoise_DataIn g_perlinNoise1_SPU __attribute__((__aligned__(16))); static PerlinNoise_DataIn g_scaleNoise_SPU __attribute__((__aligned__(16))); static PerlinNoise_DataIn g_depthNoise_SPU __attribute__((__aligned__(16))); +// #define DISABLE_SPU_CODE + #endif const double RandomLevelSource::SNOW_SCALE = 0.3; const double RandomLevelSource::SNOW_CUTOFF = 0.5; -RandomLevelSource::RandomLevelSource(Level* level, __int64 seed, +RandomLevelSource::RandomLevelSource(Level* level, int64_t seed, bool generateStructures) : generateStructures(generateStructures) { m_XZSize = level->getLevelData()->getXZSize(); - +#ifdef _LARGE_WORLDS + level->getLevelData()->getMoatFlags(&m_classicEdgeMoat, &m_smallEdgeMoat, + &m_mediumEdgeMoat); +#endif caveFeature = new LargeCaveFeature(); strongholdFeature = new StrongholdFeature(); - villageFeature = new VillageFeature(0, m_XZSize); + villageFeature = new VillageFeature(m_XZSize); mineShaftFeature = new MineShaftFeature(); scatteredFeature = new RandomScatteredLargeFeature(); canyonFeature = new CanyonFeature(); @@ -67,6 +73,8 @@ RandomLevelSource::~RandomLevelSource() { delete scatteredFeature; delete canyonFeature; + this->level = level; + delete random; ; delete lperlinNoise1; @@ -91,6 +99,140 @@ int g_numPrepareHeightCalls = 0; LARGE_INTEGER g_totalPrepareHeightsTime = {0, 0}; LARGE_INTEGER g_averagePrepareHeightsTime = {0, 0}; +#ifdef _LARGE_WORLDS + +int RandomLevelSource::getMinDistanceToEdge(int xxx, int zzz, int worldSize, + float falloffStart) { + // Get distance to edges of world in x + // we have to do a proper line dist check here + int min = -worldSize / 2; + int max = (worldSize / 2) - 1; + + // // only check if either x or z values are within the falloff + // if(xxx > (min - falloffStart) + + Vec3* topLeft = Vec3::newTemp(min, 0, min); + Vec3* topRight = Vec3::newTemp(max, 0, min); + Vec3* bottomLeft = Vec3::newTemp(min, 0, max); + Vec3* bottomRight = Vec3::newTemp(max, 0, max); + + float closest = falloffStart; + float dist; + // make sure we're in range of the edges before we do a full distance check + if ((xxx > (min - falloffStart) && xxx < (min + falloffStart)) || + (xxx > (max - falloffStart) && xxx < (max + falloffStart))) { + Vec3* point = Vec3::newTemp(xxx, 0, zzz); + if (xxx > 0) + dist = point->distanceFromLine(topRight, bottomRight); + else + dist = point->distanceFromLine(topLeft, bottomLeft); + closest = dist; + } + + // make sure we're in range of the edges before we do a full distance check + if ((zzz > (min - falloffStart) && zzz < (min + falloffStart)) || + (zzz > (max - falloffStart) && zzz < (max + falloffStart))) { + Vec3* point = Vec3::newTemp(xxx, 0, zzz); + if (zzz > 0) + dist = point->distanceFromLine(bottomLeft, bottomRight); + else + dist = point->distanceFromLine(topLeft, topRight); + if (dist < closest) closest = dist; + } + + return closest; +} + +float RandomLevelSource::getHeightFalloff(int xxx, int zzz, int* pEMin) { + /////////////////////////////////////////////////////////////////// + // 4J - add this chunk of code to make land "fall-off" at the edges of + // a finite world - size of that world is currently hard-coded in here + const int worldSize = m_XZSize * 16; + const int falloffStart = + 32; // chunks away from edge were we start doing fall-off + const float falloffMax = + 128.0f; // max value we need to get to falloff by the edge of the map + + float comp = 0.0f; + int emin = getMinDistanceToEdge(xxx, zzz, worldSize, falloffStart); + // check if we have a larger world that should have moats + int expandedWorldSizes[3] = {LEVEL_WIDTH_CLASSIC * 16, + LEVEL_WIDTH_SMALL * 16, + LEVEL_WIDTH_MEDIUM * 16}; + bool expandedMoatValues[3] = {m_classicEdgeMoat, m_smallEdgeMoat, + m_mediumEdgeMoat}; + for (int i = 0; i < 3; i++) { + if (expandedMoatValues[i] && (worldSize > expandedWorldSizes[i])) { + // this world has been expanded, with moat settings, so we need + // fallofs at this edges too + int eminMoat = getMinDistanceToEdge(xxx, zzz, expandedWorldSizes[i], + falloffStart); + if (eminMoat < emin) { + emin = eminMoat; + } + } + } + + // Calculate how much we want the world to fall away, if we're in the + // defined region to do so + if (emin < falloffStart) { + int falloff = falloffStart - emin; + comp = ((float)falloff / (float)falloffStart) * falloffMax; + } + *pEMin = emin; + return comp; + // 4J - end of extra code + /////////////////////////////////////////////////////////////////// +} + +#else + +// MGH - go back to using the simpler version for PS3/vita/360, as it was +// causing a lot of slow down on the tuturial generation +float RandomLevelSource::getHeightFalloff(int xxx, int zzz, int* pEMin) { + /////////////////////////////////////////////////////////////////// + // 4J - add this chunk of code to make land "fall-off" at the edges of + // a finite world - size of that world is currently hard-coded in here + const int worldSize = m_XZSize * 16; + const int falloffStart = + 32; // chunks away from edge were we start doing fall-off + const float falloffMax = + 128.0f; // max value we need to get to falloff by the edge of the map + + // Get distance to edges of world in x + int xxx0 = xxx + (worldSize / 2); + if (xxx0 < 0) xxx0 = 0; + int xxx1 = ((worldSize / 2) - 1) - xxx; + if (xxx1 < 0) xxx1 = 0; + + // Get distance to edges of world in z + int zzz0 = zzz + (worldSize / 2); + if (zzz0 < 0) zzz0 = 0; + int zzz1 = ((worldSize / 2) - 1) - zzz; + if (zzz1 < 0) zzz1 = 0; + + // Get min distance to any edge + int emin = xxx0; + if (xxx1 < emin) emin = xxx1; + if (zzz0 < emin) emin = zzz0; + if (zzz1 < emin) emin = zzz1; + + float comp = 0.0f; + + // Calculate how much we want the world to fall away, if we're in the + // defined region to do so + if (emin < falloffStart) { + int falloff = falloffStart - emin; + comp = ((float)falloff / (float)falloffStart) * falloffMax; + } + // 4J - end of extra code + /////////////////////////////////////////////////////////////////// + *pEMin = emin; + return comp; +} + +#endif // _LARGE_WORLDS + void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { LARGE_INTEGER startTime; int xChunks = 16 / CHUNK_WIDTH; @@ -166,50 +308,19 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { double vala = (_s1 - _s0) * zStep; val -= vala; for (int z = 0; z < CHUNK_WIDTH; z++) { - /////////////////////////////////////////////////////////////////// - // 4J - add this chunk of code to make land - // "fall-off" at the edges of a finite world - size - // of that world is currently hard-coded in here - const int worldSize = m_XZSize * 16; - const int falloffStart = - 32; // chunks away from edge were we start - // doing fall-off - const float falloffMax = - 128.0f; // max value we need to get to falloff - // by the edge of the map - + // 4J Stu - I have removed all uses of the new + // getHeightFalloff function for now as we had some + // problems with PS3/PSVita world generation I have + // fixed the non large worlds method, however we + // will be happier if the current builds go out with + // completely old code We can put the new code back + // in mid-november 2014 once those PS3/Vita builds + // are gone (and the PS4 doesn't have world + // enlarging in these either anyway) int xxx = ((xOffs * 16) + x + (xc * CHUNK_WIDTH)); int zzz = ((zOffs * 16) + z + (zc * CHUNK_WIDTH)); - - // Get distance to edges of world in x - int xxx0 = xxx + (worldSize / 2); - if (xxx0 < 0) xxx0 = 0; - int xxx1 = ((worldSize / 2) - 1) - xxx; - if (xxx1 < 0) xxx1 = 0; - - // Get distance to edges of world in z - int zzz0 = zzz + (worldSize / 2); - if (zzz0 < 0) zzz0 = 0; - int zzz1 = ((worldSize / 2) - 1) - zzz; - if (zzz1 < 0) zzz1 = 0; - - // Get min distance to any edge - int emin = xxx0; - if (xxx1 < emin) emin = xxx1; - if (zzz0 < emin) emin = zzz0; - if (zzz1 < emin) emin = zzz1; - - float comp = 0.0f; - - // Calculate how much we want the world to fall - // away, if we're in the defined region to do so - if (emin < falloffStart) { - int falloff = falloffStart - emin; - comp = ((float)falloff / (float)falloffStart) * - falloffMax; - } - // 4J - end of extra code - /////////////////////////////////////////////////////////////////// + int emin; + float comp = getHeightFalloff(xxx, zzz, &emin); // 4J - slightly rearranged this code (as of // java 1.0.1 merge) to better fit with changes @@ -220,7 +331,7 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { // 4J - this comparison used to just be with 0.0f // but is now varied by block above if ((val += vala) > comp) { - tileId = (uint8_t)Tile::rock_Id; + tileId = (uint8_t)Tile::stone_Id; } else if (yc * CHUNK_HEIGHT + y < waterHeight) { tileId = (uint8_t)Tile::calmWater_Id; } @@ -236,7 +347,7 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { // the edge of the world if (yc * CHUNK_HEIGHT + y <= (level->getSeaLevel() - 10)) - tileId = Tile::rock_Id; + tileId = Tile::stone_Id; else if (yc * CHUNK_HEIGHT + y < level->getSeaLevel()) tileId = Tile::calmWater_Id; @@ -305,7 +416,8 @@ void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, if (y <= 1 + random->nextInt( 2)) // 4J - changed to make the bedrock not // have bits you can get stuck in - // if (y <= 0 + random->nextInt(5)) + // if (y <= 0 + + // random->nextInt(5)) { blocks[offs] = (uint8_t)Tile::unbreakable_Id; } else { @@ -313,11 +425,11 @@ void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, if (old == 0) { run = -1; - } else if (old == Tile::rock_Id) { + } else if (old == Tile::stone_Id) { if (run == -1) { if (runDepth <= 0) { top = 0; - material = (uint8_t)Tile::rock_Id; + material = (uint8_t)Tile::stone_Id; } else if (y >= waterHeight - 4 && y <= waterHeight + 1) { top = b->topMaterial; @@ -343,8 +455,7 @@ void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, run--; blocks[offs] = material; - // place a few sandstone blocks beneath sand - // runs + // place a few sandstone blocks beneath sand runs if (run == 0 && material == Tile::sand_Id) { run = random->nextInt(4); material = (uint8_t)Tile::sandStone_Id; @@ -636,18 +747,19 @@ void RandomLevelSource::calcWaterDepths(ChunkSource* parent, int xt, int zt) { level->getData(xp + x2, y, zp + z2); if (od < 7 && od < d) { level->setData(xp + x2, y, zp + z2, - d); + d, Tile::UPDATE_ALL); } } } } } if (hadWater) { - level->setTileAndDataNoUpdate( - xp, y, zp, Tile::calmWater_Id, 7); + level->setTileAndData(xp, y, zp, Tile::calmWater_Id, + 7, Tile::UPDATE_CLIENTS); for (int y2 = 0; y2 < y; y2++) { - level->setTileAndDataNoUpdate( - xp, y2, zp, Tile::calmWater_Id, 8); + level->setTileAndData(xp, y2, zp, + Tile::calmWater_Id, 8, + Tile::UPDATE_CLIENTS); } } } @@ -666,7 +778,7 @@ void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { Biome* biome = level->getBiome(xo + 16, zo + 16); - if (RandomLevelSource::FLOATING_ISLANDS) { + if (FLOATING_ISLANDS) { calcWaterDepths(parent, xt, zt); } @@ -690,14 +802,15 @@ void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { PIXEndNamedEvent(); PIXBeginNamedEvent(0, "Lakes"); - if (!hasVillage && pprandom->nextInt(4) == 0) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth); - int z = zo + pprandom->nextInt(16) + 8; + if (biome != Biome::desert && biome != Biome::desertHills) { + if (!hasVillage && pprandom->nextInt(4) == 0) { + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth); + int z = zo + pprandom->nextInt(16) + 8; - LakeFeature* calmWater = new LakeFeature(Tile::calmWater_Id); - calmWater->place(level, pprandom, x, y, z); - delete calmWater; + LakeFeature calmWater(Tile::calmWater_Id); + calmWater.place(level, pprandom, x, y, z); + } } PIXEndNamedEvent(); @@ -707,9 +820,8 @@ void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { int y = pprandom->nextInt(pprandom->nextInt(Level::genDepth - 8) + 8); int z = zo + pprandom->nextInt(16) + 8; if (y < level->seaLevel || pprandom->nextInt(10) == 0) { - LakeFeature* calmLava = new LakeFeature(Tile::calmLava_Id); - calmLava->place(level, pprandom, x, y, z); - delete calmLava; + LakeFeature calmLava(Tile::calmLava_Id); + calmLava.place(level, pprandom, x, y, z); } } PIXEndNamedEvent(); @@ -719,10 +831,8 @@ void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { int x = xo + pprandom->nextInt(16) + 8; int y = pprandom->nextInt(Level::genDepth); int z = zo + pprandom->nextInt(16) + 8; - MonsterRoomFeature* mrf = new MonsterRoomFeature(); - if (mrf->place(level, pprandom, x, y, z)) { - } - delete mrf; + MonsterRoomFeature mrf; + mrf.place(level, pprandom, x, y, z); } PIXEndNamedEvent(); @@ -730,11 +840,16 @@ void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { biome->decorate(level, pprandom, xo, zo); PIXEndNamedEvent(); + PIXBeginNamedEvent(0, "Process Schematics"); app.processSchematics(parent->getChunk(xt, zt)); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0, "Post process mobs"); MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, pprandom); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0, "Update ice and snow"); // 4J - brought forward from 1.2.3 to get snow back in taiga biomes xo += 8; zo += 8; @@ -743,17 +858,16 @@ void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { int y = level->getTopRainBlock(xo + x, zo + z); if (level->shouldFreezeIgnoreNeighbors(x + xo, y - 1, z + zo)) { - level->setTileNoUpdate( - x + xo, y - 1, z + zo, - Tile::ice_Id); // 4J - changed from setTile, otherwise we - // end up creating a *lot* of dynamic water - // tiles as these ice tiles are set + level->setTileAndData(x + xo, y - 1, z + zo, Tile::ice_Id, 0, + Tile::UPDATE_CLIENTS); } if (level->shouldSnow(x + xo, y, z + zo)) { - level->setTile(x + xo, y, z + zo, Tile::topSnow_Id); + level->setTileAndData(x + xo, y, z + zo, Tile::topSnow_Id, 0, + Tile::UPDATE_CLIENTS); } } } + PIXEndNamedEvent(); HeavyTile::instaFall = false; } @@ -774,6 +888,10 @@ std::vector* RandomLevelSource::getMobsAt( if (biome == NULL) { return NULL; } + if (mobCategory == MobCategory::monster && + scatteredFeature->isSwamphut(x, y, z)) { + return scatteredFeature->getSwamphutEnemies(); + } return biome->getMobs(mobCategory); } @@ -784,3 +902,13 @@ TilePos* RandomLevelSource::findNearestMapFeature( } return NULL; } + +void RandomLevelSource::recreateLogicStructuresForChunk(int chunkX, + int chunkZ) { + if (generateStructures) { + mineShaftFeature->apply(this, level, chunkX, chunkZ, NULL); + villageFeature->apply(this, level, chunkX, chunkZ, NULL); + strongholdFeature->apply(this, level, chunkX, chunkZ, NULL); + scatteredFeature->apply(this, level, chunkX, chunkZ, NULL); + } +} \ No newline at end of file diff --git a/Minecraft.World/Level/RandomLevelSource.h b/Minecraft.World/Level/RandomLevelSource.h index 3670a1cb2..9c23ab8dc 100644 --- a/Minecraft.World/Level/RandomLevelSource.h +++ b/Minecraft.World/Level/RandomLevelSource.h @@ -45,10 +45,16 @@ private: floatArray pows; public: - RandomLevelSource(Level* level, __int64 seed, bool generateStructures); + RandomLevelSource(Level* level, int64_t seed, bool generateStructures); ~RandomLevelSource(); public: +#ifdef _LARGE_WORLDS + int getMinDistanceToEdge(int xxx, int zzz, int worldSize, + float falloffStart); + +#endif + float getHeightFalloff(int xxx, int zzz, int* pEMin); void prepareHeights(int xOffs, int zOffs, byteArray blocks); public: @@ -93,4 +99,5 @@ public: virtual TilePos* findNearestMapFeature(Level* level, const std::wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/Level/Redstone.cpp b/Minecraft.World/Level/Redstone.cpp new file mode 100644 index 000000000..6a78dfc88 --- /dev/null +++ b/Minecraft.World/Level/Redstone.cpp @@ -0,0 +1,8 @@ +#include "../Platform/stdafx.h" + +#include "Redstone.h" + +// 4J-JEV: Because whiny Ps4 compiler. +const int Redstone::SIGNAL_NONE; +const int Redstone::SIGNAL_MIN; +const int Redstone::SIGNAL_MAX; \ No newline at end of file diff --git a/Minecraft.World/Level/Redstone.h b/Minecraft.World/Level/Redstone.h new file mode 100644 index 000000000..d75ac653b --- /dev/null +++ b/Minecraft.World/Level/Redstone.h @@ -0,0 +1,8 @@ +#pragma once + +class Redstone { +public: + static const int SIGNAL_NONE = 0; + static const int SIGNAL_MIN = 0; + static const int SIGNAL_MAX = 15; +}; \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.cpp b/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.cpp index 20c0d6f42..214db3000 100644 --- a/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.cpp +++ b/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.cpp @@ -13,7 +13,7 @@ ChunkStorageProfilerDecorator::ChunkStorageProfilerDecorator( } LevelChunk* ChunkStorageProfilerDecorator::load(Level* level, int x, int z) { - __int64 nanoTime = System::nanoTime(); + int64_t nanoTime = System::nanoTime(); LevelChunk* chunk = capsulated->load(level, x, z); timeSpentLoading += System::nanoTime() - nanoTime; loadCount++; @@ -22,7 +22,7 @@ LevelChunk* ChunkStorageProfilerDecorator::load(Level* level, int x, int z) { } void ChunkStorageProfilerDecorator::save(Level* level, LevelChunk* levelChunk) { - __int64 nanoTime = System::nanoTime(); + int64_t nanoTime = System::nanoTime(); capsulated->save(level, levelChunk); timeSpentSaving += System::nanoTime() - nanoTime; saveCount++; diff --git a/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.h b/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.h index 0faae2965..678d0ce99 100644 --- a/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.h +++ b/Minecraft.World/Level/Storage/ChunkStorageProfileDecorator.h @@ -7,10 +7,10 @@ class ChunkStorageProfilerDecorator : public ChunkStorage { private: ChunkStorage* capsulated; - __int64 timeSpentLoading; - __int64 loadCount; - __int64 timeSpentSaving; - __int64 saveCount; + int64_t timeSpentLoading; + int64_t loadCount; + int64_t timeSpentSaving; + int64_t saveCount; int counter; diff --git a/Minecraft.World/Level/Storage/CompressedTileStorage.cpp b/Minecraft.World/Level/Storage/CompressedTileStorage.cpp index 7f42e331d..a30981fb2 100644 --- a/Minecraft.World/Level/Storage/CompressedTileStorage.cpp +++ b/Minecraft.World/Level/Storage/CompressedTileStorage.cpp @@ -12,6 +12,7 @@ static const int sc_maxCompressTiles = 64; static CompressedTileStorage_compress_dataIn g_compressTileDataIn[sc_maxCompressTiles] __attribute__((__aligned__(16))); static int g_currentCompressTiles = 0; +// #define DISABLE_SPU_CODE #endif //__PS3__ // Note: See header for an overview of this class @@ -150,7 +151,7 @@ bool CompressedTileStorage::isRenderChunkEmpty( for (int x = 0; x < 16; x += 4) for (int z = 0; z < 16; z += 4) { getBlock(&block, x, y, z); - __uint64* comp = (__uint64*)&blockIndices[block]; + uint64_t* comp = (uint64_t*)&blockIndices[block]; // Are the 4 y regions stored here all zero? (INDEX_TYPE_0_OR_8_BIT // | INDEX_TYPE_0_BIT_FLAG ) if ((*comp) != 0x0007000700070007L) return false; @@ -168,17 +169,17 @@ bool CompressedTileStorage::isSameAs(CompressedTileStorage* other) { // Attempt to compare as much as we can in 64-byte chunks (8 groups of 8 // bytes) int quickCount = allocatedSize / 64; - __int64* pOld = (__int64*)indicesAndData; - __int64* pNew = (__int64*)other->indicesAndData; + int64_t* pOld = (int64_t*)indicesAndData; + int64_t* pNew = (int64_t*)other->indicesAndData; for (int i = 0; i < quickCount; i++) { - __int64 d0 = pOld[0] ^ pNew[0]; - __int64 d1 = pOld[1] ^ pNew[1]; - __int64 d2 = pOld[2] ^ pNew[2]; - __int64 d3 = pOld[3] ^ pNew[3]; - __int64 d4 = pOld[4] ^ pNew[4]; - __int64 d5 = pOld[5] ^ pNew[5]; - __int64 d6 = pOld[6] ^ pNew[6]; - __int64 d7 = pOld[7] ^ pNew[7]; + int64_t d0 = pOld[0] ^ pNew[0]; + int64_t d1 = pOld[1] ^ pNew[1]; + int64_t d2 = pOld[2] ^ pNew[2]; + int64_t d3 = pOld[3] ^ pNew[3]; + int64_t d4 = pOld[4] ^ pNew[4]; + int64_t d5 = pOld[5] ^ pNew[5]; + int64_t d6 = pOld[6] ^ pNew[6]; + int64_t d7 = pOld[7] ^ pNew[7]; d0 |= d1; d2 |= d3; d4 |= d5; @@ -292,7 +293,7 @@ void CompressedTileStorage::setData(byteArray dataIn, unsigned int inOffset) { int offsets[512]; int memToAlloc = 0; // static int type0 = 0, type1 = 0, type2 = 0, type4 = 0, type8 = 0, - //chunkTotal = 0; + // chunkTotal = 0; // Loop round all blocks for (int i = 0; i < 512; i++) { @@ -327,8 +328,8 @@ void CompressedTileStorage::setData(byteArray dataIn, unsigned int inOffset) { } } #else - __uint64 usedFlags[4] = {0, 0, 0, 0}; - __int64 i64_1 = 1; // MGH - instead of 1i64, which is MS specific + uint64_t usedFlags[4] = {0, 0, 0, 0}; + int64_t i64_1 = 1; // MGH - instead of 1i64, which is MS specific for (int j = 0; j < 64; j++) // This loop of 64 is to go round the 4 x // 4 tiles in the block { @@ -374,8 +375,8 @@ void CompressedTileStorage::setData(byteArray dataIn, unsigned int inOffset) { // chunkTotal++; // printf("%d: %d (0) %d (1) %d (2) %d (4) %d (8)\n", chunkTotal, type0 / - //chunkTotal, type1 / chunkTotal, type2 / chunkTotal, type4 / chunkTotal, - //type8 / chunkTotal); + // chunkTotal, type1 / chunkTotal, type2 / chunkTotal, type4 / chunkTotal, + // type8 / chunkTotal); memToAlloc += 1024; // For the indices unsigned char* newIndicesAndData = (unsigned char*)XPhysicalAlloc( @@ -976,8 +977,8 @@ void CompressedTileStorage::compress(int upgradeBlock /*=-1*/) { } #else - __uint64 usedFlags[4] = {0, 0, 0, 0}; - __int64 i64_1 = + uint64_t usedFlags[4] = {0, 0, 0, 0}; + int64_t i64_1 = 1; // MGH - instead of 1i64, which is MS specific for (int j = 0; j < 64; j++) // This loop of 64 is to go round // the 4x4x4 tiles in the block @@ -1076,6 +1077,7 @@ void CompressedTileStorage::compress(int upgradeBlock /*=-1*/) { memToAlloc, MAXULONG_PTR, 4096, PAGE_READWRITE); //(unsigned char *)malloc( memToAlloc ); if (newIndicesAndData == NULL) { + DWORD lastError = GetLastError(); #ifndef _DURANGO MEMORYSTATUS memStatus; GlobalMemoryStatus(&memStatus); @@ -1380,4 +1382,4 @@ void CompressedTileStorage::reverseIndices(unsigned char* indices) { for (int i = 0; i < 512; i++) { System::ReverseUSHORT(&blockIndices[i]); } -} +} \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/CompressedTileStorage.h b/Minecraft.World/Level/Storage/CompressedTileStorage.h index 9f8ac8ffc..e288c8bb5 100644 --- a/Minecraft.World/Level/Storage/CompressedTileStorage.h +++ b/Minecraft.World/Level/Storage/CompressedTileStorage.h @@ -17,20 +17,20 @@ // bytes in total (2) The type of index is determined by the least significant 2 // bits, the other 14 bits represent an offset for the data, stored divided by 2 // 0 - the data for this block is represented at 1 bit per -//tile. Data pointed to is 2 bytes describing the 2 possible tiles stored in -//this block, followed by 32 bytes of data (total 34 bytes) 1 - the data for -//this block is represented at 2 bit per tile. Data pointed to is 4 bytes -//describing the 4 possible tiles stored in this block, followed by 64 bytes of -//data (total 68 bytes) 2 - the data for this block is represented at 4 bit per -//tile. Data pointed to is 16 bytes describing the 16 possible tiles stored in -//this block, followed by 128 bytes of data (total 144 bytes) 3 - if bit 2 is 0, -//then this block is represented at 8 bits per tile. Data pointed to is 64 -//bytes, offset must be a multiple of 4 (since bit 2 can also be thought of as -//being the low bit of the offset (divided by 2 as in the other cases), and is -//zero) +// tile. Data pointed to is 2 bytes describing the 2 possible tiles stored in +// this block, followed by 32 bytes of data (total 34 bytes) +// 1 - the data for this block is represented at 2 bit per tile. Data pointed to +// is 4 bytes describing the 4 possible tiles stored in this block, followed by +// 64 bytes of data (total 68 bytes) 2 - the data for this +// block is represented at 4 bit per tile. Data pointed to is 16 bytes +// describing the 16 possible tiles stored in this block, followed by 128 bytes +// of data (total 144 bytes) 3 - if bit 2 is 0, then this block is +// represented at 8 bits per tile. Data pointed to is 64 bytes, offset must be a +// multiple of 4 (since bit 2 can also be thought of as being +// the low bit of the offset (divided by 2 as in the other cases), and is zero) // - if bit 2 is 1, then this block is represented at 0 -//bits per tile. The upper 8 bits of the index store the tile value that is used -//by the entire block. +// bits per tile. The upper 8 bits of the index store the tile value that is +// used by the entire block. // So: // oooooooooooooo00 - 1 bit per tile, offset oooooooooooooo0 // oooooooooooooo01 - 2 bits per tile, offset oooooooooooooo0 diff --git a/Minecraft.World/Level/Storage/DirectoryLevelStorage.cpp b/Minecraft.World/Level/Storage/DirectoryLevelStorage.cpp index 7ce34e75d..726997e01 100644 --- a/Minecraft.World/Level/Storage/DirectoryLevelStorage.cpp +++ b/Minecraft.World/Level/Storage/DirectoryLevelStorage.cpp @@ -18,7 +18,7 @@ _MapDataMappings::_MapDataMappings() { #ifndef _DURANGO ZeroMemory(xuids, sizeof(PlayerUID) * MAXIMUM_MAP_SAVE_DATA); #endif - ZeroMemory(dimensions, sizeof(std::uint8_t) * (MAXIMUM_MAP_SAVE_DATA / 4)); + ZeroMemory(dimensions, sizeof(uint8_t) * (MAXIMUM_MAP_SAVE_DATA / 4)); } int _MapDataMappings::getDimension(int id) { @@ -79,7 +79,7 @@ _MapDataMappings_old::_MapDataMappings_old() { #ifndef _DURANGO ZeroMemory(xuids, sizeof(PlayerUID) * MAXIMUM_MAP_SAVE_DATA); #endif - ZeroMemory(dimensions, sizeof(std::uint8_t) * (MAXIMUM_MAP_SAVE_DATA / 8)); + ZeroMemory(dimensions, sizeof(uint8_t) * (MAXIMUM_MAP_SAVE_DATA / 8)); } int _MapDataMappings_old::getDimension(int id) { @@ -100,8 +100,8 @@ void DirectoryLevelStorage::PlayerMappings::addMapping(int id, int centreX, int centreZ, int dimension, int scale) { - __int64 index = (((__int64)(centreZ & 0x1FFFFFFF)) << 34) | - (((__int64)(centreX & 0x1FFFFFFF)) << 5) | + int64_t index = (((int64_t)(centreZ & 0x1FFFFFFF)) << 34) | + (((int64_t)(centreX & 0x1FFFFFFF)) << 5) | ((scale & 0x7) << 2) | (dimension & 0x3); m_mappings[index] = id; // app.DebugPrintf("Adding mapping: %d - (%d,%d)/%d/%d [%I64d - @@ -112,14 +112,14 @@ bool DirectoryLevelStorage::PlayerMappings::getMapping(int& id, int centreX, int centreZ, int dimension, int scale) { - //__int64 zMasked = centreZ & 0x1FFFFFFF; - //__int64 xMasked = centreX & 0x1FFFFFFF; - //__int64 zShifted = zMasked << 34; - //__int64 xShifted = xMasked << 5; + //int64_t zMasked = centreZ & 0x1FFFFFFF; + //int64_t xMasked = centreX & 0x1FFFFFFF; + //int64_t zShifted = zMasked << 34; + //int64_t xShifted = xMasked << 5; // app.DebugPrintf("xShifted = %d (0x%016x), zShifted = %I64d // (0x%016llx)\n", xShifted, xShifted, zShifted, zShifted); - __int64 index = (((__int64)(centreZ & 0x1FFFFFFF)) << 34) | - (((__int64)(centreX & 0x1FFFFFFF)) << 5) | + int64_t index = (((int64_t)(centreZ & 0x1FFFFFFF)) << 34) | + (((int64_t)(centreX & 0x1FFFFFFF)) << 5) | ((scale & 0x7) << 2) | (dimension & 0x3); AUTO_VAR(it, m_mappings.find(index)); if (it != m_mappings.end()) { @@ -148,7 +148,7 @@ void DirectoryLevelStorage::PlayerMappings::writeMappings( void DirectoryLevelStorage::PlayerMappings::readMappings(DataInputStream* dis) { int count = dis->readInt(); for (unsigned int i = 0; i < count; ++i) { - __int64 index = dis->readLong(); + int64_t index = dis->readLong(); int id = dis->readInt(); m_mappings[index] = id; app.DebugPrintf(" -- %lld (0x%016llx) = %d\n", index, index, id); @@ -202,7 +202,7 @@ void DirectoryLevelStorage::checkSession() { // 4J-PB - Not in the Xbox game /* - File dataFile = File( dir, std::wstring(L"session.lock")); + File dataFile = File( dir, wstring(L"session.lock")); FileInputStream fis = FileInputStream(dataFile); DataInputStream dis = DataInputStream(&fis); dis.close(); @@ -260,8 +260,7 @@ LevelData* DirectoryLevelStorage::prepareLevel() { } else #endif { - getSaveFile()->setFilePointer(fileEntry, 0, - SaveFileSeekOrigin::Begin); + getSaveFile()->setFilePointer(fileEntry, 0, NULL, FILE_BEGIN); #ifdef _LARGE_WORLDS byteArray data(fileEntry->getFileSize()); @@ -429,15 +428,12 @@ void DirectoryLevelStorage::save(std::shared_ptr player) { } // 4J Changed return val to bool to check if new player or loaded player -bool DirectoryLevelStorage::load(std::shared_ptr player) { - bool newPlayer = true; +CompoundTag* DirectoryLevelStorage::load(std::shared_ptr player) { CompoundTag* tag = loadPlayerDataTag(player->getXuid()); if (tag != NULL) { - newPlayer = false; player->load(tag); - delete tag; } - return newPlayer; + return tag; } CompoundTag* DirectoryLevelStorage::loadPlayerDataTag(PlayerUID xuid) { diff --git a/Minecraft.World/Level/Storage/DirectoryLevelStorage.h b/Minecraft.World/Level/Storage/DirectoryLevelStorage.h index 665704726..e800bb891 100644 --- a/Minecraft.World/Level/Storage/DirectoryLevelStorage.h +++ b/Minecraft.World/Level/Storage/DirectoryLevelStorage.h @@ -65,7 +65,7 @@ private: const ConsoleSavePath playerDir; // const File dataDir; const ConsoleSavePath dataDir; - const __int64 sessionId; + const int64_t sessionId; const std::wstring levelId; static const std::wstring sc_szPlayerDir; @@ -75,7 +75,7 @@ private: friend class DirectoryLevelStorage; private: - std::unordered_map<__int64, short> m_mappings; + std::unordered_map m_mappings; public: void addMapping(int id, int centreX, int centreZ, int dimension, @@ -130,9 +130,10 @@ public: std::vector >* players); virtual void saveLevelData(LevelData* levelData); virtual void save(std::shared_ptr player); - virtual bool load(std::shared_ptr - player); // 4J Changed return val to bool to check if - // new player or loaded player + virtual CompoundTag* load( + std::shared_ptr + player); // 4J Changed return val to bool to check if new player or + // loaded player virtual CompoundTag* loadPlayerDataTag(PlayerUID xuid); virtual void clearOldPlayerFiles(); // 4J Added PlayerIO* getPlayerIO(); diff --git a/Minecraft.World/Level/Storage/EntityIO.cpp b/Minecraft.World/Level/Storage/EntityIO.cpp index 37cb6d6cd..ab377ff89 100644 --- a/Minecraft.World/Level/Storage/EntityIO.cpp +++ b/Minecraft.World/Level/Storage/EntityIO.cpp @@ -3,6 +3,8 @@ #include "../../Entities/Mobs/Painting.h" #include "../../Platform/System.h" #include "../../Entities/Entity.h" +#include "../../Entities/Mobs/WitherBoss.h" +#include "../../Headers/net.minecraft.world.entity.ambient.h" #include "../../Headers/net.minecraft.world.entity.animal.h" #include "../../Headers/net.minecraft.world.entity.item.h" #include "../../Headers/net.minecraft.world.entity.monster.h" @@ -66,10 +68,11 @@ void EntityIO::staticCtor() { setId(ItemEntity::create, eTYPE_ITEMENTITY, L"Item", 1); setId(ExperienceOrb::create, eTYPE_EXPERIENCEORB, L"XPOrb", 2); + setId(LeashFenceKnotEntity::create, eTYPE_LEASHFENCEKNOT, L"LeashKnot", 8); setId(Painting::create, eTYPE_PAINTING, L"Painting", 9); setId(Arrow::create, eTYPE_ARROW, L"Arrow", 10); setId(Snowball::create, eTYPE_SNOWBALL, L"Snowball", 11); - setId(Fireball::create, eTYPE_FIREBALL, L"Fireball", 12); + setId(LargeFireball::create, eTYPE_FIREBALL, L"Fireball", 12); setId(SmallFireball::create, eTYPE_SMALL_FIREBALL, L"SmallFireball", 13); setId(ThrownEnderpearl::create, eTYPE_THROWNENDERPEARL, L"ThrownEnderpearl", 14); @@ -79,12 +82,24 @@ void EntityIO::staticCtor() { setId(ThrownExpBottle::create, eTYPE_THROWNEXPBOTTLE, L"ThrownExpBottle", 17); setId(ItemFrame::create, eTYPE_ITEM_FRAME, L"ItemFrame", 18); + setId(WitherSkull::create, eTYPE_WITHER_SKULL, L"WitherSkull", 19); setId(PrimedTnt::create, eTYPE_PRIMEDTNT, L"PrimedTnt", 20); setId(FallingTile::create, eTYPE_FALLINGTILE, L"FallingSand", 21); - setId(Minecart::create, eTYPE_MINECART, L"Minecart", 40); + setId(FireworksRocketEntity::create, eTYPE_FIREWORKS_ROCKET, + L"FireworksRocketEntity", 22); + setId(Boat::create, eTYPE_BOAT, L"Boat", 41); + setId(MinecartRideable::create, eTYPE_MINECART_RIDEABLE, + L"MinecartRideable", 42); + setId(MinecartChest::create, eTYPE_MINECART_CHEST, L"MinecartChest", 43); + setId(MinecartFurnace::create, eTYPE_MINECART_FURNACE, L"MinecartFurnace", + 44); + setId(MinecartTNT::create, eTYPE_MINECART_TNT, L"MinecartTNT", 45); + setId(MinecartHopper::create, eTYPE_MINECART_HOPPER, L"MinecartHopper", 46); + setId(MinecartSpawner::create, eTYPE_MINECART_SPAWNER, L"MinecartSpawner", + 47); setId(Mob::create, eTYPE_MOB, L"Mob", 48); setId(Monster::create, eTYPE_MONSTER, L"Monster", 49); @@ -126,7 +141,15 @@ void EntityIO::staticCtor() { setId(LavaSlime::create, eTYPE_LAVASLIME, L"LavaSlime", 62, eMinecraftColour_Mob_LavaSlime_Colour1, eMinecraftColour_Mob_LavaSlime_Colour2, IDS_LAVA_SLIME); - setId(EnderDragon::create, eTYPE_ENDERDRAGON, L"EnderDragon", 63); + setId(EnderDragon::create, eTYPE_ENDERDRAGON, L"EnderDragon", 63, + eMinecraftColour_Mob_Enderman_Colour1, + eMinecraftColour_Mob_Enderman_Colour1, IDS_ENDERDRAGON); + setId(WitherBoss::create, eTYPE_WITHERBOSS, L"WitherBoss", 64); + setId(Bat::create, eTYPE_BAT, L"Bat", 65, eMinecraftColour_Mob_Bat_Colour1, + eMinecraftColour_Mob_Bat_Colour2, IDS_BAT); + setId(Witch::create, eTYPE_WITCH, L"Witch", 66, + eMinecraftColour_Mob_Witch_Colour1, + eMinecraftColour_Mob_Witch_Colour2, IDS_WITCH); setId(Pig::create, eTYPE_PIG, L"Pig", 90, eMinecraftColour_Mob_Pig_Colour1, eMinecraftColour_Mob_Pig_Colour2, IDS_PIG); @@ -148,10 +171,13 @@ void EntityIO::staticCtor() { eMinecraftColour_Mob_MushroomCow_Colour1, eMinecraftColour_Mob_MushroomCow_Colour2, IDS_MUSHROOM_COW); setId(SnowMan::create, eTYPE_SNOWMAN, L"SnowMan", 97); - setId(Ozelot::create, eTYPE_OZELOT, L"Ozelot", 98, + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", 98, eMinecraftColour_Mob_Ocelot_Colour1, eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT); setId(VillagerGolem::create, eTYPE_VILLAGERGOLEM, L"VillagerGolem", 99); + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", 100, + eMinecraftColour_Mob_Horse_Colour1, + eMinecraftColour_Mob_Horse_Colour2, IDS_HORSE); setId(Villager::create, eTYPE_VILLAGER, L"Villager", 120, eMinecraftColour_Mob_Villager_Colour1, @@ -162,6 +188,43 @@ void EntityIO::staticCtor() { // 4J Added setId(DragonFireball::create, eTYPE_DRAGON_FIREBALL, L"DragonFireball", 1000); + + // 4J-PB - moved to allow the eggs to be named and coloured in the Creative + // Mode menu 4J Added for custom spawn eggs + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", + 100 | ((EntityHorse::TYPE_DONKEY + 1) << 12), + eMinecraftColour_Mob_Horse_Colour1, + eMinecraftColour_Mob_Horse_Colour2, IDS_DONKEY); + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", + 100 | ((EntityHorse::TYPE_MULE + 1) << 12), + eMinecraftColour_Mob_Horse_Colour1, + eMinecraftColour_Mob_Horse_Colour2, IDS_MULE); + +#ifndef _CONTENT_PACKAGE + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", + 100 | ((EntityHorse::TYPE_SKELETON + 1) << 12), + eMinecraftColour_Mob_Horse_Colour1, + eMinecraftColour_Mob_Horse_Colour2, IDS_SKELETON_HORSE); + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", + 100 | ((EntityHorse::TYPE_UNDEAD + 1) << 12), + eMinecraftColour_Mob_Horse_Colour1, + eMinecraftColour_Mob_Horse_Colour2, IDS_ZOMBIE_HORSE); + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", + 98 | ((Ocelot::TYPE_BLACK + 1) << 12), + eMinecraftColour_Mob_Ocelot_Colour1, + eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT); + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", + 98 | ((Ocelot::TYPE_RED + 1) << 12), + eMinecraftColour_Mob_Ocelot_Colour1, + eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT); + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", + 98 | ((Ocelot::TYPE_SIAMESE + 1) << 12), + eMinecraftColour_Mob_Ocelot_Colour1, + eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT); + setId(Spider::create, eTYPE_SPIDER, L"Spider", 52 | (2 << 12), + eMinecraftColour_Mob_Spider_Colour1, + eMinecraftColour_Mob_Spider_Colour2, IDS_SKELETON); +#endif } std::shared_ptr EntityIO::newEntity(const std::wstring& id, @@ -172,6 +235,10 @@ std::shared_ptr EntityIO::newEntity(const std::wstring& id, if (it != idCreateMap->end()) { entityCreateFn create = it->second; if (create != NULL) entity = std::shared_ptr(create(level)); + if ((entity != NULL) && entity->GetType() == eTYPE_ENDERDRAGON) { + std::dynamic_pointer_cast(entity) + ->AddParts(); // 4J added to finalise creation + } } return entity; @@ -180,10 +247,32 @@ std::shared_ptr EntityIO::newEntity(const std::wstring& id, std::shared_ptr EntityIO::loadStatic(CompoundTag* tag, Level* level) { std::shared_ptr entity; + if (tag->getString(L"id").compare(L"Minecart") == 0) { + // I don't like this any more than you do. Sadly, compatibility... + + switch (tag->getInt(L"Type")) { + case Minecart::TYPE_CHEST: + tag->putString(L"id", L"MinecartChest"); + break; + case Minecart::TYPE_FURNACE: + tag->putString(L"id", L"MinecartFurnace"); + break; + case Minecart::TYPE_RIDEABLE: + tag->putString(L"id", L"MinecartRideable"); + break; + } + + tag->remove(L"Type"); + } + AUTO_VAR(it, idCreateMap->find(tag->getString(L"id"))); if (it != idCreateMap->end()) { entityCreateFn create = it->second; if (create != NULL) entity = std::shared_ptr(create(level)); + if ((entity != NULL) && entity->GetType() == eTYPE_ENDERDRAGON) { + std::dynamic_pointer_cast(entity) + ->AddParts(); // 4J added to finalise creation + } } if (entity != NULL) { @@ -204,6 +293,10 @@ std::shared_ptr EntityIO::newById(int id, Level* level) { if (it != numCreateMap->end()) { entityCreateFn create = it->second; if (create != NULL) entity = std::shared_ptr(create(level)); + if ((entity != NULL) && entity->GetType() == eTYPE_ENDERDRAGON) { + std::dynamic_pointer_cast(entity) + ->AddParts(); // 4J added to finalise creation + } } if (entity != NULL) { @@ -225,6 +318,10 @@ std::shared_ptr EntityIO::newByEnumType(eINSTANCEOF eType, if (it2 != numCreateMap->end()) { entityCreateFn create = it2->second; if (create != NULL) entity = std::shared_ptr(create(level)); + if ((entity != NULL) && entity->GetType() == eTYPE_ENDERDRAGON) { + std::dynamic_pointer_cast(entity) + ->AddParts(); // 4J added to finalise creation + } } } diff --git a/Minecraft.World/Level/Storage/LevelSettings.cpp b/Minecraft.World/Level/Storage/LevelSettings.cpp index 94557e120..5c0542cfe 100644 --- a/Minecraft.World/Level/Storage/LevelSettings.cpp +++ b/Minecraft.World/Level/Storage/LevelSettings.cpp @@ -35,10 +35,10 @@ void GameType::updatePlayerAbilities(Abilities* abilities) { abilities->invulnerable = false; abilities->flying = false; } - abilities->mayBuild = !isReadOnly(); + abilities->mayBuild = !isAdventureRestricted(); } -bool GameType::isReadOnly() { return this == ADVENTURE; } +bool GameType::isAdventureRestricted() { return this == ADVENTURE; } bool GameType::isCreative() { return this == CREATIVE; } @@ -70,7 +70,7 @@ GameType* GameType::byName(const std::wstring& name) { return SURVIVAL; } -void LevelSettings::_init(__int64 seed, GameType* gameType, +void LevelSettings::_init(int64_t seed, GameType* gameType, bool generateMapFeatures, bool hardcore, bool newSeaLevel, LevelType* levelType, int xzSize, int hellScale) { @@ -82,11 +82,12 @@ void LevelSettings::_init(__int64 seed, GameType* gameType, this->levelType = levelType; this->allowCommands = false; this->startingBonusItems = false; + levelTypeOptions = L""; m_xzSize = xzSize; m_hellScale = hellScale; } -LevelSettings::LevelSettings(__int64 seed, GameType* gameType, +LevelSettings::LevelSettings(int64_t seed, GameType* gameType, bool generateMapFeatures, bool hardcore, bool newSeaLevel, LevelType* levelType, int xzSize, int hellScale) @@ -118,9 +119,14 @@ LevelSettings* LevelSettings::enableSinglePlayerCommands() { return this; } +LevelSettings* LevelSettings::setLevelTypeOptions(const std::wstring& options) { + levelTypeOptions = options; + return this; +} + bool LevelSettings::hasStartingBonusItems() { return startingBonusItems; } -__int64 LevelSettings::getSeed() { return seed; } +int64_t LevelSettings::getSeed() { return seed; } GameType* LevelSettings::getGameType() { return gameType; } @@ -142,3 +148,5 @@ bool LevelSettings::useNewSeaLevel() { return newSeaLevel; } int LevelSettings::getXZSize() { return m_xzSize; } int LevelSettings::getHellScale() { return m_hellScale; } + +std::wstring LevelSettings::getLevelTypeOptions() { return levelTypeOptions; } \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/LevelSettings.h b/Minecraft.World/Level/Storage/LevelSettings.h index bf50f56b7..17253196c 100644 --- a/Minecraft.World/Level/Storage/LevelSettings.h +++ b/Minecraft.World/Level/Storage/LevelSettings.h @@ -4,6 +4,8 @@ class LevelType; class Abilities; class LevelData; +#define _ADVENTURE_MODE_ENABLED + // 4J Stu - Was Java enum class class GameType { public: @@ -24,7 +26,7 @@ public: int getId(); std::wstring getName(); void updatePlayerAbilities(Abilities* abilities); - bool isReadOnly(); + bool isAdventureRestricted(); bool isCreative(); bool isSurvival(); static GameType* byId(int id); @@ -33,7 +35,7 @@ public: class LevelSettings { private: - __int64 seed; + int64_t seed; GameType* gameType; bool generateMapFeatures; bool hardcore; @@ -41,16 +43,17 @@ private: LevelType* levelType; bool allowCommands; bool startingBonusItems; // 4J - brought forward from 1.3.2 - int m_xzSize; // 4J Added + std::wstring levelTypeOptions; + int m_xzSize; // 4J Added int m_hellScale; - void _init(__int64 seed, GameType* gameType, bool generateMapFeatures, + void _init(int64_t seed, GameType* gameType, bool generateMapFeatures, bool hardcore, bool newSeaLevel, LevelType* levelType, int xzSize, int hellScale); // 4J Added xzSize and hellScale param public: - LevelSettings(__int64 seed, GameType* gameType, bool generateMapFeatures, + LevelSettings(int64_t seed, GameType* gameType, bool generateMapFeatures, bool hardcore, bool newSeaLevel, LevelType* levelType, int xzSize, int hellScale); // 4J Added xzSize and hellScale param @@ -58,8 +61,9 @@ public: LevelSettings* enableStartingBonusItems(); // 4J - brought forward from 1.3.2 LevelSettings* enableSinglePlayerCommands(); + LevelSettings* setLevelTypeOptions(const std::wstring& options); bool hasStartingBonusItems(); // 4J - brought forward from 1.3.2 - __int64 getSeed(); + int64_t getSeed(); GameType* getGameType(); bool isHardcore(); LevelType* getLevelType(); @@ -69,4 +73,5 @@ public: int getXZSize(); // 4J Added int getHellScale(); // 4J Added static GameType* validateGameType(int gameType); + std::wstring getLevelTypeOptions(); }; diff --git a/Minecraft.World/Level/Storage/LevelSource.h b/Minecraft.World/Level/Storage/LevelSource.h index bfc151090..fd84ea9c9 100644 --- a/Minecraft.World/Level/Storage/LevelSource.h +++ b/Minecraft.World/Level/Storage/LevelSource.h @@ -27,5 +27,6 @@ public: virtual int getMaxBuildHeight() = 0; virtual bool isAllEmpty() = 0; virtual bool isTopSolidBlocking(int x, int y, int z) = 0; + virtual int getDirectSignal(int x, int y, int z, int dir) = 0; virtual ~LevelSource() {} }; \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/LevelSummary.cpp b/Minecraft.World/Level/Storage/LevelSummary.cpp index 88c82915f..59a7f31bd 100644 --- a/Minecraft.World/Level/Storage/LevelSummary.cpp +++ b/Minecraft.World/Level/Storage/LevelSummary.cpp @@ -2,8 +2,8 @@ #include "LevelSummary.h" LevelSummary::LevelSummary(const std::wstring& levelId, - const std::wstring& levelName, __int64 lastPlayed, - __int64 sizeOnDisk, GameType* gameMode, + const std::wstring& levelName, int64_t lastPlayed, + int64_t sizeOnDisk, GameType* gameMode, bool requiresConversion, bool hardcore, bool hasCheats) : levelId(levelId), @@ -19,11 +19,11 @@ std::wstring LevelSummary::getLevelId() { return levelId; } std::wstring LevelSummary::getLevelName() { return levelName; } -__int64 LevelSummary::getSizeOnDisk() { return sizeOnDisk; } +int64_t LevelSummary::getSizeOnDisk() { return sizeOnDisk; } bool LevelSummary::isRequiresConversion() { return requiresConversion; } -__int64 LevelSummary::getLastPlayed() { return lastPlayed; } +int64_t LevelSummary::getLastPlayed() { return lastPlayed; } int LevelSummary::compareTo(LevelSummary* rhs) { if (lastPlayed < rhs->lastPlayed) { diff --git a/Minecraft.World/Level/Storage/LevelSummary.h b/Minecraft.World/Level/Storage/LevelSummary.h index 95ff7a5cb..05a1daf8b 100644 --- a/Minecraft.World/Level/Storage/LevelSummary.h +++ b/Minecraft.World/Level/Storage/LevelSummary.h @@ -5,8 +5,8 @@ class GameType; class LevelSummary { const std::wstring levelId; const std::wstring levelName; - const __int64 lastPlayed; - const __int64 sizeOnDisk; + const int64_t lastPlayed; + const int64_t sizeOnDisk; const bool requiresConversion; GameType* gameMode; const bool hardcore; @@ -14,13 +14,13 @@ class LevelSummary { public: LevelSummary(const std::wstring& levelId, const std::wstring& levelName, - __int64 lastPlayed, __int64 sizeOnDisk, GameType* gameMode, + int64_t lastPlayed, int64_t sizeOnDisk, GameType* gameMode, bool requiresConversion, bool hardcore, bool hasCheats); std::wstring getLevelId(); std::wstring getLevelName(); - __int64 getSizeOnDisk(); + int64_t getSizeOnDisk(); bool isRequiresConversion(); - __int64 getLastPlayed(); + int64_t getLastPlayed(); int compareTo(LevelSummary* rhs); GameType* getGameMode(); bool isHardcore(); diff --git a/Minecraft.World/Level/Storage/LevelType.cpp b/Minecraft.World/Level/Storage/LevelType.cpp index 48b77d154..4143a8e2b 100644 --- a/Minecraft.World/Level/Storage/LevelType.cpp +++ b/Minecraft.World/Level/Storage/LevelType.cpp @@ -43,6 +43,7 @@ LevelType::LevelType(int id, std::wstring generatorName, int version) { } void LevelType::init(int id, std::wstring generatorName, int version) { + this->id = id; m_generatorName = generatorName; m_version = version; m_selectable = true; @@ -81,12 +82,14 @@ bool LevelType::hasReplacement() { return m_replacement; } LevelType* LevelType::getLevelType(std::wstring name) { if (name.length() > 0) { for (int i = 0; i < 16; i++) { - // Fix: check NULL before accessing member to avoid null dereference - if (levelTypes[i] != NULL && - (levelTypes[i]->m_generatorName.compare(name) == 0)) { + std::wstring genname = levelTypes[i]->m_generatorName; + + if (levelTypes[i] != NULL && (genname.compare(name) == 0)) { return levelTypes[i]; } } } return NULL; } + +int LevelType::getId() { return id; } \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/LevelType.h b/Minecraft.World/Level/Storage/LevelType.h index 55bf7624a..cd83597a2 100644 --- a/Minecraft.World/Level/Storage/LevelType.h +++ b/Minecraft.World/Level/Storage/LevelType.h @@ -1,5 +1,4 @@ #pragma once - #include "../../Headers/net.minecraft.world.level.h" class LevelType { @@ -15,6 +14,7 @@ public: static void staticCtor(); private: + int id; std::wstring m_generatorName; int m_version; bool m_selectable; @@ -42,4 +42,5 @@ private: public: bool hasReplacement(); static LevelType* getLevelType(std::wstring name); + int getId(); }; diff --git a/Minecraft.World/Level/Storage/MapItemSavedData.cpp b/Minecraft.World/Level/Storage/MapItemSavedData.cpp index 664b3fcb5..0e083bb51 100644 --- a/Minecraft.World/Level/Storage/MapItemSavedData.cpp +++ b/Minecraft.World/Level/Storage/MapItemSavedData.cpp @@ -33,6 +33,8 @@ MapItemSavedData::HoldingPlayer::HoldingPlayer(std::shared_ptr player, tick = 0; sendPosTick = 0; + step = 0; + hasSentInitial = false; // java ctor // this->player = player; @@ -50,6 +52,14 @@ MapItemSavedData::HoldingPlayer::~HoldingPlayer() { charArray MapItemSavedData::HoldingPlayer::nextUpdatePacket( std::shared_ptr itemInstance) { + if (!hasSentInitial) { + charArray data(2); + data[0] = HEADER_METADATA; + data[1] = parent->scale; + + hasSentInitial = true; + return data; + } if (--sendPosTick < 0) { sendPosTick = 4; @@ -129,15 +139,13 @@ charArray MapItemSavedData::HoldingPlayer::nextUpdatePacket( std::shared_ptr servPlayer = std::dynamic_pointer_cast(player); for (int d = 0; d < 10; d++) { - int column = (tick * 11) % (MapItem::IMAGE_WIDTH); - tick++; if (rowsDirtyMin[column] >= 0) { int len = rowsDirtyMax[column] - rowsDirtyMin[column] + 1; int min = rowsDirtyMin[column]; charArray data = charArray(len + 3); - data[0] = 0; + data[0] = HEADER_COLOURS; data[1] = (char)column; data[2] = (char)min; for (unsigned int y = 0; y < data.length - 3; y++) { @@ -157,7 +165,6 @@ MapItemSavedData::MapItemSavedData(const std::wstring& id) : SavedData(id) { dimension = 0; scale = 0; colors = byteArray(MapItem::IMAGE_WIDTH * MapItem::IMAGE_HEIGHT); - step = 0; } MapItemSavedData::~MapItemSavedData() { @@ -173,7 +180,7 @@ void MapItemSavedData::load(CompoundTag* tag) { z = tag->getInt(L"zCenter"); scale = tag->getByte(L"scale"); if (scale < 0) scale = 0; - if (scale > 4) scale = 4; + if (scale > MAX_SCALE) scale = MAX_SCALE; int width = tag->getShort(L"width"); int height = tag->getShort(L"height"); @@ -246,8 +253,7 @@ void MapItemSavedData::tickCarriedBy(std::shared_ptr player, if (it2 != carriedByPlayers.end()) { carriedByPlayers.erase(it2); } - it = carriedBy.erase( - std::find(carriedBy.begin(), carriedBy.end(), hp)); + it = carriedBy.erase(find(carriedBy.begin(), carriedBy.end(), hp)); } else { ++it; @@ -330,7 +336,9 @@ void MapItemSavedData::tickCarriedBy(std::shared_ptr player, int size = MAP_SIZE - 1; char rot = (char)((item->getFrame()->dir * 90) * 16 / 360); if (dimension < 0) { - int s = step / 10; + int s = + (int)(playerLevel->getLevelData()->getDayTime() / + 10); rot = (char)((s * s * 34187121 + s * 121) >> 15 & 15); } #ifdef _LARGE_WORLDS @@ -416,7 +424,9 @@ void MapItemSavedData::tickCarriedBy(std::shared_ptr player, rot = (char)(decorationPlayer->yRot * 16 / 360 + 0.5); if (dimension < 0) { - int s = step / 10; + int s = (int)(playerLevel->getLevelData() + ->getDayTime() / + 10); rot = (char)((s * s * 34187121 + s * 121) >> 15 & 15); @@ -460,11 +470,10 @@ void MapItemSavedData::tickCarriedBy(std::shared_ptr player, } // float xd = (float) (hp->player->x - x) / (1 << - // scale); float yd = (float) (hp->player->z - z) / (1 << scale); - // int ww = 64; - // int hh = 64; - // if (xd >= -ww && yd >= -hh && xd <= ww && yd <= - // hh) + // scale); float yd = (float) (hp->player->z - z) / + // (1 << scale); int ww = 64; + // int hh = 64; if (xd >= -ww && yd >= -hh && xd + // <= ww && yd <= hh) // { // char img = 0; // char x = (char) (xd * 2 + 0.5); @@ -511,7 +520,7 @@ void MapItemSavedData::setDirty(int x, int y0, int y1) { } void MapItemSavedData::handleComplexItemData(charArray& data) { - if (data[0] == 0) { + if (data[0] == HEADER_COLOURS) { int xx = data[1] & 0xff; int yy = data[2] & 0xff; for (unsigned int y = 0; y < data.length - 3; y++) { @@ -519,7 +528,7 @@ void MapItemSavedData::handleComplexItemData(charArray& data) { } setDirty(); - } else if (data[0] == 1) { + } else if (data[0] == HEADER_DECORATIONS) { for (unsigned int i = 0; i < decorations.size(); i++) { delete decorations[i]; } @@ -546,9 +555,27 @@ void MapItemSavedData::handleComplexItemData(charArray& data) { decorations.push_back( new MapDecoration(img, x, y, rot, entityId, visible)); } + } else if (data[0] == HEADER_METADATA) { + scale = data[1]; } } +std::shared_ptr +MapItemSavedData::getHoldingPlayer(std::shared_ptr player) { + std::shared_ptr hp = nullptr; + AUTO_VAR(it, carriedByPlayers.find(player)); + + if (it == carriedByPlayers.end()) { + hp = std::shared_ptr(new HoldingPlayer(player, this)); + carriedByPlayers[player] = hp; + carriedBy.push_back(hp); + } else { + hp = it->second; + } + + return hp; +} + // 4J Added // We only have one map per player per dimension, so if they pickup someone // elses map we merge their map data with ours so that we can see everything diff --git a/Minecraft.World/Level/Storage/MapItemSavedData.h b/Minecraft.World/Level/Storage/MapItemSavedData.h index 37c392769..6642e4828 100644 --- a/Minecraft.World/Level/Storage/MapItemSavedData.h +++ b/Minecraft.World/Level/Storage/MapItemSavedData.h @@ -4,6 +4,11 @@ #include "SavedData.h" class MapItemSavedData : public SavedData { +private: + static const int HEADER_COLOURS = 0; + static const int HEADER_DECORATIONS = 1; + static const int HEADER_METADATA = 2; + public: static const int MAP_SIZE = 64; static const int MAX_SCALE = 4; @@ -35,6 +40,12 @@ public: int sendPosTick; charArray lastSentDecorations; + public: + int step; + + private: + bool hasSentInitial; + protected: const MapItemSavedData* parent; @@ -52,7 +63,6 @@ public: char dimension; uint8_t scale; byteArray colors; - int step; std::vector > carriedBy; private: @@ -86,6 +96,8 @@ public: using SavedData::setDirty; void setDirty(int x, int y0, int y1); void handleComplexItemData(charArray& data); + std::shared_ptr getHoldingPlayer( + std::shared_ptr player); // 4J Stu Added void mergeInMapData(std::shared_ptr dataToAdd); diff --git a/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp b/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp index 5b0685d2a..ea90e3542 100644 --- a/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp +++ b/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp @@ -45,7 +45,7 @@ McRegionChunkStorage::McRegionChunkStorage(ConsoleSaveFile* saveFile, int count = dis.readInt(); for (int i = 0; i < count; ++i) { - __int64 index = dis.readLong(); + int64_t index = dis.readLong(); CompoundTag* tag = NbtIo::read(&dis); ByteArrayOutputStream bos; @@ -160,6 +160,14 @@ LevelChunk* McRegionChunkStorage::load(Level* level, int x, int z) { #endif delete chunkData; } +#ifndef _CONTENT_PACKAGE + if (levelChunk && app.DebugSettingsOn() && + app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & + (1L << eDebugSetting_EnableBiomeOverride)) { + // 4J Stu - This will force an update of the chunk's biome array + levelChunk->reloadBiomes(); + } +#endif return levelChunk; } diff --git a/Minecraft.World/Level/Storage/McRegionLevelStorage.cpp b/Minecraft.World/Level/Storage/McRegionLevelStorage.cpp index 1046da478..6fdbad8fc 100644 --- a/Minecraft.World/Level/Storage/McRegionLevelStorage.cpp +++ b/Minecraft.World/Level/Storage/McRegionLevelStorage.cpp @@ -30,7 +30,7 @@ ChunkStorage* McRegionLevelStorage::createChunkStorage(Dimension* dimension) { std::vector* netherFiles = m_saveFile->getRegionFilesByDimension(1); if (netherFiles != NULL) { - unsigned int bytesWritten = 0; + DWORD bytesWritten = 0; for (AUTO_VAR(it, netherFiles->begin()); it != netherFiles->end(); ++it) { m_saveFile->zeroFile(*it, (*it)->getFileSize(), @@ -99,4 +99,4 @@ void McRegionLevelStorage::saveLevelData( MemSect(0); } -void McRegionLevelStorage::closeAll() { RegionFileCache::clear(); } +void McRegionLevelStorage::closeAll() { RegionFileCache::clear(); } \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/OldChunkStorage.cpp b/Minecraft.World/Level/Storage/OldChunkStorage.cpp index 70cc1ac0a..0ee095902 100644 --- a/Minecraft.World/Level/Storage/OldChunkStorage.cpp +++ b/Minecraft.World/Level/Storage/OldChunkStorage.cpp @@ -260,7 +260,8 @@ void OldChunkStorage::save(LevelChunk* lc, Level* level, dos->writeShort(SAVE_FILE_VERSION_NUMBER); dos->writeInt(lc->x); dos->writeInt(lc->z); - dos->writeLong(level->getTime()); + dos->writeLong(level->getGameTime()); + dos->writeLong(lc->inhabitedTime); PIXBeginNamedEvent(0, "Getting block data"); lc->writeCompressedBlockData(dos); @@ -333,7 +334,8 @@ void OldChunkStorage::save(LevelChunk* lc, Level* level, CompoundTag* tag) { level->checkSession(); tag->putInt(L"xPos", lc->x); tag->putInt(L"zPos", lc->z); - tag->putLong(L"LastUpdate", level->getTime()); + tag->putLong(L"LastUpdate", level->getGameTime()); + tag->putLong(L"InhabitedTime", lc->inhabitedTime); // 4J - changes here for new storage. Now have static storage for getting // lighting data for block, data, and sky & block lighting. This wasn't // required in the original version as we could just reference the @@ -414,6 +416,7 @@ void OldChunkStorage::save(LevelChunk* lc, Level* level, CompoundTag* tag) { teTag->putInt(L"y", td.y); teTag->putInt(L"z", td.z); teTag->putInt(L"t", (int)(td.m_delay - levelTime)); + teTag->putInt(L"p", td.priorityTilt); tickTags->add(teTag); } @@ -453,6 +456,7 @@ void OldChunkStorage::loadEntities(LevelChunk* lc, Level* level, } LevelChunk* OldChunkStorage::load(Level* level, DataInputStream* dis) { + PIXBeginNamedEvent(0, "Loading chunk"); short version = dis->readShort(); int x = dis->readInt(); int z = dis->readInt(); @@ -460,6 +464,10 @@ LevelChunk* OldChunkStorage::load(Level* level, DataInputStream* dis) { LevelChunk* levelChunk = new LevelChunk(level, x, z); + if (version >= SAVE_FILE_VERSION_CHUNK_INHABITED_TIME) { + levelChunk->inhabitedTime = dis->readLong(); + } + levelChunk->readCompressedBlockData(dis); levelChunk->readCompressedDataData(dis); levelChunk->readCompressedSkyLightData(dis); @@ -479,13 +487,26 @@ LevelChunk* OldChunkStorage::load(Level* level, DataInputStream* dis) { levelChunk->terrainPopulated |= LevelChunk::sTerrainPostPostProcessed; } - dis->readFully(levelChunk->biomes); +#ifndef _CONTENT_PACKAGE + if (app.DebugSettingsOn() && + app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & + (1L << eDebugSetting_EnableBiomeOverride)) { + // Read the biome data from the stream, but don't use it + byteArray dummyBiomes(levelChunk->biomes.length); + dis->readFully(dummyBiomes); + delete[] dummyBiomes.data; + } else +#endif + { + dis->readFully(levelChunk->biomes); + } CompoundTag* tag = NbtIo::read(dis); loadEntities(levelChunk, level, tag); if (tag->contains(L"TileTicks")) { + PIXBeginNamedEvent(0, "Loading TileTicks"); ListTag* tileTicks = (ListTag*)tag->getList(L"TileTicks"); @@ -496,13 +517,16 @@ LevelChunk* OldChunkStorage::load(Level* level, DataInputStream* dis) { level->forceAddTileTick( teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), - teTag->getInt(L"t")); + teTag->getInt(L"t"), teTag->getInt(L"p")); } } + PIXEndNamedEvent(); } delete tag; + PIXEndNamedEvent(); + return levelChunk; } @@ -536,8 +560,8 @@ LevelChunk* OldChunkStorage::load(Level* level, CompoundTag* tag) { delete[] tag->getByteArray(L"BlockLight").data; // levelChunk->skyLight = new DataLayer(tag->getByteArray(L"SkyLight"), - //level->depthBits); levelChunk->blockLight = new - //DataLayer(tag->getByteArray(L"BlockLight"), level->depthBits); + // level->depthBits); levelChunk->blockLight = new + // DataLayer(tag->getByteArray(L"BlockLight"), level->depthBits); delete[] levelChunk->heightmap.data; levelChunk->heightmap = tag->getByteArray(L"HeightMap"); @@ -597,8 +621,17 @@ LevelChunk* OldChunkStorage::load(Level* level, CompoundTag* tag) { } #endif - if (tag->contains(L"Biomes")) { - levelChunk->setBiomes(tag->getByteArray(L"Biomes")); +#ifndef _CONTENT_PACKAGE + if (app.DebugSettingsOn() && + app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & + (1L << eDebugSetting_EnableBiomeOverride)) { + // Do nothing + } else +#endif + { + if (tag->contains(L"Biomes")) { + levelChunk->setBiomes(tag->getByteArray(L"Biomes")); + } } loadEntities(levelChunk, level, tag); @@ -614,7 +647,7 @@ LevelChunk* OldChunkStorage::load(Level* level, CompoundTag* tag) { level->forceAddTileTick( teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), - teTag->getInt(L"t")); + teTag->getInt(L"t"), teTag->getInt(L"p")); } } } diff --git a/Minecraft.World/Level/Storage/PlayerIO.h b/Minecraft.World/Level/Storage/PlayerIO.h index 11cc4e2c8..7a99033ba 100644 --- a/Minecraft.World/Level/Storage/PlayerIO.h +++ b/Minecraft.World/Level/Storage/PlayerIO.h @@ -10,15 +10,13 @@ class Player; class PlayerIO { public: virtual void save(std::shared_ptr player) = 0; - virtual bool load(std::shared_ptr - player) = 0; // 4J Changed return val to bool to - // check if new player or loaded player + virtual CompoundTag* load(std::shared_ptr player) = 0; virtual CompoundTag* loadPlayerDataTag( - PlayerUID xuid) = 0; // 4J Changed from string name to xuid + PlayerUID xuid) = 0; // 4J Changed from std::string name to xuid // 4J Added virtual void clearOldPlayerFiles() = 0; virtual void saveMapIdLookup() = 0; virtual void deleteMapFilesForPlayer(std::shared_ptr player) = 0; virtual void saveAllCachedData() = 0; -}; +}; \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/PortalForcer.cpp b/Minecraft.World/Level/Storage/PortalForcer.cpp index d012694e6..8c2d9d783 100644 --- a/Minecraft.World/Level/Storage/PortalForcer.cpp +++ b/Minecraft.World/Level/Storage/PortalForcer.cpp @@ -3,11 +3,28 @@ #include "../../Headers/net.minecraft.world.level.h" #include "../../Headers/net.minecraft.world.level.tile.h" #include "../../Headers/net.minecraft.world.level.dimension.h" +#include "../../../Minecraft.Client/Level/ServerLevel.h" #include "PortalForcer.h" -PortalForcer::PortalForcer() { random = new Random(); } +PortalForcer::PortalPosition::PortalPosition(int x, int y, int z, int64_t time) + : Pos(x, y, z) { + lastUsed = time; +} -void PortalForcer::force(Level* level, std::shared_ptr e) { +PortalForcer::PortalForcer(ServerLevel* level) { + this->level = level; + random = new Random(level->getSeed()); +} + +PortalForcer::~PortalForcer() { + for (AUTO_VAR(it, cachedPortals.begin()); it != cachedPortals.end(); ++it) { + delete it->second; + } +} + +void PortalForcer::force(std::shared_ptr e, double xOriginal, + double yOriginal, double zOriginal, + float yRotOriginal) { if (level->dimension->id == 1) { int x = Mth::floor(e->x); int y = Mth::floor(e->y) - 1; @@ -24,7 +41,8 @@ void PortalForcer::force(Level* level, std::shared_ptr e) { bool border = h < 0; - level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : 0); + level->setTileAndUpdate(xt, yt, zt, + border ? Tile::obsidian_Id : 0); } } } @@ -35,15 +53,17 @@ void PortalForcer::force(Level* level, std::shared_ptr e) { return; } - if (findPortal(level, e)) { + if (findPortal(e, xOriginal, yOriginal, zOriginal, yRotOriginal)) { return; } - createPortal(level, e); - findPortal(level, e); + createPortal(e); + findPortal(e, xOriginal, yOriginal, zOriginal, yRotOriginal); } -bool PortalForcer::findPortal(Level* level, std::shared_ptr e) { +bool PortalForcer::findPortal(std::shared_ptr e, double xOriginal, + double yOriginal, double zOriginal, + float yRotOriginal) { // 4J Stu - Decrease the range at which we search for a portal in the nether // given our smaller nether int r = 16; //* 8; @@ -66,23 +86,39 @@ bool PortalForcer::findPortal(Level* level, std::shared_ptr e) { int xc = Mth::floor(e->x); int zc = Mth::floor(e->z); - for (int x = xc - r; x <= xc + r; x++) { - double xd = (x + 0.5) - e->x; - for (int z = zc - r; z <= zc + r; z++) { - double zd = (z + 0.5) - e->z; - for (int y = level->getHeight() - 1; y >= 0; y--) { - if (level->getTile(x, y, z) == Tile::portalTile_Id) { - while (level->getTile(x, y - 1, z) == Tile::portalTile_Id) { - y--; - } + long hash = ChunkPos::hashCode(xc, zc); + bool updateCache = true; - double yd = (y + 0.5) - e->y; - double dist = xd * xd + yd * yd + zd * zd; - if (closest < 0 || dist < closest) { - closest = dist; - xTarget = x; - yTarget = y; - zTarget = z; + AUTO_VAR(it, cachedPortals.find(hash)); + if (it != cachedPortals.end()) { + PortalPosition* pos = it->second; + + closest = 0; + xTarget = pos->x; + yTarget = pos->y; + zTarget = pos->z; + pos->lastUsed = level->getGameTime(); + updateCache = false; + } else { + for (int x = xc - r; x <= xc + r; x++) { + double xd = (x + 0.5) - e->x; + for (int z = zc - r; z <= zc + r; z++) { + double zd = (z + 0.5) - e->z; + for (int y = level->getHeight() - 1; y >= 0; y--) { + if (level->getTile(x, y, z) == Tile::portalTile_Id) { + while (level->getTile(x, y - 1, z) == + Tile::portalTile_Id) { + y--; + } + + double yd = (y + 0.5) - e->y; + double dist = xd * xd + yd * yd + zd * zd; + if (closest < 0 || dist < closest) { + closest = dist; + xTarget = x; + yTarget = y; + zTarget = z; + } } } } @@ -94,25 +130,115 @@ bool PortalForcer::findPortal(Level* level, std::shared_ptr e) { int y = yTarget; int z = zTarget; + if (updateCache) { + cachedPortals[hash] = + new PortalPosition(x, y, z, level->getGameTime()); + cachedPortalKeys.push_back(hash); + } + double xt = x + 0.5; double yt = y + 0.5; double zt = z + 0.5; + int dir = Direction::UNDEFINED; - if (level->getTile(x - 1, y, z) == Tile::portalTile_Id) xt -= 0.5; - if (level->getTile(x + 1, y, z) == Tile::portalTile_Id) xt += 0.5; + if (level->getTile(x - 1, y, z) == Tile::portalTile_Id) + dir = Direction::NORTH; + if (level->getTile(x + 1, y, z) == Tile::portalTile_Id) + dir = Direction::SOUTH; + if (level->getTile(x, y, z - 1) == Tile::portalTile_Id) + dir = Direction::EAST; + if (level->getTile(x, y, z + 1) == Tile::portalTile_Id) + dir = Direction::WEST; - if (level->getTile(x, y, z - 1) == Tile::portalTile_Id) zt -= 0.5; - if (level->getTile(x, y, z + 1) == Tile::portalTile_Id) zt += 0.5; + int originalDir = e->getPortalEntranceDir(); - e->moveTo(xt, yt, zt, e->yRot, 0); - e->xd = e->yd = e->zd = 0; + if (dir > Direction::UNDEFINED) { + int leftDir = Direction::DIRECTION_COUNTER_CLOCKWISE[dir]; + int forwardsx = Direction::STEP_X[dir]; + int forwardsz = Direction::STEP_Z[dir]; + int leftx = Direction::STEP_X[leftDir]; + int leftz = Direction::STEP_Z[leftDir]; + + bool leftBlocked = !level->isEmptyTile(x + forwardsx + leftx, y, + z + forwardsz + leftz) || + !level->isEmptyTile(x + forwardsx + leftx, y + 1, + z + forwardsz + leftz); + bool rightBlocked = + !level->isEmptyTile(x + forwardsx, y, z + forwardsz) || + !level->isEmptyTile(x + forwardsx, y + 1, z + forwardsz); + + if (leftBlocked && rightBlocked) { + dir = Direction::DIRECTION_OPPOSITE[dir]; + leftDir = Direction::DIRECTION_OPPOSITE[leftDir]; + forwardsx = Direction::STEP_X[dir]; + forwardsz = Direction::STEP_Z[dir]; + leftx = Direction::STEP_X[leftDir]; + leftz = Direction::STEP_Z[leftDir]; + + x -= leftx; + xt -= leftx; + z -= leftz; + zt -= leftz; + leftBlocked = !level->isEmptyTile(x + forwardsx + leftx, y, + z + forwardsz + leftz) || + !level->isEmptyTile(x + forwardsx + leftx, y + 1, + z + forwardsz + leftz); + rightBlocked = + !level->isEmptyTile(x + forwardsx, y, z + forwardsz) || + !level->isEmptyTile(x + forwardsx, y + 1, z + forwardsz); + } + + float offsetLeft = 0.5f; + float offsetForwards = 0.5f; + + if (!leftBlocked && rightBlocked) { + offsetLeft = 1; + } else if (leftBlocked && !rightBlocked) { + offsetLeft = 0; + } else if (leftBlocked && rightBlocked) { + offsetForwards = 0; + } + + // Center them in the frame and push them out forwards + xt += (leftx * offsetLeft) + (offsetForwards * forwardsx); + zt += (leftz * offsetLeft) + (offsetForwards * forwardsz); + + float xx = 0; + float zz = 0; + float xz = 0; + float zx = 0; + + if (dir == originalDir) { + xx = 1; + zz = 1; + } else if (dir == Direction::DIRECTION_OPPOSITE[originalDir]) { + xx = -1; + zz = -1; + } else if (dir == Direction::DIRECTION_CLOCKWISE[originalDir]) { + xz = 1; + zx = -1; + } else { + xz = -1; + zx = 1; + } + + double xd = e->xd; + double zd = e->zd; + e->xd = xd * xx + zd * zx; + e->zd = xd * xz + zd * zz; + e->yRot = (yRotOriginal - originalDir * 90) + (dir * 90); + } else { + e->xd = e->yd = e->zd = 0; + } + + e->moveTo(xt, yt, zt, e->yRot, e->xRot); return true; } return false; } -bool PortalForcer::createPortal(Level* level, std::shared_ptr e) { +bool PortalForcer::createPortal(std::shared_ptr e) { // 4J Stu - Increase the range at which we try and create a portal to stop // creating them floating in mid air over lava int r = 16 * 3; @@ -317,14 +443,14 @@ bool PortalForcer::createPortal(Level* level, std::shared_ptr e) { bool border = h < 0; - level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : 0); + level->setTileAndUpdate(xt, yt, zt, + border ? Tile::obsidian_Id : 0); } } } } for (int pass = 0; pass < 4; pass++) { - level->noNeighborUpdate = true; for (int s = 0; s < 4; s++) { for (int h = -1; h < 4; h++) { int xt = x + (s - 1) * xa; @@ -332,12 +458,12 @@ bool PortalForcer::createPortal(Level* level, std::shared_ptr e) { int zt = z + (s - 1) * za; bool border = s == 0 || s == 3 || h == -1 || h == 3; - level->setTile( + level->setTileAndData( xt, yt, zt, - border ? Tile::obsidian_Id : Tile::portalTile_Id); + border ? Tile::obsidian_Id : Tile::portalTile_Id, 0, + Tile::UPDATE_CLIENTS); } } - level->noNeighborUpdate = false; for (int s = 0; s < 4; s++) { for (int h = -1; h < 4; h++) { @@ -353,3 +479,23 @@ bool PortalForcer::createPortal(Level* level, std::shared_ptr e) { return true; } + +void PortalForcer::tick(int64_t time) { + if (time % (SharedConstants::TICKS_PER_SECOND * 5) == 0) { + int64_t cutoff = time - SharedConstants::TICKS_PER_SECOND * 30; + + for (AUTO_VAR(it, cachedPortalKeys.begin()); + it != cachedPortalKeys.end();) { + int64_t key = *it; + PortalPosition* pos = cachedPortals[key]; + + if (pos == NULL || pos->lastUsed < cutoff) { + delete pos; + it = cachedPortalKeys.erase(it); + cachedPortals.erase(key); + } else { + ++it; + } + } + } +} \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/PortalForcer.h b/Minecraft.World/Level/Storage/PortalForcer.h index af766ab50..9b341896c 100644 --- a/Minecraft.World/Level/Storage/PortalForcer.h +++ b/Minecraft.World/Level/Storage/PortalForcer.h @@ -3,18 +3,28 @@ class Random; class PortalForcer { +public: + class PortalPosition : public Pos { + public: + int64_t lastUsed; + + PortalPosition(int x, int y, int z, int64_t time); + }; + private: + ServerLevel* level; Random* random; + std::unordered_map cachedPortals; + std::vector cachedPortalKeys; public: - // 4J Stu Added - Java has no ctor, but we need to initialise random - PortalForcer(); + PortalForcer(ServerLevel* level); + ~PortalForcer(); - void force(Level* level, std::shared_ptr e); - -public: - bool findPortal(Level* level, std::shared_ptr e); - -public: - bool createPortal(Level* level, std::shared_ptr e); + void force(std::shared_ptr e, double xOriginal, double yOriginal, + double zOriginal, float yRotOriginal); + bool findPortal(std::shared_ptr e, double xOriginal, + double yOriginal, double zOriginal, float yRotOriginal); + bool createPortal(std::shared_ptr e); + void tick(int64_t time); }; \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/Region.cpp b/Minecraft.World/Level/Storage/Region.cpp index 484843e1b..4e5f331bd 100644 --- a/Minecraft.World/Level/Storage/Region.cpp +++ b/Minecraft.World/Level/Storage/Region.cpp @@ -3,6 +3,7 @@ #include "../../Headers/net.minecraft.world.level.chunk.h" #include "../../Headers/net.minecraft.world.level.dimension.h" #include "../../Headers/net.minecraft.world.level.tile.h" +#include "../../Headers/net.minecraft.world.level.redstone.h" #include "../../Blocks/Material.h" #include "../Level.h" @@ -23,13 +24,14 @@ Region::~Region() { } } -Region::Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2) { +Region::Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2, + int r) { this->level = level; - xc1 = x1 >> 4; - zc1 = z1 >> 4; - int xc2 = x2 >> 4; - int zc2 = z2 >> 4; + xc1 = (x1 - r) >> 4; + zc1 = (z1 - r) >> 4; + int xc2 = (x2 + r) >> 4; + int zc2 = (z2 + r) >> 4; chunks = new LevelChunk2DArray(xc2 - xc1 + 1, zc2 - zc1 + 1); @@ -40,7 +42,14 @@ Region::Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2) { if (chunk != NULL) { LevelChunkArray* lca = (*chunks)[xc - xc1]; lca->data[zc - zc1] = chunk; - //(*chunks)[xc - xc1].data[zc - zc1] = level->getChunk(xc, zc); + } + } + } + for (int xc = (x1 >> 4); xc <= (x2 >> 4); xc++) { + for (int zc = (z1 >> 4); zc <= (z2 >> 4); zc++) { + LevelChunkArray* lca = (*chunks)[xc - xc1]; + LevelChunk* chunk = lca->data[zc - zc1]; + if (chunk != NULL) { if (!chunk->isYSpaceEmpty(y1, y2)) { allEmpty = false; } @@ -246,18 +255,8 @@ bool Region::isSolidBlockingTile(int x, int y, int z) { } bool Region::isTopSolidBlocking(int x, int y, int z) { - // Temporary workaround until tahgs per-face solidity is finished Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; - - if (tile->material->isSolidBlocking() && tile->isCubeShaped()) return true; - if (dynamic_cast(tile)) - return (getData(x, y, z) & StairTile::UPSIDEDOWN_BIT) == - StairTile::UPSIDEDOWN_BIT; - if (dynamic_cast(tile)) - return (getData(x, y, z) & HalfSlabTile::TOP_SLOT_BIT) == - HalfSlabTile::TOP_SLOT_BIT; - return false; + return level->isTopSolidBlocking(tile, getData(x, y, z)); } bool Region::isEmptyTile(int x, int y, int z) { @@ -279,6 +278,9 @@ int Region::getBrightnessPropagate(LightLayer::variety layer, int x, int y, // an int return (int)layer; } + if (layer == LightLayer::Sky && level->dimension->hasCeiling) { + return 0; + } int id = tileId > -1 ? tileId : getTile(x, y, z); if (Tile::propagate[id]) { @@ -324,4 +326,10 @@ int Region::getBrightness(LightLayer::variety layer, int x, int y, int z) { return (*chunks)[xc]->data[zc]->getBrightness(layer, x & 15, y, z & 15); } -int Region::getMaxBuildHeight() { return Level::maxBuildHeight; } \ No newline at end of file +int Region::getMaxBuildHeight() { return Level::maxBuildHeight; } + +int Region::getDirectSignal(int x, int y, int z, int dir) { + int t = getTile(x, y, z); + if (t == 0) return Redstone::SIGNAL_NONE; + return Tile::tiles[t]->getDirectSignal(this, x, y, z, dir); +} \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/Region.h b/Minecraft.World/Level/Storage/Region.h index 69b16ec49..33b72d65e 100644 --- a/Minecraft.World/Level/Storage/Region.h +++ b/Minecraft.World/Level/Storage/Region.h @@ -18,7 +18,7 @@ private: unsigned char* CachedTiles; public: - Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2); + Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2, int r); virtual ~Region(); bool isAllEmpty(); int getTile(int x, int y, int z); @@ -45,6 +45,7 @@ public: int getBrightness(LightLayer::variety layer, int x, int y, int z); int getMaxBuildHeight(); + int getDirectSignal(int x, int y, int z, int dir); LevelChunk* getLevelChunk(int x, int y, int z); diff --git a/Minecraft.World/Level/Storage/RegionFile.h b/Minecraft.World/Level/Storage/RegionFile.h index d3a43a74e..35f6202d1 100644 --- a/Minecraft.World/Level/Storage/RegionFile.h +++ b/Minecraft.World/Level/Storage/RegionFile.h @@ -29,7 +29,7 @@ private: int* chunkTimestamps; std::vector* sectorFree; int sizeDelta; - __int64 _lastModified; + int64_t _lastModified; bool m_bIsEmpty; // 4J added public: @@ -37,7 +37,7 @@ public: ~RegionFile(); /* the modification date of the region file when it was first opened */ - __int64 lastModified(); + int64_t lastModified(); /* gets how much the region file has grown since it was last checked */ int getSizeDelta(); diff --git a/Minecraft.World/Level/Storage/RegionFileCache.cpp b/Minecraft.World/Level/Storage/RegionFileCache.cpp index 89965fd2d..357eeaa3a 100644 --- a/Minecraft.World/Level/Storage/RegionFileCache.cpp +++ b/Minecraft.World/Level/Storage/RegionFileCache.cpp @@ -25,7 +25,7 @@ RegionFile* RegionFileCache::_getRegionFile( // File regionDir(basePath, L"region"); - // File file(regionDir, std::wstring(L"r.") + _toString(chunkX>>5) + L"." + + // File file(regionDir, wstring(L"r.") + _toString(chunkX>>5) + L"." + // _toString(chunkZ>>5) + L".mcr" ); MemSect(31); File file; @@ -109,3 +109,5 @@ DataOutputStream* RegionFileCache::_getChunkDataOutputStream( return r->getChunkDataOutputStream(chunkX & 31, chunkZ & 31); } } + +RegionFileCache::~RegionFileCache() { _clear(); } diff --git a/Minecraft.World/Level/Storage/RegionFileCache.h b/Minecraft.World/Level/Storage/RegionFileCache.h index 9e8586eeb..3f29e132a 100644 --- a/Minecraft.World/Level/Storage/RegionFileCache.h +++ b/Minecraft.World/Level/Storage/RegionFileCache.h @@ -17,6 +17,7 @@ public: // Made public and non-static so we can have a cache for input and output // files RegionFileCache() {} + ~RegionFileCache(); RegionFile* _getRegionFile(ConsoleSaveFile* saveFile, const std::wstring& prefix, int chunkX, diff --git a/Minecraft.World/Level/Storage/SavedDataStorage.cpp b/Minecraft.World/Level/Storage/SavedDataStorage.cpp index 4a6d02ba6..3490d30f7 100644 --- a/Minecraft.World/Level/Storage/SavedDataStorage.cpp +++ b/Minecraft.World/Level/Storage/SavedDataStorage.cpp @@ -10,9 +10,9 @@ SavedDataStorage::SavedDataStorage(LevelStorage* levelStorage) { /* - cache = new std::unordered_map >; - savedDatas = new std::vector >; - usedAuxIds = new std::unordered_map; + cache = new unordered_map >; + savedDatas = new vector >; + usedAuxIds = new unordered_map; */ this->levelStorage = levelStorage; @@ -31,7 +31,8 @@ std::shared_ptr SavedDataStorage::get(const std::type_info& clazz, if (!file.getName().empty() && levelStorage->getSaveFile()->doesFileExist(file)) { // mob = std::dynamic_pointer_cast(Mob::_class->newInstance( - // level )); + // level + // )); // data = clazz.getConstructor(String.class).newInstance(id); if (clazz == typeid(MapItemSavedData)) { @@ -41,6 +42,10 @@ std::shared_ptr SavedDataStorage::get(const std::type_info& clazz, } else if (clazz == typeid(Villages)) { data = std::dynamic_pointer_cast( std::shared_ptr(new Villages(id))); + } else if (clazz == typeid(StructureFeatureSavedData)) { + data = std::dynamic_pointer_cast( + std::shared_ptr( + new StructureFeatureSavedData(id))); } else { // Handling of new SavedData class required __debugbreak(); diff --git a/Minecraft.World/Level/Storage/ZoneIO.cpp b/Minecraft.World/Level/Storage/ZoneIO.cpp index f7aee7a7f..2cdcdf3d7 100644 --- a/Minecraft.World/Level/Storage/ZoneIO.cpp +++ b/Minecraft.World/Level/Storage/ZoneIO.cpp @@ -3,7 +3,7 @@ #include "ZoneIO.h" namespace { -bool SeekFile(std::FILE* file, __int64 offset) { +bool SeekFile(std::FILE* file, int64_t offset) { #if defined(_WIN32) return _fseeki64(file, offset, SEEK_SET) == 0; #else @@ -12,7 +12,7 @@ bool SeekFile(std::FILE* file, __int64 offset) { } } // namespace -ZoneIo::ZoneIo(std::FILE* channel, __int64 pos) { +ZoneIo::ZoneIo(std::FILE* channel, int64_t pos) { this->channel = channel; this->pos = pos; } diff --git a/Minecraft.World/Level/Storage/ZoneIO.h b/Minecraft.World/Level/Storage/ZoneIO.h index 73f63970f..74f74ea91 100644 --- a/Minecraft.World/Level/Storage/ZoneIO.h +++ b/Minecraft.World/Level/Storage/ZoneIO.h @@ -8,10 +8,10 @@ class ByteBuffer; class ZoneIo { private: std::FILE* channel; - __int64 pos; + int64_t pos; public: - ZoneIo(std::FILE* channel, __int64 pos); + ZoneIo(std::FILE* channel, int64_t pos); void write(byteArray bb, int size); void write(ByteBuffer* bb, int size); ByteBuffer* read(int size); diff --git a/Minecraft.World/Level/Storage/ZonedChunkStorage.cpp b/Minecraft.World/Level/Storage/ZonedChunkStorage.cpp index 3bbe5a8c3..fcdc90cd2 100644 --- a/Minecraft.World/Level/Storage/ZonedChunkStorage.cpp +++ b/Minecraft.World/Level/Storage/ZonedChunkStorage.cpp @@ -52,7 +52,7 @@ ZoneFile* ZonedChunkStorage::getZoneFile(int x, int z, bool create) { int xZone = x >> CHUNKS_PER_ZONE_BITS; int zZone = z >> CHUNKS_PER_ZONE_BITS; - __int64 key = xZone + (zZone << 20l); + int64_t key = xZone + (zZone << 20l); // 4J - was !zoneFiles.containsKey(key) if (zoneFiles.find(key) == zoneFiles.end()) { wchar_t xRadix36[64]; @@ -108,8 +108,8 @@ LevelChunk* ZonedChunkStorage::load(Level* level, int x, int z) { header->flip(); int xOrg = header->getInt(); int zOrg = header->getInt(); - __int64 time = header->getLong(); - __int64 flags = header->getLong(); + int64_t time = header->getLong(); + int64_t flags = header->getLong(); lc->terrainPopulated = (flags & BIT_TERRAIN_POPULATED) != 0; @@ -120,7 +120,7 @@ LevelChunk* ZonedChunkStorage::load(Level* level, int x, int z) { } void ZonedChunkStorage::save(Level* level, LevelChunk* lc) { - __int64 flags = 0; + int64_t flags = 0; if (lc->terrainPopulated) flags |= BIT_TERRAIN_POPULATED; ByteBuffer* header = ByteBuffer::allocate(CHUNK_HEADER_SIZE); @@ -144,10 +144,10 @@ void ZonedChunkStorage::save(Level* level, LevelChunk* lc) { void ZonedChunkStorage::tick() { tickCount++; if (tickCount % (20 * 10) == 4) { - std::vector<__int64> toClose; + std::vector toClose; AUTO_VAR(itEndZF, zoneFiles.end()); - for (std::unordered_map<__int64, ZoneFile*>::iterator it = + for (std::unordered_map::iterator it = zoneFiles.begin(); it != itEndZF; it++) { ZoneFile* zoneFile = it->second; @@ -158,7 +158,7 @@ void ZonedChunkStorage::tick() { AUTO_VAR(itEndTC, toClose.end()); for (AUTO_VAR(it, toClose.begin()); it != itEndTC; it++) { - __int64 key = *it; // toClose[i]; + int64_t key = *it; // toClose[i]; // 4J - removed try/catch // try { char buf[256]; @@ -175,7 +175,7 @@ void ZonedChunkStorage::tick() { void ZonedChunkStorage::flush() { AUTO_VAR(itEnd, zoneFiles.end()); - for (std::unordered_map<__int64, ZoneFile*>::iterator it = + for (std::unordered_map::iterator it = zoneFiles.begin(); it != itEnd; it++) { ZoneFile* zoneFile = it->second; diff --git a/Minecraft.World/Level/Storage/ZonedChunkStorage.h b/Minecraft.World/Level/Storage/ZonedChunkStorage.h index e2dd1f879..4cf3b0e34 100644 --- a/Minecraft.World/Level/Storage/ZonedChunkStorage.h +++ b/Minecraft.World/Level/Storage/ZonedChunkStorage.h @@ -28,8 +28,8 @@ public: File dir; private: - std::unordered_map<__int64, ZoneFile*> zoneFiles; - __int64 tickCount; + std::unordered_map zoneFiles; + int64_t tickCount; public: ZonedChunkStorage(File dir); diff --git a/Minecraft.World/Level/TickNextTickData.cpp b/Minecraft.World/Level/TickNextTickData.cpp index 9bbaaa7fa..b050cf11c 100644 --- a/Minecraft.World/Level/TickNextTickData.cpp +++ b/Minecraft.World/Level/TickNextTickData.cpp @@ -1,8 +1,8 @@ #include "../Platform/stdafx.h" - +#include "../Headers/net.minecraft.world.level.tile.h" #include "TickNextTickData.h" -__int64 TickNextTickData::C = 0; +int64_t TickNextTickData::C = 0; TickNextTickData::TickNextTickData(int x, int y, int z, int tileId) { m_delay = 0; @@ -12,38 +12,47 @@ TickNextTickData::TickNextTickData(int x, int y, int z, int tileId) { this->y = y; this->z = z; this->tileId = tileId; + priorityTilt = 0; } -bool TickNextTickData::equals(const void* o) const { +bool TickNextTickData::equals(const TickNextTickData* o) const { // TODO 4J Is this safe to cast it before we do a dynamic_cast? Will the // dynamic_cast still fail? We cannot dynamic_cast a void* - if (dynamic_cast((TickNextTickData*)o) != NULL) { + if (o != NULL) { TickNextTickData* t = (TickNextTickData*)o; - return x == t->x && y == t->y && z == t->z && tileId == t->tileId; + return x == t->x && y == t->y && z == t->z && + Tile::isMatching(tileId, t->tileId); } return false; } int TickNextTickData::hashCode() const { - // 4jcraft added cast to unsigned - return ((((unsigned)x * 1024 * 1024) + ((unsigned)z * 1024) + (unsigned)y) * - 256) + - tileId; + return (((x * 1024 * 1024) + (z * 1024) + y) * 256); } -TickNextTickData* TickNextTickData::delay(__int64 l) { - this->m_delay = l; +TickNextTickData* TickNextTickData::delay(int64_t l) { + m_delay = l; return this; } +void TickNextTickData::setPriorityTilt(int priorityTilt) { + this->priorityTilt = priorityTilt; +} + int TickNextTickData::compareTo(const TickNextTickData* tnd) const { if (m_delay < tnd->m_delay) return -1; if (m_delay > tnd->m_delay) return 1; + if (priorityTilt != tnd->priorityTilt) + return priorityTilt - tnd->priorityTilt; if (c < tnd->c) return -1; if (c > tnd->c) return 1; return 0; } +bool TickNextTickData::operator==(const TickNextTickData& k) { + return equals(&k); +} + // A class that takes two arguments of the same type as the container elements // and returns a bool. The expression comp(a,b), where comp is an object of this // comparison class and a and b are elements of the container, shall return true @@ -62,6 +71,5 @@ int TickNextTickData::hash_fnct(const TickNextTickData& k) { bool TickNextTickData::eq_test(const TickNextTickData& x, const TickNextTickData& y) { - return (x.x == y.x) && (x.y == y.y) && (x.z == y.z) && - (x.tileId == y.tileId); -} + return x.equals(&y); +} \ No newline at end of file diff --git a/Minecraft.World/Level/TickNextTickData.h b/Minecraft.World/Level/TickNextTickData.h index 91b748829..0b88b4d3e 100644 --- a/Minecraft.World/Level/TickNextTickData.h +++ b/Minecraft.World/Level/TickNextTickData.h @@ -6,27 +6,30 @@ class TickNextTickData { private: - static __int64 C; + static int64_t C; public: int x, y, z, tileId; - __int64 m_delay; + int64_t m_delay; + int priorityTilt; private: - __int64 c; + int64_t c; public: TickNextTickData(int x, int y, int z, int tileId); - bool equals(const void* o) const; + bool equals(const TickNextTickData* o) const; int hashCode() const; - TickNextTickData* delay(__int64 l); + TickNextTickData* delay(int64_t l); + void setPriorityTilt(int priorityTilt); int compareTo(const TickNextTickData* tnd) const; static bool compare_fnct(const TickNextTickData& x, const TickNextTickData& y); static int hash_fnct(const TickNextTickData& k); static bool eq_test(const TickNextTickData& x, const TickNextTickData& y); + bool operator==(const TickNextTickData& k); }; struct TickNextTickDataKeyHash { diff --git a/Minecraft.World/Level/WaterLevelChunk.cpp b/Minecraft.World/Level/WaterLevelChunk.cpp index ab2661184..00102b2b3 100644 --- a/Minecraft.World/Level/WaterLevelChunk.cpp +++ b/Minecraft.World/Level/WaterLevelChunk.cpp @@ -67,6 +67,8 @@ void WaterLevelChunk::load() {} void WaterLevelChunk::unload(bool unloadTileEntities) // 4J - added parameter {} +bool WaterLevelChunk::containsPlayer() { return false; } + void WaterLevelChunk::markUnsaved() {} void WaterLevelChunk::getEntities(std::shared_ptr except, AABB bb, @@ -104,7 +106,7 @@ bool WaterLevelChunk::testSetBlocksAndData(byteArray data, int x0, int y0, return false; } -Random* WaterLevelChunk::getRandom(__int64 l) { +Random* WaterLevelChunk::getRandom(int64_t l) { return new Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l); diff --git a/Minecraft.World/Level/WaterLevelChunk.h b/Minecraft.World/Level/WaterLevelChunk.h index c4cb39c30..f153318a4 100644 --- a/Minecraft.World/Level/WaterLevelChunk.h +++ b/Minecraft.World/Level/WaterLevelChunk.h @@ -36,6 +36,7 @@ public: void removeTileEntity(int x, int y, int z); void load(); void unload(bool unloadTileEntities); // 4J - added parameter + bool containsPlayer(); // 4J added void markUnsaved(); void getEntities(std::shared_ptr except, AABB bb, std::vector >& es); @@ -49,7 +50,7 @@ public: bool includeLighting = true); // 4J - added includeLighting parameter; bool testSetBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int p); - Random* getRandom(__int64 l); + Random* getRandom(int64_t l); virtual Biome* getBiome(int x, int z, BiomeSource* biomeSource); virtual void reSyncLighting() {}; // 4J added };