4jcraft/Minecraft.World/Blocks/RedStoneDustTile.cpp

440 lines
16 KiB
C++

#include "../Platform/stdafx.h"
#include "../../Minecraft.Client/Minecraft.h"
#include "RedStoneDustTile.h"
#include <cstddef>
#include <optional>
#include "../Headers/net.minecraft.world.item.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.level.redstone.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "../Headers/net.minecraft.world.h"
#include "../Headers/net.minecraft.h"
#include "../Util/Direction.h"
#include "DiodeTile.h"
#include "Util/AABB.h"
// AP - added for Vita to set Alpha Cut out
#include "../IO/Streams/IntBuffer.h"
#include "../../Minecraft.Client/Rendering/Tesselator.h"
const std::wstring RedStoneDustTile::TEXTURE_CROSS = L"_cross";
const std::wstring RedStoneDustTile::TEXTURE_LINE = L"_line";
const std::wstring RedStoneDustTile::TEXTURE_CROSS_OVERLAY = L"_cross_overlay";
const std::wstring RedStoneDustTile::TEXTURE_LINE_OVERLAY = L"_line_overlay";
RedStoneDustTile::RedStoneDustTile(int id)
: Tile(id, Material::decoration, false) {
shouldSignal = true;
updateDefaultShape();
iconCross = NULL;
iconLine = NULL;
iconCrossOver = NULL;
iconLineOver = NULL;
}
// 4J Added override
void RedStoneDustTile::updateDefaultShape() {
setShape(0, 0, 0, 1, 1 / 16.0f, 1);
}
std::optional<AABB> RedStoneDustTile::getAABB(Level* level, int x, int y,
int z) {
return std::nullopt;
}
bool RedStoneDustTile::isSolidRender(bool isServerLevel) { return false; }
bool RedStoneDustTile::isCubeShaped() { return false; }
int RedStoneDustTile::getRenderShape() { return Tile::SHAPE_RED_DUST; }
int RedStoneDustTile::getColor() const {
return Minecraft::GetInstance()->getColourTable()->getColor(
eMinecraftColour_Tile_RedstoneDust); // 0x800000;
}
int RedStoneDustTile::getColor(LevelSource* level, int x, int y, int z) {
return Minecraft::GetInstance()->getColourTable()->getColor(
eMinecraftColour_Tile_RedstoneDust); // 0x800000;
}
int RedStoneDustTile::getColor(LevelSource* level, int x, int y, int z,
int data) {
return Minecraft::GetInstance()->getColourTable()->getColor(
eMinecraftColour_Tile_RedstoneDust); // 0x800000;
}
bool RedStoneDustTile::mayPlace(Level* level, int x, int y, int z) {
return level->isTopSolidBlocking(x, y - 1, z) ||
level->getTile(x, y - 1, z) == Tile::glowstone_Id;
}
void RedStoneDustTile::updatePowerStrength(Level* level, int x, int y, int z) {
updatePowerStrength(level, x, y, z, x, y, z);
std::vector<TilePos> updates =
std::vector<TilePos>(toUpdate.begin(), toUpdate.end());
toUpdate.clear();
AUTO_VAR(itEnd, updates.end());
for (AUTO_VAR(it, updates.begin()); it != itEnd; it++) {
TilePos tp = *it;
level->updateNeighborsAt(tp.x, tp.y, tp.z, id);
}
}
void RedStoneDustTile::updatePowerStrength(Level* level, int x, int y, int z,
int xFrom, int yFrom, int zFrom) {
int old = level->getData(x, y, z);
int target = 0;
target = checkTarget(level, xFrom, yFrom, zFrom, target);
shouldSignal = false;
int neighborSignal = level->getBestNeighborSignal(x, y, z);
shouldSignal = true;
if (neighborSignal > Redstone::SIGNAL_NONE && neighborSignal > target - 1) {
target = neighborSignal;
}
{
int newTarget = 0;
for (int i = 0; i < 4; i++) {
int xt = x;
int zt = z;
if (i == 0) xt--;
if (i == 1) xt++;
if (i == 2) zt--;
if (i == 3) zt++;
if (xt != xFrom || zt != zFrom)
newTarget = checkTarget(level, xt, y, zt, newTarget);
if (level->isSolidBlockingTile(xt, y, zt) &&
!level->isSolidBlockingTile(x, y + 1, z)) {
if ((xt != xFrom || zt != zFrom) && y >= yFrom)
newTarget = checkTarget(level, xt, y + 1, zt, newTarget);
} else if (!level->isSolidBlockingTile(xt, y, zt)) {
if ((xt != xFrom || zt != zFrom) && y <= yFrom)
newTarget = checkTarget(level, xt, y - 1, zt, newTarget);
}
}
if (newTarget > target)
target = newTarget - 1;
else if (target > 0)
target--;
else
target = 0;
if (neighborSignal > target - 1) {
target = neighborSignal;
}
}
if (old != target) {
level->setData(x, y, z, target, Tile::UPDATE_CLIENTS);
{
toUpdate.insert(TilePos(x, y, z));
toUpdate.insert(TilePos(x - 1, y, z));
toUpdate.insert(TilePos(x + 1, y, z));
toUpdate.insert(TilePos(x, y - 1, z));
toUpdate.insert(TilePos(x, y + 1, z));
toUpdate.insert(TilePos(x, y, z - 1));
toUpdate.insert(TilePos(x, y, z + 1));
}
}
}
void RedStoneDustTile::checkCornerChangeAt(Level* level, int x, int y, int z) {
if (level->getTile(x, y, z) != id) return;
level->updateNeighborsAt(x, y, z, id);
level->updateNeighborsAt(x - 1, y, z, id);
level->updateNeighborsAt(x + 1, y, z, id);
level->updateNeighborsAt(x, y, z - 1, id);
level->updateNeighborsAt(x, y, z + 1, id);
level->updateNeighborsAt(x, y - 1, z, id);
level->updateNeighborsAt(x, y + 1, z, id);
}
void RedStoneDustTile::onPlace(Level* level, int x, int y, int z) {
Tile::onPlace(level, x, y, z);
if (level->isClientSide) return;
updatePowerStrength(level, x, y, z);
level->updateNeighborsAt(x, y + 1, z, id);
level->updateNeighborsAt(x, y - 1, z, id);
checkCornerChangeAt(level, x - 1, y, z);
checkCornerChangeAt(level, x + 1, y, z);
checkCornerChangeAt(level, x, y, z - 1);
checkCornerChangeAt(level, x, y, z + 1);
if (level->isSolidBlockingTile(x - 1, y, z))
checkCornerChangeAt(level, x - 1, y + 1, z);
else
checkCornerChangeAt(level, x - 1, y - 1, z);
if (level->isSolidBlockingTile(x + 1, y, z))
checkCornerChangeAt(level, x + 1, y + 1, z);
else
checkCornerChangeAt(level, x + 1, y - 1, z);
if (level->isSolidBlockingTile(x, y, z - 1))
checkCornerChangeAt(level, x, y + 1, z - 1);
else
checkCornerChangeAt(level, x, y - 1, z - 1);
if (level->isSolidBlockingTile(x, y, z + 1))
checkCornerChangeAt(level, x, y + 1, z + 1);
else
checkCornerChangeAt(level, x, y - 1, z + 1);
}
void RedStoneDustTile::onRemove(Level* level, int x, int y, int z, int id,
int data) {
Tile::onRemove(level, x, y, z, id, data);
if (level->isClientSide) return;
level->updateNeighborsAt(x, y + 1, z, this->id);
level->updateNeighborsAt(x, y - 1, z, this->id);
level->updateNeighborsAt(x + 1, y, z, this->id);
level->updateNeighborsAt(x - 1, y, z, this->id);
level->updateNeighborsAt(x, y, z + 1, this->id);
level->updateNeighborsAt(x, y, z - 1, this->id);
updatePowerStrength(level, x, y, z);
checkCornerChangeAt(level, x - 1, y, z);
checkCornerChangeAt(level, x + 1, y, z);
checkCornerChangeAt(level, x, y, z - 1);
checkCornerChangeAt(level, x, y, z + 1);
if (level->isSolidBlockingTile(x - 1, y, z))
checkCornerChangeAt(level, x - 1, y + 1, z);
else
checkCornerChangeAt(level, x - 1, y - 1, z);
if (level->isSolidBlockingTile(x + 1, y, z))
checkCornerChangeAt(level, x + 1, y + 1, z);
else
checkCornerChangeAt(level, x + 1, y - 1, z);
if (level->isSolidBlockingTile(x, y, z - 1))
checkCornerChangeAt(level, x, y + 1, z - 1);
else
checkCornerChangeAt(level, x, y - 1, z - 1);
if (level->isSolidBlockingTile(x, y, z + 1))
checkCornerChangeAt(level, x, y + 1, z + 1);
else
checkCornerChangeAt(level, x, y - 1, z + 1);
}
int RedStoneDustTile::checkTarget(Level* level, int x, int y, int z,
int target) {
if (level->getTile(x, y, z) != id) return target;
int d = level->getData(x, y, z);
if (d > target) return d;
return target;
}
void RedStoneDustTile::neighborChanged(Level* level, int x, int y, int z,
int type) {
if (level->isClientSide) return;
bool ok = mayPlace(level, x, y, z);
if (ok) {
updatePowerStrength(level, x, y, z);
} else {
spawnResources(level, x, y, z, 0, 0);
level->removeTile(x, y, z);
}
Tile::neighborChanged(level, x, y, z, type);
}
int RedStoneDustTile::getResource(int data, Random* random,
int playerBonusLevel) {
return Item::redStone->id;
}
int RedStoneDustTile::getDirectSignal(LevelSource* level, int x, int y, int z,
int dir) {
if (!shouldSignal) return Redstone::SIGNAL_NONE;
return getSignal(level, x, y, z, dir);
}
int RedStoneDustTile::getSignal(LevelSource* level, int x, int y, int z,
int dir) {
if (!shouldSignal) return Redstone::SIGNAL_NONE;
int data = level->getData(x, y, z);
if (data == Facing::DOWN) {
return Redstone::SIGNAL_NONE;
}
if (dir == Facing::UP) return data;
bool w =
shouldReceivePowerFrom(level, x - 1, y, z, Direction::WEST) ||
(!level->isSolidBlockingTile(x - 1, y, z) &&
shouldReceivePowerFrom(level, x - 1, y - 1, z, Direction::UNDEFINED));
bool e =
shouldReceivePowerFrom(level, x + 1, y, z, Direction::EAST) ||
(!level->isSolidBlockingTile(x + 1, y, z) &&
shouldReceivePowerFrom(level, x + 1, y - 1, z, Direction::UNDEFINED));
bool n =
shouldReceivePowerFrom(level, x, y, z - 1, Direction::NORTH) ||
(!level->isSolidBlockingTile(x, y, z - 1) &&
shouldReceivePowerFrom(level, x, y - 1, z - 1, Direction::UNDEFINED));
bool s =
shouldReceivePowerFrom(level, x, y, z + 1, Direction::SOUTH) ||
(!level->isSolidBlockingTile(x, y, z + 1) &&
shouldReceivePowerFrom(level, x, y - 1, z + 1, Direction::UNDEFINED));
if (!level->isSolidBlockingTile(x, y + 1, z)) {
if (level->isSolidBlockingTile(x - 1, y, z) &&
shouldReceivePowerFrom(level, x - 1, y + 1, z,
Direction::UNDEFINED))
w = true;
if (level->isSolidBlockingTile(x + 1, y, z) &&
shouldReceivePowerFrom(level, x + 1, y + 1, z,
Direction::UNDEFINED))
e = true;
if (level->isSolidBlockingTile(x, y, z - 1) &&
shouldReceivePowerFrom(level, x, y + 1, z - 1,
Direction::UNDEFINED))
n = true;
if (level->isSolidBlockingTile(x, y, z + 1) &&
shouldReceivePowerFrom(level, x, y + 1, z + 1,
Direction::UNDEFINED))
s = true;
}
if (!n && !e && !w && !s && (dir >= 2 && dir <= 5)) return data;
if (dir == 2 && n && (!w && !e)) return data;
if (dir == 3 && s && (!w && !e)) return data;
if (dir == 4 && w && (!n && !s)) return data;
if (dir == 5 && e && (!n && !s)) return data;
return Redstone::SIGNAL_NONE;
}
bool RedStoneDustTile::isSignalSource() { return shouldSignal; }
void RedStoneDustTile::animateTick(Level* level, int x, int y, int z,
Random* random) {
int data = level->getData(x, y, z);
if (data > 0) {
double xx = x + 0.5 + (random->nextFloat() - 0.5) * 0.2;
double yy = y + 1 / 16.0f;
double zz = z + 0.5 + (random->nextFloat() - 0.5) * 0.2;
// use the x movement variable to determine particle color
// 4J Stu - Unused
// float pow = (data / 15.0f);
// float red = pow * 0.6f + 0.4f;
// if (data == 0) red = 0;
// float green = pow * pow * 0.7f - 0.5f;
// float blue = pow * pow * 0.6f - 0.7f;
// if (green < 0) green = 0;
// if (blue < 0) blue = 0;
unsigned int colour = 0;
if (data == 0) {
colour = Minecraft::GetInstance()->getColourTable()->getColor(
eMinecraftColour_Tile_RedstoneDustUnlit);
} else {
unsigned int minColour =
Minecraft::GetInstance()->getColourTable()->getColor(
eMinecraftColour_Tile_RedstoneDustLitMin);
unsigned int maxColour =
Minecraft::GetInstance()->getColourTable()->getColor(
eMinecraftColour_Tile_RedstoneDustLitMax);
uint8_t redComponent =
((minColour >> 16) & 0xFF) +
(((maxColour >> 16) & 0xFF - (minColour >> 16) & 0xFF) *
((data - 1) / 14.0f));
uint8_t greenComponent =
((minColour >> 8) & 0xFF) +
(((maxColour >> 8) & 0xFF - (minColour >> 8) & 0xFF) *
((data - 1) / 14.0f));
uint8_t blueComponent = ((minColour) & 0xFF) +
(((maxColour) & 0xFF - (minColour) & 0xFF) *
((data - 1) / 14.0f));
colour = redComponent << 16 | greenComponent << 8 | blueComponent;
}
float red = ((colour >> 16) & 0xFF) / 255.0f;
float green = ((colour >> 8) & 0xFF) / 255.0f;
float blue = (colour & 0xFF) / 255.0f;
level->addParticle(eParticleType_reddust, xx, yy, zz, red, green, blue);
}
}
bool RedStoneDustTile::shouldConnectTo(LevelSource* level, int x, int y, int z,
int direction) {
int t = level->getTile(x, y, z);
if (t == Tile::redStoneDust_Id) return true;
if (t == 0) return false;
if (Tile::diode_off->isSameDiode(t)) {
int data = level->getData(x, y, z);
return direction == (data & DiodeTile::DIRECTION_MASK) ||
direction ==
Direction::DIRECTION_OPPOSITE[data &
DiodeTile::DIRECTION_MASK];
} else if (Tile::tiles[t]->isSignalSource() &&
direction != Direction::UNDEFINED)
return true;
return false;
}
bool RedStoneDustTile::shouldReceivePowerFrom(LevelSource* level, int x, int y,
int z, int direction) {
if (shouldConnectTo(level, x, y, z, direction)) {
return true;
}
int t = level->getTile(x, y, z);
if (t == Tile::diode_on_Id) {
int data = level->getData(x, y, z);
return direction == (data & DiodeTile::DIRECTION_MASK);
}
return false;
}
int RedStoneDustTile::cloneTileId(Level* level, int x, int y, int z) {
return Item::redStone_Id;
}
void RedStoneDustTile::registerIcons(IconRegister* iconRegister) {
iconCross = iconRegister->registerIcon(getIconName() + TEXTURE_CROSS);
iconLine = iconRegister->registerIcon(getIconName() + TEXTURE_LINE);
iconCrossOver =
iconRegister->registerIcon(getIconName() + TEXTURE_CROSS_OVERLAY);
iconLineOver =
iconRegister->registerIcon(getIconName() + TEXTURE_LINE_OVERLAY);
icon = iconCross;
}
Icon* RedStoneDustTile::getTexture(const std::wstring& name) {
#ifdef __PSVITA__
// AP - alpha cut out is expensive on vita. Set the Alpha Cut out flag
Tesselator* t = Tesselator::getInstance();
t->setAlphaCutOut(true);
#endif
if (name.compare(TEXTURE_CROSS) == 0) return Tile::redStoneDust->iconCross;
if (name.compare(TEXTURE_LINE) == 0) return Tile::redStoneDust->iconLine;
if (name.compare(TEXTURE_CROSS_OVERLAY) == 0)
return Tile::redStoneDust->iconCrossOver;
if (name.compare(TEXTURE_LINE_OVERLAY) == 0)
return Tile::redStoneDust->iconLineOver;
return NULL;
}