mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 18:23:06 +00:00
Object Command & Entity Spawn Changes (#492)
- Redid object paste command - Added rotate flag to paste with rotation - Added scale flag to paste with scale. Optional interpolation method can be used - Changes are now logged and can be reverted with the undo command - Fixed edit flag - Made the edit flag now update your wand even if it isn't in your hand - Added object undo command - Added object check command - Added a surface target to spawn on for entities. This will fix mobs spawning in water - LAND for mobs that spawn on any land surface - ANIMAL for mobs that should only spawn on grass and dirt - WATER for mobs that should spawn in water - OVERWORLD for mobs that can spawn on both land and water (turtles, for example) - LAVA for mobs that can spawn on lava (striders, for example) - Attempted to fix PAPI complaining about registering on the wrong thread - Fixed console spam for entities (was due to the mount event being called async) - Fixed grass paths and a few other update breaking blocks - Made it so if a block state changes on an update, it will now use as many as the other states as it can rather than not use anything - Patch to stop people naming the world 'Iris'
This commit is contained in:
parent
75f3073cbf
commit
12b4c27468
@ -127,7 +127,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
J.a(this::splash, 20);
|
J.a(this::splash, 20);
|
||||||
J.ar(this::checkConfigHotload, 60);
|
J.ar(this::checkConfigHotload, 60);
|
||||||
J.sr(this::tickQueue, 0);
|
J.sr(this::tickQueue, 0);
|
||||||
J.a(this::setupPapi);
|
J.s(this::setupPapi);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPapi() {
|
private void setupPapi() {
|
||||||
|
@ -34,6 +34,7 @@ import org.bukkit.event.EventHandler;
|
|||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemFlag;
|
import org.bukkit.inventory.ItemFlag;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
@ -41,6 +42,7 @@ import org.bukkit.util.BlockVector;
|
|||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class WandManager implements Listener {
|
public class WandManager implements Listener {
|
||||||
@ -70,10 +72,20 @@ public class WandManager implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the outline of a selected region
|
||||||
|
* @param d The cuboid
|
||||||
|
* @param p The player to show it to
|
||||||
|
*/
|
||||||
public void draw(Cuboid d, Player p) {
|
public void draw(Cuboid d, Player p) {
|
||||||
draw(new Location[]{d.getLowerNE(), d.getUpperSW()}, p);
|
draw(new Location[]{d.getLowerNE(), d.getUpperSW()}, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the outline of a selected region
|
||||||
|
* @param d A pair of locations
|
||||||
|
* @param p The player to show them to
|
||||||
|
*/
|
||||||
public void draw(Location[] d, Player p) {
|
public void draw(Location[] d, Player p) {
|
||||||
Vector gx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65);
|
Vector gx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65);
|
||||||
d[0].getWorld().spawnParticle(Particle.CRIT_MAGIC, d[0], 1, 0.5 + gx.getX(), 0.5 + gx.getY(), 0.5 + gx.getZ(), 0, null, false);
|
d[0].getWorld().spawnParticle(Particle.CRIT_MAGIC, d[0], 1, 0.5 + gx.getX(), 0.5 + gx.getY(), 0.5 + gx.getZ(), 0, null, false);
|
||||||
@ -146,7 +158,7 @@ public class WandManager implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void on(PlayerInteractEvent e) {
|
public void on(PlayerInteractEvent e) {
|
||||||
try {
|
try {
|
||||||
if (isWand(e.getPlayer())) {
|
if (isHoldingWand(e.getPlayer())) {
|
||||||
if (e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
|
if (e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
e.getPlayer().getInventory().setItemInMainHand(update(true, Objects.requireNonNull(e.getClickedBlock()).getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
|
e.getPlayer().getInventory().setItemInMainHand(update(true, Objects.requireNonNull(e.getClickedBlock()).getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
|
||||||
@ -160,7 +172,7 @@ public class WandManager implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDust(e.getPlayer())) {
|
if (isHoldingDust(e.getPlayer())) {
|
||||||
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
|
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
e.getPlayer().playSound(Objects.requireNonNull(e.getClickedBlock()).getLocation(), Sound.ENTITY_ENDER_EYE_DEATH, 2f, 1.97f);
|
e.getPlayer().playSound(Objects.requireNonNull(e.getClickedBlock()).getLocation(), Sound.ENTITY_ENDER_EYE_DEATH, 2f, 1.97f);
|
||||||
@ -177,6 +189,11 @@ public class WandManager implements Listener {
|
|||||||
s.place(at);
|
s.place(at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an Iris Object from the 2 coordinates selected with a wand
|
||||||
|
* @param wand The wand itemstack
|
||||||
|
* @return The new object
|
||||||
|
*/
|
||||||
public static IrisObject createSchematic(ItemStack wand) {
|
public static IrisObject createSchematic(ItemStack wand) {
|
||||||
if (!isWand(wand)) {
|
if (!isWand(wand)) {
|
||||||
return null;
|
return null;
|
||||||
@ -204,6 +221,11 @@ public class WandManager implements Listener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a user friendly location string to an actual Location
|
||||||
|
* @param s The string
|
||||||
|
* @return The location
|
||||||
|
*/
|
||||||
public static Location stringToLocation(String s) {
|
public static Location stringToLocation(String s) {
|
||||||
try {
|
try {
|
||||||
String[] f = s.split("\\Q in \\E");
|
String[] f = s.split("\\Q in \\E");
|
||||||
@ -215,18 +237,31 @@ public class WandManager implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String locationToString(Location s) {
|
/**
|
||||||
if (s == null) {
|
* Get a user friendly string of a location
|
||||||
|
* @param loc The location
|
||||||
|
* @return The string
|
||||||
|
*/
|
||||||
|
public static String locationToString(Location loc) {
|
||||||
|
if (loc == null) {
|
||||||
return "<#>";
|
return "<#>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.getBlockX() + "," + s.getBlockY() + "," + s.getBlockZ() + " in " + s.getWorld().getName();
|
return loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ() + " in " + loc.getWorld().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new blank Iris wand
|
||||||
|
* @return The wand itemstack
|
||||||
|
*/
|
||||||
public static ItemStack createWand() {
|
public static ItemStack createWand() {
|
||||||
return createWand(null, null);
|
return createWand(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new dust itemstack
|
||||||
|
* @return The stack
|
||||||
|
*/
|
||||||
public static ItemStack createDust() {
|
public static ItemStack createDust() {
|
||||||
ItemStack is = new ItemStack(Material.GLOWSTONE_DUST);
|
ItemStack is = new ItemStack(Material.GLOWSTONE_DUST);
|
||||||
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
|
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
|
||||||
@ -240,15 +275,32 @@ public class WandManager implements Listener {
|
|||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDust(Player p) {
|
/**
|
||||||
|
* Is the player holding Dust?
|
||||||
|
* @param p The player
|
||||||
|
* @return True if they are
|
||||||
|
*/
|
||||||
|
public boolean isHoldingDust(Player p) {
|
||||||
ItemStack is = p.getInventory().getItemInMainHand();
|
ItemStack is = p.getInventory().getItemInMainHand();
|
||||||
return is != null && isDust(is);
|
return is != null && isDust(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the itemstack passed Iris dust?
|
||||||
|
* @param is The itemstack
|
||||||
|
* @return True if it is
|
||||||
|
*/
|
||||||
public boolean isDust(ItemStack is) {
|
public boolean isDust(ItemStack is) {
|
||||||
return is.equals(dust);
|
return is.isSimilar(dust);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the location on an Iris wand
|
||||||
|
* @param left True for first location, false for second
|
||||||
|
* @param a The location
|
||||||
|
* @param item The wand
|
||||||
|
* @return The updated wand
|
||||||
|
*/
|
||||||
public ItemStack update(boolean left, Location a, ItemStack item) {
|
public ItemStack update(boolean left, Location a, ItemStack item) {
|
||||||
if (!isWand(item)) {
|
if (!isWand(item)) {
|
||||||
return item;
|
return item;
|
||||||
@ -264,6 +316,35 @@ public class WandManager implements Listener {
|
|||||||
return createWand(left ? a : other, left ? other : a);
|
return createWand(left ? a : other, left ? other : a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an existing wand in a users inventory
|
||||||
|
* @param inventory The inventory to search
|
||||||
|
* @return The slot number the wand is in. Or -1 if none are found
|
||||||
|
*/
|
||||||
|
public static int findWand(Inventory inventory) {
|
||||||
|
ItemStack wand = createWand(); //Create blank wand
|
||||||
|
ItemMeta meta = wand.getItemMeta();
|
||||||
|
meta.setLore(new ArrayList<>()); //We are resetting the lore as the lore differs between wands
|
||||||
|
wand.setItemMeta(meta);
|
||||||
|
|
||||||
|
for (int s = 0; s < inventory.getSize(); s++) {
|
||||||
|
ItemStack stack = inventory.getItem(s);
|
||||||
|
if (stack == null) continue;
|
||||||
|
meta = stack.getItemMeta();
|
||||||
|
meta.setLore(new ArrayList<>()); //Reset the lore on this too so we can compare them
|
||||||
|
stack.setItemMeta(meta); //We dont need to clone the item as items from .get are cloned
|
||||||
|
|
||||||
|
if (wand.isSimilar(stack)) return s; //If the name, material and NBT is the same
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an Iris wand. The locations should be the currently selected locations, or null
|
||||||
|
* @param a Location A
|
||||||
|
* @param b Location B
|
||||||
|
* @return A new wand
|
||||||
|
*/
|
||||||
public static ItemStack createWand(Location a, Location b) {
|
public static ItemStack createWand(Location a, Location b) {
|
||||||
ItemStack is = new ItemStack(Material.BLAZE_ROD);
|
ItemStack is = new ItemStack(Material.BLAZE_ROD);
|
||||||
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
|
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
|
||||||
@ -277,16 +358,31 @@ public class WandManager implements Listener {
|
|||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a pair of locations that are selected in an Iris wand
|
||||||
|
* @param is The wand item
|
||||||
|
* @return An array with the 2 locations
|
||||||
|
*/
|
||||||
public static Location[] getCuboid(ItemStack is) {
|
public static Location[] getCuboid(ItemStack is) {
|
||||||
ItemMeta im = is.getItemMeta();
|
ItemMeta im = is.getItemMeta();
|
||||||
return new Location[]{stringToLocation(im.getLore().get(0)), stringToLocation(im.getLore().get(1))};
|
return new Location[]{stringToLocation(im.getLore().get(0)), stringToLocation(im.getLore().get(1))};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWand(Player p) {
|
/**
|
||||||
|
* Is a player holding an Iris wand
|
||||||
|
* @param p The player
|
||||||
|
* @return True if they are
|
||||||
|
*/
|
||||||
|
public static boolean isHoldingWand(Player p) {
|
||||||
ItemStack is = p.getInventory().getItemInMainHand();
|
ItemStack is = p.getInventory().getItemInMainHand();
|
||||||
return is != null && isWand(is);
|
return is != null && isWand(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the itemstack passed an Iris wand
|
||||||
|
* @param is The itemstack
|
||||||
|
* @return True if it is
|
||||||
|
*/
|
||||||
public static boolean isWand(ItemStack is) {
|
public static boolean isWand(ItemStack is) {
|
||||||
ItemStack wand = createWand();
|
ItemStack wand = createWand();
|
||||||
if (is.getItemMeta() == null) return false;
|
if (is.getItemMeta() == null) return false;
|
||||||
|
@ -59,6 +59,12 @@ public class CommandIrisObject extends MortarCommand {
|
|||||||
@Command
|
@Command
|
||||||
private CommandIrisObjectPaste paste;
|
private CommandIrisObjectPaste paste;
|
||||||
|
|
||||||
|
@Command
|
||||||
|
private CommandIrisObjectUndo undo;
|
||||||
|
|
||||||
|
@Command
|
||||||
|
private CommandIrisObjectAnalyze analyze;
|
||||||
|
|
||||||
public CommandIrisObject() {
|
public CommandIrisObject() {
|
||||||
super("object", "iob", "o", "obj");
|
super("object", "iob", "o", "obj");
|
||||||
requiresPermission(Iris.perm);
|
requiresPermission(Iris.perm);
|
||||||
|
@ -0,0 +1,151 @@
|
|||||||
|
package com.volmit.iris.core.command.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.core.ProjectManager;
|
||||||
|
import com.volmit.iris.core.project.loader.IrisData;
|
||||||
|
import com.volmit.iris.core.tools.IrisWorlds;
|
||||||
|
import com.volmit.iris.engine.object.IrisObject;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.plugin.MortarCommand;
|
||||||
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import com.volmit.iris.util.scheduling.Queue;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class CommandIrisObjectAnalyze extends MortarCommand {
|
||||||
|
|
||||||
|
public CommandIrisObjectAnalyze() {
|
||||||
|
super("check", "c", "analyze");
|
||||||
|
requiresPermission(Iris.perm);
|
||||||
|
setCategory("Object");
|
||||||
|
setDescription("Check an object's composition");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTabOptions(VolmitSender sender, String[] args, KList<String> list) {
|
||||||
|
if ((args.length == 0 || args.length == 1) && sender.isPlayer() && IrisWorlds.isIrisWorld(sender.player().getWorld())) {
|
||||||
|
IrisData data = IrisWorlds.access(sender.player().getWorld()).getData();
|
||||||
|
if (data == null) {
|
||||||
|
sender.sendMessage("Tab complete options only work for objects while in an Iris world.");
|
||||||
|
} else if (args.length == 0) {
|
||||||
|
list.add(data.getObjectLoader().getPossibleKeys());
|
||||||
|
} else {
|
||||||
|
list.add(data.getObjectLoader().getPossibleKeys(args[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getArgsUsage() {
|
||||||
|
return "[name]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(VolmitSender sender, String[] args) {
|
||||||
|
if (!IrisSettings.get().isStudio()) {
|
||||||
|
sender.sendMessage("To use Iris Studio Objects, please enable studio in Iris/settings.json");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sender.isPlayer()) {
|
||||||
|
sender.sendMessage("Only players can spawn objects with this command");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
sender.sendMessage("Please specify the name of of the object want to paste");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player p = sender.player();
|
||||||
|
|
||||||
|
J.a(() -> {
|
||||||
|
IrisObject obj = IrisData.loadAnyObject(args[0]);
|
||||||
|
|
||||||
|
if (obj == null || obj.getLoadFile() == null) {
|
||||||
|
sender.sendMessage("Can't find " + args[0] + " in the " + ProjectManager.WORKSPACE_NAME + " folder");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage("Object Size: " + obj.getW() + " * " + obj.getH() + " * " + obj.getD() + "");
|
||||||
|
sender.sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(obj.getBlocks().size()));
|
||||||
|
|
||||||
|
Queue<BlockData> queue = obj.getBlocks().enqueueValues();
|
||||||
|
Map<Material, Set<BlockData>> unsorted = new HashMap<>();
|
||||||
|
Map<BlockData, Integer> amounts = new HashMap<>();
|
||||||
|
Map<Material, Integer> materials = new HashMap<>();
|
||||||
|
while (queue.hasNext()) {
|
||||||
|
BlockData block = queue.next();
|
||||||
|
|
||||||
|
//unsorted.put(block.getMaterial(), block);
|
||||||
|
|
||||||
|
if (!amounts.containsKey(block)) {
|
||||||
|
amounts.put(block, 1);
|
||||||
|
|
||||||
|
|
||||||
|
} else
|
||||||
|
amounts.put(block, amounts.get(block) + 1);
|
||||||
|
|
||||||
|
if (!materials.containsKey(block.getMaterial())) {
|
||||||
|
materials.put(block.getMaterial(), 1);
|
||||||
|
unsorted.put(block.getMaterial(), new HashSet<>());
|
||||||
|
unsorted.get(block.getMaterial()).add(block);
|
||||||
|
} else {
|
||||||
|
materials.put(block.getMaterial(), materials.get(block.getMaterial()) + 1);
|
||||||
|
unsorted.get(block.getMaterial()).add(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Material> sortedMatsList = amounts.keySet().stream().map(BlockData::getMaterial)
|
||||||
|
.sorted().collect(Collectors.toList());
|
||||||
|
Set<Material> sortedMats = new TreeSet<>(Comparator.comparingInt(materials::get).reversed());
|
||||||
|
sortedMats.addAll(sortedMatsList);
|
||||||
|
sender.sendMessage("== Blocks in object ==");
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
for (Material mat : sortedMats) {
|
||||||
|
int amount = materials.get(mat);
|
||||||
|
List<BlockData> set = new ArrayList<>(unsorted.get(mat));
|
||||||
|
set.sort(Comparator.comparingInt(amounts::get).reversed());
|
||||||
|
BlockData data = set.get(0);
|
||||||
|
int dataAmount = amounts.get(data);
|
||||||
|
|
||||||
|
String string = " - " + mat.toString() + "*" + amount;
|
||||||
|
if (data.getAsString(true).contains("[")) {
|
||||||
|
string = string + " --> [" + data.getAsString(true).split("\\[")[1]
|
||||||
|
.replaceAll("true", ChatColor.GREEN + "true" + ChatColor.GRAY)
|
||||||
|
.replaceAll("false", ChatColor.RED + "false" + ChatColor.GRAY)+ "*" + dataAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(string);
|
||||||
|
|
||||||
|
n++;
|
||||||
|
|
||||||
|
if (n >= 10) {
|
||||||
|
sender.sendMessage(" + " + (sortedMats.size() - n) + " other block types");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -58,7 +58,7 @@ public class CommandIrisObjectContract extends MortarCommand {
|
|||||||
|
|
||||||
Player p = sender.player();
|
Player p = sender.player();
|
||||||
|
|
||||||
if (!WandManager.isWand(p)) {
|
if (!WandManager.isHoldingWand(p)) {
|
||||||
sender.sendMessage("Ready your Wand.");
|
sender.sendMessage("Ready your Wand.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class CommandIrisObjectExpand extends MortarCommand {
|
|||||||
|
|
||||||
Player p = sender.player();
|
Player p = sender.player();
|
||||||
|
|
||||||
if (!WandManager.isWand(p)) {
|
if (!WandManager.isHoldingWand(p)) {
|
||||||
sender.sendMessage("Ready your Wand.");
|
sender.sendMessage("Ready your Wand.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ public class CommandIrisObjectP1 extends MortarCommand {
|
|||||||
|
|
||||||
Player p = sender.player();
|
Player p = sender.player();
|
||||||
|
|
||||||
if (!WandManager.isWand(p)) {
|
if (!WandManager.isHoldingWand(p)) {
|
||||||
sender.sendMessage("Ready your Wand.");
|
sender.sendMessage("Ready your Wand.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ public class CommandIrisObjectP2 extends MortarCommand {
|
|||||||
|
|
||||||
Player p = sender.player();
|
Player p = sender.player();
|
||||||
|
|
||||||
if (!WandManager.isWand(p)) {
|
if (!WandManager.isHoldingWand(p)) {
|
||||||
sender.sendMessage("Ready your Wand.");
|
sender.sendMessage("Ready your Wand.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -24,16 +24,37 @@ import com.volmit.iris.core.ProjectManager;
|
|||||||
import com.volmit.iris.core.WandManager;
|
import com.volmit.iris.core.WandManager;
|
||||||
import com.volmit.iris.core.project.loader.IrisData;
|
import com.volmit.iris.core.project.loader.IrisData;
|
||||||
import com.volmit.iris.core.tools.IrisWorlds;
|
import com.volmit.iris.core.tools.IrisWorlds;
|
||||||
|
import com.volmit.iris.engine.object.IrisAxisRotationClamp;
|
||||||
import com.volmit.iris.engine.object.IrisObject;
|
import com.volmit.iris.engine.object.IrisObject;
|
||||||
|
import com.volmit.iris.engine.object.IrisObjectPlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisObjectPlacementScaleInterpolator;
|
||||||
|
import com.volmit.iris.engine.object.IrisObjectRotation;
|
||||||
|
import com.volmit.iris.engine.object.IrisObjectScale;
|
||||||
|
import com.volmit.iris.engine.object.common.IObjectPlacer;
|
||||||
|
import com.volmit.iris.engine.object.tile.TileData;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.math.RNG;
|
||||||
import com.volmit.iris.util.plugin.MortarCommand;
|
import com.volmit.iris.util.plugin.MortarCommand;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
|
import org.bukkit.HeightMap;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.bukkit.block.TileState;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class CommandIrisObjectPaste extends MortarCommand {
|
public class CommandIrisObjectPaste extends MortarCommand {
|
||||||
|
|
||||||
public CommandIrisObjectPaste() {
|
public CommandIrisObjectPaste() {
|
||||||
super("paste", "pasta", "place", "p");
|
super("paste", "pasta", "place", "p");
|
||||||
requiresPermission(Iris.perm);
|
requiresPermission(Iris.perm);
|
||||||
@ -82,27 +103,114 @@ public class CommandIrisObjectPaste extends MortarCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean intoWand = false;
|
boolean intoWand = false;
|
||||||
|
int rotate = 0;
|
||||||
|
double scale = 1;
|
||||||
|
IrisObjectPlacementScaleInterpolator interpolator = IrisObjectPlacementScaleInterpolator.NONE;
|
||||||
|
|
||||||
for (String i : args) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
if (i.equalsIgnoreCase("-edit")) {
|
String str = args[i];
|
||||||
|
if (str.equalsIgnoreCase("-edit") || str.equalsIgnoreCase("-e")) {
|
||||||
intoWand = true;
|
intoWand = true;
|
||||||
break;
|
} else if (str.equalsIgnoreCase("-r") || str.equalsIgnoreCase("-rotate")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
sender.sendMessage("No rotation parameter provided! Usage is -rotate <degrees>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
rotate = Integer.parseInt(args[i + 1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage("\"" + args[i + 1] + "\" is not a number!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (str.equalsIgnoreCase("-s") || str.equalsIgnoreCase("-scale")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
sender.sendMessage("No scale parameter provided! Usage is -scale <size> [method=linear|cubic|hermite|none]");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
scale = Double.parseDouble(args[i + 1]);
|
||||||
|
|
||||||
|
int max = 10;
|
||||||
|
|
||||||
|
if (obj.getBlocks().size() > 30_000) {
|
||||||
|
max = 5;
|
||||||
|
}
|
||||||
|
if (obj.getBlocks().size() > 60_000) {
|
||||||
|
max = 3;
|
||||||
|
}
|
||||||
|
if (obj.getBlocks().size() > 90_000) {
|
||||||
|
max = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale > max) {
|
||||||
|
sender.sendMessage("Due to size restrictions, the object will only be scaled to " + max + "x size");
|
||||||
|
scale = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i + 2 >= args.length) {
|
||||||
|
continue; //Dont parse the method and keep it at none
|
||||||
|
}
|
||||||
|
String intpol = args[i + 2];
|
||||||
|
if (intpol.toLowerCase().startsWith("method=")) intpol = intpol.split("=", 2)[1];
|
||||||
|
if (intpol.toLowerCase().startsWith("tri")) intpol = intpol.substring(3);
|
||||||
|
|
||||||
|
interpolator = IrisObjectPlacementScaleInterpolator.valueOf("TRI" + intpol.toUpperCase());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage("\"" + args[i + 1] + "\" is not a decimal number!");
|
||||||
|
return true;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
sender.sendMessage("\"" + args[i + 2] + "\" is not a valid interpolator method! Must be LINEAR, CUBIC, HERMITE or NONE!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (str.startsWith("-")) {
|
||||||
|
sender.sendMessage("Unknown flag \"" + args[i + 1] + "\" provided! Valid flags are -edit, -rotate and -scale");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IrisObjectPlacement placement = new IrisObjectPlacement();
|
||||||
|
if (rotate != 0) {
|
||||||
|
IrisObjectRotation rot = IrisObjectRotation.of(0, rotate, 0);
|
||||||
|
placement.setRotation(rot);
|
||||||
|
}
|
||||||
|
if (scale != 1) {
|
||||||
|
obj = obj.scaled(scale, interpolator);
|
||||||
|
}
|
||||||
|
|
||||||
ItemStack wand = sender.player().getInventory().getItemInMainHand();
|
ItemStack wand = sender.player().getInventory().getItemInMainHand();
|
||||||
|
|
||||||
Iris.debug("Loaded object for placement: " + "objects/" + args[0] + ".iob");
|
Iris.debug("Loaded object for placement: " + "objects/" + args[0] + ".iob");
|
||||||
|
|
||||||
sender.player().getWorld().playSound(sender.player().getLocation(), Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1f, 1.5f);
|
sender.player().getWorld().playSound(sender.player().getLocation(), Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1f, 1.5f);
|
||||||
Location block = sender.player().getTargetBlock(null, 256).getLocation().clone().add(0, 1, 0);
|
|
||||||
|
|
||||||
WandManager.pasteSchematic(obj, block);
|
Set<Material> skipBlocks = Set.of(Material.GRASS, Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH,
|
||||||
|
Material.POPPY, Material.DANDELION);
|
||||||
|
|
||||||
if (intoWand && WandManager.isWand(wand)) {
|
Location block = sender.player().getTargetBlock(skipBlocks, 256).getLocation().clone().add(0, 1, 0);
|
||||||
wand = WandManager.createWand(block.clone().subtract(obj.getCenter()).add(obj.getW() - 1, obj.getH(), obj.getD() - 1), block.clone().subtract(obj.getCenter()));
|
|
||||||
p.getInventory().setItemInMainHand(wand);
|
//WandManager.pasteSchematic(obj, block);
|
||||||
sender.sendMessage("Updated wand for " + "objects/" + args[0] + ".iob");
|
|
||||||
|
Map<Block, BlockData> futureChanges = new HashMap<>();
|
||||||
|
obj.place(block.getBlockX(), block.getBlockY() + (int)obj.getCenter().getY(), block.getBlockZ(), createPlacer(sender.player(), block.getWorld(), futureChanges), placement, new RNG(), null);
|
||||||
|
CommandIrisObjectUndo.addChanges(sender.player(), futureChanges);
|
||||||
|
|
||||||
|
if (intoWand) {
|
||||||
|
ItemStack newWand = WandManager.createWand(block.clone().subtract(obj.getCenter()).add(obj.getW() - 1,
|
||||||
|
obj.getH() + obj.getCenter().clone().getY() - 1, obj.getD() - 1), block.clone().subtract(obj.getCenter().clone().setY(0)));
|
||||||
|
if (WandManager.isWand(wand)) {
|
||||||
|
wand = newWand;
|
||||||
|
p.getInventory().setItemInMainHand(wand);
|
||||||
|
sender.sendMessage("Updated wand for " + "objects/" + args[0] + ".iob");
|
||||||
|
} else {
|
||||||
|
int slot = WandManager.findWand(sender.player().getInventory());
|
||||||
|
if (slot == -1) {
|
||||||
|
p.getInventory().addItem(newWand);
|
||||||
|
sender.sendMessage("Given new wand for " + "objects/" + args[0] + ".iob");
|
||||||
|
} else {
|
||||||
|
sender.player().getInventory().setItem(slot, newWand);
|
||||||
|
sender.sendMessage("Updated wand for " + "objects/" + args[0] + ".iob");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage("Placed " + "objects/" + args[0] + ".iob");
|
sender.sendMessage("Placed " + "objects/" + args[0] + ".iob");
|
||||||
}
|
}
|
||||||
@ -113,6 +221,70 @@ public class CommandIrisObjectPaste extends MortarCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getArgsUsage() {
|
protected String getArgsUsage() {
|
||||||
return "[name] [-edit]";
|
return "[name] [-edit] [-rotate [angle]] [-scale [num] [method]]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IObjectPlacer createPlacer(Player player, World world, Map<Block, BlockData> futureBlockChanges) {
|
||||||
|
|
||||||
|
return new IObjectPlacer() {
|
||||||
|
@Override
|
||||||
|
public int getHighest(int x, int z, IrisData data) {
|
||||||
|
return world.getHighestBlockYAt(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
|
||||||
|
return world.getHighestBlockYAt(x, z, ignoreFluid ? HeightMap.OCEAN_FLOOR: HeightMap.MOTION_BLOCKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(int x, int y, int z, BlockData d) {
|
||||||
|
Block block = world.getBlockAt(x, y, z);
|
||||||
|
|
||||||
|
//Prevent blocks being set in or bellow bedrock
|
||||||
|
if (y <= world.getMinHeight() || block.getType() == Material.BEDROCK) return;
|
||||||
|
|
||||||
|
futureBlockChanges.put(block, block.getBlockData());
|
||||||
|
|
||||||
|
block.setBlockData(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockData get(int x, int y, int z) {
|
||||||
|
return world.getBlockAt(x, y, z).getBlockData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPreventingDecay() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSolid(int x, int y, int z) {
|
||||||
|
return world.getBlockAt(x, y, z).getType().isSolid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnderwater(int x, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFluidHeight() {
|
||||||
|
return 63;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebugSmartBore() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) {
|
||||||
|
BlockState state = world.getBlockAt(xx, yy, zz).getState();
|
||||||
|
tile.toBukkitTry(state);
|
||||||
|
state.update();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class CommandIrisObjectShift extends MortarCommand {
|
|||||||
|
|
||||||
Player p = sender.player();
|
Player p = sender.player();
|
||||||
|
|
||||||
if (!WandManager.isWand(p)) {
|
if (!WandManager.isHoldingWand(p)) {
|
||||||
sender.sendMessage("Ready your Wand.");
|
sender.sendMessage("Ready your Wand.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.command.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.plugin.MortarCommand;
|
||||||
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class CommandIrisObjectUndo extends MortarCommand {
|
||||||
|
|
||||||
|
private static Map<UUID, Deque<Map<Block, BlockData>>> undos = new HashMap<>();
|
||||||
|
|
||||||
|
public CommandIrisObjectUndo() {
|
||||||
|
super("undo", "u", "revert");
|
||||||
|
requiresPermission(Iris.perm);
|
||||||
|
setCategory("Object");
|
||||||
|
setDescription("Undo an object paste ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTabOptions(VolmitSender sender, String[] args, KList<String> list) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(VolmitSender sender, String[] args) {
|
||||||
|
if (!IrisSettings.get().isStudio()) {
|
||||||
|
sender.sendMessage("To use Iris Studio Objects, please enable studio in Iris/settings.json");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID player = null;
|
||||||
|
int amount = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
String str = args[i];
|
||||||
|
if (str.equalsIgnoreCase("-u") || str.equalsIgnoreCase("-user")
|
||||||
|
|| str.equalsIgnoreCase("-p") || str.equalsIgnoreCase("-player")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
sender.sendMessage("No user parameter provided! Usage is -user <player>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflinePlayer p = Bukkit.getOfflinePlayer(args[i + 1]);
|
||||||
|
if (!p.hasPlayedBefore()) {
|
||||||
|
sender.sendMessage("\"" + args[i + 1] + "\" is not a player that has played before!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
player = p.getUniqueId();
|
||||||
|
} else if (str.equalsIgnoreCase("-n") || str.equalsIgnoreCase("-number")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
sender.sendMessage("No number parameter provided! Usage is -number <amount>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
amount = Integer.parseInt(args[i + 1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage("\"" + args[i + 1] + "\" is not a number!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (str.startsWith("-")) {
|
||||||
|
sender.sendMessage("Unknown flag \"" + args[i + 1] + "\" provided! Valid flags are -number and -user");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sender.isPlayer() && player == null) {
|
||||||
|
sender.sendMessage("Please specify a player to revert!");
|
||||||
|
return true;
|
||||||
|
} else if (sender.isPlayer()) {
|
||||||
|
player = sender.player().getUniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount < 0) {
|
||||||
|
sender.sendMessage("Please specify an amount greater than 0!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!undos.containsKey(player) || undos.get(player).size() == 0) {
|
||||||
|
sender.sendMessage("No pastes to undo");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int actualReverts = Math.min(undos.get(player).size(), amount);
|
||||||
|
revertChanges(player, amount);
|
||||||
|
sender.sendMessage("Reverted " + actualReverts + " pastes!");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getArgsUsage() {
|
||||||
|
return "[-number [num]] [-user [username]]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addChanges(Player player, Map<Block, BlockData> oldBlocks) {
|
||||||
|
if (!undos.containsKey(player.getUniqueId())) {
|
||||||
|
undos.put(player.getUniqueId(), new ArrayDeque<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
undos.get(player.getUniqueId()).add(oldBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void revertChanges(UUID player, int amount) {
|
||||||
|
loopChange(player, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void loopChange(UUID uuid, int amount) {
|
||||||
|
Deque<Map<Block, BlockData>> queue = undos.get(uuid);
|
||||||
|
if (queue != null && queue.size() > 0) {
|
||||||
|
revert(queue.pollLast());
|
||||||
|
if (amount > 1) {
|
||||||
|
J.s(() -> loopChange(uuid, amount - 1), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts all the block changes provided, 200 blocks per tick
|
||||||
|
* @param blocks The blocks to remove
|
||||||
|
*/
|
||||||
|
private static void revert(Map<Block, BlockData> blocks) {
|
||||||
|
int amount = 0;
|
||||||
|
Iterator<Map.Entry<Block, BlockData>> it = blocks.entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Map.Entry<Block, BlockData> entry = it.next();
|
||||||
|
BlockData data = entry.getValue();
|
||||||
|
entry.getKey().setBlockData(data, false);
|
||||||
|
it.remove();
|
||||||
|
|
||||||
|
amount++;
|
||||||
|
|
||||||
|
if (amount > 200) {
|
||||||
|
J.s(() -> revert(blocks), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -60,7 +60,7 @@ public class CommandIrisObjectXAY extends MortarCommand {
|
|||||||
|
|
||||||
Player p = sender.player();
|
Player p = sender.player();
|
||||||
|
|
||||||
if (!WandManager.isWand(p)) {
|
if (!WandManager.isHoldingWand(p)) {
|
||||||
sender.sendMessage("Ready your Wand.");
|
sender.sendMessage("Ready your Wand.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public class CommandIrisObjectXPY extends MortarCommand {
|
|||||||
|
|
||||||
Player p = sender.player();
|
Player p = sender.player();
|
||||||
|
|
||||||
if (!WandManager.isWand(p)) {
|
if (!WandManager.isHoldingWand(p)) {
|
||||||
sender.sendMessage("Ready your Wand.");
|
sender.sendMessage("Ready your Wand.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,12 @@ public class CommandIrisCreate extends MortarCommand {
|
|||||||
pregen.set(i.startsWith("pregen=") ? getVal(i.split("\\Q=\\E")[1]) : pregen.get());
|
pregen.set(i.startsWith("pregen=") ? getVal(i.split("\\Q=\\E")[1]) : pregen.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (worldName.equalsIgnoreCase("iris")) {
|
||||||
|
sender.sendMessage("You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds.");
|
||||||
|
sender.sendMessage("May we suggest the name \"IrisWorld\" instead?");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Iris.linkMultiverseCore.assignWorldType(worldName, type);
|
Iris.linkMultiverseCore.assignWorldType(worldName, type);
|
||||||
final AtomicReference<World> world = new AtomicReference<>();
|
final AtomicReference<World> world = new AtomicReference<>();
|
||||||
IrisDimension dim;
|
IrisDimension dim;
|
||||||
|
@ -27,6 +27,11 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.block.data.type.Leaves;
|
import org.bukkit.block.data.type.Leaves;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class B {
|
public class B {
|
||||||
private static final Material AIR_MATERIAL = Material.AIR;
|
private static final Material AIR_MATERIAL = Material.AIR;
|
||||||
private static final BlockData AIR = AIR_MATERIAL.createBlockData();
|
private static final BlockData AIR = AIR_MATERIAL.createBlockData();
|
||||||
@ -157,26 +162,67 @@ public class B {
|
|||||||
|
|
||||||
blockDataCache.put(ix, bx);
|
blockDataCache.put(ix, bx);
|
||||||
return bx;
|
return bx;
|
||||||
} catch (Throwable e) {
|
} catch (Exception e) {
|
||||||
Iris.reportError(e);
|
//Iris.reportError(e);
|
||||||
|
Iris.debug("Failed to load block \"" + ix + "\"");
|
||||||
|
|
||||||
|
String block = ix.contains(":") ? ix.split(":")[1].toLowerCase() : ix.toLowerCase();
|
||||||
|
String state = block.contains("[") ? block.split("\\[")[1].split("\\]")[0] : "";
|
||||||
|
Map<String, String> stateMap = new HashMap<>();
|
||||||
|
if (!state.equals("")) {
|
||||||
|
Arrays.stream(state.split(",")).forEach(s -> {
|
||||||
|
stateMap.put(s.split("=")[0], s.split("=")[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
block = block.split("\\[")[0];
|
||||||
|
|
||||||
|
switch (block) {
|
||||||
|
case "cauldron" -> block = "water_cauldron"; //Would fail to load if it has a level parameter
|
||||||
|
case "grass_path" -> block = "dirt_path";
|
||||||
|
case "concrete" -> block = "white_concrete";
|
||||||
|
case "wool" -> block = "white_wool";
|
||||||
|
case "beetroots" -> {
|
||||||
|
if (stateMap.containsKey("age")) {
|
||||||
|
String updated = stateMap.get("age");
|
||||||
|
switch (updated) {
|
||||||
|
case "7" -> updated = "3";
|
||||||
|
case "3", "4", "5" -> updated = "2";
|
||||||
|
case "1", "2" -> updated = "1";
|
||||||
|
}
|
||||||
|
stateMap.put("age", updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> newStates = new HashMap<>();
|
||||||
|
for (String key : stateMap.keySet()) { //Iterate through every state and check if its valid
|
||||||
|
try {
|
||||||
|
String newState = block + "[" + key + "=" + stateMap.get(key) + "]";
|
||||||
|
Bukkit.createBlockData(newState);
|
||||||
|
|
||||||
|
//If we get to here, the state is okay so we can use it
|
||||||
|
newStates.put(key, stateMap.get(key));
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException ignored) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
//Combine all the "good" states again
|
||||||
|
state = newStates.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).collect(Collectors.joining(","));
|
||||||
|
if (!state.equals("")) state = "[" + state + "]";
|
||||||
|
String newBlock = block + state;
|
||||||
|
Iris.debug("Converting " + ix + " to " + newBlock);
|
||||||
|
|
||||||
|
try {
|
||||||
|
BlockData bd = Bukkit.createBlockData(newBlock);
|
||||||
|
blockDataCache.put(ix, bd);
|
||||||
|
return bd;
|
||||||
|
} catch (Throwable e1) {
|
||||||
|
Iris.reportError(e1);
|
||||||
|
}
|
||||||
|
|
||||||
|
nullBlockDataCache.add(ix);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String i = ix.toUpperCase().trim();
|
|
||||||
i = i.equals("GRASS_PATH") ? "DIRT_PATH" : i;
|
|
||||||
i = i.equals("WOOL") ? "WHITE_WOOL" : i;
|
|
||||||
i = i.equals("CONCRETE") ? "WHITE_CONCRETE" : i;
|
|
||||||
|
|
||||||
try {
|
|
||||||
BlockData bd = Material.valueOf(i).createBlockData();
|
|
||||||
blockDataCache.put(ix, bd);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
nullBlockDataCache.add(ix);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockData parseBlockData(String ix) {
|
private static BlockData parseBlockData(String ix) {
|
||||||
|
@ -136,6 +136,12 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
@Desc("The this entity is ageable, set it's baby status")
|
@Desc("The this entity is ageable, set it's baby status")
|
||||||
private boolean baby = false;
|
private boolean baby = false;
|
||||||
|
|
||||||
|
@Desc("If the entity should never be culled. Useful for Jigsaws")
|
||||||
|
private boolean keepEntity = false;
|
||||||
|
|
||||||
|
@Desc("The surface type to spawn this mob on")
|
||||||
|
private IrisSurface surface = IrisSurface.LAND;
|
||||||
|
|
||||||
public Entity spawn(Engine gen, Location at) {
|
public Entity spawn(Engine gen, Location at) {
|
||||||
return spawn(gen, at, new RNG(at.hashCode()));
|
return spawn(gen, at, new RNG(at.hashCode()));
|
||||||
}
|
}
|
||||||
@ -154,10 +160,14 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
e.setGravity(isGravity());
|
e.setGravity(isGravity());
|
||||||
e.setInvulnerable(isInvulnerable());
|
e.setInvulnerable(isInvulnerable());
|
||||||
e.setSilent(isSilent());
|
e.setSilent(isSilent());
|
||||||
|
e.setPersistent(isKeepEntity());
|
||||||
|
|
||||||
int gg = 0;
|
int gg = 0;
|
||||||
for (IrisEntity i : passengers) {
|
for (IrisEntity i : passengers) {
|
||||||
e.addPassenger(i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++)));
|
Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++));
|
||||||
|
if (!Bukkit.isPrimaryThread()) {
|
||||||
|
J.s(() -> e.addPassenger(passenger));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e instanceof Attributable) {
|
if (e instanceof Attributable) {
|
||||||
|
@ -38,7 +38,9 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.HeightMap;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
|
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@ -105,8 +107,8 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (l != null) {
|
if (l != null) {
|
||||||
spawn100(gen, l);
|
if (spawn100(gen, l) != null)
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,8 +134,11 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
|
|
||||||
private Entity spawn100(Engine g, Location at) {
|
private Entity spawn100(Engine g, Location at) {
|
||||||
try {
|
try {
|
||||||
Location l = at.clone().add(0.5, 1, 0.5);
|
IrisEntity irisEntity = getRealEntity(g);
|
||||||
Entity e = getRealEntity(g).spawn(g, l, rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4)));
|
|
||||||
|
if (!irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock().getState())) return null; //Make sure it can spawn on the block
|
||||||
|
|
||||||
|
Entity e = irisEntity.spawn(g, at.add(0.5, 0, 0.5), rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4)));
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
Iris.debug("Spawned " + C.DARK_AQUA + "Entity<" + getEntity() + "> " + C.GREEN + e.getType() + C.LIGHT_PURPLE + " @ " + C.GRAY + e.getLocation().getX() + ", " + e.getLocation().getY() + ", " + e.getLocation().getZ());
|
Iris.debug("Spawned " + C.DARK_AQUA + "Entity<" + getEntity() + "> " + C.GREEN + e.getType() + C.LIGHT_PURPLE + " @ " + C.GRAY + e.getLocation().getX() + ", " + e.getLocation().getY() + ", " + e.getLocation().getZ());
|
||||||
}
|
}
|
||||||
|
@ -787,6 +787,8 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
|
|
||||||
IrisPosition l1 = getAABB().max();
|
IrisPosition l1 = getAABB().max();
|
||||||
IrisPosition l2 = getAABB().min();
|
IrisPosition l2 = getAABB().min();
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"}) HashMap<BlockVector, BlockData> placeBlock = new HashMap();
|
||||||
|
|
||||||
Vector center = getCenter();
|
Vector center = getCenter();
|
||||||
if (getH() == 2) {
|
if (getH() == 2) {
|
||||||
center = center.setY(center.getBlockY() + 0.5);
|
center = center.setY(center.getBlockY() + 0.5);
|
||||||
@ -797,14 +799,13 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
if (getD() == 2) {
|
if (getD() == 2) {
|
||||||
center = center.setZ(center.getBlockZ() + 0.5);
|
center = center.setZ(center.getBlockZ() + 0.5);
|
||||||
}
|
}
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"}) HashMap<BlockVector, BlockData> placeBlock = new HashMap();
|
|
||||||
|
|
||||||
IrisObject oo = new IrisObject((int) Math.ceil((w * scale) + (scale * 2)), (int) Math.ceil((h * scale) + (scale * 2)), (int) Math.ceil((d * scale) + (scale * 2)));
|
IrisObject oo = new IrisObject((int) Math.ceil((w * scale) + (scale * 2)), (int) Math.ceil((h * scale) + (scale * 2)), (int) Math.ceil((d * scale) + (scale * 2)));
|
||||||
|
|
||||||
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
|
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
|
||||||
BlockData bd = entry.getValue();
|
BlockData bd = entry.getValue();
|
||||||
placeBlock.put(entry.getKey().clone().add(HALF).subtract(center)
|
placeBlock.put(entry.getKey().clone().add(HALF).subtract(center)
|
||||||
.multiply(scale).toBlockVector(), bd);
|
.multiply(scale).add(sm1).toBlockVector(), bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<BlockVector, BlockData> entry : placeBlock.entrySet()) {
|
for (Map.Entry<BlockVector, BlockData> entry : placeBlock.entrySet()) {
|
||||||
|
50
src/main/java/com/volmit/iris/engine/object/IrisSurface.java
Normal file
50
src/main/java/com/volmit/iris/engine/object/IrisSurface.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.engine.object.annotations.Desc;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.bukkit.block.data.Waterlogged;
|
||||||
|
|
||||||
|
@Desc("The type of surface entities should spawn on")
|
||||||
|
public enum IrisSurface {
|
||||||
|
|
||||||
|
@Desc("Land surfaces")
|
||||||
|
LAND,
|
||||||
|
|
||||||
|
@Desc("Any surfaces animals can spawn on, such as dirt, grass and podzol")
|
||||||
|
ANIMAL,
|
||||||
|
|
||||||
|
@Desc("Within the water")
|
||||||
|
WATER,
|
||||||
|
|
||||||
|
@Desc("On land or on water")
|
||||||
|
OVERWORLD,
|
||||||
|
|
||||||
|
@Desc("Within lava")
|
||||||
|
LAVA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this Iris surface matches the blockstate provided
|
||||||
|
* @param state The blockstate
|
||||||
|
* @return True if it matches
|
||||||
|
*/
|
||||||
|
public boolean matches(BlockState state) {
|
||||||
|
Material type = state.getType();
|
||||||
|
if (type.isSolid()) {
|
||||||
|
return this == LAND || this == OVERWORLD || (this == ANIMAL
|
||||||
|
&& (type == Material.GRASS_BLOCK || type == Material.DIRT
|
||||||
|
|| type == Material.DIRT_PATH || type == Material.COARSE_DIRT
|
||||||
|
|| type == Material.ROOTED_DIRT || type == Material.PODZOL
|
||||||
|
|| type == Material.MYCELIUM || type == Material.SNOW_BLOCK));
|
||||||
|
}
|
||||||
|
if (type == Material.LAVA) return this == LAVA;
|
||||||
|
if (type == Material.WATER || type == Material.SEAGRASS
|
||||||
|
|| type == Material.TALL_SEAGRASS || type == Material.KELP_PLANT
|
||||||
|
|| type == Material.KELP ||
|
||||||
|
(state instanceof Waterlogged && ((Waterlogged) state).isWaterlogged()))
|
||||||
|
return this == WATER || this == OVERWORLD;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user