diff --git a/src/main/java/com/cleanroommc/modularui/test/ResizerTest.java b/src/main/java/com/cleanroommc/modularui/test/ResizerTest.java index fc965122f..462bf0b30 100644 --- a/src/main/java/com/cleanroommc/modularui/test/ResizerTest.java +++ b/src/main/java/com/cleanroommc/modularui/test/ResizerTest.java @@ -3,12 +3,15 @@ import com.cleanroommc.modularui.screen.CustomModularScreen; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.viewport.GuiContext; -import com.cleanroommc.modularui.utils.fakeworld.BlockInfo; -import com.cleanroommc.modularui.utils.fakeworld.BoxSchema; -import com.cleanroommc.modularui.utils.fakeworld.SchemaRenderer; +import com.cleanroommc.modularui.utils.fakeworld.*; + +import com.cleanroommc.modularui.widgets.SchemaWidget; import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; +import net.minecraft.init.MobEffects; +import net.minecraft.potion.Potion; +import net.minecraft.tileentity.TileEntityBeacon; import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.NotNull; @@ -29,7 +32,7 @@ public class ResizerTest extends CustomModularScreen { world.addBlock(new BlockPos(0, 0, 0), new BlockInfo(Blocks.DIAMOND_BLOCK.getDefaultState())); world.addBlock(new BlockPos(0, 1, 0), new BlockInfo(Blocks.BEDROCK.getDefaultState())); world.addBlock(new BlockPos(1, 0, 1), new BlockInfo(Blocks.GOLD_BLOCK.getDefaultState()));*/ - return ModularPanel.defaultPanel("main") +/* return ModularPanel.defaultPanel("main") .size(150) .overlay(new SchemaRenderer(BoxSchema.of(Minecraft.getMinecraft().world, new BlockPos(Minecraft.getMinecraft().player), 5)) .cameraFunc((camera, schema) -> { @@ -39,6 +42,34 @@ public class ResizerTest extends CustomModularScreen { camera.setLookAt(new BlockPos(Minecraft.getMinecraft().player), 20, yaw, pitch); }) .isometric(true) - .asIcon().size(140)); + .asIcon().size(140));*/ + + var plane = ModularPanel.defaultPanel("main").size(170); + + SimpleSchema world = new SimpleSchema.Builder() + .add(new BlockPos(0, 0, 0), Blocks.DIAMOND_BLOCK.getDefaultState()) + .add(new BlockPos(0, 1, 0), Blocks.BEDROCK.getDefaultState()) + .add(new BlockPos(0, 2, 0), Blocks.WOOL.getDefaultState()) + .add(new BlockPos(1, 0, 1), Blocks.GOLD_BLOCK.getDefaultState()) + .add(new BlockPos(0, 3, 0), Blocks.BEACON.getDefaultState()) + .build(); + + var schemaRenderer = new SchemaRenderer(world); + var layerUpDown = new SchemaWidget.LayerUpDown(); + world.setRenderFilter(layerUpDown.makeSchemaFilter()); + world.applyRenderFilter(); + + plane.child(layerUpDown.bottom(1).left(1).size(16)); + + var disableTESR = new SchemaWidget.DisableTESR().bottom(1).left(18).size(16); + schemaRenderer.disableTESR(disableTESR.makeSuppler()); + plane.child(disableTESR); + + + var shnemaW = new SchemaWidget(schemaRenderer).size(120); + plane.child(shnemaW); + + return plane; } -} + + } diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/BoxSchema.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/BoxSchema.java index 3cbfa74d9..5daa2a9bb 100644 --- a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/BoxSchema.java +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/BoxSchema.java @@ -4,18 +4,24 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import java.util.function.BiPredicate; + public class BoxSchema extends PosListSchema { public static BoxSchema of(World world, BlockPos center, int r) { - return new BoxSchema(world, center.add(-r, -r, -r), center.add(r, r, r)); + return new BoxSchema(world, center.add(-r, -r, -r), center.add(r, r, r), (blockPos, blockInfo) -> true); + } + + public static BoxSchema of(World world, BlockPos center, int r, BiPredicate renderFilter) { + return new BoxSchema(world, center.add(-r, -r, -r), center.add(r, r, r), renderFilter); } private final World world; private final BlockPos min, max; private final Vec3d center; - public BoxSchema(World world, BlockPos min, BlockPos max) { - super(world, BlockPosUtil.getAllInside(min, max, false)); + public BoxSchema(World world, BlockPos min, BlockPos max, BiPredicate renderFilter) { + super(world, BlockPosUtil.getAllInside(min, max, false), renderFilter); this.world = world; this.min = BlockPosUtil.getMin(min, max); this.max = BlockPosUtil.getMax(min, max); diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/IFilteredSchema.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/IFilteredSchema.java new file mode 100644 index 000000000..fa41b36d4 --- /dev/null +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/IFilteredSchema.java @@ -0,0 +1,19 @@ +package com.cleanroommc.modularui.utils.fakeworld; + +import net.minecraft.util.math.BlockPos; + +import org.jetbrains.annotations.NotNull; + +import java.util.function.BiPredicate; + +/** + * This schema gets filtered on insertion.

+ * If the filter changes, it will not get applied to ealready set blocks + */ +public interface IFilteredSchema extends ISchema { + + void setRenderFilter(@NotNull BiPredicate renderFilter); + + @NotNull BiPredicate getRenderFilter(); + +} diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/IMemorizingFilteredSchema.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/IMemorizingFilteredSchema.java new file mode 100644 index 000000000..28c618d59 --- /dev/null +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/IMemorizingFilteredSchema.java @@ -0,0 +1,17 @@ +package com.cleanroommc.modularui.utils.fakeworld; + +import net.minecraft.util.math.BlockPos; + +import org.jetbrains.annotations.Unmodifiable; + +import java.util.Map; + +/** + * This schema gets filtered on insertion.

+ * If the filter changes, it will need to manually call {@link IMemorizingFilteredSchema#applyRenderFilter()} + */ +public interface IMemorizingFilteredSchema extends IFilteredSchema { + + @Unmodifiable Map getOriginalSchema(); + void applyRenderFilter(); +} diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/ISchema.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/ISchema.java index 074dcdd29..065ecc63c 100644 --- a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/ISchema.java +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/ISchema.java @@ -7,6 +7,8 @@ import org.apache.commons.lang3.tuple.Pair; import java.util.Map; +import java.util.function.BiPredicate; +import java.util.function.Consumer; public interface ISchema extends Iterable> { @@ -15,4 +17,5 @@ public interface ISchema extends Iterable> { Vec3d getFocus(); BlockPos getOrigin(); + } diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/PosListSchema.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/PosListSchema.java index b8a634251..db5dc0195 100644 --- a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/PosListSchema.java +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/PosListSchema.java @@ -9,15 +9,28 @@ import java.util.Iterator; import java.util.Map; +import java.util.function.BiPredicate; -public abstract class PosListSchema implements ISchema { +public abstract class PosListSchema implements IFilteredSchema { private final World world; private final Iterable posList; + private BiPredicate renderFilter; - public PosListSchema(World world, Iterable posList) { + public PosListSchema(World world, Iterable posList, BiPredicate renderFilter) { this.world = world; this.posList = posList; + this.renderFilter = renderFilter; + } + + @Override + public void setRenderFilter(@NotNull BiPredicate renderFilter) { + this.renderFilter = renderFilter; + } + + @Override + public @NotNull BiPredicate getRenderFilter() { + return renderFilter; } @Override @@ -42,7 +55,10 @@ public boolean hasNext() { public Pair next() { BlockPos pos = posIt.next(); pair.setLeft(pos); - pair.setRight(BlockInfo.Mut.SHARED.set(PosListSchema.this.world, pos)); + BlockInfo.Mut.SHARED.set(PosListSchema.this.world, pos); + if (renderFilter.test(pos, BlockInfo.Mut.SHARED)) { + pair.setRight(BlockInfo.Mut.SHARED); + } else pair.setRight(BlockInfo.EMPTY); return pair; } }; diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaRenderer.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaRenderer.java index 5760b9b9e..be3a36e68 100644 --- a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaRenderer.java +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaRenderer.java @@ -24,10 +24,14 @@ import org.lwjgl.opengl.EXTFramebufferObject; import org.lwjgl.opengl.GL11; import org.lwjgl.util.glu.GLU; +import org.lwjgl.util.vector.ReadableVector3f; import org.lwjgl.util.vector.Vector3f; +import java.util.Objects; import java.util.function.BiConsumer; +import java.util.function.BooleanSupplier; import java.util.function.Consumer; +import java.util.function.DoubleSupplier; public class SchemaRenderer implements IDrawable { @@ -37,6 +41,8 @@ public class SchemaRenderer implements IDrawable { private final Framebuffer framebuffer; private final Camera camera = new Camera(new Vector3f(), new Vector3f()); private boolean cameraSetup = false; + private DoubleSupplier scale; + private BooleanSupplier disableTESR; private Consumer onRayTrace; private Consumer afterRender; private BiConsumer cameraFunc; @@ -72,6 +78,24 @@ public SchemaRenderer isometric(boolean isometric) { return this; } + public SchemaRenderer scale(double scale) { + return scale(() -> scale); + } + + public SchemaRenderer scale(DoubleSupplier scale) { + this.scale = scale; + return this; + } + + public SchemaRenderer disableTESR(boolean disable) { + return disableTESR(() -> disable); + } + + public SchemaRenderer disableTESR(BooleanSupplier disable) { + this.disableTESR = disable; + return this; + } + @Override public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { render(x, y, width, height, context.getMouseX(), context.getMouseY()); @@ -81,6 +105,14 @@ public void render(int x, int y, int width, int height, int mouseX, int mouseY) if (this.cameraFunc != null) { this.cameraFunc.accept(this.camera, this.schema); } + if (Objects.nonNull(scale)) { + Vector3f cameraPos = camera.getPos(); + Vector3f looking = camera.getLookAt(); + Vector3f.sub(cameraPos, looking, cameraPos); + if (cameraPos.length() != 0.0f) cameraPos.normalise(); + cameraPos.scale((float) scale.getAsDouble()); + Vector3f.add(looking, cameraPos, cameraPos); + } int lastFbo = bindFBO(); setupCamera(this.framebuffer.framebufferWidth, this.framebuffer.framebufferHeight); renderWorld(); @@ -159,18 +191,20 @@ private void renderWorld() { GlStateManager.enableLighting(); // render TESR - for (int pass = 0; pass < 2; pass++) { - ForgeHooksClient.setRenderPass(pass); - int finalPass = pass; - GlStateManager.color(1, 1, 1, 1); - setDefaultPassRenderState(pass); - this.schema.forEach(pair -> { - BlockPos pos = pair.getKey(); - TileEntity tile = pair.getValue().getTileEntity(); - if (tile != null && tile.shouldRenderInPass(finalPass)) { - TileEntityRendererDispatcher.instance.render(tile, pos.getX(), pos.getY(), pos.getZ(), 0); - } - }); + if (disableTESR == null || !disableTESR.getAsBoolean()) { + for (int pass = 0; pass < 2; pass++) { + ForgeHooksClient.setRenderPass(pass); + int finalPass = pass; + GlStateManager.color(1, 1, 1, 1); + setDefaultPassRenderState(pass); + this.schema.forEach(pair -> { + BlockPos pos = pair.getKey(); + TileEntity tile = pair.getValue().getTileEntity(); + if (tile != null && tile.shouldRenderInPass(finalPass)) { + TileEntityRendererDispatcher.instance.render(tile, pos.getX(), pos.getY(), pos.getZ(), 0); + } + }); + } } ForgeHooksClient.setRenderPass(-1); GlStateManager.enableDepth(); diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaWorld.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaWorld.java index a7b69bd3c..4cbbaebbf 100644 --- a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaWorld.java +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaWorld.java @@ -12,16 +12,42 @@ import java.util.Iterator; import java.util.Map; +import java.util.function.BiPredicate; -public class SchemaWorld extends DummyWorld implements ISchema { +public class SchemaWorld extends DummyWorld implements IFilteredSchema { private final ObjectLinkedOpenHashSet blocks = new ObjectLinkedOpenHashSet<>(); + private BiPredicate renderFilter; private final BlockPos.MutableBlockPos min = new BlockPos.MutableBlockPos(); private final BlockPos.MutableBlockPos max = new BlockPos.MutableBlockPos(); + public SchemaWorld() { + this((blockPos, blockInfo) -> true); + } + + public SchemaWorld(BiPredicate renderFilter) { + this.renderFilter = renderFilter; + } + + @Override + public void setRenderFilter(@NotNull BiPredicate renderFilter) { + this.renderFilter = renderFilter; + } + + @Override + public @NotNull BiPredicate getRenderFilter() { + return renderFilter; + } + @Override public boolean setBlockState(@NotNull BlockPos pos, @NotNull IBlockState newState, int flags) { - boolean b = super.setBlockState(pos, newState, flags); + boolean renderTest; + boolean state; + if (renderFilter.test(pos, BlockInfo.of(this, pos))) { + renderTest = true; + state = super.setBlockState(pos, newState, flags); + } else renderTest = state = false; + if (newState.getBlock().isAir(newState, this, pos)) { if (this.blocks.remove(pos) && BlockPosUtil.isOnBorder(min, max, pos)) { if (this.blocks.isEmpty()) { @@ -37,14 +63,15 @@ public boolean setBlockState(@NotNull BlockPos pos, @NotNull IBlockState newStat } } } else if (this.blocks.isEmpty()) { + if (!renderTest) return false; this.blocks.add(pos); this.min.setPos(pos); this.max.setPos(pos); - } else if (this.blocks.add(pos)) { + } else if (renderTest && this.blocks.add(pos)) { BlockPosUtil.setMin(this.min, pos); BlockPosUtil.setMax(this.max, pos); } - return b; + return renderTest && state; } @Override diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SimpleSchema.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SimpleSchema.java index 922f53bfb..3490c91f8 100644 --- a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SimpleSchema.java +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/SimpleSchema.java @@ -12,25 +12,34 @@ import it.unimi.dsi.fastutil.objects.ObjectIterator; import org.jetbrains.annotations.NotNull; +import java.util.Collections; import java.util.Iterator; import java.util.Map; +import java.util.function.BiPredicate; import java.util.function.Function; -public class SimpleSchema implements ISchema { +public class SimpleSchema implements IMemorizingFilteredSchema { private final World world; - private final Object2ObjectOpenHashMap blocks = new Object2ObjectOpenHashMap<>(); + private final Object2ObjectOpenHashMap originalBlocks = new Object2ObjectOpenHashMap<>(); + private final Object2ObjectOpenHashMap filteredBlocks = new Object2ObjectOpenHashMap<>(); + private BiPredicate renderFilter; private final BlockPos origin; private final Vec3d center; public SimpleSchema(Map blocks) { + this(blocks, (blockPos, blockInfo) -> true); + } + + public SimpleSchema(Map blocks, BiPredicate renderFilter) { this.world = new DummyWorld(); + this.renderFilter = renderFilter; BlockPos.MutableBlockPos min = new BlockPos.MutableBlockPos(BlockPosUtil.MAX); BlockPos.MutableBlockPos max = new BlockPos.MutableBlockPos(BlockPosUtil.MIN); if (!blocks.isEmpty()) { for (var entry : blocks.entrySet()) { if (entry.getValue().getBlockState().getBlock() != Blocks.AIR) { - this.blocks.put(entry.getKey(), entry.getValue()); + this.originalBlocks.put(entry.getKey(), entry.getValue()); entry.getValue().apply(this.world, entry.getKey()); BlockPosUtil.setMin(min, entry.getKey()); BlockPosUtil.setMax(max, entry.getKey()); @@ -42,6 +51,33 @@ public SimpleSchema(Map blocks) { } this.origin = min.toImmutable(); this.center = BlockPosUtil.getCenterD(min, max); + applyRenderFilter(); + } + + @Override + public Map getOriginalSchema() { + return Collections.unmodifiableMap(originalBlocks); + } + + @Override + public void applyRenderFilter() { + filteredBlocks.clear(); + originalBlocks.forEach((pos, bInfo) -> { + if (getRenderFilter().test(pos, bInfo)) { + bInfo.apply(getWorld(), pos); + filteredBlocks.put(pos, bInfo); + } else getWorld().setBlockToAir(pos); + }); + } + + @Override + public void setRenderFilter(@NotNull BiPredicate renderFilter) { + this.renderFilter = renderFilter; + } + + @Override + public @NotNull BiPredicate getRenderFilter() { + return renderFilter; } @Override @@ -64,7 +100,7 @@ public BlockPos getOrigin() { public Iterator> iterator() { return new Iterator<>() { - private final ObjectIterator> it = blocks.object2ObjectEntrySet().fastIterator(); + private final ObjectIterator> it = filteredBlocks.object2ObjectEntrySet().fastIterator(); @Override public boolean hasNext() { @@ -81,6 +117,7 @@ public Map.Entry next() { public static class Builder { private final Object2ObjectOpenHashMap blocks = new Object2ObjectOpenHashMap<>(); + private BiPredicate renderFilter; public Builder add(BlockPos pos, IBlockState state) { return add(pos, state, null); @@ -110,8 +147,16 @@ public Builder add(Map blocks) { return this; } + public Builder setRenderFilter(BiPredicate renderFilter) { + this.renderFilter = renderFilter; + return this; + } + public SimpleSchema build() { - return new SimpleSchema(this.blocks); + if (renderFilter == null) { + return new SimpleSchema(this.blocks); + } + return new SimpleSchema(this.blocks, renderFilter); } } } diff --git a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/Structure.java b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/Structure.java index 93555e5e9..516229d69 100644 --- a/src/main/java/com/cleanroommc/modularui/utils/fakeworld/Structure.java +++ b/src/main/java/com/cleanroommc/modularui/utils/fakeworld/Structure.java @@ -1,36 +1,85 @@ package com.cleanroommc.modularui.utils.fakeworld; +import com.google.common.base.Predicate; +import com.google.common.collect.Lists; import it.unimi.dsi.fastutil.chars.Char2ObjectMap; import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.chars.CharArrayList; +import it.unimi.dsi.fastutil.chars.CharList; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import net.minecraft.block.state.BlockWorldState; +import net.minecraft.util.math.BlockPos; + +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.Collectors; public class Structure { + private Structure(){} - private final List matrix = new ArrayList<>(); - private final Char2ObjectMap> map = new Char2ObjectOpenHashMap<>(); - - public Structure() { - this.map.put(' ', air()); + public static StaticBuilder staticBuilder(){ + return new StaticBuilder(); } - public Structure aisle(String... aisle) { - this.matrix.add(aisle); - return this; - } + public static class StaticBuilder { + private final List matrix = new ObjectArrayList<>(); + private final Char2ObjectMap map = new Char2ObjectOpenHashMap<>(); - public Structure where(char c, Supplier blockInfo) { - this.map.put(c, blockInfo); - return this; - } - public Structure where(char c, BlockInfo blockInfo) { - return where(c, () -> blockInfo); - } + private StaticBuilder() { + this.map.put(' ', air()); + } + + public StaticBuilder aisle(String... aisle) { + this.matrix.add(aisle); + return this; + } + + public StaticBuilder where(char c, BlockInfo blockInfo) { + this.map.put(c, blockInfo); + return this; + } + + public static BlockInfo air() { + return BlockInfo.EMPTY; + } + + public Map buildPosMap() { + checkMissingPredicates(); + Map posMap = new Object2ObjectOpenHashMap<>(); + + for (int y = 0; y < matrix.size(); y++) { + var aisle = matrix.get(y); + for (int x = 0; x < aisle.length; x++) { + var aisleX = aisle[x].toCharArray(); + for (int z = 0; z < aisleX.length; z++) { + var aisleZ = aisleX[z]; + posMap.put(new BlockPos(x, y, z), map.get(aisleZ)); + } + } + } + + return posMap; + } + + private void checkMissingPredicates() { + CharList list = new CharArrayList(); + + for (Char2ObjectMap.Entry entry : map.char2ObjectEntrySet()) { + if (Objects.isNull(entry.getValue())) list.add(entry.getCharKey()); + } + + if (!list.isEmpty()) throw new IllegalStateException( + list.stream().map(Object::toString).collect(Collectors.joining(",", "Predicates for character(s) ", " are missing"))); + } - public static Supplier air() { - return () -> BlockInfo.EMPTY; } + } diff --git a/src/main/java/com/cleanroommc/modularui/widgets/SchemaWidget.java b/src/main/java/com/cleanroommc/modularui/widgets/SchemaWidget.java new file mode 100644 index 000000000..bb0e17299 --- /dev/null +++ b/src/main/java/com/cleanroommc/modularui/widgets/SchemaWidget.java @@ -0,0 +1,162 @@ +package com.cleanroommc.modularui.widgets; + +import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.api.widget.Interactable; +import com.cleanroommc.modularui.drawable.GuiTextures; +import com.cleanroommc.modularui.drawable.keys.StringKey; +import com.cleanroommc.modularui.screen.ModularScreen; +import com.cleanroommc.modularui.utils.fakeworld.BlockInfo; +import com.cleanroommc.modularui.utils.fakeworld.SchemaRenderer; +import com.cleanroommc.modularui.widget.Widget; + +import net.minecraft.util.math.BlockPos; + +import net.minecraft.util.math.MathHelper; + +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiPredicate; +import java.util.function.BooleanSupplier; + +public class SchemaWidget extends Widget implements Interactable { + + private final SchemaRenderer schema; + private boolean invertMouseScrollScaleAction = false; + private double scale = 10; + + + public SchemaWidget(SchemaRenderer schema) { + this.schema = schema; + schema.cameraFunc((camera, $schema) -> { + camera.setLookAt($schema.getOrigin(), scale, Math.toRadians(yaw), Math.toRadians(pitch)); + }); + } + + @Override + public boolean onMouseScroll(ModularScreen.UpOrDown scrollDirection, int amount) { + switch (scrollDirection) { + case UP -> { + modifyScale(-((double) amount / 120)); + return true; + } + case DOWN -> { + modifyScale(((double) amount / 120)); + return true; + } + default -> { + return false; + } + } + } + + + public SchemaWidget modifyScale(double scale) { + this.scale += scale; + return this; + } + + public SchemaWidget invertMouseScrollScaleAction(boolean invert) { + invertMouseScrollScaleAction = invert; + return this; + } + + + private int lastMouseX; + private int lastMouseY; + + private float pitch; + private float yaw; + + @Override + public void onMouseDrag(int mouseButton, long timeSinceClick) { + int mouseX = getContext().getAbsMouseX(); + int mouseY = getContext().getAbsMouseY(); + + //timeSinceClick is sometimes greater than 0 even on the first click + if (timeSinceClick == 0) { + this.lastMouseX = mouseX; + this.lastMouseY = mouseY; + return; + } + + if (mouseButton == 0) { + yaw += mouseX - lastMouseX + 360; + yaw = yaw % 360; + pitch = (float) MathHelper.clamp(pitch + (mouseY - lastMouseY), -89.9, 89.9); + + this.lastMouseX = mouseX; + this.lastMouseY = mouseY; + } + + } + + @Override + public @Nullable IDrawable getOverlay() { + return schema; + } + + + public static class DisableTESR extends ButtonWidget { + + private boolean disable = false; + + public DisableTESR() { + this.background(GuiTextures.MC_BACKGROUND); + onMousePressed(mouseButton -> { + if (mouseButton == 0) { + disable = !disable; + return true; + } + + return false; + }); + } + + public BooleanSupplier makeSuppler() { + return () -> disable; + } + } + + public static class LayerUpDown extends ButtonWidget { + + private int minLayer = Integer.MIN_VALUE; + private int maxLayer = Integer.MAX_VALUE; + private int currentLayer = Integer.MIN_VALUE; + + public LayerUpDown() { + this.background(GuiTextures.MC_BACKGROUND); + + onMousePressed(mouseButton -> { + if (mouseButton == 0) { + currentLayer = Math.max(currentLayer + 1, maxLayer); + } + + if (mouseButton == 1) { + currentLayer = Math.max(currentLayer - 1, maxLayer); + } + + if (mouseButton == 0 || mouseButton == 1) { + overlay(new StringKey(Integer.toString(currentLayer))); + return true; + } + + return false; + }); + } + + public BiPredicate makeSchemaFilter() { + return (blockPos, blockInfo) -> { + maxLayer = Math.min(maxLayer, blockPos.getY()); + minLayer = Math.max(minLayer, blockPos.getY()); + if (currentLayer > blockPos.getY()) return false; + return true; + }; + } + + public LayerUpDown startLayer(int start) { + this.currentLayer = start; + return this; + } + } + +}