From de670ddfd516d0d00535330040f669f8fc662948 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 11 Aug 2024 12:03:23 +0200 Subject: [PATCH 01/14] fix explorer/treasure map --- .../com/volmit/iris/core/nms/INMSBinding.java | 11 +- .../iris/core/nms/v1X/NMSBinding1X.java | 20 +- .../iris/core/project/SchemaBuilder.java | 19 ++ .../volmit/iris/core/service/DolphinSVC.java | 93 ------- .../volmit/iris/core/service/VillageSVC.java | 127 --------- .../volmit/iris/engine/IrisWorldManager.java | 20 ++ .../iris/engine/framework/ListFunction.java | 8 + .../iris/engine/framework/ResultLocator.java | 121 +++++++++ .../iris/engine/object/IrisDimension.java | 6 +- .../engine/object/IrisJigsawStructure.java | 4 + .../annotations/RegistryListFunction.java | 17 ++ .../annotations/StructureKeyFunction.java | 23 ++ .../volmit/iris/util/mantle/MantleFlag.java | 3 +- .../core/nms/v1_19_R1/IrisChunkGenerator.java | 236 +++++++++++++++++ .../iris/core/nms/v1_19_R1/NMSBinding.java | 39 +-- .../core/nms/v1_19_R2/IrisChunkGenerator.java | 241 +++++++++++++++++ .../iris/core/nms/v1_19_R2/NMSBinding.java | 39 +-- .../core/nms/v1_19_R3/IrisChunkGenerator.java | 241 +++++++++++++++++ .../iris/core/nms/v1_19_R3/NMSBinding.java | 33 ++- .../core/nms/v1_20_R1/IrisChunkGenerator.java | 241 +++++++++++++++++ .../iris/core/nms/v1_20_R1/NMSBinding.java | 39 +-- .../core/nms/v1_20_R2/IrisChunkGenerator.java | 241 +++++++++++++++++ .../iris/core/nms/v1_20_R2/NMSBinding.java | 39 +-- .../core/nms/v1_20_R3/IrisChunkGenerator.java | 244 ++++++++++++++++++ .../iris/core/nms/v1_20_R3/NMSBinding.java | 39 +-- .../core/nms/v1_20_R4/IrisChunkGenerator.java | 239 +++++++++++++++++ .../iris/core/nms/v1_20_R4/NMSBinding.java | 44 ++-- .../core/nms/v1_21_R1/IrisChunkGenerator.java | 240 +++++++++++++++++ .../iris/core/nms/v1_21_R1/NMSBinding.java | 40 +-- 29 files changed, 2337 insertions(+), 370 deletions(-) delete mode 100644 core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java delete mode 100644 core/src/main/java/com/volmit/iris/core/service/VillageSVC.java create mode 100644 core/src/main/java/com/volmit/iris/engine/framework/ListFunction.java create mode 100644 core/src/main/java/com/volmit/iris/engine/framework/ResultLocator.java create mode 100644 core/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListFunction.java create mode 100644 core/src/main/java/com/volmit/iris/engine/object/annotations/StructureKeyFunction.java create mode 100644 nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/IrisChunkGenerator.java create mode 100644 nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/IrisChunkGenerator.java create mode 100644 nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/IrisChunkGenerator.java create mode 100644 nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/IrisChunkGenerator.java create mode 100644 nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/IrisChunkGenerator.java create mode 100644 nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/IrisChunkGenerator.java create mode 100644 nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/IrisChunkGenerator.java create mode 100644 nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/IrisChunkGenerator.java 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 b2441dfd6..75c817a81 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 @@ -28,19 +28,18 @@ 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.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.WorldCreator; +import org.bukkit.*; 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.generator.structure.Structure; import org.bukkit.inventory.ItemStack; import java.awt.*; +import java.awt.Color; public interface INMSBinding { boolean hasTile(Location l); @@ -107,8 +106,6 @@ public interface INMSBinding { ItemStack applyCustomNbt(ItemStack itemStack, KMap customNbt) throws IllegalArgumentException; - void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos); - void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException; Vector3d getBoundingbox(org.bukkit.entity.EntityType entity); @@ -124,4 +121,6 @@ public interface INMSBinding { default int getSpawnChunkCount(World world) { return 441; } + + KList getStructureKeys(); } 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 8ce6caba8..941cef9af 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 @@ -30,18 +30,18 @@ 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.Chunk; -import org.bukkit.Location; -import org.bukkit.World; +import org.bukkit.*; 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.generator.structure.Structure; import org.bukkit.inventory.ItemStack; import java.awt.*; +import java.awt.Color; public class NMSBinding1X implements INMSBinding { private static final boolean supportsCustomHeight = testCustomHeight(); @@ -81,11 +81,6 @@ public class NMSBinding1X implements INMSBinding { return itemStack; } - @Override - public void setTreasurePos(Dolphin dolphin, BlockPos pos) { - - } - @Override public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { @@ -105,6 +100,15 @@ public class NMSBinding1X implements INMSBinding { return Color.GREEN; } + @Override + public KList getStructureKeys() { + var list = Registry.STRUCTURE.stream() + .map(Structure::getKey) + .map(NamespacedKey::toString) + .toList(); + return new KList<>(list); + } + @Override public void deserializeTile(CompoundTag s, Location newPosition) { diff --git a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java index 7cdf4dd76..ea672a78f 100644 --- a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java +++ b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java @@ -22,6 +22,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.ResourceLoader; +import com.volmit.iris.engine.framework.ListFunction; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -309,6 +310,24 @@ public class SchemaBuilder { fancyType = "Enchantment Type"; prop.put("$ref", "#/definitions/" + key); description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)"); + } else if (k.isAnnotationPresent(RegistryListFunction.class)) { + var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value(); + try { + var instance = functionClass.getDeclaredConstructor().newInstance(); + String key = instance.key(); + fancyType = instance.fancyName(); + + if (!definitions.containsKey(key)) { + JSONObject j = new JSONObject(); + j.put("enum", instance.apply(data)); + definitions.put(key, j); + } + + prop.put("$ref", "#/definitions/" + key); + description.add(SYMBOL_TYPE__N + " Must be a valid " + fancyType + " (use ctrl+space for auto complete!)"); + } catch (Throwable e) { + Iris.error("Could not execute apply method in " + functionClass.getName()); + } } else if (k.getType().equals(PotionEffectType.class)) { String key = "enum-potion-effect-type"; diff --git a/core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java b/core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java deleted file mode 100644 index 0f4aa53dc..000000000 --- a/core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java +++ /dev/null @@ -1,93 +0,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.core.nms.INMS; -import com.volmit.iris.core.nms.container.BlockPos; -import com.volmit.iris.core.tools.IrisToolbelt; -import com.volmit.iris.engine.framework.Engine; -import com.volmit.iris.util.documentation.ChunkCoordinates; -import com.volmit.iris.util.function.Consumer4; -import com.volmit.iris.util.math.Spiraler; -import com.volmit.iris.util.matter.MatterStructurePOI; -import com.volmit.iris.util.plugin.IrisService; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.SoundCategory; -import org.bukkit.entity.Dolphin; -import org.bukkit.entity.EntityType; -import org.bukkit.event.EventHandler; -import org.bukkit.event.player.PlayerInteractEntityEvent; -import org.bukkit.generator.structure.StructureType; - -import java.util.concurrent.atomic.AtomicReference; - -public class DolphinSVC implements IrisService { - - @Override - public void onEnable() { - - } - - @Override - public void onDisable() { - - } - - @EventHandler - public void on(PlayerInteractEntityEvent event) { - if (!IrisToolbelt.isIrisWorld(event.getPlayer().getWorld())) { - return; - } - - Material hand = event.getPlayer().getInventory().getItem(event.getHand()).getType(); - if (event.getRightClicked().getType().equals(EntityType.DOLPHIN) && (hand.equals(Material.TROPICAL_FISH) || hand.equals(Material.PUFFERFISH) || hand.equals(Material.COD) || hand.equals(Material.SALMON))) { - Engine e = IrisToolbelt.access(event.getPlayer().getWorld()).getEngine(); - searchNearestTreasure(e, event.getPlayer().getLocation().getBlockX() >> 4, event.getPlayer().getLocation().getBlockZ() >> 4, e.getMantle().getRadius() - 1, StructureType.BURIED_TREASURE, (x, y, z, p) -> { - event.setCancelled(true); - Dolphin d = (Dolphin) event.getRightClicked(); - INMS.get().setTreasurePos(d, new BlockPos(x, y, z)); - d.getWorld().playSound(d, Sound.ENTITY_DOLPHIN_EAT, SoundCategory.NEUTRAL, 1, 1); - }); - - } - } - - @ChunkCoordinates - public void findTreasure(Engine engine, int chunkX, int chunkY, StructureType type, Consumer4 consumer) { - AtomicReference ref = new AtomicReference<>(); - engine.getMantle().getMantle().iterateChunk(chunkX, chunkY, MatterStructurePOI.class, ref.get() == null ? (x, y, z, d) -> { - if (d.getType().equals(type.getKey().getKey())) { - ref.set(d); - consumer.accept(x, y, z, d); - } - } : (x, y, z, d) -> { - }); - } - - @ChunkCoordinates - public void searchNearestTreasure(Engine engine, int chunkX, int chunkY, int radius, StructureType type, Consumer4 consumer) { - AtomicReference ref = new AtomicReference<>(); - new Spiraler(radius * 2, radius * 2, (x, z) -> findTreasure(engine, x, z, type, ref.get() == null ? (i, d, g, a) -> { - ref.set(a); - consumer.accept(i, d, g, a); - } : (i, d, g, a) -> { - })).setOffset(chunkX, chunkY).drain(); - } -} diff --git a/core/src/main/java/com/volmit/iris/core/service/VillageSVC.java b/core/src/main/java/com/volmit/iris/core/service/VillageSVC.java deleted file mode 100644 index 820f40833..000000000 --- a/core/src/main/java/com/volmit/iris/core/service/VillageSVC.java +++ /dev/null @@ -1,127 +0,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.IrisSettings; -import com.volmit.iris.core.tools.IrisToolbelt; -import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.util.format.C; -import com.volmit.iris.util.plugin.IrisService; -import com.volmit.iris.util.plugin.VolmitSender; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.entity.Villager; -import org.bukkit.event.EventHandler; -import org.bukkit.event.entity.VillagerCareerChangeEvent; - -import java.util.List; - -public class VillageSVC implements IrisService { - @Override - public void onEnable() { - - } - - @Override - public void onDisable() { - - } - - @EventHandler - public void on(VillagerCareerChangeEvent event) { - - if (!IrisToolbelt.isIrisWorld(event.getEntity().getWorld())) { - return; - } - - IrisDimension dim = IrisToolbelt.access(event.getEntity().getWorld()) - .getEngine().getDimension(); - - if (!dim.isRemoveCartographersDueToCrash()) { - return; - } - - if (event.getProfession().equals(Villager.Profession.CARTOGRAPHER)) { - event.setCancelled(true); - - Location eventLocation = event.getEntity().getLocation(); - - int radius = dim.getNotifyPlayersOfCartographerCancelledRadius(); - - if (radius == -1) { - return; - } - - List playersInWorld = event.getEntity().getWorld().getPlayers(); - - String message = C.GOLD + IrisSettings.get().getGeneral().cartographerMessage; - - Iris.info("Cancelled Cartographer Villager to prevent server crash at " + eventLocation + "!"); - - if (radius == -2) { - playersInWorld.stream().map(VolmitSender::new).forEach(v -> v.sendMessage(message)); - } else { - playersInWorld.forEach(p -> { - if (p.getLocation().distance(eventLocation) < radius) { - new VolmitSender(p).sendMessage(message); - } - }); - } - - } - } - - /* - * Replace or disable villager trade add event to prevent explorer map - */ - /* Removed due to MC breaking stuff again. This event is now called after the cartographer maps are made, - so it can fuck right off. - @EventHandler - public void on(VillagerAcquireTradeEvent event) { - if(!IrisToolbelt.isIrisWorld((event.getEntity().getWorld()))) { - return; - } - - // Iris.info("Trade event: type " + event.getRecipe().getResult().getType() + " / meta " + event.getRecipe().getResult().getItemMeta() + " / data " + event.getRecipe().getResult().getData()); - if(!event.getRecipe().getResult().getType().equals(Material.FILLED_MAP)) { - return; - } - - IrisVillagerOverride override = IrisToolbelt.access(event.getEntity().getWorld()).getEngine() - .getDimension().getPatchCartographers(); - - if(override.isDisableTrade()) { - event.setCancelled(true); - Iris.debug("Cancelled cartographer trade @ " + event.getEntity().getLocation()); - return; - } - - if(override.getValidItems() == null) { - event.setCancelled(true); - Iris.debug("Cancelled cartographer trade because no override items are valid @ " + event.getEntity().getLocation()); - return; - } - - IrisVillagerTrade trade = override.getValidItems().getRandom(); - event.setRecipe(trade.convert()); - Iris.debug("Overrode cartographer trade with: " + trade + " to prevent allowing cartography map trades"); - } - */ -} diff --git a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index cfaa4383a..075e8660d 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -76,6 +76,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager { private final ChronoLatch ecl; private final ChronoLatch cln; private final ChronoLatch chunkUpdater; + private final ChronoLatch chunkDiscovery; private double energy = 25; private int entityCount = 0; private long charge = 0; @@ -92,12 +93,14 @@ public class IrisWorldManager extends EngineAssignedWorldManager { clw = null; looper = null; chunkUpdater = null; + chunkDiscovery = null; id = -1; } public IrisWorldManager(Engine engine) { super(engine); chunkUpdater = new ChronoLatch(3000); + chunkDiscovery = new ChronoLatch(5000); cln = new ChronoLatch(60000); cl = new ChronoLatch(3000); ecl = new ChronoLatch(250); @@ -128,6 +131,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager { updateChunks(); } + if (chunkDiscovery.flip()) { + discoverChunks(); + } + if (getDimension().isInfiniteEnergy()) { energy += 1000; @@ -174,6 +181,19 @@ public class IrisWorldManager extends EngineAssignedWorldManager { looper.start(); } + private void discoverChunks() { + var mantle = getEngine().getMantle().getMantle(); + for (Player i : getEngine().getWorld().realWorld().getPlayers()) { + int r = 1; + + for (int x = -r; x <= r; x++) { + for (int z = -r; z <= r; z++) { + mantle.getChunk(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true); + } + } + } + } + private void updateChunks() { for (Player i : getEngine().getWorld().realWorld().getPlayers()) { int r = 1; diff --git a/core/src/main/java/com/volmit/iris/engine/framework/ListFunction.java b/core/src/main/java/com/volmit/iris/engine/framework/ListFunction.java new file mode 100644 index 000000000..2d2c8bfdb --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/framework/ListFunction.java @@ -0,0 +1,8 @@ +package com.volmit.iris.engine.framework; + +import java.util.function.Function; + +public interface ListFunction extends Function { + String key(); + String fancyName(); +} diff --git a/core/src/main/java/com/volmit/iris/engine/framework/ResultLocator.java b/core/src/main/java/com/volmit/iris/engine/framework/ResultLocator.java new file mode 100644 index 000000000..93d698347 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/framework/ResultLocator.java @@ -0,0 +1,121 @@ +package com.volmit.iris.engine.framework; + +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisObject; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.math.Position2; +import com.volmit.iris.util.math.Spiraler; +import com.volmit.iris.util.parallel.BurstExecutor; +import com.volmit.iris.util.parallel.MultiBurst; +import com.volmit.iris.util.scheduling.PrecisionStopwatch; +import org.apache.commons.lang3.function.TriFunction; + +import java.util.Collection; +import java.util.Set; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +@FunctionalInterface +public interface ResultLocator { + static void cancelSearch() { + if (LocatorCanceller.cancel != null) { + LocatorCanceller.cancel.run(); + LocatorCanceller.cancel = null; + } + } + + static ResultLocator locateStructure(Collection keys) { + return (e, pos) -> { + var structure = e.getStructureAt(pos.getX(), pos.getZ()); + return structure != null && keys.contains(structure.getLoadKey()) ? structure : null; + }; + } + + static ResultLocator locateObject(Collection keys) { + return (e, pos) -> { + Set objects = e.getObjectsAt(pos.getX(), pos.getZ()); + for (String object : objects) { + if (!keys.contains(object)) continue; + return e.getData().getObjectLoader().load(object); + } + return null; + }; + } + + T find(Engine e, Position2 chunkPos); + + default ResultLocator then(TriFunction filter) { + return (e, pos) -> { + var t = find(e, pos); + return t != null ? filter.apply(e, pos, t) : null; + }; + } + + default Future> find(Engine engine, Position2 pos, long timeout, Consumer checks, boolean cancelable) throws WrongEngineBroException { + if (engine.isClosed()) { + throw new WrongEngineBroException(); + } + + cancelSearch(); + + return MultiBurst.burst.completeValue(() -> { + int tc = IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()) * 17; + MultiBurst burst = MultiBurst.burst; + AtomicBoolean found = new AtomicBoolean(false); + AtomicReference> foundObj = new AtomicReference<>(); + Position2 cursor = pos; + AtomicInteger searched = new AtomicInteger(); + AtomicBoolean stop = new AtomicBoolean(false); + PrecisionStopwatch px = PrecisionStopwatch.start(); + if (cancelable) LocatorCanceller.cancel = () -> stop.set(true); + AtomicReference next = new AtomicReference<>(cursor); + Spiraler s = new Spiraler(100000, 100000, (x, z) -> next.set(new Position2(x, z))); + s.setOffset(cursor.getX(), cursor.getZ()); + s.next(); + while (!found.get() && !stop.get() && px.getMilliseconds() < timeout) { + BurstExecutor e = burst.burst(tc); + + for (int i = 0; i < tc; i++) { + Position2 p = next.get(); + s.next(); + e.queue(() -> { + var o = find(engine, p); + if (o != null) { + if (foundObj.get() == null) { + foundObj.set(new Result<>(o, p)); + } + + found.set(true); + } + searched.incrementAndGet(); + }); + } + + e.complete(); + checks.accept(searched.get()); + } + + LocatorCanceller.cancel = null; + + if (found.get() && foundObj.get() != null) { + return foundObj.get(); + } + + return null; + }); + } + + record Result(T obj, Position2 pos) { + public int getBlockX() { + return (pos.getX() << 4) + 8; + } + + public int getBlockZ() { + return (pos.getZ() << 4) + 8; + } + } +} diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java index 7206b2a3d..fae6ee23b 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java @@ -300,10 +300,8 @@ public class IrisDimension extends IrisRegistrant { private IrisMaterialPalette rockPalette = new IrisMaterialPalette().qclear().qadd("stone"); @Desc("The palette of blocks for 'water'") private IrisMaterialPalette fluidPalette = new IrisMaterialPalette().qclear().qadd("water"); - @Desc("Remove cartographers so they do not crash the server (Iris worlds only)") - private boolean removeCartographersDueToCrash = true; - @Desc("Notify players of cancelled cartographer villager in this radius in blocks (set to -1 to disable, -2 for everyone)") - private int notifyPlayersOfCartographerCancelledRadius = 30; + @Desc("Prevent cartographers to generate explorer maps (Iris worlds only)\nONLY TOUCH IF YOUR SERVER CRASHES WHILE GENERATING EXPLORER MAPS") + private boolean disableExplorerMaps = false; @Desc("Collection of ores to be generated") @ArrayType(type = IrisOreGenerator.class, min = 1) private KList ores = new KList<>(); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java index 9d6d28506..d4a577101 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java @@ -69,6 +69,10 @@ public class IrisJigsawStructure extends IrisRegistrant { @Desc("Set to true to prevent rotating the initial structure piece") private boolean disableInitialRotation = false; + @RegistryListFunction(StructureKeyFunction.class) + @Desc("The minecraft key to use when creating treasure maps") + private String structureKey = null; + private transient AtomicCache maxDimension = new AtomicCache<>(); private void loadPool(String p, KList pools, KList pieces) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListFunction.java b/core/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListFunction.java new file mode 100644 index 000000000..e437ebfae --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListFunction.java @@ -0,0 +1,17 @@ +package com.volmit.iris.engine.object.annotations; + +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.engine.framework.ListFunction; +import com.volmit.iris.util.collection.KList; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListFunction { + Class>> value(); +} diff --git a/core/src/main/java/com/volmit/iris/engine/object/annotations/StructureKeyFunction.java b/core/src/main/java/com/volmit/iris/engine/object/annotations/StructureKeyFunction.java new file mode 100644 index 000000000..5ab656cc8 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/annotations/StructureKeyFunction.java @@ -0,0 +1,23 @@ +package com.volmit.iris.engine.object.annotations; + +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.engine.framework.ListFunction; +import com.volmit.iris.util.collection.KList; + +public class StructureKeyFunction implements ListFunction> { + @Override + public String key() { + return "structure-key"; + } + + @Override + public String fancyName() { + return "Structure Key"; + } + + @Override + public KList apply(IrisData irisData) { + return INMS.get().getStructureKeys(); + } +} 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 6bb5f1e6f..fc2b9762f 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 @@ -34,7 +34,8 @@ public enum MantleFlag { PLANNED, ETCHED, TILE, - CUSTOM; + CUSTOM, + DISCOVERED; static StateList getStateList() { return new StateList(MantleFlag.values()); diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/IrisChunkGenerator.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/IrisChunkGenerator.java new file mode 100644 index 000000000..040d588df --- /dev/null +++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/IrisChunkGenerator.java @@ -0,0 +1,236 @@ +package com.volmit.iris.core.nms.v1_19_R1; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import net.minecraft.core.*; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R1.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registry.STRUCTURE_REGISTRY).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = new ResourceLocation(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registry.STRUCTURE_REGISTRY, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registry.STRUCTURE_REGISTRY, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected Codec codec() { + return Codec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager, long i) { + delegate.createStructures(iregistrycustom, randomstate, structuremanager, ichunkaccess, structuretemplatemanager, i); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} 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 058e4046d..4028d8102 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 @@ -13,7 +13,9 @@ import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.tags.TagKey; import net.minecraft.world.level.LevelReader; import org.bukkit.*; import org.bukkit.block.Biome; @@ -473,23 +475,9 @@ public class NMSBinding implements INMSBinding { } } - public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { - CraftDolphin cd = (CraftDolphin)dolphin; - cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); - cd.getHandle().setGotFish(true); - } - - public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { - ServerLevel serverLevel = ((CraftWorld)world).getHandle(); - Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + public void inject(long seed, Engine engine, World world) { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world); } public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { @@ -544,6 +532,23 @@ public class NMSBinding implements INMSBinding { return new Color(rgba, true); } + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registry.STRUCTURE_REGISTRY).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } + 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/IrisChunkGenerator.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/IrisChunkGenerator.java new file mode 100644 index 000000000..9bb31ef8c --- /dev/null +++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/IrisChunkGenerator.java @@ -0,0 +1,241 @@ +package com.volmit.iris.core.nms.v1_19_R2; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = new ResourceLocation(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected Codec codec() { + return Codec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} 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 f5f778002..75ab7732e 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 @@ -13,7 +13,9 @@ import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.tags.TagKey; import net.minecraft.world.level.LevelReader; import org.bukkit.*; import org.bukkit.block.Biome; @@ -474,23 +476,9 @@ public class NMSBinding implements INMSBinding { } } - public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { - CraftDolphin cd = (CraftDolphin)dolphin; - cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); - cd.getHandle().setGotFish(true); - } - - public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { - ServerLevel serverLevel = ((CraftWorld)world).getHandle(); - Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + public void inject(long seed, Engine engine, World world) { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world); } @@ -546,6 +534,23 @@ public class NMSBinding implements INMSBinding { return new Color(rgba, true); } + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } + 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/IrisChunkGenerator.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/IrisChunkGenerator.java new file mode 100644 index 000000000..358ef9829 --- /dev/null +++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/IrisChunkGenerator.java @@ -0,0 +1,241 @@ +package com.volmit.iris.core.nms.v1_19_R3; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = new ResourceLocation(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected Codec codec() { + return Codec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} 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 0cbf158bd..5fd9e2507 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 @@ -13,7 +13,9 @@ import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.tags.TagKey; import net.minecraft.world.level.LevelReader; import org.bukkit.*; import org.bukkit.block.Biome; @@ -482,17 +484,9 @@ public class NMSBinding implements INMSBinding { cd.getHandle().setGotFish(true); } - public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { - ServerLevel serverLevel = ((CraftWorld)world).getHandle(); - Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + public void inject(long seed, Engine engine, World world) { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world); } public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { @@ -550,6 +544,23 @@ public class NMSBinding implements INMSBinding { return new Color(rgba, true); } + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } + 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/IrisChunkGenerator.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/IrisChunkGenerator.java new file mode 100644 index 000000000..f415bbe69 --- /dev/null +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/IrisChunkGenerator.java @@ -0,0 +1,241 @@ +package com.volmit.iris.core.nms.v1_20_R1; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R1.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = new ResourceLocation(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected Codec codec() { + return Codec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} 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 cb8323009..97d1175d6 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 @@ -1,6 +1,7 @@ package com.volmit.iris.core.nms.v1_20_R1; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; @@ -27,6 +28,7 @@ import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.BiomeSource; @@ -478,12 +480,6 @@ public class NMSBinding implements INMSBinding { } } - public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { - CraftDolphin cd = (CraftDolphin)dolphin; - cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); - cd.getHandle().setGotFish(true); - } - public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { Field[] fields = net.minecraft.world.entity.EntityType.class.getDeclaredFields(); for (Field field : fields) { @@ -512,17 +508,9 @@ public class NMSBinding implements INMSBinding { 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(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + public void inject(long seed, Engine engine, World world) { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world); } @Override @@ -549,6 +537,23 @@ public class NMSBinding implements INMSBinding { return new Color(rgba, true); } + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/IrisChunkGenerator.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/IrisChunkGenerator.java new file mode 100644 index 000000000..27afcb0f7 --- /dev/null +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/IrisChunkGenerator.java @@ -0,0 +1,241 @@ +package com.volmit.iris.core.nms.v1_20_R2; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = new ResourceLocation(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected Codec codec() { + return Codec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} 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 9d073f4a7..187af289a 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 @@ -13,7 +13,9 @@ import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.tags.TagKey; import net.minecraft.world.level.LevelReader; import org.bukkit.*; import org.bukkit.block.Biome; @@ -476,23 +478,9 @@ public class NMSBinding implements INMSBinding { } } - public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { - CraftDolphin cd = (CraftDolphin)dolphin; - cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); - cd.getHandle().setGotFish(true); - } - - public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { - ServerLevel serverLevel = ((CraftWorld)world).getHandle(); - Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + public void inject(long seed, Engine engine, World world) { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world); } public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { @@ -547,6 +535,23 @@ public class NMSBinding implements INMSBinding { return new Color(rgba, true); } + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } + 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/IrisChunkGenerator.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/IrisChunkGenerator.java new file mode 100644 index 000000000..e61cbae71 --- /dev/null +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/IrisChunkGenerator.java @@ -0,0 +1,244 @@ +package com.volmit.iris.core.nms.v1_20_R3; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import com.volmit.iris.util.scheduling.S; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.StructureTags; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.item.EnderEyeItem; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = new ResourceLocation(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected Codec codec() { + return Codec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} 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 7334bb040..3b153a5dc 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 @@ -13,7 +13,9 @@ import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.tags.TagKey; import net.minecraft.world.level.LevelReader; import org.bukkit.*; import org.bukkit.block.Biome; @@ -476,23 +478,9 @@ public class NMSBinding implements INMSBinding { } } - public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { - CraftDolphin cd = (CraftDolphin)dolphin; - cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); - cd.getHandle().setGotFish(true); - } - - public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { - ServerLevel serverLevel = ((CraftWorld)world).getHandle(); - Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + public void inject(long seed, Engine engine, World world) { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world); } public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { @@ -548,6 +536,23 @@ public class NMSBinding implements INMSBinding { return new Color(rgba, true); } + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/IrisChunkGenerator.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/IrisChunkGenerator.java new file mode 100644 index 000000000..54382df77 --- /dev/null +++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/IrisChunkGenerator.java @@ -0,0 +1,239 @@ +package com.volmit.iris.core.nms.v1_20_R4; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.MapCodec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R4.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.*; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = new ResourceLocation(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected MapCodec codec() { + return MapCodec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java index 4b407ef18..2cf09de92 100644 --- a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java +++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java @@ -14,9 +14,12 @@ import java.util.Optional; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import net.minecraft.core.component.DataComponents; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.chunk.status.ChunkStatus; @@ -28,6 +31,7 @@ import org.bukkit.craftbukkit.v1_20_R4.CraftServer; import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R4.entity.CraftDolphin; +import org.bukkit.craftbukkit.v1_20_R4.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey; import org.bukkit.entity.Dolphin; @@ -64,15 +68,12 @@ import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.block.Block; 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 sun.misc.Unsafe; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -480,23 +481,9 @@ public class NMSBinding implements INMSBinding { } } - public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { - CraftDolphin cd = (CraftDolphin)dolphin; - cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); - cd.getHandle().setGotFish(true); - } - - public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { - ServerLevel serverLevel = ((CraftWorld)world).getHandle(); - Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + public void inject(long seed, Engine engine, World world) { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world); } public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { @@ -585,4 +572,21 @@ public class NMSBinding implements INMSBinding { if (radius == null) throw new IllegalStateException("GameRule.SPAWN_CHUNK_RADIUS is null!"); return (int) Math.pow(2 * radius + 1, 2); } + + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } } diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/IrisChunkGenerator.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/IrisChunkGenerator.java new file mode 100644 index 000000000..872daac16 --- /dev/null +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/IrisChunkGenerator.java @@ -0,0 +1,240 @@ +package com.volmit.iris.core.nms.v1_21_R1; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.MapCodec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.NoiseColumn; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R1.generator.CustomChunkGenerator; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private final ChunkGenerator delegate; + private final Engine engine; + private final BiomeSource biomeSource; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), delegate, null); + this.delegate = delegate; + this.engine = engine; + this.biomeSource = new CustomBiomeSource(seed, engine, world); + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = ResourceLocation.parse(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.getTag(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected MapCodec codec() { + return MapCodec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public BiomeSource getBiomeSource() { + return biomeSource; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features); + } + + @Override + public CompletableFuture fillFromNoise(Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } +} diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 1455b09e1..422131fbe 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -14,10 +14,12 @@ import java.util.Optional; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import net.minecraft.core.component.DataComponents; import net.minecraft.server.level.ChunkMap; +import net.minecraft.tags.TagKey; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.chunk.status.ChunkStatus; @@ -482,26 +484,17 @@ public class NMSBinding implements INMSBinding { } } - public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { - CraftDolphin cd = (CraftDolphin)dolphin; - cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); - cd.getHandle().setGotFish(true); - } - public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class); worldGenContextField.setAccessible(true); var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap); - Class clazz = worldGenContext.generator().getClass(); - Field biomeSource = getField(clazz, BiomeSource.class); - biomeSource.setAccessible(true); - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - Unsafe unsafe = (Unsafe)unsafeField.get(null); - CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); - unsafe.putObject(biomeSource.get(worldGenContext.generator()), unsafe.objectFieldOffset(biomeSource), customBiomeSource); - biomeSource.set(worldGenContext.generator(), customBiomeSource); + + var newContext = new WorldGenContext( + worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world), + worldGenContext.structureManager(), worldGenContext.lightEngine(), worldGenContext.mainThreadMailBox()); + + worldGenContextField.set(chunkMap, newContext); } public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { @@ -590,4 +583,21 @@ public class NMSBinding implements INMSBinding { if (radius == null) throw new IllegalStateException("GameRule.SPAWN_CHUNK_RADIUS is null!"); return (int) Math.pow(2 * radius + 1, 2); } + + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().registry(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(Pair::getFirst) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } } From 288bead792dafd274d2f12c09fa9c520c983d968 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 11 Aug 2024 12:03:47 +0200 Subject: [PATCH 02/14] fix stronghold locate using wrong seed --- core/src/main/java/com/volmit/iris/engine/framework/Engine.java | 2 +- .../iris/engine/framework/EngineAssignedWorldManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 13e1d2b6a..4a9880834 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 @@ -840,7 +840,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) { if (s.getLoadKey().equals(getDimension().getStronghold())) { - KList p = getDimension().getStrongholds(getSeedManager().getSpawn()); + KList p = getDimension().getStrongholds(getSeedManager().getMantle()); if (p.isEmpty()) { player.sendMessage(C.GOLD + "No strongholds in world."); diff --git a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java index 5219c5e6f..5f801033f 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java @@ -110,7 +110,7 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent return; } - KList positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getSpawn()); + KList positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getMantle()); if (positions.isEmpty()) { return; } From b6dc9341987fcc499cfb107b60edc588151dc532 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 15 Aug 2024 17:12:56 +0200 Subject: [PATCH 03/14] fix getEngineData NullPointer --- .../com/volmit/iris/engine/IrisEngine.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index 0499050d3..54c9ce912 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -251,39 +251,44 @@ public class IrisEngine implements Engine { @Override public IrisEngineData getEngineData() { - var ret = engineData.aquire(() -> { + return engineData.aquire(() -> { //TODO: Method this file File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json"); + IrisEngineData data = null; - if (!f.exists()) { + if (f.exists()) { try { - f.getParentFile().mkdirs(); - IrisEngineData data = new IrisEngineData(); - data.getStatistics().setVersion(Iris.instance.getIrisVersion()); - data.getStatistics().setMCVersion(Iris.instance.getMCVersion()); - data.getStatistics().setUpgradedVersion(Iris.instance.getIrisVersion()); - if (data.getStatistics().getVersion() == -1 || data.getStatistics().getMCVersion() == -1 ) { - Iris.error("Failed to setup Engine Data!"); + data = new Gson().fromJson(IO.readAll(f), IrisEngineData.class); + if (data == null) { + Iris.error("Failed to read Engine Data! Corrupted File? recreating..."); } - IO.writeAll(f, new Gson().toJson(data)); } catch (IOException e) { e.printStackTrace(); } } - try { - return new Gson().fromJson(IO.readAll(f), IrisEngineData.class); - } catch (Throwable e) { - e.printStackTrace(); + if (data == null) { + data = new IrisEngineData(); + data.getStatistics().setVersion(Iris.instance.getIrisVersion()); + data.getStatistics().setMCVersion(Iris.instance.getMCVersion()); + data.getStatistics().setUpgradedVersion(Iris.instance.getIrisVersion()); + if (data.getStatistics().getVersion() == -1 || data.getStatistics().getMCVersion() == -1 ) { + Iris.error("Failed to setup Engine Data!"); + } + + if (f.getParentFile().exists() || f.getParentFile().mkdirs()) { + try { + IO.writeAll(f, new Gson().toJson(data)); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + Iris.error("Failed to setup Engine Data!"); + } } - return new IrisEngineData(); + return data; }); - if (ret == null) { - Iris.error("Failed to load Engine Data! (How did this happen?)"); - return new IrisEngineData(); - } - return ret; } @Override From b468478fcbcead3afe4f5a62e6c78d6e8bf08f6a Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 15 Aug 2024 18:00:18 +0200 Subject: [PATCH 04/14] separate tile data into its own option in IrisBlockData --- .../java/com/volmit/iris/engine/object/IrisBlockData.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java index 722d52ddc..81a497eed 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java @@ -62,6 +62,8 @@ public class IrisBlockData extends IrisRegistrant { private IrisBlockData backup = null; @Desc("Optional properties for this block data such as 'waterlogged': true") private KMap data = new KMap<>(); + @Desc("Optional tile data for this block data") + private KMap tileData = new KMap<>(); public IrisBlockData(String b) { this.block = b; @@ -202,7 +204,7 @@ public class IrisBlockData extends IrisRegistrant { var type = getBlockData(data).getMaterial(); if (!INMS.get().hasTile(type)) return null; - return new TileData().setMaterial(type).setProperties(this.data); + return new TileData().setMaterial(type).setProperties(this.tileData); } private String keyify(String dat) { From 25b41fe62cb032b07e12591103245ebeca0cda94 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 15 Aug 2024 18:42:23 +0200 Subject: [PATCH 05/14] add 1.21.1 support --- core/src/main/java/com/volmit/iris/core/nms/INMS.java | 3 ++- .../src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMS.java b/core/src/main/java/com/volmit/iris/core/nms/INMS.java index 36b26dcb9..741018d43 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMS.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMS.java @@ -29,7 +29,8 @@ public class INMS { private static final Map REVISION = Map.of( "1.20.5", "v1_20_R4", "1.20.6", "v1_20_R4", - "1.21", "v1_21_R1" + "1.21", "v1_21_R1", + "1.21.1", "v1_21_R1" ); //@done private static final INMSBinding binding = bind(); diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java b/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java index 659c02bdd..a10152651 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java @@ -37,7 +37,7 @@ public class UtilsSFG { } if (ServerBootSFG.unsuportedversion) { Iris.safeguard(C.RED + "Server Version"); - Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.20.6"); + Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.21.1"); } if (!ServerBootSFG.passedserversoftware) { Iris.safeguard(C.YELLOW + "Unsupported Server Software"); From d0688782b1f122e4495894315f932257d2d7467d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 15 Aug 2024 18:47:27 +0200 Subject: [PATCH 06/14] fix getEngineData NullPointer --- .../com/volmit/iris/engine/IrisEngine.java | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index e1ea0a00e..54c9ce912 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -254,30 +254,40 @@ public class IrisEngine implements Engine { return engineData.aquire(() -> { //TODO: Method this file File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json"); + IrisEngineData data = null; - if (!f.exists()) { + if (f.exists()) { try { - f.getParentFile().mkdirs(); - IrisEngineData data = new IrisEngineData(); - data.getStatistics().setVersion(Iris.instance.getIrisVersion()); - data.getStatistics().setMCVersion(Iris.instance.getMCVersion()); - data.getStatistics().setUpgradedVersion(Iris.instance.getIrisVersion()); - if (data.getStatistics().getVersion() == -1 || data.getStatistics().getMCVersion() == -1 ) { - Iris.error("Failed to setup Engine Data!"); + data = new Gson().fromJson(IO.readAll(f), IrisEngineData.class); + if (data == null) { + Iris.error("Failed to read Engine Data! Corrupted File? recreating..."); } - IO.writeAll(f, new Gson().toJson(data)); } catch (IOException e) { e.printStackTrace(); } } - try { - return new Gson().fromJson(IO.readAll(f), IrisEngineData.class); - } catch (Throwable e) { - e.printStackTrace(); + if (data == null) { + data = new IrisEngineData(); + data.getStatistics().setVersion(Iris.instance.getIrisVersion()); + data.getStatistics().setMCVersion(Iris.instance.getMCVersion()); + data.getStatistics().setUpgradedVersion(Iris.instance.getIrisVersion()); + if (data.getStatistics().getVersion() == -1 || data.getStatistics().getMCVersion() == -1 ) { + Iris.error("Failed to setup Engine Data!"); + } + + if (f.getParentFile().exists() || f.getParentFile().mkdirs()) { + try { + IO.writeAll(f, new Gson().toJson(data)); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + Iris.error("Failed to setup Engine Data!"); + } } - return new IrisEngineData(); + return data; }); } From c3ac41f8941533ed8029395bc185efb86dfc5622 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Thu, 15 Aug 2024 12:58:01 -0400 Subject: [PATCH 07/14] V+ lol --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cec0f1ee0..62e4c9025 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ plugins { id "de.undercouch.download" version "5.0.1" } -version '3.4.1-1.19.2-1.21' +version '3.4.1-1.19.2-1.21.1' // ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED // ======================== WINDOWS ============================= From fc793592f7d55ce569be61ed0aabfbff3c8fcac3 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 17 Aug 2024 00:45:58 +0200 Subject: [PATCH 08/14] fix old object loading --- .../iris/core/commands/CommandDeveloper.java | 18 +++ .../core/loader/ObjectResourceLoader.java | 2 +- .../iris/engine/mantle/EngineMantle.java | 2 +- .../volmit/iris/engine/object/IrisObject.java | 4 +- .../iris/engine/object/LegacyTileData.java | 139 ++++++++++++++++++ .../volmit/iris/engine/object/TileData.java | 23 ++- .../iris/util/mantle/TectonicPlate.java | 4 +- .../volmit/iris/util/matter/TileWrapper.java | 27 ++++ .../volmit/iris/util/matter/WorldMatter.java | 6 +- .../iris/util/matter/slices/TileMatter.java | 19 +-- 10 files changed, 222 insertions(+), 22 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java create mode 100644 core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index da46c93f4..81473b45f 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -47,6 +47,7 @@ import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.nbt.mca.MCAFile; import com.volmit.iris.util.nbt.mca.MCAUtil; +import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.VolmitSender; import io.lumine.mythic.bukkit.adapters.BukkitEntity; import net.jpountz.lz4.LZ4BlockInputStream; @@ -206,6 +207,23 @@ public class CommandDeveloper implements DecreeExecutor { } + @Decree + public void objects(@Param(defaultValue = "overworld") IrisDimension dimension) { + var loader = dimension.getLoader().getObjectLoader(); + var sender = sender(); + var keys = loader.getPossibleKeys(); + var burst = MultiBurst.burst.burst(keys.length); + AtomicInteger failed = new AtomicInteger(); + for (String key : keys) { + burst.queue(() -> { + if (loader.load(key) == null) + failed.incrementAndGet(); + }); + } + burst.complete(); + sender.sendMessage(C.RED + "Failed to load " + failed.get() + " of " + keys.length + " objects"); + } + @Decree(description = "Test", aliases = {"ip"}) public void network() { try { diff --git a/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java b/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java index 37f3f43b5..3fa92bc46 100644 --- a/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java +++ b/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java @@ -50,10 +50,10 @@ public class ObjectResourceLoader extends ResourceLoader { try { PrecisionStopwatch p = PrecisionStopwatch.start(); IrisObject t = new IrisObject(0, 0, 0); - t.read(j); t.setLoadKey(name); t.setLoader(manager); t.setLoadFile(j); + t.read(j); logLoad(j, t); tlt.addAndGet(p.getMilliseconds()); return t; diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java index 4b6e334c6..d8969636b 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -108,7 +108,7 @@ public interface EngineMantle extends IObjectPlacer { @Override default void setTile(int x, int y, int z, TileData d) { - getMantle().set(x, y, z, d); + getMantle().set(x, y, z, new TileWrapper(d)); } @Override 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 bed5dac35..0866ee63f 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 @@ -385,14 +385,14 @@ public class IrisObject extends IrisRegistrant { } public void read(File file) throws IOException { - FileInputStream fin = new FileInputStream(file); + var fin = new BufferedInputStream(new FileInputStream(file)); try { read(fin); fin.close(); } catch (Throwable e) { Iris.reportError(e); fin.close(); - fin = new FileInputStream(file); + fin = new BufferedInputStream(new FileInputStream(file)); readLegacy(fin); fin.close(); } diff --git a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java new file mode 100644 index 000000000..255a0b4d0 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java @@ -0,0 +1,139 @@ +package com.volmit.iris.engine.object; + +import com.volmit.iris.Iris; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.scheduling.J; +import org.bukkit.DyeColor; +import org.bukkit.block.*; +import org.bukkit.block.banner.Pattern; +import org.bukkit.block.banner.PatternType; +import org.bukkit.entity.EntityType; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class LegacyTileData extends TileData { + private static final Map legacy = Map.of( + (short) 0, new SignHandler(), + (short) 1, new SpawnerHandler(), + (short) 2, new BannerHandler()); + private final short id; + private final KList properties; + + public LegacyTileData(DataInputStream in) throws IOException { + id = in.readShort(); + var handler = legacy.get(id); + if (handler == null) + throw new IOException("Unknown tile type: " + id); + properties = handler.read(in); + } + + @Override + public void toBukkit(Block block) { + var handler = legacy.get(id); + J.s(() -> handler.toBukkit(properties, block)); + } + + @Override + public void toBinary(DataOutputStream out) throws IOException { + out.writeShort(id); + legacy.get(id).toBinary(properties, out); + } + + private interface Handler { + KList read(DataInputStream in) throws IOException; + void toBinary(KList list, DataOutputStream out) throws IOException; + void toBukkit(KList list, Block block); + } + + private static class SignHandler implements Handler { + @Override + public KList read(DataInputStream in) throws IOException { + return new KList<>() + .qadd(in.readUTF()) + .qadd(in.readUTF()) + .qadd(in.readUTF()) + .qadd(in.readUTF()) + .qadd(DyeColor.values()[in.readByte()]); + } + + @Override + public void toBinary(KList list, DataOutputStream out) throws IOException { + out.writeUTF((String) list.get(0)); + out.writeUTF((String) list.get(1)); + out.writeUTF((String) list.get(2)); + out.writeUTF((String) list.get(3)); + out.writeByte(((DyeColor) list.get(4)).ordinal()); + } + + @Override + public void toBukkit(KList list, Block block) { + Sign sign = (Sign) block.getState(); + sign.setLine(0, (String) list.get(0)); + sign.setLine(1, (String) list.get(1)); + sign.setLine(2, (String) list.get(2)); + sign.setLine(3, (String) list.get(3)); + sign.setColor((DyeColor) list.get(4)); + sign.update(); + } + } + + private static class SpawnerHandler implements Handler { + @Override + public KList read(DataInputStream in) throws IOException { + return new KList<>().qadd(EntityType.values()[in.readShort()]); + } + + @Override + public void toBinary(KList list, DataOutputStream out) throws IOException { + out.writeShort(((EntityType) list.get(0)).ordinal()); + } + + @Override + public void toBukkit(KList list, Block block) { + CreatureSpawner spawner = (CreatureSpawner) block.getState(); + spawner.setSpawnedType((EntityType) list.get(0)); + spawner.update(); + } + } + + private static class BannerHandler implements Handler { + @Override + public KList read(DataInputStream in) throws IOException { + KList list = new KList<>(); + list.add(DyeColor.values()[in.readByte()]); + int listSize = in.readByte(); + var patterns = new KList<>(); + + for (int i = 0; i < listSize; i++) { + DyeColor color = DyeColor.values()[in.readByte()]; + PatternType type = PatternType.values()[in.readByte()]; + patterns.add(new Pattern(color, type)); + } + + list.add(patterns); + return list; + } + + @Override + public void toBinary(KList list, DataOutputStream out) throws IOException { + out.writeByte(((DyeColor) list.get(0)).ordinal()); + out.writeByte(((List) list.get(1)).size()); + for (Pattern i : (List) list.get(1)) { + out.writeByte(i.getColor().ordinal()); + out.writeByte(i.getPattern().ordinal()); + } + } + + @Override + public void toBukkit(KList list, Block block) { + Banner banner = (Banner) block.getState(); + banner.setBaseColor((DyeColor) list.get(0)); + banner.setPatterns((List) list.get(1)); + banner.update(); + } + } +} diff --git a/core/src/main/java/com/volmit/iris/engine/object/TileData.java b/core/src/main/java/com/volmit/iris/engine/object/TileData.java index a8d94f7da..9bab31df8 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/TileData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/TileData.java @@ -31,6 +31,7 @@ import org.bukkit.block.BlockState; import org.bukkit.block.TileState; import org.bukkit.block.data.BlockData; +import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -57,10 +58,24 @@ public class TileData implements Cloneable { } public static TileData read(DataInputStream in) throws IOException { - TileData d = new TileData(); - d.material = Material.matchMaterial(in.readUTF()); - d.properties = gson.fromJson(in.readUTF(), KMap.class); - return d; + if (!in.markSupported()) + throw new IOException("Mark not supported"); + in.mark(Integer.MAX_VALUE); + try { + TileData d = new TileData(); + var material = in.readUTF(); + d.material = Material.matchMaterial(material); + if (d.material == null) throw new IOException("Unknown material: " + material); + var properties = in.readUTF(); + d.properties = gson.fromJson(properties, KMap.class); + if (d.properties == null) throw new IOException("Invalid properties: " + properties); + return d; + } catch (Throwable e) { + in.reset(); + return new LegacyTileData(in); + } finally { + in.mark(0); + } } public boolean isApplicable(BlockData data) { diff --git a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java index 6f3cd0f35..044e1f745 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java @@ -86,10 +86,10 @@ public class TectonicPlate { DataInputStream din; if (file.getName().endsWith("ttp.lz4b")) { LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin); - din = new DataInputStream(lz4); + din = new DataInputStream(new BufferedInputStream(lz4)); } else { GZIPInputStream gzi = new GZIPInputStream(fin); - din = new DataInputStream(gzi); + din = new DataInputStream(new BufferedInputStream(gzi)); } TectonicPlate p = new TectonicPlate(worldHeight, din); din.close(); diff --git a/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java b/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java new file mode 100644 index 000000000..0fa14eab6 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java @@ -0,0 +1,27 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2024 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.util.matter; + +import com.volmit.iris.engine.object.TileData; +import lombok.Data; + +@Data +public class TileWrapper { + private final TileData data; +} diff --git a/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java b/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java index 0061d7f05..40ff187d0 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java @@ -34,8 +34,8 @@ public class WorldMatter { matter.slice(MatterEntityGroup.class).writeInto(at); } - if (matter.hasSlice(TileData.class)) { - matter.slice(TileData.class).writeInto(at); + if (matter.hasSlice(TileWrapper.class)) { + matter.slice(TileWrapper.class).writeInto(at); } } @@ -46,7 +46,7 @@ public class WorldMatter { s.getHeader().setAuthor(author); s.slice(BlockData.class).readFrom(c.getLowerNE()); s.slice(MatterEntityGroup.class).readFrom(c.getLowerNE()); - s.slice(TileData.class).readFrom(c.getLowerNE()); + s.slice(TileWrapper.class).readFrom(c.getLowerNE()); s.trimSlices(); return s; diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java b/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java index 47a1b9e1d..25e46a831 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java @@ -21,6 +21,7 @@ package com.volmit.iris.util.matter.slices; import com.volmit.iris.engine.object.TileData; import com.volmit.iris.util.data.palette.Palette; import com.volmit.iris.util.matter.Sliced; +import com.volmit.iris.util.matter.TileWrapper; import org.bukkit.Location; import org.bukkit.World; @@ -30,28 +31,28 @@ import java.io.IOException; @SuppressWarnings("rawtypes") @Sliced -public class TileMatter extends RawMatter { +public class TileMatter extends RawMatter { public TileMatter() { this(1, 1, 1); } public TileMatter(int width, int height, int depth) { - super(width, height, depth, TileData.class); - registerWriter(World.class, (w, d, x, y, z) -> TileData.setTileState(w.getBlockAt(new Location(w, x, y, z)), d)); - registerReader(World.class, (w, x, y, z) -> TileData.getTileState(w.getBlockAt(new Location(w, x, y, z)))); + super(width, height, depth, TileWrapper.class); + registerWriter(World.class, (w, d, x, y, z) -> TileData.setTileState(w.getBlockAt(new Location(w, x, y, z)), d.getData())); + registerReader(World.class, (w, x, y, z) -> new TileWrapper(TileData.getTileState(w.getBlockAt(new Location(w, x, y, z))))); } @Override - public Palette getGlobalPalette() { + public Palette getGlobalPalette() { return null; } - public void writeNode(TileData b, DataOutputStream dos) throws IOException { - b.toBinary(dos); + public void writeNode(TileWrapper b, DataOutputStream dos) throws IOException { + b.getData().toBinary(dos); } - public TileData readNode(DataInputStream din) throws IOException { - return TileData.read(din); + public TileWrapper readNode(DataInputStream din) throws IOException { + return new TileWrapper(TileData.read(din)); } } From dfe1cce6de4de82ed89bb7056b9ccc56619165bf Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 17 Aug 2024 11:59:28 +0200 Subject: [PATCH 09/14] restructure LegacyTileData --- .../iris/engine/object/LegacyTileData.java | 123 +++++++++--------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java index 255a0b4d0..105f818aa 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java @@ -1,8 +1,8 @@ package com.volmit.iris.engine.object; -import com.volmit.iris.Iris; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.scheduling.J; +import org.apache.commons.io.function.IOFunction; import org.bukkit.DyeColor; import org.bukkit.block.*; import org.bukkit.block.banner.Pattern; @@ -12,127 +12,126 @@ import org.bukkit.entity.EntityType; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.List; import java.util.Map; public class LegacyTileData extends TileData { - private static final Map legacy = Map.of( - (short) 0, new SignHandler(), - (short) 1, new SpawnerHandler(), - (short) 2, new BannerHandler()); - private final short id; - private final KList properties; + private static final Map> legacy = Map.of( + 0, SignHandler::new, + 1, SpawnerHandler::new, + 2, BannerHandler::new); + private final int id; + private final Handler handler; public LegacyTileData(DataInputStream in) throws IOException { id = in.readShort(); - var handler = legacy.get(id); - if (handler == null) + var factory = legacy.get(id); + if (factory == null) throw new IOException("Unknown tile type: " + id); - properties = handler.read(in); + handler = factory.apply(in); } @Override public void toBukkit(Block block) { - var handler = legacy.get(id); - J.s(() -> handler.toBukkit(properties, block)); + J.s(() -> handler.toBukkit(block)); } @Override public void toBinary(DataOutputStream out) throws IOException { out.writeShort(id); - legacy.get(id).toBinary(properties, out); + handler.toBinary(out); } private interface Handler { - KList read(DataInputStream in) throws IOException; - void toBinary(KList list, DataOutputStream out) throws IOException; - void toBukkit(KList list, Block block); + void toBinary(DataOutputStream out) throws IOException; + void toBukkit(Block block); } private static class SignHandler implements Handler { - @Override - public KList read(DataInputStream in) throws IOException { - return new KList<>() - .qadd(in.readUTF()) - .qadd(in.readUTF()) - .qadd(in.readUTF()) - .qadd(in.readUTF()) - .qadd(DyeColor.values()[in.readByte()]); + private final String line1; + private final String line2; + private final String line3; + private final String line4; + private final DyeColor dyeColor; + + private SignHandler(DataInputStream in) throws IOException { + line1 = in.readUTF(); + line2 = in.readUTF(); + line3 = in.readUTF(); + line4 = in.readUTF(); + dyeColor = DyeColor.values()[in.readByte()]; } @Override - public void toBinary(KList list, DataOutputStream out) throws IOException { - out.writeUTF((String) list.get(0)); - out.writeUTF((String) list.get(1)); - out.writeUTF((String) list.get(2)); - out.writeUTF((String) list.get(3)); - out.writeByte(((DyeColor) list.get(4)).ordinal()); + public void toBinary(DataOutputStream out) throws IOException { + out.writeUTF(line1); + out.writeUTF(line2); + out.writeUTF(line3); + out.writeUTF(line4); + out.writeByte(dyeColor.ordinal()); } @Override - public void toBukkit(KList list, Block block) { + public void toBukkit(Block block) { Sign sign = (Sign) block.getState(); - sign.setLine(0, (String) list.get(0)); - sign.setLine(1, (String) list.get(1)); - sign.setLine(2, (String) list.get(2)); - sign.setLine(3, (String) list.get(3)); - sign.setColor((DyeColor) list.get(4)); + sign.setLine(0, line1); + sign.setLine(1, line2); + sign.setLine(2, line3); + sign.setLine(3, line4); + sign.setColor(dyeColor); sign.update(); } } private static class SpawnerHandler implements Handler { - @Override - public KList read(DataInputStream in) throws IOException { - return new KList<>().qadd(EntityType.values()[in.readShort()]); + private final EntityType type; + + private SpawnerHandler(DataInputStream in) throws IOException { + type = EntityType.values()[in.readShort()]; } @Override - public void toBinary(KList list, DataOutputStream out) throws IOException { - out.writeShort(((EntityType) list.get(0)).ordinal()); + public void toBinary(DataOutputStream out) throws IOException { + out.writeShort(type.ordinal()); } @Override - public void toBukkit(KList list, Block block) { + public void toBukkit(Block block) { CreatureSpawner spawner = (CreatureSpawner) block.getState(); - spawner.setSpawnedType((EntityType) list.get(0)); + spawner.setSpawnedType(type); spawner.update(); } } private static class BannerHandler implements Handler { - @Override - public KList read(DataInputStream in) throws IOException { - KList list = new KList<>(); - list.add(DyeColor.values()[in.readByte()]); - int listSize = in.readByte(); - var patterns = new KList<>(); + private final KList patterns; + private final DyeColor baseColor; + private BannerHandler(DataInputStream in) throws IOException { + baseColor = DyeColor.values()[in.readByte()]; + patterns = new KList<>(); + int listSize = in.readByte(); for (int i = 0; i < listSize; i++) { DyeColor color = DyeColor.values()[in.readByte()]; - PatternType type = PatternType.values()[in.readByte()]; - patterns.add(new Pattern(color, type)); + PatternType pattern = PatternType.values()[in.readByte()]; + patterns.add(new Pattern(color, pattern)); } - - list.add(patterns); - return list; } @Override - public void toBinary(KList list, DataOutputStream out) throws IOException { - out.writeByte(((DyeColor) list.get(0)).ordinal()); - out.writeByte(((List) list.get(1)).size()); - for (Pattern i : (List) list.get(1)) { + public void toBinary(DataOutputStream out) throws IOException { + out.writeByte(baseColor.ordinal()); + out.writeByte(patterns.size()); + for (Pattern i : patterns) { out.writeByte(i.getColor().ordinal()); out.writeByte(i.getPattern().ordinal()); } } @Override - public void toBukkit(KList list, Block block) { + public void toBukkit(Block block) { Banner banner = (Banner) block.getState(); - banner.setBaseColor((DyeColor) list.get(0)); - banner.setPatterns((List) list.get(1)); + banner.setBaseColor(baseColor); + banner.setPatterns(patterns); banner.update(); } } From dafca8e9db9455b1e0bc1b131776ade17dfb14ef Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 17 Aug 2024 12:29:08 +0200 Subject: [PATCH 10/14] woops --- .../main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java | 1 + 1 file changed, 1 insertion(+) 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 3927f91fc..c14400975 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 @@ -20,6 +20,7 @@ import com.volmit.iris.util.scheduling.J; import net.minecraft.nbt.*; import net.minecraft.nbt.Tag; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.tags.TagKey; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.EntityBlock; import org.bukkit.*; From 7b283a56ee939c190c8a1a5d0063a95a704f0c16 Mon Sep 17 00:00:00 2001 From: RePixelatedMC <107539181+RePixelatedMC@users.noreply.github.com> Date: Sat, 17 Aug 2024 13:55:32 +0200 Subject: [PATCH 11/14] commit --- .../java/com/volmit/iris/core/commands/CommandDeveloper.java | 1 + .../com/volmit/iris/core/pregenerator/IrisPregenerator.java | 2 +- .../volmit/iris/engine/object/IrisJigsawStructurePlacement.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 79367d057..f1d51edde 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -51,6 +51,7 @@ import java.io.*; import java.net.InetAddress; import java.net.NetworkInterface; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; 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 a4ce69d18..eda3029c2 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 @@ -177,7 +177,7 @@ public class IrisPregenerator { // updater.start(); // } } else { - IrisPackBenchmarking.instance.finishedBenchmark(chunksPerSecondHistory); + IrisPackBenchmarking.getInstance().finishedBenchmark(chunksPerSecondHistory); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java index 9fe58ad54..05483f0bb 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java @@ -64,7 +64,7 @@ public class IrisJigsawStructurePlacement implements IRare { private int separation = -1; @Desc("The method used to spread the structure") - private SpreadType spreadType = SpreadType.TRIANGULAR; + private SpreadType spreadType = SpreadType.LINEAR; @ArrayType(type = IrisJigsawMinDistance.class) @Desc("List of minimum distances to check for") From 09635e12a922fab196ff6acf4073cbc8a4af935f Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 17 Aug 2024 14:04:30 +0200 Subject: [PATCH 12/14] woops --- .../java/com/volmit/iris/core/commands/CommandDeveloper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 79367d057..f1d51edde 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -51,6 +51,7 @@ import java.io.*; import java.net.InetAddress; import java.net.NetworkInterface; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; From bbf42d1af052415601e173e20edc66504638911b Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 17 Aug 2024 15:23:23 +0200 Subject: [PATCH 13/14] fix headless chunk offset --- .../volmit/iris/core/nms/v1_20_R3/Headless.java | 17 +++++++---------- .../core/nms/v1_20_R3/mca/MCATerrainChunk.java | 9 --------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java index ab8706256..71572d0a1 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java @@ -40,6 +40,7 @@ import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.scheduling.PrecisionStopwatch; +import lombok.Getter; import net.minecraft.core.Holder; import net.minecraft.core.QuartPos; import net.minecraft.nbt.CompoundTag; @@ -68,6 +69,8 @@ public class Headless implements IHeadless, LevelHeightAccessor { private final KMap> customBiomes = new KMap<>(); private final KMap> minecraftBiomes = new KMap<>(); private final RNG BIOME_RNG; + private final @Getter int minBuildHeight; + private final @Getter int height; private boolean closed = false; public Headless(NMSBinding binding, Engine engine) { @@ -75,6 +78,8 @@ public class Headless implements IHeadless, LevelHeightAccessor { this.engine = engine; this.storage = new RegionFileStorage(new File(engine.getWorld().worldFolder(), "region").toPath(), true); this.BIOME_RNG = new RNG(engine.getSeedManager().getBiome()); + this.minBuildHeight = engine.getDimension().getMinHeight(); + this.height = engine.getDimension().getMaxHeight() - minBuildHeight; engine.getWorld().headless(this); var dimKey = engine.getDimension().getLoadKey(); @@ -107,6 +112,8 @@ public class Headless implements IHeadless, LevelHeightAccessor { @Override public boolean exists(int x, int z) { if (closed) return false; + if (engine.getWorld().hasRealWorld() && engine.getWorld().realWorld().isChunkLoaded(x, z)) + return true; try { CompoundTag tag = storage.read(new ChunkPos(x, z)); return tag != null && !"empty".equals(tag.getString("Status")); @@ -270,14 +277,4 @@ public class Headless implements IHeadless, LevelHeightAccessor { minecraftBiomes.clear(); } } - - @Override - public int getHeight() { - return engine.getHeight(); - } - - @Override - public int getMinBuildHeight() { - return engine.getMinHeight(); - } } diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java index 8c6adc3f4..55a5c8fca 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java @@ -60,8 +60,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk { @Override public void setBiome(int x, int y, int z, Biome bio) { - if (y < 0) return; - y += getMinHeight(); if (y > getMaxHeight()) return; chunk.setBiome(x & 15, y, z & 15, CraftBiome.bukkitToMinecraftHolder(bio)); } @@ -82,10 +80,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk { @Override public void setBlock(int x, int y, int z, BlockData blockData) { - if (y < 0) return; - y += getMinHeight(); - if (y > getMaxHeight()) return; - if (blockData == null) { Iris.error("NULL BD"); } @@ -97,9 +91,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk { } private BlockState getBlockState(int x, int y, int z) { - if (y < 0) { - y = 0; - } y += getMinHeight(); if (y > getMaxHeight()) { y = getMaxHeight(); From bb7bbb637928ff453e43f2d2c92b1f983ec663f9 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 17 Aug 2024 19:01:27 +0200 Subject: [PATCH 14/14] fix legacy tile data loading from mantle --- .../iris/engine/object/IrisBlockData.java | 4 +-- .../iris/engine/object/LegacyTileData.java | 17 +++++++++-- .../volmit/iris/engine/object/TileData.java | 29 +++++++++---------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java index 81a497eed..65a9a59a8 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java @@ -202,9 +202,9 @@ public class IrisBlockData extends IrisRegistrant { public TileData tryGetTile(IrisData data) { //TODO Do like a registry thing with the tile data registry. Also update the parsing of data to include **block** entities. var type = getBlockData(data).getMaterial(); - if (!INMS.get().hasTile(type)) + if (!INMS.get().hasTile(type) || tileData == null || tileData.isEmpty()) return null; - return new TileData().setMaterial(type).setProperties(this.tileData); + return new TileData(type, this.tileData); } private String keyify(String dat) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java index 105f818aa..ac8728ebe 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java @@ -2,6 +2,8 @@ package com.volmit.iris.engine.object; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.scheduling.J; +import lombok.EqualsAndHashCode; +import lombok.ToString; import org.apache.commons.io.function.IOFunction; import org.bukkit.DyeColor; import org.bukkit.block.*; @@ -14,6 +16,8 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Map; +@ToString +@EqualsAndHashCode(callSuper = false) public class LegacyTileData extends TileData { private static final Map> legacy = Map.of( 0, SignHandler::new, @@ -41,11 +45,18 @@ public class LegacyTileData extends TileData { handler.toBinary(out); } + @Override + public TileData clone() { + return this; + } + private interface Handler { void toBinary(DataOutputStream out) throws IOException; void toBukkit(Block block); } + @ToString + @EqualsAndHashCode private static class SignHandler implements Handler { private final String line1; private final String line2; @@ -81,7 +92,8 @@ public class LegacyTileData extends TileData { sign.update(); } } - + @ToString + @EqualsAndHashCode private static class SpawnerHandler implements Handler { private final EntityType type; @@ -101,7 +113,8 @@ public class LegacyTileData extends TileData { spawner.update(); } } - + @ToString + @EqualsAndHashCode private static class BannerHandler implements Handler { private final KList patterns; private final DyeColor baseColor; diff --git a/core/src/main/java/com/volmit/iris/engine/object/TileData.java b/core/src/main/java/com/volmit/iris/engine/object/TileData.java index 9bab31df8..9e330702e 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/TileData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/TileData.java @@ -23,27 +23,29 @@ import com.google.gson.GsonBuilder; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.util.collection.KMap; -import lombok.Data; -import lombok.experimental.Accessors; +import lombok.*; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; import org.bukkit.block.TileState; import org.bukkit.block.data.BlockData; -import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -@Data @SuppressWarnings("ALL") -@Accessors(chain = true) +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class TileData implements Cloneable { private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create(); - private Material material = null; - private KMap properties = new KMap<>(); + @NonNull + private Material material; + @NonNull + private KMap properties; public static boolean setTileState(Block block, TileData data) { if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData())) @@ -62,14 +64,9 @@ public class TileData implements Cloneable { throw new IOException("Mark not supported"); in.mark(Integer.MAX_VALUE); try { - TileData d = new TileData(); - var material = in.readUTF(); - d.material = Material.matchMaterial(material); - if (d.material == null) throw new IOException("Unknown material: " + material); - var properties = in.readUTF(); - d.properties = gson.fromJson(properties, KMap.class); - if (d.properties == null) throw new IOException("Invalid properties: " + properties); - return d; + return new TileData( + Material.matchMaterial(in.readUTF()), + gson.fromJson(in.readUTF(), KMap.class)); } catch (Throwable e) { in.reset(); return new LegacyTileData(in);