diff --git a/Minecraft.Client/LevelRenderer.cpp b/Minecraft.Client/LevelRenderer.cpp index cf2937f4f..fdc81881b 100644 --- a/Minecraft.Client/LevelRenderer.cpp +++ b/Minecraft.Client/LevelRenderer.cpp @@ -2302,13 +2302,18 @@ void LevelRenderer::renderHitOutline(shared_ptr player, HitResult *h, in float ss = 0.002f; int tileId = level[iPad]->getTile(h->x, h->y, h->z); - if (tileId > 0) + if (tileId > 0 && Tile::tiles[tileId] != nullptr) { Tile::tiles[tileId]->updateShape(level[iPad], h->x, h->y, h->z); - double xo = player->xOld + (player->x - player->xOld) * a; - double yo = player->yOld + (player->y - player->yOld) * a; - double zo = player->zOld + (player->z - player->zOld) * a; - render(Tile::tiles[tileId]->getTileAABB(level[iPad], h->x, h->y, h->z)->grow(ss, ss, ss)->cloneMove(-xo, -yo, -zo)); + + AABB* aabb = Tile::tiles[tileId]->getTileAABB(level[iPad], h->x, h->y, h->z); + if (aabb != nullptr) + { + double xo = player->xOld + (player->x - player->xOld) * a; + double yo = player->yOld + (player->y - player->yOld) * a; + double zo = player->zOld + (player->z - player->zOld) * a; + render(aabb->grow(ss, ss, ss)->cloneMove(-xo, -yo, -zo)); + } } glDepthMask(true); glEnable(GL_TEXTURE_2D); diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index aa8fa1fa3..fbb9d26bd 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -2351,6 +2351,104 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) { // setScreen(new InBedChatScreen()); // 4J - TODO put back in } + // === Динамический свет от факела === + { + // Статические переменные для хранения последней позиции блока света + // (по одной на каждого возможного игрока) + static int lastLightX[XUSER_MAX_COUNT]; + static int lastLightY[XUSER_MAX_COUNT]; + static int lastLightZ[XUSER_MAX_COUNT]; + static bool lightPlaced[XUSER_MAX_COUNT]; + + // Инициализация при первом вызове + static bool initialized = false; + if (!initialized) + { + for (int i = 0; i < XUSER_MAX_COUNT; i++) + { + lastLightX[i] = 0; + lastLightY[i] = 0; + lastLightZ[i] = 0; + lightPlaced[i] = false; + } + initialized = true; + } + + if (player != nullptr && level != nullptr) + { + // Проверяем что держит игрок + shared_ptr heldItem = nullptr; + if (player->inventory->IsHeldItem()) + { + heldItem = player->inventory->getSelected(); + } + int heldItemId = (heldItem != nullptr) ? heldItem->getItem()->id : -1; + + bool holdingTorch = (heldItemId == Tile::torch_Id); + + // Текущая позиция игрока (целочисленная) + int curX = Mth::floor(player->x); + int curY = Mth::floor(player->y); + int curZ = Mth::floor(player->z); + + if (holdingTorch) + { + bool positionChanged = + (curX != lastLightX[iPad]) || + (curY != lastLightY[iPad]) || + (curZ != lastLightZ[iPad]); + + // Удаляем старый блок света если игрок переместился + if (lightPlaced[iPad] && positionChanged) + { + int ox = lastLightX[iPad]; + int oy = lastLightY[iPad]; + int oz = lastLightZ[iPad]; + + if (level->getTile(ox, oy, oz) == Tile::lightSourceBlock_Id) + { + level->setTileAndData(ox, oy, oz, 0, 0, Tile::UPDATE_CLIENTS); + } + lightPlaced[iPad] = false; + } + + // Ставим новый блок света если его ещё нет + if (!lightPlaced[iPad]) + { + // Ставим на позицию ног игрока только если клетка свободна + if (level->isEmptyTile(curX, curY, curZ)) + { + level->setTileAndData( + curX, curY, curZ, + Tile::lightSourceBlock_Id, 0, + Tile::UPDATE_CLIENTS + ); + lastLightX[iPad] = curX; + lastLightY[iPad] = curY; + lastLightZ[iPad] = curZ; + lightPlaced[iPad] = true; + } + } + } + else + { + // Игрок убрал факел — удаляем блок света + if (lightPlaced[iPad]) + { + int ox = lastLightX[iPad]; + int oy = lastLightY[iPad]; + int oz = lastLightZ[iPad]; + + if (level->getTile(ox, oy, oz) == Tile::lightSourceBlock_Id) + { + level->setTileAndData(ox, oy, oz, 0, 0, Tile::UPDATE_CLIENTS); + } + lightPlaced[iPad] = false; + } + } + } + } + // === Конец динамического света === } else if (screen != nullptr && (dynamic_cast(screen)!=nullptr) && !player->isSleeping()) { diff --git a/Minecraft.World/CustomLevelSource.cpp b/Minecraft.World/CustomLevelSource.cpp index 058429006..7281d298c 100644 --- a/Minecraft.World/CustomLevelSource.cpp +++ b/Minecraft.World/CustomLevelSource.cpp @@ -113,7 +113,7 @@ CustomLevelSource::CustomLevelSource(Level *level, int64_t seed, bool generateSt random = new Random(seed); pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation - perlinNoise3 = new PerlinNoise(random, 64 * (m_XZSize / 64)); + perlinNoise3 = new PerlinNoise(random, 4); #endif } diff --git a/Minecraft.World/LightSourceTile.cpp b/Minecraft.World/LightSourceTile.cpp new file mode 100644 index 000000000..fe7dbccb8 --- /dev/null +++ b/Minecraft.World/LightSourceTile.cpp @@ -0,0 +1,41 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.phys.h" +#include "LightSourceTile.h" + +LightSourceTile::LightSourceTile(int id) + : Tile(id, Material::air, /*isSolidRender=*/false) +{ + setLightEmission(1.0f); + setDestroyTime(0.0f); +} + +AABB* LightSourceTile::getAABB(Level* level, int x, int y, int z) +{ + return nullptr; // +} + +AABB* LightSourceTile::getTileAABB(Level* level, int x, int y, int z) +{ + return nullptr; // +} + +bool LightSourceTile::isSolidRender(bool isServerLevel) +{ + return false; // +} + +bool LightSourceTile::isCubeShaped() +{ + return false; +} + +int LightSourceTile::getRenderShape() +{ + return Tile::SHAPE_INVISIBLE; // +} + +bool LightSourceTile::isPathfindable(LevelSource* level, int x, int y, int z) +{ + return true; // +} diff --git a/Minecraft.World/LightSourceTile.h b/Minecraft.World/LightSourceTile.h new file mode 100644 index 000000000..60cff73da --- /dev/null +++ b/Minecraft.World/LightSourceTile.h @@ -0,0 +1,20 @@ +#pragma once +#include "Tile.h" + +class LightSourceTile : public Tile +{ +public: + LightSourceTile(int id); + + // + AABB* getAABB(Level* level, int x, int y, int z) override; + AABB* getTileAABB(Level* level, int x, int y, int z) override; + + // + bool isSolidRender(bool isServerLevel) override; + bool isCubeShaped() override; + int getRenderShape() override; + + // + bool isPathfindable(LevelSource* level, int x, int y, int z) override; +}; diff --git a/Minecraft.World/Minecraft.World.vcxproj.filters b/Minecraft.World/Minecraft.World.vcxproj.filters index bf872596b..ec5b3cb68 100644 --- a/Minecraft.World/Minecraft.World.vcxproj.filters +++ b/Minecraft.World/Minecraft.World.vcxproj.filters @@ -3197,6 +3197,12 @@ net\minecraft\world\inventory + + net\minecraft\world\level\newbiome\layer + + + net\minecraft\world\level\tile + @@ -5626,5 +5632,11 @@ net\minecraft\world\item + + net\minecraft\world\level\newbiome\layer + + + net\minecraft\world\level\tile + \ No newline at end of file diff --git a/Minecraft.World/Tile.cpp b/Minecraft.World/Tile.cpp index de113714d..dc5b1bdaf 100644 --- a/Minecraft.World/Tile.cpp +++ b/Minecraft.World/Tile.cpp @@ -220,6 +220,8 @@ Tile *Tile::woolCarpet = nullptr; Tile *Tile::clayHardened = nullptr; Tile *Tile::coalBlock = nullptr; +Tile *Tile::lightSourceBlock = nullptr; + DWORD Tile::tlsIdxShape = TlsAlloc(); Tile::ThreadStorage::ThreadStorage() @@ -312,7 +314,7 @@ void Tile::staticCtor() Tile::bookshelf = (new BookshelfTile(47)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_paper, Item::eMaterial_bookshelf)->setDestroyTime(1.5f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"bookshelf")->setDescriptionId(IDS_TILE_BOOKSHELF)->setUseDescriptionId(IDS_DESC_BOOKSHELF); Tile::mossyCobblestone = (new Tile(48, Material::stone)) ->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"cobblestone_mossy")->setDescriptionId(IDS_TILE_STONE_MOSS)->setUseDescriptionId(IDS_DESC_MOSS_STONE); Tile::obsidian = (new ObsidianTile(49)) ->setDestroyTime(50.0f)->setExplodeable(2000)->setSoundType(Tile::SOUND_STONE)->setIconName(L"obsidian")->setDescriptionId(IDS_TILE_OBSIDIAN)->setUseDescriptionId(IDS_DESC_OBSIDIAN); - Tile::torch = (new TorchTile(50)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_wood)->setDestroyTime(0.0f)->setLightEmission(15 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"torch_on")->setDescriptionId(IDS_TILE_TORCH)->setUseDescriptionId(IDS_DESC_TORCH)->disableMipmap(); + Tile::torch = (new TorchTile(torch_Id)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_wood)->setDestroyTime(0.0f)->setLightEmission(15 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"torch_on")->setDescriptionId(IDS_TILE_TORCH)->setUseDescriptionId(IDS_DESC_TORCH)->disableMipmap(); Tile::fire = static_cast(((new FireTile(51))->setDestroyTime(0.0f)->setLightEmission(1.0f)->setSoundType(Tile::SOUND_WOOD))->setIconName(L"fire")->setDescriptionId(IDS_TILE_FIRE)->setNotCollectStatistics()->setUseDescriptionId(-1)); Tile::mobSpawner = (new MobSpawnerTile(52)) ->setDestroyTime(5.0f)->setSoundType(Tile::SOUND_METAL)->setIconName(L"mob_spawner")->setDescriptionId(IDS_TILE_MOB_SPAWNER)->setNotCollectStatistics()->setUseDescriptionId(IDS_DESC_MOB_SPAWNER); @@ -442,6 +444,8 @@ void Tile::staticCtor() Tile::clayHardened = (new Tile(172, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_clay, Item::eMaterial_clay)->setDestroyTime(1.25f)->setExplodeable(7)->setSoundType(SOUND_STONE)->setIconName(L"hardened_clay")->setDescriptionId(IDS_TILE_HARDENED_CLAY)->setUseDescriptionId(IDS_DESC_HARDENED_CLAY); Tile::coalBlock = (new Tile(173, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_coal)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setIconName(L"coal_block")->setDescriptionId(IDS_TILE_COAL)->setUseDescriptionId(IDS_DESC_COAL_BLOCK); + Tile::lightSourceBlock = (new LightSourceTile(lightSourceBlock_Id))->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_wood)->setDestroyTime(0.0f)->setLightEmission(15 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"torch_on")->setDescriptionId(IDS_TILE_TORCH)->setUseDescriptionId(IDS_DESC_TORCH)->disableMipmap(); + // Special cases for certain items since they can have different icons Item::items[wool_Id] = ( new WoolTileItem(Tile::wool_Id- 256) )->setIconName(L"cloth")->setDescriptionId(IDS_TILE_CLOTH)->setUseDescriptionId(IDS_DESC_WOOL); diff --git a/Minecraft.World/Tile.h b/Minecraft.World/Tile.h index 307c4106a..6e9430158 100644 --- a/Minecraft.World/Tile.h +++ b/Minecraft.World/Tile.h @@ -365,6 +365,7 @@ public: static const int clayHardened_Id = 172; static const int coalBlock_Id = 173; + static const int lightSourceBlock_Id = 174; static Tile *stone; static GrassTile *grass; @@ -541,6 +542,8 @@ public: static Tile *clayHardened; static Tile *coalBlock; + static Tile* lightSourceBlock; + static void staticCtor(); int id; diff --git a/Minecraft.World/net.minecraft.world.level.tile.h b/Minecraft.World/net.minecraft.world.level.tile.h index 36c7ac5c6..8a019bb70 100644 --- a/Minecraft.World/net.minecraft.world.level.tile.h +++ b/Minecraft.World/net.minecraft.world.level.tile.h @@ -129,5 +129,4 @@ #include "HalfSlabTile.h" #include "WoodSlabTile.h" #include "WoolCarpetTile.h" - - +#include "LightSourceTile.h"