Files
LegacyRenouveau/Minecraft.World/JukeboxTile.cpp
T
Anaël d8d65bcd49 game loop: Refactor the tooltips loop
Moved the whole logic to a new file (TooltipManager.cpp), and rewrote most of the logic to profit from object oriented programming. The side-effect is that the changes are scattered across entities, tiles and items because moving everything to OOP requires to add the tooltip to every .cpp file for every tile/item/entities (or their class, on plants for example which all use the tooltip IDS_TOOLTIPS_PLANT)

The issue with the default tooltips loop written by 4J is that:

    Its running in the main Minecraft::tick loop and is more than a thousand lines long, polluting the function.
    Not using C++'s full potential with object oriented programming, 4J decided to use a big switch case (probably because it could run better on hardware without branch prediction like the WiiU or Xbox 360 ?)
    And seems to be better off in its own file than in the main Minecraft.cpp file
2026-10-04 20:54:24 +02:00

223 lines
6.0 KiB
C++

#include "stdafx.h"
#include "net.minecraft.world.level.redstone.h"
#include "net.minecraft.world.entity.item.h"
#include "net.minecraft.world.item.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.h"
#include "net.minecraft.world.h"
#include "net.minecraft.world.entity.player.h"
#include "JukeboxTile.h"
#include "LevelEvent.h"
JukeboxTile::Entity::Entity() : TileEntity()
{
record = nullptr;
}
void JukeboxTile::Entity::load(CompoundTag *tag)
{
TileEntity::load(tag);
if (tag->contains(L"RecordItem"))
{
setRecord(ItemInstance::fromTag(tag->getCompound(L"RecordItem")));
}
else if (tag->getInt(L"Record") > 0)
{
setRecord(std::make_shared<ItemInstance>(tag->getInt(L"Record"), 1, 0));
}
}
void JukeboxTile::Entity::save(CompoundTag *tag)
{
TileEntity::save(tag);
if (getRecord() != nullptr)
{
tag->putCompound(L"RecordItem", getRecord()->save(new CompoundTag()));
tag->putInt(L"Record", getRecord()->id);
}
}
// 4J Added
shared_ptr<TileEntity> JukeboxTile::Entity::clone()
{
shared_ptr<JukeboxTile::Entity> result = std::make_shared<JukeboxTile::Entity>();
TileEntity::clone(result);
result->record = record;
return result;
}
shared_ptr<ItemInstance> JukeboxTile::Entity::getRecord()
{
return record;
}
void JukeboxTile::Entity::setRecord(shared_ptr<ItemInstance> record)
{
this->record = record;
setChanged();
}
JukeboxTile::JukeboxTile(int id) : BaseEntityTile(id, Material::wood)
{
iconTop = nullptr;
}
void JukeboxTile::createBlockStateDefinition()
{
if (!m_blockStateDefinition)
m_blockStateDefinition = new BlockStateDefinition(this);
}
int JukeboxTile::defaultBlockState()
{
return 0;
}
int JukeboxTile::convertBlockStateToLegacyData(BlockState *state)
{
return state ? (state->value & 0x1) : 0;
}
Tile::BlockState JukeboxTile::getBlockState(int data)
{
return Tile::BlockState(data & 0x1);
}
Tile::BlockState JukeboxTile::getBlockState(LevelSource *level, int x, int y, int z)
{
return Tile::BlockState(level->getData(x, y, z) & 0x1);
}
Icon *JukeboxTile::getTexture(int face, int data)
{
if (face == Facing::UP)
{
return iconTop;
}
return icon;
}
// 4J-PB - Adding a TestUse for tooltip display
bool JukeboxTile::TestUse(Level *level, int x, int y, int z, shared_ptr<Player> player)
{
// if the jukebox is empty, return true
if (level->getData(x, y, z) == 0) return false;
return true;
}
bool JukeboxTile::use(Level *level, int x, int y, int z, shared_ptr<Player> player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param
{
if (soundOnly) return false;
if (level->getData(x, y, z) == 0) return false;
dropRecording(level, x, y, z);
return true;
}
void JukeboxTile::setRecord(Level *level, int x, int y, int z, shared_ptr<ItemInstance> record)
{
if (level->isClientSide) return;
shared_ptr<JukeboxTile::Entity> rte = dynamic_pointer_cast<JukeboxTile::Entity>( level->getTileEntity(x, y, z) );
rte->setRecord(record->copy());
rte->setChanged();
level->setData(x, y, z, 1, Tile::UPDATE_CLIENTS);
}
void JukeboxTile::dropRecording(Level *level, int x, int y, int z)
{
if (level->isClientSide) return;
shared_ptr<JukeboxTile::Entity> rte = dynamic_pointer_cast<JukeboxTile::Entity>( level->getTileEntity(x, y, z) );
if( rte == nullptr ) return;
shared_ptr<ItemInstance> oldRecord = rte->getRecord();
if (oldRecord == nullptr) return;
level->levelEvent(LevelEvent::SOUND_PLAY_RECORDING, x, y, z, 0);
// 4J-PB- the level event will play the music
//level->playStreamingMusic(L"", x, y, z);
rte->setRecord(nullptr);
rte->setChanged();
level->setData(x, y, z, 0, Tile::UPDATE_CLIENTS);
float s = 0.7f;
double xo = level->random->nextFloat() * s + (1 - s) * 0.5;
double yo = level->random->nextFloat() * s + (1 - s) * 0.2 + 0.6;
double zo = level->random->nextFloat() * s + (1 - s) * 0.5;
shared_ptr<ItemInstance> itemInstance = oldRecord->copy();
shared_ptr<ItemEntity> item = std::make_shared<ItemEntity>(level, x + xo, y + yo, z + zo, itemInstance);
item->throwTime = 10;
level->addEntity(item);
}
void JukeboxTile::onRemove(Level *level, int x, int y, int z, int id, int data)
{
dropRecording(level, x, y, z);
Tile::onRemove(level, x, y, z, id, data);
}
void JukeboxTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus)
{
if (level->isClientSide) return;
Tile::spawnResources(level, x, y, z, data, odds, 0);
}
shared_ptr<TileEntity> JukeboxTile::newTileEntity(Level *level)
{
return std::make_shared<JukeboxTile::Entity>();
}
void JukeboxTile::registerIcons(IconRegister *iconRegister)
{
icon = iconRegister->registerIcon(getIconName() + L"_side");
iconTop = iconRegister->registerIcon(getIconName() + L"_top");
}
bool JukeboxTile::hasAnalogOutputSignal()
{
return true;
}
int JukeboxTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir)
{
shared_ptr<ItemInstance> record = dynamic_pointer_cast<JukeboxTile::Entity>( level->getTileEntity(x, y, z))->getRecord();
return record == nullptr ? Redstone::SIGNAL_NONE : record->id + 1 - Item::record_13_Id;
}
int JukeboxTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr<Player> player, bool bUseItemOn) const
{
shared_ptr<ItemInstance> item = player->inventory->IsHeldItem() ? player->inventory->getSelected() : nullptr;
// Not4J Anaël: We need to check if the player holds a disk before displaying the tooltip
if (item != nullptr && item->getItem() != nullptr)
{
int itemId = item->getItem()->id;
if (itemId >= Item::record_13_Id && itemId <= Item::record_wait_Id)
{
// And if the jukebox already has a disk inside
auto tileEntity = dynamic_pointer_cast<JukeboxTile::Entity>(level->getTileEntity(x, y, z));
if (tileEntity != nullptr && tileEntity->getRecord() == nullptr)
{
return IDS_TOOLTIPS_PLAY;
}
}
}
// If the player doesn't, we can display the eject tooltip
if (Tile::jukebox->TestUse(level, x, y, z, player))
{
return IDS_TOOLTIPS_EJECT;
}
return 0;
}