Skip to content

Commit 6b2e1fe

Browse files
committed
Fluid Handling
1 parent 5b96fbc commit 6b2e1fe

File tree

11 files changed

+439
-102
lines changed

11 files changed

+439
-102
lines changed
Lines changed: 55 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
package dev.quarris.fireandflames.client.screen;
22

33
import dev.quarris.fireandflames.ModRef;
4+
import dev.quarris.fireandflames.client.screen.components.CrucibleFluidTankComponent;
45
import dev.quarris.fireandflames.world.block.entity.CrucibleControllerBlockEntity;
56
import dev.quarris.fireandflames.world.inventory.menu.CrucibleMenu;
67
import net.minecraft.client.gui.GuiGraphics;
78
import net.minecraft.client.gui.screens.inventory.EffectRenderingInventoryScreen;
8-
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
99
import net.minecraft.network.chat.Component;
1010
import net.minecraft.resources.ResourceLocation;
1111
import net.minecraft.world.entity.player.Inventory;
1212
import net.minecraft.world.inventory.Slot;
1313
import net.minecraft.world.item.ItemStack;
14-
import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions;
15-
import net.neoforged.neoforge.client.textures.FluidSpriteCache;
16-
import net.neoforged.neoforge.fluids.FluidStack;
17-
import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
1814
import org.jetbrains.annotations.NotNull;
1915
import org.jetbrains.annotations.Nullable;
2016

@@ -25,6 +21,8 @@ public class CrucibleScreen extends EffectRenderingInventoryScreen<CrucibleMenu>
2521
private static final ResourceLocation SCROLLER_SPRITE = ModRef.res("container/crucible/scroller");
2622
private static final ResourceLocation SCROLLER_DISABLED_SPRITE = ModRef.res("container/crucible/scroller_disabled");
2723

24+
private CrucibleFluidTankComponent fluidTankComponent;
25+
2826
public CrucibleScreen(CrucibleMenu menu, Inventory playerInventory, Component title) {
2927
super(menu, playerInventory, title);
3028

@@ -34,47 +32,20 @@ public CrucibleScreen(CrucibleMenu menu, Inventory playerInventory, Component ti
3432
}
3533

3634
@Override
37-
protected void containerTick() {
38-
}
39-
40-
@Override
41-
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
42-
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
43-
this.renderTooltip(pGuiGraphics, pMouseX, pMouseY);
44-
if (pMouseX >= this.leftPos + 7 && pMouseX < this.leftPos + 57 && pMouseY > this.topPos + 17 && pMouseY < this.topPos + 98) {
45-
this.setTooltipForNextRenderPass(Component.literal(this.menu.crucible.getFluidTank().getFluid().toString()));
46-
}
35+
protected void init() {
36+
super.init();
37+
this.fluidTankComponent = new CrucibleFluidTankComponent(menu.crucible::getFluidTank, this.leftPos + 8, this.topPos + 18, 48, 79);
4738
}
4839

4940
@Override
50-
protected void renderSlotHighlight(GuiGraphics pGraphics, Slot pSlot, int pMouseX, int pMouseY, float pPartialTick) {
51-
if (this.isPlayerSlot(pSlot)) {
52-
super.renderSlotHighlight(pGraphics, pSlot, pMouseX, pMouseY, pPartialTick);
53-
return;
54-
}
55-
56-
if (pSlot.isHighlightable()) {
57-
renderSlotHighlight(pGraphics, pSlot.x, pSlot.y - this.menu.getScroll() * 18, 0, getSlotColor(pSlot.index));
58-
}
41+
protected void containerTick() {
5942
}
6043

6144
@Override
62-
protected void renderSlotContents(GuiGraphics pGraphics, ItemStack pStack, Slot pSlot, @Nullable String pCountString) {
63-
if (this.isPlayerSlot(pSlot)) {
64-
super.renderSlotContents(pGraphics, pStack, pSlot, pCountString);
65-
return;
66-
}
67-
68-
int drawX = pSlot.x;
69-
int drawY = pSlot.y - this.menu.getScroll() * 18;
70-
int seed = drawX + drawY * this.imageWidth;
71-
if (pSlot.isFake()) {
72-
pGraphics.renderFakeItem(pStack, drawX, drawY, seed);
73-
} else {
74-
pGraphics.renderItem(pStack, drawX, drawY, seed);
75-
}
76-
77-
pGraphics.renderItemDecorations(this.font, pStack, drawX, drawY, pCountString);
45+
public void render(GuiGraphics pGraphics, int pMouseX, int pMouseY, float pPartialTick) {
46+
super.render(pGraphics, pMouseX, pMouseY, pPartialTick);
47+
CrucibleControllerBlockEntity crucible = this.getMenu().crucible;
48+
this.fluidTankComponent.render(pGraphics, crucible.getLevel(), crucible.getBlockPos(), pMouseX, pMouseY, pPartialTick);
7849
}
7950

8051
@Override
@@ -90,25 +61,6 @@ protected void renderBg(GuiGraphics pGuiGraphics, float pPartialTick, int pMouse
9061
int scrollPos = (int) (this.getMenu().getScrollBarPosition() * (90 - 15)); // ... * (scrollBarHeight - scrollHeight)
9162

9263
pGuiGraphics.blitSprite(scrollerSprite, this.leftPos + 156, this.topPos + 18 + scrollPos, 12, 15);
93-
94-
CrucibleControllerBlockEntity crucible = this.getMenu().crucible;
95-
FluidTank fluidTank = this.menu.crucible.getFluidTank();
96-
FluidStack fluid = fluidTank.getFluid();
97-
int tankPosX = this.leftPos + 8;
98-
int tankPosY = this.topPos + 18;
99-
int tankWidth = 48;
100-
int tankHeight = 79;
101-
102-
TextureAtlasSprite sprite = FluidSpriteCache.getFluidSprites(crucible.getLevel(), crucible.getBlockPos(), fluid.getFluid().defaultFluidState())[0];
103-
IClientFluidTypeExtensions fluidExtensions = IClientFluidTypeExtensions.of(fluid.getFluidType());
104-
int color = fluidExtensions.getTintColor(fluid.getFluid().defaultFluidState(), crucible.getLevel(), crucible.getBlockPos());
105-
106-
float red = (float) (color >> 16 & 0xFF) / 255.0F;
107-
float green = (float) (color >> 8 & 0xFF) / 255.0F;
108-
float blue = (float) (color & 0xFF) / 255.0F;
109-
110-
pGuiGraphics.blit(tankPosX, tankPosY, 0, tankWidth, tankHeight, sprite, red, green, blue, 1.0f);
111-
11264
/*
11365
SpriteContents contents = sprite.contents();
11466
int drawX, drawY;
@@ -138,6 +90,37 @@ protected void renderBg(GuiGraphics pGuiGraphics, float pPartialTick, int pMouse
13890
*/
13991
}
14092

93+
@Override
94+
protected void renderSlotHighlight(GuiGraphics pGraphics, Slot pSlot, int pMouseX, int pMouseY, float pPartialTick) {
95+
if (this.isPlayerSlot(pSlot)) {
96+
super.renderSlotHighlight(pGraphics, pSlot, pMouseX, pMouseY, pPartialTick);
97+
return;
98+
}
99+
100+
if (pSlot.isHighlightable()) {
101+
renderSlotHighlight(pGraphics, pSlot.x, pSlot.y - this.menu.getScroll() * 18, 0, getSlotColor(pSlot.index));
102+
}
103+
}
104+
105+
@Override
106+
protected void renderSlotContents(GuiGraphics pGraphics, ItemStack pStack, Slot pSlot, @Nullable String pCountString) {
107+
if (this.isPlayerSlot(pSlot)) {
108+
super.renderSlotContents(pGraphics, pStack, pSlot, pCountString);
109+
return;
110+
}
111+
112+
int drawX = pSlot.x;
113+
int drawY = pSlot.y - this.menu.getScroll() * 18;
114+
int seed = drawX + drawY * this.imageWidth;
115+
if (pSlot.isFake()) {
116+
pGraphics.renderFakeItem(pStack, drawX, drawY, seed);
117+
} else {
118+
pGraphics.renderItem(pStack, drawX, drawY, seed);
119+
}
120+
121+
pGraphics.renderItemDecorations(this.font, pStack, drawX, drawY, pCountString);
122+
}
123+
141124
private boolean isPlayerSlot(Slot pSlot) {
142125
return pSlot.index >= this.getMenu().crucible.getInventory().getSlots();
143126
}
@@ -158,8 +141,18 @@ public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, doubl
158141
}
159142

160143
@Override
161-
public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) {
162-
return super.mouseDragged(mouseX, mouseY, button, dragX, dragY);
163-
}
144+
public boolean mouseClicked(double mouseX, double mouseY, int button) {
145+
if (!this.fluidTankComponent.isHovering(mouseX, mouseY)) {
146+
return super.mouseClicked(mouseX, mouseY, button);
147+
}
164148

149+
int clickedFluidSlot = this.fluidTankComponent.getHoveringFluidTank(mouseX, mouseY);
150+
if (clickedFluidSlot < 0 || !this.menu.clickMenuButton(this.minecraft.player, clickedFluidSlot)) {
151+
return super.mouseClicked(mouseX, mouseY, button);
152+
}
153+
154+
this.minecraft.gameMode.handleInventoryButtonClick(this.menu.containerId, clickedFluidSlot);
155+
return true;
156+
157+
}
165158
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package dev.quarris.fireandflames.client.screen.components;
2+
3+
import dev.quarris.fireandflames.world.crucible.CrucibleFluidTank;
4+
import net.minecraft.client.Minecraft;
5+
import net.minecraft.client.gui.GuiGraphics;
6+
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
7+
import net.minecraft.core.BlockPos;
8+
import net.minecraft.network.chat.Component;
9+
import net.minecraft.util.Mth;
10+
import net.minecraft.world.level.Level;
11+
import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions;
12+
import net.neoforged.neoforge.client.textures.FluidSpriteCache;
13+
import net.neoforged.neoforge.fluids.FluidStack;
14+
15+
import java.util.function.Supplier;
16+
17+
public class CrucibleFluidTankComponent {
18+
19+
private final Supplier<CrucibleFluidTank> fluidTankSupplier;
20+
private final int x, y;
21+
private final int width, height;
22+
23+
public CrucibleFluidTankComponent(Supplier<CrucibleFluidTank> fluidTankSupplier, int x, int y, int width, int height) {
24+
this.fluidTankSupplier = fluidTankSupplier;
25+
this.x = x;
26+
this.y = y;
27+
this.width = width;
28+
this.height = height;
29+
}
30+
31+
public boolean isHovering(double pMouseX, double pMouseY) {
32+
return pMouseX >= this.x && pMouseX < this.x + this.width && pMouseY >= this.y && pMouseY < this.y + this.height;
33+
}
34+
35+
public int getHoveringFluidTank(double pMouseX, double pMouseY) {
36+
if (!this.isHovering(pMouseX, pMouseY)) {
37+
return -1;
38+
}
39+
40+
int pos = 0;
41+
for (int tank = 0; tank < this.fluidTankSupplier.get().getTanks(); tank++) {
42+
int height = this.getHeightForFluidSlot(tank);
43+
if (pMouseY > this.y + this.height - pos - height && pMouseY < this.y + this.height - pos) {
44+
return tank;
45+
}
46+
pos += height;
47+
}
48+
49+
return -1;
50+
}
51+
52+
public void render(GuiGraphics pGraphics, Level pLevel, BlockPos pPos, int pMouseX, int pMouseY, float pPartialTick) {
53+
CrucibleFluidTank fluidTank = this.fluidTankSupplier.get();
54+
if (fluidTank.getTanks() <= 0) {
55+
return;
56+
}
57+
58+
int tanks = fluidTank.getTanks();
59+
int drawY = 0;
60+
61+
for (int tank = 0; tank < tanks; tank++) {
62+
int drawHeight = this.getHeightForFluidSlot(tank);
63+
FluidStack fluid = fluidTank.getFluidInTank(tank);
64+
this.renderFluidAt(pGraphics, pLevel, pPos, fluid, this.x, (this.y + this.height - drawY - drawHeight), this.width, drawHeight);
65+
drawY += drawHeight;
66+
}
67+
68+
// Render Tooltip
69+
int hoverTank = this.getHoveringFluidTank(pMouseX, pMouseY);
70+
if (hoverTank < 0) {
71+
return;
72+
}
73+
74+
FluidStack fluid = fluidTank.getFluidInTank(hoverTank);
75+
pGraphics.renderTooltip(Minecraft.getInstance().font, Component.literal(fluid.toString()), pMouseX, pMouseY);
76+
}
77+
78+
public int getFluidPositionInTank(int tank) {
79+
int pos = 0;
80+
for (int i = 0; i < tank; i++) {
81+
pos += this.getHeightForFluidSlot(i);
82+
}
83+
84+
return pos;
85+
}
86+
87+
public int getHeightForFluidSlot(int tank) {
88+
CrucibleFluidTank fluidTank = this.fluidTankSupplier.get();
89+
int maxHeight = this.getMaxDrawHeight();
90+
int totalStored = fluidTank.getStored();
91+
FluidStack fluid = fluidTank.getFluidInTank(tank);
92+
double ratio = fluid.getAmount() / (double) totalStored;
93+
return (int) (maxHeight * ratio);
94+
}
95+
96+
public int getMaxDrawHeight() {
97+
CrucibleFluidTank fluidTank = this.fluidTankSupplier.get();
98+
return Mth.lerpInt((fluidTank.getCapacityMb() - fluidTank.getRemainingVolume()) / (float) fluidTank.getCapacityMb(), Math.max(9, fluidTank.getTanks()), this.height - 2);
99+
}
100+
101+
private static void renderFluidAt(GuiGraphics pGraphics, Level pLevel, BlockPos pPos, FluidStack pFluid, int pX, int pY, int pWidth, int pHeight) {
102+
TextureAtlasSprite sprite = FluidSpriteCache.getFluidSprites(pLevel, pPos, pFluid.getFluid().defaultFluidState())[0];
103+
IClientFluidTypeExtensions fluidExtensions = IClientFluidTypeExtensions.of(pFluid.getFluidType());
104+
int color = fluidExtensions.getTintColor(pFluid.getFluid().defaultFluidState(), pLevel, pPos);
105+
106+
float red = (float) (color >> 16 & 0xFF) / 255.0F;
107+
float green = (float) (color >> 8 & 0xFF) / 255.0F;
108+
float blue = (float) (color & 0xFF) / 255.0F;
109+
110+
pGraphics.blit(pX, pY, 0, pWidth, pHeight, sprite, red, green, blue, 1.0f);
111+
}
112+
}

src/main/java/dev/quarris/fireandflames/event/handler/SetupEvents.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class SetupEvents {
1313
@SubscribeEvent
1414
private static void registerCapabilities(RegisterCapabilitiesEvent event) {
1515
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, BlockEntitySetup.CRUCIBLE_CONTROLLER.get(), (be, dir) -> be.getInventory());
16+
event.registerBlockEntity(Capabilities.FluidHandler.BLOCK, BlockEntitySetup.CRUCIBLE_CONTROLLER.get(), (be, dir) -> be.getFluidTank());
1617
}
1718

1819
}

src/main/java/dev/quarris/fireandflames/mixin/client/AbstractContainerScreenMixin.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
import com.llamalad7.mixinextras.sugar.Local;
44
import com.llamalad7.mixinextras.sugar.ref.LocalIntRef;
5-
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
65
import dev.quarris.fireandflames.client.screen.CrucibleScreen;
76
import net.minecraft.client.gui.GuiGraphics;
87
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
98
import net.minecraft.world.inventory.Slot;
10-
import net.minecraft.world.item.ItemStack;
119
import org.spongepowered.asm.mixin.Mixin;
1210
import org.spongepowered.asm.mixin.injection.At;
1311
import org.spongepowered.asm.mixin.injection.Inject;

src/main/java/dev/quarris/fireandflames/world/block/CrucibleControllerBlock.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
import net.minecraft.core.BlockPos;
77
import net.minecraft.core.Direction;
88
import net.minecraft.world.Containers;
9+
import net.minecraft.world.InteractionHand;
910
import net.minecraft.world.InteractionResult;
11+
import net.minecraft.world.ItemInteractionResult;
1012
import net.minecraft.world.entity.player.Player;
13+
import net.minecraft.world.item.ItemStack;
1114
import net.minecraft.world.item.context.BlockPlaceContext;
1215
import net.minecraft.world.level.Level;
1316
import net.minecraft.world.level.block.*;
@@ -20,6 +23,7 @@
2023
import net.minecraft.world.level.block.state.properties.BooleanProperty;
2124
import net.minecraft.world.level.block.state.properties.DirectionProperty;
2225
import net.minecraft.world.phys.BlockHitResult;
26+
import net.neoforged.neoforge.fluids.FluidUtil;
2327

2428
public class CrucibleControllerBlock extends BaseEntityBlock {
2529

@@ -50,14 +54,23 @@ public BlockState getStateForPlacement(BlockPlaceContext context) {
5054
}
5155

5256
@Override
53-
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
54-
if (level.isClientSide) {
57+
protected ItemInteractionResult useItemOn(ItemStack pStack, BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pRayTrace) {
58+
if (FluidUtil.interactWithFluidHandler(pPlayer, pHand, pLevel, pPos, pRayTrace.getDirection())) {
59+
return ItemInteractionResult.sidedSuccess(pLevel.isClientSide());
60+
}
61+
62+
return super.useItemOn(pStack, pState, pLevel, pPos, pPlayer, pHand, pRayTrace);
63+
}
64+
65+
@Override
66+
public InteractionResult useWithoutItem(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, BlockHitResult pRayTrace) {
67+
if (pLevel.isClientSide) {
5568
return InteractionResult.SUCCESS;
5669
}
5770

58-
BlockEntity blockEntity = level.getBlockEntity(pos);
71+
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
5972
if (blockEntity instanceof CrucibleControllerBlockEntity crucibleController) {
60-
player.openMenu(crucibleController, pos);
73+
pPlayer.openMenu(crucibleController, pPos);
6174

6275
// Return success even if structure is invalid to prevent block placement
6376
return InteractionResult.CONSUME;

0 commit comments

Comments
 (0)