mirror of
https://github.com/BentoBoxWorld/Boxed.git
synced 2024-12-11 14:37:52 +01:00
Better structures
This commit is contained in:
parent
a359f097b9
commit
8915ef18f1
17
pom.xml
17
pom.xml
@ -127,6 +127,15 @@
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>minecraft-repo</id>
|
||||
<url>https://libraries.minecraft.net/</url>
|
||||
</repository>
|
||||
<!-- Spigot NMS required for world regeneration :( -->
|
||||
<repository>
|
||||
<id>nms-repo</id>
|
||||
<url>https://repo.codemc.io/repository/nms/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@ -162,6 +171,14 @@
|
||||
<version>${bentobox.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Spigot NMS. Used for chunk deletion and pasting. -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>${spigot.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -84,22 +84,26 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
||||
Location spot = new Location(user.getWorld(), x, y, z);
|
||||
s.place(spot, true, StructureRotation.NONE, Mirror.NONE, -1, 1, new Random());
|
||||
NewAreaListener.removeJigsaw(spot, s);
|
||||
saveStructure(spot, tag, user);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void saveStructure(Location spot, NamespacedKey tag, User user) {
|
||||
getAddon().getIslands().getIslandAt(spot).ifPresent(i -> {
|
||||
int xx = x - i.getCenter().getBlockX();
|
||||
int zz = z - i.getCenter().getBlockZ();
|
||||
int xx = spot.getBlockX() - i.getCenter().getBlockX();
|
||||
int zz = spot.getBlockZ() - i.getCenter().getBlockZ();
|
||||
File structures = new File(getAddon().getDataFolder(), "structures.yml");
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
try {
|
||||
config.load(structures);
|
||||
config.set("structures.new." + tag.getKey(), user.getWorld().getEnvironment().name().toLowerCase() + ", " + xx + ", " + y + ", " + zz);
|
||||
config.set(spot.getWorld().getEnvironment().name().toLowerCase(Locale.ENGLISH) + "." + xx + "," + spot.getBlockY() + "," + zz, tag.getKey());
|
||||
config.save(structures);
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,9 +1,8 @@
|
||||
package world.bentobox.boxed.listeners;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
@ -15,20 +14,33 @@ import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.block.structure.Mirror;
|
||||
import org.bukkit.block.structure.StructureRotation;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.structure.Structure;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
|
||||
import net.minecraft.core.BlockPosition;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutTileEntityData;
|
||||
import net.minecraft.world.level.block.entity.TileEntity;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.events.island.IslandCreatedEvent;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.boxed.Boxed;
|
||||
|
||||
/**
|
||||
@ -41,7 +53,7 @@ public class NewAreaListener implements Listener {
|
||||
private File structureFile;
|
||||
private Queue<Item> itemsToBuild = new LinkedList<>();
|
||||
private boolean pasting;
|
||||
private record Item(World w, List<Pair<Integer, Integer>> cs, Structure structure, Location location) {};
|
||||
private record Item(String name, Structure structure, Location location) {};
|
||||
Pair<Integer, Integer> min = new Pair<Integer, Integer>(0,0);
|
||||
Pair<Integer, Integer> max = new Pair<Integer, Integer>(0,0);
|
||||
|
||||
@ -51,14 +63,11 @@ public class NewAreaListener implements Listener {
|
||||
*/
|
||||
public NewAreaListener(Boxed addon) {
|
||||
this.addon = addon;
|
||||
addon.saveResource("structures.yml", false);
|
||||
// Load the config
|
||||
structureFile = new File(addon.getDataFolder(), "structures.yml");
|
||||
// Check if it exists and if not, save it from the jar
|
||||
if (!structureFile.exists()) {
|
||||
addon.saveResource("structures.yml", true);
|
||||
}
|
||||
// Try to build something every 5 seconds
|
||||
Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> BuildItem(), 20, 100);
|
||||
// Try to build something every second
|
||||
Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> BuildItem(), 20, 20);
|
||||
}
|
||||
|
||||
private void BuildItem() {
|
||||
@ -68,60 +77,50 @@ public class NewAreaListener implements Listener {
|
||||
Item item = itemsToBuild.poll();
|
||||
LoadChunksAsync(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void onIslandCreated(IslandCreatedEvent e) {
|
||||
public void onIslandCreated(IslandCreatedEvent event) {
|
||||
Island island = event.getIsland();
|
||||
// Check if this island is in this game
|
||||
if (!(addon.inWorld(island.getWorld()))) {
|
||||
return;
|
||||
}
|
||||
// Load the latest config so that admins can change it on the fly without reloading
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(structureFile);
|
||||
//addon.log(e.getEventName());
|
||||
Island island = e.getIsland();
|
||||
addon.getPlugin().getIWM().getAddon(island.getWorld()).ifPresent(gma -> addon.log(gma.getDescription().getName()));
|
||||
// Check if this island is in this game
|
||||
|
||||
Location center = island.getProtectionCenter();
|
||||
|
||||
ConfigurationSection section = config.getConfigurationSection("structures.new");
|
||||
if (section == null) {
|
||||
addon.log("structures.new not found");
|
||||
} else {
|
||||
place("structure",section, center);
|
||||
for (String env : config.getKeys(false)) {
|
||||
Environment e = Enums.getIfPresent(Environment.class, env.toUpperCase(Locale.ENGLISH)).orNull();
|
||||
if (e == null) {
|
||||
addon.logError("Error in structures.yml - unknown environment " + env);
|
||||
} else {
|
||||
place("structure",config.getConfigurationSection(env), center, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void place(String string, ConfigurationSection section, Location center) {
|
||||
private void place(String string, ConfigurationSection section, Location center, Environment env) {
|
||||
World world = env.equals(Environment.NORMAL) ? addon.getOverWorld() : addon.getNetherWorld();
|
||||
// Loop through the structures in the file - there could be more than one
|
||||
for (String structure : section.getKeys(false)) {
|
||||
addon.log(structure);
|
||||
String key = section.getString(structure,"");
|
||||
for (String vector : section.getKeys(false)) {
|
||||
String name = section.getString(vector);
|
||||
// Load Structure
|
||||
Structure s = Bukkit.getStructureManager().loadStructure(NamespacedKey.fromString("minecraft:" + name));
|
||||
if (s == null) {
|
||||
BentoBox.getInstance().logError("Could not load " + name);
|
||||
return;
|
||||
}
|
||||
// Extract coords
|
||||
String[] value = key.split(",");
|
||||
if (value.length == 4) {
|
||||
Environment env = Environment.valueOf(value[0].toUpperCase(Locale.ENGLISH).strip());
|
||||
World world = env.equals(Environment.NORMAL) ? addon.getOverWorld() : addon.getNetherWorld();
|
||||
int x = Integer.valueOf(value[1].strip()) + center.getBlockX();
|
||||
int y = Integer.valueOf(value[2].strip());
|
||||
int z = Integer.valueOf(value[3].strip()) + center.getBlockZ();
|
||||
List<Pair<Integer, Integer>> cs = new ArrayList<>();
|
||||
int size = 10;
|
||||
for (int cx = (x >> 4) - size; cx < (x >>4) + size; cx++) {
|
||||
for (int cz = (z >> 4) - size; cz < (z >>4) + size; cz++) {
|
||||
cs.add(new Pair<>(cx, cz));
|
||||
}
|
||||
}
|
||||
// Load Structure
|
||||
Structure s = Bukkit.getStructureManager().loadStructure(NamespacedKey.fromString("minecraft:" + structure));
|
||||
if (s == null) {
|
||||
BentoBox.getInstance().logError("Could not load " + structure);
|
||||
return;
|
||||
}
|
||||
String[] value = vector.split(",");
|
||||
if (value.length == 3) {
|
||||
int x = Integer.valueOf(value[0].strip()) + center.getBlockX();
|
||||
int y = Integer.valueOf(value[1].strip());
|
||||
int z = Integer.valueOf(value[2].strip()) + center.getBlockZ();
|
||||
Location l = new Location(world, x, y, z);
|
||||
itemsToBuild.add(new Item(world, cs, s, l));
|
||||
itemsToBuild.add(new Item(name, s, l));
|
||||
} else {
|
||||
addon.logError("Structure file syntax error: " + structure + " " + key);
|
||||
addon.logError("Structure file syntax error: " + name + " " + vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,7 +129,7 @@ public class NewAreaListener implements Listener {
|
||||
private void LoadChunksAsync(Item item) {
|
||||
pasting = true;
|
||||
item.structure().place(item.location(), true, StructureRotation.NONE, Mirror.NONE, -1, 1, new Random());
|
||||
addon.log("Structure placed at " + item.location);
|
||||
addon.log(item.name() + " placed at " + item.location().getWorld().getName() + " " + Util.xyz(item.location().toVector()));
|
||||
// Find it
|
||||
removeJigsaw(item.location(), item.structure());
|
||||
pasting = false;
|
||||
@ -151,14 +150,60 @@ public class NewAreaListener implements Listener {
|
||||
b.setType(Material.STRUCTURE_VOID);
|
||||
} else if (b.getType().equals(Material.STRUCTURE_BLOCK)) {
|
||||
// I would like to read the data from the block an do something with it!
|
||||
String data = nmsData(b);
|
||||
b.setType(Material.STRUCTURE_VOID);
|
||||
BentoBox.getInstance().logDebug(data);
|
||||
int index = data.indexOf("metadata:");
|
||||
if (index > -1) {
|
||||
data = data.substring(index + 10, data.length());
|
||||
index = data.indexOf("\"");
|
||||
data = data.substring(0, index);
|
||||
BentoBox.getInstance().logDebug(data);
|
||||
EntityType type = Enums.getIfPresent(EntityType.class, data.toUpperCase(Locale.ENGLISH)).orNull();
|
||||
if (type != null) {
|
||||
if (loc.getWorld().spawnEntity(loc, type) != null) {
|
||||
BentoBox.getInstance().logDebug("Spawned a " + type);
|
||||
}
|
||||
}
|
||||
if (data.contains("chest")) {
|
||||
Block downBlock = b.getRelative(BlockFace.DOWN);
|
||||
if (downBlock.getType().equals(Material.CHEST)) {
|
||||
Chest chest = (Chest)downBlock.getState();
|
||||
chest.getInventory().addItem(new ItemStack(Material.GOLD_INGOT, 3));
|
||||
if (chest.getBlockData() instanceof Waterlogged wl) {
|
||||
if (wl.isWaterlogged()) {
|
||||
b.setType(Material.WATER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static String nmsData(Block block) {
|
||||
Location w = block.getLocation();
|
||||
CraftWorld cw = (CraftWorld) w.getWorld(); // CraftWorld is NMS one
|
||||
// for 1.13+ (we have use WorldServer)
|
||||
TileEntity te = cw.getHandle().c_(new BlockPosition(w.getBlockX(), w.getBlockY(), w.getBlockZ()));
|
||||
try {
|
||||
PacketPlayOutTileEntityData packet = ((PacketPlayOutTileEntityData) te.h()); // get update packet from NMS object
|
||||
// here we should use reflection because "c" field isn't accessible
|
||||
Field f = packet.getClass().getDeclaredField("c"); // get field
|
||||
f.setAccessible(true); // make it available
|
||||
NBTTagCompound nbtTag = (NBTTagCompound) f.get(packet);
|
||||
return nbtTag.toString(); // this will show what you want
|
||||
} catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
}
|
||||
return "Nothing";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,19 @@
|
||||
tructures:
|
||||
new:
|
||||
village/plains/houses/plains_masons_house_1: "normal, 0 ,64, 80"
|
||||
ruined_portal/portal_5: "normal, -38, 66, 20"
|
||||
shipwreck/rightsideup_backhalf: "normal, 3, 59, -60"
|
||||
|
||||
normal:
|
||||
0,64,80: village/plains/houses/plains_masons_house_1
|
||||
-38,63,20: ruined_portal/portal_5
|
||||
3,58,-60: shipwreck/rightsideup_backhalf
|
||||
16,67,23: village/plains/houses/plains_cartographer_1
|
||||
-66,63,17: igloo/top
|
||||
-34,52,-35: underwater_ruin/warm_5
|
||||
80,71,113: pillager_outpost/watchtower
|
||||
33,70,-34: village/savanna/town_centers/savanna_meeting_point_1
|
||||
34,70,-29: village/common/iron_golem
|
||||
41,70,-26: village/common/animals/cat_calico
|
||||
35,70,-22: village/common/animals/cat_calico
|
||||
nether:
|
||||
62,33,-17: bastion/hoglin_stable/walls/wall_base
|
||||
68,32,-13: bastion/hoglin_stable/large_stables/inner_0
|
||||
79,33,-10: bastion/hoglin_stable/ramparts/ramparts_1
|
||||
75,34,-4: bastion/hoglin_stable/ramparts/ramparts_3
|
||||
66,39,-7: bastion/hoglin_stable/large_stables/inner_3
|
||||
73,24,-8: bastion/hoglin_stable/stairs/stairs_3_3
|
||||
|
Loading…
Reference in New Issue
Block a user