Compare commits

..
12 Commits
Author SHA1 Message Date
Martin Robertz b9d0143245 update 2024-12-14 20:12:25 +01:00
43fc39c99b Add error hint when block is invalid (#31)
Co-authored-by: kstvr32 <kstvr32@gmail.com>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
2024-12-14 19:13:34 +01:00
Lyft 6337536dc3 Send correct identifier when instrumenting (#34) 2024-11-19 10:20:47 +08:00
Lyft 9b96560119 Fix IStructureElementChain returning an invalid Iterable (#33) 2024-11-09 15:46:49 +01:00
Dream Master 3ce1c877e3 update 2024-08-07 15:42:01 +07:00
GleaseandDream Master 3d150d95cb customizable registries (#25)
* add a bit javadoc

Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>

* customizable registries

Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>

* add gui for customizing registries

* add a bit javadoc

Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>

* spotless

Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>

* remove debug statements

Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>

* add notes on localization

Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>

* update

* fix

* fix

---------

Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
Co-authored-by: Dream Master <dream-master@gmx.net>
2024-08-07 15:37:30 +07:00
Dream Master 03e84e3d37 update 2024-07-10 11:12:56 +07:00
Jason Mitchell 547833bedb Bump NEI dep
Bump GTNHLib dep for CoordinatePacker

Bump deps
2024-07-09 09:39:45 -07:00
Jason Mitchell 61e0d4b7e7 Add basic BlockChangeNotifier & BlockChangeListener 2024-07-09 09:39:45 -07:00
Jason Mitchell 6867ed50e6 Add mixins 2024-07-09 09:39:45 -07:00
Jason Mitchell e7a47c199b Enable checkstyle 2024-07-09 09:39:45 -07:00
Jason Mitchell b2bc474382 Update BS, enable Jabel & Generic injection 2024-07-09 09:39:45 -07:00
36 changed files with 906 additions and 46 deletions

No files matched your search

+2 -2
View File
@@ -1,8 +1,8 @@
// Add your dependencies here
dependencies {
api("com.github.GTNewHorizons:GTNHLib:0.2.11:dev")
runtimeOnly("com.github.GTNewHorizons:NotEnoughItems:2.6.0-GTNH:dev")
api("com.github.GTNewHorizons:GTNHLib:0.5.22:dev")
runtimeOnly("com.github.GTNewHorizons:NotEnoughItems:2.6.51-GTNH:dev")
testImplementation(platform('org.junit:junit-bom:5.9.2'))
testImplementation('org.junit.jupiter:junit-jupiter')
+21 -10
View File
@@ -41,19 +41,19 @@ developmentEnvironmentUserName = "Developer"
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
# See https://github.com/bsideup/jabel for details on how this works.
enableModernJavaSyntax = false
enableModernJavaSyntax = true
# Enables injecting missing generics into the decompiled source code for a better coding experience.
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
enableGenericInjection = false
enableGenericInjection = true
# Generate a class with a String field for the mod version named as defined below.
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
generateGradleTokenClass =
generateGradleTokenClass = com.gtnewhorizon.structurelib.Tags
# Name of the token containing the project's current version to generate/replace.
gradleTokenVersion = GRADLETOKEN_VERSION
gradleTokenVersion = VERSION
# [DEPRECATED] Mod ID replacement token.
gradleTokenModId =
@@ -70,7 +70,7 @@ gradleTokenGroupName =
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
# version in @Mod([...], version = VERSION, [...]).
# Leave these properties empty to skip individual token replacements.
replaceGradleTokenInFile = StructureLib.java
replaceGradleTokenInFile =
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
# leave this property empty.
@@ -83,7 +83,12 @@ apiPackage =
accessTransformersFile =
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins = false
usesMixins = true
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
# Mixin classes will have access to "main" classes, but not the other way around.
separateMixinSourceSet =
# Adds some debug arguments like verbose output and class export.
usesMixinDebug = false
@@ -92,12 +97,12 @@ usesMixinDebug = false
mixinPlugin =
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
mixinsPackage =
mixinsPackage = mixins
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# This parameter is for legacy compatibility only
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
coreModClass =
coreModClass = core.StructureLibCore
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
@@ -117,9 +122,15 @@ minimizeShadowedDependencies = true
# If disabled, won't rename the shadowed classes.
relocateShadowedDependencies = true
# Adds the GTNH maven, CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
includeWellKnownRepositories = true
# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated
# list of strings, with the acceptable keys being(case does not matter):
# cursemaven
# modrinth
excludeWellKnownRepositories =
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables.
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
@@ -176,7 +187,7 @@ curseForgeRelations =
# disableSpotless = true
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
disableCheckstyle = true
# disableCheckstyle = true
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
# (force use delegated build).
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+5 -2
View File
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
Vendored
+2
View File
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.22'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.30'
}
@@ -3,7 +3,13 @@ package com.gtnewhorizon.structurelib;
import static com.gtnewhorizon.structurelib.StructureLib.RANDOM;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
@@ -42,7 +42,7 @@ import cpw.mods.fml.relauncher.SideOnly;
@Mod(
modid = StructureLibAPI.MOD_ID,
name = "StructureLib",
version = "GRADLETOKEN_VERSION",
version = Tags.VERSION,
acceptableRemoteVersions = "*",
guiFactory = "com.gtnewhorizon.structurelib.GuiFactory")
public class StructureLib {
@@ -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
@@ -72,7 +72,7 @@ public class StructureLibAPI {
*/
public static void enableInstrument(Object identifier) {
if (isInstrumentEnabled()) throw new IllegalStateException();
instrument.set(instrument);
instrument.set(identifier);
}
/**
@@ -4,9 +4,18 @@ import static com.gtnewhorizon.structurelib.alignment.IAlignment.FLIPS_COUNT;
import static com.gtnewhorizon.structurelib.alignment.IAlignment.ROTATIONS_COUNT;
import static java.lang.Math.abs;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.*;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import java.util.*;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import net.minecraft.util.StatCollector;
import net.minecraft.util.Vec3;
@@ -35,7 +35,7 @@ public class CommandConfigureChannels extends CommandBase {
}
@Override
public List<?> addTabCompletionOptions(ICommandSender p_71516_1_, String[] p_71516_2_) {
public List<String> addTabCompletionOptions(ICommandSender p_71516_1_, String[] p_71516_2_) {
if (p_71516_2_.length == 1)
return getListOfStringsMatchingLastWord(p_71516_2_, "get", "set", "unset", "wipe", "getall");
return null;
@@ -28,7 +28,7 @@ public class CommandRegistryDebug extends CommandBase {
}
@Override
public List<?> addTabCompletionOptions(ICommandSender p_71516_1_, String[] p_71516_2_) {
public List<String> addTabCompletionOptions(ICommandSender p_71516_1_, String[] p_71516_2_) {
if (p_71516_2_.length == 1) return getListOfStringsMatchingLastWord(
p_71516_2_,
SortedRegistry.getRegistryNames().toArray(new String[0]));
@@ -0,0 +1,53 @@
package com.gtnewhorizon.structurelib.core;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
import com.gtnewhorizon.structurelib.mixins.Mixins;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
public class StructureLibCore implements IFMLLoadingPlugin, IEarlyMixinLoader {
public static final Logger log = LogManager.getLogger("StructureLibCore");
@Override
public String getMixinConfig() {
return "mixins.structurelib.early.json";
}
@Override
public List<String> getMixins(Set<String> loadedCoreMods) {
return Mixins.getEarlyMixins(loadedCoreMods);
}
@Override
public String[] getASMTransformerClass() {
return new String[0];
}
@Override
public String getModContainerClass() {
return null;
}
@Override
public String getSetupClass() {
return null;
}
@Override
public void injectData(Map<String, Object> data) {
}
@Override
public String getAccessTransformerClass() {
return null;
}
}
@@ -0,0 +1,11 @@
package com.gtnewhorizon.structurelib.event;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
public interface BlockChangeListener {
void onBlockChange(World world, Chunk chunk, int x, int y, int z, Block oldBlock, Block newBlock, int oldMeta,
int newMeta);
}
@@ -0,0 +1,33 @@
package com.gtnewhorizon.structurelib.event;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
@SuppressWarnings("ForLoopReplaceableByForEach")
public class BlockChangeNotifier {
private static final List<BlockChangeListener> listeners = new ArrayList<>();
public static synchronized void addListener(BlockChangeListener listener) {
listeners.add(listener);
}
public static void onBlockChange(World world, Chunk chunk, int x, int y, int z, Block oldBlock, Block newBlock,
int oldMeta, int newMeta) {
if (oldBlock == newBlock && oldMeta == newMeta) return;
if (chunk == null) {
chunk = world.getChunkFromBlockCoords(x, z);
}
final int numListeners = listeners.size();
for (int i = 0; i < numListeners; i++) {
final BlockChangeListener listener = listeners.get(i);
listener.onBlockChange(world, chunk, x, y, z, oldBlock, newBlock, oldMeta, newMeta);
}
}
}
@@ -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<String, Integer> e = getElementAt(elementIndex);
if (e != null) {
ChannelDataAccessor.unsetChannelData(trigger, e.getKey());
updateButtons();
return false;
}
}
@@ -34,7 +34,7 @@ public class ItemFrontRotationTool extends Item {
@Override
@SideOnly(Side.CLIENT)
public void addInformation(ItemStack p_77624_1_, EntityPlayer p_77624_2_, List aList, boolean p_77624_4_) {
public void addInformation(ItemStack p_77624_1_, EntityPlayer p_77624_2_, List<String> aList, boolean p_77624_4_) {
aList.add(translateToLocal("item.structurelib.frontRotationTool.desc.0")); // Triggers Front Rotation Interface
aList.add(EnumChatFormatting.BLUE + translateToLocal("item.structurelib.frontRotationTool.desc.1")); // Rotates
// only the
@@ -0,0 +1,188 @@
package com.gtnewhorizon.structurelib.mixins;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import com.gtnewhorizon.structurelib.core.StructureLibCore;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
public enum Mixins {
BLOCK_CHANGE_NOTIFIER(new Builder("Block Change Notifier").setPhase(Phase.EARLY)
.addMixinClasses("blockChangeNotifier.MixinForgeHooks", "blockChangeNotifier.MixinWorld")
.addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH).setApplyIf(() -> true));
private final List<String> mixinClasses;
private final List<TargetedMod> targetedMods;
private final List<TargetedMod> excludedMods;
private final Supplier<Boolean> applyIf;
private final Phase phase;
private final Side side;
Mixins(Builder builder) {
this.mixinClasses = builder.mixinClasses;
this.targetedMods = builder.targetedMods;
this.excludedMods = builder.excludedMods;
this.applyIf = builder.applyIf;
this.phase = builder.phase;
this.side = builder.side;
if (this.mixinClasses.isEmpty()) {
throw new RuntimeException("No mixin class specified for Mixin : " + this.name());
}
if (this.targetedMods.isEmpty()) {
throw new RuntimeException("No targeted mods specified for Mixin : " + this.name());
}
if (this.applyIf == null) {
throw new RuntimeException("No ApplyIf function specified for Mixin : " + this.name());
}
if (this.phase == null) {
throw new RuntimeException("No Phase specified for Mixin : " + this.name());
}
if (this.side == null) {
throw new RuntimeException("No Side function specified for Mixin : " + this.name());
}
}
public static List<String> getEarlyMixins(Set<String> loadedCoreMods) {
final List<String> mixins = new ArrayList<>();
final List<String> notLoading = new ArrayList<>();
for (Mixins mixin : Mixins.values()) {
if (mixin.phase == Phase.EARLY) {
if (mixin.shouldLoad(loadedCoreMods, Collections.emptySet())) {
mixins.addAll(mixin.mixinClasses);
} else {
notLoading.addAll(mixin.mixinClasses);
}
}
}
StructureLibCore.log.info("Not loading the following EARLY mixins: {}", notLoading.toString());
return mixins;
}
public static List<String> getLateMixins(Set<String> loadedMods) {
// NOTE: Any targetmod here needs a modid, not a coremod id
final List<String> mixins = new ArrayList<>();
final List<String> notLoading = new ArrayList<>();
for (Mixins mixin : Mixins.values()) {
if (mixin.phase == Phase.LATE) {
if (mixin.shouldLoad(Collections.emptySet(), loadedMods)) {
mixins.addAll(mixin.mixinClasses);
} else {
notLoading.addAll(mixin.mixinClasses);
}
}
}
StructureLibCore.log.info("Not loading the following LATE mixins: {}", notLoading.toString());
return mixins;
}
private boolean shouldLoadSide() {
return side == Side.BOTH || (side == Side.SERVER && FMLLaunchHandler.side().isServer())
|| (side == Side.CLIENT && FMLLaunchHandler.side().isClient());
}
private boolean allModsLoaded(List<TargetedMod> targetedMods, Set<String> loadedCoreMods, Set<String> loadedMods) {
if (targetedMods.isEmpty()) return false;
for (TargetedMod target : targetedMods) {
if (target == TargetedMod.VANILLA) continue;
// Check coremod first
if (!loadedCoreMods.isEmpty() && target.coreModClass != null
&& !loadedCoreMods.contains(target.coreModClass))
return false;
else if (!loadedMods.isEmpty() && target.modId != null && !loadedMods.contains(target.modId)) return false;
}
return true;
}
private boolean noModsLoaded(List<TargetedMod> targetedMods, Set<String> loadedCoreMods, Set<String> loadedMods) {
if (targetedMods.isEmpty()) return true;
for (TargetedMod target : targetedMods) {
if (target == TargetedMod.VANILLA) continue;
// Check coremod first
if (!loadedCoreMods.isEmpty() && target.coreModClass != null
&& loadedCoreMods.contains(target.coreModClass))
return false;
else if (!loadedMods.isEmpty() && target.modId != null && loadedMods.contains(target.modId)) return false;
}
return true;
}
private boolean shouldLoad(Set<String> loadedCoreMods, Set<String> loadedMods) {
return (shouldLoadSide() && applyIf.get()
&& allModsLoaded(targetedMods, loadedCoreMods, loadedMods)
&& noModsLoaded(excludedMods, loadedCoreMods, loadedMods));
}
private static class Builder {
private final String name;
private final List<String> mixinClasses = new ArrayList<>();
private final List<TargetedMod> targetedMods = new ArrayList<>();
private final List<TargetedMod> excludedMods = new ArrayList<>();
private Supplier<Boolean> applyIf = null;
private Phase phase = null;
private Side side = null;
public Builder(String name) {
this.name = name;
}
public Builder addMixinClasses(String... mixinClasses) {
this.mixinClasses.addAll(Arrays.asList(mixinClasses));
return this;
}
public Builder setPhase(Phase phase) {
if (this.phase != null) {
throw new RuntimeException("Trying to define Phase twice for " + this.name);
}
this.phase = phase;
return this;
}
public Builder setSide(Side side) {
if (this.side != null) {
throw new RuntimeException("Trying to define Side twice for " + this.name);
}
this.side = side;
return this;
}
public Builder setApplyIf(Supplier<Boolean> applyIf) {
this.applyIf = applyIf;
return this;
}
public Builder addTargetedMod(TargetedMod mod) {
this.targetedMods.add(mod);
return this;
}
public Builder addExcludedMod(TargetedMod mod) {
this.excludedMods.add(mod);
return this;
}
}
private enum Side {
BOTH,
CLIENT,
SERVER
}
private enum Phase {
EARLY,
LATE,
}
}
@@ -0,0 +1,30 @@
package com.gtnewhorizon.structurelib.mixins;
import cpw.mods.fml.common.Mod;
public enum TargetedMod {
VANILLA("Minecraft", null);
/** The "name" in the {@link Mod @Mod} annotation */
public final String modName;
/** Class that implements the IFMLLoadingPlugin interface */
public final String coreModClass;
/** The "modid" in the {@link Mod @Mod} annotation */
public final String modId;
TargetedMod(String modName, String coreModClass) {
this(modName, coreModClass, null);
}
TargetedMod(String modName, String coreModClass, String modId) {
this.modName = modName;
this.coreModClass = coreModClass;
this.modId = modId;
}
@Override
public String toString() {
return "TargetedMod{modName='" + modName + "', coreModClass='" + coreModClass + "', modId='" + modId + "'}";
}
}
@@ -0,0 +1,44 @@
package com.gtnewhorizon.structurelib.mixins.early.blockChangeNotifier;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.util.BlockSnapshot;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.gtnewhorizon.structurelib.event.BlockChangeNotifier;
import com.llamalad7.mixinextras.sugar.Local;
@Mixin(ForgeHooks.class)
public class MixinForgeHooks {
@Inject(
method = "onPlaceItemIntoWorld",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/World;markAndNotifyBlock(IIILnet/minecraft/world/chunk/Chunk;Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;I)V",
shift = At.Shift.AFTER),
remap = false)
private static void onBlockChange(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z,
int side, float hitX, float hitY, float hitZ, CallbackInfoReturnable<Boolean> cir,
@Local(name = "blocksnapshot") BlockSnapshot blocksnapshot, @Local(name = "newBlock") Block newBlock,
@Local(name = "metadata") int newMetadata) {
BlockChangeNotifier.onBlockChange(
world,
null,
blocksnapshot.x,
blocksnapshot.y,
blocksnapshot.z,
blocksnapshot.replacedBlock,
newBlock,
blocksnapshot.meta,
newMetadata);
}
}
@@ -0,0 +1,55 @@
package com.gtnewhorizon.structurelib.mixins.early.blockChangeNotifier;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.gtnewhorizon.structurelib.event.BlockChangeNotifier;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalIntRef;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
@Mixin(World.class)
public class MixinWorld {
@Inject(
method = "Lnet/minecraft/world/World;setBlock(IIILnet/minecraft/block/Block;II)Z",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/World;markAndNotifyBlock(IIILnet/minecraft/world/chunk/Chunk;Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;I)V",
shift = At.Shift.AFTER,
remap = false))
public void setBlockObserve(int x, int y, int z, Block newBlock, int newMeta, int flags,
CallbackInfoReturnable<Boolean> cir, @Local(name = "block1") Block originalBlock,
@Share("originalMeta") LocalIntRef originalMeta, @Share("chunk") LocalRef<Chunk> chunkLocalRef) {
BlockChangeNotifier.onBlockChange(
(World) ((Object) (this)),
chunkLocalRef.get(),
x,
y,
z,
originalBlock,
newBlock,
originalMeta.get(),
newMeta);
}
@Inject(
method = "Lnet/minecraft/world/World;setBlock(IIILnet/minecraft/block/Block;II)Z",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/chunk/Chunk;func_150807_a(IIILnet/minecraft/block/Block;I)Z",
shift = At.Shift.BEFORE))
public void captureChunkAndOriginalMetadata(int x, int y, int z, Block blockIn, int metadataIn, int flags,
CallbackInfoReturnable<Boolean> cir, @Local(name = "chunk") Chunk chunk,
@Share("originalMeta") LocalIntRef originalMeta, @Share("chunk") LocalRef<Chunk> chunkLocalRef) {
chunkLocalRef.set(chunk);
originalMeta.set(chunk.getBlockMetadata(x & 15, y, z & 15));
}
}
@@ -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.</li>
* <li>The "C" position would be the number of blocks between you and controller, not counting controller itself.</li>
* </ul>
*
*
* @param <T> Type of the context object. Usually this will be the multiblock controller.
*/
public interface IStructureDefinition<T> {
@@ -72,7 +73,7 @@ public interface IStructureDefinition<T> {
/**
* 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<T> {
/**
* 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<T> {
/**
* 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<T> {
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<T> {
/**
* Create a new instance of builder.
*
*
* @param <T> type of context object
*/
static <T> StructureDefinition.Builder<T> builder() {
@@ -32,6 +32,16 @@ public interface IStructureElement<T> {
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<T> {
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);
@@ -31,6 +31,16 @@ public interface IStructureElementChain<T> extends IStructureElement<T> {
return false;
}
@Override
default boolean couldBeValid(T t, World world, int x, int y, int z, ItemStack trigger) {
for (IStructureElement<T> 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<T> fallback : fallbacks()) {
@@ -62,7 +72,8 @@ public interface IStructureElementChain<T> extends IStructureElement<T> {
if (e == null) continue;
if (predicate == null) predicate = e.getPredicate();
else predicate = predicate.or(e.getPredicate());
is.add(e.getStacks());
Iterable<ItemStack> stacks = e.getStacks();
if (stacks != null) is.add(stacks);
}
if (predicate == null) return null;
return new BlocksToPlace(predicate, Iterables.concat(is));
@@ -14,6 +14,11 @@ public interface IStructureElementCheckOnly<T> extends IStructureElement<T> {
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;
@@ -17,6 +17,11 @@ interface IStructureNavigate<T> extends IStructureElement<T> {
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;
@@ -32,6 +32,11 @@ class LazyStructureElement<T> implements IStructureElementDeferred<T> {
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);
@@ -1,8 +1,15 @@
package com.gtnewhorizon.structurelib.structure;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.*;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.isAir;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.notAir;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.step;
import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;
import com.gtnewhorizon.structurelib.util.Vec3Impl;
@@ -2,9 +2,26 @@ package com.gtnewhorizon.structurelib.structure;
import static java.lang.Integer.MIN_VALUE;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.*;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nullable;
@@ -138,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);
@@ -169,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);
@@ -208,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);
@@ -462,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);
@@ -482,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());
@@ -502,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);
@@ -650,9 +697,23 @@ public class StructureUtility {
}
private Pair<Block, Integer> 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<Block, Integer> 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<Block, Integer> hint = getHint(trigger);
@@ -750,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);
@@ -824,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()) {
@@ -904,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);
@@ -941,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);
@@ -965,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);
@@ -999,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);
@@ -1032,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);
@@ -1076,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);
@@ -1141,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);
@@ -1186,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);
@@ -1243,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);
@@ -1270,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);
@@ -1306,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);
@@ -1333,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);
@@ -1399,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);
@@ -1438,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);
@@ -1493,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);
@@ -1519,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);
@@ -1552,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);
@@ -1603,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);
@@ -1661,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);
@@ -1757,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);
@@ -1844,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);
@@ -1897,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);
@@ -2109,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);
@@ -2301,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);
@@ -2545,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
@@ -14,7 +14,10 @@
*/
package com.gtnewhorizon.structurelib.util;
import java.util.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -0,0 +1,64 @@
package com.gtnewhorizon.structurelib.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NavigableMap;
import java.util.Spliterator;
import java.util.TreeMap;
import java.util.function.Consumer;
public class SortedRegistry<V> implements Iterable<V> {
private final NavigableMap<String, V> store = new TreeMap<>();
/**
* Store stuff in an array for faster iteration access than a red black tree
*/
private List<V> baked = Collections.emptyList();
public void register(String key, V val) {
if (key == null || val == null) throw new NullPointerException();
V old = store.putIfAbsent(key, val);
if (old != null) {
throw new IllegalArgumentException("Duplicate key: " + key);
}
// TODO allow a user to edit the order with a configuration file
baked = new ArrayList<>(store.values());
}
public int size() {
return store.size();
}
public boolean isEmpty() {
return store.isEmpty();
}
public boolean containsKey(String key) {
return store.containsKey(key);
}
public boolean containsValue(V value) {
return store.containsValue(value);
}
public V get(String key) {
return store.get(key);
}
@Override
public Iterator<V> iterator() {
return baked.iterator();
}
@Override
public void forEach(Consumer<? super V> action) {
baked.forEach(action);
}
@Override
public Spliterator<V> spliterator() {
return baked.spliterator();
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

@@ -0,0 +1,8 @@
{
"required": true,
"minVersion": "0.8.5-GTNH",
"package": "com.gtnewhorizon.structurelib.mixins.early",
"refmap": "mixins.structurelib.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
}
@@ -0,0 +1,8 @@
{
"required": true,
"minVersion": "0.8.5-GTNH",
"package": "com.gtnewhorizon.structurelib.mixins",
"refmap": "mixins.structurelib.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
}
@@ -0,0 +1,8 @@
{
"required": true,
"minVersion": "0.8.5-GTNH",
"package": "com.gtnewhorizon.structurelib.mixins.late",
"refmap": "mixins.structurelib.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
}