From 17529632886dbd1b3a20e8ed224ef566935c19ec Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 17 Nov 2016 23:13:02 -0800 Subject: [PATCH] [Forge] Make //regen work better It now creates a brand-new world, generates the appropriate section there, and copies it over to the original world. --- .../com/sk89q/worldedit/forge/ForgeWorld.java | 134 ++++++++---------- 1 file changed, 61 insertions(+), 73 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 8f8f7a29d..562afb126 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -19,16 +19,22 @@ package com.sk89q.worldedit.forge; +import com.google.common.io.Files; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.history.change.BlockChange; import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; @@ -36,40 +42,55 @@ import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.registry.WorldData; -import net.minecraft.block.*; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockLeaves; +import net.minecraft.block.BlockOldLeaf; +import net.minecraft.block.BlockOldLog; +import net.minecraft.block.BlockPlanks; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityList; import net.minecraft.entity.item.EntityItem; -import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.server.management.PlayerChunkMap; -import net.minecraft.server.management.PlayerChunkMapEntry; +import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkGenerator; import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.chunk.storage.AnvilSaveHandler; import net.minecraft.world.gen.ChunkProviderServer; -import net.minecraft.world.gen.feature.*; +import net.minecraft.world.gen.feature.WorldGenBigMushroom; +import net.minecraft.world.gen.feature.WorldGenBigTree; +import net.minecraft.world.gen.feature.WorldGenBirchTree; +import net.minecraft.world.gen.feature.WorldGenCanopyTree; +import net.minecraft.world.gen.feature.WorldGenMegaJungle; +import net.minecraft.world.gen.feature.WorldGenMegaPineTree; +import net.minecraft.world.gen.feature.WorldGenSavannaTree; +import net.minecraft.world.gen.feature.WorldGenShrub; +import net.minecraft.world.gen.feature.WorldGenSwamp; +import net.minecraft.world.gen.feature.WorldGenTaiga1; +import net.minecraft.world.gen.feature.WorldGenTaiga2; +import net.minecraft.world.gen.feature.WorldGenTrees; +import net.minecraft.world.gen.feature.WorldGenerator; +import net.minecraftforge.common.DimensionManager; import javax.annotation.Nullable; + +import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Random; -import java.util.logging.Level; -import java.util.logging.Logger; import static com.google.common.base.Preconditions.checkNotNull; @@ -80,7 +101,6 @@ public class ForgeWorld extends AbstractWorld { private static final Random random = new Random(); private static final int UPDATE = 1, NOTIFY = 2; - private static final Logger logger = Logger.getLogger(ForgeWorld.class.getCanonicalName()); private static final IBlockState JUNGLE_LOG = Blocks.LOG.getDefaultState().withProperty(BlockOldLog.VARIANT, BlockPlanks.EnumType.JUNGLE); private static final IBlockState JUNGLE_LEAF = Blocks.LEAVES.getDefaultState().withProperty(BlockOldLeaf.VARIANT, BlockPlanks.EnumType.JUNGLE).withProperty(BlockLeaves.CHECK_DECAY, Boolean.valueOf(false)); @@ -246,73 +266,41 @@ public class ForgeWorld extends AbstractWorld { if (!(provider instanceof ChunkProviderServer)) { return false; } - BaseBlock[] history = new BaseBlock[256 * (getMaxY() + 1)]; + + File saveFolder = Files.createTempDir(); + // register this just in case something goes wrong + // normally it should be deleted at the end of this method + saveFolder.deleteOnExit(); - for (Vector2D chunk : region.getChunks()) { - Vector min = new Vector(chunk.getBlockX() * 16, 0, chunk.getBlockZ() * 16); + WorldServer originalWorld = (WorldServer) getWorld(); - for (int x = 0; x < 16; x++) { - for (int y = 0; y < getMaxY() + 1; y++) { - for (int z = 0; z < 16; z++) { - Vector pt = min.add(x, y, z); - int index = y * 16 * 16 + z * 16 + x; - history[index] = editSession.getBlock(pt); - } - } - } - PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap(); - List oldWatchers = null; - Chunk mcChunk = null; - try { - ChunkProviderServer chunkServer = (ChunkProviderServer) provider; - IChunkGenerator gen = chunkServer.chunkGenerator; - long pos = ChunkPos.asLong(chunk.getBlockX(), chunk.getBlockZ()); - if (chunkServer.chunkExists(chunk.getBlockX(), chunk.getBlockZ())) { - mcChunk = chunkServer.loadChunk(chunk.getBlockX(), chunk.getBlockZ()); - PlayerChunkMapEntry entry = playerManager.getEntry(chunk.getBlockX(), chunk.getBlockZ()); - if (entry != null) { - oldWatchers = entry.players; - playerManager.removeEntry(entry); - } - mcChunk.onChunkUnload(); - } - chunkServer.droppedChunksSet.remove(pos); - chunkServer.id2ChunkMap.remove(pos); - mcChunk = gen.provideChunk(chunk.getBlockX(), chunk.getBlockZ()); - chunkServer.id2ChunkMap.put(pos, mcChunk); - if (mcChunk != null) { - mcChunk.onChunkLoad(); - mcChunk.populateChunk(chunkServer, chunkServer.chunkGenerator); - } - } catch (Throwable t) { - logger.log(Level.WARNING, "Failed to generate chunk", t); - return false; - } + MinecraftServer server = originalWorld.getMinecraftServer(); + AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, + originalWorld.getSaveHandler().getWorldDirectory().getName(), true, server.getDataFixer()); + World freshWorld = new WorldServer(server, saveHandler, originalWorld.getWorldInfo(), + originalWorld.provider.getDimension(), originalWorld.theProfiler).init(); - for (int x = 0; x < 16; x++) { - for (int y = 0; y < getMaxY() + 1; y++) { - for (int z = 0; z < 16; z++) { - Vector pt = min.add(x, y, z); - int index = y * 16 * 16 + z * 16 + x; - - if (!region.contains(pt)) - editSession.smartSetBlock(pt, history[index]); - else { - editSession.getChangeSet().add(new BlockChange(pt.toBlockVector(), history[index], editSession.getBlock(pt))); - } - } - } - } - // We don't need to recreate the ChunkMapEntry unless there are players - // but addPlayer handles that for us - if (oldWatchers != null) { - for (EntityPlayerMP player : oldWatchers) { - playerManager.addPlayer(player); - } + // Pre-gen all the chunks + // We need to also pull one more chunk in every direction + CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); + for (Vector2D chunk : expandedPreGen.getChunks()) { + freshWorld.getChunkFromChunkCoords(chunk.getBlockX(), chunk.getBlockZ()); + } + + ForgeWorld from = new ForgeWorld(freshWorld); + try { + for (BlockVector vec : region) { + editSession.setBlock(vec, from.getBlock(vec)); } + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } finally { + saveFolder.delete(); + DimensionManager.setWorld(originalWorld.provider.getDimension(), null, server); + DimensionManager.setWorld(originalWorld.provider.getDimension(), originalWorld, server); } - return false; + return true; } @Nullable