mirror of
https://github.com/celisej567/mcpe.git
synced 2025-12-31 17:49:17 +03:00
315 lines
6.5 KiB
C++
315 lines
6.5 KiB
C++
/********************************************************************
|
|
Minecraft: Pocket Edition - Decompilation Project
|
|
Copyright (C) 2023 iProgramInCpp
|
|
|
|
The following code is licensed under the BSD 1 clause license.
|
|
SPDX-License-Identifier: BSD-1-Clause
|
|
********************************************************************/
|
|
|
|
#include "LiquidTileDynamic.hpp"
|
|
#include "world/level/Level.hpp"
|
|
|
|
constexpr bool g_bDisableSponges = true; // disable sponges for now
|
|
|
|
LiquidTileDynamic::LiquidTileDynamic(int id, Material* pMtl) : LiquidTile(id, pMtl)
|
|
{
|
|
}
|
|
|
|
bool LiquidTileDynamic::checkSpongesNearby(Level* level, int x, int y, int z)
|
|
{
|
|
// NOTE: I imagine this could get slow. So you can disable it
|
|
if (g_bDisableSponges)
|
|
return false;
|
|
|
|
for (int ox = -2; ox <= 2; ox++)
|
|
{
|
|
for (int oy = -2; oy <= 2; oy++)
|
|
{
|
|
for (int oz = -2; oz <= 2; oz++)
|
|
{
|
|
if (level->getTile(x + ox, y + oy, z + oz) == Tile::sponge->m_ID)
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool LiquidTileDynamic::isWaterBlocking(Level* level, int x, int y, int z)
|
|
{
|
|
TileID tile = level->getTile(x, y, z);
|
|
if (tile == Tile::reeds->m_ID)
|
|
return true;
|
|
|
|
if (!g_bDisableSponges)
|
|
{
|
|
if (checkSpongesNearby(level, x, y, z))
|
|
return true;
|
|
}
|
|
|
|
if (!tile)
|
|
return false;
|
|
|
|
return Tile::tiles[tile]->m_pMaterial->isSolid();
|
|
}
|
|
|
|
bool LiquidTileDynamic::canSpreadTo(Level* level, int x, int y, int z)
|
|
{
|
|
Material* pMtl = level->getMaterial(x, y, z);
|
|
if (pMtl == m_pMaterial || pMtl == Material::lava)
|
|
return false;
|
|
|
|
return !isWaterBlocking(level, x, y, z);
|
|
}
|
|
|
|
int LiquidTileDynamic::getSlopeDistance(Level* level, int x, int y, int z, int depth, int a7)
|
|
{
|
|
int cost = 1000;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if ((i == 0 && a7 == 1) || (i == 1 && a7 == 0) || (i == 2 && a7 == 3) || (i == 3 && a7 == 2))
|
|
continue;
|
|
|
|
int checkX = x, checkY = y, checkZ = z;
|
|
switch (i)
|
|
{
|
|
case 0: checkX--; break;
|
|
case 1: checkX++; break;
|
|
case 2: checkZ--; break;
|
|
case 3: checkZ++; break;
|
|
}
|
|
|
|
if (isWaterBlocking(level, checkX, checkY, checkZ))
|
|
continue;
|
|
|
|
if (level->getMaterial(checkX, checkY, checkZ) == m_pMaterial &&
|
|
level->getData(checkX,checkY,checkZ) == 0)
|
|
continue;
|
|
|
|
if (!isWaterBlocking(level, checkX, checkY - 1, checkZ))
|
|
return depth;
|
|
|
|
if (depth >= 4)
|
|
continue;
|
|
|
|
int otherCost = getSlopeDistance(level, checkX, checkY, checkZ, depth + 1, i);
|
|
if (cost > otherCost)
|
|
cost = otherCost;
|
|
}
|
|
|
|
return cost;
|
|
}
|
|
|
|
bool* LiquidTileDynamic::getSpread(Level* level, int x, int y, int z)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
field_74[i] = 1000;
|
|
|
|
int xChk = x, zChk = z;
|
|
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
xChk--;
|
|
break;
|
|
case 1:
|
|
xChk++;
|
|
break;
|
|
case 2:
|
|
zChk--;
|
|
break;
|
|
case 3:
|
|
zChk++;
|
|
break;
|
|
}
|
|
|
|
if (isWaterBlocking(level, xChk, y, zChk))
|
|
continue;
|
|
|
|
if (level->getMaterial(xChk, y, zChk) == m_pMaterial &&
|
|
level->getData(xChk, y, zChk) == 0)
|
|
continue;
|
|
|
|
if (isWaterBlocking(level, xChk, y - 1, zChk))
|
|
field_74[i] = getSlopeDistance(level, xChk, y, zChk, 1, i);
|
|
else
|
|
field_74[i] = 0;
|
|
}
|
|
|
|
int min = field_74[0];
|
|
// @NOTE: unrolled loop
|
|
for (int i = 1; i < 4; i++)
|
|
{
|
|
if (min >= field_74[i])
|
|
min = field_74[i];
|
|
}
|
|
|
|
// @NOTE: unrolled loop
|
|
for (int i = 0; i < 4; i++)
|
|
field_70[i] = field_74[i] == min;
|
|
|
|
return field_70;
|
|
}
|
|
|
|
void LiquidTileDynamic::onPlace(Level* level, int x, int y, int z)
|
|
{
|
|
updateLiquid(level, x, y, z);
|
|
|
|
if (level->getTile(x, y, z) == m_ID)
|
|
{
|
|
level->addToTickNextTick(x, y, z, m_ID, getTickDelay());
|
|
}
|
|
}
|
|
|
|
void LiquidTileDynamic::setStatic(Level* level, int x, int y, int z)
|
|
{
|
|
int data = level->getData(x, y, z);
|
|
level->setTileAndDataNoUpdate(x, y, z, m_ID + 1, data);
|
|
level->setTilesDirty(x, y, z, x, y, z);
|
|
level->sendTileUpdated(x, y, z);
|
|
}
|
|
|
|
void LiquidTileDynamic::trySpreadTo(Level* level, int x, int y, int z, int data)
|
|
{
|
|
if (!canSpreadTo(level, x, y, z))
|
|
return;
|
|
|
|
TileID tile = level->getTile(x, y, z);
|
|
if (tile > 0)
|
|
{
|
|
if (m_pMaterial == Material::lava)
|
|
{
|
|
fizz(level, x, y, z);
|
|
}
|
|
else
|
|
{
|
|
Tile::tiles[tile]->spawnResources(level, x, y, z, level->getData(x, y, z));
|
|
}
|
|
}
|
|
|
|
level->setTileAndData(x, y, z, m_ID, data);
|
|
}
|
|
|
|
// @NOTE: This is inlined in PE.
|
|
int LiquidTileDynamic::getSmallestDepth(Level* level, int x, int y, int z, int oldDepth)
|
|
{
|
|
int depth = getDepth(level, x, y, z);
|
|
if (depth < 0)
|
|
return oldDepth;
|
|
|
|
if (depth == 0)
|
|
field_6C++;
|
|
|
|
if (depth >= 8)
|
|
depth = 0;
|
|
|
|
return oldDepth >= 0 && depth >= oldDepth ? oldDepth : depth;
|
|
}
|
|
|
|
void LiquidTileDynamic::tick(Level* level, int x, int y, int z, Random* random)
|
|
{
|
|
int depth = getDepth(level, x, y, z);
|
|
int speed;
|
|
if (m_pMaterial != Material::lava || level->m_pDimension->field_D)
|
|
speed = 1;
|
|
else
|
|
speed = 2;
|
|
|
|
int depthMax, newData;
|
|
bool flag = true;
|
|
|
|
if (depth > 0)
|
|
{
|
|
field_6C = 0;
|
|
|
|
depthMax = -100;
|
|
depthMax = getSmallestDepth(level, x - 1, y, z, depthMax);
|
|
depthMax = getSmallestDepth(level, x + 1, y, z, depthMax);
|
|
depthMax = getSmallestDepth(level, x, y, z - 1, depthMax);
|
|
depthMax = getSmallestDepth(level, x, y, z + 1, depthMax);
|
|
|
|
newData = speed + depthMax;
|
|
if (newData > 7 || newData < 0)
|
|
newData = -1;
|
|
|
|
if (getDepth(level, x, y + 1, z) >= 0)
|
|
{
|
|
int depthUp = getDepth(level, x, y + 1, z);
|
|
if (depthUp >= 8)
|
|
newData = depthUp;
|
|
else
|
|
newData = depthUp + 8;
|
|
}
|
|
|
|
if (field_6C >= 2 && m_pMaterial == Material::water)
|
|
{
|
|
if (level->isSolidTile(x, y - 1, z))
|
|
{
|
|
newData = 0;
|
|
}
|
|
else if (m_pMaterial == level->getMaterial(x, y - 1, z))
|
|
{
|
|
if (!level->getData(x, y - 1, z))
|
|
newData = 0;
|
|
}
|
|
}
|
|
|
|
if (m_pMaterial == Material::lava && newData < 8 && depth < 8 && newData > depth && random->nextInt(4))
|
|
{
|
|
flag = false;
|
|
newData = depth;
|
|
}
|
|
|
|
if (newData != depth)
|
|
{
|
|
depth = newData;
|
|
if (depth < 0)
|
|
{
|
|
level->setTile(x, y, z, 0);
|
|
}
|
|
else
|
|
{
|
|
level->setData(x, y, z, depth);
|
|
level->addToTickNextTick(x, y, z, m_ID, getTickDelay());
|
|
}
|
|
}
|
|
else if (flag)
|
|
{
|
|
setStatic(level, x, y, z);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setStatic(level, x, y, z);
|
|
}
|
|
|
|
if (canSpreadTo(level, x, y - 1, z))
|
|
{
|
|
if (depth < 8)
|
|
depth += 8;
|
|
|
|
level->setTileAndData(x, y - 1, z, m_ID, depth);
|
|
return;
|
|
}
|
|
|
|
if (depth >= 0 && (depth == 0 || isWaterBlocking(level, x, y - 1, z)))
|
|
{
|
|
bool* bSpread = getSpread(level, x, y, z);
|
|
|
|
int data = depth + speed;
|
|
if (depth >= 8)
|
|
data = 1;
|
|
|
|
if (data >= 8)
|
|
return;
|
|
|
|
if (bSpread[0]) trySpreadTo(level, x - 1, y, z, data);
|
|
if (bSpread[1]) trySpreadTo(level, x + 1, y, z, data);
|
|
if (bSpread[2]) trySpreadTo(level, x, y, z - 1, data);
|
|
if (bSpread[3]) trySpreadTo(level, x, y, z + 1, data);
|
|
}
|
|
}
|