mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-02 03:16:41 +00:00
Feature/1.17 (#1120)
* start v6 * Update classes to v6 method signatures * change rootVersion to signify p2v6 compat * Use 16 as toolchain version but target 11 for build output * add minimessage as api * Require v6 and don't attempt to "setup" hook from FAWE * Address comments * *address /all/ comments * FAWE classes should only act as a delegate * Uppercase logger * Settings for v6-hook have moved to P2-v6, remove unneeded if statements * Rename classes to Delegate * add whenDone task to setCuboids * Remove bad spaces * Fix plot swap * Initial work on 1.17 support * Remove data versions from the Bukkit adapters (#1507) * Remove data versions from the Bukkit adapters * Don't allow saving schematics without an adapter in place on Bukkit. * Removed confusing line (cherry picked from commit 2056218b4a8644836b1d127105dfa289e9cdbc1c) * More progress * Fix chunk sending * Repackage from com.boydti to com.fastasyncworldedit.<module> (#1119) * Preliminary work on repackaging * Rename build artifacts matching our pattern * Finish up repackaging * Fix a few field accesses and old imports * Dirty fix for chunks container ChunkSections outside of 0-15 * Correctly read from NibbleArrays for lighting * Fix getSections and BlockMaterial for 1.17 * Fix writing blocks to the world. - The issue isn't the presence of a "-1" chunk, it's the constructor for ChunkSection requiring the layer (0 to 15) rather than the y chord * Fix more field accesses * More work towards 1.17 * Update Upstream a57f66f Fix watchdog, add negative y support. (1782) * Add azalea tree to `/tool tree` * Don't define toolchain twice * Repackage GriefDefender * Relocate under new namespace * Bye bye ecma left overs * Add 1.17 to issue templates and instructions * Move to adventure-nbt (#918) * Initial work for adventure-nbt * Some more FAWE specific stuff * Fix erroneous deprecation check * Workflow change * Continued merging all adventure NBT related changes * Continued merging all adventure NBT related changes * Made a constructor public again This needs to be public for BlockTransformExtent.java * Finished converting all NBT data to adventure. * Make this compile * Fix conflicts Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> * Update adapters to 1.17 * Change build prefix to 1.17 * Move more nms classes to adapters * Move left over nms classes * Move Spigot 1.17 class * Remove unneeded adapter loader code The loader will find the appropriate class now itself * Update adapters * Update adapters * Lazy fix tests * Update adapters * Update Upstream 43da91a Remove method reflection for getMinHeight in BukkitWorld. (1796) * Relocate adventure-nbt under proper namespace * Add LazyCompoundTag as a non-version-specific class to be used by adapters * Better integration between old NBT and Adventure NBT - begin fixing the issues seen recently * Correctly NBT conversion method * LazyCompoundTags should actually be overriding and correctly returning a CompoundBinaryTag. * Update worldedit-adapters Fixes #1141 * Remove unnecessary massive lag machine * Refactor apply to applyBlock in subclasses * applyBlock should be overriden by all subclasses. Default apply to applyBlock * Closes #1130 Closes #1132 * Squashed commit of the following: commit a9bfa1a07c77083c844a0c3ba62f4bd94bed107c Author: NotMyFault <mc.cache@web.de> Date: Sun Jun 27 21:53:21 2021 +0200 [ci skip] Update gradle wrapper validation commit aa7471f95317d28a16f62e4b200de8d0fea2fa95 Author: Matthew Miller <mnmiller1@me.com> Date: Sat Oct 10 15:49:13 2020 +1000 Add ^x,y,z relative offset support to the offset parser (#1545) * Add ^x,y,z relative offset support to the offset parser * Wrap in a try-catch (cherry picked from commit 28bdf7ff9254bbc85bb4f5f792b303943a3930a8) * Add `fawe.error.schematic.not.found` translation key * Update Upstream 728a152 Skip notify if chunk section doesn't exist (1794) * Fixed #1157 * Add a null check to prevent NPE in nbt code * Update adapters * Update Upstream fbb047a Optimize legacy schematic loading (1808) * Hurr durr I don't want to update Java * Update Upstream 0790e6e Fix CLI Mess (1811) * Fixes #1160 * Expose minimessage transitively thru PlotSquared Touches #32 * [ci skip] Remove unneeded maven repository * Steal tab completion from PlotSquared for P2 related commands * Don't error on startup when building locally Co-Authored-By: goldfishapp <8278196+goldfishapp@users.noreply.github.com> * [ci skip] Update gh actions to Java 16 * Update textures to grab 1.17 jar Co-authored-by: NotMyFault <mc.cache@web.de> Co-authored-by: SirYwell <hannesgreule@outlook.de> Co-authored-by: Matthew Miller <mnmiller1@me.com> Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> Co-authored-by: goldfishapp <8278196+goldfishapp@users.noreply.github.com>
This commit is contained in:
@ -22,8 +22,8 @@ package com.sk89q.worldedit.bukkit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.SimpleBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.SimpleBukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
|
@ -1,34 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
|
||||
public class BukkitPermissionAttachmentManager {
|
||||
|
||||
private final WorldEditPlugin plugin;
|
||||
private final Map<Player, PermissionAttachment> attachments = new ConcurrentHashMap<>();
|
||||
|
||||
public BukkitPermissionAttachmentManager(WorldEditPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public PermissionAttachment getOrAddAttachment(@Nullable final Player p) {
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
return attachments.computeIfAbsent(p, k -> k.addAttachment(plugin));
|
||||
}
|
||||
|
||||
public void removeAttachment(@Nullable final Player p) {
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
PermissionAttachment attach = attachments.remove(p);
|
||||
if (attach != null) {
|
||||
p.removeAttachment(attach);
|
||||
}
|
||||
}
|
||||
}
|
@ -19,10 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.object.RunnableVal;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.wepif.VaultResolver;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -46,6 +46,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
||||
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
@ -392,11 +393,12 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData());
|
||||
} else {
|
||||
player.sendBlockChange(loc, BukkitAdapter.adapt(block));
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK) {
|
||||
adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbtData());
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK && block instanceof BaseBlock) {
|
||||
CompoundBinaryTag nbt = ((BaseBlock) block).getNbt();
|
||||
if (nbt != null) {
|
||||
adapter.sendFakeNBT(player, pos, nbt);
|
||||
adapter.sendFakeOP(player);
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.lighting.RelighterFactory;
|
||||
import com.boydti.fawe.bukkit.NMSRelighterFactory;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.TuinityRelighterFactory_1_16_5;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.bukkit.util.CommandInfo;
|
||||
import com.sk89q.bukkit.util.CommandRegistration;
|
||||
@ -38,7 +36,6 @@ import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.extension.platform.Watchdog;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.lifecycle.Lifecycled;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.registry.Registries;
|
||||
@ -70,7 +67,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
public final WorldEditPlugin plugin;
|
||||
private final CommandRegistration dynamicCommands;
|
||||
private final Lifecycled<Watchdog> watchdog;
|
||||
private final RelighterFactory relighterFactory;
|
||||
private RelighterFactory relighterFactory;
|
||||
private boolean hookingEvents;
|
||||
|
||||
public BukkitServerInterface(WorldEditPlugin plugin, Server server) {
|
||||
@ -80,16 +77,6 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
this.watchdog = plugin.getLifecycledBukkitImplAdapter()
|
||||
.filter(BukkitImplAdapter::supportsWatchdog)
|
||||
.map(BukkitWatchdog::new);
|
||||
RelighterFactory tempFactory;
|
||||
try {
|
||||
Class.forName("com.tuinity.tuinity.config.TuinityConfig");
|
||||
tempFactory = new TuinityRelighterFactory_1_16_5();
|
||||
LOGGER.info("Using Tuinity internals for relighting");
|
||||
} catch (ClassNotFoundException e) {
|
||||
tempFactory = new NMSRelighterFactory();
|
||||
LOGGER.info("Using FAWE for relighting");
|
||||
}
|
||||
this.relighterFactory = tempFactory;
|
||||
}
|
||||
|
||||
CommandRegistration getDynamicCommands() {
|
||||
@ -144,7 +131,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
|
||||
@Override
|
||||
public Watchdog getWatchdog() {
|
||||
return watchdog.valueOrThrow();
|
||||
return watchdog.value().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -262,6 +249,10 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
|
||||
@Override
|
||||
public @NotNull RelighterFactory getRelighterFactory() {
|
||||
if (this.relighterFactory == null) {
|
||||
this.relighterFactory = this.plugin.getBukkitImplAdapter().getRelighterFactory();
|
||||
LOGGER.info("Using " + this.relighterFactory.getClass().getCanonicalName() + " as relighter factory.");
|
||||
}
|
||||
return this.relighterFactory;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -80,6 +80,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final boolean HAS_3D_BIOMES;
|
||||
private static final boolean HAS_MIN_Y;
|
||||
|
||||
private static final Map<Integer, Effect> effects = new HashMap<>();
|
||||
|
||||
@ -98,6 +99,13 @@ public class BukkitWorld extends AbstractWorld {
|
||||
temp = false;
|
||||
}
|
||||
HAS_3D_BIOMES = temp;
|
||||
try {
|
||||
World.class.getMethod("getMinHeight");
|
||||
temp = true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
temp = false;
|
||||
}
|
||||
HAS_MIN_Y = temp;
|
||||
}
|
||||
|
||||
private WeakReference<World> worldRef;
|
||||
@ -143,7 +151,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
return list;
|
||||
}
|
||||
|
||||
//createEntity was moved to IChunkExtent to prevent issues with Async Entitiy Add.
|
||||
//createEntity was moved to IChunkExtent to prevent issues with Async Entity Add.
|
||||
|
||||
/**
|
||||
* Get the world handle.
|
||||
@ -252,6 +260,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
if (!getBlock(pt).getBlockType().getMaterial().hasContainer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
BlockState state = PaperLib.getBlockState(block, false).getState();
|
||||
if (!(state instanceof InventoryHolder)) {
|
||||
@ -360,6 +369,14 @@ public class BukkitWorld extends AbstractWorld {
|
||||
return getWorld().getMaxHeight() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
if (HAS_MIN_Y) {
|
||||
return getWorld().getMinHeight();
|
||||
}
|
||||
return super.getMinY();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void fixAfterFastMode(Iterable<BlockVector2> chunks) {
|
||||
@ -463,9 +480,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
try {
|
||||
return worldNativeAccess.setBlock(position, block, sideEffects);
|
||||
} catch (Exception e) {
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).getNbtData() != null) {
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).getNbt() != null) {
|
||||
LOGGER.warn("Tried to set a corrupt tile entity at " + position.toString()
|
||||
+ ": " + ((BaseBlock) block).getNbtData(), e);
|
||||
+ ": " + ((BaseBlock) block).getNbt(), e);
|
||||
} else {
|
||||
LOGGER.warn("Failed to set block via adapter, falling back to generic", e);
|
||||
}
|
||||
|
@ -19,8 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.bukkit.BukkitPermissionAttachmentManager;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.sk89q.util.yaml.YAMLProcessor;
|
||||
import com.sk89q.wepif.PermissionsResolverManager;
|
||||
@ -30,10 +31,6 @@ import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R2;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R3;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
||||
@ -72,7 +69,6 @@ import org.bukkit.event.world.WorldInitEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.incendo.serverlib.ServerLib;
|
||||
|
||||
@ -299,15 +295,6 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
|
||||
// Attempt to load a Bukkit adapter
|
||||
BukkitImplLoader adapterLoader = new BukkitImplLoader();
|
||||
try {
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_15_R2.class);
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_16_R1.class);
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_16_R2.class);
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_16_R3.class);
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
adapterLoader.addFromPath(getClass().getClassLoader());
|
||||
} catch (IOException e) {
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
/**
|
||||
|
@ -19,11 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.AdventureNBTConverter;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
@ -37,6 +40,8 @@ import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
@ -54,23 +59,16 @@ import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An interface for adapters of various Bukkit implementations.
|
||||
*/
|
||||
public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
|
||||
/**
|
||||
* Get the Minecraft data version for the current world data.
|
||||
*
|
||||
* @return the data version
|
||||
*/
|
||||
int getDataVersion();
|
||||
|
||||
/**
|
||||
* Get a data fixer, or null if not supported.
|
||||
*
|
||||
@ -168,7 +166,7 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
* @param pos The position
|
||||
* @param nbtData The NBT Data
|
||||
*/
|
||||
void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData);
|
||||
void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData);
|
||||
|
||||
/**
|
||||
* Make the client think it has operator status.
|
||||
@ -239,11 +237,24 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default Tag toNative(T foreign) {
|
||||
return AdventureNBTConverter.fromAdventure(toNativeBinary(foreign));
|
||||
}
|
||||
|
||||
default BinaryTag toNativeBinary(T foreign) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default T fromNative(Tag foreign) {
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
return fromNativeBinary(foreign.asBinaryTag());
|
||||
}
|
||||
|
||||
default T fromNativeBinary(BinaryTag foreign) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -278,4 +289,8 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
default int getInternalBiomeId(BiomeType biome) {
|
||||
return Biome.BADLANDS.ordinal();
|
||||
}
|
||||
|
||||
default RelighterFactory getRelighterFactory() {
|
||||
return new NMSRelighterFactory(); // TODO implement in adapters instead
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class BukkitImplLoader {
|
||||
private final List<String> adapterCandidates = new ArrayList<>();
|
||||
private String customCandidate;
|
||||
|
||||
private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl";
|
||||
private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl.fawe";
|
||||
private static final String SEARCH_PACKAGE_DOT = SEARCH_PACKAGE + ".";
|
||||
private static final String SEARCH_PATH = SEARCH_PACKAGE.replace(".", "/");
|
||||
private static final String CLASS_SUFFIX = ".class";
|
||||
@ -76,10 +76,6 @@ public class BukkitImplLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public void addClass(Class<?> cls) {
|
||||
adapterCandidates.add(0, cls.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the given JAR for candidate implementations.
|
||||
*
|
||||
|
@ -1,101 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public abstract class CachedBukkitAdapter implements IBukkitAdapter {
|
||||
private int[] itemTypes;
|
||||
private int[] blockTypes;
|
||||
|
||||
private boolean init() {
|
||||
if (itemTypes == null) {
|
||||
Material[] materials = Material.values();
|
||||
itemTypes = new int[materials.length];
|
||||
blockTypes = new int[materials.length];
|
||||
for (int i = 0; i < materials.length; i++) {
|
||||
Material material = materials[i];
|
||||
if (material.isLegacy()) {
|
||||
continue;
|
||||
}
|
||||
NamespacedKey key = material.getKey();
|
||||
String id = key.getNamespace() + ":" + key.getKey();
|
||||
if (material.isBlock()) {
|
||||
blockTypes[i] = BlockTypes.get(id).getInternalId();
|
||||
}
|
||||
if (material.isItem()) {
|
||||
itemTypes[i] = ItemTypes.get(id).getInternalId();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Material to a ItemType.
|
||||
*
|
||||
* @param material The material
|
||||
* @return The itemtype
|
||||
*/
|
||||
@Override
|
||||
public ItemType asItemType(Material material) {
|
||||
try {
|
||||
return ItemTypes.get(itemTypes[material.ordinal()]);
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return asItemType(material);
|
||||
}
|
||||
return ItemTypes.get(itemTypes[material.ordinal()]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockType asBlockType(Material material) {
|
||||
try {
|
||||
return BlockTypesCache.values[blockTypes[material.ordinal()]];
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return asBlockType(material);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockStateHolder from a Bukkit BlockData.
|
||||
*
|
||||
* @param blockData The Bukkit BlockData
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
try {
|
||||
checkNotNull(blockData);
|
||||
Material material = blockData.getMaterial();
|
||||
BlockType type = BlockTypes.getFromStateId(blockTypes[material.ordinal()]);
|
||||
List<? extends Property> propList = type.getProperties();
|
||||
if (propList.size() == 0) {
|
||||
return type.getDefaultState();
|
||||
}
|
||||
String properties = blockData.getAsString();
|
||||
return BlockState.get(type, properties, type.getDefaultState());
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return adapt(blockData);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,354 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.NotABlockException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||
import com.sk89q.worldedit.bukkit.BukkitItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.gamemode.GameModes;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public interface IBukkitAdapter {
|
||||
|
||||
/**
|
||||
* Convert any WorldEdit world into an equivalent wrapped Bukkit world.
|
||||
*
|
||||
* <p>If a matching world cannot be found, a {@link RuntimeException}
|
||||
* will be thrown.</p>
|
||||
*
|
||||
* @param world the world
|
||||
* @return a wrapped Bukkit world
|
||||
*/
|
||||
default BukkitWorld asBukkitWorld(World world) {
|
||||
if (world instanceof BukkitWorld) {
|
||||
return (BukkitWorld) world;
|
||||
} else {
|
||||
BukkitWorld bukkitWorld = WorldEditPlugin.getInstance().getInternalPlatform().matchWorld(world);
|
||||
if (bukkitWorld == null) {
|
||||
throw new RuntimeException("World '" + world.getName() + "' has no matching version in Bukkit");
|
||||
}
|
||||
return bukkitWorld;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit world from a WorldEdit world.
|
||||
*
|
||||
* @param world the WorldEdit world
|
||||
* @return a Bukkit world
|
||||
*/
|
||||
default org.bukkit.World adapt(World world) {
|
||||
checkNotNull(world);
|
||||
if (world instanceof BukkitWorld) {
|
||||
return ((BukkitWorld) world).getWorld();
|
||||
} else {
|
||||
org.bukkit.World match = Bukkit.getServer().getWorld(world.getName());
|
||||
if (match != null) {
|
||||
return match;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't find a Bukkit world for " + world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit location from a WorldEdit position with a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @param position the WorldEdit position
|
||||
* @return a Bukkit location
|
||||
*/
|
||||
default org.bukkit.Location adapt(org.bukkit.World world, Vector3 position) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(position);
|
||||
return new org.bukkit.Location(
|
||||
world,
|
||||
position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
default org.bukkit.Location adapt(org.bukkit.World world, BlockVector3 position) {
|
||||
return adapt(world, position.toVector3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit location from a WorldEdit location with a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @param location the WorldEdit location
|
||||
* @return a Bukkit location
|
||||
*/
|
||||
default org.bukkit.Location adapt(org.bukkit.World world, Location location) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(location);
|
||||
return new org.bukkit.Location(
|
||||
world,
|
||||
location.getX(), location.getY(), location.getZ(),
|
||||
location.getYaw(),
|
||||
location.getPitch());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit Vector from a Bukkit location.
|
||||
*
|
||||
* @param location The Bukkit location
|
||||
* @return a WorldEdit vector
|
||||
*/
|
||||
default Vector3 asVector(org.bukkit.Location location) {
|
||||
checkNotNull(location);
|
||||
return Vector3.at(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockVector from a Bukkit location.
|
||||
*
|
||||
* @param location The Bukkit location
|
||||
* @return a WorldEdit vector
|
||||
*/
|
||||
default BlockVector3 asBlockVector(org.bukkit.Location location) {
|
||||
checkNotNull(location);
|
||||
return BlockVector3.at(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit entity from a Bukkit entity.
|
||||
*
|
||||
* @param entity the Bukkit entity
|
||||
* @return a WorldEdit entity
|
||||
*/
|
||||
default Entity adapt(org.bukkit.entity.Entity entity) {
|
||||
checkNotNull(entity);
|
||||
return new BukkitEntity(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit Material form a WorldEdit ItemType
|
||||
*
|
||||
* @param itemType The WorldEdit ItemType
|
||||
* @return The Bukkit Material
|
||||
*/
|
||||
default Material adapt(ItemType itemType) {
|
||||
checkNotNull(itemType);
|
||||
if (!itemType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports Minecraft items");
|
||||
}
|
||||
return Material.getMaterial(itemType.getId().substring(10).toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit Material form a WorldEdit BlockType
|
||||
*
|
||||
* @param blockType The WorldEdit BlockType
|
||||
* @return The Bukkit Material
|
||||
*/
|
||||
default Material adapt(BlockType blockType) {
|
||||
checkNotNull(blockType);
|
||||
if (!blockType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports Minecraft blocks");
|
||||
}
|
||||
String id = blockType.getId().substring(10).toUpperCase(Locale.ROOT);
|
||||
return Material.getMaterial(id);
|
||||
}
|
||||
|
||||
default org.bukkit.entity.EntityType adapt(EntityType entityType) {
|
||||
if (!entityType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports vanilla entities");
|
||||
}
|
||||
return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10).toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Material to a BlockType
|
||||
*
|
||||
* @param material The material
|
||||
* @return The blocktype
|
||||
*/
|
||||
default BlockType asBlockType(Material material) {
|
||||
checkNotNull(material);
|
||||
if (!material.isBlock()) {
|
||||
throw new IllegalArgumentException(material.getKey().toString() + " is not a block!") {
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
return BlockTypes.get(material.getKey().toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Converts a Material to a ItemType
|
||||
*
|
||||
* @param material The material
|
||||
* @return The itemtype
|
||||
*/
|
||||
default ItemType asItemType(Material material) {
|
||||
return ItemTypes.get(material.getKey().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockStateHolder from a Bukkit BlockData
|
||||
*
|
||||
* @param blockData The Bukkit BlockData
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
default BlockState adapt(BlockData blockData) {
|
||||
String id = blockData.getAsString();
|
||||
return BlockState.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit BlockData from a WorldEdit BlockStateHolder
|
||||
*
|
||||
* @param block The WorldEdit BlockStateHolder
|
||||
* @return The Bukkit BlockData
|
||||
*/
|
||||
default <B extends BlockStateHolder<B>> BlockData adapt(B block) {
|
||||
return Bukkit.createBlockData(block.getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BaseItemStack from a Bukkit ItemStack
|
||||
*
|
||||
* @param itemStack The Bukkit ItemStack
|
||||
* @return The WorldEdit BaseItemStack
|
||||
*/
|
||||
default BaseItemStack adapt(ItemStack itemStack) {
|
||||
checkNotNull(itemStack);
|
||||
return new BukkitItemStack(itemStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit ItemStack from a WorldEdit BaseItemStack
|
||||
*
|
||||
* @param item The WorldEdit BaseItemStack
|
||||
* @return The Bukkit ItemStack
|
||||
*/
|
||||
default ItemStack adapt(BaseItemStack item) {
|
||||
checkNotNull(item);
|
||||
if (item instanceof BukkitItemStack) {
|
||||
return ((BukkitItemStack) item).getBukkitItemStack();
|
||||
}
|
||||
return new ItemStack(adapt(item.getType()), item.getAmount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit Player from a Bukkit Player.
|
||||
*
|
||||
* @param player The Bukkit player
|
||||
* @return The WorldEdit player
|
||||
*/
|
||||
default BukkitPlayer adapt(Player player) {
|
||||
return WorldEditPlugin.getInstance().wrapPlayer(player);
|
||||
}
|
||||
/**
|
||||
* Create a Bukkit Player from a WorldEdit Player.
|
||||
*
|
||||
* @param player The WorldEdit player
|
||||
* @return The Bukkit player
|
||||
*/
|
||||
default Player adapt(com.sk89q.worldedit.entity.Player player) {
|
||||
return ((BukkitPlayer) player).getPlayer();
|
||||
}
|
||||
|
||||
default Biome adapt(BiomeType biomeType) {
|
||||
if (!biomeType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports vanilla biomes");
|
||||
}
|
||||
try {
|
||||
return Biome.valueOf(biomeType.getId().substring(10).toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
default BiomeType adapt(Biome biome) {
|
||||
return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks equality between a WorldEdit BlockType and a Bukkit Material
|
||||
*
|
||||
* @param blockType The WorldEdit BlockType
|
||||
* @param type The Bukkit Material
|
||||
* @return If they are equal
|
||||
*/
|
||||
default boolean equals(BlockType blockType, Material type) {
|
||||
return blockType == asItemType(type).getBlockType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit world from a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @return a WorldEdit world
|
||||
*/
|
||||
default World adapt(org.bukkit.World world) {
|
||||
checkNotNull(world);
|
||||
return new BukkitWorld(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit GameMode from a Bukkit one.
|
||||
*
|
||||
* @param gameMode Bukkit GameMode
|
||||
* @return WorldEdit GameMode
|
||||
*/
|
||||
default GameMode adapt(org.bukkit.GameMode gameMode) {
|
||||
checkNotNull(gameMode);
|
||||
return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit EntityType from a Bukkit one.
|
||||
*
|
||||
* @param entityType Bukkit EntityType
|
||||
* @return WorldEdit EntityType
|
||||
*/
|
||||
default EntityType adapt(org.bukkit.entity.EntityType entityType) {
|
||||
return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockStateHolder from a Bukkit ItemStack
|
||||
*
|
||||
* @param itemStack The Bukkit ItemStack
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
default BlockState asBlockState(ItemStack itemStack) {
|
||||
checkNotNull(itemStack);
|
||||
if (itemStack.getType().isBlock()) {
|
||||
return adapt(itemStack.getType().createBlockData());
|
||||
} else {
|
||||
throw new NotABlockException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,269 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
|
||||
BukkitImplAdapter<T> getParent();
|
||||
|
||||
@Override
|
||||
default int getDataVersion() {
|
||||
return getParent().getDataVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default DataFixer getDataFixer() {
|
||||
return getParent().getDataFixer();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsWatchdog() {
|
||||
return getParent().supportsWatchdog();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void tickWatchdog() {
|
||||
getParent().tickWatchdog();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock getBlock(Location location) {
|
||||
return getParent().getBlock(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default BaseEntity getEntity(Entity entity) {
|
||||
return getParent().getEntity(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default Entity createEntity(Location location, BaseEntity state) {
|
||||
return getParent().createEntity(location, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData) {
|
||||
getParent().sendFakeNBT(player, pos, nbtData);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeOP(Player player) {
|
||||
getParent().sendFakeOP(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) {
|
||||
return getParent().simulateItemUse(world, position, item, face);
|
||||
}
|
||||
|
||||
@Override
|
||||
default ItemStack adapt(BaseItemStack item) {
|
||||
return getParent().adapt(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseItemStack adapt(ItemStack itemStack) {
|
||||
return getParent().adapt(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
default OptionalInt getInternalBlockStateId(BlockData data) {
|
||||
return getParent().getInternalBlockStateId(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
default OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
return getParent().getInternalBlockStateId(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockMaterial getMaterial(BlockType blockType) {
|
||||
return getParent().getMaterial(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockMaterial getMaterial(BlockState blockState) {
|
||||
return getParent().getMaterial(blockState);
|
||||
}
|
||||
|
||||
default Tag toNative(T foreign) {
|
||||
return getParent().toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
default T fromNative(Tag foreign) {
|
||||
return getParent().fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default World createWorld(WorldCreator creator) {
|
||||
return getParent().createWorld(creator);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeChunk(World world, Player player, ChunkPacket packet) {
|
||||
getParent().sendFakeChunk(world, player, packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BukkitWorld asBukkitWorld(com.sk89q.worldedit.world.World world) {
|
||||
return getParent().asBukkitWorld(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
default World adapt(com.sk89q.worldedit.world.World world) {
|
||||
return getParent().adapt(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Location adapt(World world, Vector3 position) {
|
||||
return getParent().adapt(world, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Location adapt(World world, BlockVector3 position) {
|
||||
return getParent().adapt(world, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Location adapt(World world, com.sk89q.worldedit.util.Location location) {
|
||||
return getParent().adapt(world, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Vector3 asVector(Location location) {
|
||||
return getParent().asVector(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockVector3 asBlockVector(Location location) {
|
||||
return getParent().asBlockVector(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
default com.sk89q.worldedit.entity.Entity adapt(Entity entity) {
|
||||
return getParent().adapt(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Material adapt(ItemType itemType) {
|
||||
return getParent().adapt(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Material adapt(BlockType blockType) {
|
||||
return getParent().adapt(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default EntityType adapt(com.sk89q.worldedit.world.entity.EntityType entityType) {
|
||||
return getParent().adapt(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockType asBlockType(Material material) {
|
||||
return getParent().asBlockType(material);
|
||||
}
|
||||
|
||||
@Override
|
||||
default ItemType asItemType(Material material) {
|
||||
return getParent().asItemType(material);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState adapt(BlockData blockData) {
|
||||
return getParent().adapt(blockData);
|
||||
}
|
||||
|
||||
@Override
|
||||
default <B extends BlockStateHolder<B>> BlockData adapt(B block) {
|
||||
return getParent().adapt(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BukkitPlayer adapt(Player player) {
|
||||
return getParent().adapt(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Player adapt(com.sk89q.worldedit.entity.Player player) {
|
||||
return getParent().adapt(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Biome adapt(BiomeType biomeType) {
|
||||
return getParent().adapt(biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType adapt(Biome biome) {
|
||||
return getParent().adapt(biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean equals(BlockType blockType, Material type) {
|
||||
return getParent().equals(blockType, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
default com.sk89q.worldedit.world.World adapt(World world) {
|
||||
return getParent().adapt(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
default GameMode adapt(org.bukkit.GameMode gameMode) {
|
||||
return getParent().adapt(gameMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
default com.sk89q.worldedit.world.entity.EntityType adapt(EntityType entityType) {
|
||||
return getParent().adapt(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState asBlockState(ItemStack itemStack) {
|
||||
return getParent().asBlockState(itemStack);
|
||||
}
|
||||
}
|
@ -1,551 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
/**
|
||||
* Represents an abstract regeneration handler.
|
||||
* @param <IChunkAccess> the type of the {@Code IChunkAccess} of the current Minecraft implementation
|
||||
* @param <ProtoChunk> the type of the {@Code ProtoChunk} of the current Minecraft implementation
|
||||
* @param <Chunk> the type of the {@Code Chunk} of the current Minecraft implementation
|
||||
* @param <ChunkStatus> the type of the {@Code ChunkStatusWrapper} wrapping the {@Code ChunkStatus} enum
|
||||
*/
|
||||
public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess, Chunk extends IChunkAccess, ChunkStatus extends Regenerator.ChunkStatusWrapper<IChunkAccess>> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
protected final org.bukkit.World originalBukkitWorld;
|
||||
protected final Region region;
|
||||
protected final Extent target;
|
||||
protected final RegenOptions options;
|
||||
|
||||
//runtime
|
||||
protected final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
protected boolean generateConcurrent = true;
|
||||
protected long seed;
|
||||
|
||||
private final Long2ObjectLinkedOpenHashMap<ProtoChunk> protoChunks = new Long2ObjectLinkedOpenHashMap<>();
|
||||
private final Long2ObjectOpenHashMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
|
||||
private ExecutorService executor;
|
||||
private SingleThreadQueueExtent source;
|
||||
|
||||
/**
|
||||
* Initializes an abstract regeneration handler.
|
||||
* @param originalBukkitWorld the Bukkit world containing all the information on how to regenerate the {code Region}
|
||||
* @param region the selection to regenerate
|
||||
* @param target the target {@code Extent} to paste the regenerated blocks into
|
||||
* @param options the options to used while regenerating and pasting into the target {@code Extent}
|
||||
*/
|
||||
public Regenerator(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
this.originalBukkitWorld = originalBukkitWorld;
|
||||
this.region = region;
|
||||
this.target = target;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerates the selected {@code Region}.
|
||||
* @return whether or not the regeneration process was successful
|
||||
* @throws Exception when something goes terribly wrong
|
||||
*/
|
||||
public boolean regenerate() throws Exception {
|
||||
if (!prepare()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!initNewWorld()) {
|
||||
cleanup0();
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
cleanup0();
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!generate()) {
|
||||
cleanup0();
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
cleanup0();
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
copyToWorld();
|
||||
} catch (Exception e) {
|
||||
cleanup0();
|
||||
throw e;
|
||||
}
|
||||
|
||||
cleanup0();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code ProtoChunk} at the given chunk coordinates.
|
||||
* @param x the chunk x coordinate
|
||||
* @param z the chunk z coordinate
|
||||
* @return the {@code ProtoChunk} at the given chunk coordinates or null if it is not part of the regeneration process or has not been initialized yet.
|
||||
*/
|
||||
protected ProtoChunk getProtoChunkAt(int x, int z) {
|
||||
return protoChunks.get(MathMan.pairInt(x, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Chunk} at the given chunk coordinates.
|
||||
* @param x the chunk x coordinate
|
||||
* @param z the chunk z coordinate
|
||||
* @return the {@code Chunk} at the given chunk coordinates or null if it is not part of the regeneration process or has not been converted yet.
|
||||
*/
|
||||
protected Chunk getChunkAt(int x, int z) {
|
||||
return chunks.get(MathMan.pairInt(x, z));
|
||||
}
|
||||
|
||||
private boolean generate() throws Exception {
|
||||
if (generateConcurrent) {
|
||||
//Using concurrent chunk generation
|
||||
executor = Executors.newFixedThreadPool(Settings.IMP.QUEUE.PARALLEL_THREADS);
|
||||
} // else using sequential chunk generation, concurrent not supported
|
||||
|
||||
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?
|
||||
//for now it is working well and fast, if we are bored in the future we could do the research (a lot of it) to reduce the border radius
|
||||
|
||||
//generate chunk coords lists with a certain radius
|
||||
Int2ObjectOpenHashMap<List<Long>> chunkCoordsForRadius = new Int2ObjectOpenHashMap<>();
|
||||
chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeigborChunkRadius0).distinct().forEach(radius -> {
|
||||
if (radius == -1) //ignore ChunkStatus.EMPTY
|
||||
return;
|
||||
int border = 16 - radius; //9 = 8 + 1, 8: max border radius used in chunk stages, 1: need 1 extra chunk for chunk features to generate at the border of the region
|
||||
chunkCoordsForRadius.put(radius, getChunkCoordsRegen(region, border));
|
||||
});
|
||||
|
||||
//create chunks
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) {
|
||||
ProtoChunk chunk = createProtoChunk(MathMan.unpairIntX(xz), MathMan.unpairIntY(xz));
|
||||
protoChunks.put(xz, chunk);
|
||||
}
|
||||
|
||||
//generate lists for RegionLimitedWorldAccess, need to be square with odd length (e.g. 17x17), 17 = 1 middle chunk + 8 border chunks * 2
|
||||
Int2ObjectOpenHashMap<Long2ObjectOpenHashMap<List<IChunkAccess>>> worldlimits = new Int2ObjectOpenHashMap<>();
|
||||
chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeigborChunkRadius0).distinct().forEach(radius -> {
|
||||
if (radius == -1) //ignore ChunkStatus.EMPTY
|
||||
return;
|
||||
Long2ObjectOpenHashMap<List<IChunkAccess>> map = new Long2ObjectOpenHashMap<>();
|
||||
for (Long xz : chunkCoordsForRadius.get(radius)) {
|
||||
int x = MathMan.unpairIntX(xz);
|
||||
int z = MathMan.unpairIntY(xz);
|
||||
List<IChunkAccess> l = new ArrayList<>((radius + 1 + radius) * (radius + 1 + radius));
|
||||
for (int zz = z - radius; zz <= z + radius; zz++) { //order is important, first z then x
|
||||
for (int xx = x - radius; xx <= x + radius; xx++) {
|
||||
l.add(protoChunks.get(MathMan.pairInt(xx, zz)));
|
||||
}
|
||||
}
|
||||
map.put(xz, l);
|
||||
}
|
||||
worldlimits.put(radius, map);
|
||||
});
|
||||
|
||||
//run generation tasks exluding FULL chunk status
|
||||
for (Map.Entry<ChunkStatus, Concurrency> entry : chunkStati.entrySet()) {
|
||||
ChunkStatus chunkStatus = entry.getKey();
|
||||
int radius = chunkStatus.requiredNeigborChunkRadius0();
|
||||
|
||||
List<Long> coords = chunkCoordsForRadius.get(radius);
|
||||
if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) {
|
||||
SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> tasks = getChunkStatusTaskRows(coords, radius);
|
||||
for (ConcurrentTasks<SequentialTasks<Long>> para : tasks) {
|
||||
List scheduled = new ArrayList<>(tasks.size());
|
||||
for (SequentialTasks<Long> row : para) {
|
||||
scheduled.add((Callable) () -> {
|
||||
for (Long xz : row) {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
try {
|
||||
List<Future> futures = executor.invokeAll(scheduled);
|
||||
for (Future future : futures) {
|
||||
future.get();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) {
|
||||
// every chunk can be processed individually
|
||||
List scheduled = new ArrayList(coords.size());
|
||||
for (long xz : coords) {
|
||||
scheduled.add((Callable) () -> {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
try {
|
||||
List<Future> futures = executor.invokeAll(scheduled);
|
||||
for (Future future : futures) {
|
||||
future.get();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else { // Concurrency.NONE or generateConcurrent == false
|
||||
// run sequential
|
||||
for (long xz : coords) {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//convert to proper chunks
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) {
|
||||
ProtoChunk proto = protoChunks.get(xz);
|
||||
chunks.put(xz, createChunk(proto));
|
||||
}
|
||||
|
||||
//final chunkstatus
|
||||
ChunkStatus FULL = getFullChunkStatus();
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) { //FULL.requiredNeighbourChunkRadius() == 0!
|
||||
Chunk chunk = chunks.get(xz);
|
||||
FULL.processChunkSave(xz, Arrays.asList(chunk));
|
||||
}
|
||||
|
||||
//populate
|
||||
List<BlockPopulator> populators = getBlockPopulators();
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) {
|
||||
int x = MathMan.unpairIntX(xz);
|
||||
int z = MathMan.unpairIntY(xz);
|
||||
|
||||
//prepare chunk seed
|
||||
Random random = getChunkRandom(seed, x, z);
|
||||
|
||||
//actually populate
|
||||
Chunk c = chunks.get(xz);
|
||||
populators.forEach(pop -> {
|
||||
populate(c, random, pop);
|
||||
});
|
||||
}
|
||||
|
||||
source = new SingleThreadQueueExtent();
|
||||
source.init(null, initSourceQueueCache(), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void copyToWorld() {
|
||||
//Setting Blocks
|
||||
long start = System.currentTimeMillis();
|
||||
boolean genbiomes = options.shouldRegenBiomes();
|
||||
boolean hasBiome = options.hasBiomeType();
|
||||
BiomeType biome = options.getBiomeType();
|
||||
for (BlockVector3 vec : region) {
|
||||
target.setBlock(vec, source.getBlock(vec));
|
||||
if (hasBiome) {
|
||||
target.setBiome(vec, biome);
|
||||
} else if (genbiomes) {
|
||||
target.setBiome(vec, source.getBiome(vec));
|
||||
}
|
||||
// realExtent.setSkyLight(vec, extent.getSkyLight(vec));
|
||||
// realExtent.setBlockLight(vec, extent.getBrightness(vec));
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup0() {
|
||||
if (executor != null) {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
//functions to be implemented by sub class
|
||||
/**
|
||||
* <p>Implement the preparation process in here. DO NOT instanciate any variable here that require the cleanup function. This function is for gathering further information before initializing a new
|
||||
* world.</p>
|
||||
*
|
||||
* <p>Fields required to be initialized: chunkStati, seed</p>
|
||||
* <p>For chunkStati also see {code ChunkStatusWrapper}.</p>
|
||||
*
|
||||
* @return whether or not the preparation process was successful
|
||||
*/
|
||||
protected abstract boolean prepare();
|
||||
|
||||
/**
|
||||
* Implement the creation of the seperate world in here.
|
||||
*
|
||||
* Fields required to be initialized: generateConcurrent
|
||||
*
|
||||
* @return true if everything went fine, otherwise false. When false is returned the Regenerator halts the regeneration process and calls the cleanup function.
|
||||
* @throws java.lang.Exception When the implementation of this method throws and exception the Regenerator halts the regeneration process and calls the cleanup function.
|
||||
*/
|
||||
protected abstract boolean initNewWorld() throws Exception;
|
||||
|
||||
/**
|
||||
* Implement the cleanup of all the mess that is created during the regeneration process (initNewWorld() and generate()).This function must not throw any exceptions.
|
||||
*/
|
||||
protected abstract void cleanup();
|
||||
|
||||
//functions to implement by sub class - regenate related
|
||||
/**
|
||||
* Implement the initialization of a {@code ProtoChunk} here.
|
||||
*
|
||||
* @param x the x coorinate of the {@code ProtoChunk} to create
|
||||
* @param z the z coorinate of the {@code ProtoChunk} to create
|
||||
* @return an initialized {@code ProtoChunk}
|
||||
*/
|
||||
protected abstract ProtoChunk createProtoChunk(int x, int z);
|
||||
|
||||
/**
|
||||
* Implement the convertion of a {@code ProtoChunk} to a {@code Chunk} here.
|
||||
*
|
||||
* @param protoChunk the {@code ProtoChunk} to be converted to a {@code Chunk}
|
||||
* @return the converted {@code Chunk}
|
||||
*/
|
||||
protected abstract Chunk createChunk(ProtoChunk protoChunk);
|
||||
|
||||
/**
|
||||
* Return the {@code ChunkStatus.FULL} here.
|
||||
* ChunkStatus.FULL is the last step of vanilla chunk generation.
|
||||
*
|
||||
* @return {@code ChunkStatus.FULL}
|
||||
*/
|
||||
protected abstract ChunkStatus getFullChunkStatus();
|
||||
|
||||
/**
|
||||
* Return a list of {@code BlockPopulator} used to populate the original world here.
|
||||
*
|
||||
* @return {@code ChunkStatus.FULL}
|
||||
*/
|
||||
protected abstract List<BlockPopulator> getBlockPopulators();
|
||||
|
||||
/**
|
||||
* Implement the population of the {@code Chunk} with the given chunk random and {@code BlockPopulator} here.
|
||||
*
|
||||
* @param chunk the {@code Chunk} to populate
|
||||
* @param random the chunk random to use for population
|
||||
* @param pop the {@code BlockPopulator} to use
|
||||
*/
|
||||
protected abstract void populate(Chunk chunk, Random random, BlockPopulator pop);
|
||||
|
||||
/**
|
||||
* Implement the initialization an {@code IChunkCache<IChunkGet>} here. Use will need the {@code getChunkAt} function
|
||||
* @return an initialized {@code IChunkCache<IChunkGet>}
|
||||
*/
|
||||
protected abstract IChunkCache<IChunkGet> initSourceQueueCache();
|
||||
|
||||
//algorithms
|
||||
private List<Long> getChunkCoordsRegen(Region region, int border) { //needs to be square num of chunks
|
||||
BlockVector3 oldMin = region.getMinimumPoint();
|
||||
BlockVector3 newMin = BlockVector3.at((oldMin.getX() >> 4 << 4) - border * 16, oldMin.getY(), (oldMin.getZ() >> 4 << 4) - border * 16);
|
||||
BlockVector3 oldMax = region.getMaximumPoint();
|
||||
BlockVector3 newMax = BlockVector3.at((oldMax.getX() >> 4 << 4) + (border + 1) * 16 - 1, oldMax.getY(), (oldMax.getZ() >> 4 << 4) + (border + 1) * 16 - 1);
|
||||
Region adjustedRegion = new CuboidRegion(newMin, newMax);
|
||||
return adjustedRegion.getChunks().stream()
|
||||
.map(c -> BlockVector2.at(c.getX(), c.getZ()))
|
||||
.sorted(Comparator.<BlockVector2>comparingInt(c -> c.getZ()).thenComparingInt(c -> c.getX())) //needed for RegionLimitedWorldAccess
|
||||
.map(c -> MathMan.pairInt(c.getX(), c.getZ()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of chunkcoord rows that may be executed concurrently
|
||||
*
|
||||
* @param allcoords the coords that should be sorted into rows, must be sorted by z and x
|
||||
* @param requiredNeighborChunkRadius the radius of neighbor chunks that may not be written to conccurently (ChunkStatus.requiredNeighborRadius)
|
||||
* @return a list of chunkcoords rows that may be executed concurrently
|
||||
*/
|
||||
private SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> getChunkStatusTaskRows(List<Long> allcoords, int requiredNeighborChunkRadius) {
|
||||
int requiredneighbors = Math.max(0, requiredNeighborChunkRadius);
|
||||
|
||||
int minx = allcoords.isEmpty() ? 0 : MathMan.unpairIntX(allcoords.get(0));
|
||||
int maxx = allcoords.isEmpty() ? 0 : MathMan.unpairIntX(allcoords.get(allcoords.size() - 1));
|
||||
int minz = allcoords.isEmpty() ? 0 : MathMan.unpairIntY(allcoords.get(0));
|
||||
int maxz = allcoords.isEmpty() ? 0 : MathMan.unpairIntY(allcoords.get(allcoords.size() - 1));
|
||||
SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> tasks;
|
||||
if (maxz - minz > maxx - minx) {
|
||||
int numlists = Math.min(requiredneighbors * 2 + 1, maxx - minx + 1);
|
||||
|
||||
Int2ObjectOpenHashMap<SequentialTasks<Long>> byx = new Int2ObjectOpenHashMap();
|
||||
int expectedListLength = (allcoords.size() + 1) / (maxx - minx);
|
||||
|
||||
//init lists
|
||||
for (int i = minx; i <= maxx; i++) {
|
||||
byx.put(i, new SequentialTasks(expectedListLength));
|
||||
}
|
||||
|
||||
//sort into lists by x coord
|
||||
for (Long xz : allcoords) {
|
||||
byx.get(MathMan.unpairIntX(xz)).add(xz);
|
||||
}
|
||||
|
||||
//create parallel tasks
|
||||
tasks = new SequentialTasks(numlists);
|
||||
for (int offset = 0; offset < numlists; offset++) {
|
||||
ConcurrentTasks<SequentialTasks<Long>> para = new ConcurrentTasks((maxz - minz + 1) / numlists + 1);
|
||||
for (int i = 0; minx + i * numlists + offset <= maxx; i++)
|
||||
para.add(byx.get(minx + i * numlists + offset));
|
||||
tasks.add(para);
|
||||
}
|
||||
} else {
|
||||
int numlists = Math.min(requiredneighbors * 2 + 1, maxz - minz + 1);
|
||||
|
||||
Int2ObjectOpenHashMap<SequentialTasks<Long>> byz = new Int2ObjectOpenHashMap();
|
||||
int expectedListLength = (allcoords.size() + 1) / (maxz - minz);
|
||||
|
||||
//init lists
|
||||
for (int i = minz; i <= maxz; i++) {
|
||||
byz.put(i, new SequentialTasks(expectedListLength));
|
||||
}
|
||||
|
||||
//sort into lists by x coord
|
||||
for (Long xz : allcoords) {
|
||||
byz.get(MathMan.unpairIntY(xz)).add(xz);
|
||||
}
|
||||
|
||||
//create parallel tasks
|
||||
tasks = new SequentialTasks(numlists);
|
||||
for (int offset = 0; offset < numlists; offset++) {
|
||||
ConcurrentTasks<SequentialTasks<Long>> para = new ConcurrentTasks((maxx - minx + 1) / numlists + 1);
|
||||
for (int i = 0; minz + i * numlists + offset <= maxz; i++)
|
||||
para.add(byz.get(minz + i * numlists + offset));
|
||||
tasks.add(para);
|
||||
}
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private static Random getChunkRandom(long worldseed, int x, int z) {
|
||||
Random random = new Random();
|
||||
random.setSeed(worldseed);
|
||||
long xRand = random.nextLong() / 2L * 2L + 1L;
|
||||
long zRand = random.nextLong() / 2L * 2L + 1L;
|
||||
random.setSeed((long) x * xRand + (long) z * zRand ^ worldseed);
|
||||
return random;
|
||||
}
|
||||
|
||||
//classes
|
||||
/**
|
||||
* This class is used to wrap the ChunkStatus of the current Minecraft implementation and as the implementation to execute a chunk generation step.
|
||||
* @param <IChunkAccess> the IChunkAccess class of the current Minecraft implementation
|
||||
*/
|
||||
public static abstract class ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
/**
|
||||
* Return the required neighbor chunk radius the wrapped {@code ChunkStatus} requires.
|
||||
*
|
||||
* @return the radius of required neighbor chunks
|
||||
*/
|
||||
public abstract int requiredNeigborChunkRadius();
|
||||
|
||||
int requiredNeigborChunkRadius0() {
|
||||
return Math.max(0, requiredNeigborChunkRadius());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the wrapped {@code ChunkStatus}.
|
||||
*
|
||||
* @return the radius of required neighbor chunks
|
||||
*/
|
||||
public abstract String name();
|
||||
|
||||
/**
|
||||
* Return the name of the wrapped {@code ChunkStatus}.
|
||||
*
|
||||
* @param xz represents the chunk coordinates of the chunk to process as denoted by {@code MathMan}
|
||||
* @param accessibleChunks a list of chunks that will be used during the execution of the wrapped {@code ChunkStatus}.
|
||||
* This list is order in the correct order required by the {@code ChunkStatus}, unless Mojang suddenly decides to do things differently.
|
||||
*/
|
||||
public abstract void processChunk(Long xz, List<IChunkAccess> accessibleChunks);
|
||||
|
||||
void processChunkSave(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
try {
|
||||
processChunk(xz, accessibleChunks);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error while running " + name() + " on chunk " + MathMan.unpairIntX(xz) + "/" + MathMan.unpairIntY(xz), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Concurrency {
|
||||
FULL,
|
||||
RADIUS,
|
||||
NONE
|
||||
}
|
||||
|
||||
public static class SequentialTasks<T> extends Tasks<T> {
|
||||
|
||||
public SequentialTasks(int expectedsize) {
|
||||
super(expectedsize);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConcurrentTasks<T> extends Tasks<T> {
|
||||
|
||||
public ConcurrentTasks(int expectedsize) {
|
||||
super(expectedsize);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Tasks<T> implements Iterable<T> {
|
||||
|
||||
private final List<T> tasks;
|
||||
|
||||
public Tasks(int expectedsize) {
|
||||
tasks = new ArrayList(expectedsize);
|
||||
}
|
||||
|
||||
public void add(T task) {
|
||||
tasks.add(task);
|
||||
}
|
||||
|
||||
public List<T> list() {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return tasks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return tasks.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return tasks.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class SimpleBukkitAdapter extends CachedBukkitAdapter {
|
||||
private BlockData[][] blockDataCache;
|
||||
|
||||
private boolean init() {
|
||||
if (blockDataCache != null) {
|
||||
return false;
|
||||
}
|
||||
this.blockDataCache = new BlockData[BlockTypes.size()][];
|
||||
blockDataCache[0] = new BlockData[] {Material.AIR.createBlockData()};
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit BlockData from a WorldEdit BlockStateHolder
|
||||
*
|
||||
* @param block The WorldEdit BlockStateHolder
|
||||
* @return The Bukkit BlockData
|
||||
*/
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B block) {
|
||||
try {
|
||||
checkNotNull(block);
|
||||
int typeId = block.getInternalBlockTypeId();
|
||||
BlockData[] dataCache = blockDataCache[typeId];
|
||||
if (dataCache == null) {
|
||||
BlockType type = BlockTypes.get(typeId);
|
||||
blockDataCache[typeId] = dataCache = new BlockData[type.getMaxStateId() + 1];
|
||||
}
|
||||
int propId = block.getInternalPropertiesId();
|
||||
BlockData blockData = dataCache[propId];
|
||||
if (blockData == null) {
|
||||
dataCache[propId] = blockData = Bukkit.createBlockData(block.getAsString());
|
||||
}
|
||||
return blockData;
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return adapt(block);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,450 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BlockMaterial_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitAdapter_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitGetBlocks_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.FAWEWorldNativeAccess_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.MapChunkUtil_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_15_R2;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_15_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_15_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.IRegistry;
|
||||
import net.minecraft.server.v1_15_R1.ItemStack;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_15_R1.NBTBase;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_15_R2 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_15_R2() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_15_R2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_15_2(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_15_2(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_15_2) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_15_2) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_15_2(this,
|
||||
new WeakReference<>(((CraftWorld) world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) state.getMaterial();
|
||||
IBlockData mcState = material.getCraftBlockData().getState();
|
||||
return OptionalInt.of(Block.REGISTRY_ID.getId(mcState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
CraftBlockData cbd = ((CraftBlockData) blockData);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_15_2 mapUtil = new MapChunkUtil_1_15_2();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_15_2.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ());
|
||||
if (map != null && map.hasBeenLoaded()) {
|
||||
boolean flag = false;
|
||||
PlayerChunk.d players = map.players;
|
||||
Stream<EntityPlayer> stream = players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag);
|
||||
|
||||
EntityPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
|
||||
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
|
||||
.forEach(entityPlayer -> {
|
||||
synchronized (packet) {
|
||||
PacketPlayOutMapChunk nmsPacket = (PacketPlayOutMapChunk) packet.getNativePacket();
|
||||
if (nmsPacket == null) {
|
||||
nmsPacket = mapUtil.create( this, packet);
|
||||
packet.setNativePacket(nmsPacket);
|
||||
}
|
||||
try {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(true);
|
||||
entityPlayer.playerConnection.sendPacket(nmsPacket);
|
||||
} finally {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_15_2) {
|
||||
return ((LazyCompoundTag_1_15_2) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_15_R2(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_15_2(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(BukkitAdapter.adapt(biome));
|
||||
return IRegistry.BIOME.a(base);
|
||||
}
|
||||
}
|
@ -1,452 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser 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 Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BlockMaterial_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BukkitAdapter_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BukkitGetBlocks_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.FAWEWorldNativeAccess_1_16_R1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.MapChunkUtil_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_16_R1;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R1.Entity;
|
||||
import net.minecraft.server.v1_16_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_16_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.IRegistry;
|
||||
import net.minecraft.server.v1_16_R1.ItemStack;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_16_R1 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_16_R1() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_16_R1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_16_1(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_16_1(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_16_1) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_16_1) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_16_R1(this,
|
||||
new WeakReference<>(((CraftWorld)world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
|
||||
IBlockData mcState = material.getCraftBlockData().getState();
|
||||
return OptionalInt.of(Block.REGISTRY_ID.getId(mcState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
CraftBlockData cbd = ((CraftBlockData) blockData);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_16_1 mapUtil = new MapChunkUtil_1_16_1();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_16_1.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ());
|
||||
if (map != null && map.hasBeenLoaded()) {
|
||||
boolean flag = false;
|
||||
PlayerChunk.d players = map.players;
|
||||
Stream<EntityPlayer> stream = players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag);
|
||||
|
||||
EntityPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
|
||||
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
|
||||
.forEach(entityPlayer -> {
|
||||
synchronized (packet) {
|
||||
PacketPlayOutMapChunk nmsPacket = (PacketPlayOutMapChunk) packet.getNativePacket();
|
||||
if (nmsPacket == null) {
|
||||
nmsPacket = mapUtil.create( this, packet);
|
||||
packet.setNativePacket(nmsPacket);
|
||||
}
|
||||
try {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(true);
|
||||
entityPlayer.playerConnection.sendPacket(nmsPacket);
|
||||
} finally {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_16_1) {
|
||||
return ((LazyCompoundTag_1_16_1) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_16_R1(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_16_1(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(BukkitAdapter.adapt(biome));
|
||||
return IRegistry.BIOME.a(base);
|
||||
}
|
||||
}
|
@ -1,453 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BlockMaterial_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BukkitAdapter_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BukkitGetBlocks_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.FAWEWorldNativeAccess_1_16_R2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.MapChunkUtil_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_16_R2;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R2.Entity;
|
||||
import net.minecraft.server.v1_16_R2.EntityPlayer;
|
||||
import net.minecraft.server.v1_16_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.ItemStack;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_16_R2 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_16_R2() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_16_R2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_16_2(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_16_2(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_16_2) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_16_2) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_16_R2(this,
|
||||
new WeakReference<>(((CraftWorld)world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) state.getMaterial();
|
||||
IBlockData mcState = material.getCraftBlockData().getState();
|
||||
return OptionalInt.of(Block.REGISTRY_ID.getId(mcState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
CraftBlockData cbd = ((CraftBlockData) blockData);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_16_2 mapUtil = new MapChunkUtil_1_16_2();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_16_2.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ());
|
||||
if (map != null && map.hasBeenLoaded()) {
|
||||
boolean flag = false;
|
||||
PlayerChunk.d players = map.players;
|
||||
Stream<EntityPlayer> stream = players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag);
|
||||
|
||||
EntityPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
|
||||
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
|
||||
.forEach(entityPlayer -> {
|
||||
synchronized (packet) {
|
||||
PacketPlayOutMapChunk nmsPacket = (PacketPlayOutMapChunk) packet.getNativePacket();
|
||||
if (nmsPacket == null) {
|
||||
nmsPacket = mapUtil.create( this, packet);
|
||||
packet.setNativePacket(nmsPacket);
|
||||
}
|
||||
try {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(true);
|
||||
entityPlayer.playerConnection.sendPacket(nmsPacket);
|
||||
} finally {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_16_2) {
|
||||
return ((LazyCompoundTag_1_16_2) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_16_R2(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_16_2(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay), BukkitAdapter.adapt(biome));
|
||||
return MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay).a(base);
|
||||
}
|
||||
}
|
@ -1,454 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.BlockMaterial_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.BukkitAdapter_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.BukkitGetBlocks_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.FAWEWorldNativeAccess_1_16_R3;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.MapChunkUtil_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_16_R3;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R3.Entity;
|
||||
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||
import net.minecraft.server.v1_16_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.IRegistry;
|
||||
import net.minecraft.server.v1_16_R3.ItemStack;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R3.NBTBase;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.World;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_16_R3 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_16_R3() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_16_R3();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_16_5 material = (BlockMaterial_1_16_5) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_16_5(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_16_5(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_16_5) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_16_5) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_16_R3(this,
|
||||
new WeakReference<>(((CraftWorld)world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_16_5 material = (BlockMaterial_1_16_5) state.getMaterial();
|
||||
IBlockData mcState = material.getCraftBlockData().getState();
|
||||
return OptionalInt.of(Block.REGISTRY_ID.getId(mcState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
CraftBlockData cbd = ((CraftBlockData) blockData);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_16_5 material = (BlockMaterial_1_16_5) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_16_5 mapUtil = new MapChunkUtil_1_16_5();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_16_5.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ());
|
||||
if (map != null && map.hasBeenLoaded()) {
|
||||
boolean flag = false;
|
||||
PlayerChunk.d players = map.players;
|
||||
Stream<EntityPlayer> stream = players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag);
|
||||
|
||||
EntityPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
|
||||
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
|
||||
.forEach(entityPlayer -> {
|
||||
synchronized (packet) {
|
||||
PacketPlayOutMapChunk nmsPacket = (PacketPlayOutMapChunk) packet.getNativePacket();
|
||||
if (nmsPacket == null) {
|
||||
nmsPacket = mapUtil.create( this, packet);
|
||||
packet.setNativePacket(nmsPacket);
|
||||
}
|
||||
try {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(true);
|
||||
entityPlayer.playerConnection.sendPacket(nmsPacket);
|
||||
} finally {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_16_5) {
|
||||
return ((LazyCompoundTag_1_16_5) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_16_R3(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_16_5(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay), BukkitAdapter.adapt(biome));
|
||||
return MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay).a(base);
|
||||
}
|
||||
}
|
@ -1,513 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.regen;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitGetBlocks_1_15_2;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Regenerator;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_15_R1.Area;
|
||||
import net.minecraft.server.v1_15_R1.AreaContextTransformed;
|
||||
import net.minecraft.server.v1_15_R1.AreaFactory;
|
||||
import net.minecraft.server.v1_15_R1.AreaTransformer8;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeLayoutOverworldConfiguration;
|
||||
import net.minecraft.server.v1_15_R1.Biomes;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkConverter;
|
||||
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_15_R1.ChunkGenerator;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderFlat;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderGenerate;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderHell;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderTheEnd;
|
||||
import net.minecraft.server.v1_15_R1.ChunkStatus;
|
||||
import net.minecraft.server.v1_15_R1.DefinedStructureManager;
|
||||
import net.minecraft.server.v1_15_R1.GenLayer;
|
||||
import net.minecraft.server.v1_15_R1.GenLayers;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsEnd;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsFlat;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsNether;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsOverworld;
|
||||
import net.minecraft.server.v1_15_R1.IChunkAccess;
|
||||
import net.minecraft.server.v1_15_R1.IRegistry;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_15_R1.LinearCongruentialGenerator;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NoiseGeneratorPerlin;
|
||||
import net.minecraft.server.v1_15_R1.ProtoChunk;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import net.minecraft.server.v1_15_R1.WorldChunkManager;
|
||||
import net.minecraft.server.v1_15_R1.WorldChunkManagerOverworld;
|
||||
import net.minecraft.server.v1_15_R1.WorldData;
|
||||
import net.minecraft.server.v1_15_R1.WorldLoadListener;
|
||||
import net.minecraft.server.v1_15_R1.WorldNBTStorage;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import net.minecraft.server.v1_15_R1.WorldType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.generator.CustomChunkGenerator;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.util.CraftMagicNumbers;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
public class Regen_v1_15_R2 extends Regenerator<IChunkAccess, ProtoChunk, Chunk, Regen_v1_15_R2.ChunkStatusWrap> {
|
||||
|
||||
private static final Field serverWorldsField;
|
||||
private static final Field worldPaperConfigField;
|
||||
private static final Field flatBedrockField;
|
||||
private static final Field delegateField;
|
||||
private static final Field chunkProviderField;
|
||||
|
||||
//list of chunk stati in correct order without FULL
|
||||
private static final Map<ChunkStatus, Regenerator.Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
chunkStati.put(ChunkStatus.EMPTY, Regenerator.Concurrency.FULL); // radius -1, does nothing
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_REFERENCES, Regenerator.Concurrency.FULL); // radius 8, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.BIOMES, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.NOISE, Regenerator.Concurrency.RADIUS); // radius 8
|
||||
chunkStati.put(ChunkStatus.SURFACE, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.LIQUID_CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.FEATURES, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.LIGHT, Regenerator.Concurrency.FULL); // radius 1, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.SPAWN, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.HEIGHTMAPS, Regenerator.Concurrency.FULL); // radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
serverWorldsField.setAccessible(true);
|
||||
|
||||
Field tmpPaperConfigField = null;
|
||||
Field tmpFlatBedrockField = null;
|
||||
try { //only present on paper
|
||||
tmpPaperConfigField = World.class.getDeclaredField("paperConfig");
|
||||
tmpPaperConfigField.setAccessible(true);
|
||||
|
||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
||||
tmpFlatBedrockField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
tmpPaperConfigField = null;
|
||||
tmpFlatBedrockField = null;
|
||||
}
|
||||
worldPaperConfigField = tmpPaperConfigField;
|
||||
flatBedrockField = tmpFlatBedrockField;
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkProviderField = World.class.getDeclaredField("chunkProvider");
|
||||
chunkProviderField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//runtime
|
||||
private WorldServer originalNMSWorld;
|
||||
private ChunkProviderServer originalChunkProvider;
|
||||
private WorldServer freshNMSWorld;
|
||||
private ChunkProviderServer freshChunkProvider;
|
||||
private DefinedStructureManager structureManager;
|
||||
private LightEngineThreaded lightEngine;
|
||||
private ChunkGenerator generator;
|
||||
|
||||
private Path tempDir;
|
||||
|
||||
private boolean generateFlatBedrock = false;
|
||||
|
||||
public Regen_v1_15_R2(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
super(originalBukkitWorld, region, target, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepare() {
|
||||
this.originalNMSWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
||||
originalChunkProvider = originalNMSWorld.getChunkProvider();
|
||||
if (!(originalChunkProvider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//flat bedrock? (only on paper)
|
||||
try {
|
||||
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalNMSWorld));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
seed = options.getSeed().orElse(originalNMSWorld.getSeed());
|
||||
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initNewWorld() throws Exception {
|
||||
//world folder
|
||||
tempDir = java.nio.file.Files.createTempDirectory("WorldEditWorldGen");
|
||||
|
||||
//prepare for world init (see upstream implementation for reference)
|
||||
org.bukkit.World.Environment env = originalBukkitWorld.getEnvironment();
|
||||
org.bukkit.generator.ChunkGenerator gen = originalBukkitWorld.getGenerator();
|
||||
|
||||
MinecraftServer server = originalNMSWorld.getServer().getServer();
|
||||
WorldData newWorldData = new WorldData(originalNMSWorld.worldData.a((NBTTagCompound) null), server.dataConverterManager, CraftMagicNumbers.INSTANCE.getDataVersion(), (NBTTagCompound) null);
|
||||
newWorldData.setName("worldeditregentempworld");
|
||||
WorldNBTStorage saveHandler = new WorldNBTStorage(new File(tempDir.toUri()), originalNMSWorld.getDataManager().getDirectory().getName(), server, server.dataConverterManager);
|
||||
|
||||
//init world
|
||||
freshNMSWorld = Fawe.get().getQueueHandler().sync((Supplier<WorldServer>) () -> new WorldServer(server, server.executorService, saveHandler, newWorldData, originalNMSWorld.worldProvider.getDimensionManager(), originalNMSWorld.getMethodProfiler(), new RegenNoOpWorldLoadListener(), env, gen) {
|
||||
@Override
|
||||
public void doTick(BooleanSupplier booleansupplier) { //no ticking
|
||||
}
|
||||
|
||||
private final BiomeBase singleBiome = options.hasBiomeType() ? IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId())) : null;
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int i, int k, int j) {
|
||||
if (options.hasBiomeType()) {
|
||||
return singleBiome;
|
||||
}
|
||||
return this.getChunkProvider().getChunkGenerator().getWorldChunkManager().getBiome(i, j, k);
|
||||
}
|
||||
}).get();
|
||||
freshNMSWorld.savingDisabled = true;
|
||||
removeWorldFromWorldsMap();
|
||||
newWorldData.checkName(originalNMSWorld.getWorldData().getName()); //rename to original world name
|
||||
|
||||
try { //flat bedrock (paper only)
|
||||
Object paperconf = worldPaperConfigField.get(freshNMSWorld);
|
||||
flatBedrockField.setBoolean(paperconf, generateFlatBedrock);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
DefinedStructureManager tmpStructureManager = saveHandler.f();
|
||||
freshChunkProvider = new ChunkProviderServer(freshNMSWorld, saveHandler.getDirectory(), server.aC(), tmpStructureManager, server.executorService, originalChunkProvider.chunkGenerator, freshNMSWorld.spigotConfig.viewDistance, new RegenNoOpWorldLoadListener(), () -> freshNMSWorld.getWorldPersistentData()) {
|
||||
// redirect to our protoChunks list
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int x, int z, ChunkStatus chunkstatus, boolean flag) {
|
||||
return getProtoChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
chunkProviderField.set(freshNMSWorld, freshChunkProvider);
|
||||
|
||||
//generator
|
||||
if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderFlat) {
|
||||
GeneratorSettingsFlat generatorSettingFlat = (GeneratorSettingsFlat) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
generator = new ChunkProviderFlat(freshNMSWorld, originalChunkProvider.getChunkGenerator().getWorldChunkManager(), generatorSettingFlat);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderGenerate) { //overworld
|
||||
GeneratorSettingsOverworld settings = (GeneratorSettingsOverworld) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
WorldChunkManager chunkManager = originalChunkProvider.getChunkGenerator().getWorldChunkManager();
|
||||
if (chunkManager instanceof WorldChunkManagerOverworld) { //should always be true
|
||||
chunkManager = fastOverWorldChunkManager(chunkManager);
|
||||
}
|
||||
generator = new ChunkProviderGenerate(freshNMSWorld, chunkManager, settings);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderHell) { //nether
|
||||
GeneratorSettingsNether settings = (GeneratorSettingsNether) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
generator = new ChunkProviderHell(freshNMSWorld, originalChunkProvider.getChunkGenerator().getWorldChunkManager(), settings);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderTheEnd) { //end
|
||||
GeneratorSettingsEnd settings = (GeneratorSettingsEnd) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
generator = new ChunkProviderTheEnd(freshNMSWorld, originalChunkProvider.getChunkGenerator().getWorldChunkManager(), settings);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof CustomChunkGenerator) {
|
||||
ChunkGenerator delegate = (ChunkGenerator) delegateField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = delegate;
|
||||
} else {
|
||||
System.out.println("Unsupported generator type " + originalChunkProvider.getChunkGenerator().getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (originalNMSWorld.generator != null) {
|
||||
// wrap custom world generator
|
||||
generator = new CustomChunkGenerator(freshNMSWorld, originalNMSWorld.generator);
|
||||
generateConcurrent = originalNMSWorld.generator.isParallelCapable();
|
||||
}
|
||||
|
||||
//lets start then
|
||||
structureManager = tmpStructureManager;
|
||||
lightEngine = freshChunkProvider.getLightEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
//shutdown chunk provider
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
freshChunkProvider.close(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//remove world from server
|
||||
try {
|
||||
removeWorldFromWorldsMap();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//delete directory
|
||||
try {
|
||||
SafeFiles.tryHardToDeleteDir(tempDir);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtoChunk createProtoChunk(int x, int z) {
|
||||
return new ProtoChunk(new ChunkCoordIntPair(x, z), ChunkConverter.a) {
|
||||
public boolean generateFlatBedrock() {
|
||||
return generateFlatBedrock;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chunk createChunk(ProtoChunk protoChunk) {
|
||||
return new Chunk(freshNMSWorld, protoChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkStatusWrap getFullChunkStatus() {
|
||||
return new ChunkStatusWrap(ChunkStatus.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlockPopulator> getBlockPopulators() {
|
||||
return originalNMSWorld.getWorld().getPopulators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Chunk chunk, Random random, BlockPopulator pop) {
|
||||
pop.populate(freshNMSWorld.getWorld(), random, chunk.bukkitChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||
return (chunkX, chunkZ) -> new BukkitGetBlocks_1_15_2(freshNMSWorld, chunkX, chunkZ) {
|
||||
@Override
|
||||
public Chunk ensureLoaded(World nmsWorld, int x, int z) {
|
||||
return getChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected class ChunkStatusWrap extends Regenerator.ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
private final ChunkStatus chunkStatus;
|
||||
|
||||
public ChunkStatusWrap(ChunkStatus chunkStatus) {
|
||||
this.chunkStatus = chunkStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requiredNeigborChunkRadius() {
|
||||
return chunkStatus.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processChunk(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
chunkStatus.a(freshNMSWorld,
|
||||
generator,
|
||||
structureManager,
|
||||
lightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks);
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private void removeWorldFromWorldsMap() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||
map.remove("worldeditregentempworld");
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WorldChunkManager fastOverWorldChunkManager(WorldChunkManager chunkManager) throws Exception {
|
||||
Field genLayerField = WorldChunkManagerOverworld.class.getDeclaredField("d");
|
||||
genLayerField.setAccessible(true);
|
||||
Field areaLazyField = GenLayer.class.getDeclaredField("b");
|
||||
areaLazyField.setAccessible(true);
|
||||
Method initAreaFactoryMethod = GenLayers.class.getDeclaredMethod("a", WorldType.class, GeneratorSettingsOverworld.class, LongFunction.class);
|
||||
initAreaFactoryMethod.setAccessible(true);
|
||||
|
||||
//init new WorldChunkManagerOverworld
|
||||
BiomeLayoutOverworldConfiguration biomeconfig = new BiomeLayoutOverworldConfiguration(freshNMSWorld.getWorldData())
|
||||
.a((GeneratorSettingsOverworld) originalChunkProvider.getChunkGenerator().getSettings());
|
||||
AreaFactory<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) initAreaFactoryMethod.invoke(null, biomeconfig.b(), biomeconfig.c(), (LongFunction) (l -> new FastWorldGenContextArea(seed, l)));
|
||||
if (options.hasBiomeType()) {
|
||||
BiomeBase biome = IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId()));
|
||||
chunkManager = new SingleBiomeWorldChunkManagerOverworld(biome);
|
||||
} else {
|
||||
chunkManager = new WorldChunkManagerOverworld(biomeconfig);
|
||||
//replace genlayer
|
||||
genLayerField.set(chunkManager, new FastGenLayer(factory));
|
||||
}
|
||||
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
private static class SingleBiomeWorldChunkManagerOverworld extends WorldChunkManager {
|
||||
|
||||
private final BiomeBase biome;
|
||||
|
||||
public SingleBiomeWorldChunkManagerOverworld(BiomeBase biome) {
|
||||
super(ImmutableSet.of(biome));
|
||||
this.biome = biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(int i, int i1, int i2) {
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastWorldGenContextArea implements AreaContextTransformed<FastAreaLazy> {
|
||||
|
||||
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
|
||||
private final NoiseGeneratorPerlin perlinNoise;
|
||||
private final long magicrandom;
|
||||
private final ConcurrentHashMap<Long, Long> map = new ConcurrentHashMap<>(); //needed for multithreaded generation
|
||||
|
||||
public FastWorldGenContextArea(long seed, long lconst) {
|
||||
this.magicrandom = mix(seed, lconst);
|
||||
this.perlinNoise = new NoiseGeneratorPerlin(new Random(seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAreaLazy a(AreaTransformer8 var0) {
|
||||
return new FastAreaLazy(sharedAreaMap, var0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(long x, long z) {
|
||||
long l = this.magicrandom;
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
this.map.put(Thread.currentThread().getId(), l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int y) {
|
||||
long tid = Thread.currentThread().getId();
|
||||
long e = this.map.computeIfAbsent(tid, i -> 0L);
|
||||
int mod = (int) Math.floorMod(e >> 24L, (long) y);
|
||||
this.map.put(tid, LinearCongruentialGenerator.a(e, this.magicrandom));
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoiseGeneratorPerlin b() {
|
||||
return this.perlinNoise;
|
||||
}
|
||||
|
||||
private static long mix(long seed, long lconst) {
|
||||
long l1 = lconst;
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
long l2 = seed;
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
return l2;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastGenLayer extends GenLayer {
|
||||
|
||||
private final FastAreaLazy areaLazy;
|
||||
|
||||
public FastGenLayer(AreaFactory<FastAreaLazy> factory) throws Exception {
|
||||
super(() -> null);
|
||||
this.areaLazy = factory.make();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int x, int z) {
|
||||
BiomeBase biome = IRegistry.BIOME.fromId(this.areaLazy.a(x, z));
|
||||
if (biome == null)
|
||||
return Biomes.b;
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastAreaLazy implements Area {
|
||||
|
||||
private final AreaTransformer8 transformer;
|
||||
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a syncronized context
|
||||
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
|
||||
private final ConcurrentHashMap<Long, Integer> sharedMap;
|
||||
|
||||
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, AreaTransformer8 transformer) {
|
||||
this.sharedMap = sharedMap;
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int x, int z) {
|
||||
long zx = ChunkCoordIntPair.pair(x, z);
|
||||
return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegenNoOpWorldLoadListener implements WorldLoadListener {
|
||||
|
||||
private RegenNoOpWorldLoadListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair, @Nullable ChunkStatus chunkStatus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkRadius(int i) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,559 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.regen;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BukkitGetBlocks_1_16_1;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Regenerator;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_16_R1.Area;
|
||||
import net.minecraft.server.v1_16_R1.AreaContextTransformed;
|
||||
import net.minecraft.server.v1_16_R1.AreaFactory;
|
||||
import net.minecraft.server.v1_16_R1.AreaTransformer8;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.Biomes;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkConverter;
|
||||
import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R1.ChunkGenerator;
|
||||
import net.minecraft.server.v1_16_R1.ChunkGeneratorAbstract;
|
||||
import net.minecraft.server.v1_16_R1.ChunkProviderFlat;
|
||||
import net.minecraft.server.v1_16_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R1.ChunkStatus;
|
||||
import net.minecraft.server.v1_16_R1.Convertable;
|
||||
import net.minecraft.server.v1_16_R1.DefinedStructureManager;
|
||||
import net.minecraft.server.v1_16_R1.DynamicOpsNBT;
|
||||
import net.minecraft.server.v1_16_R1.GenLayer;
|
||||
import net.minecraft.server.v1_16_R1.GenLayers;
|
||||
import net.minecraft.server.v1_16_R1.GeneratorSettingBase;
|
||||
import net.minecraft.server.v1_16_R1.GeneratorSettings;
|
||||
import net.minecraft.server.v1_16_R1.GeneratorSettingsFlat;
|
||||
import net.minecraft.server.v1_16_R1.IChunkAccess;
|
||||
import net.minecraft.server.v1_16_R1.IRegistry;
|
||||
import net.minecraft.server.v1_16_R1.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_16_R1.LinearCongruentialGenerator;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NoiseGeneratorPerlin;
|
||||
import net.minecraft.server.v1_16_R1.ProtoChunk;
|
||||
import net.minecraft.server.v1_16_R1.ResourceKey;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import net.minecraft.server.v1_16_R1.WorldChunkManager;
|
||||
import net.minecraft.server.v1_16_R1.WorldChunkManagerOverworld;
|
||||
import net.minecraft.server.v1_16_R1.WorldDataServer;
|
||||
import net.minecraft.server.v1_16_R1.WorldDimension;
|
||||
import net.minecraft.server.v1_16_R1.WorldLoadListener;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import net.minecraft.server.v1_16_R1.WorldSettings;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.generator.CustomChunkGenerator;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
public class Regen_v1_16_R1 extends Regenerator<IChunkAccess, ProtoChunk, Chunk, Regen_v1_16_R1.ChunkStatusWrap> {
|
||||
|
||||
private static final Field serverWorldsField;
|
||||
private static final Field worldPaperConfigField;
|
||||
private static final Field flatBedrockField;
|
||||
private static final Field generatorSettingBaseField;
|
||||
private static final Field generatorSettingFlatField;
|
||||
private static final Field delegateField;
|
||||
private static final Field chunkProviderField;
|
||||
|
||||
//list of chunk stati in correct order without FULL
|
||||
private static final Map<ChunkStatus, Regenerator.Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
chunkStati.put(ChunkStatus.EMPTY, Regenerator.Concurrency.FULL); // radius -1, does nothing
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_REFERENCES, Regenerator.Concurrency.FULL); // radius 8, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.BIOMES, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.NOISE, Regenerator.Concurrency.RADIUS); // radius 8
|
||||
chunkStati.put(ChunkStatus.SURFACE, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.LIQUID_CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.FEATURES, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.LIGHT, Regenerator.Concurrency.FULL); // radius 1, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.SPAWN, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.HEIGHTMAPS, Regenerator.Concurrency.FULL); // radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
serverWorldsField.setAccessible(true);
|
||||
|
||||
Field tmpPaperConfigField = null;
|
||||
Field tmpFlatBedrockField = null;
|
||||
try { //only present on paper
|
||||
tmpPaperConfigField = World.class.getDeclaredField("paperConfig");
|
||||
tmpPaperConfigField.setAccessible(true);
|
||||
|
||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
||||
tmpFlatBedrockField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
tmpPaperConfigField = null;
|
||||
tmpFlatBedrockField = null;
|
||||
}
|
||||
worldPaperConfigField = tmpPaperConfigField;
|
||||
flatBedrockField = tmpFlatBedrockField;
|
||||
|
||||
generatorSettingBaseField = ChunkGeneratorAbstract.class.getDeclaredField("h");
|
||||
generatorSettingBaseField.setAccessible(true);
|
||||
|
||||
generatorSettingFlatField = ChunkProviderFlat.class.getDeclaredField("e");
|
||||
generatorSettingFlatField.setAccessible(true);
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkProviderField = WorldServer.class.getDeclaredField("chunkProvider");
|
||||
chunkProviderField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//runtime
|
||||
private WorldServer originalNMSWorld;
|
||||
private ChunkProviderServer originalChunkProvider;
|
||||
private WorldServer freshNMSWorld;
|
||||
private ChunkProviderServer freshChunkProvider;
|
||||
private Convertable.ConversionSession session;
|
||||
private DefinedStructureManager structureManager;
|
||||
private LightEngineThreaded lightEngine;
|
||||
private ChunkGenerator generator;
|
||||
|
||||
private Path tempDir;
|
||||
|
||||
private boolean generateFlatBedrock = false;
|
||||
|
||||
public Regen_v1_16_R1(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
super(originalBukkitWorld, region, target, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepare() {
|
||||
this.originalNMSWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
||||
originalChunkProvider = originalNMSWorld.getChunkProvider();
|
||||
if (!(originalChunkProvider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//flat bedrock? (only on paper)
|
||||
try {
|
||||
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalNMSWorld));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
seed = options.getSeed().orElse(originalNMSWorld.getSeed());
|
||||
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initNewWorld() throws Exception {
|
||||
//world folder
|
||||
tempDir = java.nio.file.Files.createTempDirectory("WorldEditWorldGen");
|
||||
|
||||
//prepare for world init (see upstream implementation for reference)
|
||||
org.bukkit.World.Environment env = originalBukkitWorld.getEnvironment();
|
||||
org.bukkit.generator.ChunkGenerator gen = originalBukkitWorld.getGenerator();
|
||||
Convertable convertable = Convertable.a(tempDir);
|
||||
ResourceKey<WorldDimension> worldDimKey = getWorldDimKey(env);
|
||||
session = convertable.c("worldeditregentempworld", worldDimKey);
|
||||
WorldDataServer originalWorldData = originalNMSWorld.worldDataServer;
|
||||
|
||||
MinecraftServer server = originalNMSWorld.getServer().getServer();
|
||||
WorldDataServer levelProperties = (WorldDataServer) server.getSaveData();
|
||||
GeneratorSettings newOpts = GeneratorSettings.a.encodeStart(DynamicOpsNBT.a, levelProperties.getGeneratorSettings()).flatMap(tag -> GeneratorSettings.a.parse(this.recursivelySetSeed(new Dynamic<>(DynamicOpsNBT.a, tag), seed, new HashSet<>()))).result().orElseThrow(() -> new IllegalStateException("Unable to map GeneratorOptions"));
|
||||
WorldSettings newWorldSettings = new WorldSettings("worldeditregentempworld", originalWorldData.b.getGameType(), originalWorldData.b.hardcore, originalWorldData.b.getDifficulty(), originalWorldData.b.e(), originalWorldData.b.getGameRules(), originalWorldData.b.g());
|
||||
WorldDataServer newWorldData = new WorldDataServer(newWorldSettings, newOpts, Lifecycle.stable());
|
||||
|
||||
//init world
|
||||
freshNMSWorld = Fawe.get().getQueueHandler().sync((Supplier<WorldServer>) () -> new WorldServer(server, server.executorService, session, newWorldData, originalNMSWorld.getDimensionKey(), originalNMSWorld.getTypeKey(), originalNMSWorld.getDimensionManager(), new RegenNoOpWorldLoadListener(), ((WorldDimension) newOpts.e().a(worldDimKey)).c(), originalNMSWorld.isDebugWorld(), seed, ImmutableList.of(), false, env, gen) {
|
||||
@Override
|
||||
public void doTick(BooleanSupplier booleansupplier) { //no ticking
|
||||
}
|
||||
|
||||
private final BiomeBase singleBiome = options.hasBiomeType() ? IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId())) : null;
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int i, int j, int k) {
|
||||
if (options.hasBiomeType()) {
|
||||
return singleBiome;
|
||||
}
|
||||
return this.getChunkProvider().getChunkGenerator().getWorldChunkManager().getBiome(i, j, k);
|
||||
}
|
||||
}).get();
|
||||
freshNMSWorld.savingDisabled = true;
|
||||
removeWorldFromWorldsMap();
|
||||
newWorldData.checkName(originalNMSWorld.worldDataServer.getName()); //rename to original world name
|
||||
|
||||
freshChunkProvider = new ChunkProviderServer(freshNMSWorld, session, server.getDataFixer(), server.getDefinedStructureManager(), server.executorService, originalChunkProvider.chunkGenerator, freshNMSWorld.spigotConfig.viewDistance, server.isSyncChunkWrites(), new RegenNoOpWorldLoadListener(), () -> server.D().getWorldPersistentData()) {
|
||||
// redirect to our protoChunks list
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int x, int z, ChunkStatus chunkstatus, boolean flag) {
|
||||
return getProtoChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
chunkProviderField.set(freshNMSWorld, freshChunkProvider);
|
||||
|
||||
//generator
|
||||
if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderFlat) {
|
||||
GeneratorSettingsFlat generatorSettingFlat = (GeneratorSettingsFlat) generatorSettingFlatField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = new ChunkProviderFlat(generatorSettingFlat);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkGeneratorAbstract) {
|
||||
GeneratorSettingBase generatorSettingBase = (GeneratorSettingBase) generatorSettingBaseField.get(originalChunkProvider.getChunkGenerator());
|
||||
WorldChunkManager chunkManager = originalChunkProvider.getChunkGenerator().getWorldChunkManager();
|
||||
if (chunkManager instanceof WorldChunkManagerOverworld) {
|
||||
chunkManager = fastOverWorldChunkManager(chunkManager);
|
||||
}
|
||||
generator = new ChunkGeneratorAbstract(chunkManager, seed, generatorSettingBase);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof CustomChunkGenerator) {
|
||||
ChunkGenerator delegate = (ChunkGenerator) delegateField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = delegate;
|
||||
} else {
|
||||
System.out.println("Unsupported generator type " + originalChunkProvider.getChunkGenerator().getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (originalNMSWorld.generator != null) {
|
||||
// wrap custom world generator
|
||||
generator = new CustomChunkGenerator(freshNMSWorld, generator, originalNMSWorld.generator);
|
||||
generateConcurrent = originalNMSWorld.generator.isParallelCapable();
|
||||
}
|
||||
|
||||
//lets start then
|
||||
structureManager = server.getDefinedStructureManager();
|
||||
lightEngine = freshChunkProvider.getLightEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//shutdown chunk provider
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
freshChunkProvider.close(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//remove world from server
|
||||
try {
|
||||
removeWorldFromWorldsMap();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//delete directory
|
||||
try {
|
||||
SafeFiles.tryHardToDeleteDir(tempDir);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtoChunk createProtoChunk(int x, int z) {
|
||||
return new ProtoChunk(new ChunkCoordIntPair(x, z), ChunkConverter.a) {
|
||||
public boolean generateFlatBedrock() {
|
||||
return generateFlatBedrock;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chunk createChunk(ProtoChunk protoChunk) {
|
||||
return new Chunk(freshNMSWorld, protoChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkStatusWrap getFullChunkStatus() {
|
||||
return new ChunkStatusWrap(ChunkStatus.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlockPopulator> getBlockPopulators() {
|
||||
return originalNMSWorld.getWorld().getPopulators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Chunk chunk, Random random, BlockPopulator pop) {
|
||||
pop.populate(freshNMSWorld.getWorld(), random, chunk.bukkitChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||
return (chunkX, chunkZ) -> new BukkitGetBlocks_1_16_1(freshNMSWorld, chunkX, chunkZ) {
|
||||
@Override
|
||||
public Chunk ensureLoaded(World nmsWorld, int x, int z) {
|
||||
return getChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected class ChunkStatusWrap extends Regenerator.ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
private final ChunkStatus chunkStatus;
|
||||
|
||||
public ChunkStatusWrap(ChunkStatus chunkStatus) {
|
||||
this.chunkStatus = chunkStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requiredNeigborChunkRadius() {
|
||||
return chunkStatus.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processChunk(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
chunkStatus.a(freshNMSWorld,
|
||||
generator,
|
||||
structureManager,
|
||||
lightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks);
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private void removeWorldFromWorldsMap() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||
map.remove("worldeditregentempworld");
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ResourceKey<WorldDimension> getWorldDimKey(org.bukkit.World.Environment env) {
|
||||
switch (env) {
|
||||
case NETHER:
|
||||
return WorldDimension.THE_NETHER;
|
||||
case THE_END:
|
||||
return WorldDimension.THE_END;
|
||||
case NORMAL:
|
||||
default:
|
||||
return WorldDimension.OVERWORLD;
|
||||
}
|
||||
}
|
||||
|
||||
private Dynamic<NBTBase> recursivelySetSeed(Dynamic<NBTBase> dynamic, long seed, Set<Dynamic<NBTBase>> seen) {
|
||||
return !seen.add(dynamic) ? dynamic : dynamic.updateMapValues((pair) -> {
|
||||
if (((Dynamic) pair.getFirst()).asString("").equals("seed")) {
|
||||
return pair.mapSecond((v) -> {
|
||||
return v.createLong(seed);
|
||||
});
|
||||
} else {
|
||||
return ((Dynamic) pair.getSecond()).getValue() instanceof NBTTagCompound ? pair.mapSecond((v) -> {
|
||||
return this.recursivelySetSeed((Dynamic) v, seed, seen);
|
||||
}) : pair;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WorldChunkManager fastOverWorldChunkManager(WorldChunkManager chunkManager) throws Exception {
|
||||
Field legacyBiomeInitLayerField = WorldChunkManagerOverworld.class.getDeclaredField("i");
|
||||
legacyBiomeInitLayerField.setAccessible(true);
|
||||
Field largeBiomesField = WorldChunkManagerOverworld.class.getDeclaredField("j");
|
||||
largeBiomesField.setAccessible(true);
|
||||
Field genLayerField = WorldChunkManagerOverworld.class.getDeclaredField("f");
|
||||
genLayerField.setAccessible(true);
|
||||
Field areaLazyField = GenLayer.class.getDeclaredField("b");
|
||||
areaLazyField.setAccessible(true);
|
||||
Method initAreaFactoryMethod = GenLayers.class.getDeclaredMethod("a", boolean.class, int.class, int.class, LongFunction.class);
|
||||
initAreaFactoryMethod.setAccessible(true);
|
||||
|
||||
//init new WorldChunkManagerOverworld
|
||||
boolean legacyBiomeInitLayer = legacyBiomeInitLayerField.getBoolean(chunkManager);
|
||||
boolean largeBiomes = largeBiomesField.getBoolean(chunkManager);
|
||||
|
||||
AreaFactory<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) initAreaFactoryMethod.invoke(null, legacyBiomeInitLayer, largeBiomes ? 6 : 4, 4, (LongFunction) (l -> new FastWorldGenContextArea(seed, l)));
|
||||
if (options.hasBiomeType()) {
|
||||
BiomeBase biome = IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId()));
|
||||
chunkManager = new SingleBiomeWorldChunkManagerOverworld(biome);
|
||||
} else {
|
||||
chunkManager = new WorldChunkManagerOverworld(seed, legacyBiomeInitLayer, largeBiomes);
|
||||
//replace genLayer
|
||||
genLayerField.set(chunkManager, new FastGenLayer(factory));
|
||||
}
|
||||
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
private static class SingleBiomeWorldChunkManagerOverworld extends WorldChunkManager {
|
||||
|
||||
private final BiomeBase biome;
|
||||
|
||||
public SingleBiomeWorldChunkManagerOverworld(BiomeBase biome) {
|
||||
super(Arrays.asList(biome));
|
||||
this.biome = biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Codec<? extends WorldChunkManager> a() {
|
||||
return WorldChunkManagerOverworld.e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(int i, int i1, int i2) {
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastWorldGenContextArea implements AreaContextTransformed<FastAreaLazy> {
|
||||
|
||||
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
|
||||
private final NoiseGeneratorPerlin perlinNoise;
|
||||
private final long magicrandom;
|
||||
private final ConcurrentHashMap<Long, Long> map = new ConcurrentHashMap<>(); //needed for multithreaded generation
|
||||
|
||||
public FastWorldGenContextArea(long seed, long lconst) {
|
||||
this.magicrandom = mix(seed, lconst);
|
||||
this.perlinNoise = new NoiseGeneratorPerlin(new Random(seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAreaLazy a(AreaTransformer8 var0) {
|
||||
return new FastAreaLazy(sharedAreaMap, var0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(long x, long z) {
|
||||
long l = this.magicrandom;
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
this.map.put(Thread.currentThread().getId(), l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int y) {
|
||||
long tid = Thread.currentThread().getId();
|
||||
long e = this.map.computeIfAbsent(tid, i -> 0L);
|
||||
int mod = (int) Math.floorMod(e >> 24L, (long) y);
|
||||
this.map.put(tid, LinearCongruentialGenerator.a(e, this.magicrandom));
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoiseGeneratorPerlin b() {
|
||||
return this.perlinNoise;
|
||||
}
|
||||
|
||||
private static long mix(long seed, long lconst) {
|
||||
long l1 = lconst;
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
long l2 = seed;
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
return l2;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastGenLayer extends GenLayer {
|
||||
|
||||
private final FastAreaLazy areaLazy;
|
||||
|
||||
public FastGenLayer(AreaFactory<FastAreaLazy> factory) throws Exception {
|
||||
super(() -> null);
|
||||
this.areaLazy = factory.make();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int x, int z) {
|
||||
BiomeBase biome = IRegistry.BIOME.fromId(this.areaLazy.a(x, z));
|
||||
if (biome == null)
|
||||
return Biomes.b;
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastAreaLazy implements Area {
|
||||
|
||||
private final AreaTransformer8 transformer;
|
||||
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a syncronized context
|
||||
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
|
||||
private final ConcurrentHashMap<Long, Integer> sharedMap;
|
||||
|
||||
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, AreaTransformer8 transformer) {
|
||||
this.sharedMap = sharedMap;
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int x, int z) {
|
||||
long zx = ChunkCoordIntPair.pair(x, z);
|
||||
return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegenNoOpWorldLoadListener implements WorldLoadListener {
|
||||
|
||||
private RegenNoOpWorldLoadListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair, @Nullable ChunkStatus chunkStatus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkRadius(int i) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,582 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.regen;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BukkitGetBlocks_1_16_2;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Regenerator;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_16_R2.Area;
|
||||
import net.minecraft.server.v1_16_R2.AreaContextTransformed;
|
||||
import net.minecraft.server.v1_16_R2.AreaFactory;
|
||||
import net.minecraft.server.v1_16_R2.AreaTransformer8;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeRegistry;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkConverter;
|
||||
import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R2.ChunkGenerator;
|
||||
import net.minecraft.server.v1_16_R2.ChunkGeneratorAbstract;
|
||||
import net.minecraft.server.v1_16_R2.ChunkProviderFlat;
|
||||
import net.minecraft.server.v1_16_R2.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R2.ChunkStatus;
|
||||
import net.minecraft.server.v1_16_R2.Convertable;
|
||||
import net.minecraft.server.v1_16_R2.DefinedStructureManager;
|
||||
import net.minecraft.server.v1_16_R2.DynamicOpsNBT;
|
||||
import net.minecraft.server.v1_16_R2.GenLayer;
|
||||
import net.minecraft.server.v1_16_R2.GenLayers;
|
||||
import net.minecraft.server.v1_16_R2.GeneratorSettingBase;
|
||||
import net.minecraft.server.v1_16_R2.GeneratorSettings;
|
||||
import net.minecraft.server.v1_16_R2.GeneratorSettingsFlat;
|
||||
import net.minecraft.server.v1_16_R2.IChunkAccess;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.IRegistryCustom;
|
||||
import net.minecraft.server.v1_16_R2.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_16_R2.LinearCongruentialGenerator;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NoiseGeneratorPerlin;
|
||||
import net.minecraft.server.v1_16_R2.ProtoChunk;
|
||||
import net.minecraft.server.v1_16_R2.RegistryGeneration;
|
||||
import net.minecraft.server.v1_16_R2.RegistryMaterials;
|
||||
import net.minecraft.server.v1_16_R2.RegistryReadOps;
|
||||
import net.minecraft.server.v1_16_R2.ResourceKey;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import net.minecraft.server.v1_16_R2.WorldChunkManager;
|
||||
import net.minecraft.server.v1_16_R2.WorldChunkManagerOverworld;
|
||||
import net.minecraft.server.v1_16_R2.WorldDataServer;
|
||||
import net.minecraft.server.v1_16_R2.WorldDimension;
|
||||
import net.minecraft.server.v1_16_R2.WorldLoadListener;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import net.minecraft.server.v1_16_R2.WorldSettings;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.generator.CustomChunkGenerator;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
public class Regen_v1_16_R2 extends Regenerator<IChunkAccess, ProtoChunk, Chunk, Regen_v1_16_R2.ChunkStatusWrap> {
|
||||
|
||||
private static final Field serverWorldsField;
|
||||
private static final Field worldPaperConfigField;
|
||||
private static final Field flatBedrockField;
|
||||
private static final Field generatorSettingBaseSupplierField;
|
||||
private static final Field generatorSettingFlatField;
|
||||
private static final Field delegateField;
|
||||
private static final Field chunkProviderField;
|
||||
|
||||
//list of chunk stati in correct order without FULL
|
||||
private static final Map<ChunkStatus, Regenerator.Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
chunkStati.put(ChunkStatus.EMPTY, Regenerator.Concurrency.FULL); // radius -1, does nothing
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_REFERENCES, Regenerator.Concurrency.FULL); // radius 8, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.BIOMES, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.NOISE, Regenerator.Concurrency.RADIUS); // radius 8
|
||||
chunkStati.put(ChunkStatus.SURFACE, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.LIQUID_CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.FEATURES, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.LIGHT, Regenerator.Concurrency.FULL); // radius 1, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.SPAWN, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.HEIGHTMAPS, Regenerator.Concurrency.FULL); // radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
serverWorldsField.setAccessible(true);
|
||||
|
||||
Field tmpPaperConfigField = null;
|
||||
Field tmpFlatBedrockField = null;
|
||||
try { //only present on paper
|
||||
tmpPaperConfigField = World.class.getDeclaredField("paperConfig");
|
||||
tmpPaperConfigField.setAccessible(true);
|
||||
|
||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
||||
tmpFlatBedrockField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
tmpPaperConfigField = null;
|
||||
tmpFlatBedrockField = null;
|
||||
}
|
||||
worldPaperConfigField = tmpPaperConfigField;
|
||||
flatBedrockField = tmpFlatBedrockField;
|
||||
|
||||
generatorSettingBaseSupplierField = ChunkGeneratorAbstract.class.getDeclaredField("h");
|
||||
generatorSettingBaseSupplierField.setAccessible(true);
|
||||
|
||||
generatorSettingFlatField = ChunkProviderFlat.class.getDeclaredField("e");
|
||||
generatorSettingFlatField.setAccessible(true);
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkProviderField = WorldServer.class.getDeclaredField("chunkProvider");
|
||||
chunkProviderField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//runtime
|
||||
private WorldServer originalNMSWorld;
|
||||
private ChunkProviderServer originalChunkProvider;
|
||||
private WorldServer freshNMSWorld;
|
||||
private ChunkProviderServer freshChunkProvider;
|
||||
private Convertable.ConversionSession session;
|
||||
private DefinedStructureManager structureManager;
|
||||
private LightEngineThreaded lightEngine;
|
||||
private ChunkGenerator generator;
|
||||
|
||||
private Path tempDir;
|
||||
|
||||
private boolean generateFlatBedrock = false;
|
||||
|
||||
public Regen_v1_16_R2(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
super(originalBukkitWorld, region, target, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepare() {
|
||||
this.originalNMSWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
||||
originalChunkProvider = originalNMSWorld.getChunkProvider();
|
||||
if (!(originalChunkProvider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//flat bedrock? (only on paper)
|
||||
try {
|
||||
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalNMSWorld));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
seed = options.getSeed().orElse(originalNMSWorld.getSeed());
|
||||
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initNewWorld() throws Exception {
|
||||
//world folder
|
||||
tempDir = java.nio.file.Files.createTempDirectory("WorldEditWorldGen");
|
||||
|
||||
//prepare for world init (see upstream implementation for reference)
|
||||
org.bukkit.World.Environment env = originalBukkitWorld.getEnvironment();
|
||||
org.bukkit.generator.ChunkGenerator gen = originalBukkitWorld.getGenerator();
|
||||
Convertable convertable = Convertable.a(tempDir);
|
||||
ResourceKey<WorldDimension> worldDimKey = getWorldDimKey(env);
|
||||
session = convertable.c("worldeditregentempworld", worldDimKey);
|
||||
WorldDataServer originalWorldData = originalNMSWorld.worldDataServer;
|
||||
|
||||
MinecraftServer server = originalNMSWorld.getServer().getServer();
|
||||
WorldDataServer levelProperties = (WorldDataServer) server.getSaveData();
|
||||
RegistryReadOps<NBTBase> nbtRegOps = RegistryReadOps.a(DynamicOpsNBT.a, server.dataPackResources.h(), IRegistryCustom.b());
|
||||
GeneratorSettings newOpts = GeneratorSettings.a.encodeStart(nbtRegOps, levelProperties.getGeneratorSettings()).flatMap(tag -> GeneratorSettings.a.parse(this.recursivelySetSeed(new Dynamic<>(nbtRegOps, tag), seed, new HashSet<>()))).result().orElseThrow(() -> new IllegalStateException("Unable to map GeneratorOptions"));
|
||||
WorldSettings newWorldSettings = new WorldSettings("worldeditregentempworld", originalWorldData.b.getGameType(), originalWorldData.b.hardcore, originalWorldData.b.getDifficulty(), originalWorldData.b.e(), originalWorldData.b.getGameRules(), originalWorldData.b.g());
|
||||
WorldDataServer newWorldData = new WorldDataServer(newWorldSettings, newOpts, Lifecycle.stable());
|
||||
|
||||
//init world
|
||||
freshNMSWorld = Fawe.get().getQueueHandler().sync((Supplier<WorldServer>) () -> new WorldServer(server, server.executorService, session, newWorldData, originalNMSWorld.getDimensionKey(), originalNMSWorld.getDimensionManager(), new RegenNoOpWorldLoadListener(), ((WorldDimension) newOpts.d().a(worldDimKey)).c(), originalNMSWorld.isDebugWorld(), seed, ImmutableList.of(), false, env, gen) {
|
||||
@Override
|
||||
public void doTick(BooleanSupplier booleansupplier) { //no ticking
|
||||
}
|
||||
|
||||
private final BiomeBase singleBiome = options.hasBiomeType() ? RegistryGeneration.WORLDGEN_BIOME.get(MinecraftKey.a(options.getBiomeType().getId())) : null;
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int i, int j, int k) {
|
||||
if (options.hasBiomeType()) {
|
||||
return singleBiome;
|
||||
}
|
||||
return this.getChunkProvider().getChunkGenerator().getWorldChunkManager().getBiome(i, j, k);
|
||||
}
|
||||
}).get();
|
||||
freshNMSWorld.savingDisabled = true;
|
||||
removeWorldFromWorldsMap();
|
||||
newWorldData.checkName(originalNMSWorld.worldDataServer.getName()); //rename to original world name
|
||||
|
||||
freshChunkProvider = new ChunkProviderServer(freshNMSWorld, session, server.getDataFixer(), server.getDefinedStructureManager(), server.executorService, originalChunkProvider.chunkGenerator, freshNMSWorld.spigotConfig.viewDistance, server.isSyncChunkWrites(), new RegenNoOpWorldLoadListener(), () -> server.E().getWorldPersistentData()) {
|
||||
// redirect to our protoChunks list
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int x, int z, ChunkStatus chunkstatus, boolean flag) {
|
||||
return getProtoChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
chunkProviderField.set(freshNMSWorld, freshChunkProvider);
|
||||
|
||||
//generator
|
||||
if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderFlat) {
|
||||
GeneratorSettingsFlat generatorSettingFlat = (GeneratorSettingsFlat) generatorSettingFlatField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = new ChunkProviderFlat(generatorSettingFlat);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkGeneratorAbstract) {
|
||||
Supplier<GeneratorSettingBase> generatorSettingBaseSupplier = (Supplier<GeneratorSettingBase>) generatorSettingBaseSupplierField.get(originalChunkProvider.getChunkGenerator());
|
||||
WorldChunkManager chunkManager = originalChunkProvider.getChunkGenerator().getWorldChunkManager();
|
||||
if (chunkManager instanceof WorldChunkManagerOverworld) {
|
||||
chunkManager = fastOverWorldChunkManager(chunkManager);
|
||||
}
|
||||
generator = new ChunkGeneratorAbstract(chunkManager, seed, generatorSettingBaseSupplier);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof CustomChunkGenerator) {
|
||||
ChunkGenerator delegate = (ChunkGenerator) delegateField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = delegate;
|
||||
} else {
|
||||
System.out.println("Unsupported generator type " + originalChunkProvider.getChunkGenerator().getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (originalNMSWorld.generator != null) {
|
||||
// wrap custom world generator
|
||||
generator = new CustomChunkGenerator(freshNMSWorld, generator, originalNMSWorld.generator);
|
||||
generateConcurrent = originalNMSWorld.generator.isParallelCapable();
|
||||
}
|
||||
|
||||
//lets start then
|
||||
structureManager = server.getDefinedStructureManager();
|
||||
lightEngine = freshChunkProvider.getLightEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//shutdown chunk provider
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
freshChunkProvider.close(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//remove world from server
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
removeWorldFromWorldsMap();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//delete directory
|
||||
try {
|
||||
SafeFiles.tryHardToDeleteDir(tempDir);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtoChunk createProtoChunk(int x, int z) {
|
||||
return new ProtoChunk(new ChunkCoordIntPair(x, z), ChunkConverter.a) {
|
||||
public boolean generateFlatBedrock() {
|
||||
return generateFlatBedrock;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chunk createChunk(ProtoChunk protoChunk) {
|
||||
return new Chunk(freshNMSWorld, protoChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkStatusWrap getFullChunkStatus() {
|
||||
return new ChunkStatusWrap(ChunkStatus.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlockPopulator> getBlockPopulators() {
|
||||
return originalNMSWorld.getWorld().getPopulators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Chunk chunk, Random random, BlockPopulator pop) {
|
||||
pop.populate(freshNMSWorld.getWorld(), random, chunk.bukkitChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||
return (chunkX, chunkZ) -> new BukkitGetBlocks_1_16_2(freshNMSWorld, chunkX, chunkZ) {
|
||||
@Override
|
||||
public Chunk ensureLoaded(World nmsWorld, int x, int z) {
|
||||
return getChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected class ChunkStatusWrap extends Regenerator.ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
private final ChunkStatus chunkStatus;
|
||||
|
||||
public ChunkStatusWrap(ChunkStatus chunkStatus) {
|
||||
this.chunkStatus = chunkStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requiredNeigborChunkRadius() {
|
||||
return chunkStatus.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processChunk(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
chunkStatus.a(freshNMSWorld,
|
||||
generator,
|
||||
structureManager,
|
||||
lightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks);
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private void removeWorldFromWorldsMap() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||
map.remove("worldeditregentempworld");
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ResourceKey<WorldDimension> getWorldDimKey(org.bukkit.World.Environment env) {
|
||||
switch (env) {
|
||||
case NETHER:
|
||||
return WorldDimension.THE_NETHER;
|
||||
case THE_END:
|
||||
return WorldDimension.THE_END;
|
||||
case NORMAL:
|
||||
default:
|
||||
return WorldDimension.OVERWORLD;
|
||||
}
|
||||
}
|
||||
|
||||
private Dynamic<NBTBase> recursivelySetSeed(Dynamic<NBTBase> dynamic, long seed, Set<Dynamic<NBTBase>> seen) {
|
||||
return !seen.add(dynamic) ? dynamic : dynamic.updateMapValues((pair) -> {
|
||||
if (((Dynamic) pair.getFirst()).asString("").equals("seed")) {
|
||||
return pair.mapSecond((v) -> {
|
||||
return v.createLong(seed);
|
||||
});
|
||||
} else {
|
||||
return ((Dynamic) pair.getSecond()).getValue() instanceof NBTTagCompound ? pair.mapSecond((v) -> {
|
||||
return this.recursivelySetSeed((Dynamic) v, seed, seen);
|
||||
}) : pair;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WorldChunkManager fastOverWorldChunkManager(WorldChunkManager chunkManager) throws Exception {
|
||||
Field legacyBiomeInitLayerField = WorldChunkManagerOverworld.class.getDeclaredField("i");
|
||||
legacyBiomeInitLayerField.setAccessible(true);
|
||||
Field largeBiomesField = WorldChunkManagerOverworld.class.getDeclaredField("j");
|
||||
largeBiomesField.setAccessible(true);
|
||||
Field biomeRegistryField = WorldChunkManagerOverworld.class.getDeclaredField("k");
|
||||
biomeRegistryField.setAccessible(true);
|
||||
Field areaLazyField = GenLayer.class.getDeclaredField("b");
|
||||
areaLazyField.setAccessible(true);
|
||||
Method initAreaFactoryMethod = GenLayers.class.getDeclaredMethod("a", boolean.class, int.class, int.class, LongFunction.class);
|
||||
initAreaFactoryMethod.setAccessible(true);
|
||||
|
||||
//init new WorldChunkManagerOverworld
|
||||
boolean legacyBiomeInitLayer = legacyBiomeInitLayerField.getBoolean(chunkManager);
|
||||
boolean largebiomes = largeBiomesField.getBoolean(chunkManager);
|
||||
IRegistry<BiomeBase> biomeRegistrynms = (IRegistry<BiomeBase>) biomeRegistryField.get(chunkManager);
|
||||
IRegistry<BiomeBase> biomeRegistry;
|
||||
if (options.hasBiomeType()) {
|
||||
BiomeBase biome = RegistryGeneration.WORLDGEN_BIOME.get(MinecraftKey.a(options.getBiomeType().getId()));
|
||||
biomeRegistry = new RegistryMaterials<>(ResourceKey.a(new MinecraftKey("fawe_biomes")), Lifecycle.experimental());
|
||||
((RegistryMaterials) biomeRegistry).a(0, RegistryGeneration.WORLDGEN_BIOME.c(biome).get(), biome, Lifecycle.experimental());
|
||||
} else {
|
||||
biomeRegistry = biomeRegistrynms;
|
||||
}
|
||||
chunkManager = new FastWorldChunkManagerOverworld(seed, legacyBiomeInitLayer, largebiomes, biomeRegistry);
|
||||
|
||||
//replace genLayer
|
||||
AreaFactory<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) initAreaFactoryMethod.invoke(null, legacyBiomeInitLayer, largebiomes ? 6 : 4, 4, (LongFunction) (l -> new FastWorldGenContextArea(seed, l)));
|
||||
((FastWorldChunkManagerOverworld) chunkManager).genLayer = new FastGenLayer(factory);
|
||||
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
private static class FastWorldChunkManagerOverworld extends WorldChunkManager {
|
||||
|
||||
private GenLayer genLayer;
|
||||
private final IRegistry<BiomeBase> k;
|
||||
private final boolean isSingleRegistry;
|
||||
|
||||
public FastWorldChunkManagerOverworld(long seed, boolean legacyBiomeInitLayer, boolean largeBiomes, IRegistry<BiomeBase> biomeRegistry) {
|
||||
super(biomeRegistry.g().collect(Collectors.toList()));
|
||||
this.k = biomeRegistry;
|
||||
this.isSingleRegistry = biomeRegistry.d().size() == 1;
|
||||
this.genLayer = GenLayers.a(seed, legacyBiomeInitLayer, largeBiomes ? 6 : 4, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Codec<? extends WorldChunkManager> a() {
|
||||
return WorldChunkManagerOverworld.e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(int i, int i1, int i2) {
|
||||
if (this.isSingleRegistry) {
|
||||
return this.k.fromId(0);
|
||||
}
|
||||
return this.genLayer.a(this.k, i, i2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class FastWorldGenContextArea implements AreaContextTransformed<FastAreaLazy> {
|
||||
|
||||
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
|
||||
private final NoiseGeneratorPerlin perlinNoise;
|
||||
private final long magicrandom;
|
||||
private final ConcurrentHashMap<Long, Long> map = new ConcurrentHashMap<>(); //needed for multithreaded generation
|
||||
|
||||
public FastWorldGenContextArea(long seed, long lconst) {
|
||||
this.magicrandom = mix(seed, lconst);
|
||||
this.perlinNoise = new NoiseGeneratorPerlin(new Random(seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAreaLazy a(AreaTransformer8 var0) {
|
||||
return new FastAreaLazy(sharedAreaMap, var0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(long x, long z) {
|
||||
long l = this.magicrandom;
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
this.map.put(Thread.currentThread().getId(), l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int y) {
|
||||
long tid = Thread.currentThread().getId();
|
||||
long e = this.map.computeIfAbsent(tid, i -> 0L);
|
||||
int mod = (int) Math.floorMod(e >> 24L, (long) y);
|
||||
this.map.put(tid, LinearCongruentialGenerator.a(e, this.magicrandom));
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoiseGeneratorPerlin b() {
|
||||
return this.perlinNoise;
|
||||
}
|
||||
|
||||
private static long mix(long seed, long lconst) {
|
||||
long l1 = lconst;
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
long l2 = seed;
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
return l2;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastGenLayer extends GenLayer {
|
||||
|
||||
private final FastAreaLazy areaLazy;
|
||||
|
||||
public FastGenLayer(AreaFactory<FastAreaLazy> factory) throws Exception {
|
||||
super(() -> null);
|
||||
this.areaLazy = factory.make();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase a(IRegistry<BiomeBase> registry, int x, int z) {
|
||||
ResourceKey<BiomeBase> key = BiomeRegistry.a(this.areaLazy.a(x, z));
|
||||
if (key == null)
|
||||
return registry.a(BiomeRegistry.a(0));
|
||||
BiomeBase biome = registry.a(key);
|
||||
if (biome == null)
|
||||
return registry.a(BiomeRegistry.a(0));
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastAreaLazy implements Area {
|
||||
|
||||
private final AreaTransformer8 transformer;
|
||||
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a syncronized context
|
||||
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
|
||||
private final ConcurrentHashMap<Long, Integer> sharedMap;
|
||||
|
||||
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, AreaTransformer8 transformer) {
|
||||
this.sharedMap = sharedMap;
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int x, int z) {
|
||||
long zx = ChunkCoordIntPair.pair(x, z);
|
||||
return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegenNoOpWorldLoadListener implements WorldLoadListener {
|
||||
|
||||
private RegenNoOpWorldLoadListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair, @Nullable ChunkStatus chunkStatus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkRadius(int i) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,590 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.regen;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.BukkitGetBlocks_1_16_5;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Regenerator;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import net.minecraft.server.v1_16_R3.Area;
|
||||
import net.minecraft.server.v1_16_R3.AreaContextTransformed;
|
||||
import net.minecraft.server.v1_16_R3.AreaFactory;
|
||||
import net.minecraft.server.v1_16_R3.AreaTransformer8;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.BiomeRegistry;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkConverter;
|
||||
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.ChunkGenerator;
|
||||
import net.minecraft.server.v1_16_R3.ChunkGeneratorAbstract;
|
||||
import net.minecraft.server.v1_16_R3.ChunkProviderFlat;
|
||||
import net.minecraft.server.v1_16_R3.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R3.ChunkStatus;
|
||||
import net.minecraft.server.v1_16_R3.Convertable;
|
||||
import net.minecraft.server.v1_16_R3.DefinedStructureManager;
|
||||
import net.minecraft.server.v1_16_R3.DynamicOpsNBT;
|
||||
import net.minecraft.server.v1_16_R3.GenLayer;
|
||||
import net.minecraft.server.v1_16_R3.GenLayers;
|
||||
import net.minecraft.server.v1_16_R3.GeneratorSettingBase;
|
||||
import net.minecraft.server.v1_16_R3.GeneratorSettings;
|
||||
import net.minecraft.server.v1_16_R3.GeneratorSettingsFlat;
|
||||
import net.minecraft.server.v1_16_R3.IChunkAccess;
|
||||
import net.minecraft.server.v1_16_R3.IRegistry;
|
||||
import net.minecraft.server.v1_16_R3.IRegistryCustom;
|
||||
import net.minecraft.server.v1_16_R3.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_16_R3.LinearCongruentialGenerator;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R3.NBTBase;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.NoiseGeneratorPerlin;
|
||||
import net.minecraft.server.v1_16_R3.ProtoChunk;
|
||||
import net.minecraft.server.v1_16_R3.RegistryGeneration;
|
||||
import net.minecraft.server.v1_16_R3.RegistryMaterials;
|
||||
import net.minecraft.server.v1_16_R3.RegistryReadOps;
|
||||
import net.minecraft.server.v1_16_R3.ResourceKey;
|
||||
import net.minecraft.server.v1_16_R3.World;
|
||||
import net.minecraft.server.v1_16_R3.WorldChunkManager;
|
||||
import net.minecraft.server.v1_16_R3.WorldChunkManagerOverworld;
|
||||
import net.minecraft.server.v1_16_R3.WorldDataServer;
|
||||
import net.minecraft.server.v1_16_R3.WorldDimension;
|
||||
import net.minecraft.server.v1_16_R3.WorldLoadListener;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import net.minecraft.server.v1_16_R3.WorldSettings;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.generator.CustomChunkGenerator;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Regen_v1_16_R3 extends Regenerator<IChunkAccess, ProtoChunk, Chunk, Regen_v1_16_R3.ChunkStatusWrap> {
|
||||
|
||||
private static final Field serverWorldsField;
|
||||
private static final Field worldPaperConfigField;
|
||||
private static final Field flatBedrockField;
|
||||
private static final Field generatorSettingBaseSupplierField;
|
||||
private static final Field generatorSettingFlatField;
|
||||
private static final Field delegateField;
|
||||
private static final Field chunkProviderField;
|
||||
|
||||
//list of chunk stati in correct order without FULL
|
||||
private static final Map<ChunkStatus, Regenerator.Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
chunkStati.put(ChunkStatus.EMPTY, Regenerator.Concurrency.FULL); // radius -1, does nothing
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_REFERENCES, Regenerator.Concurrency.FULL); // radius 8, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.BIOMES, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.NOISE, Regenerator.Concurrency.RADIUS); // radius 8
|
||||
chunkStati.put(ChunkStatus.SURFACE, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.LIQUID_CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.FEATURES, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.LIGHT, Regenerator.Concurrency.FULL); // radius 1, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.SPAWN, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.HEIGHTMAPS, Regenerator.Concurrency.FULL); // radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
serverWorldsField.setAccessible(true);
|
||||
|
||||
Field tmpPaperConfigField = null;
|
||||
Field tmpFlatBedrockField = null;
|
||||
try { //only present on paper
|
||||
tmpPaperConfigField = World.class.getDeclaredField("paperConfig");
|
||||
tmpPaperConfigField.setAccessible(true);
|
||||
|
||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
||||
tmpFlatBedrockField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
tmpPaperConfigField = null;
|
||||
tmpFlatBedrockField = null;
|
||||
}
|
||||
worldPaperConfigField = tmpPaperConfigField;
|
||||
flatBedrockField = tmpFlatBedrockField;
|
||||
|
||||
generatorSettingBaseSupplierField = ChunkGeneratorAbstract.class.getDeclaredField("h");
|
||||
generatorSettingBaseSupplierField.setAccessible(true);
|
||||
|
||||
generatorSettingFlatField = ChunkProviderFlat.class.getDeclaredField("e");
|
||||
generatorSettingFlatField.setAccessible(true);
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkProviderField = WorldServer.class.getDeclaredField("chunkProvider");
|
||||
chunkProviderField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//runtime
|
||||
private WorldServer originalNMSWorld;
|
||||
private ChunkProviderServer originalChunkProvider;
|
||||
private WorldServer freshNMSWorld;
|
||||
private ChunkProviderServer freshChunkProvider;
|
||||
private Convertable.ConversionSession session;
|
||||
private DefinedStructureManager structureManager;
|
||||
private LightEngineThreaded lightEngine;
|
||||
private ChunkGenerator generator;
|
||||
|
||||
private Path tempDir;
|
||||
|
||||
private boolean generateFlatBedrock = false;
|
||||
|
||||
public Regen_v1_16_R3(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
super(originalBukkitWorld, region, target, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepare() {
|
||||
this.originalNMSWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
||||
originalChunkProvider = originalNMSWorld.getChunkProvider();
|
||||
if (!(originalChunkProvider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//flat bedrock? (only on paper)
|
||||
try {
|
||||
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalNMSWorld));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
seed = options.getSeed().orElse(originalNMSWorld.getSeed());
|
||||
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initNewWorld() throws Exception {
|
||||
//world folder
|
||||
tempDir = java.nio.file.Files.createTempDirectory("WorldEditWorldGen");
|
||||
|
||||
//prepare for world init (see upstream implementation for reference)
|
||||
org.bukkit.World.Environment env = originalBukkitWorld.getEnvironment();
|
||||
org.bukkit.generator.ChunkGenerator gen = originalBukkitWorld.getGenerator();
|
||||
Convertable convertable = Convertable.a(tempDir);
|
||||
ResourceKey<WorldDimension> worldDimKey = getWorldDimKey(env);
|
||||
session = convertable.c("worldeditregentempworld", worldDimKey);
|
||||
WorldDataServer originalWorldData = originalNMSWorld.worldDataServer;
|
||||
|
||||
MinecraftServer server = originalNMSWorld.getServer().getServer();
|
||||
WorldDataServer levelProperties = (WorldDataServer) server.getSaveData();
|
||||
RegistryReadOps<NBTBase> nbtRegOps = RegistryReadOps.a(DynamicOpsNBT.a, server.dataPackResources.h(), IRegistryCustom.b());
|
||||
GeneratorSettings newOpts = GeneratorSettings.a.encodeStart(nbtRegOps, levelProperties.getGeneratorSettings()).flatMap(tag -> GeneratorSettings.a.parse(this.recursivelySetSeed(new Dynamic<>(nbtRegOps, tag), seed, new HashSet<>()))).result().orElseThrow(() -> new IllegalStateException("Unable to map GeneratorOptions"));
|
||||
WorldSettings newWorldSettings = new WorldSettings("worldeditregentempworld", originalWorldData.b.getGameType(), originalWorldData.b.hardcore, originalWorldData.b.getDifficulty(), originalWorldData.b.e(), originalWorldData.b.getGameRules(), originalWorldData.b.g());
|
||||
WorldDataServer newWorldData = new WorldDataServer(newWorldSettings, newOpts, Lifecycle.stable());
|
||||
|
||||
//init world
|
||||
freshNMSWorld = Fawe.get().getQueueHandler().sync((Supplier<WorldServer>) () -> new WorldServer(server, server.executorService, session, newWorldData, originalNMSWorld.getDimensionKey(), originalNMSWorld.getDimensionManager(), new RegenNoOpWorldLoadListener(), ((WorldDimension) newOpts.d().a(worldDimKey)).c(), originalNMSWorld.isDebugWorld(), seed, ImmutableList.of(), false, env, gen) {
|
||||
@Override
|
||||
public void doTick(BooleanSupplier booleansupplier) { //no ticking
|
||||
}
|
||||
|
||||
private final BiomeBase singleBiome = options.hasBiomeType() ? RegistryGeneration.WORLDGEN_BIOME.get(MinecraftKey.a(options.getBiomeType().getId())) : null;
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int i, int j, int k) {
|
||||
if (options.hasBiomeType()) {
|
||||
return singleBiome;
|
||||
}
|
||||
return this.getChunkProvider().getChunkGenerator().getWorldChunkManager().getBiome(i, j, k);
|
||||
}
|
||||
}).get();
|
||||
freshNMSWorld.savingDisabled = true;
|
||||
removeWorldFromWorldsMap();
|
||||
newWorldData.checkName(originalNMSWorld.worldDataServer.getName()); //rename to original world name
|
||||
|
||||
freshChunkProvider = new ChunkProviderServer(freshNMSWorld, session, server.getDataFixer(), server.getDefinedStructureManager(), server.executorService, originalChunkProvider.chunkGenerator, freshNMSWorld.spigotConfig.viewDistance, server.isSyncChunkWrites(), new RegenNoOpWorldLoadListener(), () -> server.E().getWorldPersistentData()) {
|
||||
// redirect to our protoChunks list
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int x, int z, ChunkStatus chunkstatus, boolean flag) {
|
||||
return getProtoChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
chunkProviderField.set(freshNMSWorld, freshChunkProvider);
|
||||
|
||||
//generator
|
||||
if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderFlat) {
|
||||
GeneratorSettingsFlat generatorSettingFlat = (GeneratorSettingsFlat) generatorSettingFlatField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = new ChunkProviderFlat(generatorSettingFlat);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkGeneratorAbstract) {
|
||||
Supplier<GeneratorSettingBase> generatorSettingBaseSupplier = (Supplier<GeneratorSettingBase>) generatorSettingBaseSupplierField.get(originalChunkProvider.getChunkGenerator());
|
||||
WorldChunkManager chunkManager = originalChunkProvider.getChunkGenerator().getWorldChunkManager();
|
||||
if (chunkManager instanceof WorldChunkManagerOverworld) {
|
||||
chunkManager = fastOverWorldChunkManager(chunkManager);
|
||||
}
|
||||
generator = new ChunkGeneratorAbstract(chunkManager, seed, generatorSettingBaseSupplier);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof CustomChunkGenerator) {
|
||||
ChunkGenerator delegate = (ChunkGenerator) delegateField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = delegate;
|
||||
} else {
|
||||
System.out.println("Unsupported generator type " + originalChunkProvider.getChunkGenerator().getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (originalNMSWorld.generator != null) {
|
||||
// wrap custom world generator
|
||||
generator = new CustomChunkGenerator(freshNMSWorld, generator, originalNMSWorld.generator);
|
||||
generateConcurrent = originalNMSWorld.generator.isParallelCapable();
|
||||
}
|
||||
|
||||
//lets start then
|
||||
structureManager = server.getDefinedStructureManager();
|
||||
lightEngine = freshChunkProvider.getLightEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//shutdown chunk provider
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
freshChunkProvider.close(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//remove world from server
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
removeWorldFromWorldsMap();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//delete directory
|
||||
try {
|
||||
SafeFiles.tryHardToDeleteDir(tempDir);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtoChunk createProtoChunk(int x, int z) {
|
||||
return new ProtoChunk(new ChunkCoordIntPair(x, z), ChunkConverter.a) {
|
||||
public boolean generateFlatBedrock() {
|
||||
return generateFlatBedrock;
|
||||
}
|
||||
|
||||
// no one will ever see the entities!
|
||||
@Override
|
||||
public List<NBTTagCompound> y() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chunk createChunk(ProtoChunk protoChunk) {
|
||||
return new Chunk(freshNMSWorld, protoChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkStatusWrap getFullChunkStatus() {
|
||||
return new ChunkStatusWrap(ChunkStatus.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlockPopulator> getBlockPopulators() {
|
||||
return originalNMSWorld.getWorld().getPopulators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Chunk chunk, Random random, BlockPopulator pop) {
|
||||
pop.populate(freshNMSWorld.getWorld(), random, chunk.bukkitChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||
return (chunkX, chunkZ) -> new BukkitGetBlocks_1_16_5(freshNMSWorld, chunkX, chunkZ) {
|
||||
@Override
|
||||
public Chunk ensureLoaded(World nmsWorld, int x, int z) {
|
||||
return getChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected class ChunkStatusWrap extends Regenerator.ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
private final ChunkStatus chunkStatus;
|
||||
|
||||
public ChunkStatusWrap(ChunkStatus chunkStatus) {
|
||||
this.chunkStatus = chunkStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requiredNeigborChunkRadius() {
|
||||
return chunkStatus.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processChunk(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
chunkStatus.a(freshNMSWorld,
|
||||
generator,
|
||||
structureManager,
|
||||
lightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks);
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private void removeWorldFromWorldsMap() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||
map.remove("worldeditregentempworld");
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ResourceKey<WorldDimension> getWorldDimKey(org.bukkit.World.Environment env) {
|
||||
switch (env) {
|
||||
case NETHER:
|
||||
return WorldDimension.THE_NETHER;
|
||||
case THE_END:
|
||||
return WorldDimension.THE_END;
|
||||
case NORMAL:
|
||||
default:
|
||||
return WorldDimension.OVERWORLD;
|
||||
}
|
||||
}
|
||||
|
||||
private Dynamic<NBTBase> recursivelySetSeed(Dynamic<NBTBase> dynamic, long seed, Set<Dynamic<NBTBase>> seen) {
|
||||
return !seen.add(dynamic) ? dynamic : dynamic.updateMapValues((pair) -> {
|
||||
if (((Dynamic) pair.getFirst()).asString("").equals("seed")) {
|
||||
return pair.mapSecond((v) -> {
|
||||
return v.createLong(seed);
|
||||
});
|
||||
} else {
|
||||
return ((Dynamic) pair.getSecond()).getValue() instanceof NBTTagCompound ? pair.mapSecond((v) -> {
|
||||
return this.recursivelySetSeed((Dynamic) v, seed, seen);
|
||||
}) : pair;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WorldChunkManager fastOverWorldChunkManager(WorldChunkManager chunkManager) throws Exception {
|
||||
Field legacyBiomeInitLayerField = WorldChunkManagerOverworld.class.getDeclaredField("i");
|
||||
legacyBiomeInitLayerField.setAccessible(true);
|
||||
Field largeBiomesField = WorldChunkManagerOverworld.class.getDeclaredField("j");
|
||||
largeBiomesField.setAccessible(true);
|
||||
Field biomeRegistryField = WorldChunkManagerOverworld.class.getDeclaredField("k");
|
||||
biomeRegistryField.setAccessible(true);
|
||||
Field areaLazyField = GenLayer.class.getDeclaredField("b");
|
||||
areaLazyField.setAccessible(true);
|
||||
Method initAreaFactoryMethod = GenLayers.class.getDeclaredMethod("a", boolean.class, int.class, int.class, LongFunction.class);
|
||||
initAreaFactoryMethod.setAccessible(true);
|
||||
|
||||
//init new WorldChunkManagerOverworld
|
||||
boolean legacyBiomeInitLayer = legacyBiomeInitLayerField.getBoolean(chunkManager);
|
||||
boolean largebiomes = largeBiomesField.getBoolean(chunkManager);
|
||||
IRegistry<BiomeBase> biomeRegistrynms = (IRegistry<BiomeBase>) biomeRegistryField.get(chunkManager);
|
||||
IRegistry<BiomeBase> biomeRegistry;
|
||||
if (options.hasBiomeType()) {
|
||||
BiomeBase biome = RegistryGeneration.WORLDGEN_BIOME.get(MinecraftKey.a(options.getBiomeType().getId()));
|
||||
biomeRegistry = new RegistryMaterials<>(ResourceKey.a(new MinecraftKey("fawe_biomes")), Lifecycle.experimental());
|
||||
((RegistryMaterials) biomeRegistry).a(0, RegistryGeneration.WORLDGEN_BIOME.c(biome).get(), biome, Lifecycle.experimental());
|
||||
} else {
|
||||
biomeRegistry = biomeRegistrynms;
|
||||
}
|
||||
chunkManager = new FastWorldChunkManagerOverworld(seed, legacyBiomeInitLayer, largebiomes, biomeRegistry);
|
||||
|
||||
//replace genLayer
|
||||
AreaFactory<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) initAreaFactoryMethod.invoke(null, legacyBiomeInitLayer, largebiomes ? 6 : 4, 4, (LongFunction) (l -> new FastWorldGenContextArea(seed, l)));
|
||||
((FastWorldChunkManagerOverworld) chunkManager).genLayer = new FastGenLayer(factory);
|
||||
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
private static class FastWorldChunkManagerOverworld extends WorldChunkManager {
|
||||
|
||||
private GenLayer genLayer;
|
||||
private final IRegistry<BiomeBase> k;
|
||||
private final boolean isSingleRegistry;
|
||||
|
||||
public FastWorldChunkManagerOverworld(long seed, boolean legacyBiomeInitLayer, boolean largeBiomes, IRegistry<BiomeBase> biomeRegistry) {
|
||||
super(biomeRegistry.g().collect(Collectors.toList()));
|
||||
this.k = biomeRegistry;
|
||||
this.isSingleRegistry = biomeRegistry.d().size() == 1;
|
||||
this.genLayer = GenLayers.a(seed, legacyBiomeInitLayer, largeBiomes ? 6 : 4, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Codec<? extends WorldChunkManager> a() {
|
||||
return WorldChunkManagerOverworld.e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(int i, int i1, int i2) {
|
||||
if (this.isSingleRegistry) {
|
||||
return this.k.fromId(0);
|
||||
}
|
||||
return this.genLayer.a(this.k, i, i2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class FastWorldGenContextArea implements AreaContextTransformed<FastAreaLazy> {
|
||||
|
||||
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
|
||||
private final NoiseGeneratorPerlin perlinNoise;
|
||||
private final long magicrandom;
|
||||
private final ConcurrentHashMap<Long, Long> map = new ConcurrentHashMap<>(); //needed for multithreaded generation
|
||||
|
||||
public FastWorldGenContextArea(long seed, long lconst) {
|
||||
this.magicrandom = mix(seed, lconst);
|
||||
this.perlinNoise = new NoiseGeneratorPerlin(new Random(seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAreaLazy a(AreaTransformer8 var0) {
|
||||
return new FastAreaLazy(sharedAreaMap, var0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(long x, long z) {
|
||||
long l = this.magicrandom;
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
this.map.put(Thread.currentThread().getId(), l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int y) {
|
||||
long tid = Thread.currentThread().getId();
|
||||
long e = this.map.computeIfAbsent(tid, i -> 0L);
|
||||
int mod = (int) Math.floorMod(e >> 24L, (long) y);
|
||||
this.map.put(tid, LinearCongruentialGenerator.a(e, this.magicrandom));
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoiseGeneratorPerlin b() {
|
||||
return this.perlinNoise;
|
||||
}
|
||||
|
||||
private static long mix(long seed, long lconst) {
|
||||
long l1 = lconst;
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
long l2 = seed;
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
return l2;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastGenLayer extends GenLayer {
|
||||
|
||||
private final FastAreaLazy areaLazy;
|
||||
|
||||
public FastGenLayer(AreaFactory<FastAreaLazy> factory) throws Exception {
|
||||
super(() -> null);
|
||||
this.areaLazy = factory.make();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase a(IRegistry<BiomeBase> registry, int x, int z) {
|
||||
ResourceKey<BiomeBase> key = BiomeRegistry.a(this.areaLazy.a(x, z));
|
||||
if (key == null)
|
||||
return registry.a(BiomeRegistry.a(0));
|
||||
BiomeBase biome = registry.a(key);
|
||||
if (biome == null)
|
||||
return registry.a(BiomeRegistry.a(0));
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastAreaLazy implements Area {
|
||||
|
||||
private final AreaTransformer8 transformer;
|
||||
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a syncronized context
|
||||
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
|
||||
private final ConcurrentHashMap<Long, Integer> sharedMap;
|
||||
|
||||
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, AreaTransformer8 transformer) {
|
||||
this.sharedMap = sharedMap;
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int x, int z) {
|
||||
long zx = ChunkCoordIntPair.pair(x, z);
|
||||
return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegenNoOpWorldLoadListener implements WorldLoadListener {
|
||||
|
||||
private RegenNoOpWorldLoadListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair, @Nullable ChunkStatus chunkStatus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkRadius(int i) {
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user