diff --git a/build.gradle b/build.gradle index 5e4744f..c64cff8 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,7 @@ repositories { // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. // See https://docs.gradle.org/current/userguide/declaring_repositories.html // for more information about repositories. + mavenCentral() } loom { @@ -42,7 +43,8 @@ dependencies { // Uncomment the following line to enable the deprecated Fabric API modules. // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. - + include 'net.objecthunter:exp4j:0.4.8' + implementation 'net.objecthunter:exp4j:0.4.8' // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" } diff --git a/src/main/java/quimufu/structure_item/MyItem.java b/src/main/java/quimufu/structure_item/MyItem.java index 798a539..5a74e0c 100644 --- a/src/main/java/quimufu/structure_item/MyItem.java +++ b/src/main/java/quimufu/structure_item/MyItem.java @@ -5,7 +5,6 @@ import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.minecraft.block.Block; import net.minecraft.client.item.TooltipContext; import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; import net.minecraft.nbt.NbtCompound; @@ -16,13 +15,10 @@ import net.minecraft.network.packet.s2c.play.SubtitleS2CPacket; import net.minecraft.network.packet.s2c.play.TitleS2CPacket; import net.minecraft.registry.DefaultedRegistry; import net.minecraft.registry.Registries; -import net.minecraft.registry.Registry; -import net.minecraft.registry.SimpleDefaultedRegistry; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.structure.StructureTemplate; -import net.minecraft.text.LiteralTextContent; import net.minecraft.text.Text; import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; @@ -63,6 +59,17 @@ public class MyItem extends Item { Text.literal(String.valueOf(offset.getY())), Text.literal(String.valueOf(offset.getZ()))); texts.add(c); + } else if (tag.contains("offsetV2", 10)) { + + NbtCompound offsetV2 = tag.getCompound("offsetV2"); + + texts.add(Text.translatable("item.structure_item.item.tooltip.v2.offset")); + texts.add(Text.translatable("item.structure_item.item.tooltip.xFuncOff", + Text.literal(String.valueOf(offsetV2.get("x"))))); + texts.add(Text.translatable("item.structure_item.item.tooltip.yFuncOff", + Text.literal(String.valueOf(offsetV2.get("y"))))); + texts.add(Text.translatable("item.structure_item.item.tooltip.zFuncOff", + Text.literal(String.valueOf(offsetV2.get("z"))))); } else { texts.add(Text.translatable("item.structure_item.item.tooltip.dynamic.offset")); } @@ -70,7 +77,7 @@ public class MyItem extends Item { texts.add(Text.translatable("item.structure_item.item.tooltip.blacklist")); NbtList bl = tag.getList("blacklist", 8); int i = 0; - for ( NbtElement entry : bl) { + for (NbtElement entry : bl) { texts.add(Text.literal(" " + entry.asString())); i++; if (i == 4) { @@ -91,6 +98,7 @@ public class MyItem extends Item { } } } + } @Override @@ -162,12 +170,23 @@ public class MyItem extends Item { if (tag.contains("offset", 10)) { BlockPos offset = NbtHelper.toBlockPos(tag.getCompound("offset")); loc = loc.add(offset); - } else if (c.getPlayer() != null) { - Direction direction = Direction.getEntityFacingOrder(c.getPlayer())[0]; - Vec3i size = x.getSize(); - loc = loc.add(getDirectionalOffset(direction, size)); + } else if (tag.contains("offsetV2", 10)) { + Direction direction = c.getSide().getOpposite(); + try { + StructureOffsetSettings offset = StructureOffsetSettings.ofTag(tag.getCompound("offsetV2")); + Vec3i size = x.getSize(); + loc = loc.add(offset.getEffective(direction, size)); + } catch (Exception e) { + Text message = + Text.translatable("items.structure.spawner.invalid.offsetV2", + Text.literal(tag.getCompound("offsetV2").asString()), e.getMessage()); + sendPlayerChat(player, message); + } } else { - LOGGER.info("No player & no offset"); + Direction direction = c.getSide().getOpposite(); + StructureOffsetSettings offset = StructureOffsetSettings.dynamic(); + Vec3i size = x.getSize(); + loc = loc.add(offset.getEffective(direction, size)); } MyPlacementSettings ps = (new MyPlacementSettings()); @@ -200,7 +219,7 @@ public class MyItem extends Item { .setRotation(BlockRotation.NONE); boolean success = false; try { - if(x.place((ServerWorld)c.getWorld(), loc, loc, ps, c.getWorld().getRandom(), 2)) + if (x.place((ServerWorld) c.getWorld(), loc, loc, ps, c.getWorld().getRandom(), 2)) success = true; } catch (NullPointerException ignored) { } @@ -232,35 +251,6 @@ public class MyItem extends Item { LOGGER.info(message.getContent()); } - private BlockPos getDirectionalOffset(Direction direction, Vec3i size) { - BlockPos loc = new BlockPos(0, 0, 0); - switch (direction) { - case WEST -> { - loc = loc.offset(Direction.NORTH, size.getZ() / 2); - loc = loc.offset(Direction.WEST, size.getX() - 1); - } - case EAST -> //positive x - loc = loc.offset(Direction.NORTH, size.getZ() / 2); - case NORTH -> { - loc = loc.offset(Direction.NORTH, size.getZ() - 1); - loc = loc.offset(Direction.WEST, size.getX() / 2); - } - case SOUTH -> //positive z - loc = loc.offset(Direction.WEST, size.getX() / 2); - case UP -> { //positive y - loc = loc.offset(Direction.NORTH, size.getZ() / 2); - loc = loc.offset(Direction.WEST, size.getX() / 2); - loc = loc.offset(Direction.UP); - } - case DOWN -> { - loc = loc.offset(Direction.NORTH, size.getZ() / 2); - loc = loc.offset(Direction.WEST, size.getX() / 2); - loc = loc.offset(Direction.DOWN, size.getY()); - } - } - return loc; - } - private Block getBlock(String loc) { Identifier location = Identifier.tryParse(loc); DefaultedRegistry blocks = Registries.BLOCK; diff --git a/src/main/java/quimufu/structure_item/StructureOffsetSettings.java b/src/main/java/quimufu/structure_item/StructureOffsetSettings.java new file mode 100644 index 0000000..a61d547 --- /dev/null +++ b/src/main/java/quimufu/structure_item/StructureOffsetSettings.java @@ -0,0 +1,112 @@ +package quimufu.structure_item; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3i; +import net.objecthunter.exp4j.Expression; +import net.objecthunter.exp4j.ExpressionBuilder; +import net.objecthunter.exp4j.function.Function; + +import java.util.Arrays; +import java.util.Map; + +public class StructureOffsetSettings { + + Expression[] xyz = new Expression[3]; + String[] xyzS = new String[3]; + boolean[] rel = new boolean[3]; + static Function DIR_SELECT = new Function("dirSelect", 7) { + @Override + public double apply(double... args) { + return args[(int) (Math.round(args[0]) + 1L)]; + } + }; + + public static StructureOffsetSettings ofTag(NbtCompound offsetTag) { + StructureOffsetSettings settings = new StructureOffsetSettings(); + String x1 = offsetTag.getString("x"); + unwrap(x1, settings, 0); + String y1 = offsetTag.getString("y"); + unwrap(y1, settings, 1); + String z1 = offsetTag.getString("z"); + unwrap(z1, settings, 2); + return settings; + } + + private static void unwrap(String expr, StructureOffsetSettings settings, int x) { + if (expr.startsWith("~")) { + settings.rel[x] = true; + expr = expr.substring(1); + } + if (expr.isBlank()) { + expr = "0"; + } + settings.xyzS[x] = expr; + settings.xyz[x] = new ExpressionBuilder(expr) + .variables("sizeX", "sizeY", "sizeZ", "dir") + .function(DIR_SELECT) + .build(); + } + + public static StructureOffsetSettings dynamic() { + StructureOffsetSettings settings = new StructureOffsetSettings(); + for (int i = 0; i < 3; i++) { + settings.xyz[i] = new ExpressionBuilder("0").build(); + settings.xyzS[i] = "0"; + } + Arrays.fill(settings.rel, true); + return settings; + } + + public Vec3i getEffective(Direction direction, Vec3i size) { + int[] xyzI = new int[3]; + for (int i = 0; i < 3; i++) { + xyz[i].setVariables(Map.of("sizeX", (double) size.getX(), + "sizeY", (double) size.getY(), + "sizeZ", (double) size.getZ(), + "dir", (double) direction.getId() + )); + xyzI[i] = MathHelper.floor(xyz[i].evaluate()); + } + Vec3i dynamicOffset = getDirectionalOffset(direction, size); + + int[] xyzDynamicI = {dynamicOffset.getX(), dynamicOffset.getY(), dynamicOffset.getZ()}; + for (int i = 0; i < 3; i++) { + if (rel[i]) { + xyzI[i] += xyzDynamicI[i]; + } + } + return new Vec3i(xyzI[0], xyzI[1], xyzI[2]); + } + + private Vec3i getDirectionalOffset(Direction direction, Vec3i size) { + BlockPos loc = new BlockPos(0, 0, 0); + switch (direction) { + case WEST -> { + loc = loc.offset(Direction.NORTH, size.getZ() / 2); + loc = loc.offset(Direction.WEST, size.getX() - 1); + } + case EAST -> //positive x + loc = loc.offset(Direction.NORTH, size.getZ() / 2); + case NORTH -> { + loc = loc.offset(Direction.NORTH, size.getZ() - 1); + loc = loc.offset(Direction.WEST, size.getX() / 2); + } + case SOUTH -> //positive z + loc = loc.offset(Direction.WEST, size.getX() / 2); + case UP -> { //positive y + loc = loc.offset(Direction.NORTH, size.getZ() / 2); + loc = loc.offset(Direction.WEST, size.getX() / 2); + loc = loc.offset(Direction.UP); + } + case DOWN -> { + loc = loc.offset(Direction.NORTH, size.getZ() / 2); + loc = loc.offset(Direction.WEST, size.getX() / 2); + loc = loc.offset(Direction.DOWN, size.getY()); + } + } + return loc; + } +} diff --git a/src/main/resources/assets/structure_item/lang/en_us.json b/src/main/resources/assets/structure_item/lang/en_us.json index 7df49da..c2d82b2 100644 --- a/src/main/resources/assets/structure_item/lang/en_us.json +++ b/src/main/resources/assets/structure_item/lang/en_us.json @@ -4,6 +4,7 @@ "items.structure.spawner.invalid.structure.name": "Invalid structure name", "items.structure.spawner.structure.nonexistent": "Structure: %s does not exist", "items.structure.spawner.invalid.block": "Block %s invalid", + "items.structure.spawner.invalid.offsetV2": "offsetV2 tag %s invalid: %s", "items.structure.spawner.no.tag": "Item has no NBT tag", "items.structure.spawner.no.structure": "Item has no String \"structure\": tag", "item.structure_item.item": "Structure Spawner", @@ -11,7 +12,11 @@ "item.structure_item.item.tooltip.structure": "Places down: ", "item.structure_item.item.tooltip.allowed.on": "Can be placed on: ", "item.structure_item.item.tooltip.fixed.offset": "Offset:", + "item.structure_item.item.tooltip.v2.offset": "Advanced Offset:", "item.structure_item.item.tooltip.xyz":" x: %s y: %s z: %s", + "item.structure_item.item.tooltip.xFuncOff":" x: %s", + "item.structure_item.item.tooltip.yFuncOff":" y: %s", + "item.structure_item.item.tooltip.zFuncOff":" z: %s", "item.structure_item.item.tooltip.dynamic.offset": "Dynamic offset", "item.structure_item.item.tooltip.blacklist": "Blacklist:", "item.structure_item.item.tooltip.blacklist.more": " And %s more...",