feat(jui): add beacon screen

This commit is contained in:
Sally Knight 2026-03-29 20:16:56 +03:00 committed by Tropical
parent 18dd2ed2ca
commit 1ab985805a
18 changed files with 527 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -436,6 +436,9 @@ tile.oreEmerald.name=Emerald Ore
tile.blockEmerald.name=Block of Emerald
tile.tripWire.name=Tripwire
tile.tripWireSource.name=Tripwire Hook
tile.beacon.name=Beacon
tile.beacon.primary=Primary Power
tile.beacon.secondary=Secondary Power
item.shovelIron.name=Iron Shovel
item.pickaxeIron.name=Iron Pickaxe

View file

@ -1,5 +1,6 @@
#include "../Platform/stdafx.h"
#include "LocalPlayer.h"
#include "UI/Screens/BeaconScreen.h"
#include "UI/Screens/BrewingStandScreen.h"
#include "UI/Screens/EnchantmentScreen.h"
#include "UI/Screens/HopperScreen.h"
@ -696,9 +697,13 @@ bool LocalPlayer::openBrewingStand(
}
bool LocalPlayer::openBeacon(std::shared_ptr<BeaconTileEntity> beacon) {
// minecraft->setScreen(new BeaconScreen(inventory, beacon));
#ifdef ENABLE_JAVA_GUIS
minecraft->setScreen(new BeaconScreen(inventory, beacon));
bool success = true;
#else
bool success = app.LoadBeaconMenu(GetXboxPad(), inventory, beacon);
if (success) ui.PlayUISFX(eSFX_Press);
#endif
return success;
}

View file

@ -180,6 +180,7 @@ const wchar_t* Textures::preLoaded[TN_COUNT] = {
L"gui/horse",
L"gui/anvil",
L"gui/trap",
L"gui/beacon",
L"gui/hopper",
L"gui/enchant",
L"gui/villager",

View file

@ -162,6 +162,7 @@ typedef enum _TEXTURE_NAME {
TN_GUI_HORSE,
TN_GUI_ANVIL,
TN_GUI_TRAP,
TN_GUI_BEACON,
TN_GUI_HOPPER,
TN_GUI_ENCHANT,
TN_GUI_VILLAGER,

View file

@ -0,0 +1,46 @@
#include "../../Platform/stdafx.h"
#include "AbstractBeaconButton.h"
#include "../Textures/Textures.h"
#include "../../../Minecraft.Client/Minecraft.h"
#include <GL/gl.h>
// 4jcraft: referenced from MCP 8.11 (JE 1.6.4)
#ifdef ENABLE_JAVA_GUIS
extern ResourceLocation GUI_BEACON_LOCATION;
#endif
AbstractBeaconButton::AbstractBeaconButton(int id, int x, int y)
: Button(id, x, y, 22, 22, L"") {
hovered = false;
selected = false;
iconRes = nullptr;
iconU = iconV = 0;
}
void AbstractBeaconButton::renderBg(Minecraft* minecraft, int xm, int ym) {
#ifdef ENABLE_JAVA_GUIS
if (!visible) return;
hovered = (xm >= x && ym >= y && xm < x + w && ym < y + h);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
minecraft->textures->bindTexture(&GUI_BEACON_LOCATION);
int texU = 0;
if (!active) {
texU += w * 2;
} else if (selected) {
texU += w * 1;
} else if (hovered) {
texU += w * 3;
}
int texV = 219;
blit(x, y, texU, texV, w, h);
if (iconRes != nullptr && iconRes != &GUI_BEACON_LOCATION) {
minecraft->textures->bindTexture(iconRes);
}
blit(x + 2, y + 2, iconU, iconV, 18, 18);
#endif
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "Button.h"
class ResourceLocation;
class AbstractBeaconButton : public Button {
protected:
bool hovered;
bool selected;
ResourceLocation* iconRes;
int iconU, iconV;
public:
AbstractBeaconButton(int id, int x, int y);
void setSelected(bool sel) { selected = sel; }
bool isSelected() const { return selected; }
bool isHovered() const { return hovered; }
virtual void renderTooltip(int xm, int ym) = 0;
protected:
virtual void renderBg(Minecraft* minecraft, int xm, int ym) override;
};

View file

@ -0,0 +1,25 @@
#include "../../Platform/stdafx.h"
#include "BeaconCancelButton.h"
#include "Screens/BeaconScreen.h"
#include "../../../Minecraft.World/Headers/net.minecraft.locale.h"
// 4jcraft: referenced from MCP 8.11 (JE 1.6.4)
#ifdef ENABLE_JAVA_GUIS
extern ResourceLocation GUI_BEACON_LOCATION;
#endif
BeaconCancelButton::BeaconCancelButton(BeaconScreen* screen, int id, int x,
int y)
: AbstractBeaconButton(id, x, y) {
this->screen = screen;
#ifdef ENABLE_JAVA_GUIS
this->iconRes = &GUI_BEACON_LOCATION;
#endif
this->iconU = 112;
this->iconV = 220;
}
void BeaconCancelButton::renderTooltip(int xm, int ym) {
screen->renderTooltip(Language::getInstance()->getElement(L"gui.cancel"),
xm, ym);
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "AbstractBeaconButton.h"
class BeaconScreen;
class BeaconCancelButton : public AbstractBeaconButton {
public:
BeaconCancelButton(BeaconScreen* screen, int id, int x, int y);
void renderTooltip(int xm, int ym) override;
private:
BeaconScreen* screen;
};

View file

@ -0,0 +1,25 @@
#include "../../Platform/stdafx.h"
#include "BeaconConfirmButton.h"
#include "Screens/BeaconScreen.h"
#include "../../../Minecraft.World/Headers/net.minecraft.locale.h"
// 4jcraft: referenced from MCP 8.11 (JE 1.6.4)
#ifdef ENABLE_JAVA_GUIS
extern ResourceLocation GUI_BEACON_LOCATION;
#endif
BeaconConfirmButton::BeaconConfirmButton(BeaconScreen* screen, int id, int x,
int y)
: AbstractBeaconButton(id, x, y) {
this->screen = screen;
#ifdef ENABLE_JAVA_GUIS
this->iconRes = &GUI_BEACON_LOCATION;
#endif
this->iconU = 90;
this->iconV = 220;
}
void BeaconConfirmButton::renderTooltip(int xm, int ym) {
screen->renderTooltip(Language::getInstance()->getElement(L"gui.done"), xm,
ym);
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "AbstractBeaconButton.h"
class BeaconScreen;
class BeaconConfirmButton : public AbstractBeaconButton {
public:
BeaconConfirmButton(BeaconScreen* screen, int id, int x, int y);
void renderTooltip(int xm, int ym) override;
private:
BeaconScreen* screen;
};

View file

@ -0,0 +1,39 @@
#include "../../Platform/stdafx.h"
#include "BeaconPowerButton.h"
#include "Screens/BeaconScreen.h"
#include "../../../Minecraft.World/Entities/MobEffect.h"
#include "../../../Minecraft.World/Headers/net.minecraft.locale.h"
#include "../Textures/Textures.h"
#include "Textures/ResourceLocation.h"
// 4jcraft: referenced from MCP 8.11 (JE 1.6.4)
#ifdef ENABLE_JAVA_GUIS
ResourceLocation GUI_INVENTORY_LOCATION = ResourceLocation(TN_GUI_INVENTORY);
#endif
BeaconPowerButton::BeaconPowerButton(BeaconScreen* screen, int id, int x, int y,
int effectId, int tier)
: AbstractBeaconButton(id, x, y) {
this->screen = screen;
this->effectId = effectId;
this->tier = tier;
#ifdef ENABLE_JAVA_GUIS
this->iconRes = &GUI_INVENTORY_LOCATION;
#endif
int statusIconIndex = MobEffect::javaId(effectId);
this->iconU = (statusIconIndex % 8) * 18;
this->iconV = 198 + (statusIconIndex / 8) * 18;
}
void BeaconPowerButton::renderTooltip(int xm, int ym) {
MobEffect* effect = MobEffect::effects[effectId];
if (!effect) return;
std::wstring name = app.GetString(effect->getDescriptionId());
if (tier >= 3 && effect->id != MobEffect::regeneration->id) {
name += L" II";
}
screen->renderTooltip(name, xm, ym);
}

View file

@ -0,0 +1,18 @@
#pragma once
#include "AbstractBeaconButton.h"
#include "../../../Minecraft.World/Headers/net.minecraft.world.effect.h"
class BeaconScreen;
class BeaconPowerButton : public AbstractBeaconButton {
public:
BeaconPowerButton(BeaconScreen* screen, int id, int x, int y, int effectId,
int tier);
void renderTooltip(int xm, int ym) override;
bool isSelected() const { return selected; }
private:
BeaconScreen* screen;
int effectId;
int tier;
};

View file

@ -0,0 +1,229 @@
#include "../../Platform/stdafx.h"
#include "BeaconScreen.h"
#include "../BeaconConfirmButton.h"
#include "../BeaconCancelButton.h"
#include "../BeaconPowerButton.h"
#include <GL/gl.h>
#include <memory>
#include "../../Player/MultiPlayerLocalPlayer.h"
#include "../../Rendering/Lighting.h"
#include "../../Textures/Textures.h"
#include "../../../Minecraft.World/Headers/net.minecraft.locale.h"
#include "../../../Minecraft.World/Containers/Slot.h"
#include "../../../Minecraft.World/Headers/net.minecraft.world.item.h"
#include "../../../Minecraft.Client/Minecraft.h"
#include "../../../Minecraft.Client/Network/ClientConnection.h"
#include "../../../Minecraft.World/IO/Streams/ByteArrayOutputStream.h"
#include "../../../Minecraft.World/IO/Streams/DataOutputStream.h"
// 4jcraft: referenced from MCP 8.11 (JE 1.6.4) and the existing
// container classes (and iggy too)
#ifdef ENABLE_JAVA_GUIS
ResourceLocation GUI_BEACON_LOCATION = ResourceLocation(TN_GUI_BEACON);
#endif
BeaconScreen::BeaconScreen(std::shared_ptr<Inventory> inventory,
std::shared_ptr<BeaconTileEntity> beacon)
: AbstractContainerScreen(new BeaconMenu(inventory, beacon)) {
this->inventory = inventory;
this->beacon = beacon;
this->beaconMenu = static_cast<BeaconMenu*>(menu);
this->imageWidth = 230;
this->imageHeight = 219;
this->buttonsNotDrawn = true;
this->beaconConfirmButton = nullptr;
}
BeaconScreen::~BeaconScreen() = default;
void BeaconScreen::init() {
AbstractContainerScreen::init();
int xo = (width - imageWidth) / 2;
int yo = (height - imageHeight) / 2;
beaconConfirmButton = new BeaconConfirmButton(this, -1, xo + 164, yo + 107);
buttons.push_back(beaconConfirmButton);
buttons.push_back(new BeaconCancelButton(this, -2, xo + 190, yo + 107));
buttonsNotDrawn = true;
beaconConfirmButton->active = false;
}
void BeaconScreen::tick() {
if (buttonsNotDrawn && beacon->getLevels() >= 0) {
buttonsNotDrawn = false;
int xo = (width - imageWidth) / 2;
int yo = (height - imageHeight) / 2;
for (int tier = 0; tier <= 2; ++tier) {
int effectCount = BeaconTileEntity::BEACON_EFFECTS_EFFECTS;
int actualCount = 0;
for (int e = 0; e < effectCount; ++e) {
if (BeaconTileEntity::BEACON_EFFECTS[tier][e] != nullptr) {
actualCount++;
} else {
break;
}
}
int totalWidth = actualCount * 22 + (actualCount - 1) * 2;
int startX = xo + 53 + (actualCount * 24 - totalWidth) / 2;
for (int e = 0; e < actualCount; ++e) {
MobEffect* effect = BeaconTileEntity::BEACON_EFFECTS[tier][e];
if (effect == nullptr) break;
int buttonId = (tier << 8) | effect->id;
BeaconPowerButton* button = new BeaconPowerButton(
this, buttonId, startX + e * 24, yo + 22 + tier * 25,
effect->id, tier);
buttons.push_back(button);
if (tier >= beacon->getLevels()) {
button->active = false;
} else if (effect->id == beacon->getPrimaryPower()) {
button->setSelected(true);
}
}
}
int tier = 3;
int effectCount = BeaconTileEntity::BEACON_EFFECTS_EFFECTS;
int actualCount = 0;
for (int e = 0; e < effectCount; ++e) {
if (BeaconTileEntity::BEACON_EFFECTS[tier][e] != nullptr) {
actualCount++;
} else {
break;
}
}
int totalWidth = (actualCount + 1) * 22 + actualCount * 2;
int startX = xo + 143 + ((actualCount + 1) * 24 - totalWidth) / 2;
for (int e = 0; e < actualCount; ++e) {
MobEffect* effect = BeaconTileEntity::BEACON_EFFECTS[tier][e];
if (effect == nullptr) break;
int buttonId = (tier << 8) | effect->id;
BeaconPowerButton* button = new BeaconPowerButton(
this, buttonId, startX + e * 24, yo + 47, effect->id, tier);
buttons.push_back(button);
if (tier >= beacon->getLevels()) {
button->active = false;
} else if (effect->id == beacon->getSecondaryPower()) {
button->setSelected(true);
}
}
if (beacon->getPrimaryPower() > 0) {
int buttonId = (tier << 8) | beacon->getPrimaryPower();
BeaconPowerButton* button =
new BeaconPowerButton(this, buttonId, startX + actualCount * 24,
yo + 47, beacon->getPrimaryPower(), tier);
buttons.push_back(button);
if (tier >= beacon->getLevels()) {
button->active = false;
} else if (beacon->getPrimaryPower() ==
beacon->getSecondaryPower()) {
button->setSelected(true);
}
}
}
beaconConfirmButton->active =
(beacon->getItem(0) != nullptr && beacon->getPrimaryPower() > 0);
}
void BeaconScreen::removed() { AbstractContainerScreen::removed(); }
void BeaconScreen::renderLabels() {
std::wstring primaryLabel =
Language::getInstance()->getElement(L"tile.beacon.primary");
font->drawShadow(primaryLabel, 25, 10, 0xE1E1E1);
std::wstring secondaryLabel =
Language::getInstance()->getElement(L"tile.beacon.secondary");
font->drawShadow(secondaryLabel, 125, 10, 0xE1E1E1);
}
void BeaconScreen::renderBg(float a) {
#ifdef ENABLE_JAVA_GUIS
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
minecraft->textures->bindTexture(&GUI_BEACON_LOCATION);
int xo = (width - imageWidth) / 2;
int yo = (height - imageHeight) / 2;
blit(xo, yo, 0, 0, imageWidth, imageHeight);
// Render payment item icons
itemRenderer->renderGuiItem(
font, minecraft->textures,
std::shared_ptr<ItemInstance>(new ItemInstance(Item::emerald_Id, 1, 0)),
xo + 42, yo + 109);
itemRenderer->renderGuiItem(
font, minecraft->textures,
std::shared_ptr<ItemInstance>(new ItemInstance(Item::diamond_Id, 1, 0)),
xo + 42 + 22, yo + 109);
itemRenderer->renderGuiItem(font, minecraft->textures,
std::shared_ptr<ItemInstance>(
new ItemInstance(Item::goldIngot_Id, 1, 0)),
xo + 42 + 44, yo + 109);
itemRenderer->renderGuiItem(font, minecraft->textures,
std::shared_ptr<ItemInstance>(
new ItemInstance(Item::ironIngot_Id, 1, 0)),
xo + 42 + 66, yo + 109);
#endif
}
void BeaconScreen::render(int xm, int ym, float a) {
AbstractContainerScreen::render(xm, ym, a);
for (Button* button : buttons) {
AbstractBeaconButton* beaconButton =
dynamic_cast<AbstractBeaconButton*>(button);
if (beaconButton && beaconButton->isHovered()) {
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
beaconButton->renderTooltip(xm, ym);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
break;
}
}
}
void BeaconScreen::buttonClicked(Button* button) {
if (button->id == -2) {
minecraft->player->closeContainer();
} else if (button->id == -1) {
// 4jcraft: copied from IUIScene_BeaconMenu
ByteArrayOutputStream baos;
DataOutputStream dos(&baos);
dos.writeInt(beacon->getPrimaryPower());
dos.writeInt(beacon->getSecondaryPower());
minecraft->player->connection->send(
std::shared_ptr<CustomPayloadPacket>(new CustomPayloadPacket(
CustomPayloadPacket::SET_BEACON_PACKET, baos.toByteArray())));
minecraft->player->closeContainer();
} else if (dynamic_cast<BeaconPowerButton*>(button)) {
int effectId = button->id & 255;
int tier = button->id >> 8;
if (tier < 3) {
beacon->setPrimaryPower(effectId);
} else {
beacon->setSecondaryPower(effectId);
}
for (Button* btn : buttons) {
delete btn;
}
buttons.clear();
init();
tick();
}
}

View file

@ -0,0 +1,32 @@
#pragma once
#include "AbstractContainerScreen.h"
#include "../../../Minecraft.World/Containers/BeaconMenu.h"
#include "../../../Minecraft.World/Headers/net.minecraft.world.level.tile.entity.h"
class BeaconConfirmButton;
class BeaconCancelButton;
class BeaconScreen : public AbstractContainerScreen {
public:
BeaconScreen(std::shared_ptr<Inventory> inventory,
std::shared_ptr<BeaconTileEntity> beacon);
virtual ~BeaconScreen();
void init() override;
void removed() override;
void tick() override;
void renderLabels() override;
void renderBg(float a) override;
void render(int xm, int ym, float a) override;
void buttonClicked(Button* button) override;
std::shared_ptr<BeaconTileEntity> getBeacon() { return beacon; }
private:
std::shared_ptr<Inventory> inventory;
std::shared_ptr<BeaconTileEntity> beacon;
BeaconMenu* beaconMenu;
BeaconConfirmButton* beaconConfirmButton;
bool buttonsNotDrawn;
};

View file

@ -5,6 +5,7 @@
#include "JoinMultiplayerScreen.h"
#include "../../Rendering/Tesselator.h"
#include "../../Textures/Textures.h"
#include "../../GameState/Options.h"
#include "../../../Minecraft.World/Util/StringHelpers.h"
#include "../../../Minecraft.World/IO/Streams/InputOutputStream.h"
#include "../../../Minecraft.World/Headers/net.minecraft.locale.h"

View file

@ -443,4 +443,53 @@ void MobEffect::addAttributeModifiers(std::shared_ptr<LivingEntity> entity,
double MobEffect::getAttributeModifierValue(int amplifier,
AttributeModifier* original) {
return original->getAmount() * (amplifier + 1);
}
// 4jcraft: helper for inventoryscreen and beaconscreen
int MobEffect::javaId(int id) {
// mapped to java based on the inventory texture (see gui/inventory.png)
switch (id) {
case 1:
return 0;
case 2:
return 1;
case 3:
return 2;
case 4:
return 3;
case 5:
return 4;
case 18:
return 5;
case 19:
return 6;
case 10:
return 7;
case 14:
return 8;
case 17:
return 9;
case 8:
return 10;
case 9:
return 11;
case 16:
return 12;
case 15:
return 13;
case 11:
return 14;
case 12:
return 15;
case 13:
return 16;
case 20:
return 17;
case 21:
return 18;
case 22:
return 18;
default:
return 0;
}
}

View file

@ -134,4 +134,6 @@ public:
int amplifier);
virtual double getAttributeModifierValue(int amplifier,
AttributeModifier* original);
static int javaId(
int id); // 4jcraft: helper for inventoryscreen and beaconscreen
};