Skip to content

Commit

Permalink
* Add working lever block.
Browse files Browse the repository at this point in the history
Currently it renders like a torch.
  • Loading branch information
iProgramMC committed Apr 7, 2024
1 parent bb0afa2 commit 08ada94
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 2 deletions.
2 changes: 2 additions & 0 deletions platforms/windows/projects/World/World.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@
<ClCompile Include="$(MC_ROOT)\source\world\entity\Cow.cpp" />
<ClCompile Include="$(MC_ROOT)\source\world\entity\Creeper.cpp" />
<ClCompile Include="$(MC_ROOT)\source\world\entity\Pig.cpp" />
<ClCompile Include="..\..\..\..\source\world\tile\LeverTile.cpp" />
<ClCompile Include="..\..\..\..\source\world\tile\RedStoneTorchTile.cpp" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -459,6 +460,7 @@
<ClInclude Include="$(MC_ROOT)\source\world\entity\Creeper.hpp" />
<ClInclude Include="$(MC_ROOT)\source\world\entity\Pig.hpp" />
<ClInclude Include="$(MC_ROOT)\source\world\entity\Rocket.hpp" />
<ClInclude Include="..\..\..\..\source\world\tile\LeverTile.hpp" />
<ClInclude Include="..\..\..\..\source\world\tile\RedStoneTorchTile.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
Expand Down
6 changes: 6 additions & 0 deletions platforms/windows/projects/World/World.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,9 @@
<ClCompile Include="..\..\..\..\source\world\tile\RedStoneTorchTile.cpp">
<Filter>Source Files\Tile</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\source\world\tile\LeverTile.cpp">
<Filter>Source Files\Tile</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MC_ROOT)\source\world\entity\Entity.hpp">
Expand Down Expand Up @@ -802,5 +805,8 @@
<ClInclude Include="..\..\..\..\source\world\tile\RedStoneTorchTile.hpp">
<Filter>Header Files\Tile</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\source\world\tile\LeverTile.hpp">
<Filter>Header Files\Tile</Filter>
</ClInclude>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ add_library(reminecraftpe-core STATIC
world/tile/RocketLauncherTile.cpp
world/tile/WireTile.cpp
world/tile/RedStoneTorchTile.cpp
world/tile/LeverTile.cpp
renderer/GL/GL.cpp
)
target_include_directories(reminecraftpe-core PUBLIC . ..)
Expand Down
1 change: 1 addition & 0 deletions source/world/item/Inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ void Inventory::prepareCreativeInventory()
addCreativeItem(Tile::wire->m_ID);
addCreativeItem(Tile::notGate_off->m_ID);
addCreativeItem(Tile::notGate->m_ID);
addCreativeItem(Tile::lever->m_ID);

for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++)
m_hotbar[i] = i;
Expand Down
245 changes: 245 additions & 0 deletions source/world/tile/LeverTile.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
/********************************************************************
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 "LeverTile.hpp"
#include "world/level/Level.hpp"

LeverTile::LeverTile(int ID, int texture, Material* pMtl) : Tile(ID, texture, pMtl)
{
}

AABB* LeverTile::getAABB(Level*, int x, int y, int z)
{
return nullptr;
}

int LeverTile::getRenderShape()
{
return SHAPE_TORCH; // SHAPE_LEVER
}

bool LeverTile::isCubeShaped()
{
return false;
}

bool LeverTile::isSolidRender()
{
return false;
}

bool LeverTile::checkCanSurvive(Level* level, int x, int y, int z)
{
if (mayPlace(level, x, y, z))
return true;

spawnResources(level, x, y, z, level->getData(x, y, z));
level->setTile(x, y, z, TILE_AIR);

return false;
}

HitResult LeverTile::clip(Level* level, int x, int y, int z, Vec3 a, Vec3 b)
{
constexpr float f = 0.1875f;
constexpr float f1 = 0.25f;

switch (level->getData(x, y, z) & 0x7)
{
case 1:
setShape(0.0f, 0.2f, 0.5f - f, f * 2.0f, 0.8f, 0.5f + f);
break;
case 2:
setShape(1.0f - f * 2.0f, 0.2f, 0.5f - f, 1.0f, 0.8f, 0.5f + f);
break;
case 3:
setShape(0.5f - f, 0.2f, 0.0f, 0.5f + f, 0.8f, f * 2.0f);
break;
case 4:
setShape(0.5f - f, 0.2f, 1.0f - f * 2.0f, 0.5f + f, 0.8f, 1.0f);
break;
default:
setShape(0.5f - f1, 0.0f, 0.5f - f1, 0.5f + f1, 0.6f, 0.5f + f1);
break;
}

return Tile::clip(level, x, y, z, a, b);
}

bool LeverTile::mayPlace(Level* level, int x, int y, int z)
{
if (level->isSolidTile(x, y - 1, z)) return true;
if (level->isSolidTile(x - 1, y, z)) return true;
if (level->isSolidTile(x + 1, y, z)) return true;
if (level->isSolidTile(x, y, z - 1)) return true;
if (level->isSolidTile(x, y, z + 1)) return true;

return false;
}

void LeverTile::neighborChanged(Level* level, int x, int y, int z, int dir)
{
if (!checkCanSurvive(level, x, y, z))
return;

int data = level->getData(x, y, z) & 0x7;

bool flag = false;
if (!level->isSolidTile(x - 1, y, z) && data == 1) flag = true;
if (!level->isSolidTile(x + 1, y, z) && data == 2) flag = true;
if (!level->isSolidTile(x, y, z - 1) && data == 3) flag = true;
if (!level->isSolidTile(x, y, z + 1) && data == 4) flag = true;
if (!level->isSolidTile(x, y - 1, z) && data == 5) flag = true;
if (!level->isSolidTile(x, y - 1, z) && data == 6) flag = true;

if (!flag)
return; // all good

spawnResources(level, x, y, z, level->getData(x, y, z));
level->setTile(x, y, z, TILE_AIR);
}

void LeverTile::onPlace(Level* level, int x, int y, int z)
{
if (level->isSolidTile(x - 1, y, z))
level->setData(x, y, z, 1);
else if (level->isSolidTile(x + 1, y, z))
level->setData(x, y, z, 2);
else if (level->isSolidTile(x, y, z - 1))
level->setData(x, y, z, 3);
else if (level->isSolidTile(x, y, z + 1))
level->setData(x, y, z, 4);
else if (level->isSolidTile(x, y - 1, z))
level->setData(x, y, z, 5);

checkCanSurvive(level, x, y, z);
}

void LeverTile::setPlacedOnFace(Level* level, int x, int y, int z, int dir)
{
int data = level->getData(x, y, z);
int bit3 = data & 0x8;
data = -1;

switch (dir)
{
case DIR_YPOS:
if (level->isSolidTile(x, y - 1, z))
data = 5; // TODO: +level->m_random.nextInt(2)
break;
case DIR_ZNEG:
if (level->isSolidTile(x, y, z + 1))
data = 4;
break;
case DIR_ZPOS:
if (level->isSolidTile(x, y, z - 1))
data = 3;
break;
case DIR_XNEG:
if (level->isSolidTile(x + 1, y, z))
data = 2;
break;
case DIR_XPOS:
if (level->isSolidTile(x - 1, y, z))
data = 1;
break;
}

if (data == -1)
{
spawnResources(level, x, y, z, level->getData(x, y, z));
level->setTile(x, y, z, TILE_AIR);
return;
}

level->setData(x, y, z, data | bit3);
}

int LeverTile::use(Level* pLevel, int x, int y, int z, Player* player)
{
if (pLevel->m_bIsMultiplayer)
return true;

int data = pLevel->getData(x, y, z);
data ^= 0x8;
pLevel->setData(x, y, z, data);
pLevel->setTilesDirty(x, y, z, x, y, z);
pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "random.click", 0.3f, (data & 0x8) ? 0.6f : 0.5f);
pLevel->updateNeighborsAt(x, y, z, m_ID);

switch (data & 0x7)
{
case 1: pLevel->updateNeighborsAt(x - 1, y, z, m_ID); break;
case 2: pLevel->updateNeighborsAt(x + 1, y, z, m_ID); break;
case 3: pLevel->updateNeighborsAt(x, y, z - 1, m_ID); break;
case 4: pLevel->updateNeighborsAt(x, y, z + 1, m_ID); break;
default: pLevel->updateNeighborsAt(x, y - 1, z, m_ID); break;
}

return true;
}

void LeverTile::destroy(Level* pLevel, int x, int y, int z, int dir)
{
int data = pLevel->getData(x, y, z);
if (~data & 0x8)
{
Tile::destroy(pLevel, x, y, z, dir);
return;
}

pLevel->updateNeighborsAt(x, y, z, m_ID);

switch (data & 0x7)
{
case 1: pLevel->updateNeighborsAt(x - 1, y, z, m_ID); break;
case 2: pLevel->updateNeighborsAt(x + 1, y, z, m_ID); break;
case 3: pLevel->updateNeighborsAt(x, y, z - 1, m_ID); break;
case 4: pLevel->updateNeighborsAt(x, y, z + 1, m_ID); break;
default: pLevel->updateNeighborsAt(x, y - 1, z, m_ID); break;
}

Tile::destroy(pLevel, x, y, z, dir);
}

// TODO FIXME:
// In Minecraft JE Beta 1.6.4, WireTile::getDirectSignal is `isPoweringTo` and
// WireTile::getSignal is `isIndirectlyPoweringTo`.
//
// Meanwhile I had to reverse them, so LeverTile::getDirectSignal is actually
// `isIndirectlyPoweringTo` and vice versa...

int LeverTile::getDirectSignal(LevelSource* pLevel, int x, int y, int z, int dir)
{
int data = pLevel->getData(x, y, z);
if (~data & 0x8)
return false;

switch (data & 0x7)
{
case 1: return dir == DIR_XPOS;
case 2: return dir == DIR_XNEG;
case 3: return dir == DIR_ZPOS;
case 4: return dir == DIR_ZNEG;
case 5:
case 6: return dir == DIR_YPOS;
}

return false;
}

int LeverTile::getSignal(LevelSource* pLevel, int x, int y, int z, int dir)
{
int data = pLevel->getData(x, y, z);
return (data & 0x8) != 0;
}

bool LeverTile::isSignalSource()
{
return true;
}
34 changes: 34 additions & 0 deletions source/world/tile/LeverTile.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/********************************************************************
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
********************************************************************/

#pragma once

#include "Tile.hpp"

class LeverTile : public Tile
{
public:
LeverTile(int ID, int texture, Material* pMtl);

AABB* getAABB(Level*, int x, int y, int z) override;
bool isSolidRender() override;
bool isCubeShaped() override;
int getRenderShape() override;
HitResult clip(Level*, int x, int y, int z, Vec3 a, Vec3 b) override;
bool mayPlace(Level*, int, int, int) override;
void neighborChanged(Level*, int, int, int, int) override;
void onPlace(Level*, int, int, int) override;
void setPlacedOnFace(Level*, int, int, int, int) override;
int use(Level* pLevel, int x, int y, int z, Player* player) override;
void destroy(Level*, int, int, int, int dir) override;
int getSignal(LevelSource*, int x, int y, int z, int dir) override;
int getDirectSignal(LevelSource*, int x, int y, int z, int dir) override;
bool isSignalSource() override;

bool checkCanSurvive(Level*, int x, int y, int z);
};
9 changes: 8 additions & 1 deletion source/world/tile/Tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "RocketLauncherTile.hpp"
#include "WireTile.hpp"
#include "RedStoneTorchTile.hpp"
#include "LeverTile.hpp"

std::string Tile::TILE_DESCRIPTION_PREFIX = "tile.";

Expand Down Expand Up @@ -708,7 +709,7 @@ void Tile::initTiles()
Tile::wire = (new WireTile(TILE_WIRE))
->init()
->setDestroyTime(0.0f)
->setSoundType(Tile::SOUND_STONE)
->setSoundType(Tile::SOUND_NORMAL)
->setDescriptionId("wire");

Tile::notGate_off = (new RedStoneTorchTile(TILE_NOT_GATE_OFF, TEXTURE_TORCH_RED_STONE_OFF, Material::decoration))
Expand All @@ -723,6 +724,12 @@ void Tile::initTiles()
->setSoundType(Tile::SOUND_WOOD)
->setDescriptionId("notGateLit");

Tile::lever = (new LeverTile(TILE_LEVER, TEXTURE_LEVER, Material::decoration))
->init()
->setDestroyTime(0.0f)
->setSoundType(Tile::SOUND_WOOD)
->setDescriptionId("lever");

for (int i = 0; i < C_MAX_TILES; i++)
{
if (Tile::tiles[i])
Expand Down
6 changes: 5 additions & 1 deletion source/world/tile/WireTile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@

// HACK HACK HACK: This is crap

// Include the C++ source directly, because Apple made it purposely
// Include other C++ sources directly, because Apple made it purposely
// difficult to add more source files by modifying the PBXPROJ. I
// have to allocate GUIDs and .. ugh, it's a pain. Apple can suck
// a big, fat one.
//
// Brent, please help. I don't want to merge it into master like this.
#include "RedStoneTorchTile.cpp"
#include "LeverTile.cpp"

#endif

Expand Down Expand Up @@ -354,6 +355,9 @@ int WireTile::getDirectSignal(LevelSource* level, int x, int y, int z, int dir)
if (level->getData(x, y, z) == 0)
return 0;

if (dir == DIR_YPOS)
return true;

bool flag0 = isSignalSource(level, x - 1, y, z) || !level->isSolidTile(x - 1, y, z) && isSignalSource(level, x - 1, y - 1, z);
bool flag1 = isSignalSource(level, x + 1, y, z) || !level->isSolidTile(x + 1, y, z) && isSignalSource(level, x + 1, y - 1, z);
bool flag2 = isSignalSource(level, x, y, z - 1) || !level->isSolidTile(x, y, z - 1) && isSignalSource(level, x, y - 1, z - 1);
Expand Down

0 comments on commit 08ada94

Please sign in to comment.