Skip to content

Commit

Permalink
Add ability to change biome in unloaded chunks (#28).
Browse files Browse the repository at this point in the history
Create new object that stores information about pending biome change operation per chunk.
Add new ChunkLoadListener that fires on ChunkLoadEvent and changes biome in given chunk, if it is in pending list.
Add new operation that force-load chunk once per 5 ticks and change biome in it.
  • Loading branch information
BONNe committed Jul 5, 2019
1 parent a1eafe0 commit e6b0846
Show file tree
Hide file tree
Showing 7 changed files with 668 additions and 14 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
<java.version>1.8</java.version>
<powermock.version>1.7.4</powermock.version>
<!-- More visible way how to change dependency versions -->
<spigot.version>1.13.2-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.5.2</bentobox.version>
<spigot.version>1.14.3-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.5.3</bentobox.version>
<level.version>1.5.0</level.version>
<vault.version>1.7</vault.version>
<anvilgui.version>a07c9b64f7</anvilgui.version>
Expand Down
40 changes: 37 additions & 3 deletions src/main/java/world/bentobox/biomes/BiomesAddon.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@

import org.bukkit.Bukkit;
import org.bukkit.Material;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.World;
import java.util.Iterator;
import java.util.Optional;

import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.biomes.commands.admin.AdminCommand;
import world.bentobox.biomes.commands.user.BiomesCommand;
import world.bentobox.biomes.database.objects.BiomeChunkUpdateObject;
import world.bentobox.biomes.handlers.BiomeDataRequestHandler;
import world.bentobox.biomes.handlers.BiomeListRequestHandler;
import world.bentobox.biomes.handlers.ChangeBiomeRequestHandler;
import world.bentobox.biomes.listeners.ChangeOwnerListener;
import world.bentobox.biomes.config.Settings;
import world.bentobox.biomes.listeners.ChunkLoadListener;
import world.bentobox.level.Level;


Expand Down Expand Up @@ -121,6 +122,7 @@ public void onEnable()

// Register the reset listener
this.registerListener(new ChangeOwnerListener(this));
this.registerListener(new ChunkLoadListener(this));

// Register Flags
this.registerFlag(BIOMES_WORLD_PROTECTION);
Expand All @@ -131,6 +133,38 @@ public void onEnable()
this.registerRequestHandler(new BiomeListRequestHandler(this));

this.registerRequestHandler(new ChangeBiomeRequestHandler(this));

// This task will force-load chunk every 5th tick if its biome is not updated.
Bukkit.getScheduler().runTaskTimer(this.getPlugin(), () -> {
Iterator<BiomeChunkUpdateObject> iterator = this.addonManager.getBiomeUpdaterCollection().iterator();

// if there is nothing to load, then skip.
if (!iterator.hasNext())
{
return;
}

BiomeChunkUpdateObject updater = iterator.next();

// if chunk is already force-loaded, then skip.
while (iterator.hasNext() && updater.isForceLoaded())
{
updater = iterator.next();
}

World world = updater.getWorld();

// if chunk is loaded then skip.
if (!world.isChunkLoaded(updater.getChunkX(), updater.getChunkZ()))
{
// Set flag as force-loaded.
updater.setForceLoaded(true);

// force-load chunk.
world.setChunkForceLoaded(updater.getChunkX(), updater.getChunkZ(), true);
world.loadChunk(updater.getChunkX(), updater.getChunkZ());
}
}, 5L, 5L);
}
else
{
Expand Down
92 changes: 91 additions & 1 deletion src/main/java/world/bentobox/biomes/BiomesAddonManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.util.ItemParser;
import world.bentobox.bentobox.util.Util;
import world.bentobox.biomes.database.objects.BiomeChunkUpdateObject;
import world.bentobox.biomes.database.objects.BiomesObject;
import world.bentobox.biomes.config.Settings.VisibilityMode;
import world.bentobox.biomes.panels.GuiUtils;
Expand Down Expand Up @@ -45,6 +46,9 @@ protected BiomesAddonManager(BiomesAddon addon)
this.addon.saveResource("biomes.yml", false);
}

this.biomePendingChunkUpdateDatabase = new Database<>(addon, BiomeChunkUpdateObject.class);
this.biomePendingChunkUpdateMap = new HashMap<>();

this.load();

// TODO: Remove this code after some time, as this is just a protective code against invalid world names.
Expand All @@ -56,7 +60,9 @@ protected BiomesAddonManager(BiomesAddon addon)
biomesObject.setWorld(biomesObject.getWorld().toLowerCase());
biomesObject.setUniqueId(biomesObject.getUniqueId().toLowerCase());

this.addon.logWarning("Biomes addon fixed your data for biome " + biomesObject.getUniqueId() + ". 1.14 does not allow to use capital letters in world names.");
this.addon.logWarning("Biomes addon fixed your data for biome "
+ biomesObject.getUniqueId() +
". 1.14 does not allow to use capital letters in world names.");
}
});
}
Expand All @@ -74,9 +80,12 @@ protected BiomesAddonManager(BiomesAddon addon)
private void load()
{
this.biomesCacheData.clear();
this.biomePendingChunkUpdateMap.clear();

this.addon.getLogger().info("Loading biomes...");

this.biomesDatabase.loadObjects().forEach(this::loadBiomes);
this.biomePendingChunkUpdateDatabase.loadObjects().forEach(this::addChunkUpdateObject);
}


Expand All @@ -89,6 +98,9 @@ public void reload()

this.biomesDatabase = new Database<>(this.addon, BiomesObject.class);
this.biomesDatabase.loadObjects().forEach(this::loadBiomes);

this.biomePendingChunkUpdateDatabase = new Database<>(this.addon, BiomeChunkUpdateObject.class);
this.biomePendingChunkUpdateDatabase.loadObjects().forEach(this::addChunkUpdateObject);
}


Expand All @@ -113,6 +125,19 @@ public void saveBiome(BiomesObject biome)
public void save()
{
this.biomesCacheData.values().forEach(this.biomesDatabase::saveObject);

// Clear Database.
List<BiomeChunkUpdateObject> objectList =
this.biomePendingChunkUpdateDatabase.loadObjects();
objectList.forEach(object -> this.biomePendingChunkUpdateDatabase.
deleteID(object.getUniqueId()));

// Save cache into database.
if (!this.biomePendingChunkUpdateMap.isEmpty())
{
this.biomePendingChunkUpdateMap.values().forEach(
this.biomePendingChunkUpdateDatabase::saveObject);
}
}

/**
Expand Down Expand Up @@ -581,6 +606,60 @@ public boolean hasAnyBiome(World world)
}


// ---------------------------------------------------------------------
// Section: Later Biome Updater
// ---------------------------------------------------------------------


/**
* This method finds and returns BiomeChunkUpdaterObject in given world with given
* chunk X and Z coordinates.
* @param world World where process will happen.
* @param x Chunk X coordinate.
* @param z Chunk Z coordinate.
* @return BiomeChunkUpdateObject where update is pending or null.
*/
public BiomeChunkUpdateObject getPendingChunkUpdateObject(World world, int x, int z)
{
return this.biomePendingChunkUpdateMap.get(world.getName() + "-" + x + "-" + z);
}


/**
* This method returns collection with all objects that contains information about
* chunks where biome update is still not completed.
* @return Collection of BiomeCHunkUpdateObjects.
*/
public Collection<BiomeChunkUpdateObject> getBiomeUpdaterCollection()
{
return this.biomePendingChunkUpdateMap.values();
}


/**
* This method adds BiomeChunkUpdateObject to cache.
* @param updateObject Object that must be added to cache.
*/
public void addChunkUpdateObject(BiomeChunkUpdateObject updateObject)
{
this.biomePendingChunkUpdateMap.put(updateObject.getUniqueId(), updateObject);
}


/**
* This method removes given element form cache and database.
* @param element Element that should be removed.
*/
public void removeUpdateObject(BiomeChunkUpdateObject element)
{
if (this.biomePendingChunkUpdateMap.containsKey(element.getUniqueId()))
{
this.biomePendingChunkUpdateMap.remove(element.getUniqueId());
this.biomePendingChunkUpdateDatabase.deleteObject(element);
}
}


// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
Expand All @@ -604,4 +683,15 @@ public boolean hasAnyBiome(World world)
* Variable stores biomes.yml location
*/
private File biomesFile;

/**
* Variable stores BiomeChunkUpdateObject objects that contains information about
* chunk that is not updated yet.
*/
private Map<String, BiomeChunkUpdateObject> biomePendingChunkUpdateMap;

/**
* Variable stores database of BiomeChunkUpdateObject.
*/
private Database<BiomeChunkUpdateObject> biomePendingChunkUpdateDatabase;
}

0 comments on commit e6b0846

Please sign in to comment.