mirror of
https://github.com/BentoBoxWorld/Boxed.git
synced 2024-11-13 10:14:19 +01:00
Fixed bugs with structure placing and added more of them
This commit is contained in:
parent
36162fe293
commit
628068eb5d
@ -21,19 +21,35 @@ import org.bukkit.structure.Structure;
|
||||
import com.google.common.base.Enums;
|
||||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
import world.bentobox.boxed.Boxed;
|
||||
import world.bentobox.boxed.listeners.NewAreaListener;
|
||||
import world.bentobox.boxed.listeners.NewAreaListener.Item;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class AdminPlaceStructureCommand extends CompositeCommand {
|
||||
|
||||
|
||||
private static final String STRUCTURE_FILE = "structures.yml";
|
||||
|
||||
/**
|
||||
* Integrity determines how damaged the building should look by randomly skipping blocks to place.
|
||||
* This value can range from 0 to 1. With 0 removing all blocks and 1 spawning the structure in pristine condition.
|
||||
*/
|
||||
private static final float INTEGRITY = 1;
|
||||
|
||||
/**
|
||||
* The palette index of the structure to use, starting at 0, or -1 to pick a random palette.
|
||||
*/
|
||||
private static final int PALETTE = -1;
|
||||
|
||||
private StructureRotation sr = StructureRotation.NONE;
|
||||
private Mirror mirror = Mirror.NONE;
|
||||
private boolean noMobs;
|
||||
|
||||
public AdminPlaceStructureCommand(CompositeCommand parent) {
|
||||
super(parent, "place");
|
||||
@ -54,7 +70,7 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
||||
// Initialize
|
||||
sr = StructureRotation.NONE;
|
||||
mirror = Mirror.NONE;
|
||||
|
||||
|
||||
// Check world
|
||||
if (!((Boxed)getAddon()).inWorld(getWorld())) {
|
||||
user.sendMessage("boxed.admin.place.wrong-world");
|
||||
@ -66,6 +82,7 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
||||
* 4. place <structure> ~ ~ ~
|
||||
* 5. place <structure> ~ ~ ~ ROTATION
|
||||
* 6. place <structure> ~ ~ ~ ROTATION MIRROR
|
||||
* 7. place <structure> ~ ~ ~ ROTATION MIRROR NO_MOBS
|
||||
*/
|
||||
// Format is place <structure> ~ ~ ~ or coords
|
||||
if (args.isEmpty() || args.size() == 2 || args.size() == 3 || args.size() > 6) {
|
||||
@ -110,6 +127,14 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
||||
Arrays.stream(Mirror.values()).map(Mirror::name).forEach(user::sendRawMessage);
|
||||
return false;
|
||||
}
|
||||
if (args.size() == 7) {
|
||||
if (args.get(6).toUpperCase(Locale.ENGLISH).equals("NO_MOBS")) {
|
||||
noMobs = true;
|
||||
} else {
|
||||
user.sendMessage("boxed.admin.place.unknown", TextVariables.LABEL, args.get(6).toUpperCase(Locale.ENGLISH));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Syntax is okay
|
||||
return true;
|
||||
}
|
||||
@ -122,28 +147,39 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
||||
int y = args.size() == 1 || args.get(2).equals("~") ? user.getLocation().getBlockY() : Integer.valueOf(args.get(2).trim());
|
||||
int z = args.size() == 1 || args.get(3).equals("~") ? user.getLocation().getBlockZ() : Integer.valueOf(args.get(3).trim());
|
||||
Location spot = new Location(user.getWorld(), x, y, z);
|
||||
s.place(spot, true, sr, mirror, -1, 1, new Random());
|
||||
NewAreaListener.removeJigsaw(spot, s, sr, tag.getKey());
|
||||
saveStructure(spot, tag, user, sr, mirror);
|
||||
return true;
|
||||
s.place(spot, true, sr, mirror, PALETTE, INTEGRITY, new Random());
|
||||
NewAreaListener.removeJigsaw(new Item(tag.getKey(), s, spot, sr, mirror, noMobs));
|
||||
boolean result = saveStructure(spot, tag, user, sr, mirror);
|
||||
if (result) {
|
||||
user.sendMessage("boxed.admin.place.saved");
|
||||
} else {
|
||||
user.sendMessage("boxed.admin.place.failed");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void saveStructure(Location spot, NamespacedKey tag, User user, StructureRotation sr2, Mirror mirror2) {
|
||||
getAddon().getIslands().getIslandAt(spot).ifPresent(i -> {
|
||||
private boolean saveStructure(Location spot, NamespacedKey tag, User user, StructureRotation sr2, Mirror mirror2) {
|
||||
return getAddon().getIslands().getIslandAt(spot).map(i -> {
|
||||
int xx = spot.getBlockX() - i.getCenter().getBlockX();
|
||||
int zz = spot.getBlockZ() - i.getCenter().getBlockZ();
|
||||
File structures = new File(getAddon().getDataFolder(), "structures.yml");
|
||||
File structures = new File(getAddon().getDataFolder(), STRUCTURE_FILE);
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
try {
|
||||
config.load(structures);
|
||||
String value = tag.getKey() + "," + sr2.name() + "," + mirror2.name();
|
||||
config.set(spot.getWorld().getEnvironment().name().toLowerCase(Locale.ENGLISH) + "." + xx + "," + spot.getBlockY() + "," + zz, value);
|
||||
StringBuilder v = new StringBuilder();
|
||||
v.append(tag.getKey() + "," + sr2.name() + "," + mirror2.name());
|
||||
if (noMobs) {
|
||||
v.append(" NO_MOBS");
|
||||
}
|
||||
config.set(spot.getWorld().getEnvironment().name().toLowerCase(Locale.ENGLISH) + "." + xx + "," + spot.getBlockY() + "," + zz, v.toString());
|
||||
config.save(structures);
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
// TODO Auto-generated catch block
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}).orElse(false);
|
||||
|
||||
}
|
||||
|
||||
@ -163,6 +199,8 @@ public class AdminPlaceStructureCommand extends CompositeCommand {
|
||||
return Optional.of(Arrays.stream(StructureRotation.values()).map(StructureRotation::name).toList());
|
||||
} else if (args.size() == 7) {
|
||||
return Optional.of(Arrays.stream(Mirror.values()).map(Mirror::name).toList());
|
||||
}else if (args.size() == 8) {
|
||||
return Optional.of(List.of("NO_MOBS"));
|
||||
}
|
||||
return Optional.of(Collections.emptyList());
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class NewAreaListener implements Listener {
|
||||
private static Random rand = new Random();
|
||||
private boolean pasting;
|
||||
private static Gson gson = new Gson();
|
||||
private record Item(String name, Structure structure, Location location, StructureRotation rot, Mirror mirror) {};
|
||||
public record Item(String name, Structure structure, Location location, StructureRotation rot, Mirror mirror, Boolean noMobs) {};
|
||||
Pair<Integer, Integer> min = new Pair<Integer, Integer>(0,0);
|
||||
Pair<Integer, Integer> max = new Pair<Integer, Integer>(0,0);
|
||||
// Database handler for structure data
|
||||
@ -181,7 +181,14 @@ public class NewAreaListener implements Listener {
|
||||
}
|
||||
|
||||
private IslandStructures getIslandStructData(String islandId) {
|
||||
return this.islandStructureCache.computeIfAbsent(islandId, k -> Objects.requireNonNullElse(handler.loadObject(k), new IslandStructures(islandId)));
|
||||
// Return from cache if it exists
|
||||
if (islandStructureCache.containsKey(islandId)) {
|
||||
return islandStructureCache.get(islandId);
|
||||
}
|
||||
// Get from database
|
||||
IslandStructures struct = handler.objectExists(islandId) ? handler.loadObject(islandId) : new IslandStructures(islandId);
|
||||
this.islandStructureCache.put(islandId, struct);
|
||||
return struct;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
@ -219,6 +226,7 @@ public class NewAreaListener implements Listener {
|
||||
for (String vector : section.getKeys(false)) {
|
||||
StructureRotation rot = StructureRotation.NONE;
|
||||
Mirror mirror = Mirror.NONE;
|
||||
boolean noMobs = false;
|
||||
String name = section.getString(vector);
|
||||
// Check for rotation
|
||||
String[] split = name.split(",");
|
||||
@ -229,7 +237,10 @@ public class NewAreaListener implements Listener {
|
||||
}
|
||||
if (split.length == 3) {
|
||||
// Mirror
|
||||
mirror = Enums.getIfPresent(Mirror.class, split[1].strip().toUpperCase(Locale.ENGLISH)).or(Mirror.NONE);
|
||||
mirror = Enums.getIfPresent(Mirror.class, split[2].strip().toUpperCase(Locale.ENGLISH)).or(Mirror.NONE);
|
||||
}
|
||||
if (split.length == 4) {
|
||||
noMobs = split[3].strip().toUpperCase(Locale.ENGLISH).equals("NO_MOBS");
|
||||
}
|
||||
// Load Structure
|
||||
Structure s = Bukkit.getStructureManager().loadStructure(NamespacedKey.fromString("minecraft:" + name));
|
||||
@ -244,7 +255,7 @@ public class NewAreaListener implements Listener {
|
||||
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(name, s, l, rot, mirror));
|
||||
itemsToBuild.add(new Item(name, s, l, rot, mirror, noMobs));
|
||||
} else {
|
||||
addon.logError("Structure file syntax error: " + vector + ": " + value);
|
||||
}
|
||||
@ -256,7 +267,7 @@ public class NewAreaListener implements Listener {
|
||||
item.structure().place(item.location(), true, item.rot(), item.mirror(), -1, 1, rand);
|
||||
addon.log(item.name() + " placed at " + item.location().getWorld().getName() + " " + Util.xyz(item.location().toVector()));
|
||||
// Find it
|
||||
BoundingBox bb = removeJigsaw(item.location(), item.structure(), item.rot(), item.name());
|
||||
BoundingBox bb = removeJigsaw(item);
|
||||
// Store it
|
||||
addon.getIslands().getIslandAt(item.location()).map(Island::getUniqueId).ifPresent(id -> {
|
||||
addon.log("Saved " + item.name());
|
||||
@ -273,13 +284,15 @@ public class NewAreaListener implements Listener {
|
||||
|
||||
/**
|
||||
* Removes Jigsaw blocks from a placed structure. Fills underwater ruins with water.
|
||||
* @param loc - location where the structure was placed
|
||||
* @param structure - structure that was placed
|
||||
* @param structureRotation - rotation of structure
|
||||
* @param key
|
||||
* @param item - record of what's required
|
||||
* @return the resulting bounding box of the structure
|
||||
*/
|
||||
public static BoundingBox removeJigsaw(Location loc, Structure structure, StructureRotation structureRotation, String key) {
|
||||
public static BoundingBox removeJigsaw(Item item) {
|
||||
Location loc = item.location();
|
||||
Structure structure = item.structure();
|
||||
StructureRotation structureRotation = item.rot();
|
||||
String key = item.name();
|
||||
|
||||
Location otherCorner = switch (structureRotation) {
|
||||
|
||||
case CLOCKWISE_180 -> loc.clone().add(new Vector(-structure.getSize().getX(), structure.getSize().getY(), -structure.getSize().getZ()));
|
||||
@ -299,7 +312,7 @@ public class NewAreaListener implements Listener {
|
||||
Block b = loc.getWorld().getBlockAt(x, y, z);
|
||||
if (b.getType().equals(Material.JIGSAW)) {
|
||||
// I would like to read the data from the block and do something with it!
|
||||
processJigsaw(b, structureRotation);
|
||||
processJigsaw(b, structureRotation, !item.noMobs());
|
||||
} else if (b.getType().equals(Material.STRUCTURE_BLOCK)) {
|
||||
processStructureBlock(b);
|
||||
}
|
||||
@ -338,15 +351,19 @@ public class NewAreaListener implements Listener {
|
||||
}
|
||||
|
||||
private static final Map<Integer, EntityType> BUTCHER_ANIMALS = Map.of(0, EntityType.COW, 1, EntityType.SHEEP, 2, EntityType.PIG);
|
||||
private static void processJigsaw(Block b, StructureRotation structureRotation) {
|
||||
private static void processJigsaw(Block b, StructureRotation structureRotation, boolean pasteMobs) {
|
||||
String data = nmsData(b);
|
||||
BoxedJigsawBlock bjb = gson.fromJson(data, BoxedJigsawBlock.class);
|
||||
//BentoBox.getInstance().logDebug("Jigsaw: " + bjb);
|
||||
//BentoBox.getInstance().logDebug("FinalState: " + bjb.getFinal_state());
|
||||
String finalState = correctDirection(bjb.getFinal_state(), structureRotation);
|
||||
//BentoBox.getInstance().logDebug("FinalState after rotation: " + finalState);
|
||||
BlockData bd = Bukkit.createBlockData(finalState);
|
||||
b.setBlockData(bd);
|
||||
if (!bjb.getPool().equalsIgnoreCase("minecraft:empty") && pasteMobs) {
|
||||
spawnMob(b, bjb);
|
||||
}
|
||||
}
|
||||
|
||||
private static void spawnMob(Block b, BoxedJigsawBlock bjb) {
|
||||
// bjb.getPool contains a lot more than just mobs, so we have to filter it to see if any mobs are in there. This list may need to grow in the future
|
||||
EntityType type =
|
||||
switch (bjb.getPool()) {
|
||||
case "minecraft:bastion/mobs/piglin" -> EntityType.PIGLIN;
|
||||
@ -362,16 +379,19 @@ public class NewAreaListener implements Listener {
|
||||
case "minecraft:village/common/animals" -> BUTCHER_ANIMALS.get(rand.nextInt(3));
|
||||
default -> null;
|
||||
};
|
||||
// Villagers
|
||||
if (bjb.getPool().contains("zombie/villagers")) {
|
||||
type = EntityType.ZOMBIE_VILLAGER;
|
||||
} else if (bjb.getPool().contains("villagers")) {
|
||||
type = EntityType.VILLAGER;
|
||||
}
|
||||
if (type == null) {
|
||||
BentoBox.getInstance().logDebug(bjb.getPool());
|
||||
}
|
||||
// Spawn it
|
||||
if (type != null && b.getWorld().spawnEntity(b.getRelative(BlockFace.UP).getLocation(), type) != null) {
|
||||
//BentoBox.getInstance().logDebug("Spawned a " + type + " at " + b.getRelative(BlockFace.UP).getLocation());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,18 @@ boxed:
|
||||
parameters: '[home number]'
|
||||
sethome:
|
||||
parameters: '[home number]'
|
||||
admin:
|
||||
place:
|
||||
description: "Place an area structure"
|
||||
parameters: "<x> <y> <z> <rotation> <mirror> <no mobs>"
|
||||
use-integers: "&c Coordinated must be integers"
|
||||
wrong-world: "&c This command can only be used in a Boxed world"
|
||||
unknown-structure: "&c Cannot place: Unknown structure"
|
||||
unknown-rotation: "&c Cannot place: Unknown rotation type"
|
||||
unknown-mirror: "&c Cannot place: Unknown mirror type"
|
||||
saved: "&a Placed and saved to structures.yml"
|
||||
failed: "&c Could not be saved to structures.yml. Check console for error"
|
||||
unknown: "&c Unknown parameter: [label]"
|
||||
island:
|
||||
go:
|
||||
parameters: '[home number]'
|
||||
|
@ -1,4 +1,5 @@
|
||||
normal:
|
||||
# This file is written by the /boxadmin place command
|
||||
ormal:
|
||||
0,64,80: village/plains/houses/plains_masons_house_1,CLOCKWISE_90
|
||||
-38,63,20: ruined_portal/portal_5
|
||||
3,58,-60: shipwreck/rightsideup_backhalf
|
||||
@ -15,6 +16,8 @@ normal:
|
||||
34,69,-29: village/common/iron_golem
|
||||
41,69,-26: village/common/animals/cat_calico
|
||||
35,69,-22: village/common/animals/cat_calico
|
||||
32,70,65: village/savanna/houses/savanna_temple_1,NONE,NONE
|
||||
25,70,72: village/savanna/houses/savanna_small_house_7,COUNTERCLOCKWISE_90,NONE,NO_MOBS
|
||||
99,72,118: pillager_outpost/feature_cage1
|
||||
33,72,100: village/desert/houses/desert_farm_1
|
||||
26,72,100: village/desert/houses/desert_medium_house_1
|
||||
@ -33,7 +36,16 @@ normal:
|
||||
-52,72,33: village/snowy/houses/snowy_farm_1,COUNTERCLOCKWISE_90,NONE
|
||||
-28,63,47: village/snowy/snowy_lamp_post_01,COUNTERCLOCKWISE_90,NONE
|
||||
-6,64,52: village/snowy/houses/snowy_small_house_3,COUNTERCLOCKWISE_90,NONE
|
||||
40,73,-3: village/savanna/houses/savanna_small_house_1,CLOCKWISE_180
|
||||
60,81,88: village/desert/camel_spawn,NONE,NONE
|
||||
64,81,93: village/desert/houses/desert_animal_pen_1,NONE,NONE
|
||||
49,81,94: village/desert/houses/desert_large_farm_1,NONE,NONE
|
||||
-106,45,68: underwater_ruin/big_brick_1,NONE,NONE
|
||||
-117,45,88: underwater_ruin/big_brick_2,NONE,NONE
|
||||
64,78,49: village/common/animals/horses_1,NONE,NONE
|
||||
65,78,51: village/common/animals/horses_2,NONE,NONE
|
||||
67,78,52: village/common/animals/horses_3,NONE,NONE
|
||||
57,70,-90: village/common/animals/horses_5,NONE,NONE
|
||||
62,70,-88: village/common/animals/horses_5,NONE,NONE
|
||||
|
||||
nether:
|
||||
16,32,0: bastion/bridge/starting_pieces/entrance
|
||||
|
Loading…
Reference in New Issue
Block a user