Simple dynamic lighting from torches in hand

This commit is contained in:
NSDeathman 2026-03-12 15:12:25 +03:00
parent 6f725b8355
commit 26a9d6adb7
9 changed files with 191 additions and 9 deletions

View file

@ -2302,13 +2302,18 @@ void LevelRenderer::renderHitOutline(shared_ptr<Player> 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);

View file

@ -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<ItemInstance> 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<InBedChatScreen *>(screen)!=nullptr) && !player->isSleeping())
{

View file

@ -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
}

View file

@ -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; // ìîáû ïðîõîäÿò ñêâîçü áëîê
}

View file

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

View file

@ -3197,6 +3197,12 @@
<ClInclude Include="FireworksMenu.h">
<Filter>net\minecraft\world\inventory</Filter>
</ClInclude>
<ClInclude Include="ClimateLayer.h">
<Filter>net\minecraft\world\level\newbiome\layer</Filter>
</ClInclude>
<ClInclude Include="LightSourceTile.h">
<Filter>net\minecraft\world\level\tile</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -5626,5 +5632,11 @@
<ClCompile Include="EmptyMapItem.cpp">
<Filter>net\minecraft\world\item</Filter>
</ClCompile>
<ClCompile Include="ClimateLayer.cpp">
<Filter>net\minecraft\world\level\newbiome\layer</Filter>
</ClCompile>
<ClCompile Include="LightSourceTile.cpp">
<Filter>net\minecraft\world\level\tile</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -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<FireTile *>(((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);

View file

@ -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;

View file

@ -129,5 +129,4 @@
#include "HalfSlabTile.h"
#include "WoodSlabTile.h"
#include "WoolCarpetTile.h"
#include "LightSourceTile.h"