Compare commits

..
11 Commits
Author SHA1 Message Date
Martin Robertz 1b7fe15299 Merge remote-tracking branch 'ReignOfFROZE/master' into dev 2025-04-20 21:58:47 +02:00
Martin Robertz 3cbd6cf581 update 2025-04-12 23:09:52 +02:00
Martin Robertz 9d06da9b3b fix 2025-04-12 11:22:49 +02:00
Martin Robertz 88d5991161 update 2025-04-12 11:17:31 +02:00
Martin Robertz cce7372675 Merge remote-tracking branch 'origin/feature/channel-desc' into dev
# Conflicts:
#	dependencies.gradle
#	src/main/java/com/gtnewhorizon/structurelib/StructureLib.java
#	src/main/java/com/gtnewhorizon/structurelib/StructureLibAPI.java
#	src/main/java/com/gtnewhorizon/structurelib/gui/GuiScreenConfigureChannels.java
#	src/main/java/com/gtnewhorizon/structurelib/structure/IStructureDefinition.java
#	src/main/resources/assets/structurelib/lang/en_US.lang
#	src/main/resources/assets/structurelib/lang/zh_CN.lang
#	src/main/resources/assets/structurelib/textures/gui/channels.png
2025-04-12 11:16:46 +02:00
Glease 24403a82ce spotless
Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
2025-04-11 17:15:54 +08:00
Glease b775c1068d add gui tutorial and remove debug code
Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
2025-04-11 17:11:00 +08:00
Glease 6a557c9aa0 bruh
Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
2025-04-08 14:53:47 +08:00
Glease 14d7219b41 change NEI to a implementation dependency
Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
2025-04-08 14:46:12 +08:00
Glease faa3e75ed1 spotless
Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
2025-04-08 14:34:32 +08:00
Glease df96277bd7 add channel desc and channel indicator item
Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
2025-04-08 14:32:10 +08:00
14 changed files with 158 additions and 135 deletions

No files matched your search

+5 -3
View File
@@ -1,13 +1,15 @@
// Add your dependencies here
dependencies {
api("com.github.GTNewHorizons:GTNHLib:0.6.31:dev")
implementation("com.github.GTNewHorizons:NotEnoughItems:2.7.56-GTNH:dev")
api("com.github.GTNewHorizons:GTNHLib:0.6.19:dev")
implementation("com.github.GTNewHorizons:NotEnoughItems:2.7.38-GTNH:dev")
compileOnly("com.github.GTNewHorizons:ServerUtilities:2.1.41-pre")
testImplementation(platform('org.junit:junit-bom:5.9.2'))
testImplementation('org.junit.jupiter:junit-jupiter')
// runtimeOnlyNonPublishable("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.261:dev") {
// runtimeOnlyNonPublishable("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.234:dev") {
// exclude group: "com.github.GTNewHorizons", module: "StructureLib"
// }
}
+1 -1
View File
@@ -37,7 +37,7 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co
# Select a default username for testing your mod. You can always override this per-run by running
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
developmentEnvironmentUserName = Developer
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.
-1
View File
@@ -1,5 +1,4 @@
// Add any additional repositiroes for your dependencies here
repositories {
mavenLocal()
}
@@ -260,6 +260,11 @@ public class ClientProxy extends CommonProxy {
MinecraftForge.EVENT_BUS.register(new ForgeEventHandler());
}
@Override
public void init(FMLInitializationEvent e) {
super.init(e);
}
static void markTextureUsed(IIcon icon) {
if (StructureLib.COMPAT instanceof IStructureCompat)
((IStructureCompat) StructureLib.COMPAT).markTextureUsed(icon);
@@ -67,6 +67,8 @@ public class CommonProxy {
public void preInit(FMLPreInitializationEvent e) {}
public void init(FMLInitializationEvent e) {}
public long getOverworldTime() {
return MinecraftServer.getServer().getEntityWorld().getTotalWorldTime();
}
@@ -1,11 +1,8 @@
package com.gtnewhorizon.structurelib;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
public interface IStructureCompat {
void markTextureUsed(IIcon o);
boolean checkServerUtilitiesPermission(World world, EntityPlayer actor, int x, int z);
}
@@ -93,7 +93,7 @@ public class StructureLib {
@Mod.Instance
static StructureLib INSTANCE;
@Mod.Instance(STRUCTURECOMPAT_MODID)
public static Object COMPAT;
static Object COMPAT;
static Block blockHint;
static Item itemBlockHint;
@@ -129,6 +129,11 @@ public class StructureLib {
DevelopHelper.onPreInit();
}
@Mod.EventHandler
public void init(FMLInitializationEvent e) {
proxy.init(e);
}
@Mod.EventHandler
public void loadComplete(FMLLoadCompleteEvent e) {
proxy.loadComplete(e);
@@ -23,15 +23,29 @@ import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
import com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility;
public class ItemConstructableTrigger extends ModeToggleableItem {
public class ItemConstructableTrigger extends Item {
private static final String TAG_MODE = "mode";
private static final IIcon[] textures = new IIcon[3];
public enum TriggerMode {
BUILDING,
UPDATING,
REMOVING
}
public ItemConstructableTrigger() {
setUnlocalizedName("structurelib.constructableTrigger");
setCreativeTab(StructureLib.creativeTab);
}
public static void cycleMode(ItemStack held) {
if (held.getTagCompound() == null) held.setTagCompound(new NBTTagCompound());
if (!held.getTagCompound().hasKey(TAG_MODE)) held.getTagCompound().setTag(TAG_MODE, new NBTTagInt(0));
held.getTagCompound().setInteger(TAG_MODE, (held.getTagCompound().getInteger(TAG_MODE) + 1) % 3);
}
@Override
public void registerIcons(IIconRegister register) {
textures[0] = register.registerIcon(MOD_ID + ":constructableTrigger/BUILDING");
@@ -75,6 +89,15 @@ public class ItemConstructableTrigger extends ModeToggleableItem {
+ StatCollector.translateToLocal("item.structurelib.constructableTrigger.modes." + mode);
}
public static TriggerMode getMode(ItemStack held) {
if (held == null || !held.hasTagCompound() || !held.getTagCompound().hasKey(TAG_MODE)) {
// default behavior
return TriggerMode.BUILDING;
}
// get user-defined mode
return TriggerMode.values()[held.getTagCompound().getInteger(TAG_MODE)];
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) {
if (!world.isRemote && getMovingObjectPositionFromPlayer(world, player, true) == null) {
@@ -1,32 +0,0 @@
package com.gtnewhorizon.structurelib.item;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagInt;
public class ModeToggleableItem extends Item {
public enum TriggerMode {
BUILDING,
UPDATING,
REMOVING
}
public static TriggerMode getMode(ItemStack held) {
if (held == null || !held.hasTagCompound() || !held.getTagCompound().hasKey(TAG_MODE)) {
// default behavior
return TriggerMode.BUILDING;
}
// get user-defined mode
return TriggerMode.values()[held.getTagCompound().getInteger(TAG_MODE)];
}
public static void cycleMode(ItemStack held) {
if (held.getTagCompound() == null) held.setTagCompound(new NBTTagCompound());
if (!held.getTagCompound().hasKey(TAG_MODE)) held.getTagCompound().setTag(TAG_MODE, new NBTTagInt(0));
held.getTagCompound().setInteger(TAG_MODE, (held.getTagCompound().getInteger(TAG_MODE) + 1) % 3);
}
protected static final String TAG_MODE = "mode";
}
@@ -379,7 +379,7 @@ public interface IStructureDefinition<T> {
basePositionC,
hintsOnly ? ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
e.spawnHint(object, world, x, y, z, trigger);
if (ChannelDataAccessor.hasSubChannel(trigger, "show_error")
if (ChannelDataAccessor.hasSubChannel(trigger, StructureLibAPI.CHANNEL_SHOW_ERROR)
&& !e.couldBeValid(object, world, x, y, z, trigger)) {
StructureLibAPI.markHintParticleError(StructureLib.getCurrentPlayer(), world, x, y, z);
}
@@ -2,7 +2,7 @@ package com.gtnewhorizon.structurelib.structure;
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
import static com.gtnewhorizon.structurelib.item.ModeToggleableItem.TriggerMode.REMOVING;
import static com.gtnewhorizon.structurelib.item.ItemConstructableTrigger.TriggerMode.REMOVING;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.checkForRemoving;
import java.util.Arrays;
@@ -1,21 +1,35 @@
package com.gtnewhorizon.structurelib.structure;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizon.structurelib.IStructureCompat;
import com.gtnewhorizon.structurelib.StructureEvent.StructureElementVisitedEvent;
import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.StructureLibAPI;
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult;
import com.gtnewhorizon.structurelib.structure.adders.IBlockAdder;
import com.gtnewhorizon.structurelib.structure.adders.ITileAdder;
import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
import com.gtnewhorizon.structurelib.util.Vec3Impl;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.registry.GameRegistry;
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
import static com.gtnewhorizon.structurelib.item.ItemConstructableTrigger.TriggerMode.BUILDING;
import static com.gtnewhorizon.structurelib.item.ItemConstructableTrigger.TriggerMode.REMOVING;
import static com.gtnewhorizon.structurelib.item.ItemConstructableTrigger.TriggerMode.UPDATING;
import static java.lang.Integer.MIN_VALUE;
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.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;
import net.minecraft.block.Block;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
@@ -31,18 +45,27 @@ import net.minecraft.util.IChatComponent;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.*;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizon.structurelib.StructureEvent.StructureElementVisitedEvent;
import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.StructureLibAPI;
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult;
import com.gtnewhorizon.structurelib.structure.adders.IBlockAdder;
import com.gtnewhorizon.structurelib.structure.adders.ITileAdder;
import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
import com.gtnewhorizon.structurelib.util.Vec3Impl;
import com.gtnewhorizon.structurelib.xmod.ServerUtilitiesCompat;
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
import static com.gtnewhorizon.structurelib.item.ModeToggleableItem.TriggerMode.*;
import static java.lang.Integer.MIN_VALUE;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.registry.GameRegistry;
/**
* A brief index of everything contained
@@ -386,31 +409,23 @@ public class StructureUtility {
}
}
}
if (mode == REMOVING) {
// We're in removing mode, so let's check some stuff
if (world.isAirBlock(x, y, z)) {
return PlaceResult.SKIP;
}
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
if (!checkPermission(world, actor, x, y, z)) {
return PlaceResult.REJECT;
}
world.setBlockToAir(x, y, z);
if (!tryGiveOrDropItem(world, actor, toGive)) {
// We're in removing mode and something went wrong while trying to give the player the block we removed,
// let's just fail for now
return PlaceResult.REJECT;
}
} else if (!s.takeOne(stack, false)) {
// If the user didn't have the block in their inventory, and we're in some
if (mode == REMOVING || !s.takeOne(stack, false)) {
// If we're in removing mode, or if the user didn't have the block in their inventory, and we're in some
// other mode, let's check some stuff
if (world.isAirBlock(x, y, z)) {
return PlaceResult.SKIP;
}
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
if (mode == REMOVING && !checkPermission(world, actor, x, y, z)) {
return PlaceResult.REJECT;
}
world.setBlockToAir(x, y, z);
if (mode == REMOVING && !tryGiveOrDropItem(world, actor, toGive)) {
// We're in removing mode and something went wrong while trying to give the player the block we removed,
// let's just fail for now
return PlaceResult.REJECT;
}
}
return PlaceResult.ACCEPT;
}
@@ -554,30 +569,22 @@ public class StructureUtility {
return PlaceResult.REJECT;
}
}
if (mode == REMOVING) {
if (mode == REMOVING || !s.takeOne(stack, false)) {
if (world.isAirBlock(x, y, z)) {
return PlaceResult.SKIP;
}
// If we're in removing mode, we set it to air
// If the user didn't have the item in their inventory, or we're in removing mode, we set it to air
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
if (!checkPermission(world, actor, x, y, z)) {
if (mode == REMOVING && !checkPermission(world, actor, x, y, z)) {
return PlaceResult.REJECT;
}
world.setBlockToAir(x, y, z);
if (!tryGiveOrDropItem(world, actor, toGive)) {
if (mode == REMOVING && !tryGiveOrDropItem(world, actor, toGive)) {
// We were in removing mode and something went wrong while trying to give the player the block we
// ...removed, let's just fail for now
return PlaceResult.REJECT;
}
} else if (!s.takeOne(stack, false)) {
if (world.isAirBlock(x, y, z)) {
return PlaceResult.SKIP;
}
// If the user didn't have the item in their inventory, we set it to air
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
world.setBlockToAir(x, y, z);
}
return PlaceResult.ACCEPT;
}
@@ -761,20 +768,7 @@ public class StructureUtility {
* given tier, then player will be allowed to use multiple kinds of blocks, but their tier is guaranteed to be the
* same.
* <p>
* <h4>WARNING</h4> <b>You SHOULD NOT return notSet from your tierExtractor.</b> If you do so, we will have this
* chain of events:
* <ul>
* <li>at check start, tier is reset to notSet
* <li>the tier extractor returns notSet for first block, so since ofBlocksTiered finds your current tier is notSet,
* and the new block's tier is the same as that, so it's accepted
* <li>at 2nd, 3rd..., same thing in 2 happens
* <li>at last occurrence, player placed a valid block with a tier not notSet. ofBlocksTiered now sets your current
* tier to this tier, and accept the block
* <li>check got notified structure is sound, and tier is not notSet. it marks the structure as complete and start
* doing its business
* <li>Player enjoy a (probably) hilariously shaped multi and (probably) reduced build cost.
* </ul>
* <h4>Example Implementation</h4>
* <b>Example Implementation:</b>
* <p>
* Assume you have 16 tier, each map to one particular block's 16 different meta. You will usually want something
* like this
@@ -801,7 +795,7 @@ public class StructureUtility {
* }
* </pre>
*
* Important bits of this example implementation:
* Important bits:
* <ul>
* <li>The supplied ITierConverter returns null for an invalid block</li>
* <li>Possible tier returned by ITierConverter is Integer object 0 to 15.</li>
@@ -810,8 +804,19 @@ public class StructureUtility {
* <li>notSet is never a tier returned by ITierConverter.</li>
* </ul>
* <p>
* As a friendly reminder, the above characteristics are only for this simply demo, not as a general restriction
* imposed by ofBlocksTiered.
* <p>
* <b>You SHOULD NOT return notSet from your tierExtractor.</b> If you do so, we will have this chain of events:
* <ul>
* <li>at check start, tier is reset to notSet
* <li>the tier extractor returns notSet for first block, so since ofBlocksTiered finds your current tier is notSet,
* and the new block's tier is the same as that, so it's accepted
* <li>at 2nd, 3rd..., same thing in 2 happens
* <li>at last occurrence, player placed a valid block with a tier not notSet. ofBlocksTiered now sets your current
* tier to this tier, and accept the block
* <li>check got notified structure is sound, and tier is not notSet. it marks the structure as complete and start
* doing its business
* <li>Player enjoy a (probably) hilariously shaped multi and (probably) reduced build cost.
* </ul>
*
* @param tierExtractor a function to extract tier info from a block. This function can return null and will never
* be passed a null block or an invalid block meta. If this function returns null, then the
@@ -901,14 +906,10 @@ public class StructureUtility {
Block block = world.getBlock(x, y, z);
int meta = world.getBlockMetadata(x, y, z);
TIER tier = tierExtractor.convert(block, meta);
if (mode == REMOVING) {
if (!isInAllKnownTiers(block) && !world.isAirBlock(x, y, z)) {
return PlaceResult.REJECT;
}
} else {
if ((Objects.equals(tier, tierExtractor.convert(hint.getKey(), hint.getValue())))) {
return PlaceResult.SKIP;
}
if (mode != REMOVING && (Objects.equals(tier, tierExtractor.convert(hint.getKey(), hint.getValue()))))
return PlaceResult.SKIP;
if (mode == REMOVING && (!isInAllKnownTiers(block) && !world.isAirBlock(x, y, z))) {
return PlaceResult.REJECT;
}
return StructureUtility.survivalPlaceBlock(
hint.getKey(),
@@ -2047,6 +2048,7 @@ public class StructureUtility {
@Deprecated
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
if (predicate.test(t))
return downstream.survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
return placeResultWhenDisabled;
@@ -2055,6 +2057,7 @@ public class StructureUtility {
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
AutoPlaceEnvironment env) {
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
if (predicate.test(t)) return downstream.survivalPlaceBlock(t, world, x, y, z, trigger, env);
return placeResultWhenDisabled;
}
@@ -3461,8 +3464,8 @@ public class StructureUtility {
public static boolean checkPermission(World world, EntityPlayer actor, int x, int y, int z) {
boolean res = true;
if (isSULoaded && StructureLib.COMPAT instanceof IStructureCompat isc) {
res = isc.checkServerUtilitiesPermission(world, actor, x, z);
if (isSULoaded) {
res = ServerUtilitiesCompat.checkPermission(world, actor, x, z);
}
res = res && !world.getBlock(x, y, z).isAssociatedBlock(Blocks.bedrock);
// maybe check mining level who knows :shrug:
@@ -0,0 +1,29 @@
package com.gtnewhorizon.structurelib.xmod;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import cpw.mods.fml.common.Optional;
import serverutils.data.ClaimedChunks;
import serverutils.lib.data.ForgePlayer;
import serverutils.lib.data.ForgeTeam;
import serverutils.lib.data.Universe;
import serverutils.lib.math.ChunkDimPos;
public class ServerUtilitiesCompat {
@Optional.Method(modid = "serverutilities")
public static boolean checkPermission(World world, EntityPlayer actor, int x, int z) {
final ForgeTeam owningTeam = ClaimedChunks.instance
.getChunkTeam(new ChunkDimPos(x >> 4, z >> 4, world.provider.dimensionId));
if (owningTeam == null) {
return true;
}
final ForgePlayer currentPlayer = new ForgePlayer(
Universe.get(),
actor.getUniqueID(),
actor.getCommandSenderName());
return owningTeam.isAlly(currentPlayer) || owningTeam.isMember(currentPlayer);
}
}
-10
View File
@@ -133,16 +133,6 @@ StructureLib API documentation.
Usually there is no reason to reimplement this on your own.
</p>
<h2>{@link com.gtnewhorizon.structurelib.item.ModeToggleableItem}</h2>
<p>
This class is the base class for {@link com.gtnewhorizon.structurelib.item.ItemConstructableTrigger} that defines
the <code>TriggerMode</code>s for the {@link com.gtnewhorizon.structurelib.item.ItemConstructableTrigger}. There are
3 modes, <code>BUILDING</code>, <code>UPDATING</code>, and <code>REMOVING</code>. Each of these modes does as they
say, where building will build a new multi from scratch, updating will remove existing an existing structure and
replace it with new components (think upgrading glass on a multi, changing from a tier 1 to tier 2 of a multi, etc),
and removing will just straight up remove the multi.
</p>
<h2><a href="#channels" id="channels">Channels</a></h2>
<p>