Add the insolator #17

Merged
BlakeRain merged 19 commits from BlakeRain/utamacraft:main into main 2023-12-01 18:20:57 +00:00
18 changed files with 561 additions and 59 deletions
Showing only changes of commit 903e20de7b - Show all commits

Binary file not shown.

View File

@ -133,6 +133,16 @@ repositories {
includeGroup("org.squiddev")
}
}
maven {
// location of the maven that hosts JEI files since January 2023
name = "Jared's maven"
url = "https://maven.blamejared.com/"
}
maven {
url 'https://modmaven.dev/'
}
}
dependencies {
@ -141,25 +151,17 @@ dependencies {
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
// Real mod deobf dependency examples - these get remapped to your current mappings
// compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency
// runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency
// implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency
// compile against the JEI API but do not include it at runtime
compileOnly(fg.deobf("mezz.jei:jei-${minecraft_version}-common-api:${jei_version}"))
compileOnly(fg.deobf("mezz.jei:jei-${minecraft_version}-forge-api:${jei_version}"))
// at runtime, use the full JEI jar for Forge
runtimeOnly(fg.deobf("mezz.jei:jei-${minecraft_version}-forge:${jei_version}"))
// Examples using mod jars from ./libs
// implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}")
// CC:Tweaked API
implementation(fg.deobf("org.squiddev:cc-tweaked-${minecraft_version}:${cct_version}"))
// For more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
// Vanilla (i.e. for multi-loader systems)
// compileOnly("cc.tweaked:cc-tweaked-${minecraft_version}-common-api:${cct_version}")
// Forge Gradle
// compileOnly("cc.tweaked:cc-tweaked-${minecraft_version}-core-api:${cct_version}")
// compileOnly(fg.deobf("cc.tweaked:cc-tweaked-${minecraft_version}-forge-api:${cct_version}"))
implementation fg.deobf("org.squiddev:cc-tweaked-${minecraft_version}:${cct_version}")
// Mekanism: useful for testing energy and so on.
runtimeOnly(fg.deobf("mekanism:Mekanism:${minecraft_version}-${mekanism_version}"))
}
// This task will expand all declared properties from Gradle (gradle.properties) in the specified resource targets.

View File

@ -39,6 +39,10 @@ mapping_version=2022.11.27-1.19.2
# The version of CC:Tweaked we're building against
cct_version=1.101.3
# The version of JEI that we're building against
jei_version=11.6.0.1015
# The version of Mekanism we use when testing
mekanism_version=10.3.8.477
## Mod Properties

View File

@ -7,6 +7,8 @@ import net.banutama.utamacraft.block.custom.ModBlocks;
import net.banutama.utamacraft.block.entity.ModBlockEntities;
import net.banutama.utamacraft.item.ModItems;
import net.banutama.utamacraft.networking.ModMessages;
import net.banutama.utamacraft.recipe.ModRecipes;
import net.banutama.utamacraft.screen.InsolatorScreen;
import net.banutama.utamacraft.screen.ModMenuTypes;
import net.banutama.utamacraft.sound.ModSounds;
@ -38,12 +40,16 @@ public class Utamacraft {
CCRegistration.register(bus);
ModMenuTypes.register(bus);
ModSounds.register(bus);
ModRecipes.register(bus);
bus.addListener(this::commonSetup);
MinecraftForge.EVENT_BUS.register(this);
}
private void commonSetup(final FMLCommonSetupEvent event) {
event.enqueueWork(() -> {
ModMessages.register();
});
}
@Mod.EventBusSubscriber(modid = MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)

View File

@ -6,6 +6,7 @@ import net.banutama.utamacraft.networking.ModMessages;
import net.banutama.utamacraft.networking.packet.EnergySyncPacket;
import net.banutama.utamacraft.networking.packet.FluidSyncPacket;
import net.banutama.utamacraft.networking.packet.ItemStackSyncPacket;
import net.banutama.utamacraft.recipe.InsolatorRecipe;
import net.banutama.utamacraft.screen.InsolatorMenu;
import net.banutama.utamacraft.util.ModEnergyStorage;
import net.minecraft.core.BlockPos;
@ -25,6 +26,7 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
@ -33,11 +35,14 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import java.util.Optional;
public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, EnergySyncPacket.EnergySyncReceiver, FluidSyncPacket.FluidSyncReceiver, ItemStackSyncPacket.ItemStackSyncReceiver {
private static final Logger LOGGER = LogUtils.getLogger();
@ -73,12 +78,16 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
@Override
public void onEnergyChanged() {
setChanged();
ModMessages.sendToClients(new EnergySyncPacket(energy, getBlockPos()));
ModMessages.sendToClients(new EnergySyncPacket(energy, capacity, getBlockPos()));
}
};
public IEnergyStorage getEnergyStorage() {
return this.energyStorage;
}
@Override
public void receiveEnergySync(int energy) {
public void receiveEnergySync(int energy, int capacity) {
energyStorage.setEnergy(energy);
}
@ -90,6 +99,11 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
ModMessages.sendToClients(new FluidSyncPacket(fluid, worldPosition));
}
}
@Override
public boolean isFluidValid(FluidStack stack) {
return stack.getFluid() == Fluids.WATER;
}
};
public FluidStack getFluidStack() {
@ -147,7 +161,7 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
@Nullable
@Override
public AbstractContainerMenu createMenu(int pContainerId, @NotNull Inventory pPlayerInventory, @NotNull Player pPlayer) {
ModMessages.sendToClients(new EnergySyncPacket(this.energyStorage.getEnergyStored(), getBlockPos()));
ModMessages.sendToClients(new EnergySyncPacket(this.energyStorage.getEnergyStored(), this.energyStorage.getMaxEnergyStored(), getBlockPos()));
ModMessages.sendToClients(new FluidSyncPacket(this.fluidTank.getFluid(), getBlockPos()));
return new InsolatorMenu(pContainerId, pPlayerInventory, this, this.data);
}
@ -223,9 +237,10 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
boolean newActive;
if (entity.canCraft()) {
if (entity.canCraft().isPresent() && entity.hasEnoughEnergy()) {
++entity.progress;
newActive = true;
entity.energyStorage.extractEnergy(ENERGY_REQUIRED, false);
setChanged(level, pos, state);
if (entity.progress >= entity.maxProgress) {
@ -242,6 +257,28 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
state = state.setValue(InsolatorBlock.ACTIVE, newActive);
level.setBlock(pos, state, 3);
}
ItemStack fluid = entity.itemHandler.getStackInSlot(0);
if (fluid.getCount() > 0) {
fluid.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresent(handler -> {
// Remove as much as we need, but no more than a bucket
int amount = Math.min(entity.fluidTank.getSpace(), 1000);
// Simulate removal of that amount from the IFluidHandlerItem
FluidStack stack = handler.drain(amount, IFluidHandler.FluidAction.SIMULATE);
// Ensure that the fluid we would use is valid
if (entity.fluidTank.isFluidValid(stack)) {
// Remove the amount of fluid from the IFluidHandlerItem
stack = handler.drain(amount, IFluidHandler.FluidAction.EXECUTE);
// Fill our fluid tank with the fluid stack we drained from the IFluidHandlerItem
entity.fluidTank.fill(stack, IFluidHandler.FluidAction.EXECUTE);
// Extract the current item from the fluid slot? TODO: Should this be when empty?
entity.itemHandler.extractItem(0, 1, false);
entity.itemHandler.insertItem(0, handler.getContainer(), false);
}
});
}
}
private void resetProgress() {
@ -249,38 +286,80 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
}
private void craftItem() {
ItemStack stack = itemHandler.extractItem(1, 1, false);
stack.grow(1);
itemHandler.insertItem(2, stack, false);
Optional<InsolatorRecipe> recipe = canCraft();
if (recipe.isEmpty()) {
return;
}
// Drain the amount of fluid specified in our recipe from the fluid tank
fluidTank.drain(recipe.get().getFluid().getAmount(), IFluidHandler.FluidAction.EXECUTE);
// Remove an item from the input slot.
itemHandler.extractItem(1, 1, false);
// Insert the recipe output in to the output slot.
ItemStack output = itemHandler.getStackInSlot(2);
if (output.isEmpty()) {
itemHandler.setStackInSlot(2, recipe.get().getResultItem().copy());
} else {
output.grow(recipe.get().getResultItem().getCount());
}
resetProgress();
}
private boolean canCraft() {
ItemStack input = itemHandler.getStackInSlot(1);
private boolean hasEnoughEnergy() {
return energyStorage.getEnergyStored() >= ENERGY_REQUIRED * maxProgress;
}
private Optional<InsolatorRecipe> canCraft() {
Optional<InsolatorRecipe> recipe = getRecipe();
if (recipe.isEmpty()) {
// LOGGER.info("Insolator cannot find recipe");
return Optional.empty();
}
// Make sure that the correct fluid is in the tank.
if (!fluidTank.getFluid().equals(recipe.get().getFluid())) {
// LOGGER.info("Insolator does not have correct fluid; contains {}, expected {}",
// fluidTank.getFluid().getFluid(), recipe.get().getFluid().getFluid());
return Optional.empty();
}
// Ensure that we have enough fluid
if (fluidTank.getFluidAmount() < recipe.get().getFluid().getAmount()) {
// LOGGER.info("Insolator has {} of fluid; recipe requires {}", fluidTank.getFluidAmount(), recipe.get().getFluid().getAmount());
return Optional.empty();
}
ItemStack output = itemHandler.getStackInSlot(2);
if (input.isEmpty()) {
return false;
}
// Make sure that the item in the input is a flower.
if (input.getItem() != Items.CORNFLOWER) {
LOGGER.info("Cannot run insolator, as item is not recognized");
return false;
}
// If the output isn't empty, and the item in the output is different to the input, we cannot process.
if (!output.isEmpty() && output.getItem() != input.getItem()) {
LOGGER.info("Cannot run insolator, as output item is not the same as the input item");
return false;
// If the output isn't empty, and the item in the output is different to the output of the recipe, we cannot process.
if (!output.isEmpty() && output.getItem() != recipe.get().getResultItem().getItem()) {
// LOGGER.info("Cannot run insolator, as output item is not the same as the recipe output");
return Optional.empty();
}
// Make sure that the output is not saturated.
if (output.getCount() >= output.getMaxStackSize()) {
LOGGER.info("Cannot run insolator, as output of {} items exceeds maximum of {}", output.getCount(), output.getMaxStackSize());
return false;
if (output.getCount() + recipe.get().getResultItem().getCount() > output.getMaxStackSize()) {
// LOGGER.info("Cannot run insolator, as output of {} items exceeds maximum of {}", output.getCount(), output.getMaxStackSize());
return Optional.empty();
}
return true;
return recipe;
}
private Optional<InsolatorRecipe> getRecipe() {
if (level == null) {
return Optional.empty();
}
SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots());
for (int slot = 0; slot < itemHandler.getSlots(); ++slot) {
inventory.setItem(slot, itemHandler.getStackInSlot(slot));
}
return level.getRecipeManager()
.getRecipeFor(InsolatorRecipe.Type.INSTANCE, inventory, level);
}
}

View File

@ -13,21 +13,25 @@ import java.util.function.Supplier;
public class EnergySyncPacket extends BasePacket {
private final int energy;
private final int capacity;
private final BlockPos pos;
public EnergySyncPacket(int energy, BlockPos pos) {
public EnergySyncPacket(int energy, int capacity, BlockPos pos) {
this.energy = energy;
this.capacity = capacity;
this.pos = pos;
}
public EnergySyncPacket(@NotNull FriendlyByteBuf buf) {
this.energy = buf.readInt();
this.capacity = buf.readInt();
this.pos = buf.readBlockPos();
}
@Override
public void toBytes(@NotNull FriendlyByteBuf buf) {
buf.writeInt(energy);
buf.writeInt(capacity);
buf.writeBlockPos(pos);
}
@ -42,7 +46,7 @@ public class EnergySyncPacket extends BasePacket {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof EnergySyncReceiver energyReceiver) {
energyReceiver.receiveEnergySync(energy);
energyReceiver.receiveEnergySync(energy, capacity);
Player player = Minecraft.getInstance().player;
if (player == null) {
@ -51,7 +55,7 @@ public class EnergySyncPacket extends BasePacket {
if (player.containerMenu instanceof EnergySyncReceiverMenu menu &&
menu.getBlockEntity().getBlockPos().equals(pos)) {
menu.receiveEnergySync(energy);
menu.receiveEnergySync(energy, capacity);
}
}
});
@ -60,7 +64,7 @@ public class EnergySyncPacket extends BasePacket {
}
public interface EnergySyncReceiver {
void receiveEnergySync(int energy);
void receiveEnergySync(int energy, int capacity);
}
public interface EnergySyncReceiverMenu extends EnergySyncReceiver {

View File

@ -8,12 +8,10 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.network.NetworkEvent;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
@ -27,7 +25,7 @@ public class ItemStackSyncPacket extends BasePacket {
}
public ItemStackSyncPacket(IItemHandler handler, BlockPos pos) {
this.stacks = NonNullList.withSize(handler.getSlots(), ItemStack.EMPTY);
this.stacks = NonNullList.create();
for (int slot = 0; slot < handler.getSlots(); ++slot) {
this.stacks.add(handler.getStackInSlot(slot));
}
@ -36,7 +34,12 @@ public class ItemStackSyncPacket extends BasePacket {
}
public ItemStackSyncPacket(@NotNull FriendlyByteBuf buf) {
this.stacks = buf.readCollection((int size) -> NonNullList.withSize(size, ItemStack.EMPTY), FriendlyByteBuf::readItem);
List<ItemStack> stacks = buf.readCollection(ArrayList::new, FriendlyByteBuf::readItem);
this.stacks = NonNullList.withSize(stacks.size(), ItemStack.EMPTY);
for (int slot = 0; slot < stacks.size(); ++slot) {
this.stacks.set(slot, stacks.get(slot));
}
this.pos = buf.readBlockPos();
}

View File

@ -0,0 +1,108 @@
package net.banutama.utamacraft.recipe;
import com.google.gson.JsonObject;
import com.mojang.serialization.JsonOps;
import net.banutama.utamacraft.Utamacraft;
import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.level.Level;
import net.minecraftforge.fluids.FluidStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class InsolatorRecipe implements Recipe<SimpleContainer> {
private final ResourceLocation id;
private final ItemStack output;
private final Ingredient input;
private final FluidStack fluid;
public InsolatorRecipe(ResourceLocation id, ItemStack output, Ingredient input, FluidStack fluid) {
this.id = id;
this.output = output;
this.input = input;
this.fluid = fluid;
}
@Override
public boolean matches(@NotNull SimpleContainer pContainer, @NotNull Level pLevel) {
if (pLevel.isClientSide()) {
return false;
}
return input.test(pContainer.getItem(1));
}
@Override
public @NotNull ItemStack assemble(@NotNull SimpleContainer pContainer) {
return output;
}
@Override
public boolean canCraftInDimensions(int pWidth, int pHeight) {
return true;
}
public FluidStack getFluid() {
return fluid;
}
@Override
public @NotNull ItemStack getResultItem() {
return output.copy();
}
@Override
public @NotNull ResourceLocation getId() {
return id;
}
@Override
public @NotNull RecipeSerializer<?> getSerializer() {
return Serializer.INSTANCE;
}
@Override
public @NotNull RecipeType<?> getType() {
return Type.INSTANCE;
}
public static class Type implements RecipeType<InsolatorRecipe> {
public static final Type INSTANCE = new Type();
public static final String ID = "insolator";
private Type() {
}
}
public static class Serializer implements RecipeSerializer<InsolatorRecipe> {
public static final Serializer INSTANCE = new Serializer();
public static final ResourceLocation ID = new ResourceLocation(Utamacraft.MOD_ID, "insolator");
@Override
public @NotNull InsolatorRecipe fromJson(@NotNull ResourceLocation pRecipeId, @NotNull JsonObject pSerializedRecipe) {
ItemStack output = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(pSerializedRecipe, "output"));
Ingredient input = Ingredient.fromJson(pSerializedRecipe.getAsJsonObject("input"));
FluidStack fluid = FluidStack.CODEC.decode(JsonOps.INSTANCE, pSerializedRecipe.get("fluid")).result().orElseThrow().getFirst();
return new InsolatorRecipe(pRecipeId, output, input, fluid);
}
@Override
public @Nullable InsolatorRecipe fromNetwork(@NotNull ResourceLocation pRecipeId, @NotNull FriendlyByteBuf pBuffer) {
ItemStack output = pBuffer.readItem();
Ingredient input = Ingredient.fromNetwork(pBuffer);
FluidStack fluid = pBuffer.readFluidStack();
return new InsolatorRecipe(pRecipeId, output, input, fluid);
}
@Override
public void toNetwork(@NotNull FriendlyByteBuf pBuffer, @NotNull InsolatorRecipe pRecipe) {
pBuffer.writeItemStack(pRecipe.output, false);
pRecipe.input.toNetwork(pBuffer);
pBuffer.writeFluidStack(pRecipe.fluid);
}
}
}

View File

@ -0,0 +1,20 @@
package net.banutama.utamacraft.recipe;
import net.banutama.utamacraft.Utamacraft;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
public class ModRecipes {
public static final DeferredRegister<RecipeSerializer<?>> SERIALIZERS =
DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, Utamacraft.MOD_ID);
public static final RegistryObject<RecipeSerializer<InsolatorRecipe>> INSOLATOR_SERIALIZER =
SERIALIZERS.register("insolator", () -> InsolatorRecipe.Serializer.INSTANCE);
public static void register(IEventBus bus) {
SERIALIZERS.register(bus);
}
}

View File

@ -3,6 +3,7 @@ package net.banutama.utamacraft.screen;
import com.mojang.logging.LogUtils;
import net.banutama.utamacraft.block.custom.ModBlocks;
import net.banutama.utamacraft.block.entity.InsolatorBlockEntity;
import net.banutama.utamacraft.networking.packet.EnergySyncPacket;
import net.banutama.utamacraft.networking.packet.FluidSyncPacket;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Inventory;
@ -17,12 +18,14 @@ import net.minecraftforge.items.SlotItemHandler;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
public class InsolatorMenu extends AbstractContainerMenu implements FluidSyncPacket.FluidSyncReceiverMenu {
public class InsolatorMenu extends AbstractContainerMenu implements FluidSyncPacket.FluidSyncReceiverMenu, EnergySyncPacket.EnergySyncReceiverMenu {
private static final Logger LOGGER = LogUtils.getLogger();
public final InsolatorBlockEntity blockEntity;
private final Level level;
private final ContainerData data;
private FluidStack fluid;
private int energy = 0;
private int capacity = 0;
public InsolatorMenu(int id, Inventory inventory, FriendlyByteBuf extraData) {
this(id, inventory, inventory.player.level.getBlockEntity(extraData.readBlockPos()), new SimpleContainerData(3));
@ -37,6 +40,8 @@ public class InsolatorMenu extends AbstractContainerMenu implements FluidSyncPac
this.data = data;
this.blockEntity = insolator;
this.fluid = insolator.getFluidStack();
this.energy = insolator.getEnergyStorage().getEnergyStored();
this.capacity = insolator.getEnergyStorage().getMaxEnergyStored();
addPlayerInventory(inventory);
addPlayerHotbar(inventory);
@ -58,20 +63,38 @@ public class InsolatorMenu extends AbstractContainerMenu implements FluidSyncPac
this.fluid = fluid;
}
@Override
public void receiveEnergySync(int energy, int capacity) {
this.energy = energy;
this.capacity = capacity;
}
@Override
public BlockEntity getBlockEntity() {
return blockEntity;
}
public boolean isCrafting() {
return data.get(0) > 0;
public FluidStack getFluid() {
return fluid;
}
public int getScaledProgress(int scale) {
public int getEnergy() {
return energy;
}
public int getEnergyCapacity() {
return capacity;
}
public boolean isCrafting() {
return data.get(2) == 1;
}
public float getScaledProgress() {
int progress = this.data.get(0);
int maxProgress = this.data.get(1);
return maxProgress != 0 && progress != 0 ? progress * scale / maxProgress : 0;
return maxProgress != 0 && progress != 0 ? (float)progress / (float)maxProgress : 0;
}
@Override

View File

@ -3,19 +3,30 @@ package net.banutama.utamacraft.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.banutama.utamacraft.Utamacraft;
import net.banutama.utamacraft.screen.utils.FluidSprite;
import net.banutama.utamacraft.screen.utils.MouseUtils;
import net.banutama.utamacraft.screen.utils.TiledSprite;
import net.banutama.utamacraft.screen.utils.TooltipUtils;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.fluids.FluidStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
public class InsolatorScreen extends AbstractContainerScreen<InsolatorMenu> {
private static final ResourceLocation TEXTURE =
new ResourceLocation(Utamacraft.MOD_ID, "textures/gui/insolator_gui.png");
public InsolatorScreen(InsolatorMenu menu, Inventory inventory, Component component) {
super(menu, inventory, component);
inventoryLabelY += 5;
}
@Override
@ -27,12 +38,72 @@ public class InsolatorScreen extends AbstractContainerScreen<InsolatorMenu> {
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
blit(stack, x, y, 0, 0, imageWidth, imageHeight);
renderBulb(stack, x, y);
renderProgressArrow(stack, x, y);
renderFluid(stack, x + 33, y + 16);
renderEnergy(stack, x + 46, y + 16);
}
@Override
protected void renderLabels(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY) {
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
if (MouseUtils.isMouseOver(pMouseX, pMouseY, x + 32, y + 15, 11, 61)) {
List<Component> components = TooltipUtils.getFluidTooltip(menu.getFluid(), 64000);
renderTooltip(pPoseStack, components, Optional.empty(),
pMouseX - x, pMouseY - y);
}
if (MouseUtils.isMouseOver(pMouseX, pMouseY, x + 45, y + 15, 11, 61)) {
List<Component> components = TooltipUtils.getEnergyTooltip(getMenu().getEnergy(), getMenu().getEnergyCapacity());
renderTooltip(pPoseStack, components, Optional.empty(), pMouseX - x, pMouseY - y);
}
}
private void renderEnergy(@NotNull PoseStack stack, int x, int y) {
if (menu.getEnergy() <= 0 || menu.getEnergyCapacity() <= 0) {
return;
}
final int ENERGY_HEIGHT = 60;
int stored = (int)(ENERGY_HEIGHT * ((float)menu.getEnergy() / (float)menu.getEnergyCapacity()));
fillGradient(stack, x, y + (ENERGY_HEIGHT - stored), x + 9, y + 60, 0xffb51500, 0xff600b00);
}
private void renderFluid(@NotNull PoseStack stack, int x, int y) {
FluidStack fluid = menu.getFluid();
if (fluid.getFluid().isSame(Fluids.EMPTY)) {
return;
}
final int FLUID_HEIGHT = 60;
TextureAtlasSprite sprite = FluidSprite.getStillFluidSprite(fluid);
int tint = FluidSprite.getTint(fluid);
int amount = fluid.getAmount();
int scaled = Math.min(FLUID_HEIGHT, Math.max(amount > 0 ? 1 : 0, (amount * FLUID_HEIGHT) / 64000));
RenderSystem.enableBlend();
stack.pushPose();
stack.translate(x, y, 0);
TiledSprite.drawTiledSprite(stack, 9, FLUID_HEIGHT, tint, scaled, sprite, 16);
stack.popPose();
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
RenderSystem.disableBlend();
}
private void renderProgressArrow(PoseStack stack, int x, int y) {
if (menu.isCrafting()) {
blit(stack, x + 90, y + 33, 176, 0, 8, menu.getScaledProgress(25));
blit(stack, x + 90, y + 33, 176, 0, 8, (int)(25.0f * menu.getScaledProgress()));
}
}
private void renderBulb(PoseStack stack, int x, int y) {
if (menu.isCrafting()) {
blit(stack, x + 67, y + 38, 176, 25, 9, 14);
}
}

View File

@ -0,0 +1,29 @@
package net.banutama.utamacraft.screen.utils;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions;
import net.minecraftforge.fluids.FluidStack;
public class FluidSprite {
public static int getTint(FluidStack fluid) {
return IClientFluidTypeExtensions.of(fluid.getFluid()).getTintColor(fluid);
}
public static void setColorFromTint(int tint) {
float a = ((tint >> 24) & 0xff) / 255.0f;
float r = ((tint >> 16) & 0xff) / 255.0f;
float g = ((tint >> 8) & 0xff) / 255.0f;
float b = (tint & 0xff) / 255.0f;
RenderSystem.setShaderColor(r, g, b, a);
}
public static TextureAtlasSprite getStillFluidSprite(FluidStack fluid) {
ResourceLocation texture = IClientFluidTypeExtensions.of(fluid.getFluid()).getStillTexture(fluid);
return Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(texture);
}
}

View File

@ -0,0 +1,7 @@
package net.banutama.utamacraft.screen.utils;
public class MouseUtils {
public static boolean isMouseOver(double mouseX, double mouseY, int x, int y, int w, int h) {
return mouseX >= x && mouseX <= x + w && mouseY >= y && mouseY <= y + h;
}
}

View File

@ -0,0 +1,60 @@
package net.banutama.utamacraft.screen.utils;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix4f;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.world.inventory.InventoryMenu;
public class TiledSprite {
public static void drawTiledSprite(PoseStack stack, int tiledWidth, int tiledHeight, int tint, int scaledAmount, TextureAtlasSprite sprite, int textureSize) {
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
Matrix4f m = stack.last().pose();
FluidSprite.setColorFromTint(tint);
int xTileCount = tiledWidth / textureSize;
int xRemainder = tiledWidth - (xTileCount * textureSize);
int yTileCount = scaledAmount / textureSize;
int yRemainder = scaledAmount - (yTileCount * textureSize);
for (int xTile = 0; xTile <= xTileCount; ++xTile) {
for (int yTile = 0; yTile <= yTileCount; ++yTile) {
int width = (xTile == xTileCount) ? xRemainder : textureSize;
if (width <= 0) {
continue;
}
int height = (yTile == yTileCount) ? yRemainder : textureSize;
if (height <= 0) {
continue;
}
int x = xTile * textureSize;
int y = tiledHeight - ((yTile + 1) * textureSize);
drawTextureWithMasking(m, x, y, sprite, textureSize - height, textureSize - width, 100);
}
}
}
private static void drawTextureWithMasking(Matrix4f m, float x, float y, TextureAtlasSprite sprite, int maskTop, int maskRight, float z) {
float u0 = sprite.getU0();
float u1 = sprite.getU1();
float v0 = sprite.getV0();
float v1 = sprite.getV1();
u1 = u1 - (maskRight / 16.0f * (u1 - u0));
v1 = v1 - (maskTop / 16.0f * (v1 - v0));
RenderSystem.setShader(GameRenderer::getPositionTexShader);
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder builder = tesselator.getBuilder();
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
builder.vertex(m, x, y + 16, z).uv(u0, v1).endVertex();
builder.vertex(m, x + 16 - maskRight, y + 16, z).uv(u1, v1).endVertex();
builder.vertex(m, x + 16 - maskRight, y + maskTop, z).uv(u1, v0).endVertex();
builder.vertex(m, x, y + maskTop, z).uv(u0, v0).endVertex();
tesselator.end();
}
}

View File

@ -0,0 +1,71 @@
package net.banutama.utamacraft.screen.utils;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidType;
import org.jetbrains.annotations.NotNull;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class TooltipUtils {
private static final NumberFormat nf = NumberFormat.getIntegerInstance();
private static @NotNull List<Component> startFluidTooltip(@NotNull FluidStack stack) {
List<Component> tooltip = new ArrayList<>();
Fluid fluid = stack.getFluid();
if (fluid.isSame(Fluids.EMPTY)) {
tooltip.add(Component.translatable("tooltip.utamacraft.fluid.empty")
.withStyle(ChatFormatting.ITALIC)
.withStyle(ChatFormatting.GRAY));
return tooltip;
}
tooltip.add(stack.getDisplayName());
return tooltip;
}
public static @NotNull List<Component> getFluidTooltip(@NotNull FluidStack stack, int capacity) {
List<Component> tooltip = startFluidTooltip(stack);
int amount = stack.getAmount();
int mb = (amount * 1000) / FluidType.BUCKET_VOLUME;
tooltip.add(Component.translatable("tooltip.utamacraft.fluid.amount.with_capacity",
nf.format(mb), nf.format(capacity))
.withStyle(ChatFormatting.GRAY));
return tooltip;
}
public static @NotNull List<Component> getFluidTooltip(@NotNull FluidStack stack) {
List<Component> tooltip = startFluidTooltip(stack);
int amount = stack.getAmount();
int mb = (amount * 1000) / FluidType.BUCKET_VOLUME;
tooltip.add(Component.translatable("tooltip.utamacraft.fluid.amount", nf.format(mb))
.withStyle(ChatFormatting.GRAY));
return tooltip;
}
public static @NotNull List<Component> getEnergyTooltip(int energy) {
return List.of(Component.translatable("tooltip.utamacraft.energy.amount",
nf.format(energy)).withStyle(ChatFormatting.GRAY));
}
public static @NotNull List<Component> getEnergyTooltip(int energy, int capacity) {
return List.of(
Component.translatable(("tooltip.utamacraft.energy")),
Component.translatable("tooltip.utamacraft.energy.amount.with_capacity",
nf.format(energy), nf.format(capacity)).withStyle(ChatFormatting.GRAY));
}
}

View File

@ -14,7 +14,13 @@
"item.utamacraft.tungsten_ingot": "Tungsten Ingot",
"item.utamacraft.utamacraft_logo": "Utamacraft",
"itemGroup.utamacraft_tab": "Utamacraft",
"tooltip.utamacraft.energy": "Energy",
"tooltip.utamacraft.energy.amount": "%s FE",
"tooltip.utamacraft.energy.amount.with_capacity": "%s / %s FE",
"tooltip.utamacraft.ethereal_glass": "Glass that is not solid to players",
"tooltip.utamacraft.fluid.empty": "Empty",
"tooltip.utamacraft.fluid.amount": "%s mB",
"tooltip.utamacraft.fluid.amount.with_capacity": "%s / %s mB",
"tooltip.utamacraft.tinted_ethereal_glass": "Glass that is not solid to players and blocks light",
"turtle.utamacraft.player_turtle": "Player"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,9 @@
{
"type": "utamacraft:insolator",
"input": { "item": "minecraft:cornflower" },
"fluid": {
"FluidName": "minecraft:water",
"Amount": 500
},
"output": { "item": "minecraft:cornflower", "count": 2 }
}