listQuads, int combinedLightsIn, int combinedOverlayIn) {
for(BakedQuad bakedquad : listQuads) {
float f;
float f1;
float f2;
if (bakedquad.isTinted()) {
f = red * 1f;
f1 = green * 1f;
f2 = blue * 1f;
} else {
f = 1f;
f1 = 1f;
f2 = 1f;
}
builder.putBulkData(matrixEntry, bakedquad, f, f1, f2, alpha, combinedLightsIn, combinedOverlayIn, true);
}
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/renderer/OurRenderTypes.java
================================================
package com.direwolf20.buildinggadgets.client.renderer;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.InventoryMenu;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import java.util.OptionalDouble;
public class OurRenderTypes extends RenderType {
private static final LineStateShard THICK_LINES = new LineStateShard(OptionalDouble.of(3.0D));
public static final RenderType RenderBlock = create("GadgetRenderBlock",
DefaultVertexFormat.BLOCK, VertexFormat.Mode.QUADS, 256, false, false,
RenderType.CompositeState.builder()
// .setShadeModelState(SMOOTH_SHADE)
.setShaderState(RenderStateShard.BLOCK_SHADER)
.setLightmapState(LIGHTMAP)
.setTextureState(BLOCK_SHEET_MIPPED) //BLOCK_SHEET_MIPPED (mcp) = BLOCK_SHEET_MIPPED (yarn)
.setLayeringState(VIEW_OFFSET_Z_LAYERING) // view_offset_z_layering
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setDepthTestState(LEQUAL_DEPTH_TEST)
.setCullState(NO_CULL)
.setWriteMaskState(COLOR_DEPTH_WRITE)
.createCompositeState(false));
public static final RenderType MissingBlockOverlay = create("GadgetMissingBlockOverlay",
DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, 256, false, false,
RenderType.CompositeState.builder()
.setShaderState(RenderStateShard.POSITION_COLOR_SHADER)
.setLayeringState(VIEW_OFFSET_Z_LAYERING) // view_offset_z_layering
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setTextureState(NO_TEXTURE)
.setDepthTestState(LEQUAL_DEPTH_TEST)
.setCullState(NO_CULL)
.setLightmapState(NO_LIGHTMAP)
.setWriteMaskState(COLOR_WRITE)
.createCompositeState(false));
// public static final RenderType.CompositeRenderType LINES =
// create("lines", DefaultVertexFormat.POSITION_COLOR_NORMAL, VertexFormat.Mode.LINES, 256, RenderType.CompositeState.builder()
// .setShaderState(RENDERTYPE_LINES_SHADER)
// .setLineState(new RenderStateShard.LineStateShard(OptionalDouble.empty()))
// .setLayeringState(VIEW_OFFSET_Z_LAYERING)
// .setTransparencyState(TRANSLUCENT_TRANSPARENCY)
// .setOutputState(ITEM_ENTITY_TARGET)
// .setWriteMaskState(COLOR_DEPTH_WRITE)
// .setCullState(NO_CULL)
// .createCompositeState(false));
public static final RenderType CopyGadgetLines = create("GadgetCopyLines",
DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.LINES, 256, false, false,
RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_LINES_SHADER)
.setLineState(new LineStateShard(OptionalDouble.of(2.0D)))
.setLayeringState(VIEW_OFFSET_Z_LAYERING)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setOutputState(ITEM_ENTITY_TARGET)
.setCullState(NO_CULL)
.setWriteMaskState(COLOR_DEPTH_WRITE)
.createCompositeState(false));
public static final RenderType CopyPasteRenderBlock = create("CopyPasteRenderBlock",
DefaultVertexFormat.BLOCK, VertexFormat.Mode.QUADS, 256, false, false,
RenderType.CompositeState.builder()
.setShaderState(RenderStateShard.BLOCK_SHADER)
// .setShadeModelState(SMOOTH_SHADE)
.setLightmapState(LIGHTMAP)
.setTextureState(BLOCK_SHEET_MIPPED) //BLOCK_SHEET_MIPPED (mcp) = BLOCK_SHEET_MIPPED (yarn)
.setLayeringState(VIEW_OFFSET_Z_LAYERING) // view_offset_z_layering
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setDepthTestState(LEQUAL_DEPTH_TEST)
.setCullState(NO_CULL)
.setWriteMaskState(COLOR_WRITE)
.createCompositeState(false));
public static final RenderType BlockOverlay = create("BGBlockOverlay",
DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, 256, false, false,
RenderType.CompositeState.builder()
.setShaderState(RenderStateShard.RENDERTYPE_SOLID_SHADER)
.setLayeringState(VIEW_OFFSET_Z_LAYERING) // view_offset_z_layering
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setTextureState(NO_TEXTURE)
.setDepthTestState(LEQUAL_DEPTH_TEST)
.setCullState(CULL)
.setLightmapState(NO_LIGHTMAP)
.setWriteMaskState(COLOR_DEPTH_WRITE)
.createCompositeState(false));
public static final RenderType TRIANGLE_STRIP =
create("triangle_strip", DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_STRIP, 256, false, false,
RenderType.CompositeState.builder()
.setShaderState(RenderStateShard.POSITION_COLOR_SHADER)
.setTextureState(NO_TEXTURE)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setCullState(NO_CULL)
.setLightmapState(NO_LIGHTMAP)
.createCompositeState(false));
public OurRenderTypes(String p_173178_, VertexFormat p_173179_, VertexFormat.Mode p_173180_, int p_173181_, boolean p_173182_, boolean p_173183_, Runnable p_173184_, Runnable p_173185_) {
super(p_173178_, p_173179_, p_173180_, p_173181_, p_173182_, p_173183_, p_173184_, p_173185_);
}
/**
* This is used for rendering blocks with an alpha value as the alpha currently isn't
* supported by minecraft.
*
* Literally just raps the buffer so we can render a different RenderType
*/
public static class MultiplyAlphaRenderTypeBuffer implements MultiBufferSource {
private final MultiBufferSource inner;
private final float constantAlpha;
public MultiplyAlphaRenderTypeBuffer(MultiBufferSource inner, float constantAlpha) {
this.inner = inner;
this.constantAlpha = constantAlpha;
}
@Override
public VertexConsumer getBuffer(RenderType type) {
RenderType localType = type;
if (localType instanceof CompositeRenderType) {
// all of this requires a lot of AT's so be aware of that on ports
ResourceLocation texture = ((TextureStateShard) ((CompositeRenderType) localType).state.textureState).texture
.orElse(InventoryMenu.BLOCK_ATLAS);
localType = entityTranslucentCull(texture);
} else if (localType.toString().equals(Sheets.translucentCullBlockSheet().toString())) {
localType = Sheets.translucentCullBlockSheet();
}
return new MultiplyAlphaVertexBuilder(this.inner.getBuffer(localType), this.constantAlpha);
}
/**
* Required for modifying the alpha value.
*/
public static class MultiplyAlphaVertexBuilder implements VertexConsumer {
private final VertexConsumer inner;
private final float constantAlpha;
public MultiplyAlphaVertexBuilder(VertexConsumer inner, float constantAlpha) {
this.inner = inner;
this.constantAlpha = constantAlpha;
}
@Override
public VertexConsumer vertex(double x, double y, double z) {
return inner.vertex(x, y, z);
}
@Override
public VertexConsumer vertex(Matrix4f matrixIn, float x, float y, float z) {
return inner.vertex(matrixIn, x, y, z);
}
@Override
public VertexConsumer color(int red, int green, int blue, int alpha) {
return inner.color(red, green, blue, (int) (alpha * constantAlpha));
}
@Override
public VertexConsumer uv(float u, float v) {
return inner.uv(u, v);
}
@Override
public VertexConsumer overlayCoords(int u, int v) {
return inner.overlayCoords(u, v);
}
@Override
public VertexConsumer uv2(int u, int v) {
return inner.uv2(u, v);
}
@Override
public VertexConsumer normal(float x, float y, float z) {
return inner.normal(x, y, z);
}
@Override
public VertexConsumer normal(Matrix3f matrixIn, float x, float y, float z) {
return inner.normal(matrixIn, x, y, z);
}
@Override
public void endVertex() {
this.inner.endVertex();
}
@Override
public void defaultColor(int p_166901_, int p_166902_, int p_166903_, int p_166904_) {
inner.defaultColor(p_166901_, p_166902_, p_166903_, p_166904_);
}
@Override
public void unsetDefaultColor() {
inner.unsetDefaultColor();
}
}
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/renderer/package-info.java
================================================
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
package com.direwolf20.buildinggadgets.client.renderer;
import net.minecraft.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/renders/BaseRenderer.java
================================================
package com.direwolf20.buildinggadgets.client.renders;
import com.direwolf20.buildinggadgets.client.cache.RemoteInventoryCache;
import com.direwolf20.buildinggadgets.client.renderer.OurRenderTypes;
import com.direwolf20.buildinggadgets.common.tainted.inventory.InventoryLinker;
import com.direwolf20.buildinggadgets.common.tainted.inventory.materials.objects.UniqueItem;
import com.direwolf20.buildinggadgets.common.world.MockBuilderWorld;
import com.direwolf20.buildinggadgets.common.world.MockTileEntityRenderWorld;
import com.google.common.collect.Multiset;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.event.RenderLevelStageEvent;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import org.apache.commons.lang3.tuple.Pair;
import org.joml.Matrix4f;
import java.util.HashSet;
import java.util.Set;
public abstract class BaseRenderer {
public static final BlockState AIR = Blocks.AIR.defaultBlockState();
private static final MockTileEntityRenderWorld tileEntityWorld = new MockTileEntityRenderWorld();
private static final MockBuilderWorld builderWorld = new MockBuilderWorld();
private static final Set invalidTileEntities = new HashSet<>();
private static final RemoteInventoryCache cacheInventory = new RemoteInventoryCache(false);
public void render(RenderLevelStageEvent evt, Player player, ItemStack heldItem) {
// FIXME: might be wrong
if (evt.getStage() != RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) {
return;
}
// This is necessary to prevent issues with not rendering the overlay's at all (when Botania being present) - See #329 for more information
bindBlocks();
if( this.isLinkable() )
BaseRenderer.renderLinkedInventoryOutline(evt, heldItem, player);
}
private void bindBlocks() {
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
}
private static void renderLinkedInventoryOutline(RenderLevelStageEvent evt, ItemStack item, Player player) {
Pair> dataFromStack = InventoryLinker.getDataFromStack(item);
if (dataFromStack == null) {
return;
}
if (!player.level.dimension().equals(dataFromStack.getValue())) {
return;
}
BlockPos pos = dataFromStack.getKey();
Vec3 renderPos = getMc().gameRenderer.getMainCamera().getPosition()
.subtract(pos.getX(), pos.getY(), pos.getZ())
.add(.005f, .005f, .005f);
MultiBufferSource.BufferSource buffer = Minecraft.getInstance().renderBuffers().bufferSource();
PoseStack stack = evt.getPoseStack();
stack.pushPose();
stack.translate(-renderPos.x(), -renderPos.y(), -renderPos.z());
stack.scale(1.01f, 1.01f, 1.01f);
renderBoxSolid(stack.last().pose(), buffer.getBuffer(OurRenderTypes.BlockOverlay), BlockPos.ZERO, 0, 1, 0, .35f);
stack.popPose();
RenderSystem.disableDepthTest();
buffer.endBatch(); // @mcp: finish (mcp) = draw (yarn)
}
int getEnergy(Player player, ItemStack heldItem) {
LazyOptional energy = heldItem.getCapability(ForgeCapabilities.ENERGY);
if (player.isCreative() || !energy.isPresent())
return Integer.MAX_VALUE;
return energy.map(IEnergyStorage::getEnergyStored).orElse(0);
}
protected static void renderMissingBlock(Matrix4f matrix, VertexConsumer builder, BlockPos pos) {
renderBoxSolid(matrix, builder, pos, 1f, 0f, 0f, 0.35f);
}
protected static void renderBoxSolid(Matrix4f matrix, VertexConsumer builder, BlockPos pos, float r, float g, float b, float alpha) {
double x = pos.getX() - 0.001;
double y = pos.getY() - 0.001;
double z = pos.getZ() - 0.001;
double xEnd = pos.getX() + 1.0015;
double yEnd = pos.getY() + 1.0015;
double zEnd = pos.getZ() + 1.0015;
renderBoxSolid(matrix, builder, x, y, z, xEnd, yEnd, zEnd, r, g, b, alpha);
}
protected static void renderBoxSolid(Matrix4f matrix, VertexConsumer builder, double x, double y, double z, double xEnd, double yEnd, double zEnd, float red, float green, float blue, float alpha) {
//careful: mc want's it's vertices to be defined CCW - if you do it the other way around weird cullling issues will arise
//CCW herby counts as if you were looking at it from the outside
float startX = (float) x;
float startY = (float) y;
float startZ = (float) z;
float endX = (float) xEnd;
float endY = (float) yEnd;
float endZ = (float) zEnd;
// float startX = 0, startY = 0, startZ = -1, endX = 1, endY = 1, endZ = 0;
//down
builder.vertex(matrix, startX, startY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, startY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, startY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, startX, startY, endZ).color(red, green, blue, alpha).endVertex();
//up
builder.vertex(matrix, startX, endY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, startX, endY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, endY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, endY, startZ).color(red, green, blue, alpha).endVertex();
//east
builder.vertex(matrix, startX, startY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, startX, endY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, endY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, startY, startZ).color(red, green, blue, alpha).endVertex();
//west
builder.vertex(matrix, startX, startY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, startY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, endY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, startX, endY, endZ).color(red, green, blue, alpha).endVertex();
//south
builder.vertex(matrix, endX, startY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, endY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, endY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, endX, startY, endZ).color(red, green, blue, alpha).endVertex();
//north
builder.vertex(matrix, startX, startY, startZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, startX, startY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, startX, endY, endZ).color(red, green, blue, alpha).endVertex();
builder.vertex(matrix, startX, endY, startZ).color(red, green, blue, alpha).endVertex();
}
/**
* Can the gadget be linked to other inventories?
*/
public boolean isLinkable() {
return false;
}
static Minecraft getMc() {
return Minecraft.getInstance();
}
static MockBuilderWorld getBuilderWorld() {
return builderWorld;
}
static RemoteInventoryCache getCacheInventory() {
return cacheInventory;
}
public static void setInventoryCache(Multiset cache) {
BaseRenderer.cacheInventory.setCache(cache);
}
public static void updateInventoryCache() {
cacheInventory.forceUpdate();
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/renders/BuildRender.java
================================================
package com.direwolf20.buildinggadgets.client.renders;
import com.direwolf20.buildinggadgets.client.renderer.OurRenderTypes;
import com.direwolf20.buildinggadgets.common.blocks.OurBlocks;
import com.direwolf20.buildinggadgets.common.items.AbstractGadget;
import com.direwolf20.buildinggadgets.common.items.GadgetBuilding;
import com.direwolf20.buildinggadgets.common.items.GadgetExchanger;
import com.direwolf20.buildinggadgets.common.items.modes.AbstractMode;
import com.direwolf20.buildinggadgets.common.tainted.building.BlockData;
import com.direwolf20.buildinggadgets.common.tainted.building.view.BuildContext;
import com.direwolf20.buildinggadgets.common.tainted.inventory.IItemIndex;
import com.direwolf20.buildinggadgets.common.tainted.inventory.InventoryHelper;
import com.direwolf20.buildinggadgets.common.tainted.inventory.MatchResult;
import com.direwolf20.buildinggadgets.common.tainted.inventory.RecordingItemIndex;
import com.direwolf20.buildinggadgets.common.tainted.inventory.materials.MaterialList;
import com.direwolf20.buildinggadgets.common.tainted.inventory.materials.objects.UniqueItem;
import com.direwolf20.buildinggadgets.common.util.helpers.VectorHelper;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.event.RenderLevelStageEvent;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import java.util.List;
import java.util.Optional;
import static com.direwolf20.buildinggadgets.common.util.GadgetUtils.getAnchor;
import static com.direwolf20.buildinggadgets.common.util.GadgetUtils.getToolBlock;
public class BuildRender extends BaseRenderer {
private final boolean isExchanger;
private static final BlockState DEFAULT_EFFECT_BLOCK = OurBlocks.EFFECT_BLOCK.get().defaultBlockState();
public BuildRender(boolean isExchanger) {
this.isExchanger = isExchanger;
}
@Override
public void render(RenderLevelStageEvent evt, Player player, ItemStack heldItem) {
super.render(evt, player, heldItem);
BlockHitResult lookingAt = VectorHelper.getLookingAt(player, heldItem);
BlockState state = AIR;
Optional> anchor = getAnchor(heldItem);
BlockState startBlock = player.level.getBlockState(lookingAt.getBlockPos());
if( (player.level.isEmptyBlock(lookingAt.getBlockPos()) && !anchor.isPresent()) || startBlock == DEFAULT_EFFECT_BLOCK )
return;
BlockData data = getToolBlock(heldItem);
BlockState renderBlockState = data.getState();
if (renderBlockState == BaseRenderer.AIR)
return;
// Get the coordinates from the anchor. If the anchor isn't present then build the collector.
List coordinates = anchor.orElseGet(() -> {
AbstractMode mode = !this.isExchanger ? GadgetBuilding.getToolMode(heldItem).getMode() : GadgetExchanger.getToolMode(heldItem).getMode();
return mode.getCollection(
new AbstractMode.UseContext(player.level, player, renderBlockState, lookingAt.getBlockPos(), heldItem, lookingAt.getDirection(), !this.isExchanger && GadgetBuilding.shouldPlaceAtop(heldItem), !this.isExchanger ? GadgetBuilding.getConnectedArea(heldItem) : GadgetExchanger.getConnectedArea(heldItem)),
player
);
});
// Sort them on a new line for readability
// coordinates = SortingHelper.Blocks.byDistance(coordinates, player);
//Prepare the fake world -- using a fake world lets us render things properly, like fences connecting.
getBuilderWorld().setWorldAndState(player.level, renderBlockState, coordinates);
Vec3 playerPos = getMc().gameRenderer.getMainCamera().getPosition();
MultiBufferSource.BufferSource buffer = Minecraft.getInstance().renderBuffers().bufferSource();
//Save the current position that is being rendered (I think)
PoseStack matrix = evt.getPoseStack();
matrix.pushPose();
matrix.translate(-playerPos.x(), -playerPos.y(), -playerPos.z());
BlockRenderDispatcher dispatcher = getMc().getBlockRenderer();
for (BlockPos coordinate : coordinates) {
matrix.pushPose();
matrix.translate(coordinate.getX(), coordinate.getY(), coordinate.getZ());
if( this.isExchanger ) {
matrix.translate(-0.0005f, -0.0005f, -0.0005f);
matrix.scale(1.001f, 1.001f, 1.001f);
}
// todo: add back from 1.16 port
// if (getBuilderWorld().getWorldType() != WorldType.DEBUG_ALL_BLOCK_STATES) { //Get the block state in the fake world
// try {
state = renderBlockState;
// } catch (Exception ignored) {}
// }
OurRenderTypes.MultiplyAlphaRenderTypeBuffer mutatedBuffer = new OurRenderTypes.MultiplyAlphaRenderTypeBuffer(Minecraft.getInstance().renderBuffers().bufferSource(), .55f);
try {
dispatcher.renderSingleBlock(
state, matrix, mutatedBuffer, 15728640, OverlayTexture.NO_OVERLAY, ModelData.EMPTY, RenderType.solid()
);
} catch (Exception ignored) {} // I'm sure if this is an issue someone will report it
//Move the render position back to where it was
matrix.popPose();
RenderSystem.disableDepthTest();
buffer.endBatch(); // @mcp: finish (mcp) = draw (yarn)
}
// Don't even waste the time checking to see if we have the right energy, items, etc for creative mode
if (!player.isCreative()) {
VertexConsumer builder;
boolean hasLinkedInventory = getCacheInventory().maintainCache(heldItem);
int remainingCached = getCacheInventory().getCache() == null ? -1 : getCacheInventory().getCache().count(new UniqueItem(data.getState().getBlock().asItem()));
// Figure out how many of the block we're rendering we have in the inventory of the player.
IItemIndex index = new RecordingItemIndex(InventoryHelper.index(heldItem, player));
BuildContext context = new BuildContext(player.level, player, heldItem);
MaterialList materials = data.getRequiredItems(context, null, null);
int hasEnergy = getEnergy(player, heldItem);
LazyOptional energyCap = heldItem.getCapability(ForgeCapabilities.ENERGY);
for (BlockPos coordinate : coordinates) { //Now run through the UNSORTED list of coords, to show which blocks won't place if you don't have enough of them.
boolean renderFree = false;
if (energyCap.isPresent())
hasEnergy -= ((AbstractGadget) heldItem.getItem()).getEnergyCost(heldItem);
builder = buffer.getBuffer(OurRenderTypes.MissingBlockOverlay);
MatchResult match = index.tryMatch(materials);
if (!match.isSuccess())
match = index.tryMatch(InventoryHelper.PASTE_LIST);
if (!match.isSuccess() || hasEnergy < 0) {
if (hasLinkedInventory && remainingCached > 0) {
renderFree = true;
remainingCached --;
} else {
renderMissingBlock(matrix.last().pose(), builder, coordinate);
}
} else {
index.applyMatch(match); //notify the recording index that this counts
renderBoxSolid(matrix.last().pose(), builder, coordinate, .97f, 1f, .99f, .1f);
}
if (renderFree) {
renderBoxSolid(matrix.last().pose(), builder, coordinate, .97f, 1f, .99f, .1f);
}
}
}
matrix.popPose();
RenderSystem.disableDepthTest();
buffer.endBatch(); // @mcp: finish (mcp) = draw (yarn)
}
@Override
public boolean isLinkable() {
return true;
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/renders/CopyPasteRender.java
================================================
package com.direwolf20.buildinggadgets.client.renders;
import com.direwolf20.buildinggadgets.client.renderer.DireBufferBuilder;
import com.direwolf20.buildinggadgets.client.renderer.DireVertexBuffer;
import com.direwolf20.buildinggadgets.client.renderer.OurRenderTypes;
import com.direwolf20.buildinggadgets.common.capability.CapabilityTemplate;
import com.direwolf20.buildinggadgets.common.items.GadgetCopyPaste;
import com.direwolf20.buildinggadgets.common.tainted.building.PlacementTarget;
import com.direwolf20.buildinggadgets.common.tainted.building.Region;
import com.direwolf20.buildinggadgets.common.tainted.building.view.BuildContext;
import com.direwolf20.buildinggadgets.common.tainted.building.view.IBuildView;
import com.direwolf20.buildinggadgets.common.tainted.template.ITemplateKey;
import com.direwolf20.buildinggadgets.common.tainted.template.ITemplateProvider;
import com.direwolf20.buildinggadgets.common.tainted.template.ITemplateProvider.IUpdateListener;
import com.direwolf20.buildinggadgets.common.tainted.template.Template;
import com.direwolf20.buildinggadgets.common.world.MockDelegationWorld;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.event.RenderLevelStageEvent;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import java.io.Closeable;
import java.util.*;
import java.util.function.Consumer;
public class CopyPasteRender extends BaseRenderer implements IUpdateListener {
private MultiVBORenderer renderBuffer;
private int tickTrack = 0;
private UUID lastRendered = null;
@Override
public void onTemplateUpdate(ITemplateProvider provider, ITemplateKey key, Template template) {
if (provider.getId(key).equals(lastRendered))
renderBuffer = null;
}
@Override
public void onTemplateUpdateSend(ITemplateProvider provider, ITemplateKey key, Template template) {
onTemplateUpdate(provider, key, template);
}
@Override
public void render(RenderLevelStageEvent evt, Player player, ItemStack heldItem) {
// We can completely trust that heldItem isn't empty and that it's a copy paste gadget.
super.render(evt, player, heldItem);
// Provide this as both renders require the data.
Vec3 cameraView = getMc().gameRenderer.getMainCamera().getPosition();
// translate the matric to the projected view
PoseStack stack = evt.getPoseStack(); //Get current matrix position from the evt call
stack.pushPose(); //Save the render position from RenderWorldLast
stack.translate(-cameraView.x(), -cameraView.y(), -cameraView.z()); //Sets render position to 0,0,0
if (GadgetCopyPaste.getToolMode(heldItem) == GadgetCopyPaste.ToolMode.COPY) {
renderBuffer = null; //fix the surroundings not being taken into account when you've walked around a bit
GadgetCopyPaste.getSelectedRegion(heldItem).ifPresent(region ->
renderCopy(stack, region));
} else
renderPaste(stack, cameraView, player, heldItem);
stack.popPose();
}
private void renderCopy(PoseStack matrix, Region region) {
BlockPos startPos = region.getMin();
BlockPos endPos = region.getMax();
BlockPos blankPos = new BlockPos(0, 0, 0);
if (startPos.equals(blankPos) || endPos.equals(blankPos))
return;
//We want to draw from the starting position to the (ending position)+1
int x = Math.min(startPos.getX(), endPos.getX()), y = Math.min(startPos.getY(), endPos.getY()), z = Math.min(startPos.getZ(), endPos.getZ());
int dx = (startPos.getX() > endPos.getX()) ? startPos.getX() + 1 : endPos.getX() + 1;
int dy = (startPos.getY() > endPos.getY()) ? startPos.getY() + 1 : endPos.getY() + 1;
int dz = (startPos.getZ() > endPos.getZ()) ? startPos.getZ() + 1 : endPos.getZ() + 1;
MultiBufferSource.BufferSource buffer = Minecraft.getInstance().renderBuffers().bufferSource();
VertexConsumer builder = buffer.getBuffer(OurRenderTypes.lines());
matrix.pushPose();
Matrix4f matrix4f = matrix.last().pose();
Matrix3f matrix3f = matrix.last().normal();
builder.vertex(matrix4f, x, y, z).color(0F, 0F, 1F, 1.0F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, z).color(0F, 0F, 1F, 1.0F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, z).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, dy, z).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, z).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, x, y, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, dx, y, z).color(0F, 1F, 0F, 1.0F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, z).color(0F, 1F, 0F, 1.0F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, z).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, -1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, dy, z).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, -1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, dy, z).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, x, dy, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, x, dy, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, dz).color(1F, 0F, 0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, -1.0F).endVertex();
builder.vertex(matrix4f, dx, y, z).color(1F, 0F, 0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, -1.0F).endVertex();
builder.vertex(matrix4f, x, dy, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, z).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, dx, dy, dz).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
buffer.endBatch(); // @mcp: draw = finish
matrix.popPose();
}
private void renderPaste(PoseStack matrices, Vec3 cameraView, Player player, ItemStack heldItem) {
Level world = player.level;
// Check the template cap from the world
// Fetch the template key (because for some reason this is it's own cap)
world.getCapability(CapabilityTemplate.TEMPLATE_PROVIDER_CAPABILITY).ifPresent(provider -> heldItem.getCapability(CapabilityTemplate.TEMPLATE_KEY_CAPABILITY).ifPresent(key -> {
// Finally get the data from the render.
GadgetCopyPaste.getActivePos(player, heldItem).ifPresent(startPos -> {
MockDelegationWorld fakeWorld = new MockDelegationWorld(world);
BuildContext context = BuildContext.builder().player(player).stack(heldItem).build(fakeWorld);
// Get the template and move it to the start pos (player.pick())
IBuildView view = provider.getTemplateForKey(key).createViewInContext(context);
// Sort the render
List targets = new ArrayList<>(view.estimateSize());
for (PlacementTarget target : view) {
if (target.placeIn(context)) {
targets.add(target);
}
}
UUID id = provider.getId(key);
if (! id.equals(lastRendered))
renderBuffer = null;
renderTargets(matrices, cameraView, context, targets, startPos, view);
lastRendered = id;
});
}));
}
private void renderTargets(PoseStack matrix, Vec3 projectedView, BuildContext context, List targets, BlockPos startPos, IBuildView view) {
MultiBufferSource.BufferSource buffer = Minecraft.getInstance().renderBuffers().bufferSource();
VertexConsumer builder = buffer.getBuffer(OurRenderTypes.lines());
matrix.pushPose();
Matrix4f matrix4f = matrix.last().pose();
Matrix3f matrix3f = matrix.last().normal();
Region bb = view.getBoundingBox().translate(startPos.getX(), startPos.getY(), startPos.getZ());
float x = bb.getMinX(), y = bb.getMinY(), z = bb.getMinZ(),
dx = bb.getMaxX() + 1, dy = bb.getMaxY() + 1, dz = bb.getMaxZ() + 1;
builder.vertex(matrix4f, x, y, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, dy, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, x, y, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, dx, y, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, z).color(1F, 1F, 1F, 1F).normal(matrix3f, -1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, dy, z).color(1F, 1F, 1F, 1F).normal(matrix3f, -1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, dy, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, x, dy, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, x, dy, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, -1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, x, y, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, -1.0F).endVertex();
builder.vertex(matrix4f, dx, y, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, -1.0F).endVertex();
builder.vertex(matrix4f, x, dy, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 1.0F, 0.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, y, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex();
builder.vertex(matrix4f, dx, dy, z).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
builder.vertex(matrix4f, dx, dy, dz).color(1F, 1F, 1F, 1F).normal(matrix3f, 0.0F, 0.0F, 1.0F).endVertex();
buffer.endBatch(); // @mcp: draw = finish
matrix.popPose();
// TODO: fix me plz
// tickTrack++;
// if (renderBuffer != null && tickTrack < 300) {
// if (tickTrack % 30 == 0) {
// try {
// Vec3 projectedView2 = projectedView;
// Vec3 startPosView = new Vec3(startPos.getX(), startPos.getY(), startPos.getZ());
// projectedView2 = projectedView2.subtract(startPosView);
// renderBuffer.sort((float) projectedView2.x(), (float) projectedView2.y(), (float) projectedView2.z());
// } catch (Exception ignored) {
// }
// }
//
// matrix.translate(startPos.getX(), startPos.getY(), startPos.getZ());
// renderBuffer.render(matrix.last().pose()); //Actually draw whats in the buffer
// return;
// }
//
//// List blockPosList = sorter.getSortedTargets().stream().map(PlacementTarget::getPos).collect(Collectors.toList());
//
// tickTrack = 0;
// if (renderBuffer != null) //Reset Render Buffer before rebuilding
// renderBuffer.close();
//
// renderBuffer = MultiVBORenderer.of((buffer) -> {
// VertexConsumer builder = buffer.getBuffer(OurRenderTypes.RenderBlock);
// VertexConsumer noDepthbuilder = buffer.getBuffer(OurRenderTypes.CopyPasteRenderBlock);
//
// BlockRenderDispatcher dispatcher = getMc().getBlockRenderer();
//
// PoseStack stack = new PoseStack(); //Create a new matrix stack for use in the buffer building process
// stack.pushPose(); //Save position
//
// for (PlacementTarget target : targets) {
// BlockPos targetPos = target.getPos();
// BlockState state = context.getWorld().getBlockState(target.getPos());
//
// stack.pushPose(); //Save position again
// //matrix.translate(-startPos.getX(), -startPos.getY(), -startPos.getZ());
// stack.translate(targetPos.getX(), targetPos.getY(), targetPos.getZ());
//
// BakedModel ibakedmodel = dispatcher.getBlockModel(state);
// BlockColors blockColors = Minecraft.getInstance().getBlockColors();
// int color = blockColors.getColor(state, context.getWorld(), targetPos, 0);
//
// float f = (float) (color >> 16 & 255) / 255.0F;
// float f1 = (float) (color >> 8 & 255) / 255.0F;
// float f2 = (float) (color & 255) / 255.0F;
// try {
// if (state.getRenderShape() == RenderShape.MODEL) {
// for (Direction direction : Direction.values()) {
// // TODO: likely broken this
// if (Block.shouldRenderFace(state, context.getWorld(), targetPos, direction, target.getPos()) && !(context.getWorld().getBlockState(targetPos.relative(direction)).getBlock().equals(state.getBlock()))) {
// if (state.getMaterial().isSolidBlocking()) {
// renderModelBrightnessColorQuads(stack.last(), builder, f, f1, f2, 0.7f, ibakedmodel.getQuads(state, direction, new Random(Mth.getSeed(targetPos)), EmptyModelData.INSTANCE), 15728640, 655360);
// } else {
// renderModelBrightnessColorQuads(stack.last(), noDepthbuilder, f, f1, f2, 0.7f, ibakedmodel.getQuads(state, direction, new Random(Mth.getSeed(targetPos)), EmptyModelData.INSTANCE), 15728640, 655360);
// }
// }
// }
// if (state.getMaterial().isSolidBlocking())
// renderModelBrightnessColorQuads(stack.last(), builder, f, f1, f2, 0.7f, ibakedmodel.getQuads(state, null, new Random(Mth.getSeed(targetPos)), EmptyModelData.INSTANCE), 15728640, 655360);
// else
// renderModelBrightnessColorQuads(stack.last(), noDepthbuilder, f, f1, f2, 0.7f, ibakedmodel.getQuads(state, null, new Random(Mth.getSeed(targetPos)), EmptyModelData.INSTANCE), 15728640, 655360);
// }
// } catch (Exception e) {
// BuildingGadgets.LOG.trace("Caught exception whilst rendering {}.", state, e);
// }
//
// stack.popPose(); // Load the position we saved earlier
// }
// stack.popPose(); //Load after loop
// });
//// try {
// Vec3 projectedView2 = getMc().gameRenderer.getMainCamera().getPosition();
// Vec3 startPosView = new Vec3(startPos.getX(), startPos.getY(), startPos.getZ());
// projectedView2 = projectedView2.subtract(startPosView);
// renderBuffer.sort((float) projectedView2.x(), (float) projectedView2.y(), (float) projectedView2.z());
//// } catch (Exception ignored) {
//// }
// matrix.translate(startPos.getX(), startPos.getY(), startPos.getZ());
// renderBuffer.render(matrix.last().pose()); //Actually draw whats in the buffer
}
@Override
public boolean isLinkable() {
return true;
}
/**
* Vertex Buffer Object for caching the render. Pretty similar to how the chunk caching works
*/
public static class MultiVBORenderer implements Closeable {
private static final int BUFFER_SIZE = 2 * 1024 * 1024 * 3;
public static MultiVBORenderer of(Consumer vertexProducer) {
final Map builders = Maps.newHashMap();
vertexProducer.accept(rt -> builders.computeIfAbsent(rt, (_rt) -> {
DireBufferBuilder builder = new DireBufferBuilder(BUFFER_SIZE);
builder.begin(_rt.mode().asGLMode, _rt.format());
return builder;
}));
Map sortCaches = Maps.newHashMap();
Map buffers = Maps.transformEntries(builders, (rt, builder) -> {
Objects.requireNonNull(rt);
Objects.requireNonNull(builder);
sortCaches.put(rt, builder.getVertexState());
builder.finishDrawing();
VertexFormat fmt = rt.format();
DireVertexBuffer vbo = new DireVertexBuffer(fmt);
vbo.upload(builder);
return vbo;
});
return new MultiVBORenderer(buffers, sortCaches);
}
private final ImmutableMap buffers;
private final ImmutableMap sortCaches;
protected MultiVBORenderer(Map buffers, Map sortCaches) {
this.buffers = ImmutableMap.copyOf(buffers);
this.sortCaches = ImmutableMap.copyOf(sortCaches);
}
public void sort(float x, float y, float z) {
for (Map.Entry kv : sortCaches.entrySet()) {
RenderType rt = kv.getKey();
DireBufferBuilder.State state = kv.getValue();
DireBufferBuilder builder = new DireBufferBuilder(BUFFER_SIZE);
builder.begin(rt.mode().asGLMode, rt.format());
builder.setVertexState(state);
builder.sortVertexData(x, y, z);
builder.finishDrawing();
DireVertexBuffer vbo = buffers.get(rt);
vbo.upload(builder);
}
}
public void render(Matrix4f matrix) {
buffers.forEach((rt, vbo) -> {
VertexFormat fmt = rt.format();
rt.setupRenderState();
vbo.bindBuffer();
fmt.setupBufferState();
vbo.draw(matrix, rt.mode().asGLMode);
DireVertexBuffer.unbindBuffer();
fmt.clearBufferState();
rt.clearRenderState();
});
}
public void close() {
buffers.values().forEach(DireVertexBuffer::close);
}
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/renders/DestructionRender.java
================================================
package com.direwolf20.buildinggadgets.client.renders;
import com.direwolf20.buildinggadgets.client.renderer.OurRenderTypes;
import com.direwolf20.buildinggadgets.common.blocks.OurBlocks;
import com.direwolf20.buildinggadgets.common.items.AbstractGadget;
import com.direwolf20.buildinggadgets.common.items.GadgetDestruction;
import com.direwolf20.buildinggadgets.common.util.helpers.VectorHelper;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.event.RenderLevelStageEvent;
public class DestructionRender extends BaseRenderer {
@Override
public void render(RenderLevelStageEvent evt, Player player, ItemStack heldItem) {
if (!GadgetDestruction.getOverlay(heldItem))
return;
BlockHitResult lookingAt = VectorHelper.getLookingAt(player, heldItem);
Level world = player.level;
BlockPos anchor = ((AbstractGadget) heldItem.getItem()).getAnchor(heldItem);
if (world.getBlockState(VectorHelper.getLookingAt(player, heldItem).getBlockPos()) == AIR && anchor == null)
return;
BlockPos startBlock = (anchor == null) ? lookingAt.getBlockPos() : anchor;
Direction facing = (GadgetDestruction.getAnchorSide(heldItem) == null) ? lookingAt.getDirection() : GadgetDestruction.getAnchorSide(heldItem);
if (world.getBlockState(startBlock) == OurBlocks.EFFECT_BLOCK.get().defaultBlockState())
return;
Vec3 playerPos = getMc().gameRenderer.getMainCamera().getPosition();
PoseStack stack = evt.getPoseStack();
stack.pushPose();
stack.translate(-playerPos.x(), -playerPos.y(), -playerPos.z());
MultiBufferSource.BufferSource buffer = Minecraft.getInstance().renderBuffers().bufferSource();
VertexConsumer builder = buffer.getBuffer(OurRenderTypes.MissingBlockOverlay);
GadgetDestruction.getArea(world, startBlock, facing, player, heldItem)
.forEach(pos -> renderMissingBlock(stack.last().pose(), builder, pos));
stack.popPose();
RenderSystem.disableDepthTest();
buffer.endBatch(); // @mcp: draw = finish
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/screen/CopyGUI.java
================================================
package com.direwolf20.buildinggadgets.client.screen;
import com.direwolf20.buildinggadgets.client.screen.widgets.GuiIncrementer;
import com.direwolf20.buildinggadgets.common.config.Config;
import com.direwolf20.buildinggadgets.common.items.GadgetCopyPaste;
import com.direwolf20.buildinggadgets.common.network.PacketHandler;
import com.direwolf20.buildinggadgets.common.network.packets.PacketCopyCoords;
import com.direwolf20.buildinggadgets.common.tainted.building.Region;
import com.direwolf20.buildinggadgets.common.util.lang.GuiTranslation;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.AbstractButton;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.resources.language.I18n;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import java.util.ArrayList;
import java.util.List;
public class CopyGUI extends Screen {
private GuiIncrementer startX, startY, startZ, endX, endY, endZ;
private boolean absoluteCoords = Config.GENERAL.absoluteCoordDefault.get() && Config.GENERAL.allowAbsoluteCoords.get();
private int x;
private int y;
private ItemStack copyPasteTool;
private BlockPos startPos;
private BlockPos endPos;
private List fields = new ArrayList<>();
public CopyGUI(ItemStack tool) {
super(Component.literal(""));
this.copyPasteTool = tool;
}
@Override
public void init() {
super.init();
this.fields.clear();
this.x = width / 2;
this.y = height / 2;
Region reg = GadgetCopyPaste.getSelectedRegion(copyPasteTool).orElse(Region.singleZero());
startPos = reg.getMin();
endPos = reg.getMax();
int incrementerWidth = GuiIncrementer.WIDTH + (GuiIncrementer.WIDTH / 2);
fields.add(startX = new GuiIncrementer(x - incrementerWidth - 35, y - 40));
fields.add(startY = new GuiIncrementer(x - GuiIncrementer.WIDTH / 2, y - 40));
fields.add(startZ = new GuiIncrementer(x + (GuiIncrementer.WIDTH / 2) + 35, y - 40));
fields.add(endX = new GuiIncrementer(x - incrementerWidth - 35, y - 15));
fields.add(endY = new GuiIncrementer(x - GuiIncrementer.WIDTH / 2, y - 15));
fields.add(endZ = new GuiIncrementer(x + (GuiIncrementer.WIDTH / 2) + 35, y - 15));
fields.forEach(this::addRenderableWidget);
updateTextFields();
List buttons = new ArrayList() {{
add(new CenteredButton(y + 20, 50, GuiTranslation.SINGLE_CONFIRM.componentTranslation(), (button) -> {
if (absoluteCoords) {
startPos = new BlockPos(startX.getValue(), startY.getValue(), startZ.getValue());
endPos = new BlockPos(endX.getValue(), endY.getValue(), endZ.getValue());
} else {
startPos = new BlockPos(startPos.getX() + startX.getValue(), startPos.getY() + startY.getValue(), startPos.getZ() + startZ.getValue());
endPos = new BlockPos(startPos.getX() + endX.getValue(), startPos.getY() + endY.getValue(), startPos.getZ() + endZ.getValue());
}
PacketHandler.sendToServer(new PacketCopyCoords(startPos, endPos));
}));
add(new CenteredButton(y + 20, 50, GuiTranslation.SINGLE_CLOSE.componentTranslation(), (button) -> onClose()));
add(new CenteredButton(y + 20, 50, GuiTranslation.SINGLE_CLEAR.componentTranslation(), (button) -> {
PacketHandler.sendToServer(new PacketCopyCoords(BlockPos.ZERO, BlockPos.ZERO));
onClose();
}));
if (Config.GENERAL.allowAbsoluteCoords.get()) {
add(new CenteredButton(y + 20, 120, GuiTranslation.COPY_BUTTON_ABSOLUTE.componentTranslation(), (button) -> {
coordsModeSwitch();
updateTextFields();
}));
}
}};
CenteredButton.centerButtonList(buttons, x);
buttons.forEach(this::addRenderableWidget);
}
private void drawFieldLabel(PoseStack matrices, String name, int x, int y) {
font.drawShadow(matrices, name, this.x + x, this.y + y, 0xFFFFFF);
}
private void coordsModeSwitch() {
absoluteCoords = !absoluteCoords;
}
private void updateTextFields() {
if (absoluteCoords) {
BlockPos start = startX.getValue() != 0 ? new BlockPos(startPos.getX() + startX.getValue(), startPos.getY() + startY.getValue(), startPos.getZ() + startZ.getValue()) : startPos;
BlockPos end = endX.getValue() != 0 ? new BlockPos(startPos.getX() + endX.getValue(), startPos.getY() + endY.getValue(), startPos.getZ() + endZ.getValue()) : endPos;
startX.setValue(start.getX());
startY.setValue(start.getY());
startZ.setValue(start.getZ());
endX.setValue(end.getX());
endY.setValue(end.getY());
endZ.setValue(end.getZ());
} else {
startX.setValue(startX.getValue() != 0 ? startX.getValue() - startPos.getX() : 0);
startY.setValue(startY.getValue() != 0 ? startY.getValue() - startPos.getY() : 0);
startZ.setValue(startZ.getValue() != 0 ? startZ.getValue() - startPos.getZ() : 0);
endX.setValue(endX.getValue() != 0 ? endX.getValue() - startPos.getX() : endPos.getX() - startPos.getX());
endY.setValue(endY.getValue() != 0 ? endY.getValue() - startPos.getY() : endPos.getY() - startPos.getY());
endZ.setValue(endZ.getValue() != 0 ? endZ.getValue() - startPos.getZ() : endPos.getZ() - startPos.getZ());
}
}
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float partialTicks) {
drawFieldLabel(matrices, GuiTranslation.FIELD_START.format() + " X", -175, -36);
drawFieldLabel(matrices, "Y", -45, -36);
drawFieldLabel(matrices, "Z", 55, -36);
drawFieldLabel(matrices, GuiTranslation.FIELD_END.format() + " X", 8 - 175, -11);
drawFieldLabel(matrices, "Y", -45, -11);
drawFieldLabel(matrices, "Z", 55, -11);
drawCenteredString(matrices, Minecraft.getInstance().font, I18n.get(GuiTranslation.COPY_LABEL_HEADING.getTranslationKey()), this.x, this.y - 80, 0xFFFFFF);
drawCenteredString(matrices, Minecraft.getInstance().font, I18n.get(GuiTranslation.COPY_LABEL_SUBHEADING.getTranslationKey()), this.x, this.y - 68, 0xFFFFFF);
super.render(matrices, mouseX, mouseY, partialTicks);
}
@Override
public boolean keyPressed(int mouseX, int mouseY, int __unused) {
fields.forEach(button -> button.keyPressed(mouseX, mouseY, __unused));
return super.keyPressed(mouseX, mouseY, __unused);
}
@Override
public boolean charTyped(char charTyped, int __unused) {
fields.forEach(button -> button.charTyped(charTyped, __unused));
return false;
}
@Override
public boolean isPauseScreen() {
return false;
}
static class CenteredButton extends Button {
CenteredButton(int y, int width, Component text, OnPress onPress) {
super(builder(text, onPress)
.pos(0, y)
.size(width, 20)
);
}
static void centerButtonList(List buttons, int startX) {
int collectiveWidth = buttons.stream().mapToInt(AbstractButton::getWidth).sum() + (buttons.size() - 1) * 5;
int nextX = startX - collectiveWidth / 2;
for (AbstractButton button : buttons) {
button.setX(nextX);
nextX += button.getWidth() + 5;
}
}
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/screen/DestructionGUI.java
================================================
package com.direwolf20.buildinggadgets.client.screen;
import com.direwolf20.buildinggadgets.client.screen.widgets.IncrementalSliderWidget;
import com.direwolf20.buildinggadgets.common.config.Config;
import com.direwolf20.buildinggadgets.common.items.GadgetDestruction;
import com.direwolf20.buildinggadgets.common.network.PacketHandler;
import com.direwolf20.buildinggadgets.common.network.packets.PacketDestructionGUI;
import com.direwolf20.buildinggadgets.common.util.lang.GuiTranslation;
import com.direwolf20.buildinggadgets.common.util.lang.MessageTranslation;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Set;
public class DestructionGUI extends Screen {
private final Set sliders = new HashSet<>();
private IncrementalSliderWidget left;
private IncrementalSliderWidget right;
private IncrementalSliderWidget up;
private IncrementalSliderWidget down;
private IncrementalSliderWidget depth;
private Button confirm;
private String sizeString = "";
private boolean isValidSize = true;
private final ItemStack destructionGadget;
public DestructionGUI(ItemStack tool) {
super(Component.empty());
this.destructionGadget = tool;
}
@Override
public void init() {
super.init();
int x = width / 2;
int y = height / 2;
this.addRenderableWidget(confirm = Button.builder(Component.translatable(GuiMod.getLangKeySingle("confirm")), b -> {
if (Minecraft.getInstance().player == null) {
return;
}
if (isWithinBounds()) {
PacketHandler.sendToServer(new PacketDestructionGUI(left.getValueInt(), right.getValueInt(), up.getValueInt(), down.getValueInt(), depth.getValueInt()));
this.onClose();
} else
Minecraft.getInstance().player.displayClientMessage(MessageTranslation.DESTRCUT_TOO_LARGE.componentTranslation(Config.GADGETS.GADGET_DESTRUCTION.destroySize.get()), true);
})
.pos((x - 30) + 32, y + 65)
.size(60, 20)
.build());
this.addRenderableWidget(Button.builder(Component.translatable(GuiMod.getLangKeySingle("cancel")), b -> onClose())
.pos((x - 30) - 32, y + 65)
.size(60, 20)
.build());
sliders.clear();
sliders.add(depth = this.createSlider(x - (70 / 2), y - (14 / 2), GuiTranslation.SINGLE_DEPTH, GadgetDestruction.getToolValue(destructionGadget, "depth")));
sliders.add(right = this.createSlider(x + (70 + 5), y - (14 / 2), GuiTranslation.SINGLE_RIGHT, GadgetDestruction.getToolValue(destructionGadget, "right")));
sliders.add(left = this.createSlider(x - (70 * 2) - 5, y - (14 / 2), GuiTranslation.SINGLE_LEFT, GadgetDestruction.getToolValue(destructionGadget, "left")));
sliders.add(up = this.createSlider(x - (70 / 2), y - 35, GuiTranslation.SINGLE_UP, GadgetDestruction.getToolValue(destructionGadget, "up")));
sliders.add(down = this.createSlider(x - (70 / 2), y + 20, GuiTranslation.SINGLE_DOWN, GadgetDestruction.getToolValue(destructionGadget, "down")));
updateSizeString();
updateIsValid();
// Adds their buttons to the gui
sliders.forEach(gui -> gui.getComponents().forEach(this::addRenderableWidget));
}
public IncrementalSliderWidget createSlider(int x, int y, GuiTranslation prefix, int value) {
return new IncrementalSliderWidget(x, y, 70, 14, 0D, 16D, prefix.componentTranslation().append(": "), value, this::onSliderUpdate);
}
public void onSliderUpdate(IncrementalSliderWidget widget) {
this.updateSizeString();
this.updateIsValid();
}
private boolean isWithinBounds() {
int x = 1 + left.getValueInt() + right.getValueInt();
int y = 1 + up.getValueInt() + down.getValueInt();
int z = depth.getValueInt();
int dim = Config.GADGETS.GADGET_DESTRUCTION.destroySize.get();
return x <= (dim + 1) && y <= (dim + 1) && z <= dim;
}
private String getSizeString() {
int x = 1 + left.getValueInt() + right.getValueInt();
int y = 1 + up.getValueInt() + down.getValueInt();
int z = depth.getValueInt();
return String.format("%d x %d x %d", x, y, z);
}
private void updateIsValid() {
this.isValidSize = isWithinBounds();
if (!isValidSize && this.confirm.active) {
this.confirm.setFGColor(0xFF2000);
this.confirm.active = false;
}
if (isValidSize && !this.confirm.active) {
this.confirm.clearFGColor();
this.confirm.active = true;
}
}
private void updateSizeString() {
this.sizeString = getSizeString();
}
@Override
public void render(@Nonnull PoseStack matrices, int mouseX, int mouseY, float partialTicks) {
super.render(matrices, mouseX, mouseY, partialTicks);
drawCenteredString(matrices, font, this.sizeString, width / 2, (height / 2) + 40, this.isValidSize ? 0x00FF00 : 0xFF2000);
if (!this.isValidSize) {
drawCenteredString(matrices, font, MessageTranslation.DESTRCUT_TOO_LARGE.format(Config.GADGETS.GADGET_DESTRUCTION.destroySize.get()), width / 2, (height / 2) + 50, 0xFF2000);
}
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int mouseButton) {
return super.mouseReleased(mouseX, mouseY, mouseButton);
}
@Override
public boolean isPauseScreen() {
return false;
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/screen/GuiMod.java
================================================
package com.direwolf20.buildinggadgets.client.screen;
import com.direwolf20.buildinggadgets.common.items.GadgetCopyPaste;
import com.direwolf20.buildinggadgets.common.items.GadgetDestruction;
import com.direwolf20.buildinggadgets.common.items.TemplateItem;
import com.direwolf20.buildinggadgets.common.util.lang.LangUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import java.util.function.Function;
import java.util.function.Supplier;
public enum GuiMod {
COPY(GadgetCopyPaste::getGadget, stack -> () -> new CopyGUI(stack)),
PASTE(GadgetCopyPaste::getGadget, stack -> () -> new PasteGUI(stack)),
DESTRUCTION(GadgetDestruction::getGadget, stack -> () -> new DestructionGUI(stack)),
MATERIAL_LIST(TemplateItem::getTemplateItem, stack -> () -> new MaterialListGUI(stack));
private final Function stackReader;
private final Function> clientScreenProvider;
GuiMod(Function stackReader, Function> clientScreenProvider) {
this.stackReader = stackReader;
this.clientScreenProvider = clientScreenProvider;
}
public boolean openScreen(Player player) {
if (clientScreenProvider == null)
return false;
ItemStack stack = stackReader.apply(player);
if (stack == null || stack.isEmpty())
return false;
Screen screen = clientScreenProvider.apply(stack).get();
Minecraft.getInstance().setScreen(screen);
return screen == null;
}
public static String getLangKeySingle(String name) {
return LangUtil.getLangKey("gui", "single", name);
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/screen/MaterialListGUI.java
================================================
package com.direwolf20.buildinggadgets.client.screen;
import com.direwolf20.buildinggadgets.common.BuildingGadgets;
import com.direwolf20.buildinggadgets.common.capability.CapabilityTemplate;
import com.direwolf20.buildinggadgets.common.tainted.building.view.BuildContext;
import com.direwolf20.buildinggadgets.common.tainted.template.ITemplateKey;
import com.direwolf20.buildinggadgets.common.tainted.template.ITemplateProvider;
import com.direwolf20.buildinggadgets.common.tainted.template.Template;
import com.direwolf20.buildinggadgets.common.tainted.template.TemplateHeader;
import com.direwolf20.buildinggadgets.common.util.lang.MaterialListTranslation;
import com.direwolf20.buildinggadgets.common.util.ref.Reference;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.util.LazyOptional;
import java.awt.*;
import java.util.List;
import java.util.UUID;
public class MaterialListGUI extends Screen implements ITemplateProvider.IUpdateListener {
public static final int BUTTON_HEIGHT = 20;
public static final int BUTTONS_PADDING = 4;
public static final ResourceLocation BACKGROUND_TEXTURE = new ResourceLocation(Reference.MODID, "textures/gui/material_list.png");
public static final int BACKGROUND_WIDTH = 256;
public static final int BACKGROUND_HEIGHT = 200;
public static final int BORDER_SIZE = 4;
public static final int WINDOW_WIDTH = BACKGROUND_WIDTH - BORDER_SIZE * 2;
public static final int WINDOW_HEIGHT = BACKGROUND_HEIGHT - BORDER_SIZE * 2;
private int backgroundX;
private int backgroundY;
private ItemStack item;
private String title;
private int titleLeft;
private int titleTop;
private ScrollingMaterialList scrollingList;
private Button buttonClose;
private Button buttonSortingModes;
private Button buttonCopyList;
private int hoveringTextX;
private int hoveringTextY;
private List hoveringText;
private TemplateHeader header;
public MaterialListGUI(ItemStack item) {
super(MaterialListTranslation.TITLE.componentTranslation());
Preconditions.checkArgument(item.getCapability(CapabilityTemplate.TEMPLATE_KEY_CAPABILITY).isPresent());
this.item = item;
}
@Override
public void init() {
this.backgroundX = getXForAlignedCenter(0, width, BACKGROUND_WIDTH);
this.backgroundY = getYForAlignedCenter(0, height, BACKGROUND_HEIGHT);
header = evaluateTemplateHeader();
evaluateTitle();
this.scrollingList = new ScrollingMaterialList(this);
// Make it receive mouse scroll events, so that the player can use his mouse wheel at the start
this.setFocused(scrollingList);
this.addRenderableWidget(scrollingList);
int buttonY = getWindowBottomY() - (ScrollingMaterialList.BOTTOM / 2 + BUTTON_HEIGHT / 2);
this.buttonClose = Button.builder(MaterialListTranslation.BUTTON_CLOSE.componentTranslation(), b -> getMinecraft().player.closeContainer())
.pos(0, buttonY)
.size( 0, BUTTON_HEIGHT)
.build();
this.buttonSortingModes = Button.builder(scrollingList.getSortingMode().getTranslationProvider().componentTranslation(), (button) -> {
scrollingList.setSortingMode(scrollingList.getSortingMode().next());
buttonSortingModes.setMessage(scrollingList.getSortingMode().getTranslationProvider().componentTranslation());
})
.pos(0, buttonY)
.size(0, BUTTON_HEIGHT)
.build();
this.buttonCopyList = Button.builder(MaterialListTranslation.BUTTON_COPY.componentTranslation(), (button) -> {
getMinecraft().keyboardHandler.setClipboard(evaluateTemplateHeader().toJson(false, hasControlDown()));
if (getMinecraft().player != null)
getMinecraft().player.displayClientMessage(Component.translatable(MaterialListTranslation.MESSAGE_COPY_SUCCESS.getTranslationKey()), true);
})
.pos(0, buttonY)
.size(0, BUTTON_HEIGHT)
.build();
// Buttons will be placed left to right in this order
this.addRenderableWidget(buttonSortingModes);
this.addRenderableWidget(buttonCopyList);
this.addRenderableWidget(buttonClose);
this.calculateButtonsWidthAndX();
}
public TemplateHeader evaluateTemplateHeader() {
Template template = getTemplateCapability();
BuildContext context = BuildContext.builder()
.player(getMinecraft().player)
.stack(getTemplateItem())
.build(getMinecraft().level);
return template.getHeaderAndForceMaterials(context);
}
public TemplateHeader getHeader() {
return header;
}
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float particleTicks) {
RenderSystem.setShaderTexture(0, BACKGROUND_TEXTURE);
blit(matrices, backgroundX, backgroundY, 0, 0, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); // TODO: Might be wrong
scrollingList.render(matrices, mouseX, mouseY, particleTicks);
drawString(matrices, font, title, titleLeft, titleTop, Color.WHITE.getRGB());
super.render(matrices, mouseX, mouseY, particleTicks);
if (buttonCopyList.isMouseOver(mouseX, mouseY)) {
renderTooltip(matrices, Lists.transform(ImmutableList.of(MaterialListTranslation.HELP_COPY_LIST.componentTranslation()), Component::getVisualOrderText), mouseX, mouseY);
// GuiUtils.drawHoveringText(matrices, ImmutableList.of(MaterialListTranslation.HELP_COPY_LIST.componentTranslation()), mouseX, mouseY, width, height, Integer.MAX_VALUE, textRenderer);
} else if (hoveringText != null) {
renderTooltip(matrices, Lists.transform(hoveringText, Component::getVisualOrderText), mouseX, mouseY);
// GuiUtils.drawHoveringText(matrices, hoveringText, hoveringTextX, hoveringTextY, width, height, Integer.MAX_VALUE, textRenderer);
hoveringText = null;
}
}
private void calculateButtonsWidthAndX() {
// This part would can create narrower buttons when there are too few of them, due to the vanilla button texture is 200 pixels wide
int amountButtons = (int) children().stream().filter(e -> e instanceof Button).count();
int amountMargins = amountButtons - 1;
int totalMarginWidth = amountMargins * BUTTONS_PADDING;
int usableWidth = getWindowWidth();
int buttonWidth = (usableWidth - totalMarginWidth) / amountButtons;
// Align the box of buttons in the center, and start from the left
int nextX = getWindowLeftX();
for (GuiEventListener widget : children()) {
if (widget instanceof Button btn) {
btn.setWidth(buttonWidth);
btn.setX(nextX);
nextX += buttonWidth + BUTTONS_PADDING;
}
}
}
public Template getTemplateCapability() {
if (getMinecraft().level == null || getMinecraft().player == null)
return null;
LazyOptional providerCap = getMinecraft().level.getCapability(CapabilityTemplate.TEMPLATE_PROVIDER_CAPABILITY);
if (providerCap.isPresent()) {
LazyOptional keyCap = item.getCapability(CapabilityTemplate.TEMPLATE_KEY_CAPABILITY);
ITemplateProvider provider = providerCap.orElseThrow(RuntimeException::new);
if (keyCap.isPresent()) {
provider.registerUpdateListener(this);
ITemplateKey key = keyCap.orElseThrow(RuntimeException::new);
return provider.getTemplateForKey(key);
}
BuildingGadgets.LOG.warn("Item used for material list does not have an ITemplateKey capability!");
getMinecraft().player.closeContainer();
return null;
}
BuildingGadgets.LOG.warn("Client world used for material list does not have an ITemplateProvider capability!");
getMinecraft().player.closeContainer();
return null;
}
public void setTaskHoveringText(int x, int y, List text) {
hoveringTextX = x;
hoveringTextY = y;
hoveringText = text;
}
@Override
public void onTemplateUpdate(ITemplateProvider provider, ITemplateKey key, Template template) {
item.getCapability(CapabilityTemplate.TEMPLATE_KEY_CAPABILITY).ifPresent(itemKey -> {
UUID keyId = provider.getId(key);
UUID itemId = provider.getId(itemKey);
if (keyId.equals(itemId)) {
header = evaluateTemplateHeader();
evaluateTitle();
scrollingList.reset();
}
});
}
private void evaluateTitle() {
String name = getHeader().getName();
String author = getHeader().getAuthor();
this.title = name == null && author == null ? MaterialListTranslation.TITLE_EMPTY.format()
: name == null ? MaterialListTranslation.TITLE_AUTHOR_ONLY.format(author)
: author == null ? MaterialListTranslation.TITLE_NAME_ONLY.format(name)
: MaterialListTranslation.TITLE.format(name, author);
this.titleTop = getYForAlignedCenter(backgroundY, getWindowTopY() + ScrollingMaterialList.TOP, font.lineHeight);
this.titleLeft = getXForAlignedCenter(backgroundX, getWindowRightX(), font.width(title));
}
@Override
public boolean isPauseScreen() {
return false;
}
public int getWindowLeftX() {
return backgroundX + BORDER_SIZE;
}
public int getWindowRightX() {
return backgroundX + BACKGROUND_WIDTH - BORDER_SIZE;
}
public int getWindowTopY() {
return backgroundY + BORDER_SIZE;
}
public int getWindowBottomY() {
return backgroundY + BACKGROUND_HEIGHT - BORDER_SIZE;
}
public int getWindowWidth() {
return WINDOW_WIDTH;
}
public int getWindowHeight() {
return WINDOW_HEIGHT;
}
public ItemStack getTemplateItem() {
return item;
}
public static int getXForAlignedRight(int right, int width) {
return right - width;
}
public static int getXForAlignedCenter(int left, int right, int width) {
return left + (right - left) / 2 - width / 2;
}
public static int getYForAlignedCenter(int top, int bottom, int height) {
return top + (bottom - top) / 2 - height / 2;
}
public static void renderTextVerticalCenter(PoseStack matrices, String text, int leftX, int top, int bottom, int color) {
Font fontRenderer = Minecraft.getInstance().font;
int y = getYForAlignedCenter(top, bottom, fontRenderer.lineHeight);
fontRenderer.draw(matrices, text, leftX, y, color);
}
public static void renderTextHorizontalRight(PoseStack matrices, String text, int right, int y, int color) {
Font fontRenderer = Minecraft.getInstance().font;
int x = getXForAlignedRight(right, fontRenderer.width(text));
fontRenderer.draw(matrices, text, x, y, color);
}
public static boolean isPointInBox(double x, double y, int bx, int by, int width, int height) {
return x >= bx &&
y >= by &&
x < bx + width &&
y < by + height;
}
}
================================================
FILE: src/main/java/com/direwolf20/buildinggadgets/client/screen/ModeRadialMenu.java
================================================
/**
* This class was adapted from code written by Vazkii for the PSI mod: https://github.com/Vazkii/Psi
* Psi is Open Source and distributed under the
* Psi License: http://psi.vazkii.us/license.php
*/
package com.direwolf20.buildinggadgets.client.screen;
import com.direwolf20.buildinggadgets.client.KeyBindings;
import com.direwolf20.buildinggadgets.client.OurSounds;
import com.direwolf20.buildinggadgets.client.renderer.OurRenderTypes;
import com.direwolf20.buildinggadgets.client.screen.widgets.GuiIconActionable;
import com.direwolf20.buildinggadgets.client.screen.widgets.IncrementalSliderWidget;
import com.direwolf20.buildinggadgets.common.config.Config;
import com.direwolf20.buildinggadgets.common.items.*;
import com.direwolf20.buildinggadgets.common.items.modes.BuildingModes;
import com.direwolf20.buildinggadgets.common.items.modes.ExchangingModes;
import com.direwolf20.buildinggadgets.common.network.PacketHandler;
import com.direwolf20.buildinggadgets.common.network.packets.*;
import com.direwolf20.buildinggadgets.common.util.GadgetUtils;
import com.direwolf20.buildinggadgets.common.util.lang.GuiTranslation;
import com.direwolf20.buildinggadgets.common.util.lang.MessageTranslation;
import com.direwolf20.buildinggadgets.common.util.lang.RadialTranslation;
import com.direwolf20.buildinggadgets.common.util.lang.Styles;
import com.direwolf20.buildinggadgets.common.util.ref.Reference;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.ForgeI18n;
import org.joml.Matrix4f;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class ModeRadialMenu extends Screen {
private static final ImmutableList signsCopyPaste = ImmutableList.of(
new ResourceLocation(Reference.MODID, "textures/gui/mode/copy.png"),
new ResourceLocation(Reference.MODID, "textures/gui/mode/paste.png")
);
private final List