Add in some additional ticket loading callbacks for ChickenBones. Closes #284

Add in a call to determine if there are possible chunktickets for a world. This should let
Mystcraft and other dynamic world generating mods check if they should immediately load
a world based on existing chunk tickets.
This commit is contained in:
Christian 2012-12-02 00:38:32 -05:00
parent 0243df1c4a
commit 784ad96194
2 changed files with 93 additions and 7 deletions

View File

@ -13,13 +13,17 @@ import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.LinkedHashMultimap;
@ -28,6 +32,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Multiset;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
@ -37,6 +42,7 @@ import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.src.Chunk;
import net.minecraft.src.ChunkCoordIntPair;
import net.minecraft.src.CompressedStreamTools;
@ -143,6 +149,25 @@ public class ForgeChunkManager
*/
public List<Ticket> ticketsLoaded(List<Ticket> tickets, World world, int maxTicketCount);
}
public interface PlayerOrderedLoadingCallback extends LoadingCallback
{
/**
* Called back when tickets are loaded from the world to allow the
* mod to decide if it wants the ticket still.
* This is for player bound tickets rather than mod bound tickets. It is here so mods can
* decide they want to dump all player tickets
*
* WARNING: You cannot force chunks in this callback, it is strictly for allowing the mod
* to be more selective in which tickets it wishes to preserve
*
* @param tickets The tickets that you will want to select from. The list is immutable and cannot be manipulated directly. Copy it first.
* @param world The world
* @return A list of the tickets this mod wishes to use. This list will subsequently be offered
* to the main callback for action
*/
public ListMultimap<String, Ticket> playerTicketsLoaded(ListMultimap<String, Ticket> tickets, World world);
}
public enum Type
{
@ -334,6 +359,34 @@ public class ForgeChunkManager
}
}
/**
* Allows dynamically loading world mods to test if there are chunk tickets in the world
* Mods that add dynamically generated worlds (like Mystcraft) should call this method
* to determine if the world should be loaded during server starting.
*
* @param chunkDir The chunk directory to test: should be equivalent to {@link WorldServer#getChunkSaveLocation()}
* @return if there are tickets outstanding for this world or not
*/
public static boolean savedWorldHasForcedChunkTickets(File chunkDir)
{
File chunkLoaderData = new File(chunkDir, "forcedchunks.dat");
if (chunkLoaderData.exists() && chunkLoaderData.isFile())
{
;
try
{
NBTTagCompound forcedChunkData = CompressedStreamTools.read(chunkLoaderData);
return forcedChunkData.getTagList("TicketList").tagCount() > 0;
}
catch (IOException e)
{
}
}
return false;
}
static void loadWorld(World world)
{
ArrayListMultimap<String, Ticket> newTickets = ArrayListMultimap.<String, Ticket>create();
@ -354,7 +407,7 @@ public class ForgeChunkManager
if (chunkLoaderData.exists() && chunkLoaderData.isFile())
{
ArrayListMultimap<String, Ticket> loadedTickets = ArrayListMultimap.<String, Ticket>create();
ArrayListMultimap<String, Ticket> playerLoadedTickets = ArrayListMultimap.<String, Ticket>create();
Map<String,ListMultimap<String,Ticket>> playerLoadedTickets = Maps.newHashMap();
NBTTagCompound forcedChunkData;
try
{
@ -399,8 +452,11 @@ public class ForgeChunkManager
if (ticket.hasKey("Player"))
{
tick.player = ticket.getString("Player");
playerLoadedTickets.put(tick.modId, tick);
playerTickets.put(tick.player, tick);
if (!playerLoadedTickets.containsKey(tick.modId))
{
playerLoadedTickets.put(modId, ArrayListMultimap.<String,Ticket>create());
}
playerLoadedTickets.get(tick.modId).put(tick.player, tick);
}
else
{
@ -458,13 +514,37 @@ public class ForgeChunkManager
for (String modId : playerLoadedTickets.keySet())
{
LoadingCallback loadingCallback = callbacks.get(modId);
List<Ticket> tickets = playerLoadedTickets.get(modId);
ForgeChunkManager.tickets.get(world).putAll("Forge", tickets);
loadingCallback.ticketsLoaded(ImmutableList.copyOf(tickets), world);
ListMultimap<String,Ticket> tickets = playerLoadedTickets.get(modId);
if (loadingCallback instanceof PlayerOrderedLoadingCallback)
{
PlayerOrderedLoadingCallback orderedLoadingCallback = (PlayerOrderedLoadingCallback) loadingCallback;
tickets = orderedLoadingCallback.playerTicketsLoaded(ImmutableListMultimap.copyOf(tickets), world);
playerTickets.putAll(tickets);
}
ForgeChunkManager.tickets.get(world).putAll("Forge", tickets.values());
loadingCallback.ticketsLoaded(ImmutableList.copyOf(tickets.values()), world);
}
}
}
static void unloadWorld(World world)
{
// World save fires before this event so the chunk loading info will be done
if (!(world instanceof WorldServer))
{
return;
}
forcedChunks.remove(world);
dormantChunkCache.remove(world);
// integrated server is shutting down
if (!MinecraftServer.getServer().isServerRunning())
{
playerTickets.clear();
tickets.clear();
}
}
/**
* Set a chunkloading callback for the supplied mod object
*

View File

@ -41,7 +41,7 @@ public class ForgeInternalHandler
Item item = stack.getItem();
if (item == null)
{
FMLLog.warning("Attempted to add a EntityItem to the world with a invalid item: ID %d at " +
FMLLog.warning("Attempted to add a EntityItem to the world with a invalid item: ID %d at " +
"(%d, %d, %d), this is most likely a config issue between you and the server. Please double check your configs",
stack.itemID, entity.posX, entity.posY, entity.posZ);
entity.setDead();
@ -73,4 +73,10 @@ public class ForgeInternalHandler
{
ForgeChunkManager.saveWorld(event.world);
}
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onDimensionUnload(WorldEvent.Unload event)
{
ForgeChunkManager.unloadWorld(event.world);
}
}