diff --git a/build.gradle b/build.gradle index bcd5a3319..f03557fdf 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ plugins { id "de.undercouch.download" version "5.0.1" } -version '3.2.0-1.19.2-1.20.4' +version '3.2.1-1.19.2-1.20.4' def specialSourceVersion = '1.11.0' //[NMS] // ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 70031c5ee..e32c8239d 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -128,6 +128,10 @@ public class Iris extends VolmitPlugin implements Listener { private KMap, IrisService> services; public static VolmitSender getSender() { + if (sender == null) { + sender = new VolmitSender(Bukkit.getConsoleSender()); + sender.setTag(instance.getTag()); + } return sender; } @@ -194,10 +198,10 @@ public class Iris extends VolmitPlugin implements Listener { public static void msg(String string) { try { - sender.sendMessage(string); + getSender().sendMessage(string); } catch (Throwable e) { try { - System.out.println(instance.getTag() + string.replaceAll("(<([^>]+)>)", "")); + instance.getLogger().info(instance.getTag() + string.replaceAll("(<([^>]+)>)", "")); } catch (Throwable ignored1) { } @@ -433,7 +437,7 @@ public class Iris extends VolmitPlugin implements Listener { } pw.close(); - System.out.println("DUMPED! See " + fi.getAbsolutePath()); + Iris.info("DUMPED! See " + fi.getAbsolutePath()); } catch (Throwable e) { e.printStackTrace(); } @@ -453,14 +457,12 @@ public class Iris extends VolmitPlugin implements Listener { private void enable() { instance = this; services = new KMap<>(); + setupAudience(); initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class) i.getClass(), (IrisService) i)); INMS.get(); IO.delete(new File("iris")); - setupAudience(); IrisSafeguard.IrisSafeguardSystem(); - sender = new VolmitSender(Bukkit.getConsoleSender()); - sender.setTag(getTag()); - instance = this; + getSender().setTag(getTag()); compat = IrisCompat.configured(getDataFile("compat.json")); linkMultiverseCore = new MultiverseCoreLink(); linkMythicMobs = new MythicMobsLink(); @@ -533,7 +535,7 @@ public class Iris extends VolmitPlugin implements Listener { Iris.info("Starting up auto Studio!"); try { Player r = new KList<>(getServer().getOnlinePlayers()).getRandom(); - Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : sender, 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> { + Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : getSender(), 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> { J.s(() -> { for (Player i : getServer().getOnlinePlayers()) { i.setGameMode(GameMode.SPECTATOR); @@ -734,7 +736,7 @@ public class Iris extends VolmitPlugin implements Listener { File ff = new File(w.worldFolder(), "iris/pack"); if (!ff.exists() || ff.listFiles().length == 0) { ff.mkdirs(); - service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), w.worldFolder()); + service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder()); } return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index fc8a2d90b..bf7b05b48 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -475,7 +475,7 @@ public class CommandIris implements DecreeExecutor { } WorldToLoad = world; File BUKKIT_YML = new File("bukkit.yml"); - String pathtodim = world + "\\iris\\pack\\dimensions\\"; + String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator; File directory = new File(Bukkit.getWorldContainer(), pathtodim); String dimension = null; diff --git a/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java index ee4d46bfc..7e3b4d00e 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java @@ -1,8 +1,10 @@ package com.volmit.iris.core.link; +import com.volmit.iris.engine.framework.Engine; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; +import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; @@ -28,6 +30,7 @@ public abstract class ExternalDataProvider { public abstract BlockData getBlockData(Identifier blockId) throws MissingResourceException; public abstract ItemStack getItemStack(Identifier itemId) throws MissingResourceException; + public void processUpdate(Engine engine, Block block, Identifier blockId) {}; public abstract Identifier[] getBlockTypes(); diff --git a/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java new file mode 100644 index 000000000..3e0a384c9 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java @@ -0,0 +1,129 @@ +package com.volmit.iris.core.link; + +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.data.IrisBlockData; +import com.volmit.iris.util.reflect.WrappedField; +import com.volmit.iris.util.reflect.WrappedReturningMethod; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Leaves; +import org.bukkit.inventory.ItemStack; + +import java.util.Map; +import java.util.MissingResourceException; +import java.util.function.Supplier; + +public class HMCLeavesDataProvider extends ExternalDataProvider { + private Object apiInstance; + private WrappedReturningMethod worldBlockType; + private WrappedReturningMethod setCustomBlock; + private Map blockDataMap = Map.of(); + private Map> itemDataField = Map.of(); + + public HMCLeavesDataProvider() { + super("HMCLeaves"); + } + + @Override + public String getPluginId() { + return "HMCLeaves"; + } + + @Override + public void init() { + try { + worldBlockType = new WrappedReturningMethod<>((Class) Class.forName("io.github.fisher2911.hmcleaves.data.BlockData"), "worldBlockType"); + apiInstance = getApiInstance(Class.forName("io.github.fisher2911.hmcleaves.api.HMCLeavesAPI")); + setCustomBlock = new WrappedReturningMethod<>((Class) apiInstance.getClass(), "setCustomBlock", Location.class, String.class, boolean.class); + Object config = getLeavesConfig(apiInstance.getClass()); + blockDataMap = getMap(config, "blockDataMap"); + itemDataField = getMap(config, "itemSupplierMap"); + } catch (Throwable e) { + Iris.error("Failed to initialize HMCLeavesDataProvider: " + e.getMessage()); + } + } + + @Override + public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + Object o = blockDataMap.get(blockId.key()); + if (o == null) + throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); + Material material = worldBlockType.invoke(o, new Object[0]); + if (material == null) + throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); + BlockData blockData = Bukkit.createBlockData(material); + if (blockData instanceof Leaves leaves) + leaves.setPersistent(true); + return new IrisBlockData(blockData, blockId); + } + + @Override + public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + if (!itemDataField.containsKey(itemId.key())) + throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); + return itemDataField.get(itemId.key()).get(); + } + + @Override + public void processUpdate(Engine engine, Block block, Identifier blockId) { + Boolean result = setCustomBlock.invoke(apiInstance, new Object[]{block.getLocation(), blockId.key(), true}); + if (result == null || !result) + Iris.warn("Failed to set custom block! " + blockId.key() + " " + block.getX() + " " + block.getY() + " " + block.getZ()); + } + + @Override + public Identifier[] getBlockTypes() { + KList names = new KList<>(); + for (String name : blockDataMap.keySet()) { + try { + Identifier key = new Identifier("hmcleaves", name); + if (getBlockData(key) != null) + names.add(key); + } catch (MissingResourceException ignored) { + } + } + + return names.toArray(new Identifier[0]); + } + + @Override + public Identifier[] getItemTypes() { + KList names = new KList<>(); + for (String name : itemDataField.keySet()) { + try { + Identifier key = new Identifier("hmcleaves", name); + if (getItemStack(key) != null) + names.add(key); + } catch (MissingResourceException ignored) { + } + } + + return names.toArray(new Identifier[0]); + } + + @Override + public boolean isValidProvider(Identifier id, boolean isItem) { + return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key()); + } + + private Map getMap(C config, String name) { + WrappedField> field = new WrappedField<>((Class) config.getClass(), name); + return field.get(config); + } + + private A getApiInstance(Class apiClass) { + WrappedReturningMethod instance = new WrappedReturningMethod<>(apiClass, "getInstance"); + return instance.invoke(); + } + + private C getLeavesConfig(Class apiClass) { + WrappedReturningMethod instance = new WrappedReturningMethod<>(apiClass, "getInstance"); + WrappedField config = new WrappedField<>(apiClass, "config"); + return config.get(instance.invoke()); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java index 068c8c18e..58e21883d 100644 --- a/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java @@ -19,18 +19,25 @@ package com.volmit.iris.core.link; import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.data.B; +import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.reflect.WrappedField; import io.th0rgal.oraxen.api.OraxenItems; import io.th0rgal.oraxen.items.ItemBuilder; +import io.th0rgal.oraxen.mechanics.Mechanic; import io.th0rgal.oraxen.mechanics.MechanicFactory; import io.th0rgal.oraxen.mechanics.MechanicsManager; import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanic; import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory; +import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureFactory; +import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic; import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory; import io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.MultipleFacing; import org.bukkit.inventory.ItemStack; @@ -69,6 +76,8 @@ public class OraxenDataProvider extends ExternalDataProvider { return newBlockData; } else if (factory instanceof StringBlockMechanicFactory f) { return f.createTripwireData(blockId.key()); + } else if (factory instanceof FurnitureFactory) { + return new IrisBlockData(B.getAir(), blockId); } else throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); } @@ -79,6 +88,14 @@ public class OraxenDataProvider extends ExternalDataProvider { return opt.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())).build(); } + @Override + public void processUpdate(Engine engine, Block block, Identifier blockId) { + Mechanic mechanic = getFactory(blockId).getMechanic(blockId.key()); + if (mechanic instanceof FurnitureMechanic f) { + f.place(block.getLocation()); + } + } + @Override public Identifier[] getBlockTypes() { KList names = new KList<>(); diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 5989a50d8..5f1d114b5 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -27,10 +27,16 @@ import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; import com.volmit.iris.util.nbt.tag.CompoundTag; -import org.bukkit.*; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.WorldCreator; import org.bukkit.block.Biome; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntitySpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; @@ -104,4 +110,6 @@ public interface INMSBinding { void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException; Vector3d getBoundingbox(org.bukkit.entity.EntityType entity); + + Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason); } diff --git a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java index 754915c2c..e99478753 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java +++ b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java @@ -35,6 +35,8 @@ import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; @@ -90,6 +92,11 @@ public class NMSBinding1X implements INMSBinding { return null; } + @Override + public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return location.getWorld().spawnEntity(location, type); + } + @Override public void deserializeTile(CompoundTag s, Location newPosition) { diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java index b5b705900..56ee44b05 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java @@ -163,7 +163,10 @@ public class IrisPregenerator { generator.close(); ticker.interrupt(); listener.onClose(); - getMantle().trim(0, 0); + Mantle mantle = getMantle(); + if (mantle != null) { + mantle.trim(0, 0); + } } private void visitRegion(int x, int z, boolean regions) { diff --git a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java index de6d2ac81..53f566586 100644 --- a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java @@ -1,119 +1,134 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 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 . - */ - -package com.volmit.iris.core.service; - -import com.volmit.iris.Iris; -import com.volmit.iris.core.link.*; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.plugin.IrisService; -import lombok.Data; -import org.bukkit.Bukkit; -import org.bukkit.block.data.BlockData; -import org.bukkit.event.EventHandler; -import org.bukkit.event.server.PluginEnableEvent; -import org.bukkit.inventory.ItemStack; - -import java.util.MissingResourceException; -import java.util.Optional; - -@Data -public class ExternalDataSVC implements IrisService { - - private KList providers = new KList<>(), activeProviders = new KList<>(); - - @Override - public void onEnable() { - Iris.info("Loading ExternalDataProvider..."); - Bukkit.getPluginManager().registerEvents(this, Iris.instance); - - providers.add(new OraxenDataProvider()); - if (Bukkit.getPluginManager().getPlugin("Oraxen") != null) { - Iris.info("Oraxen found, loading OraxenDataProvider..."); - } - providers.add(new ItemAdderDataProvider()); - if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) { - Iris.info("ItemAdder found, loading ItemAdderDataProvider..."); - } - providers.add(new ExecutableItemsDataProvider()); - if (Bukkit.getPluginManager().getPlugin("ExecutableItems") != null) { - Iris.info("ExecutableItems found, loading ExecutableItemsDataProvider..."); - } - - for (ExternalDataProvider p : providers) { - if (p.isReady()) { - activeProviders.add(p); - p.init(); - Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId()); - } - } - } - - @Override - public void onDisable() { - } - - @EventHandler - public void onPluginEnable(PluginEnableEvent e) { - if (activeProviders.stream().noneMatch(p -> p.getPlugin().equals(e.getPlugin()))) { - providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> { - activeProviders.add(edp); - edp.init(); - Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId()); - }); - } - } - - public Optional getBlockData(Identifier key) { - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, false)).findFirst(); - if (provider.isEmpty()) - return Optional.empty(); - try { - return Optional.of(provider.get().getBlockData(key)); - } catch (MissingResourceException e) { - Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); - return Optional.empty(); - } - } - - public Optional getItemStack(Identifier key) { - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst(); - if (provider.isEmpty()) { - Iris.warn("No matching Provider found for modded material \"%s\"!", key); - return Optional.empty(); - } - try { - return Optional.of(provider.get().getItemStack(key)); - } catch (MissingResourceException e) { - Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); - return Optional.empty(); - } - } - - public Identifier[] getAllBlockIdentifiers() { - KList names = new KList<>(); - activeProviders.forEach(p -> names.add(p.getBlockTypes())); - return names.toArray(new Identifier[0]); - } - - public Identifier[] getAllItemIdentifiers() { - KList names = new KList<>(); - activeProviders.forEach(p -> names.add(p.getItemTypes())); - return names.toArray(new Identifier[0]); - } -} +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 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 . + */ + +package com.volmit.iris.core.service; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.link.*; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.plugin.IrisService; +import lombok.Data; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.event.EventHandler; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.MissingResourceException; +import java.util.Optional; + +@Data +public class ExternalDataSVC implements IrisService { + + private KList providers = new KList<>(), activeProviders = new KList<>(); + + @Override + public void onEnable() { + Iris.info("Loading ExternalDataProvider..."); + Bukkit.getPluginManager().registerEvents(this, Iris.instance); + + providers.add(new OraxenDataProvider()); + if (Bukkit.getPluginManager().getPlugin("Oraxen") != null) { + Iris.info("Oraxen found, loading OraxenDataProvider..."); + } + providers.add(new ItemAdderDataProvider()); + if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) { + Iris.info("ItemAdder found, loading ItemAdderDataProvider..."); + } + providers.add(new ExecutableItemsDataProvider()); + if (Bukkit.getPluginManager().getPlugin("ExecutableItems") != null) { + Iris.info("ExecutableItems found, loading ExecutableItemsDataProvider..."); + } + providers.add(new HMCLeavesDataProvider()); + if (Bukkit.getPluginManager().getPlugin("HMCLeaves") != null) { + Iris.info("BlockAdder found, loading HMCLeavesDataProvider..."); + } + + for (ExternalDataProvider p : providers) { + if (p.isReady()) { + activeProviders.add(p); + p.init(); + Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId()); + } + } + } + + @Override + public void onDisable() { + } + + @EventHandler + public void onPluginEnable(PluginEnableEvent e) { + if (activeProviders.stream().noneMatch(p -> p.getPlugin().equals(e.getPlugin()))) { + providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> { + activeProviders.add(edp); + edp.init(); + Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId()); + }); + } + } + + public Optional getBlockData(Identifier key) { + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, false)).findFirst(); + if (provider.isEmpty()) + return Optional.empty(); + try { + return Optional.of(provider.get().getBlockData(key)); + } catch (MissingResourceException e) { + Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); + return Optional.empty(); + } + } + + public Optional getItemStack(Identifier key) { + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst(); + if (provider.isEmpty()) { + Iris.warn("No matching Provider found for modded material \"%s\"!", key); + return Optional.empty(); + } + try { + return Optional.of(provider.get().getItemStack(key)); + } catch (MissingResourceException e) { + Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); + return Optional.empty(); + } + } + + public void processUpdate(Engine engine, Block block, Identifier blockId) { + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, true)).findFirst(); + if (provider.isEmpty()) { + Iris.warn("No matching Provider found for modded material \"%s\"!", blockId); + return; + } + provider.get().processUpdate(engine, block, blockId); + } + + public Identifier[] getAllBlockIdentifiers() { + KList names = new KList<>(); + activeProviders.forEach(p -> names.add(p.getBlockTypes())); + return names.toArray(new Identifier[0]); + } + + public Identifier[] getAllItemIdentifiers() { + KList names = new KList<>(); + activeProviders.forEach(p -> names.add(p.getItemTypes())); + return names.toArray(new Identifier[0]); + } +} diff --git a/core/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java b/core/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java index cbf18c1e6..015efd0e9 100644 --- a/core/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java +++ b/core/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine.data.chunk; import com.volmit.iris.core.nms.BiomeBaseInjector; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.util.data.IrisBiomeStorage; +import com.volmit.iris.util.data.IrisBlockData; import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -120,6 +121,8 @@ public class LinkedTerrainChunk implements TerrainChunk { @Override public synchronized void setBlock(int x, int y, int z, BlockData blockData) { + if (blockData instanceof IrisBlockData d) + blockData = d.getBase(); rawChunkData.setBlock(x, y, z, blockData); } diff --git a/core/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java b/core/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java index 31b24a665..2da3db43a 100644 --- a/core/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java +++ b/core/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java @@ -20,6 +20,7 @@ package com.volmit.iris.engine.data.chunk; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.BiomeBaseInjector; +import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.nbt.mca.Chunk; import com.volmit.iris.util.nbt.mca.NBTWorld; import lombok.AllArgsConstructor; @@ -88,6 +89,8 @@ public class MCATerrainChunk implements TerrainChunk { if (blockData == null) { Iris.error("NULL BD"); } + if (blockData instanceof IrisBlockData data) + blockData = data.getBase(); mcaChunk.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false); } diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 4d57cdf83..e1f6560dc 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -22,10 +22,12 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.gui.components.RenderType; import com.volmit.iris.core.gui.components.Renderer; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.nms.container.BlockPos; import com.volmit.iris.core.nms.container.Pair; +import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.data.chunk.TerrainChunk; @@ -38,6 +40,7 @@ import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.DataProvider; +import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.format.C; @@ -254,6 +257,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat if (B.isUpdatable(data)) { getMantle().updateBlock(x, y, z); } + if (data instanceof IrisBlockData d) { + getMantle().getMantle().set(x, y, z, d.getCustom()); + } else { + getMantle().getMantle().remove(x, y, z, Identifier.class); + } } void blockUpdatedMetric(); @@ -277,6 +285,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), tile.getData().getTileId()); }); })); + getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.s(() -> { + getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> { + Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v); + }); + })); getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.UPDATE, () -> J.s(() -> { PrecisionStopwatch p = PrecisionStopwatch.start(); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java index 8dabc091d..61de43e69 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.loader.IrisRegistrant; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; @@ -41,6 +42,7 @@ import org.bukkit.*; import org.bukkit.attribute.Attributable; import org.bukkit.entity.*; import org.bukkit.entity.Panda.Gene; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.loot.LootContext; @@ -67,6 +69,9 @@ public class IrisEntity extends IrisRegistrant { @Desc("The type of entity to spawn. To spawn a mythic mob, set this type to unknown and define mythic type.") private EntityType type = EntityType.UNKNOWN; + @Desc("The SpawnReason to spawn the entity with.") + private CreatureSpawnEvent.SpawnReason reason = CreatureSpawnEvent.SpawnReason.NATURAL; + @Desc("The custom name of this entity") private String customName = ""; @@ -457,7 +462,7 @@ public class IrisEntity extends IrisRegistrant { } - return at.getWorld().spawnEntity(at, getType()); + return INMS.get().spawnEntity(at, getType(), getReason()); } public boolean isCitizens() { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java index 03a306a1c..8b5924e41 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java @@ -23,6 +23,7 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.PlacedObject; import com.volmit.iris.engine.framework.placer.HeightmapObjectPlacer; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -698,12 +699,15 @@ public class IrisObject extends IrisRegistrant { if (!config.getAllowedCollisions().isEmpty() || !config.getForbiddenCollisions().isEmpty()) { Engine engine = rdata.getEngine(); - String key; BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); for (int i = x - Math.floorDiv(w, 2) + (int) offset.getX(); i <= x + Math.floorDiv(w, 2) - (w % 2 == 0 ? 1 : 0) + (int) offset.getX(); i++) { for (int j = y - Math.floorDiv(h, 2) + (int) offset.getY(); j <= y + Math.floorDiv(h, 2) - (h % 2 == 0 ? 1 : 0) + (int) offset.getY(); j++) { for (int k = z - Math.floorDiv(d, 2) + (int) offset.getZ(); k <= z + Math.floorDiv(d, 2) - (d % 2 == 0 ? 1 : 0) + (int) offset.getX(); k++) { - key = engine.getObjectPlacementKey(i, j, k); + PlacedObject p = engine.getObjectPlacement(i, j, k); + if (p == null) continue; + IrisObject o = p.getObject(); + if (o == null) continue; + String key = o.getLoadKey(); if (key != null) { if (config.getForbiddenCollisions().contains(key) && !config.getAllowedCollisions().contains(key)) { // Iris.debug("%s collides with %s (%s / %s / %s)", getLoadKey(), key, i, j, k); diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index f63b6d12a..50206b6d1 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -1,413 +1,432 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 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 . - */ - -package com.volmit.iris.engine.platform; - -import com.volmit.iris.Iris; -import com.volmit.iris.core.loader.IrisData; -import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.core.service.StudioSVC; -import com.volmit.iris.engine.IrisEngine; -import com.volmit.iris.engine.data.chunk.TerrainChunk; -import com.volmit.iris.engine.framework.Engine; -import com.volmit.iris.engine.framework.EngineTarget; -import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.engine.object.IrisWorld; -import com.volmit.iris.engine.object.StudioMode; -import com.volmit.iris.engine.platform.studio.StudioGenerator; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.data.IrisBiomeStorage; -import com.volmit.iris.util.hunk.Hunk; -import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; -import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; -import com.volmit.iris.util.io.ReactiveFolder; -import com.volmit.iris.util.scheduling.ChronoLatch; -import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.Looper; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.Setter; -import org.bukkit.*; -import org.bukkit.block.Biome; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.WorldInitEvent; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.ChunkGenerator; -import org.bukkit.generator.WorldInfo; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.List; -import java.util.Random; -import java.util.concurrent.Semaphore; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; - -@EqualsAndHashCode(callSuper = true) -@Data -public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator, Listener { - private static final int LOAD_LOCKS = Runtime.getRuntime().availableProcessors() * 4; - private final Semaphore loadLock; - private final IrisWorld world; - private final File dataLocation; - private final String dimensionKey; - private final ReactiveFolder folder; - private final ReentrantLock lock = new ReentrantLock(); - private final KList populators; - private final ChronoLatch hotloadChecker; - private final AtomicBoolean setup; - private final boolean studio; - private final AtomicInteger a = new AtomicInteger(0); - private Engine engine; - private Looper hotloader; - private StudioMode lastMode; - private DummyBiomeProvider dummyBiomeProvider; - @Setter - private StudioGenerator studioGenerator; - - private boolean initialized = false; - - public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) { - setup = new AtomicBoolean(false); - studioGenerator = null; - dummyBiomeProvider = new DummyBiomeProvider(); - populators = new KList<>(); - loadLock = new Semaphore(LOAD_LOCKS); - this.world = world; - this.hotloadChecker = new ChronoLatch(1000, false); - this.studio = studio; - this.dataLocation = dataLocation; - this.dimensionKey = dimensionKey; - this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload()); - Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance); - } - - private static Field getField(Class clazz, String fieldName) - throws NoSuchFieldException { - try { - return clazz.getDeclaredField(fieldName); - } catch (NoSuchFieldException e) { - Class superClass = clazz.getSuperclass(); - if (superClass == null) { - throw e; - } else { - return getField(superClass, fieldName); - } - } - } - - @EventHandler - public void onWorldInit(WorldInitEvent event) { - try { - if (!initialized) { - world.setRawWorldSeed(event.getWorld().getSeed()); - if (world.name().equals(event.getWorld().getName())) { - INMS.get().inject(event.getWorld().getSeed(), getEngine(event.getWorld()), event.getWorld()); - Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); - initialized = true; - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - - private void setupEngine() { - IrisData data = IrisData.get(dataLocation); - IrisDimension dimension = data.getDimensionLoader().load(dimensionKey); - - if (dimension == null) { - Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey); - IrisDimension test = IrisData.loadAnyDimension(dimensionKey); - - if (test != null) { - Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " "); - Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile()); - Iris.warn("Attempted to install into " + data.getDataFolder().getPath()); - data.dump(); - data.clearLists(); - test = data.getDimensionLoader().load(dimensionKey); - - if (test != null) { - Iris.success("Woo! Patched the Engine!"); - dimension = test; - } else { - Iris.error("Failed to patch dimension!"); - throw new RuntimeException("Missing Dimension: " + dimensionKey); - } - } else { - Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?"); - throw new RuntimeException("Missing Dimension: " + dimensionKey); - } - } - - lastMode = StudioMode.NORMAL; - engine = new IrisEngine(new EngineTarget(world, dimension, data), studio); - populators.clear(); - } - - @Override - public void injectChunkReplacement(World world, int x, int z, Consumer jobs) { - try { - loadLock.acquire(); - IrisBiomeStorage st = new IrisBiomeStorage(); - TerrainChunk tc = TerrainChunk.createUnsafe(world, st); - Hunk blocks = Hunk.view(tc); - Hunk biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight()); - this.world.bind(world); - getEngine().generate(x << 4, z << 4, blocks, biomes, true); - Iris.debug("Regenerated " + x + " " + z); - int t = 0; - for (int i = getEngine().getHeight() >> 4; i >= 0; i--) { - if (!world.isChunkLoaded(x, z)) { - continue; - } - - Chunk c = world.getChunkAt(x, z); - for (Entity ee : c.getEntities()) { - if (ee instanceof Player) { - continue; - } - - J.s(ee::remove); - } - - J.s(() -> engine.getWorldManager().onChunkLoad(c, false)); - - int finalI = i; - jobs.accept(() -> { - - for (int xx = 0; xx < 16; xx++) { - for (int yy = 0; yy < 16; yy++) { - for (int zz = 0; zz < 16; zz++) { - if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) { - continue; - } - c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz) - .setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false); - } - } - } - }); - } - - loadLock.release(); - } catch (Throwable e) { - loadLock.release(); - Iris.error("======================================"); - e.printStackTrace(); - Iris.reportErrorChunk(x, z, e, "CHUNK"); - Iris.error("======================================"); - - ChunkData d = Bukkit.createChunkData(world); - - for (int i = 0; i < 16; i++) { - for (int j = 0; j < 16; j++) { - d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData()); - } - } - } - } - - private Engine getEngine(WorldInfo world) { - if (setup.get()) { - return getEngine(); - } - - lock.lock(); - - if (setup.get()) { - return getEngine(); - } - - - setup.set(true); - getWorld().setRawWorldSeed(world.getSeed()); - setupEngine(); - this.hotloader = studio ? new Looper() { - @Override - protected long loop() { - if (hotloadChecker.flip()) { - folder.check(); - } - - return 250; - } - } : null; - - if (studio) { - hotloader.setPriority(Thread.MIN_PRIORITY); - hotloader.start(); - hotloader.setName(getTarget().getWorld().name() + " Hotloader"); - } - - lock.unlock(); - - return engine; - } - - @Override - public void close() { - withExclusiveControl(() -> { - if (isStudio()) { - hotloader.interrupt(); - } - - getEngine().close(); - folder.clear(); - populators.clear(); - - }); - } - - @Override - public boolean isStudio() { - return studio; - } - - @Override - public void hotload() { - if (!isStudio()) { - return; - } - - withExclusiveControl(() -> getEngine().hotload()); - } - - public void withExclusiveControl(Runnable r) { - J.a(() -> { - try { - loadLock.acquire(LOAD_LOCKS); - r.run(); - loadLock.release(LOAD_LOCKS); - } catch (Throwable e) { - Iris.reportError(e); - } - }); - } - - @Override - public void touch(World world) { - getEngine(world); - } - - @Override - public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) { - try { - getEngine(world); - computeStudioGenerator(); - TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage()); - this.world.bind(world); - if (studioGenerator != null) { - studioGenerator.generateChunk(getEngine(), tc, x, z); - } else { - ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc); - BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight()); - getEngine().generate(x << 4, z << 4, blocks, biomes, false); - blocks.apply(); - biomes.apply(); - } - - Iris.debug("Generated " + x + " " + z); - } catch (Throwable e) { - Iris.error("======================================"); - e.printStackTrace(); - Iris.reportErrorChunk(x, z, e, "CHUNK"); - Iris.error("======================================"); - - for (int i = 0; i < 16; i++) { - for (int j = 0; j < 16; j++) { - d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData()); - } - } - } - } - - @Override - public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) { - return 4; - } - - private void computeStudioGenerator() { - if (!getEngine().getDimension().getStudioMode().equals(lastMode)) { - lastMode = getEngine().getDimension().getStudioMode(); - getEngine().getDimension().getStudioMode().inject(this); - } - } - - @NotNull - @Override - public List getDefaultPopulators(@NotNull World world) { - return populators; - } - - @Override - public boolean isParallelCapable() { - return true; - } - - @Override - public boolean shouldGenerateCaves() { - return false; - } - - @Override - public boolean shouldGenerateDecorations() { - return false; - } - - @Override - public boolean shouldGenerateMobs() { - return false; - } - - @Override - public boolean shouldGenerateStructures() { - return false; - } - - @Override - public boolean shouldGenerateNoise() { - return false; - } - - @Override - public boolean shouldGenerateSurface() { - return false; - } - - @Override - public boolean shouldGenerateBedrock() { - return false; - } - - @Nullable - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return dummyBiomeProvider; - } -} +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 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 . + */ + +package com.volmit.iris.engine.platform; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.service.StudioSVC; +import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.data.chunk.TerrainChunk; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.EngineTarget; +import com.volmit.iris.engine.object.IrisDimension; +import com.volmit.iris.engine.object.IrisWorld; +import com.volmit.iris.engine.object.StudioMode; +import com.volmit.iris.engine.platform.studio.StudioGenerator; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.data.IrisBiomeStorage; +import com.volmit.iris.util.hunk.Hunk; +import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; +import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; +import com.volmit.iris.util.io.ReactiveFolder; +import com.volmit.iris.util.scheduling.ChronoLatch; +import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.Looper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Setter; +import org.bukkit.*; +import org.bukkit.block.Biome; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldInitEvent; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.generator.WorldInfo; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Random; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; + +@EqualsAndHashCode(callSuper = true) +@Data +public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator, Listener { + private static final int LOAD_LOCKS = Runtime.getRuntime().availableProcessors() * 4; + private final Semaphore loadLock; + private final IrisWorld world; + private final File dataLocation; + private final String dimensionKey; + private final ReactiveFolder folder; + private final ReentrantLock lock = new ReentrantLock(); + private final KList populators; + private final ChronoLatch hotloadChecker; + private final AtomicBoolean setup; + private final boolean studio; + private final AtomicInteger a = new AtomicInteger(0); + private Engine engine; + private Looper hotloader; + private StudioMode lastMode; + private DummyBiomeProvider dummyBiomeProvider; + @Setter + private StudioGenerator studioGenerator; + + private boolean initialized = false; + + public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) { + setup = new AtomicBoolean(false); + studioGenerator = null; + dummyBiomeProvider = new DummyBiomeProvider(); + populators = new KList<>(); + loadLock = new Semaphore(LOAD_LOCKS); + this.world = world; + this.hotloadChecker = new ChronoLatch(1000, false); + this.studio = studio; + this.dataLocation = dataLocation; + this.dimensionKey = dimensionKey; + this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload()); + Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance); + } + + private static Field getField(Class clazz, String fieldName) + throws NoSuchFieldException { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) { + throw e; + } else { + return getField(superClass, fieldName); + } + } + } + + @EventHandler + public void onWorldInit(WorldInitEvent event) { + try { + if (!initialized) { + world.setRawWorldSeed(event.getWorld().getSeed()); + if (world.name().equals(event.getWorld().getName())) { + Engine engine = getEngine(event.getWorld()); + if (engine == null) { + Iris.warn("Failed to get Engine!"); + J.s(() -> { + Engine engine1 = getEngine(event.getWorld()); + if (engine1 != null) { + try { + INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld()); + Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); + initialized = true; + } catch (Throwable e) { + e.printStackTrace(); + } + } + }, 10); + } else { + INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld()); + Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); + initialized = true; + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + private void setupEngine() { + IrisData data = IrisData.get(dataLocation); + IrisDimension dimension = data.getDimensionLoader().load(dimensionKey); + + if (dimension == null) { + Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey); + IrisDimension test = IrisData.loadAnyDimension(dimensionKey); + + if (test != null) { + Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " "); + Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile()); + Iris.warn("Attempted to install into " + data.getDataFolder().getPath()); + data.dump(); + data.clearLists(); + test = data.getDimensionLoader().load(dimensionKey); + + if (test != null) { + Iris.success("Woo! Patched the Engine!"); + dimension = test; + } else { + Iris.error("Failed to patch dimension!"); + throw new RuntimeException("Missing Dimension: " + dimensionKey); + } + } else { + Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?"); + throw new RuntimeException("Missing Dimension: " + dimensionKey); + } + } + + lastMode = StudioMode.NORMAL; + engine = new IrisEngine(new EngineTarget(world, dimension, data), studio); + populators.clear(); + } + + @Override + public void injectChunkReplacement(World world, int x, int z, Consumer jobs) { + try { + loadLock.acquire(); + IrisBiomeStorage st = new IrisBiomeStorage(); + TerrainChunk tc = TerrainChunk.createUnsafe(world, st); + Hunk blocks = Hunk.view(tc); + Hunk biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight()); + this.world.bind(world); + getEngine().generate(x << 4, z << 4, blocks, biomes, true); + Iris.debug("Regenerated " + x + " " + z); + int t = 0; + for (int i = getEngine().getHeight() >> 4; i >= 0; i--) { + if (!world.isChunkLoaded(x, z)) { + continue; + } + + Chunk c = world.getChunkAt(x, z); + for (Entity ee : c.getEntities()) { + if (ee instanceof Player) { + continue; + } + + J.s(ee::remove); + } + + J.s(() -> engine.getWorldManager().onChunkLoad(c, false)); + + int finalI = i; + jobs.accept(() -> { + + for (int xx = 0; xx < 16; xx++) { + for (int yy = 0; yy < 16; yy++) { + for (int zz = 0; zz < 16; zz++) { + if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) { + continue; + } + c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz) + .setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false); + } + } + } + }); + } + + loadLock.release(); + } catch (Throwable e) { + loadLock.release(); + Iris.error("======================================"); + e.printStackTrace(); + Iris.reportErrorChunk(x, z, e, "CHUNK"); + Iris.error("======================================"); + + ChunkData d = Bukkit.createChunkData(world); + + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData()); + } + } + } + } + + private Engine getEngine(WorldInfo world) { + if (setup.get()) { + return getEngine(); + } + + lock.lock(); + + try { + if (setup.get()) { + return getEngine(); + } + + + getWorld().setRawWorldSeed(world.getSeed()); + setupEngine(); + setup.set(true); + this.hotloader = studio ? new Looper() { + @Override + protected long loop() { + if (hotloadChecker.flip()) { + folder.check(); + } + + return 250; + } + } : null; + + if (studio) { + hotloader.setPriority(Thread.MIN_PRIORITY); + hotloader.start(); + hotloader.setName(getTarget().getWorld().name() + " Hotloader"); + } + + return engine; + } finally { + lock.unlock(); + } + } + + @Override + public void close() { + withExclusiveControl(() -> { + if (isStudio()) { + hotloader.interrupt(); + } + + getEngine().close(); + folder.clear(); + populators.clear(); + + }); + } + + @Override + public boolean isStudio() { + return studio; + } + + @Override + public void hotload() { + if (!isStudio()) { + return; + } + + withExclusiveControl(() -> getEngine().hotload()); + } + + public void withExclusiveControl(Runnable r) { + J.a(() -> { + try { + loadLock.acquire(LOAD_LOCKS); + r.run(); + loadLock.release(LOAD_LOCKS); + } catch (Throwable e) { + Iris.reportError(e); + } + }); + } + + @Override + public void touch(World world) { + getEngine(world); + } + + @Override + public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) { + try { + getEngine(world); + computeStudioGenerator(); + TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage()); + this.world.bind(world); + if (studioGenerator != null) { + studioGenerator.generateChunk(getEngine(), tc, x, z); + } else { + ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc); + BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight()); + getEngine().generate(x << 4, z << 4, blocks, biomes, false); + blocks.apply(); + biomes.apply(); + } + + Iris.debug("Generated " + x + " " + z); + } catch (Throwable e) { + Iris.error("======================================"); + e.printStackTrace(); + Iris.reportErrorChunk(x, z, e, "CHUNK"); + Iris.error("======================================"); + + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData()); + } + } + } + } + + @Override + public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) { + return 4; + } + + private void computeStudioGenerator() { + if (!getEngine().getDimension().getStudioMode().equals(lastMode)) { + lastMode = getEngine().getDimension().getStudioMode(); + getEngine().getDimension().getStudioMode().inject(this); + } + } + + @NotNull + @Override + public List getDefaultPopulators(@NotNull World world) { + return populators; + } + + @Override + public boolean isParallelCapable() { + return true; + } + + @Override + public boolean shouldGenerateCaves() { + return false; + } + + @Override + public boolean shouldGenerateDecorations() { + return false; + } + + @Override + public boolean shouldGenerateMobs() { + return false; + } + + @Override + public boolean shouldGenerateStructures() { + return false; + } + + @Override + public boolean shouldGenerateNoise() { + return false; + } + + @Override + public boolean shouldGenerateSurface() { + return false; + } + + @Override + public boolean shouldGenerateBedrock() { + return false; + } + + @Nullable + @Override + public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { + return dummyBiomeProvider; + } +} diff --git a/core/src/main/java/com/volmit/iris/util/data/IrisBlockData.java b/core/src/main/java/com/volmit/iris/util/data/IrisBlockData.java new file mode 100644 index 000000000..dce36cd17 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/data/IrisBlockData.java @@ -0,0 +1,127 @@ +package com.volmit.iris.util.data; + +import com.volmit.iris.core.link.Identifier; +import lombok.Data; +import lombok.NonNull; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.SoundGroup; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.structure.Mirror; +import org.bukkit.block.structure.StructureRotation; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@Data +public class IrisBlockData implements BlockData{ + private final @NonNull BlockData base; + private final @NotNull Identifier custom; + + @NotNull + @Override + public Material getMaterial() { + return base.getMaterial(); + } + + @NotNull + @Override + public String getAsString() { + return base.getAsString(); + } + + @NotNull + @Override + public String getAsString(boolean b) { + return base.getAsString(b); + } + + @NotNull + @Override + public BlockData merge(@NotNull BlockData blockData) { + return new IrisBlockData(base.merge(blockData), custom); + } + + @Override + public boolean matches(@Nullable BlockData blockData) { + if (blockData instanceof IrisBlockData b) + return custom.equals(b.custom) && base.matches(b.base); + return base.matches(blockData); + } + + @NotNull + @Override + public BlockData clone() { + return new IrisBlockData(base.clone(), custom); + } + + @NotNull + @Override + public SoundGroup getSoundGroup() { + return base.getSoundGroup(); + } + + @Override + public int getLightEmission() { + return base.getLightEmission(); + } + + @Override + public boolean isOccluding() { + return base.isOccluding(); + } + + @Override + public boolean requiresCorrectToolForDrops() { + return base.requiresCorrectToolForDrops(); + } + + @Override + public boolean isPreferredTool(@NotNull ItemStack itemStack) { + return base.isPreferredTool(itemStack); + } + + @NotNull + @Override + public PistonMoveReaction getPistonMoveReaction() { + return base.getPistonMoveReaction(); + } + + @Override + public boolean isSupported(@NotNull Block block) { + return base.isSupported(block); + } + + @Override + public boolean isSupported(@NotNull Location location) { + return base.isSupported(location); + } + + @Override + public boolean isFaceSturdy(@NotNull BlockFace blockFace, @NotNull BlockSupport blockSupport) { + return base.isFaceSturdy(blockFace, blockSupport); + } + + @NotNull + @Override + public Material getPlacementMaterial() { + return base.getPlacementMaterial(); + } + + @Override + public void rotate(@NotNull StructureRotation structureRotation) { + base.rotate(structureRotation); + } + + @Override + public void mirror(@NotNull Mirror mirror) { + base.mirror(mirror); + } + + @NotNull + @Override + public BlockState createBlockState() { + return base.createBlockState(); + } +} diff --git a/core/src/main/java/com/volmit/iris/util/hunk/view/ChunkDataHunkView.java b/core/src/main/java/com/volmit/iris/util/hunk/view/ChunkDataHunkView.java index a9267f3fc..62cb7fc61 100644 --- a/core/src/main/java/com/volmit/iris/util/hunk/view/ChunkDataHunkView.java +++ b/core/src/main/java/com/volmit/iris/util/hunk/view/ChunkDataHunkView.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.hunk.view; import com.volmit.iris.util.data.B; +import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.hunk.Hunk; import org.bukkit.block.data.BlockData; import org.bukkit.generator.ChunkGenerator.ChunkData; @@ -72,7 +73,8 @@ public class ChunkDataHunkView implements Hunk { } try { - + if (t instanceof IrisBlockData d) + t = d.getBase(); chunk.setBlock(x, y + chunk.getMinHeight(), z, t); } catch (Throwable ignored) { diff --git a/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java b/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java index 03d98dee6..6bb5f1e6f 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java @@ -33,7 +33,8 @@ public enum MantleFlag { CLEANED, PLANNED, ETCHED, - TILE; + TILE, + CUSTOM; static StateList getStateList() { return new StateList(MantleFlag.values()); diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java b/core/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java index 9a0de90ba..cf6eef776 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/BlockMatter.java @@ -18,6 +18,7 @@ package com.volmit.iris.util.matter.slices; +import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.palette.Palette; import com.volmit.iris.util.matter.Sliced; import org.bukkit.Bukkit; @@ -39,7 +40,11 @@ public class BlockMatter extends RawMatter { public BlockMatter(int width, int height, int depth) { super(width, height, depth, BlockData.class); - registerWriter(World.class, ((w, d, x, y, z) -> w.getBlockAt(x, y, z).setBlockData(d))); + registerWriter(World.class, ((w, d, x, y, z) -> { + if (d instanceof IrisBlockData c) + w.getBlockAt(x, y, z).setBlockData(c.getBase()); + else w.getBlockAt(x, y, z).setBlockData(d); + })); registerReader(World.class, (w, x, y, z) -> { BlockData d = w.getBlockAt(x, y, z).getBlockData(); return d.getMaterial().isAir() ? null : d; diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/IdentifierMatter.java b/core/src/main/java/com/volmit/iris/util/matter/slices/IdentifierMatter.java new file mode 100644 index 000000000..5777c6320 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/IdentifierMatter.java @@ -0,0 +1,36 @@ +package com.volmit.iris.util.matter.slices; + +import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.util.data.palette.Palette; +import com.volmit.iris.util.matter.Sliced; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +@Sliced +public class IdentifierMatter extends RawMatter { + + public IdentifierMatter() { + this(1, 1, 1); + } + + public IdentifierMatter(int width, int height, int depth) { + super(width, height, depth, Identifier.class); + } + + @Override + public Palette getGlobalPalette() { + return null; + } + + @Override + public void writeNode(Identifier b, DataOutputStream dos) throws IOException { + dos.writeUTF(b.toString()); + } + + @Override + public Identifier readNode(DataInputStream din) throws IOException { + return Identifier.fromString(din.readUTF()); + } +} diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java index ff0433491..2317f0fcb 100644 --- a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java +++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java @@ -42,9 +42,12 @@ import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R1.entity.CraftDolphin; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftWarden; import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -510,6 +513,11 @@ public class NMSBinding implements INMSBinding { return null; } + @Override + public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java index 7609c6195..07a28b5cd 100644 --- a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java +++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java @@ -1,5 +1,34 @@ package com.volmit.iris.core.nms.v1_19_R2; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicInteger; + +import org.bukkit.*; +import org.bukkit.block.Biome; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_19_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_19_R2.CraftServer; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftDolphin; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; +import org.bukkit.entity.Dolphin; +import org.bukkit.entity.Entity; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; @@ -16,6 +45,7 @@ import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; + import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; @@ -33,35 +63,8 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.*; -import org.bukkit.block.Biome; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R2.CraftServer; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock; -import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftDolphin; -import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; -import org.bukkit.entity.Dolphin; -import org.bukkit.entity.Entity; -import org.bukkit.generator.ChunkGenerator; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import sun.misc.Unsafe; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.List; -import java.util.Vector; -import java.util.concurrent.atomic.AtomicInteger; - public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); private final BlockData AIR = Material.AIR.createBlockData(); @@ -511,6 +514,11 @@ public class NMSBinding implements INMSBinding { return null; } + @Override + public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java index 2244ed16c..7648ba946 100644 --- a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java +++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java @@ -47,6 +47,8 @@ import org.bukkit.craftbukkit.v1_19_R3.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -280,7 +282,7 @@ public class NMSBinding implements INMSBinding { @Override public KList getBiomes() { - return new KList<>(Biome.values()).qadd(Biome.CHERRY_GROVE).qdel(Biome.CUSTOM); + return new KList<>(Biome.values()).qdel(Biome.CHERRY_GROVE).qdel(Biome.CUSTOM); } @Override @@ -514,6 +516,15 @@ public class NMSBinding implements INMSBinding { return null; } + + @Override + public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) { + if (type == EntityType.CAMEL) { + return null; + } + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java index 4852ee5fa..38db0098a 100644 --- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java @@ -48,6 +48,8 @@ import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.entity.EntityType; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -502,6 +504,11 @@ public class NMSBinding implements INMSBinding { return null; } + @Override + public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { ServerLevel serverLevel = ((CraftWorld)world).getHandle(); Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java index e39897d6b..3e20e15f2 100644 --- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java @@ -48,6 +48,8 @@ import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -513,6 +515,11 @@ public class NMSBinding implements INMSBinding { return null; } + @Override + public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java index 0cf438604..125fe23ca 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java @@ -54,6 +54,8 @@ import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; import org.bukkit.entity.Creeper; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -520,6 +522,12 @@ public class NMSBinding implements INMSBinding { return null; } + + @Override + public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) {