mirror of
				https://github.com/mcMMO-Dev/mcMMO.git
				synced 2025-11-03 18:43:43 +01:00 
			
		
		
		
	Merge pull request #295 from Glitchfinder/master
Updating block storage to a region-style format.
This commit is contained in:
		@@ -9,6 +9,7 @@ public class HiddenConfig {
 | 
				
			|||||||
    private static String fileName;
 | 
					    private static String fileName;
 | 
				
			||||||
    private static YamlConfiguration config;
 | 
					    private static YamlConfiguration config;
 | 
				
			||||||
    private static boolean chunkletsEnabled;
 | 
					    private static boolean chunkletsEnabled;
 | 
				
			||||||
 | 
					    private static int conversionRate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public HiddenConfig(String fileName) {
 | 
					    public HiddenConfig(String fileName) {
 | 
				
			||||||
        HiddenConfig.fileName = fileName;
 | 
					        HiddenConfig.fileName = fileName;
 | 
				
			||||||
@@ -27,10 +28,15 @@ public class HiddenConfig {
 | 
				
			|||||||
        if (mcMMO.p.getResource(fileName) != null) {
 | 
					        if (mcMMO.p.getResource(fileName) != null) {
 | 
				
			||||||
            config = YamlConfiguration.loadConfiguration(mcMMO.p.getResource(fileName));
 | 
					            config = YamlConfiguration.loadConfiguration(mcMMO.p.getResource(fileName));
 | 
				
			||||||
            chunkletsEnabled = config.getBoolean("Options.Chunklets", true);
 | 
					            chunkletsEnabled = config.getBoolean("Options.Chunklets", true);
 | 
				
			||||||
 | 
					            conversionRate = config.getInt("Options.ConversionRate", 3);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean getChunkletsEnabled() {
 | 
					    public boolean getChunkletsEnabled() {
 | 
				
			||||||
        return chunkletsEnabled;
 | 
					        return chunkletsEnabled;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getConversionRate() {
 | 
				
			||||||
 | 
					        return conversionRate;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,38 @@
 | 
				
			|||||||
package com.gmail.nossr50.listeners;
 | 
					package com.gmail.nossr50.listeners;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.File;
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.bukkit.event.EventHandler;
 | 
					import org.bukkit.event.EventHandler;
 | 
				
			||||||
import org.bukkit.event.Listener;
 | 
					import org.bukkit.event.Listener;
 | 
				
			||||||
 | 
					import org.bukkit.event.world.ChunkLoadEvent;
 | 
				
			||||||
import org.bukkit.event.world.ChunkUnloadEvent;
 | 
					import org.bukkit.event.world.ChunkUnloadEvent;
 | 
				
			||||||
import org.bukkit.event.world.WorldLoadEvent;
 | 
					import org.bukkit.event.world.WorldInitEvent;
 | 
				
			||||||
import org.bukkit.event.world.WorldSaveEvent;
 | 
					import org.bukkit.event.world.WorldSaveEvent;
 | 
				
			||||||
import org.bukkit.event.world.WorldUnloadEvent;
 | 
					import org.bukkit.event.world.WorldUnloadEvent;
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.gmail.nossr50.mcMMO;
 | 
					import com.gmail.nossr50.mcMMO;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.runnables.blockstoreconversion.BlockStoreConversionMain;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.chunkmeta.HashChunkManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WorldListener implements Listener {
 | 
					public class WorldListener implements Listener {
 | 
				
			||||||
 | 
					    ArrayList<BlockStoreConversionMain> converters = new ArrayList<BlockStoreConversionMain>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @EventHandler
 | 
					    @EventHandler
 | 
				
			||||||
    public void onWorldLoad(WorldLoadEvent event) {
 | 
					    public void onWorldInit(WorldInitEvent event) {
 | 
				
			||||||
        File dataDir = new File(event.getWorld().getWorldFolder(), "mcmmo_data");
 | 
					        File dataDir = new File(event.getWorld().getWorldFolder(), "mcmmo_data");
 | 
				
			||||||
        if(!dataDir.exists()) {
 | 
					        if(!dataDir.exists()) {
 | 
				
			||||||
            dataDir.mkdir();
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(mcMMO.p == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mcMMO.p.getLogger().info("Converting block storage for " + event.getWorld().getName() + " to a new format.");
 | 
				
			||||||
 | 
					        BlockStoreConversionMain converter = new BlockStoreConversionMain(event.getWorld());
 | 
				
			||||||
 | 
					        converter.run();
 | 
				
			||||||
 | 
					        converters.add(converter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @EventHandler
 | 
					    @EventHandler
 | 
				
			||||||
@@ -34,4 +49,19 @@ public class WorldListener implements Listener {
 | 
				
			|||||||
    public void onChunkUnload(ChunkUnloadEvent event) {
 | 
					    public void onChunkUnload(ChunkUnloadEvent event) {
 | 
				
			||||||
        mcMMO.placeStore.chunkUnloaded(event.getChunk().getX(), event.getChunk().getZ(), event.getWorld());
 | 
					        mcMMO.placeStore.chunkUnloaded(event.getChunk().getX(), event.getChunk().getZ(), event.getWorld());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @EventHandler
 | 
				
			||||||
 | 
					    public void onChunkLoad(ChunkLoadEvent event) {
 | 
				
			||||||
 | 
						File dataDir = new File(event.getChunk().getWorld().getWorldFolder(), "mcmmo_data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!dataDir.exists() || !dataDir.isDirectory()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        World world = event.getChunk().getWorld();
 | 
				
			||||||
 | 
					        int cx = event.getChunk().getX();
 | 
				
			||||||
 | 
					        int cz = event.getChunk().getZ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ((HashChunkManager) mcMMO.p.placeStore).convertChunk(dataDir, cx, cz, world);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ import org.bukkit.plugin.PluginDescriptionFile;
 | 
				
			|||||||
import org.bukkit.plugin.PluginManager;
 | 
					import org.bukkit.plugin.PluginManager;
 | 
				
			||||||
import org.bukkit.plugin.java.JavaPlugin;
 | 
					import org.bukkit.plugin.java.JavaPlugin;
 | 
				
			||||||
import org.bukkit.scheduler.BukkitScheduler;
 | 
					import org.bukkit.scheduler.BukkitScheduler;
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.gmail.nossr50.commands.general.AddlevelsCommand;
 | 
					import com.gmail.nossr50.commands.general.AddlevelsCommand;
 | 
				
			||||||
import com.gmail.nossr50.commands.general.AddxpCommand;
 | 
					import com.gmail.nossr50.commands.general.AddxpCommand;
 | 
				
			||||||
@@ -78,8 +79,9 @@ import com.gmail.nossr50.util.Leaderboard;
 | 
				
			|||||||
import com.gmail.nossr50.util.Metrics;
 | 
					import com.gmail.nossr50.util.Metrics;
 | 
				
			||||||
import com.gmail.nossr50.util.Metrics.Graph;
 | 
					import com.gmail.nossr50.util.Metrics.Graph;
 | 
				
			||||||
import com.gmail.nossr50.util.Users;
 | 
					import com.gmail.nossr50.util.Users;
 | 
				
			||||||
import com.gmail.nossr50.util.blockmeta.ChunkletManager;
 | 
					import com.gmail.nossr50.util.blockmeta.chunkmeta.ChunkManager;
 | 
				
			||||||
import com.gmail.nossr50.util.blockmeta.ChunkletManagerFactory;
 | 
					import com.gmail.nossr50.util.blockmeta.chunkmeta.ChunkManagerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class mcMMO extends JavaPlugin {
 | 
					public class mcMMO extends JavaPlugin {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,7 +97,7 @@ public class mcMMO extends JavaPlugin {
 | 
				
			|||||||
    private static Database database;
 | 
					    private static Database database;
 | 
				
			||||||
    public static mcMMO p;
 | 
					    public static mcMMO p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static ChunkletManager placeStore;
 | 
					    public static ChunkManager placeStore;
 | 
				
			||||||
    public static RepairManager repairManager;
 | 
					    public static RepairManager repairManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Jar Stuff */
 | 
					    /* Jar Stuff */
 | 
				
			||||||
@@ -223,7 +225,7 @@ public class mcMMO extends JavaPlugin {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Get our ChunkletManager
 | 
					        // Get our ChunkletManager
 | 
				
			||||||
        placeStore = ChunkletManagerFactory.getChunkletManager();
 | 
					        placeStore = ChunkManagerFactory.getChunkManager();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.runnables.blockstoreconversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.lang.Runnable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.scheduler.BukkitScheduler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.config.HiddenConfig;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.mcMMO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BlockStoreConversionMain implements Runnable {
 | 
				
			||||||
 | 
					    private int taskID, i;
 | 
				
			||||||
 | 
					    private org.bukkit.World world;
 | 
				
			||||||
 | 
					    BukkitScheduler scheduler;
 | 
				
			||||||
 | 
					    File dataDir;
 | 
				
			||||||
 | 
					    File[] xDirs;
 | 
				
			||||||
 | 
					    BlockStoreConversionXDirectory[] converters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public BlockStoreConversionMain(org.bukkit.World world) {
 | 
				
			||||||
 | 
					        this.taskID = -1;
 | 
				
			||||||
 | 
					        this.world = world;
 | 
				
			||||||
 | 
					        this.scheduler = mcMMO.p.getServer().getScheduler();
 | 
				
			||||||
 | 
						this.dataDir = new File(this.world.getWorldFolder(), "mcmmo_data");
 | 
				
			||||||
 | 
						this.converters = new BlockStoreConversionXDirectory[HiddenConfig.getInstance().getConversionRate()];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void start() {
 | 
				
			||||||
 | 
					        if(this.taskID >= 0)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.taskID = this.scheduler.scheduleSyncDelayedTask(mcMMO.p, this, 1);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void run() {
 | 
				
			||||||
 | 
					        if(!this.dataDir.exists()) {
 | 
				
			||||||
 | 
					            softStop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!this.dataDir.isDirectory()) {
 | 
				
			||||||
 | 
					            this.dataDir.delete();
 | 
				
			||||||
 | 
					            softStop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.dataDir.listFiles().length <= 0) {
 | 
				
			||||||
 | 
					            this.dataDir.delete();
 | 
				
			||||||
 | 
					            softStop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.xDirs = this.dataDir.listFiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (this.i = 0; (this.i < HiddenConfig.getInstance().getConversionRate()) && (this.i < this.xDirs.length); this.i++) {
 | 
				
			||||||
 | 
					            if(this.converters[this.i] == null)
 | 
				
			||||||
 | 
					                this.converters[this.i] = new BlockStoreConversionXDirectory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.converters[this.i].start(this.world, this.xDirs[this.i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        softStop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void stop() {
 | 
				
			||||||
 | 
					        if(this.taskID < 0)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.scheduler.cancelTask(this.taskID);
 | 
				
			||||||
 | 
					        this.taskID = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void softStop() {
 | 
				
			||||||
 | 
					        stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.dataDir.exists() || this.dataDir.isDirectory()) {
 | 
				
			||||||
 | 
					            start();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mcMMO.p.getLogger().info("Finished converting the storage for " + world.getName() + ".");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.dataDir = null;
 | 
				
			||||||
 | 
					        this.xDirs = null;
 | 
				
			||||||
 | 
					        this.world = null;
 | 
				
			||||||
 | 
					        this.scheduler = null;
 | 
				
			||||||
 | 
					        this.converters = null;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.runnables.blockstoreconversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.lang.Runnable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.scheduler.BukkitScheduler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.config.HiddenConfig;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.mcMMO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BlockStoreConversionXDirectory implements Runnable {
 | 
				
			||||||
 | 
					    private int taskID, i;
 | 
				
			||||||
 | 
					    private org.bukkit.World world;
 | 
				
			||||||
 | 
					    BukkitScheduler scheduler;
 | 
				
			||||||
 | 
					    File dataDir;
 | 
				
			||||||
 | 
					    File[] zDirs;
 | 
				
			||||||
 | 
					    BlockStoreConversionZDirectory[] converters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public BlockStoreConversionXDirectory() {
 | 
				
			||||||
 | 
					        this.taskID = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void start(org.bukkit.World world, File dataDir) {
 | 
				
			||||||
 | 
					        this.world = world;
 | 
				
			||||||
 | 
					        this.scheduler = mcMMO.p.getServer().getScheduler();
 | 
				
			||||||
 | 
					        this.converters = new BlockStoreConversionZDirectory[HiddenConfig.getInstance().getConversionRate()];
 | 
				
			||||||
 | 
					        this.dataDir = dataDir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.taskID >= 0)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.taskID = this.scheduler.scheduleSyncDelayedTask(mcMMO.p, this, 1);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void run() {
 | 
				
			||||||
 | 
					        if(!this.dataDir.exists()) {
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!this.dataDir.isDirectory()) {
 | 
				
			||||||
 | 
					            this.dataDir.delete();
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.dataDir.listFiles().length <= 0) {
 | 
				
			||||||
 | 
					            this.dataDir.delete();
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       this.zDirs = this.dataDir.listFiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (this.i = 0; (this.i < HiddenConfig.getInstance().getConversionRate()) && (this.i < this.zDirs.length); this.i++) {
 | 
				
			||||||
 | 
					            if(this.converters[this.i] == null)
 | 
				
			||||||
 | 
					                this.converters[this.i] = new BlockStoreConversionZDirectory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.converters[this.i].start(this.world, this.dataDir, this.zDirs[this.i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void stop() {
 | 
				
			||||||
 | 
					        if(this.taskID < 0)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.scheduler.cancelTask(this.taskID);
 | 
				
			||||||
 | 
					        this.taskID = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.dataDir = null;
 | 
				
			||||||
 | 
						this.zDirs = null;
 | 
				
			||||||
 | 
						this.world = null;
 | 
				
			||||||
 | 
						this.scheduler = null;
 | 
				
			||||||
 | 
						this.converters = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,173 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.runnables.blockstoreconversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.lang.Runnable;
 | 
				
			||||||
 | 
					import java.lang.String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.scheduler.BukkitScheduler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.mcMMO;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.ChunkletStore;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.PrimitiveChunkletStore;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.PrimitiveExChunkletStore;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.HashChunkletManager;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.chunkmeta.HashChunkManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BlockStoreConversionZDirectory implements Runnable {
 | 
				
			||||||
 | 
					    private int taskID, cx, cz, x, y, z, y2, xPos, zPos, cxPos, czPos;
 | 
				
			||||||
 | 
					    private String cxs, czs, chunkletName, chunkName;
 | 
				
			||||||
 | 
					    private org.bukkit.World world;
 | 
				
			||||||
 | 
					    private BukkitScheduler scheduler;
 | 
				
			||||||
 | 
					    private File xDir, dataDir;
 | 
				
			||||||
 | 
					    private HashChunkletManager manager;
 | 
				
			||||||
 | 
					    private HashChunkManager newManager;
 | 
				
			||||||
 | 
					    private ChunkletStore tempChunklet;
 | 
				
			||||||
 | 
					    private PrimitiveChunkletStore primitiveChunklet = null;
 | 
				
			||||||
 | 
					    private PrimitiveExChunkletStore primitiveExChunklet = null;
 | 
				
			||||||
 | 
					    private PrimitiveChunkStore currentChunk;
 | 
				
			||||||
 | 
					    private boolean[] oldArray, newArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public BlockStoreConversionZDirectory() {
 | 
				
			||||||
 | 
					        this.taskID = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void start(org.bukkit.World world, File xDir, File dataDir) {
 | 
				
			||||||
 | 
					        this.world = world;
 | 
				
			||||||
 | 
					        this.scheduler = mcMMO.p.getServer().getScheduler();
 | 
				
			||||||
 | 
					        this.manager = new HashChunkletManager();
 | 
				
			||||||
 | 
					        this.newManager = (HashChunkManager) mcMMO.p.placeStore;
 | 
				
			||||||
 | 
					        this.dataDir = dataDir;
 | 
				
			||||||
 | 
					        this.xDir = xDir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.taskID >= 0)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.taskID = this.scheduler.scheduleSyncDelayedTask(mcMMO.p, this, 1);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void run() {
 | 
				
			||||||
 | 
					        if(!this.dataDir.exists()) {
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!this.dataDir.isDirectory()) {
 | 
				
			||||||
 | 
					            this.dataDir.delete();
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.dataDir.listFiles().length <= 0) {
 | 
				
			||||||
 | 
					            this.dataDir.delete();
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.cxs = this.xDir.getName();
 | 
				
			||||||
 | 
					        this.czs = this.dataDir.getName();
 | 
				
			||||||
 | 
					        this.cx = 0;
 | 
				
			||||||
 | 
					        this.cz = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            this.cx = Integer.parseInt(this.cxs);
 | 
				
			||||||
 | 
					            this.cz = Integer.parseInt(this.czs);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch(Exception e) {
 | 
				
			||||||
 | 
					            this.dataDir.delete();
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.manager.loadChunk(this.cx, this.cz, this.world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(this.y = 0; this.y < (this.world.getMaxHeight() / 64); this.y++) {
 | 
				
			||||||
 | 
					            this.chunkletName = this.world.getName() + "," + this.cx + "," + this.cz + "," + this.y;
 | 
				
			||||||
 | 
						    this.tempChunklet = this.manager.store.get(this.chunkletName);
 | 
				
			||||||
 | 
					            if(this.tempChunklet instanceof PrimitiveChunkletStore)
 | 
				
			||||||
 | 
					                this.primitiveChunklet = (PrimitiveChunkletStore) this.tempChunklet;
 | 
				
			||||||
 | 
					            else if(this.tempChunklet instanceof PrimitiveExChunkletStore)
 | 
				
			||||||
 | 
					                this.primitiveExChunklet = (PrimitiveExChunkletStore) this.tempChunklet;
 | 
				
			||||||
 | 
					            if(this.tempChunklet == null) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.chunkName = this.world.getName() + "," + this.cx + "," + this.cz;
 | 
				
			||||||
 | 
					                this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(this.currentChunk != null) {
 | 
				
			||||||
 | 
					                    this.xPos = this.cx * 16;
 | 
				
			||||||
 | 
					                    this.zPos = this.cz * 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for(this.x = 0; this.x < 16; this.x++) {
 | 
				
			||||||
 | 
					                        for(this.z = 0; this.z < 16; this.z++) {
 | 
				
			||||||
 | 
					                            this.cxPos = this.xPos + this.x;
 | 
				
			||||||
 | 
					                            this.czPos = this.zPos + this.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            for(this.y2 = (64 * this.y); this.y2 < (64 * this.y + 64); this.y2++) {
 | 
				
			||||||
 | 
					                                if(!this.manager.isTrue(this.cxPos, this.y2, this.czPos, this.world))
 | 
				
			||||||
 | 
					                                    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                this.newManager.setTrue(this.cxPos, this.y2, this.czPos, this.world);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                this.newManager.setTrue(this.cx * 16, 0, this.cz * 16, this.world);
 | 
				
			||||||
 | 
							this.newManager.setFalse(this.cx * 16, 0, this.cz * 16, this.world);
 | 
				
			||||||
 | 
					                this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for(this.x = 0; this.x < 16; this.x++) {
 | 
				
			||||||
 | 
					                    for(this.z = 0; this.z < 16; this.z++) {
 | 
				
			||||||
 | 
					                        if(this.primitiveChunklet != null)
 | 
				
			||||||
 | 
					                            this.oldArray = this.primitiveChunklet.store[x][z];
 | 
				
			||||||
 | 
					                        if(this.primitiveExChunklet != null)
 | 
				
			||||||
 | 
					                            this.oldArray = this.primitiveExChunklet.store[x][z];
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        this.newArray = this.currentChunk.store[x][z];
 | 
				
			||||||
 | 
					                        if(this.oldArray.length < 64)
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        else if(this.newArray.length < ((this.y * 64) + 64))
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        System.arraycopy(this.oldArray, 0, this.newArray, (this.y * 64), 64);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.manager.unloadChunk(this.cx, this.cz, this.world);
 | 
				
			||||||
 | 
					        this.newManager.unloadChunk(this.cx, this.cz, this.world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(File yFile : dataDir.listFiles()) {
 | 
				
			||||||
 | 
					            if(!yFile.exists())
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            yFile.delete();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void stop() {
 | 
				
			||||||
 | 
					        if(this.taskID < 0)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.scheduler.cancelTask(taskID);
 | 
				
			||||||
 | 
					        this.taskID = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.cxs = null;
 | 
				
			||||||
 | 
					        this.czs = null;
 | 
				
			||||||
 | 
					        this.chunkletName = null;
 | 
				
			||||||
 | 
					        this.chunkName = null;
 | 
				
			||||||
 | 
					        this.manager = null;
 | 
				
			||||||
 | 
					        this.xDir = null;
 | 
				
			||||||
 | 
					        this.dataDir = null;
 | 
				
			||||||
 | 
					        this.tempChunklet = null;
 | 
				
			||||||
 | 
					        this.primitiveChunklet = null;
 | 
				
			||||||
 | 
					        this.primitiveExChunklet = null;
 | 
				
			||||||
 | 
					        this.currentChunk = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -19,7 +19,7 @@ import com.gmail.nossr50.mcMMO;
 | 
				
			|||||||
import com.gmail.nossr50.runnables.ChunkletUnloader;
 | 
					import com.gmail.nossr50.runnables.ChunkletUnloader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class HashChunkletManager implements ChunkletManager {
 | 
					public class HashChunkletManager implements ChunkletManager {
 | 
				
			||||||
    private HashMap<String, ChunkletStore> store = new HashMap<String, ChunkletStore>();
 | 
					    public HashMap<String, ChunkletStore> store = new HashMap<String, ChunkletStore>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void loadChunklet(int cx, int cy, int cz, World world) {
 | 
					    public void loadChunklet(int cx, int cy, int cz, World world) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ public class PrimitiveChunkletStore implements ChunkletStore {
 | 
				
			|||||||
    private static final long serialVersionUID = -3453078050608607478L;
 | 
					    private static final long serialVersionUID = -3453078050608607478L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** X, Z, Y */
 | 
					    /** X, Z, Y */
 | 
				
			||||||
    private boolean[][][] store = new boolean[16][16][64];
 | 
					    public boolean[][][] store = new boolean[16][16][64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean isTrue(int x, int y, int z) {
 | 
					    public boolean isTrue(int x, int y, int z) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ public class PrimitiveExChunkletStore implements ChunkletStore, Externalizable {
 | 
				
			|||||||
    private static final long serialVersionUID = 8603603827094383873L;
 | 
					    private static final long serialVersionUID = 8603603827094383873L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** X, Z, Y */
 | 
					    /** X, Z, Y */
 | 
				
			||||||
    private boolean[][][] store = new boolean[16][16][64];
 | 
					    public boolean[][][] store = new boolean[16][16][64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean isTrue(int x, int y, int z) {
 | 
					    public boolean isTrue(int x, int y, int z) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										168
									
								
								src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										168
									
								
								src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,168 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.util.blockmeta.chunkmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
 | 
					import org.bukkit.block.Block;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface ChunkManager {
 | 
				
			||||||
 | 
					    public void closeAll();
 | 
				
			||||||
 | 
					    public ChunkStore readChunkStore(World world, int x, int z) throws IOException;
 | 
				
			||||||
 | 
					    public void writeChunkStore(World world, int x, int z, ChunkStore data);
 | 
				
			||||||
 | 
					    public void closeChunkStore(World world, int x, int z);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Loads a specific chunklet
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @param cx Chunklet X coordinate that needs to be loaded
 | 
				
			||||||
 | 
					     * @param cy Chunklet Y coordinate that needs to be loaded
 | 
				
			||||||
 | 
					     * @param cz Chunklet Z coordinate that needs to be loaded
 | 
				
			||||||
 | 
					     * @param world World that the chunklet needs to be loaded in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void loadChunklet(int cx, int cy, int cz, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Unload a specific chunklet
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param cx Chunklet X coordinate that needs to be unloaded
 | 
				
			||||||
 | 
					     * @param cy Chunklet Y coordinate that needs to be unloaded
 | 
				
			||||||
 | 
					     * @param cz Chunklet Z coordinate that needs to be unloaded
 | 
				
			||||||
 | 
					     * @param world World that the chunklet needs to be unloaded from
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void unloadChunklet(int cx, int cy, int cz, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Load a given Chunk's Chunklet data
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param cx Chunk X coordinate that is to be loaded
 | 
				
			||||||
 | 
					     * @param cz Chunk Z coordinate that is to be loaded
 | 
				
			||||||
 | 
					     * @param world World that the Chunk is in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void loadChunk(int cx, int cz, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Unload a given Chunk's Chunklet data
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param cx Chunk X coordinate that is to be unloaded
 | 
				
			||||||
 | 
					     * @param cz Chunk Z coordinate that is to be unloaded
 | 
				
			||||||
 | 
					     * @param world World that the Chunk is in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void unloadChunk(int cx, int cz, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Saves a given Chunk's Chunklet data
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param cx Chunk X coordinate that is to be saved
 | 
				
			||||||
 | 
					     * @param cz Chunk Z coordinate that is to be saved
 | 
				
			||||||
 | 
					     * @param world World that the Chunk is in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void saveChunk(int cx, int cz, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean isChunkLoaded(int cx, int cz, World world);
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Informs the ChunkletManager a chunk is loaded
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param cx Chunk X coordinate that is loaded
 | 
				
			||||||
 | 
					     * @param cz Chunk Z coordinate that is loaded
 | 
				
			||||||
 | 
					     * @param world World that the chunk was loaded in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void chunkLoaded(int cx, int cz, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Informs the ChunkletManager a chunk is unloaded
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param cx Chunk X coordinate that is unloaded
 | 
				
			||||||
 | 
					     * @param cz Chunk Z coordinate that is unloaded
 | 
				
			||||||
 | 
					     * @param world World that the chunk was unloaded in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void chunkUnloaded(int cx, int cz, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save all ChunkletStores related to the given world
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param world World to save
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void saveWorld(World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Unload all ChunkletStores from memory related to the given world after saving them
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param world World to unload
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void unloadWorld(World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Load all ChunkletStores from all loaded chunks from this world into memory
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param world World to load
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void loadWorld(World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save all ChunkletStores
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void saveAll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Unload all ChunkletStores after saving them
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void unloadAll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check to see if a given location is set to true
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param x X coordinate to check
 | 
				
			||||||
 | 
					     * @param y Y coordinate to check
 | 
				
			||||||
 | 
					     * @param z Z coordinate to check
 | 
				
			||||||
 | 
					     * @param world World to check in
 | 
				
			||||||
 | 
					     * @return true if the given location is set to true, false if otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isTrue(int x, int y, int z, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check to see if a given block location is set to true
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param block Block location to check
 | 
				
			||||||
 | 
					     * @return true if the given block location is set to true, false if otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isTrue(Block block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set a given location to true, should create stores as necessary if the location does not exist
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param x X coordinate to set
 | 
				
			||||||
 | 
					     * @param y Y coordinate to set
 | 
				
			||||||
 | 
					     * @param z Z coordinate to set
 | 
				
			||||||
 | 
					     * @param world World to set in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setTrue(int x, int y, int z, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set a given block location to true, should create stores as necessary if the location does not exist
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param block Block location to set
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setTrue(Block block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set a given location to false, should not create stores if one does not exist for the given location
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param x X coordinate to set
 | 
				
			||||||
 | 
					     * @param y Y coordinate to set
 | 
				
			||||||
 | 
					     * @param z Z coordinate to set
 | 
				
			||||||
 | 
					     * @param world World to set in
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setFalse(int x, int y, int z, World world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set a given block location to false, should not create stores if one does not exist for the given location
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param block Block location to set
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setFalse(Block block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete any ChunkletStores that are empty
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void cleanUp();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.util.blockmeta.chunkmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.config.HiddenConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ChunkManagerFactory {
 | 
				
			||||||
 | 
					    public static ChunkManager getChunkManager() {
 | 
				
			||||||
 | 
					        HiddenConfig hConfig = HiddenConfig.getInstance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(hConfig.getChunkletsEnabled()) {
 | 
				
			||||||
 | 
					            return new HashChunkManager();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return new NullChunkManager();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										74
									
								
								src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.util.blockmeta.chunkmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.Serializable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.ChunkletStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A ChunkStore should be responsible for a 16x16xWorldHeight area of data
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public interface ChunkStore extends Serializable {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks the chunk's save state
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return true if the has been modified since it was last saved
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isDirty();
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks the chunk's save state
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param dirty the save state of the current chunk
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setDirty(boolean dirty);
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks the chunk's x coordinate
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return the chunk's x coordinate.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public int getChunkX();
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks the chunk's z coordinate
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return the chunk's z coordinate.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public int getChunkZ();
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks the value at the given coordinates
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param x x coordinate in current chunklet
 | 
				
			||||||
 | 
					     * @param y y coordinate in current chunklet
 | 
				
			||||||
 | 
					     * @param z z coordinate in current chunklet
 | 
				
			||||||
 | 
					     * @return true if the value is true at the given coordinates, false if otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isTrue(int x, int y, int z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set the value to true at the given coordinates
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param x x coordinate in current chunklet
 | 
				
			||||||
 | 
					     * @param y y coordinate in current chunklet
 | 
				
			||||||
 | 
					     * @param z z coordinate in current chunklet
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setTrue(int x, int y, int z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set the value to false at the given coordinates
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param x x coordinate in current chunklet
 | 
				
			||||||
 | 
					     * @param y y coordinate in current chunklet
 | 
				
			||||||
 | 
					     * @param z z coordinate in current chunklet
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setFalse(int x, int y, int z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return true if all values in the chunklet are false, false if otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isEmpty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set all values in this ChunkletStore to the values from another provided ChunkletStore
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param otherStore Another ChunkletStore that this one should copy all data from
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void copyFrom(ChunkletStore otherStore);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.util.blockmeta.chunkmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ChunkStoreFactory {
 | 
				
			||||||
 | 
					    protected static ChunkStore getChunkStore(World world, int x, int z) {
 | 
				
			||||||
 | 
					        // TODO: Add in loading from config what type of store we want.
 | 
				
			||||||
 | 
					        return new PrimitiveChunkStore(world, x, z);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										464
									
								
								src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										464
									
								
								src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,464 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.util.blockmeta.chunkmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.ObjectInputStream;
 | 
				
			||||||
 | 
					import java.io.ObjectOutputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.lang.Integer;
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					import java.util.Iterator;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
 | 
					import org.bukkit.block.Block;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.mcMMO;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.runnables.ChunkletUnloader;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.ChunkletStore;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.PrimitiveChunkletStore;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.PrimitiveExChunkletStore;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.HashChunkletManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.getspout.spoutapi.chunkstore.mcMMOSimpleRegionFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class HashChunkManager implements ChunkManager {
 | 
				
			||||||
 | 
					    private HashMap<UUID, HashMap<Long, mcMMOSimpleRegionFile>> regionFiles = new HashMap<UUID, HashMap<Long, mcMMOSimpleRegionFile>>();
 | 
				
			||||||
 | 
					    public HashMap<String, ChunkStore> store = new HashMap<String, ChunkStore>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void closeAll() {
 | 
				
			||||||
 | 
					        for (UUID uid : regionFiles.keySet()) {
 | 
				
			||||||
 | 
					            HashMap<Long, mcMMOSimpleRegionFile> worldRegions = regionFiles.get(uid);
 | 
				
			||||||
 | 
					            Iterator<mcMMOSimpleRegionFile> itr = worldRegions.values().iterator();
 | 
				
			||||||
 | 
					            while (itr.hasNext()) {
 | 
				
			||||||
 | 
					                mcMMOSimpleRegionFile rf = itr.next();
 | 
				
			||||||
 | 
					                if (rf != null) {
 | 
				
			||||||
 | 
					                    rf.close();
 | 
				
			||||||
 | 
					                    itr.remove();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        regionFiles.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public ChunkStore readChunkStore(World world, int x, int z) throws IOException {
 | 
				
			||||||
 | 
					        mcMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
 | 
				
			||||||
 | 
					        InputStream in = rf.getInputStream(x, z);
 | 
				
			||||||
 | 
					        if (in == null) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ObjectInputStream objectStream = new ObjectInputStream(in);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Object o = objectStream.readObject();
 | 
				
			||||||
 | 
					            if (o instanceof ChunkStore) {
 | 
				
			||||||
 | 
					                return (ChunkStore) o;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                throw new RuntimeException("Wrong class type read for chunk meta data for " + x + ", " + z);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            // Assume the format changed
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					            //throw new RuntimeException("Unable to process chunk meta data for " + x + ", " + z, e);
 | 
				
			||||||
 | 
					        } catch (ClassNotFoundException e) {
 | 
				
			||||||
 | 
					            // Assume the format changed
 | 
				
			||||||
 | 
					            //System.out.println("[SpoutPlugin] is Unable to find serialized class for " + x + ", " + z + ", " + e.getMessage());
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					            //throw new RuntimeException("Unable to find serialized class for " + x + ", " + z, e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void writeChunkStore(World world, int x, int z, ChunkStore data) {
 | 
				
			||||||
 | 
					        if (!data.isDirty()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            mcMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
 | 
				
			||||||
 | 
					            ObjectOutputStream objectStream = new ObjectOutputStream(rf.getOutputStream(x, z));
 | 
				
			||||||
 | 
					            objectStream.writeObject(data);
 | 
				
			||||||
 | 
					            objectStream.flush();
 | 
				
			||||||
 | 
					            objectStream.close();
 | 
				
			||||||
 | 
					            data.setDirty(false);
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            throw new RuntimeException("Unable to write chunk meta data for " + x + ", " + z, e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void closeChunkStore(World world, int x, int z) {
 | 
				
			||||||
 | 
					        mcMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
 | 
				
			||||||
 | 
					        if (rf != null) {
 | 
				
			||||||
 | 
					            rf.close();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private mcMMOSimpleRegionFile getSimpleRegionFile(World world, int x, int z) {
 | 
				
			||||||
 | 
					        File directory = new File(world.getWorldFolder(), "mcmmo_regions");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        directory.mkdirs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        UUID key = world.getUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        HashMap<Long, mcMMOSimpleRegionFile> worldRegions = regionFiles.get(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (worldRegions == null) {
 | 
				
			||||||
 | 
					            worldRegions = new HashMap<Long, mcMMOSimpleRegionFile>();
 | 
				
			||||||
 | 
					            regionFiles.put(key, worldRegions);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int rx = x >> 5;
 | 
				
			||||||
 | 
					        int rz = z >> 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        long key2 = (((long) rx) << 32) | (((long) rz) & 0xFFFFFFFFL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mcMMOSimpleRegionFile regionFile = worldRegions.get(key2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (regionFile == null) {
 | 
				
			||||||
 | 
					            File file = new File(directory, "mcmmo_" + rx + "_" + rz + "_.mcm");
 | 
				
			||||||
 | 
					            regionFile = new mcMMOSimpleRegionFile(file, rx, rz);
 | 
				
			||||||
 | 
					            worldRegions.put(key2, regionFile);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return regionFile;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadChunklet(int cx, int cy, int cz, World world) {
 | 
				
			||||||
 | 
					        loadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadChunklet(int cx, int cy, int cz, World world) {
 | 
				
			||||||
 | 
					        unloadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadChunk(int cx, int cz, World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(store.containsKey(world.getName() + "," + cx + "," + cz))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ChunkStore in = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            in = readChunkStore(world, cx, cz);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch(Exception e) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(in != null) {
 | 
				
			||||||
 | 
					            store.put(world.getName() + "," + cx + "," + cz, in);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadChunk(int cx, int cz, World world) {
 | 
				
			||||||
 | 
					        saveChunk(cx, cz, world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(store.containsKey(world.getName() + "," + cx + "," + cz)) {
 | 
				
			||||||
 | 
					            store.remove(world.getName() + "," + cx + "," + cz);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void saveChunk(int cx, int cz, World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(store.containsKey(world.getName() + "," + cx + "," + cz)) {
 | 
				
			||||||
 | 
					            ChunkStore out = store.get(world.getName() + "," + cx + "," + cz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!out.isDirty())
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            writeChunkStore(world, cx, cz, out);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isChunkLoaded(int cx, int cz, World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return store.containsKey(world.getName() + "," + cx + "," + cz);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void chunkLoaded(int cx, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void chunkUnloaded(int cx, int cz, World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ChunkletUnloader.addToList(cx, cx, world);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void saveWorld(World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        closeAll();
 | 
				
			||||||
 | 
					        String worldName = world.getName();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(String key : store.keySet()) {
 | 
				
			||||||
 | 
					            String[] info = key.split(",");
 | 
				
			||||||
 | 
					            if(worldName.equals(info[0])) {
 | 
				
			||||||
 | 
					                int cx = 0;
 | 
				
			||||||
 | 
					                int cz = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    cx = Integer.parseInt(info[1]);
 | 
				
			||||||
 | 
							    cz = Integer.parseInt(info[2]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
							catch(Exception e) {
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                saveChunk(cx, cz, world);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadWorld(World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        closeAll();
 | 
				
			||||||
 | 
					        String worldName = world.getName();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(String key : store.keySet()) {
 | 
				
			||||||
 | 
					            String[] info = key.split(",");
 | 
				
			||||||
 | 
					            if(worldName.equals(info[0])) {
 | 
				
			||||||
 | 
					                int cx = 0;
 | 
				
			||||||
 | 
					                int cz = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    cx = Integer.parseInt(info[1]);
 | 
				
			||||||
 | 
							    cz = Integer.parseInt(info[2]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
							catch(Exception e) {
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                unloadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadWorld(World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void saveAll() {
 | 
				
			||||||
 | 
					        closeAll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(World world : Bukkit.getWorlds()) {
 | 
				
			||||||
 | 
					            saveWorld(world);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadAll() {
 | 
				
			||||||
 | 
					        closeAll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(World world : Bukkit.getWorlds()) {
 | 
				
			||||||
 | 
					            unloadWorld(world);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isTrue(int x, int y, int z, World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int cx = x / 16;
 | 
				
			||||||
 | 
					        int cz = z / 16;
 | 
				
			||||||
 | 
					        String key = world.getName() + "," + cx + "," + cz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!store.containsKey(key)) {
 | 
				
			||||||
 | 
					            loadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!store.containsKey(key)) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ChunkStore check = store.get(key);
 | 
				
			||||||
 | 
					        int ix = Math.abs(x) % 16;
 | 
				
			||||||
 | 
					        int iz = Math.abs(z) % 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return check.isTrue(ix, y, iz);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isTrue(Block block) {
 | 
				
			||||||
 | 
					        if(block == null)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setTrue(int x, int y, int z, World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int cx = x / 16;
 | 
				
			||||||
 | 
					        int cz = z / 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int ix = Math.abs(x) % 16;
 | 
				
			||||||
 | 
					        int iz = Math.abs(z) % 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String key = world.getName() + "," + cx + "," + cz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!store.containsKey(key)) {
 | 
				
			||||||
 | 
					            loadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ChunkStore cStore = store.get(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (cStore == null) {
 | 
				
			||||||
 | 
					            cStore = ChunkStoreFactory.getChunkStore(world, cx, cz);
 | 
				
			||||||
 | 
					            store.put(key, cStore);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cStore.setTrue(ix, y, iz);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setTrue(Block block) {
 | 
				
			||||||
 | 
					        if(block == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setFalse(int x, int y, int z, World world) {
 | 
				
			||||||
 | 
					        if(world == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int cx = x / 16;
 | 
				
			||||||
 | 
					        int cz = z / 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int ix = Math.abs(x) % 16;
 | 
				
			||||||
 | 
					        int iz = Math.abs(z) % 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String key = world.getName() + "," + cx + "," + cz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!store.containsKey(key)) {
 | 
				
			||||||
 | 
					            loadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ChunkStore cStore = store.get(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (cStore == null) {
 | 
				
			||||||
 | 
					            return; //No need to make a store for something we will be setting to false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cStore.setFalse(ix, y, iz);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setFalse(Block block) {
 | 
				
			||||||
 | 
					        if(block == null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void cleanUp() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void convertChunk(File dataDir, int cx, int cz, World world) {
 | 
				
			||||||
 | 
					        HashChunkletManager manager = new HashChunkletManager();
 | 
				
			||||||
 | 
					        manager.loadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(int y = 0; y < (world.getMaxHeight() / 64); y++) {
 | 
				
			||||||
 | 
					            String chunkletName = world.getName() + "," + cx + "," + cz + "," + y;
 | 
				
			||||||
 | 
						    ChunkletStore tempChunklet = manager.store.get(chunkletName);
 | 
				
			||||||
 | 
					            PrimitiveChunkletStore primitiveChunklet = null;
 | 
				
			||||||
 | 
					            PrimitiveExChunkletStore primitiveExChunklet = null;
 | 
				
			||||||
 | 
					            if(tempChunklet instanceof PrimitiveChunkletStore)
 | 
				
			||||||
 | 
					                primitiveChunklet = (PrimitiveChunkletStore) tempChunklet;
 | 
				
			||||||
 | 
					            else if(tempChunklet instanceof PrimitiveExChunkletStore)
 | 
				
			||||||
 | 
					                primitiveExChunklet = (PrimitiveExChunkletStore) tempChunklet;
 | 
				
			||||||
 | 
					            if(tempChunklet == null) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                String chunkName = world.getName() + "," + cx + "," + cz;
 | 
				
			||||||
 | 
					                PrimitiveChunkStore cChunk = (PrimitiveChunkStore) store.get(chunkName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(cChunk != null) {
 | 
				
			||||||
 | 
					                    int xPos = cx * 16;
 | 
				
			||||||
 | 
					                    int zPos = cz * 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for(int x = 0; x < 16; x++) {
 | 
				
			||||||
 | 
					                        for(int z = 0; z < 16; z++) {
 | 
				
			||||||
 | 
					                            int cxPos = xPos + x;
 | 
				
			||||||
 | 
					                            int czPos = zPos + z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            for(int y2 = (64 * y); y2 < (64 * y + 64); y2++) {
 | 
				
			||||||
 | 
					                                if(!manager.isTrue(cxPos, y2, czPos, world))
 | 
				
			||||||
 | 
					                                    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                setTrue(cxPos, y2, czPos, world);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                setTrue(cx * 16, 0, cz * 16, world);
 | 
				
			||||||
 | 
							setFalse(cx * 16, 0, cz * 16, world);
 | 
				
			||||||
 | 
					                cChunk = (PrimitiveChunkStore) store.get(chunkName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for(int x = 0; x < 16; x++) {
 | 
				
			||||||
 | 
					                    for(int z = 0; z < 16; z++) {
 | 
				
			||||||
 | 
					                        boolean[] oldArray;
 | 
				
			||||||
 | 
					                        if(primitiveChunklet != null)
 | 
				
			||||||
 | 
					                            oldArray = primitiveChunklet.store[x][z];
 | 
				
			||||||
 | 
					                        if(primitiveExChunklet != null)
 | 
				
			||||||
 | 
					                            oldArray = primitiveExChunklet.store[x][z];
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        boolean[] newArray = cChunk.store[x][z];
 | 
				
			||||||
 | 
					                        if(oldArray.length < 64)
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        else if(newArray.length < ((y * 64) + 64))
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        System.arraycopy(oldArray, 0, newArray, (y * 64), 64);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        manager.unloadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					        unloadChunk(cx, cz, world);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        File cxDir = new File(dataDir, "" + cx);
 | 
				
			||||||
 | 
					        if(!cxDir.exists()) return;
 | 
				
			||||||
 | 
					        File czDir = new File(cxDir, "" + cz);
 | 
				
			||||||
 | 
					        if(!czDir.exists()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(File yFile : czDir.listFiles()) {
 | 
				
			||||||
 | 
					            if(!yFile.exists())
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            yFile.delete();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(czDir.listFiles().length <= 0)
 | 
				
			||||||
 | 
					            czDir.delete();
 | 
				
			||||||
 | 
					        if(cxDir.listFiles().length <= 0)
 | 
				
			||||||
 | 
					            cxDir.delete();
 | 
				
			||||||
 | 
					        if(dataDir.listFiles().length <= 0)
 | 
				
			||||||
 | 
					            dataDir.delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.util.blockmeta.chunkmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
 | 
					import org.bukkit.block.Block;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class NullChunkManager implements ChunkManager {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void closeAll() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public ChunkStore readChunkStore(World world, int x, int z) throws IOException {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void writeChunkStore(World world, int x, int z, ChunkStore data) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void closeChunkStore(World world, int x, int z) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadChunklet(int cx, int cy, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadChunklet(int cx, int cy, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadChunk(int cx, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadChunk(int cx, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void saveChunk(int cx, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isChunkLoaded(int cx, int cz, World world) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void chunkLoaded(int cx, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void chunkUnloaded(int cx, int cz, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void saveWorld(World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadWorld(World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadWorld(World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void saveAll() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void unloadAll() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isTrue(int x, int y, int z, World world) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isTrue(Block block) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setTrue(int x, int y, int z, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setTrue(Block block) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setFalse(int x, int y, int z, World world) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setFalse(Block block) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void cleanUp() {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					package com.gmail.nossr50.util.blockmeta.chunkmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.ObjectInputStream;
 | 
				
			||||||
 | 
					import java.io.ObjectOutputStream;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.World;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.gmail.nossr50.mcMMO;
 | 
				
			||||||
 | 
					import com.gmail.nossr50.util.blockmeta.ChunkletStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class PrimitiveChunkStore implements ChunkStore {
 | 
				
			||||||
 | 
					    private static final long serialVersionUID = -1L;
 | 
				
			||||||
 | 
					    transient private boolean dirty = false;
 | 
				
			||||||
 | 
					    /** X, Z, Y */
 | 
				
			||||||
 | 
					    public boolean[][][] store;
 | 
				
			||||||
 | 
					    private static final int CURRENT_VERSION = 4;
 | 
				
			||||||
 | 
					    private static final int MAGIC_NUMBER = 0xEA5EDEBB;
 | 
				
			||||||
 | 
					    private int cx;
 | 
				
			||||||
 | 
					    private int cz;
 | 
				
			||||||
 | 
					    private UUID worldUid;
 | 
				
			||||||
 | 
					    transient private int worldHeight;
 | 
				
			||||||
 | 
					    transient private int xBitShifts;
 | 
				
			||||||
 | 
					    transient private int zBitShifts;
 | 
				
			||||||
 | 
					    transient private boolean conversionNeeded;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public PrimitiveChunkStore(World world, int cx, int cz) {
 | 
				
			||||||
 | 
					        this.cx = cx;
 | 
				
			||||||
 | 
					        this.cz = cz;
 | 
				
			||||||
 | 
						this.worldUid = world.getUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.worldHeight = world != null ? world.getMaxHeight() : 128;
 | 
				
			||||||
 | 
					        this.xBitShifts = 11;
 | 
				
			||||||
 | 
					        this.zBitShifts = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.store = new boolean[16][16][this.worldHeight - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conversionNeeded = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isDirty() {
 | 
				
			||||||
 | 
					        return dirty;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setDirty(boolean dirty) {
 | 
				
			||||||
 | 
					        this.dirty = dirty;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getChunkX() {
 | 
				
			||||||
 | 
					        return cx;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getChunkZ() {
 | 
				
			||||||
 | 
					        return cz;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isTrue(int x, int y, int z) {
 | 
				
			||||||
 | 
					        return store[x][z][y];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setTrue(int x, int y, int z) {
 | 
				
			||||||
 | 
					        store[x][z][y] = true;
 | 
				
			||||||
 | 
					        dirty = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setFalse(int x, int y, int z) {
 | 
				
			||||||
 | 
					        store[x][z][y] = false;
 | 
				
			||||||
 | 
					        dirty = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean isEmpty() {
 | 
				
			||||||
 | 
					        for(int x = 0; x < 16; x++) {
 | 
				
			||||||
 | 
					            for(int z = 0; z < 16; z++) {
 | 
				
			||||||
 | 
					                for(int y = 0; y < this.worldHeight; y++) {
 | 
				
			||||||
 | 
					                    if(store[x][z][y]) return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void copyFrom(ChunkletStore otherStore) {
 | 
				
			||||||
 | 
					        for(int x = 0; x < 16; x++) {
 | 
				
			||||||
 | 
					            for(int z = 0; z < 16; z++) {
 | 
				
			||||||
 | 
					                for(int y = 0; y < this.worldHeight; y++) {
 | 
				
			||||||
 | 
					                    store[x][z][y] = otherStore.isTrue(x, y, z);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dirty = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void writeObject(ObjectOutputStream out) throws IOException {
 | 
				
			||||||
 | 
					        out.writeInt(MAGIC_NUMBER);
 | 
				
			||||||
 | 
					        out.writeInt(CURRENT_VERSION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        out.writeLong(worldUid.getLeastSignificantBits());
 | 
				
			||||||
 | 
					        out.writeLong(worldUid.getMostSignificantBits());
 | 
				
			||||||
 | 
					        out.writeInt(cx);
 | 
				
			||||||
 | 
					        out.writeInt(cz);
 | 
				
			||||||
 | 
						out.writeObject(store);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dirty = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 | 
				
			||||||
 | 
					        int fileVersionNumber; // Can be used to determine the format of the file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        long lsb = in.readLong();
 | 
				
			||||||
 | 
					        if (((int) (lsb >> 32)) == MAGIC_NUMBER) {
 | 
				
			||||||
 | 
					            fileVersionNumber = (int) lsb;
 | 
				
			||||||
 | 
					            lsb = in.readLong();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            fileVersionNumber = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        long msb = in.readLong();
 | 
				
			||||||
 | 
					        worldUid = new UUID(msb, lsb);
 | 
				
			||||||
 | 
					        cx = in.readInt();
 | 
				
			||||||
 | 
					        cz = in.readInt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Constructor is not invoked, need to set these fields
 | 
				
			||||||
 | 
					        World world = mcMMO.p.getServer().getWorld(this.worldUid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.worldHeight = world.getMaxHeight();
 | 
				
			||||||
 | 
					        this.xBitShifts = 11;
 | 
				
			||||||
 | 
					        this.zBitShifts = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        store = (boolean[][][]) in.readObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (fileVersionNumber < CURRENT_VERSION) {
 | 
				
			||||||
 | 
					            dirty = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleChunkBuffer.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										39
									
								
								src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleChunkBuffer.java
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This file is part of SpoutPlugin.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
 | 
				
			||||||
 | 
					 * SpoutPlugin is licensed under the GNU Lesser General Public License.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SpoutPlugin 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SpoutPlugin 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 org.getspout.spoutapi.chunkstore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class mcMMOSimpleChunkBuffer extends ByteArrayOutputStream {
 | 
				
			||||||
 | 
						final mcMMOSimpleRegionFile rf;
 | 
				
			||||||
 | 
						final int index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mcMMOSimpleChunkBuffer(mcMMOSimpleRegionFile rf, int index) {
 | 
				
			||||||
 | 
							super(1024);
 | 
				
			||||||
 | 
							this.rf = rf;
 | 
				
			||||||
 | 
							this.index = index;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public void close() throws IOException {
 | 
				
			||||||
 | 
							rf.write(index, buf, count);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										300
									
								
								src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleRegionFile.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										300
									
								
								src/main/java/org/getspout/spoutapi/chunkstore/mcMMOSimpleRegionFile.java
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,300 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This file is part of SpoutPlugin.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
 | 
				
			||||||
 | 
					 * SpoutPlugin is licensed under the GNU Lesser General Public License.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SpoutPlugin 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SpoutPlugin 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 org.getspout.spoutapi.chunkstore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayInputStream;
 | 
				
			||||||
 | 
					import java.io.DataInputStream;
 | 
				
			||||||
 | 
					import java.io.DataOutputStream;
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.RandomAccessFile;
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.zip.DeflaterOutputStream;
 | 
				
			||||||
 | 
					import java.util.zip.InflaterInputStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class mcMMOSimpleRegionFile {
 | 
				
			||||||
 | 
						private RandomAccessFile file;
 | 
				
			||||||
 | 
						private final int[] dataStart = new int[1024];
 | 
				
			||||||
 | 
						private final int[] dataActualLength = new int[1024];
 | 
				
			||||||
 | 
						private final int[] dataLength = new int[1024];
 | 
				
			||||||
 | 
						private final ArrayList<Boolean> inuse = new ArrayList<Boolean>();
 | 
				
			||||||
 | 
						private int segmentSize;
 | 
				
			||||||
 | 
						private int segmentMask;
 | 
				
			||||||
 | 
						private final int rx;
 | 
				
			||||||
 | 
						private final int rz;
 | 
				
			||||||
 | 
						private final int defaultSegmentSize;
 | 
				
			||||||
 | 
						private final File parent;
 | 
				
			||||||
 | 
						@SuppressWarnings("unused")
 | 
				
			||||||
 | 
						private long lastAccessTime = System.currentTimeMillis();
 | 
				
			||||||
 | 
						@SuppressWarnings("unused")
 | 
				
			||||||
 | 
						private static long TIMEOUT_TIME = 300000; // 5 min
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public mcMMOSimpleRegionFile(File f, int rx, int rz) {
 | 
				
			||||||
 | 
							this(f, rx, rz, 10);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public mcMMOSimpleRegionFile(File f, int rx, int rz, int defaultSegmentSize) {
 | 
				
			||||||
 | 
							this.rx = rx;
 | 
				
			||||||
 | 
							this.rz = rz;
 | 
				
			||||||
 | 
							this.defaultSegmentSize = defaultSegmentSize;
 | 
				
			||||||
 | 
							this.parent = f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							lastAccessTime = System.currentTimeMillis();
 | 
				
			||||||
 | 
							if (file == null) {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									this.file = new RandomAccessFile(parent, "rw");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (file.length() < 4096 * 3) {
 | 
				
			||||||
 | 
										for (int i = 0; i < 1024 * 3; i++) {
 | 
				
			||||||
 | 
											file.writeInt(0);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										file.seek(4096 * 2);
 | 
				
			||||||
 | 
										file.writeInt(defaultSegmentSize);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									file.seek(4096 * 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									this.segmentSize = file.readInt();
 | 
				
			||||||
 | 
									this.segmentMask = (1 << segmentSize) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									int reservedSegments = this.sizeToSegments(4096 * 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < reservedSegments; i++) {
 | 
				
			||||||
 | 
										while (inuse.size() <= i) {
 | 
				
			||||||
 | 
											inuse.add(false);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										inuse.set(i, true);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									file.seek(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < 1024; i++) {
 | 
				
			||||||
 | 
										dataStart[i] = file.readInt();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < 1024; i++) {
 | 
				
			||||||
 | 
										dataActualLength[i] = file.readInt();
 | 
				
			||||||
 | 
										dataLength[i] = sizeToSegments(dataActualLength[i]);
 | 
				
			||||||
 | 
										setInUse(i, true);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									extendFile();
 | 
				
			||||||
 | 
								} catch (IOException fnfe) {
 | 
				
			||||||
 | 
									throw new RuntimeException(fnfe);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public final RandomAccessFile getFile() {
 | 
				
			||||||
 | 
							lastAccessTime = System.currentTimeMillis();
 | 
				
			||||||
 | 
							if (file == null) {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									this.file = new RandomAccessFile(parent, "rw");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (file.length() < 4096 * 3) {
 | 
				
			||||||
 | 
										for (int i = 0; i < 1024 * 3; i++) {
 | 
				
			||||||
 | 
											file.writeInt(0);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										file.seek(4096 * 2);
 | 
				
			||||||
 | 
										file.writeInt(defaultSegmentSize);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									file.seek(4096 * 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									this.segmentSize = file.readInt();
 | 
				
			||||||
 | 
									this.segmentMask = (1 << segmentSize) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									int reservedSegments = this.sizeToSegments(4096 * 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < reservedSegments; i++) {
 | 
				
			||||||
 | 
										while (inuse.size() <= i) {
 | 
				
			||||||
 | 
											inuse.add(false);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										inuse.set(i, true);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									file.seek(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < 1024; i++) {
 | 
				
			||||||
 | 
										dataStart[i] = file.readInt();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < 1024; i++) {
 | 
				
			||||||
 | 
										dataActualLength[i] = file.readInt();
 | 
				
			||||||
 | 
										dataLength[i] = sizeToSegments(dataActualLength[i]);
 | 
				
			||||||
 | 
										setInUse(i, true);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									extendFile();
 | 
				
			||||||
 | 
								} catch (IOException fnfe) {
 | 
				
			||||||
 | 
									throw new RuntimeException(fnfe);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return file;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public boolean testCloseTimeout() {
 | 
				
			||||||
 | 
							/*if (System.currentTimeMillis() - TIMEOUT_TIME > lastAccessTime) {
 | 
				
			||||||
 | 
								close();
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}*/
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public DataOutputStream getOutputStream(int x, int z) {
 | 
				
			||||||
 | 
							int index = getChunkIndex(x, z);
 | 
				
			||||||
 | 
							return new DataOutputStream(new DeflaterOutputStream(new mcMMOSimpleChunkBuffer(this, index)));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public DataInputStream getInputStream(int x, int z) throws IOException {
 | 
				
			||||||
 | 
							int index = getChunkIndex(x, z);
 | 
				
			||||||
 | 
							int actualLength = dataActualLength[index];
 | 
				
			||||||
 | 
							if (actualLength == 0) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							byte[] data = new byte[actualLength];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							getFile().seek(dataStart[index] << segmentSize);
 | 
				
			||||||
 | 
							getFile().readFully(data);
 | 
				
			||||||
 | 
							return new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(data)));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void write(int index, byte[] buffer, int size) throws IOException {
 | 
				
			||||||
 | 
							int oldStart = setInUse(index, false);
 | 
				
			||||||
 | 
							int start = findSpace(oldStart, size);
 | 
				
			||||||
 | 
							getFile().seek(start << segmentSize);
 | 
				
			||||||
 | 
							getFile().write(buffer, 0, size);
 | 
				
			||||||
 | 
							dataStart[index] = start;
 | 
				
			||||||
 | 
							dataActualLength[index] = size;
 | 
				
			||||||
 | 
							dataLength[index] = sizeToSegments(size);
 | 
				
			||||||
 | 
							setInUse(index, true);
 | 
				
			||||||
 | 
							saveFAT();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void close() {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								if (file != null) {
 | 
				
			||||||
 | 
									file.seek(4096 * 2);
 | 
				
			||||||
 | 
									file.close();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								file = null;
 | 
				
			||||||
 | 
							} catch (IOException ioe) {
 | 
				
			||||||
 | 
								throw new RuntimeException("Unable to close file", ioe);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private int setInUse(int index, boolean used) {
 | 
				
			||||||
 | 
							if (dataActualLength[index] == 0) {
 | 
				
			||||||
 | 
								return dataStart[index];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int start = dataStart[index];
 | 
				
			||||||
 | 
							int end = start + dataLength[index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = start; i < end; i++) {
 | 
				
			||||||
 | 
								while (i > inuse.size() - 1) {
 | 
				
			||||||
 | 
									inuse.add(false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Boolean old = inuse.set(i, used);
 | 
				
			||||||
 | 
								if (old != null && old == used) {
 | 
				
			||||||
 | 
									if (old) {
 | 
				
			||||||
 | 
										throw new IllegalStateException("Attempting to overwrite an in-use segment");
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										throw new IllegalStateException("Attempting to delete empty segment");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return dataStart[index];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void extendFile() throws IOException {
 | 
				
			||||||
 | 
							long extend = (-getFile().length()) & segmentMask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							getFile().seek(getFile().length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while ((extend--) > 0) {
 | 
				
			||||||
 | 
								getFile().write(0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private int findSpace(int oldStart, int size) {
 | 
				
			||||||
 | 
							int segments = sizeToSegments(size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							boolean oldFree = true;
 | 
				
			||||||
 | 
							for (int i = oldStart; i < inuse.size() && i < oldStart + segments; i++) {
 | 
				
			||||||
 | 
								if (inuse.get(i)) {
 | 
				
			||||||
 | 
									oldFree = false;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (oldFree) {
 | 
				
			||||||
 | 
								return oldStart;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int start = 0;
 | 
				
			||||||
 | 
							int end = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while (end < inuse.size()) {
 | 
				
			||||||
 | 
								if (inuse.get(end)) {
 | 
				
			||||||
 | 
									end++;
 | 
				
			||||||
 | 
									start = end;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									end++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (end - start >= segments) {
 | 
				
			||||||
 | 
									return start;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return start;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private int sizeToSegments(int size) {
 | 
				
			||||||
 | 
							if (size <= 0) {
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return ((size - 1) >> segmentSize) + 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private Integer getChunkIndex(int x, int z) {
 | 
				
			||||||
 | 
							if (rx != (x >> 5) || rz != (z >> 5)) {
 | 
				
			||||||
 | 
								throw new RuntimeException(x + ", " + z + " not in region " + rx + ", " + rz);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							x = x & 0x1F;
 | 
				
			||||||
 | 
							z = z & 0x1F;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return (x << 5) + z;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void saveFAT() throws IOException {
 | 
				
			||||||
 | 
							getFile().seek(0);
 | 
				
			||||||
 | 
							for (int i = 0; i < 1024; i++) {
 | 
				
			||||||
 | 
								getFile().writeInt(dataStart[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < 1024; i++) {
 | 
				
			||||||
 | 
								getFile().writeInt(dataActualLength[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,4 +4,6 @@
 | 
				
			|||||||
###
 | 
					###
 | 
				
			||||||
Options:
 | 
					Options:
 | 
				
			||||||
    # true to use Chunklets metadata store system, false to disable
 | 
					    # true to use Chunklets metadata store system, false to disable
 | 
				
			||||||
    Chunklets: true
 | 
					    Chunklets: true
 | 
				
			||||||
 | 
					    # Square root of the number of chunks to convert per tick.
 | 
				
			||||||
 | 
					    ConversionRate: 3
 | 
				
			||||||
		Reference in New Issue
	
	Block a user