diff --git a/build.gradle b/build.gradle index c64cff8..bfc6222 100644 --- a/build.gradle +++ b/build.gradle @@ -20,18 +20,6 @@ repositories { mavenCentral() } -loom { - splitEnvironmentSourceSets() - - mods { - "modid" { - sourceSet sourceSets.main - sourceSet sourceSets.client - } - } - -} - dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" diff --git a/gradle.properties b/gradle.properties index 5be4d52..d9504af 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ loader_version=0.14.21 fabric_version=0.84.0+1.20.1 #Mod properties -mod_version = 0.9.2 +mod_version = 0.9.4 maven_group = quimufu.structure_item archives_base_name = structure_item diff --git a/src/main/java/quimufu/structure_item/MyItem.java b/src/main/java/quimufu/structure_item/MyItem.java index 5a74e0c..3fd6cbf 100644 --- a/src/main/java/quimufu/structure_item/MyItem.java +++ b/src/main/java/quimufu/structure_item/MyItem.java @@ -83,6 +83,7 @@ public class MyItem extends Item { if (i == 4) { texts.add(Text.translatable("item.structure_item.item.tooltip.blacklist.more", Text.literal(String.valueOf(bl.size() - i)))); + break; } } } @@ -96,6 +97,15 @@ public class MyItem extends Item { } else { texts.add(Text.translatable("item.structure_item.item.tooltip.doNotPlaceEntities")); } + if (tag.contains("rotate", NbtElement.STRING_TYPE)) { + texts.add(Text.translatable("item.structure_item.item.tooltip.dynamic.rotation")); + texts.add(Text.translatable("item.structure_item.item.tooltip.dynamic.rotation.value", + Text.translatable("item.structure_item.item.tooltip.dynamic.dir." + tag.getString("rotate")))); + } else { + texts.add(Text.translatable("item.structure_item.item.tooltip.fixed.rotation")); + + } + } } @@ -165,15 +175,40 @@ public class MyItem extends Item { } StructureTemplate x = xOpt.get(); + BlockRotation rotation = BlockRotation.NONE; + if (tag.contains("rotate", NbtElement.STRING_TYPE)) { + String defaultOrientation = tag.getString("rotate"); + + Direction defaultDir = Direction.byName(defaultOrientation); + Direction currentDir = c.getSide(); + + if (defaultDir == null) { + Text message = + Text.translatable("items.structure.spawner.invalid.rotate", + Text.literal(defaultOrientation)); + sendPlayerChat(player, message); + } else { + rotation = getRotationBetween(defaultDir, currentDir); + } + } + BlockPos loc = c.getBlockPos().offset(c.getSide()); if (tag.contains("offset", 10)) { BlockPos offset = NbtHelper.toBlockPos(tag.getCompound("offset")); loc = loc.add(offset); + + Vec3i size = x.getSize(); + switch (rotation) { + case CLOCKWISE_90 -> loc = loc.add(new Vec3i(size.getX()-1, 0, 0)); + case CLOCKWISE_180 -> loc = loc.add(new Vec3i(size.getX()-1, 0, size.getZ()-1)); + case COUNTERCLOCKWISE_90 -> loc = loc.add(new Vec3i(0, 0, size.getZ()-1)); + } } else if (tag.contains("offsetV2", 10)) { Direction direction = c.getSide().getOpposite(); try { StructureOffsetSettings offset = StructureOffsetSettings.ofTag(tag.getCompound("offsetV2")); + offset.setRotation(rotation); Vec3i size = x.getSize(); loc = loc.add(offset.getEffective(direction, size)); } catch (Exception e) { @@ -185,11 +220,12 @@ public class MyItem extends Item { } else { Direction direction = c.getSide().getOpposite(); StructureOffsetSettings offset = StructureOffsetSettings.dynamic(); + offset.setRotation(rotation); Vec3i size = x.getSize(); loc = loc.add(offset.getEffective(direction, size)); } - MyPlacementSettings ps = (new MyPlacementSettings()); + MyPlacementSettings ps = new MyPlacementSettings(); if (tag.contains("replaceEntities", 99)) { ps.setReplaceEntities(tag.getBoolean("replaceEntities")); } @@ -213,15 +249,17 @@ public class MyItem extends Item { } ps.forbidOverwrite(blacklist); } + + ps.setWorld(c.getWorld()) .setSize(x.getSize()) .setMirror(BlockMirror.NONE) - .setRotation(BlockRotation.NONE); + .setRotation(rotation); boolean success = false; try { - if (x.place((ServerWorld) c.getWorld(), loc, loc, ps, c.getWorld().getRandom(), 2)) + if (x.place((ServerWorld) c.getWorld(), loc, BlockPos.ORIGIN, ps, c.getWorld().getRandom(), 2)) success = true; - } catch (NullPointerException ignored) { + } catch (PlacementNotAllowedException ignored) { } if (success) { c.getStack().decrement(1); @@ -235,6 +273,22 @@ public class MyItem extends Item { return ActionResult.FAIL; } + private BlockRotation getRotationBetween(Direction from, Direction to) { + if (to == Direction.DOWN || to == Direction.UP) { + return BlockRotation.NONE; + } + if (from.getOpposite() == to) { + return BlockRotation.CLOCKWISE_180; + } + if (from.rotateYClockwise() == to) { + return BlockRotation.CLOCKWISE_90; + } + if (from.rotateYCounterclockwise() == to) { + return BlockRotation.COUNTERCLOCKWISE_90; + } + return BlockRotation.NONE; + } + private static void sendPlayer(ServerPlayerEntity player, Text message) { if (player == null) return; diff --git a/src/main/java/quimufu/structure_item/MyPlacementSettings.java b/src/main/java/quimufu/structure_item/MyPlacementSettings.java index ce1cfd5..59ec9bb 100644 --- a/src/main/java/quimufu/structure_item/MyPlacementSettings.java +++ b/src/main/java/quimufu/structure_item/MyPlacementSettings.java @@ -4,12 +4,18 @@ import com.google.common.collect.Lists; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.structure.StructurePlacementData; import net.minecraft.structure.StructureTemplate; +import net.minecraft.structure.processor.BlockIgnoreStructureProcessor; +import net.minecraft.structure.processor.StructureProcessor; +import net.minecraft.structure.processor.StructureProcessorType; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; +import net.minecraft.world.WorldView; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -20,6 +26,11 @@ public class MyPlacementSettings extends StructurePlacementData { private Vec3i size; private boolean replaceEntities = true; + public MyPlacementSettings() { + addProcessor(BlockIgnoreStructureProcessor.IGNORE_STRUCTURE_BLOCKS); + addProcessor(new CheckingStructureProcess()); + } + public void forbidOverwrite(List blocks) { if (blocks.size() == 0) { blacklist = null; @@ -38,69 +49,6 @@ public class MyPlacementSettings extends StructurePlacementData { return this; } - @Override - public StructureTemplate.PalettedBlockInfoList getRandomBlockInfos(List blocks, BlockPos pos) { - if (world == null || pos == null || size == null) { - return super.getRandomBlockInfos(blocks, pos); - } - - List eligibleStructures; - eligibleStructures = getEligibleStructures(blocks, pos); - if (eligibleStructures.size() == 0) - return null; - StructureTemplate.PalettedBlockInfoList randomBlockInfos = super.getRandomBlockInfos(eligibleStructures, pos); - List locs = randomBlockInfos.getAll(); - if (!locs.isEmpty()) { - List entitiesWithinAABB = world.getNonSpectatingEntities(Entity.class, new Box(pos,pos.add(size))); - for (StructureTemplate.StructureBlockInfo blockInfo : locs) { - BlockPos posToClean = blockInfo.pos().add(pos); - for (Entity e : entitiesWithinAABB) { - if (!(e instanceof PlayerEntity) && e.getBoundingBox().intersects(new Box(posToClean))) { - e.remove(Entity.RemovalReason.DISCARDED); - } - } - } - } - return randomBlockInfos; - } - - private List getEligibleStructures(List blocks, BlockPos pos) { - List eligibleStructures = new ArrayList<>(); - if (blacklist == null && shouldReplaceEntities()) { - eligibleStructures = blocks; - } else { - for (StructureTemplate.PalettedBlockInfoList struct : blocks) { - if (isValid(struct, pos)) { - eligibleStructures.add(struct); - } - } - } - return eligibleStructures; - } - - private boolean isValid(StructureTemplate.PalettedBlockInfoList struct, BlockPos pos) { - List entitiesWithinAABB; - if (shouldReplaceEntities()) { - entitiesWithinAABB = world.getNonSpectatingEntities(PlayerEntity.class, new Box(pos, pos.add(size))); - } else { - entitiesWithinAABB = world.getNonSpectatingEntities(Entity.class, new Box(pos, pos.add(size))); - } - for (StructureTemplate.StructureBlockInfo bi : struct.getAll()) { - BlockPos posToCheck = bi.pos().add(pos); - if (World.isValid(posToCheck)) { - for (Entity e : entitiesWithinAABB) { - if (e.getBoundingBox().intersects(new Box(posToCheck))) { - return false; - } - } - Block blockToCheck = world.getBlockState(posToCheck).getBlock(); - if(blacklist.contains(blockToCheck)) - return false; - } - } - return true; - } - public boolean shouldReplaceEntities() { return replaceEntities; } @@ -108,4 +56,38 @@ public class MyPlacementSettings extends StructurePlacementData { public void setReplaceEntities(boolean replaceEntities) { this.replaceEntities = replaceEntities; } + + public class CheckingStructureProcess extends StructureProcessor { + + List entitiesWithinAABB; + + @Nullable + @Override + public StructureTemplate.StructureBlockInfo process(WorldView world, BlockPos pos, BlockPos pivot, StructureTemplate.StructureBlockInfo originalBlockInfo, StructureTemplate.StructureBlockInfo currentBlockInfo, StructurePlacementData data) { + if (entitiesWithinAABB == null) { + if (shouldReplaceEntities()) { + entitiesWithinAABB = ((ServerWorld) world).getNonSpectatingEntities(PlayerEntity.class, new Box(pos.subtract(size), pos.add(size))); + } else { + entitiesWithinAABB = ((ServerWorld) world).getNonSpectatingEntities(Entity.class, new Box(pos.subtract(size), pos.add(size))); + } + } + BlockPos posToCheck; + if (currentBlockInfo != null && World.isValid(posToCheck = currentBlockInfo.pos())) { + for (Entity e : entitiesWithinAABB) { + if (e.getBoundingBox().intersects(new Box(posToCheck))) { + throw new PlacementNotAllowedException(); + } + } + Block blockToCheck = world.getBlockState(posToCheck).getBlock(); + if (blacklist.contains(blockToCheck)) + throw new PlacementNotAllowedException(); + } + return currentBlockInfo; + } + + @Override + protected StructureProcessorType getType() { + return null; + } + } } diff --git a/src/main/java/quimufu/structure_item/PlacementNotAllowedException.java b/src/main/java/quimufu/structure_item/PlacementNotAllowedException.java new file mode 100644 index 0000000..48fc18e --- /dev/null +++ b/src/main/java/quimufu/structure_item/PlacementNotAllowedException.java @@ -0,0 +1,4 @@ +package quimufu.structure_item; + +public class PlacementNotAllowedException extends RuntimeException{ +} diff --git a/src/main/java/quimufu/structure_item/StructureOffsetSettings.java b/src/main/java/quimufu/structure_item/StructureOffsetSettings.java index a61d547..0e867b3 100644 --- a/src/main/java/quimufu/structure_item/StructureOffsetSettings.java +++ b/src/main/java/quimufu/structure_item/StructureOffsetSettings.java @@ -1,6 +1,7 @@ package quimufu.structure_item; import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; @@ -23,6 +24,7 @@ public class StructureOffsetSettings { return args[(int) (Math.round(args[0]) + 1L)]; } }; + private BlockRotation rotation; public static StructureOffsetSettings ofTag(NbtCompound offsetTag) { StructureOffsetSettings settings = new StructureOffsetSettings(); @@ -83,30 +85,96 @@ public class StructureOffsetSettings { 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()); - } + switch (rotation) { + case NONE: + switch (direction) { + case WEST: + loc = loc.offset(Direction.NORTH, size.getZ() / 2); + return loc.offset(Direction.WEST, size.getX() - 1); + case EAST://positive x + return loc.offset(Direction.NORTH, size.getZ() / 2); + case NORTH: + loc = loc.offset(Direction.NORTH, size.getZ() - 1); + return loc.offset(Direction.WEST, size.getX() / 2); + case SOUTH://positive z + return 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); + return loc.offset(Direction.UP); + case DOWN: + loc = loc.offset(Direction.NORTH, size.getZ() / 2); + loc = loc.offset(Direction.WEST, size.getX() / 2); + return loc.offset(Direction.DOWN, size.getY()); + } + case CLOCKWISE_90: + switch (direction) { + case WEST: + return loc.offset(Direction.NORTH, size.getX() / 2); + case EAST://positive x + loc = loc.offset(Direction.NORTH, size.getX() / 2); + return loc.offset(Direction.EAST, size.getZ() - 1); + case NORTH: + loc = loc.offset(Direction.NORTH, size.getX() - 1); + return loc.offset(Direction.EAST, size.getZ() / 2); + case SOUTH://positive z + return loc.offset(Direction.EAST, size.getZ() / 2); + case UP://positive y + loc = loc.offset(Direction.NORTH, size.getX() / 2); + loc = loc.offset(Direction.EAST, size.getZ() / 2); + return loc.offset(Direction.UP); + case DOWN: + loc = loc.offset(Direction.NORTH, size.getX() / 2); + loc = loc.offset(Direction.EAST, size.getZ() / 2); + return loc.offset(Direction.DOWN, size.getY()); + } + case CLOCKWISE_180: + switch (direction) { + case WEST: + return loc.offset(Direction.SOUTH, size.getX() / 2); + case EAST://positive x + loc = loc.offset(Direction.SOUTH, size.getZ() / 2); + return loc.offset(Direction.EAST, size.getX() - 1); + case NORTH: + return loc.offset(Direction.EAST, size.getX() / 2); + case SOUTH://positive z + loc = loc.offset(Direction.EAST, size.getX() / 2); + return loc.offset(Direction.SOUTH, size.getZ() - 1); + case UP://positive y + loc = loc.offset(Direction.SOUTH, size.getZ() / 2); + loc = loc.offset(Direction.EAST, size.getX() / 2); + return loc.offset(Direction.UP); + case DOWN: + loc = loc.offset(Direction.SOUTH, size.getZ() / 2); + loc = loc.offset(Direction.EAST, size.getX() / 2); + return loc.offset(Direction.DOWN, size.getY()); + } + case COUNTERCLOCKWISE_90: + switch (direction) { + case WEST: + loc = loc.offset(Direction.SOUTH, size.getX() / 2); + return loc.offset(Direction.WEST, size.getZ() - 1); + case EAST://positive x + return loc.offset(Direction.SOUTH, size.getX() / 2); + case NORTH: + return loc.offset(Direction.WEST, size.getZ() / 2); + case SOUTH://positive z + loc = loc.offset(Direction.SOUTH, size.getX() - 1); + return loc.offset(Direction.WEST, size.getZ() / 2); + case UP://positive y + loc = loc.offset(Direction.SOUTH, size.getX() / 2); + loc = loc.offset(Direction.WEST, size.getZ() / 2); + return loc.offset(Direction.UP); + case DOWN: + loc = loc.offset(Direction.SOUTH, size.getX() / 2); + loc = loc.offset(Direction.WEST, size.getZ() / 2); + return loc.offset(Direction.DOWN, size.getY()); + } } return loc; } + + public void setRotation(BlockRotation rotation) { + this.rotation = rotation; + } } 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 c2d82b2..4adee5a 100644 --- a/src/main/resources/assets/structure_item/lang/en_us.json +++ b/src/main/resources/assets/structure_item/lang/en_us.json @@ -5,6 +5,7 @@ "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.invalid.rotate": "rotate tag invalid direction: %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", @@ -12,7 +13,7 @@ "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.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", @@ -21,7 +22,14 @@ "item.structure_item.item.tooltip.blacklist": "Blacklist:", "item.structure_item.item.tooltip.blacklist.more": " And %s more...", "item.structure_item.item.tooltip.replaceEntities": "Deletes Entities in the way", - "item.structure_item.item.tooltip.doNotReplaceEntities": "Doesn't allow placement with Entities in the way", + "item.structure_item.item.tooltip.doNotReplaceEntities": "Doesn't allow placement with entities in the way", "item.structure_item.item.tooltip.placeEntities": "Places contained Entities", - "item.structure_item.item.tooltip.doNotPlaceEntities": "Doesn't place contained Entities" + "item.structure_item.item.tooltip.doNotPlaceEntities": "Doesn't place contained entities", + "item.structure_item.item.tooltip.dynamic.rotation": "Rotated dynamically", + "item.structure_item.item.tooltip.dynamic.rotation.value": "Player is standing %s of structure ", + "item.structure_item.item.tooltip.dynamic.dir.north": "north", + "item.structure_item.item.tooltip.dynamic.dir.south": "south", + "item.structure_item.item.tooltip.dynamic.dir.east": "east", + "item.structure_item.item.tooltip.dynamic.dir.west": "west", + "item.structure_item.item.tooltip.fixed.rotation": "Fixed rotation" }