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>
|
<id>codemc-repo</id>
|
||||||
<url>https://repo.codemc.org/repository/maven-public/</url>
|
<url>https://repo.codemc.org/repository/maven-public/</url>
|
||||||
</repository>
|
</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>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -162,6 +171,14 @@
|
|||||||
<version>${bentobox.version}</version>
|
<version>${bentobox.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -84,14 +84,19 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
|||||||
Location spot = new Location(user.getWorld(), x, y, z);
|
Location spot = new Location(user.getWorld(), x, y, z);
|
||||||
s.place(spot, true, StructureRotation.NONE, Mirror.NONE, -1, 1, new Random());
|
s.place(spot, true, StructureRotation.NONE, Mirror.NONE, -1, 1, new Random());
|
||||||
NewAreaListener.removeJigsaw(spot, s);
|
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 -> {
|
getAddon().getIslands().getIslandAt(spot).ifPresent(i -> {
|
||||||
int xx = x - i.getCenter().getBlockX();
|
int xx = spot.getBlockX() - i.getCenter().getBlockX();
|
||||||
int zz = z - i.getCenter().getBlockZ();
|
int zz = spot.getBlockZ() - i.getCenter().getBlockZ();
|
||||||
File structures = new File(getAddon().getDataFolder(), "structures.yml");
|
File structures = new File(getAddon().getDataFolder(), "structures.yml");
|
||||||
YamlConfiguration config = new YamlConfiguration();
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
try {
|
try {
|
||||||
config.load(structures);
|
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);
|
config.save(structures);
|
||||||
} catch (IOException | InvalidConfigurationException e) {
|
} catch (IOException | InvalidConfigurationException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
@ -99,7 +104,6 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package world.bentobox.boxed.listeners;
|
package world.bentobox.boxed.listeners;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.lang.reflect.Field;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@ -15,20 +14,33 @@ import org.bukkit.NamespacedKey;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.World.Environment;
|
import org.bukkit.World.Environment;
|
||||||
import org.bukkit.block.Block;
|
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.Mirror;
|
||||||
import org.bukkit.block.structure.StructureRotation;
|
import org.bukkit.block.structure.StructureRotation;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
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.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.structure.Structure;
|
import org.bukkit.structure.Structure;
|
||||||
import org.bukkit.util.BoundingBox;
|
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.BentoBox;
|
||||||
import world.bentobox.bentobox.api.events.island.IslandCreatedEvent;
|
import world.bentobox.bentobox.api.events.island.IslandCreatedEvent;
|
||||||
import world.bentobox.bentobox.database.objects.Island;
|
import world.bentobox.bentobox.database.objects.Island;
|
||||||
import world.bentobox.bentobox.util.Pair;
|
import world.bentobox.bentobox.util.Pair;
|
||||||
|
import world.bentobox.bentobox.util.Util;
|
||||||
import world.bentobox.boxed.Boxed;
|
import world.bentobox.boxed.Boxed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +53,7 @@ public class NewAreaListener implements Listener {
|
|||||||
private File structureFile;
|
private File structureFile;
|
||||||
private Queue<Item> itemsToBuild = new LinkedList<>();
|
private Queue<Item> itemsToBuild = new LinkedList<>();
|
||||||
private boolean pasting;
|
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> min = new Pair<Integer, Integer>(0,0);
|
||||||
Pair<Integer, Integer> max = 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) {
|
public NewAreaListener(Boxed addon) {
|
||||||
this.addon = addon;
|
this.addon = addon;
|
||||||
|
addon.saveResource("structures.yml", false);
|
||||||
// Load the config
|
// Load the config
|
||||||
structureFile = new File(addon.getDataFolder(), "structures.yml");
|
structureFile = new File(addon.getDataFolder(), "structures.yml");
|
||||||
// Check if it exists and if not, save it from the jar
|
// Try to build something every second
|
||||||
if (!structureFile.exists()) {
|
Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> BuildItem(), 20, 20);
|
||||||
addon.saveResource("structures.yml", true);
|
|
||||||
}
|
|
||||||
// Try to build something every 5 seconds
|
|
||||||
Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> BuildItem(), 20, 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildItem() {
|
private void BuildItem() {
|
||||||
@ -68,60 +77,50 @@ public class NewAreaListener implements Listener {
|
|||||||
Item item = itemsToBuild.poll();
|
Item item = itemsToBuild.poll();
|
||||||
LoadChunksAsync(item);
|
LoadChunksAsync(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
@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
|
// Load the latest config so that admins can change it on the fly without reloading
|
||||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(structureFile);
|
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();
|
Location center = island.getProtectionCenter();
|
||||||
|
for (String env : config.getKeys(false)) {
|
||||||
ConfigurationSection section = config.getConfigurationSection("structures.new");
|
Environment e = Enums.getIfPresent(Environment.class, env.toUpperCase(Locale.ENGLISH)).orNull();
|
||||||
if (section == null) {
|
if (e == null) {
|
||||||
addon.log("structures.new not found");
|
addon.logError("Error in structures.yml - unknown environment " + env);
|
||||||
} else {
|
} else {
|
||||||
place("structure",section, center);
|
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
|
// Loop through the structures in the file - there could be more than one
|
||||||
for (String structure : section.getKeys(false)) {
|
for (String vector : section.getKeys(false)) {
|
||||||
addon.log(structure);
|
String name = section.getString(vector);
|
||||||
String key = section.getString(structure,"");
|
// Load Structure
|
||||||
|
Structure s = Bukkit.getStructureManager().loadStructure(NamespacedKey.fromString("minecraft:" + name));
|
||||||
|
if (s == null) {
|
||||||
|
BentoBox.getInstance().logError("Could not load " + name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Extract coords
|
// Extract coords
|
||||||
String[] value = key.split(",");
|
String[] value = vector.split(",");
|
||||||
if (value.length == 4) {
|
if (value.length == 3) {
|
||||||
Environment env = Environment.valueOf(value[0].toUpperCase(Locale.ENGLISH).strip());
|
int x = Integer.valueOf(value[0].strip()) + center.getBlockX();
|
||||||
World world = env.equals(Environment.NORMAL) ? addon.getOverWorld() : addon.getNetherWorld();
|
int y = Integer.valueOf(value[1].strip());
|
||||||
int x = Integer.valueOf(value[1].strip()) + center.getBlockX();
|
int z = Integer.valueOf(value[2].strip()) + center.getBlockZ();
|
||||||
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;
|
|
||||||
}
|
|
||||||
Location l = new Location(world, x, y, z);
|
Location l = new Location(world, x, y, z);
|
||||||
itemsToBuild.add(new Item(world, cs, s, l));
|
itemsToBuild.add(new Item(name, s, l));
|
||||||
} else {
|
} 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) {
|
private void LoadChunksAsync(Item item) {
|
||||||
pasting = true;
|
pasting = true;
|
||||||
item.structure().place(item.location(), true, StructureRotation.NONE, Mirror.NONE, -1, 1, new Random());
|
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
|
// Find it
|
||||||
removeJigsaw(item.location(), item.structure());
|
removeJigsaw(item.location(), item.structure());
|
||||||
pasting = false;
|
pasting = false;
|
||||||
@ -151,7 +150,36 @@ public class NewAreaListener implements Listener {
|
|||||||
b.setType(Material.STRUCTURE_VOID);
|
b.setType(Material.STRUCTURE_VOID);
|
||||||
} else if (b.getType().equals(Material.STRUCTURE_BLOCK)) {
|
} else if (b.getType().equals(Material.STRUCTURE_BLOCK)) {
|
||||||
// I would like to read the data from the block an do something with it!
|
// I would like to read the data from the block an do something with it!
|
||||||
|
String data = nmsData(b);
|
||||||
b.setType(Material.STRUCTURE_VOID);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,5 +188,22 @@ public class NewAreaListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
normal:
|
||||||
new:
|
0,64,80: village/plains/houses/plains_masons_house_1
|
||||||
village/plains/houses/plains_masons_house_1: "normal, 0 ,64, 80"
|
-38,63,20: ruined_portal/portal_5
|
||||||
ruined_portal/portal_5: "normal, -38, 66, 20"
|
3,58,-60: shipwreck/rightsideup_backhalf
|
||||||
shipwreck/rightsideup_backhalf: "normal, 3, 59, -60"
|
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