4jcraft/targets/minecraft/world/level/tile/entity/BeaconTileEntity.cpp

315 lines
9.6 KiB
C++

#include "minecraft/IGameServices.h"
#include "BeaconTileEntity.h"
#include <format>
#include <vector>
#include "app/linux/LinuxGame.h"
#include "SharedConstants.h"
#include "minecraft/network/packet/TileEntityDataPacket.h"
#include "minecraft/world/effect/MobEffect.h"
#include "minecraft/world/effect/MobEffectInstance.h"
#include "minecraft/world/entity/player/Player.h"
#include "minecraft/world/item/Item.h"
#include "minecraft/world/item/ItemInstance.h"
#include "minecraft/world/level/Level.h"
#include "minecraft/world/level/tile/Tile.h"
#include "minecraft/world/level/tile/entity/TileEntity.h"
#include "minecraft/world/phys/AABB.h"
#include "nbt/CompoundTag.h"
#include "strings.h"
class Entity;
std::shared_ptr<TileEntity> BeaconTileEntity::clone() {
std::shared_ptr<BeaconTileEntity> result =
std::make_shared<BeaconTileEntity>();
TileEntity::clone(result);
result->primaryPower = primaryPower;
result->secondaryPower = secondaryPower;
result->levels = levels;
return result;
}
MobEffect*
BeaconTileEntity::BEACON_EFFECTS[BeaconTileEntity::BEACON_EFFECTS_TIERS]
[BeaconTileEntity::BEACON_EFFECTS_EFFECTS];
void BeaconTileEntity::staticCtor() {
for (unsigned int tier = 0; tier < BEACON_EFFECTS_TIERS; ++tier) {
for (unsigned int effect = 0; effect < BEACON_EFFECTS_EFFECTS;
++effect) {
BEACON_EFFECTS[tier][effect] = nullptr;
}
}
BEACON_EFFECTS[0][0] = MobEffect::movementSpeed;
BEACON_EFFECTS[0][1] = MobEffect::digSpeed;
BEACON_EFFECTS[1][0] = MobEffect::damageResistance;
BEACON_EFFECTS[1][1] = MobEffect::jump;
BEACON_EFFECTS[2][0] = MobEffect::damageBoost;
BEACON_EFFECTS[3][0] = MobEffect::regeneration;
}
BeaconTileEntity::BeaconTileEntity() {
clientSideRenderTick = 0;
clientSideRenderScale = 0.0f;
isActive = false;
levels = -1;
primaryPower = 0;
secondaryPower = 0;
paymentItem = nullptr;
name = "";
}
void BeaconTileEntity::tick() {
// 4J Stu - Added levels check to force an initial tick
if ((!level->isClientSide && levels < 0) ||
(level->getGameTime() % (SharedConstants::TICKS_PER_SECOND * 4)) == 0) {
updateShape();
applyEffects();
}
}
void BeaconTileEntity::applyEffects() {
if (isActive && levels > 0 && !level->isClientSide && primaryPower > 0) {
double range = (levels * 10) + 10;
int baseAmp = 0;
if (levels >= 4 && primaryPower == secondaryPower) {
baseAmp = 1;
}
AABB bb = AABB(x, y, z, x + 1, y + 1, z + 1).grow(range, range, range);
bb.y1 = level->getMaxBuildHeight();
std::vector<std::shared_ptr<Entity> >* players =
level->getEntitiesOfClass(typeid(Player), &bb);
for (auto it = players->begin(); it != players->end(); ++it) {
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(*it);
player->addEffect(new MobEffectInstance(
primaryPower, SharedConstants::TICKS_PER_SECOND * 9, baseAmp,
true));
}
if (levels >= 4 && primaryPower != secondaryPower &&
secondaryPower > 0) {
for (auto it = players->begin(); it != players->end(); ++it) {
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(*it);
player->addEffect(new MobEffectInstance(
secondaryPower, SharedConstants::TICKS_PER_SECOND * 9, 0,
true));
}
}
delete players;
}
}
void BeaconTileEntity::updateShape() {
if (!level->canSeeSky(x, y + 1, z)) {
isActive = false;
levels = 0;
} else {
isActive = true;
levels = 0;
for (int step = 1; step <= 4; step++) {
int ly = y - step;
if (ly < 0) {
break;
}
bool isOk = true;
for (int lx = x - step; lx <= x + step && isOk; lx++) {
for (int lz = z - step; lz <= z + step; lz++) {
int tile = level->getTile(lx, ly, lz);
if (tile != Tile::emeraldBlock_Id &&
tile != Tile::goldBlock_Id &&
tile != Tile::diamondBlock_Id &&
tile != Tile::ironBlock_Id) {
isOk = false;
break;
}
}
}
if (isOk) {
levels = step;
} else {
break;
}
}
if (levels == 0) {
isActive = false;
}
}
}
float BeaconTileEntity::getAndUpdateClientSideScale() {
if (!isActive) {
return 0;
}
int renderDelta = (int)(level->getGameTime() - clientSideRenderTick);
clientSideRenderTick = level->getGameTime();
if (renderDelta > 1) {
clientSideRenderScale -= ((float)renderDelta / (float)SCALE_TIME);
if (clientSideRenderScale < 0) {
clientSideRenderScale = 0;
}
}
clientSideRenderScale += (1.0f / (float)SCALE_TIME);
if (clientSideRenderScale > 1) {
clientSideRenderScale = 1;
}
return clientSideRenderScale;
}
int BeaconTileEntity::getPrimaryPower() { return primaryPower; }
int BeaconTileEntity::getSecondaryPower() { return secondaryPower; }
int BeaconTileEntity::getLevels() { return levels; }
// client-side method used by GUI
void BeaconTileEntity::setLevels(int levels) { this->levels = levels; }
void BeaconTileEntity::setPrimaryPower(int primaryPower) {
this->primaryPower = 0;
// verify power
for (int tier = 0; tier < levels && tier < 3; tier++) {
for (unsigned int e = 0; e < BEACON_EFFECTS_EFFECTS; ++e) {
MobEffect* effect = BEACON_EFFECTS[tier][e];
if (effect == nullptr) break;
if (effect->id == primaryPower) {
this->primaryPower = primaryPower;
return;
}
}
}
}
void BeaconTileEntity::setSecondaryPower(int secondaryPower) {
this->secondaryPower = 0;
// verify power
if (levels >= 4) {
for (int tier = 0; tier < 4; tier++) {
for (unsigned int e = 0; e < BEACON_EFFECTS_EFFECTS; ++e) {
MobEffect* effect = BEACON_EFFECTS[tier][e];
if (effect == nullptr) break;
if (effect->id == secondaryPower) {
this->secondaryPower = secondaryPower;
return;
}
}
}
}
}
std::shared_ptr<Packet> BeaconTileEntity::getUpdatePacket() {
CompoundTag* tag = new CompoundTag();
save(tag);
return std::make_shared<TileEntityDataPacket>(
x, y, z, TileEntityDataPacket::TYPE_BEACON, tag);
}
double BeaconTileEntity::getViewDistance() { return 256 * 256; }
void BeaconTileEntity::load(CompoundTag* tag) {
TileEntity::load(tag);
primaryPower = tag->getInt("Primary");
secondaryPower = tag->getInt("Secondary");
levels = tag->getInt("Levels");
}
void BeaconTileEntity::save(CompoundTag* tag) {
TileEntity::save(tag);
tag->putInt("Primary", primaryPower);
tag->putInt("Secondary", secondaryPower);
// this value is re-calculated, but save it anyway to avoid update lag
tag->putInt("Levels", levels);
}
unsigned int BeaconTileEntity::getContainerSize() { return 1; }
std::shared_ptr<ItemInstance> BeaconTileEntity::getItem(unsigned int slot) {
if (slot == 0) {
return paymentItem;
}
return nullptr;
}
std::shared_ptr<ItemInstance> BeaconTileEntity::removeItem(unsigned int slot,
int count) {
if (slot == 0 && paymentItem != nullptr) {
if (count >= paymentItem->count) {
std::shared_ptr<ItemInstance> returnItem = paymentItem;
paymentItem = nullptr;
return returnItem;
} else {
paymentItem->count -= count;
return std::make_shared<ItemInstance>(paymentItem->id, count,
paymentItem->getAuxValue());
}
}
return nullptr;
}
std::shared_ptr<ItemInstance> BeaconTileEntity::removeItemNoUpdate(int slot) {
if (slot == 0 && paymentItem != nullptr) {
std::shared_ptr<ItemInstance> returnItem = paymentItem;
paymentItem = nullptr;
return returnItem;
}
return nullptr;
}
void BeaconTileEntity::setItem(unsigned int slot,
std::shared_ptr<ItemInstance> item) {
if (slot == 0) {
paymentItem = item;
}
}
std::string BeaconTileEntity::getName() {
return hasCustomName() ? name : gameServices().getString(IDS_CONTAINER_BEACON);
}
std::string BeaconTileEntity::getCustomName() {
return hasCustomName() ? name : "";
}
bool BeaconTileEntity::hasCustomName() { return !name.empty(); }
void BeaconTileEntity::setCustomName(const std::string& name) {
this->name = name;
}
int BeaconTileEntity::getMaxStackSize() { return 1; }
bool BeaconTileEntity::stillValid(std::shared_ptr<Player> player) {
if (level->getTileEntity(x, y, z) != shared_from_this()) return false;
if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false;
return true;
}
void BeaconTileEntity::startOpen() {}
void BeaconTileEntity::stopOpen() {}
bool BeaconTileEntity::canPlaceItem(int slot,
std::shared_ptr<ItemInstance> item) {
return (item->id == Item::emerald_Id || item->id == Item::diamond_Id ||
item->id == Item::goldIngot_Id || item->id == Item::ironIngot_Id);
}