diff --git a/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java b/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java index c441bc40..0d8504e0 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java +++ b/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java @@ -100,6 +100,8 @@ public class StructureLib { } }; + public static boolean isGTLoaded; + @Mod.EventHandler public void preInit(FMLPreInitializationEvent e) { ConfigurationHandler.INSTANCE.init(e.getSuggestedConfigurationFile()); @@ -118,6 +120,8 @@ public class StructureLib { if (Loader.isModLoaded(STRUCTURECOMPAT_MODID)) { COMPAT = Loader.instance().getIndexedModList().get(STRUCTURECOMPAT_MODID).getMod(); } + + isGTLoaded = Loader.isModLoaded("gregtech"); } @Mod.EventHandler diff --git a/src/main/java/com/gtnewhorizon/structurelib/gui/GuiScreenConfigureChannels.java b/src/main/java/com/gtnewhorizon/structurelib/gui/GuiScreenConfigureChannels.java index 314c2519..10dcba09 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/gui/GuiScreenConfigureChannels.java +++ b/src/main/java/com/gtnewhorizon/structurelib/gui/GuiScreenConfigureChannels.java @@ -25,6 +25,15 @@ import com.gtnewhorizon.structurelib.gui.GuiScrollableList.IGuiScreen; public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen { + private static final int ADD_BTN = 0; + private static final int UNSET_BTN = 1; + private static final int WIPE_BTN = 2; + private static final int SHOW_ERROR_BTN = 3; + private static final int GT_NO_HATCH_BTN = 4; + + private static final String SHOW_ERROR_CHANNEL = "show_error"; + private static final String GT_NO_HATCH_CHANNEL = "gt_no_hatch"; + private static final int KEY_MAX_WIDTH = 50; private final ItemStack trigger; private final GuiChannelsList list; @@ -128,7 +137,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen addButton( new GuiButton( - 0, + ADD_BTN, guiLeft + 12, guiTop + 157, 47, @@ -136,7 +145,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen I18n.format("item.structurelib.constructableTrigger.gui.add"))); addButton( new GuiButton( - 1, + UNSET_BTN, guiLeft + 65, guiTop + 157, 47, @@ -144,13 +153,27 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen I18n.format("item.structurelib.constructableTrigger.gui.unset"))); addButton( new GuiButton( - 2, + WIPE_BTN, guiLeft + 118, guiTop + 157, 47, 20, I18n.format("item.structurelib.constructableTrigger.gui.wipe"))); + addButton( + new GuiButton( + SHOW_ERROR_BTN, + StructureLib.isGTLoaded ? guiLeft + 12 : guiLeft + 52, + guiTop + 180, + 73, + 20, + "")); + + // only show GT hatch button if GT is loaded + if (StructureLib.isGTLoaded) { + addButton(new GuiButton(GT_NO_HATCH_BTN, guiLeft + 92, guiTop + 180, 73, 20, "")); + } + updateButtons(); } @@ -171,7 +194,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen @Override public int getYSize() { - return 188; + return 211; } @Override @@ -250,10 +273,27 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen // STACKOVERFLOW! String keyText = key.getText(); boolean existing = !StringUtils.isEmpty(keyText) && ChannelDataAccessor.hasSubChannel(trigger, keyText); - getButtonList().get(0).displayString = existing ? I18n.format("item.structurelib.constructableTrigger.gui.set") + getButtonList().get(ADD_BTN).displayString = existing + ? I18n.format("item.structurelib.constructableTrigger.gui.set") : I18n.format("item.structurelib.constructableTrigger.gui.add"); - getButtonList().get(0).enabled = !StringUtils.isBlank(value.getText()); - getButtonList().get(1).enabled = existing && !StringUtils.isBlank(value.getText()); + getButtonList().get(ADD_BTN).enabled = !StringUtils.isBlank(value.getText()); + getButtonList().get(UNSET_BTN).enabled = existing && !StringUtils.isBlank(value.getText()); + + if (ChannelDataAccessor.hasSubChannel(trigger, SHOW_ERROR_CHANNEL)) { + getButtonList().get(SHOW_ERROR_BTN).displayString = "Hide Errors"; + } else { + getButtonList().get(SHOW_ERROR_BTN).displayString = "Show Errors"; + } + + // this button only exists if GT is loaded. + if (StructureLib.isGTLoaded) { + if (ChannelDataAccessor.hasSubChannel(trigger, GT_NO_HATCH_CHANNEL)) { + getButtonList().get(GT_NO_HATCH_BTN).displayString = "Hatches"; + } else { + getButtonList().get(GT_NO_HATCH_BTN).displayString = "No Hatch"; + } + } + } private int getValue() { @@ -268,18 +308,35 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen protected void actionPerformed(GuiButton btn) { if (btn == null) return; switch (btn.id) { - case 0: + case ADD_BTN: int value = getValue(); if (value <= 0) return; ChannelDataAccessor.setChannelData(trigger, key.getText(), value); break; - case 1: + case UNSET_BTN: ChannelDataAccessor.unsetChannelData(trigger, key.getText()); break; - case 2: + case WIPE_BTN: ChannelDataAccessor.wipeChannelData(trigger); break; + case SHOW_ERROR_BTN: + if (ChannelDataAccessor.hasSubChannel(trigger, SHOW_ERROR_CHANNEL)) { + ChannelDataAccessor.unsetChannelData(trigger, SHOW_ERROR_CHANNEL); + } else { + ChannelDataAccessor.setChannelData(trigger, SHOW_ERROR_CHANNEL, 1); + } + break; + case GT_NO_HATCH_BTN: + if (ChannelDataAccessor.hasSubChannel(trigger, GT_NO_HATCH_CHANNEL)) { + ChannelDataAccessor.unsetChannelData(trigger, GT_NO_HATCH_CHANNEL); + } else { + ChannelDataAccessor.setChannelData(trigger, GT_NO_HATCH_CHANNEL, 1); + } + break; } + + updateButtons(); + super.actionPerformed(btn); } @@ -350,6 +407,7 @@ public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen Entry e = getElementAt(elementIndex); if (e != null) { ChannelDataAccessor.unsetChannelData(trigger, e.getKey()); + updateButtons(); return false; } } diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureDefinition.java b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureDefinition.java index 8c152071..2b6b7732 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureDefinition.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureDefinition.java @@ -12,6 +12,7 @@ import net.minecraft.world.World; import com.gtnewhorizon.structurelib.StructureLib; import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; @@ -50,7 +51,7 @@ import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; * itself. *
  • The "C" position would be the number of blocks between you and controller, not counting controller itself.
  • * - * + * * @param Type of the context object. Usually this will be the multiblock controller. */ public interface IStructureDefinition { @@ -72,7 +73,7 @@ public interface IStructureDefinition { /** * Run a structure check. - * + * * @param object context object. usually multiblock controller. * @param piece the structure piece's string identifier. * @param world the world object this check takes place in. @@ -107,7 +108,7 @@ public interface IStructureDefinition { /** * Spawn hint particles. Should not be called on server side. - * + * * @param object context object. usually multiblock controller. * @param piece the structure piece's string identifier. * @param world the world object this check takes place in. @@ -320,7 +321,7 @@ public interface IStructureDefinition { /** * Low level utility. - * + * * @param object context object. usually multiblock controller. * @param trigger The trigger item that contains channel data. * @param elements the structure piece @@ -394,6 +395,10 @@ public interface IStructureDefinition { basePositionC, ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> { e.spawnHint(object, world, x, y, z, trigger); + if (ChannelDataAccessor.hasSubChannel(trigger, "show_error") + && !e.couldBeValid(object, world, x, y, z, trigger)) { + StructureLibAPI.markHintParticleError(StructureLib.getCurrentPlayer(), world, x, y, z); + } return true; }), "spawnHint"); @@ -420,7 +425,7 @@ public interface IStructureDefinition { /** * Create a new instance of builder. - * + * * @param type of context object */ static StructureDefinition.Builder builder() { diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java index eb16fcc5..63d1b4b7 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java @@ -32,6 +32,16 @@ public interface IStructureElement { boolean check(T t, World world, int x, int y, int z); + /** + * Pure (stateless and side effect free) function to test if current block could be valid. Used to give user hints + * about incorrectly placed blocks given a controller and trigger item. If couldBeValid(...) == false for a set of + * channels, with those same tiers, check(...) == false. Not required, defaults to true which is always safe but + * won't give the user error hints. + */ + default boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return true; + } + boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger); boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger); @@ -185,6 +195,11 @@ public interface IStructureElement { return IStructureElement.this.check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return IStructureElement.this.couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { return IStructureElement.this.spawnHint(t, world, x, y, z, trigger); diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java index 819990fd..c527c76a 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java @@ -31,6 +31,16 @@ public interface IStructureElementChain extends IStructureElement { return false; } + @Override + default boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + for (IStructureElement fallback : fallbacks()) { + if (fallback.couldBeValid(t, world, x, y, z, trigger)) { + return true; + } + } + return false; + } + @Override default boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { for (IStructureElement fallback : fallbacks()) { diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementCheckOnly.java b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementCheckOnly.java index 03f2b859..ee8144a5 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementCheckOnly.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementCheckOnly.java @@ -14,6 +14,11 @@ public interface IStructureElementCheckOnly extends IStructureElement { return false; } + @Override + default boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return true; + } + @Override default boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { return false; diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureNavigate.java b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureNavigate.java index 6ce52c52..602a4993 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureNavigate.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureNavigate.java @@ -17,6 +17,11 @@ interface IStructureNavigate extends IStructureElement { return true; } + @Override + default boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return true; + } + @Override default boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { return true; diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java b/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java index 3f8cfda3..0959ee67 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java @@ -32,6 +32,11 @@ class LazyStructureElement implements IStructureElementDeferred { return get(t).check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return get(t).couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { return get(t).placeBlock(t, world, x, y, z, trigger); diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java b/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java index a6baa3c9..f44e3095 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java @@ -155,6 +155,11 @@ public class StructureUtility { return world.isAirBlock(x, y, z); } + @Override + public boolean couldBeValid(Object t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(Object o, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), 13); @@ -186,6 +191,11 @@ public class StructureUtility { return !world.isAirBlock(x, y, z); } + @Override + public boolean couldBeValid(Object t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(Object o, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), 14); @@ -225,6 +235,11 @@ public class StructureUtility { return false; } + @Override + public boolean couldBeValid(Object t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(Object o, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), 15); @@ -479,6 +494,11 @@ public class StructureUtility { return true; } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), meta); @@ -499,6 +519,11 @@ public class StructureUtility { return true; } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, icons.get()); @@ -519,6 +544,11 @@ public class StructureUtility { return true; } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticleTinted(world, x, y, z, icons.get(), RGBa); @@ -667,9 +697,23 @@ public class StructureUtility { } private Pair getHint(ItemStack trigger) { + if (hints.isEmpty()) return null; return hints.get(Math.min(Math.max(trigger.stackSize, 1), hints.size()) - 1); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + Pair hint = getHint(trigger); + if (hint == null) return true; + TIER hintTier = tierExtractor.convert(hint.getKey(), hint.getValue()); + Block block = world.getBlock(x, y, z); + int meta = world.getBlockMetadata(x, y, z); + TIER worldTier = tierExtractor.convert(block, meta); + + // if the block is in the same tier as the hint block, this could be valid + return Objects.equals(hintTier, worldTier); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { Pair hint = getHint(trigger); @@ -767,6 +811,11 @@ public class StructureUtility { return world.getBlock(x, y, z) == getBlock() && (wildcard || world.getBlockMetadata(x, y, z) == meta); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { if (getBlock() == null) return error().spawnHint(t, world, x, y, z, trigger); @@ -841,10 +890,16 @@ public class StructureUtility { @Override public boolean check(T t, World world, int x, int y, int z) { - if (init()) return world.getBlock(x, y, z) != block && world.getBlockMetadata(x, y, z) == meta; + if (init()) return world.getBlock(x, y, z) == block && world.getBlockMetadata(x, y, z) == meta; else return fallback.check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + if (init()) return world.getBlock(x, y, z) == block && world.getBlockMetadata(x, y, z) == meta; + else return fallback.couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { if (init()) { @@ -921,6 +976,11 @@ public class StructureUtility { return blocsMap.getOrDefault(worldBlock, MIN_VALUE) == worldBlock.getDamageValue(world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta); @@ -958,6 +1018,11 @@ public class StructureUtility { .contains(worldBlock.getDamageValue(world, x, y, z)); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta); @@ -982,6 +1047,11 @@ public class StructureUtility { return block == worldBlock && meta == worldBlock.getDamageValue(world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta); @@ -1016,6 +1086,13 @@ public class StructureUtility { return iBlockAdder.apply(t, worldBlock, worldBlock.getDamageValue(world, x, y, z)); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + // calling iBlockAdder can potentially modify external state + // therefore we assume this can always be valid. + return true; + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta); @@ -1049,6 +1126,11 @@ public class StructureUtility { return blocsMap.getOrDefault(worldBlock, MIN_VALUE) == worldBlock.getDamageValue(world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { ((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta); @@ -1093,6 +1175,11 @@ public class StructureUtility { return blocsMap.getOrDefault(worldBlock, MIN_VALUE) == worldBlock.getDamageValue(world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { world.setBlock(x, y, z, defaultBlock, defaultMeta, 2); @@ -1158,6 +1245,11 @@ public class StructureUtility { .contains(worldBlock.getDamageValue(world, x, y, z)); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { ((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta); @@ -1203,6 +1295,11 @@ public class StructureUtility { .contains(worldBlock.getDamageValue(world, x, y, z)); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { world.setBlock(x, y, z, defaultBlock, defaultMeta, 2); @@ -1260,6 +1357,11 @@ public class StructureUtility { return block == worldBlock && meta == worldBlock.getDamageValue(world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { ((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta); @@ -1287,6 +1389,11 @@ public class StructureUtility { return block == worldBlock && meta == worldBlock.getDamageValue(world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { world.setBlock(x, y, z, defaultBlock, defaultMeta, 2); @@ -1323,6 +1430,11 @@ public class StructureUtility { return block == world.getBlock(x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { ((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta); @@ -1350,6 +1462,11 @@ public class StructureUtility { return block == world.getBlock(x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return check(t, world, x, y, z); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { world.setBlock(x, y, z, defaultBlock, defaultMeta, 2); @@ -1416,6 +1533,13 @@ public class StructureUtility { return iBlockAdder.apply(t, worldBlock, worldBlock.getDamageValue(world, x, y, z)); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + // calling iBlockAdder can potentially modify external state + // therefore we assume this can always be valid. + return true; + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { ((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta); @@ -1455,6 +1579,13 @@ public class StructureUtility { return iBlockAdder.apply(t, worldBlock, worldBlock.getDamageValue(world, x, y, z)); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + // calling iBlockAdder can potentially modify external state + // therefore we assume this can always be valid. + return true; + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { world.setBlock(x, y, z, defaultBlock, defaultMeta, 2); @@ -1510,6 +1641,13 @@ public class StructureUtility { return iTileAdder.apply(t, tileEntity); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + // calling iTileAdder can potentially modify external state + // therefore we assume this can always be valid. + return true; + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta); @@ -1536,6 +1674,13 @@ public class StructureUtility { return tileClass.isInstance(tileEntity) && iTileAdder.test(t, tileClass.cast(tileEntity)); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + // calling iTileAdder can potentially modify external state + // therefore we assume this can always be valid. + return true; + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta); @@ -1569,6 +1714,11 @@ public class StructureUtility { return check; } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return element.couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { return element.placeBlock(t, world, x, y, z, trigger); @@ -1620,6 +1770,11 @@ public class StructureUtility { return check; } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return element.couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { return element.placeBlock(t, world, x, y, z, trigger); @@ -1678,6 +1833,13 @@ public class StructureUtility { return predicate.test(t) && downstream.check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + // this COULD potentially impact external state + // but predicate really should not have side effects + return predicate.test(t) && downstream.couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { return predicate.test(t) && downstream.spawnHint(t, world, x, y, z, trigger); @@ -1774,6 +1936,11 @@ public class StructureUtility { return elem.check(t.getCurrentContext(), world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return elem.couldBeValid(t.getCurrentContext(), world, x, y, z, trigger); + } + @Override public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { return elem.spawnHint(t.getCurrentContext(), world, x, y, z, trigger); @@ -1861,6 +2028,11 @@ public class StructureUtility { return to.get().check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return to.get().couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { return to.get().placeBlock(t, world, x, y, z, trigger); @@ -1914,6 +2086,11 @@ public class StructureUtility { return to.apply(t).check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return to.apply(t).couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { return to.apply(t).placeBlock(t, world, x, y, z, trigger); @@ -2126,6 +2303,11 @@ public class StructureUtility { return to.apply(t, null).check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return to.apply(t, trigger).couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { return to.apply(t, trigger).placeBlock(t, world, x, y, z, trigger); @@ -2318,6 +2500,11 @@ public class StructureUtility { return toCheck.apply(t).check(t, world, x, y, z); } + @Override + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + return to.apply(t, trigger).couldBeValid(t, world, x, y, z, trigger); + } + @Override public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { return to.apply(t, trigger).placeBlock(t, world, x, y, z, trigger); @@ -2562,6 +2749,11 @@ public class StructureUtility { return backing.check(t, world, x, y, z); } + public boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) { + ItemStack newTrigger = ChannelDataAccessor.withChannel(trigger, channel); + return backing.couldBeValid(t, world, x, y, z, newTrigger); + } + public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { ItemStack newTrigger = ChannelDataAccessor.withChannel(trigger, channel); // We know spawnHint will only be called on client side, so the lack of player isn't quite an issue diff --git a/src/main/resources/assets/structurelib/textures/gui/channels.png b/src/main/resources/assets/structurelib/textures/gui/channels.png index c76cdf33..4726863d 100644 Binary files a/src/main/resources/assets/structurelib/textures/gui/channels.png and b/src/main/resources/assets/structurelib/textures/gui/channels.png differ