Working cross dimensional implementation of chunkloading for Forge.
This commit is contained in:
parent
d21e3ae218
commit
c684360f51
14 changed files with 783 additions and 240 deletions
|
@ -73,4 +73,8 @@ public aae.m # ComponentScatteredFeatureJunglePyramid.junglePyramidsDispenserCon
|
|||
public aan.a # ComponentStrongholdChestCorridor.strongholdChestContents
|
||||
public aar.b # ComponentStrongholdLibrary.strongholdLibraryChestContents
|
||||
public aaw.c # ComponentStrongholdRoomCrossing.field_75014_c
|
||||
public abu.a # ComponentVillageHouse2.villageBlacksmithChestContents
|
||||
public abu.a # ComponentVillageHouse2.villageBlacksmithChestContents
|
||||
# AnvilChunkLoader.chunkSaveLocation
|
||||
default wy.d
|
||||
# ChunkProviderServer.currentChunkLoader
|
||||
default gq.e
|
||||
|
|
|
@ -20,6 +20,9 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraft.src.Block;
|
||||
|
||||
/**
|
||||
|
@ -36,12 +39,15 @@ public class Configuration
|
|||
public static final String CATEGORY_ITEM = "item";
|
||||
|
||||
File file;
|
||||
|
||||
|
||||
public Map<String, Map<String, Property>> categories = new TreeMap<String, Map<String, Property>>();
|
||||
|
||||
|
||||
public TreeMap<String, Property> blockProperties = new TreeMap<String, Property>();
|
||||
public TreeMap<String, Property> itemProperties = new TreeMap<String, Property>();
|
||||
public TreeMap<String, Property> generalProperties = new TreeMap<String, Property>();
|
||||
|
||||
private Map<String,String> customCategoryComments = Maps.newHashMap();
|
||||
private boolean caseSensitiveCustomCategories;
|
||||
public static final String ALLOWED_CHARS = "._-";
|
||||
|
||||
/**
|
||||
|
@ -55,6 +61,11 @@ public class Configuration
|
|||
categories.put(CATEGORY_ITEM, itemProperties);
|
||||
}
|
||||
|
||||
public Configuration(File file, boolean caseSensitiveCustomCategories)
|
||||
{
|
||||
this(file);
|
||||
this.caseSensitiveCustomCategories = caseSensitiveCustomCategories;
|
||||
}
|
||||
/**
|
||||
* Gets or create a block id property. If the block id property key is
|
||||
* already in the configuration, then it will be used. Otherwise,
|
||||
|
@ -72,7 +83,7 @@ public class Configuration
|
|||
configBlocks[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Map<String, Property> properties = categories.get(CATEGORY_BLOCK);
|
||||
if (properties.containsKey(key))
|
||||
{
|
||||
|
@ -108,7 +119,7 @@ public class Configuration
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Property getOrCreateIntProperty(String key, String category, int defaultValue)
|
||||
{
|
||||
Property prop = getOrCreateProperty(key, category, Integer.toString(defaultValue));
|
||||
|
@ -123,7 +134,7 @@ public class Configuration
|
|||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Property getOrCreateBooleanProperty(String key, String category, boolean defaultValue)
|
||||
{
|
||||
Property prop = getOrCreateProperty(key, category, Boolean.toString(defaultValue));
|
||||
|
@ -137,10 +148,13 @@ public class Configuration
|
|||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Property getOrCreateProperty(String key, String category, String defaultValue)
|
||||
{
|
||||
category = category.toLowerCase(Locale.ENGLISH);
|
||||
if (!caseSensitiveCustomCategories)
|
||||
{
|
||||
category = category.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
Map<String, Property> source = categories.get(category);
|
||||
|
||||
if(source == null)
|
||||
|
@ -276,7 +290,7 @@ public class Configuration
|
|||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
buffer.close();
|
||||
} catch (IOException e){}
|
||||
|
@ -311,6 +325,17 @@ public class Configuration
|
|||
{
|
||||
buffer.write("####################\r\n");
|
||||
buffer.write("# " + category.getKey() + " \r\n");
|
||||
if (customCategoryComments.containsKey(category.getKey()))
|
||||
{
|
||||
buffer.write("#===================\r\n");
|
||||
String comment = customCategoryComments.get(category.getKey());
|
||||
Splitter splitter = Splitter.onPattern("\r?\n");
|
||||
for (String commentLine : splitter.split(comment))
|
||||
{
|
||||
buffer.write("# ");
|
||||
buffer.write(commentLine+"\r\n");
|
||||
}
|
||||
}
|
||||
buffer.write("####################\r\n\r\n");
|
||||
|
||||
buffer.write(category.getKey() + " {\r\n");
|
||||
|
@ -328,13 +353,24 @@ public class Configuration
|
|||
}
|
||||
}
|
||||
|
||||
public void addCustomCategoryComment(String category, String comment)
|
||||
{
|
||||
if (!caseSensitiveCustomCategories)
|
||||
category = category.toLowerCase(Locale.ENGLISH);
|
||||
customCategoryComments.put(category, comment);
|
||||
}
|
||||
|
||||
private void writeProperties(BufferedWriter buffer, Collection<Property> props) throws IOException
|
||||
{
|
||||
for (Property property : props)
|
||||
{
|
||||
if (property.comment != null)
|
||||
{
|
||||
buffer.write(" # " + property.comment + "\r\n");
|
||||
Splitter splitter = Splitter.onPattern("\r?\n");
|
||||
for (String commentLine : splitter.split(property.comment))
|
||||
{
|
||||
buffer.write(" # " + commentLine + "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
buffer.write(" " + property.getName() + "=" + property.value);
|
||||
|
|
|
@ -2,9 +2,15 @@ package net.minecraftforge.common;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
@ -17,6 +23,7 @@ public class DimensionManager
|
|||
private static Hashtable<Integer, WorldServer> worlds = new Hashtable<Integer, WorldServer>();
|
||||
private static boolean hasInit = false;
|
||||
private static Hashtable<Integer, Integer> dimensions = new Hashtable<Integer, Integer>();
|
||||
private static Map<World, ListMultimap<ChunkCoordIntPair, String>> persistentChunkStore = Maps.newHashMap();
|
||||
|
||||
public static boolean registerProviderType(int id, Class<? extends WorldProvider> provider, boolean keepLoaded)
|
||||
{
|
||||
|
@ -133,12 +140,11 @@ public class DimensionManager
|
|||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE,String.format("An error occured trying to create an instance of WorldProvider %d (%s)",
|
||||
dim,
|
||||
providers.get(getProviderType(dim)).getSimpleName()),e);
|
||||
dim, providers.get(getProviderType(dim)).getSimpleName()),e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
|
557
common/net/minecraftforge/common/ForgeChunkManager.java
Normal file
557
common/net/minecraftforge/common/ForgeChunkManager.java
Normal file
|
@ -0,0 +1,557 @@
|
|||
package net.minecraftforge.common;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.TreeMultiset;
|
||||
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
import net.minecraft.src.ChunkCoordIntPair;
|
||||
import net.minecraft.src.CompressedStreamTools;
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.MathHelper;
|
||||
import net.minecraft.src.NBTBase;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
import net.minecraft.src.NBTTagList;
|
||||
import net.minecraft.src.World;
|
||||
import net.minecraft.src.WorldServer;
|
||||
import net.minecraftforge.common.ForgeChunkManager.Ticket;
|
||||
|
||||
/**
|
||||
* Manages chunkloading for mods.
|
||||
*
|
||||
* The basic principle is a ticket based system.
|
||||
* 1. Mods register a callback {@link #setForcedChunkLoadingCallback(Object, LoadingCallback)}
|
||||
* 2. Mods ask for a ticket {@link #requestTicket(Object, World, Type)} and then hold on to that ticket.
|
||||
* 3. Mods request chunks to stay loaded {@link #forceChunk(Ticket, ChunkCoordIntPair)} or remove chunks from force loading {@link #unforceChunk(Ticket, ChunkCoordIntPair)}.
|
||||
* 4. When a world unloads, the tickets associated with that world are saved by the chunk manager.
|
||||
* 5. When a world loads, saved tickets are offered to the mods associated with the tickets. The {@link Ticket#getModData()} that is set by the mod should be used to re-register
|
||||
* chunks to stay loaded (and maybe take other actions).
|
||||
*
|
||||
* The chunkloading is configurable at runtime. The file "config/forgeChunkLoading.cfg" contains both default configuration for chunkloading, and a sample individual mod
|
||||
* specific override section.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ForgeChunkManager
|
||||
{
|
||||
private static int defaultMaxCount;
|
||||
private static int defaultMaxChunks;
|
||||
private static boolean overridesEnabled;
|
||||
|
||||
private static Map<World, Multimap<String, Ticket>> tickets = Maps.newHashMap();
|
||||
private static Map<String, Integer> ticketConstraints = Maps.newHashMap();
|
||||
private static Map<String, Integer> chunkConstraints = Maps.newHashMap();
|
||||
|
||||
private static Map<String, LoadingCallback> callbacks = Maps.newHashMap();
|
||||
|
||||
private static Map<World, SetMultimap<ChunkCoordIntPair,Ticket>> forcedChunks = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* All mods requiring chunkloading need to implement this to handle the
|
||||
* re-registration of chunk tickets at world loading time
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public interface LoadingCallback
|
||||
{
|
||||
/**
|
||||
* Called back when tickets are loaded from the world to allow the
|
||||
* mod to re-register the chunks associated with those tickets
|
||||
*
|
||||
* @param tickets
|
||||
* @param world
|
||||
*/
|
||||
public void ticketsLoaded(List<Ticket> tickets, World world);
|
||||
}
|
||||
public enum Type
|
||||
{
|
||||
|
||||
/**
|
||||
* For non-entity registrations
|
||||
*/
|
||||
NORMAL,
|
||||
/**
|
||||
* For entity registrations
|
||||
*/
|
||||
ENTITY
|
||||
}
|
||||
public static class Ticket
|
||||
{
|
||||
private String modId;
|
||||
private Type ticketType;
|
||||
private LinkedHashSet<ChunkCoordIntPair> requestedChunks;
|
||||
private NBTTagCompound modData;
|
||||
private World world;
|
||||
private int maxDepth;
|
||||
private String entityClazz;
|
||||
private int entityX;
|
||||
private int entityY;
|
||||
private int entityZ;
|
||||
private Entity entity;
|
||||
|
||||
Ticket(String modId, Type type, World world)
|
||||
{
|
||||
this.modId = modId;
|
||||
this.ticketType = type;
|
||||
this.world = world;
|
||||
this.maxDepth = getMaxChunkDepthFor(modId);
|
||||
this.requestedChunks = Sets.newLinkedHashSet();
|
||||
}
|
||||
|
||||
void bindEntityData(int x, int y, int z, String clazz)
|
||||
{
|
||||
this.entityX = x;
|
||||
this.entityY = y;
|
||||
this.entityZ = z;
|
||||
this.entityClazz = clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* The chunk list depth can be manipulated up to the maximal grant allowed for the mod. This value is configurable. Once the maximum is reached,
|
||||
* the least recently forced chunk, by original registration time, is removed from the forced chunk list.
|
||||
*
|
||||
* @param depth The new depth to set
|
||||
*/
|
||||
public void setChunkListDepth(int depth)
|
||||
{
|
||||
if (depth > getMaxChunkDepthFor(modId))
|
||||
{
|
||||
FMLLog.warning("The mod %s tried to modify the chunk ticket depth to: %d, greater than it's maximum: %d", modId, depth, getMaxChunkDepthFor(modId));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.maxDepth = depth;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the maximum chunk depth size
|
||||
*
|
||||
* @return The maximum chunk depth size
|
||||
*/
|
||||
public int getMaxChunkListDepth()
|
||||
{
|
||||
return getMaxChunkDepthFor(modId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the entity to the ticket for {@link Type#ENTITY} type tickets. Other types will throw a runtime exception.
|
||||
*
|
||||
* @param entity The entity to bind
|
||||
*/
|
||||
public void bindEntity(Entity entity)
|
||||
{
|
||||
if (ticketType!=Type.ENTITY)
|
||||
{
|
||||
throw new RuntimeException("Cannot bind an entity to a non-entity ticket");
|
||||
}
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the {@link NBTTagCompound} that stores mod specific data for the chunk ticket.
|
||||
* Example data to store would be a TileEntity or Block location. This is persisted with the ticket and
|
||||
* provided to the {@link LoadingCallback} for the mod. It is recommended to use this to recover
|
||||
* useful state information for the forced chunks.
|
||||
*
|
||||
* @return The custom compound tag for mods to store additional chunkloading data
|
||||
*/
|
||||
public NBTTagCompound getModData()
|
||||
{
|
||||
if (this.modData == null)
|
||||
{
|
||||
this.modData = new NBTTagCompound();
|
||||
}
|
||||
return modData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity class associated with this ticket. Only valid for callbacks.
|
||||
* @return
|
||||
*/
|
||||
public String getEntityClass()
|
||||
{
|
||||
return this.entityClazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last known entity X coordinate for this ticket. Only valid for callbacks.
|
||||
* @return
|
||||
*/
|
||||
public int getEntityX()
|
||||
{
|
||||
return entityX;
|
||||
}
|
||||
/**
|
||||
* Get the last known entity Y coordinate for this ticket. Only valid for callbacks.
|
||||
* @return
|
||||
*/
|
||||
public int getEntityY()
|
||||
{
|
||||
return entityY;
|
||||
}
|
||||
/**
|
||||
* Get the last known entity Z coordinate for this ticket. Only valid for callbacks.
|
||||
* @return
|
||||
*/
|
||||
public int getEntityZ()
|
||||
{
|
||||
return entityZ;
|
||||
}
|
||||
}
|
||||
|
||||
static void loadWorld(World world)
|
||||
{
|
||||
ArrayListMultimap<String, Ticket> loadedTickets = ArrayListMultimap.<String, Ticket>create();
|
||||
tickets.put(world, loadedTickets);
|
||||
|
||||
SetMultimap<ChunkCoordIntPair,Ticket> forcedChunkMap = LinkedHashMultimap.create();
|
||||
forcedChunks.put(world, forcedChunkMap);
|
||||
|
||||
if (!(world instanceof WorldServer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WorldServer worldServer = (WorldServer) world;
|
||||
File chunkDir = worldServer.getChunkSaveLocation();
|
||||
File chunkLoaderData = new File(chunkDir, "forcedchunks.dat");
|
||||
|
||||
if (chunkLoaderData.exists() && chunkLoaderData.isFile())
|
||||
{
|
||||
NBTTagCompound forcedChunkData;
|
||||
try
|
||||
{
|
||||
forcedChunkData = CompressedStreamTools.read(chunkLoaderData);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLLog.log(Level.WARNING, e, "Unable to read forced chunk data at %s - it will be ignored", chunkLoaderData.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
NBTTagList ticketList = forcedChunkData.getTagList("TicketList");
|
||||
for (int i = 0; i < ticketList.tagCount(); i++)
|
||||
{
|
||||
NBTTagCompound ticketHolder = (NBTTagCompound) ticketList.tagAt(i);
|
||||
String modId = ticketHolder.getString("Owner");
|
||||
|
||||
if (!Loader.isModLoaded(modId))
|
||||
{
|
||||
FMLLog.warning("Found chunkloading data for mod %s which is currently not available or active - it will be removed from the world save", modId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!callbacks.containsKey(modId))
|
||||
{
|
||||
FMLLog.warning("The mod %s has registered persistent chunkloading data but doesn't seem to want to be called back with it - it will be removed from the world save", modId);
|
||||
continue;
|
||||
}
|
||||
|
||||
int maxTicketLength = getMaxTicketLengthFor(modId);
|
||||
|
||||
NBTTagList tickets = ticketHolder.getTagList("Tickets");
|
||||
if (tickets.tagCount() > maxTicketLength)
|
||||
{
|
||||
FMLLog.warning("The mod %s has more tickets in to load than it is allowed. Only the first %d will be loaded - the rest will be removed", modId, maxTicketLength);
|
||||
}
|
||||
for (int j = 0; j < Math.min(tickets.tagCount(), maxTicketLength); j++)
|
||||
{
|
||||
NBTTagCompound ticket = (NBTTagCompound) tickets.tagAt(j);
|
||||
Type type = Type.values()[ticket.getByte("Type")];
|
||||
byte ticketChunkDepth = ticket.getByte("ChunkListDepth");
|
||||
NBTTagCompound modData = ticket.getCompoundTag("ModData");
|
||||
Ticket tick = new Ticket(modId, type, world);
|
||||
tick.modData = modData;
|
||||
if (type == Type.ENTITY)
|
||||
{
|
||||
int entX = ticket.getInteger("entityX");
|
||||
int entY = ticket.getInteger("entityY");
|
||||
int entZ = ticket.getInteger("entityZ");
|
||||
String entClass = ticket.getString("entityClass");
|
||||
tick.bindEntityData(entX, entY, entZ, entClass);
|
||||
}
|
||||
loadedTickets.put(modId, tick);
|
||||
}
|
||||
}
|
||||
|
||||
// send callbacks
|
||||
for (String modId : loadedTickets.keySet())
|
||||
{
|
||||
callbacks.get(modId).ticketsLoaded(loadedTickets.get(modId), world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a chunkloading callback for the supplied mod object
|
||||
*
|
||||
* @param mod The mod instance registering the callback
|
||||
* @param callback The code to call back when forced chunks are loaded
|
||||
*/
|
||||
public static void setForcedChunkLoadingCallback(Object mod, LoadingCallback callback)
|
||||
{
|
||||
ModContainer container = getContainer(mod);
|
||||
if (container == null)
|
||||
{
|
||||
FMLLog.warning("Unable to register a callback for an unknown mod %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
|
||||
return;
|
||||
}
|
||||
|
||||
callbacks.put(container.getModId(), callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover the available tickets for the mod in the world
|
||||
*
|
||||
* @param mod The mod that will own the tickets
|
||||
* @param world The world
|
||||
* @return The count of tickets left for the mod in the supplied world
|
||||
*/
|
||||
public static int ticketCountAvailableFor(Object mod, World world)
|
||||
{
|
||||
ModContainer container = getContainer(mod);
|
||||
if (container!=null)
|
||||
{
|
||||
String modId = container.getModId();
|
||||
int allowedCount = getMaxTicketLengthFor(modId);
|
||||
return allowedCount - tickets.get(world).get(modId).size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static ModContainer getContainer(Object mod)
|
||||
{
|
||||
ModContainer container = Loader.instance().getModObjectList().inverse().get(mod);
|
||||
return container;
|
||||
}
|
||||
|
||||
private static int getMaxTicketLengthFor(String modId)
|
||||
{
|
||||
int allowedCount = ticketConstraints.containsKey(modId) && overridesEnabled ? ticketConstraints.get(modId) : defaultMaxCount;
|
||||
return allowedCount;
|
||||
}
|
||||
|
||||
private static int getMaxChunkDepthFor(String modId)
|
||||
{
|
||||
int allowedCount = chunkConstraints.containsKey(modId) && overridesEnabled ? chunkConstraints.get(modId) : defaultMaxChunks;
|
||||
return allowedCount;
|
||||
}
|
||||
/**
|
||||
* Request a chunkloading ticket of the appropriate type for the supplied mod
|
||||
*
|
||||
* @param mod The mod requesting a ticket
|
||||
* @param world The world in which it is requesting the ticket
|
||||
* @param type The type of ticket
|
||||
* @return A ticket with which to register chunks for loading, or null if no further tickets are available
|
||||
*/
|
||||
public static Ticket requestTicket(Object mod, World world, Type type)
|
||||
{
|
||||
ModContainer container = getContainer(mod);
|
||||
if (container == null)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
|
||||
return null;
|
||||
}
|
||||
String modId = container.getModId();
|
||||
if (!callbacks.containsKey(modId))
|
||||
{
|
||||
FMLLog.severe("The mod %s has attempted to request a ticket without a listener in place", modId);
|
||||
throw new RuntimeException("Invalid ticket request");
|
||||
}
|
||||
|
||||
int allowedCount = ticketConstraints.containsKey(modId) ? ticketConstraints.get(modId) : defaultMaxCount;
|
||||
|
||||
if (tickets.get(world).get(modId).size() >= allowedCount)
|
||||
{
|
||||
FMLLog.info("The mod %s has attempted to allocate a chunkloading ticket beyond it's currently allocated maximum : %d", modId, allowedCount);
|
||||
return null;
|
||||
}
|
||||
Ticket ticket = new Ticket(modId, type, world);
|
||||
tickets.get(world).put(modId, ticket);
|
||||
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the ticket back to the system. This will also unforce any chunks held by the ticket so that they can be unloaded and/or stop ticking.
|
||||
*
|
||||
* @param ticket The ticket to release
|
||||
*/
|
||||
public static void releaseTicket(Ticket ticket)
|
||||
{
|
||||
if (ticket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (ChunkCoordIntPair chunk : ticket.requestedChunks)
|
||||
{
|
||||
unforceChunk(ticket, chunk);
|
||||
}
|
||||
tickets.get(ticket.world).remove(ticket.modId, ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the supplied chunk coordinate to be loaded by the supplied ticket. If the ticket's {@link Ticket#maxDepth} is exceeded, the least
|
||||
* recently registered chunk is unforced and may be unloaded.
|
||||
* It is safe to force the chunk several times for a ticket, it will not generate duplication or change the ordering.
|
||||
*
|
||||
* @param ticket The ticket registering the chunk
|
||||
* @param chunk The chunk to force
|
||||
*/
|
||||
public static void forceChunk(Ticket ticket, ChunkCoordIntPair chunk)
|
||||
{
|
||||
if (ticket == null || chunk == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ticket.ticketType == Type.ENTITY && ticket.entity == null)
|
||||
{
|
||||
throw new RuntimeException("Attempted to use an entity ticket to force a chunk, without an entity");
|
||||
}
|
||||
ticket.requestedChunks.add(chunk);
|
||||
forcedChunks.get(ticket.world).put(chunk, ticket);
|
||||
if (ticket.maxDepth > 0 && ticket.requestedChunks.size() > ticket.maxDepth)
|
||||
{
|
||||
ChunkCoordIntPair removed = ticket.requestedChunks.iterator().next();
|
||||
unforceChunk(ticket,removed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unforce the supplied chunk, allowing it to be unloaded and stop ticking.
|
||||
*
|
||||
* @param ticket The ticket holding the chunk
|
||||
* @param chunk The chunk to unforce
|
||||
*/
|
||||
public static void unforceChunk(Ticket ticket, ChunkCoordIntPair chunk)
|
||||
{
|
||||
if (ticket == null || chunk == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ticket.requestedChunks.remove(chunk);
|
||||
forcedChunks.get(ticket.world).remove(chunk, ticket);
|
||||
}
|
||||
|
||||
static void loadConfiguration(File configDir)
|
||||
{
|
||||
Configuration config = new Configuration(new File(configDir,"forgeChunkLoading.cfg"), true);
|
||||
try
|
||||
{
|
||||
config.categories.clear();
|
||||
config.load();
|
||||
config.addCustomCategoryComment("defaults", "Default configuration for forge chunk loading control");
|
||||
Property maxTicketCount = config.getOrCreateIntProperty("maximumTicketCount", "defaults", 200);
|
||||
maxTicketCount.comment = "The default maximum ticket count for a mod which does not have an override\n" +
|
||||
"in this file. This is the number of chunk loading requests a mod is allowed to make.";
|
||||
defaultMaxCount = maxTicketCount.getInt(200);
|
||||
|
||||
Property maxChunks = config.getOrCreateIntProperty("maximumChunksPerTicket", "defaults", 25);
|
||||
maxChunks.comment = "The default maximum number of chunks a mod can force, per ticket, \n" +
|
||||
"for a mod without an override. This is the maximum number of chunks a single ticket can force.";
|
||||
defaultMaxChunks = maxChunks.getInt(25);
|
||||
|
||||
Property modOverridesEnabled = config.getOrCreateBooleanProperty("enabled", "defaults", true);
|
||||
modOverridesEnabled.comment = "Are mod overrides enabled?";
|
||||
overridesEnabled = modOverridesEnabled.getBoolean(true);
|
||||
|
||||
config.addCustomCategoryComment("Forge", "Sample mod specific control section.\n" +
|
||||
"Copy this section and rename the with the modid for the mod you wish to override.\n" +
|
||||
"A value of zero in either entry effectively disables any chunkloading capabilities\n" +
|
||||
"for that mod");
|
||||
Property sampleTC = config.getOrCreateIntProperty("maximumTicketCount", "Forge", 200);
|
||||
sampleTC.comment = "Maximum ticket count for the mod. Zero disables chunkloading capabilities.";
|
||||
sampleTC = config.getOrCreateIntProperty("maximumChunksPerTicket", "Forge", 25);
|
||||
sampleTC.comment = "Maximum chunks per ticket for the mod.";
|
||||
}
|
||||
finally
|
||||
{
|
||||
config.save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of persistent chunks in the world. This set is immutable.
|
||||
* @param world
|
||||
* @return
|
||||
*/
|
||||
public static SetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunksFor(World world)
|
||||
{
|
||||
return ImmutableSetMultimap.copyOf(forcedChunks.get(world));
|
||||
}
|
||||
|
||||
static void saveWorld(World world)
|
||||
{
|
||||
// only persist persistent worlds
|
||||
if (!(world instanceof WorldServer)) { return; }
|
||||
WorldServer worldServer = (WorldServer) world;
|
||||
File chunkDir = worldServer.getChunkSaveLocation();
|
||||
File chunkLoaderData = new File(chunkDir, "forcedchunks.dat");
|
||||
|
||||
NBTTagCompound forcedChunkData = new NBTTagCompound();
|
||||
NBTTagList ticketList = new NBTTagList();
|
||||
forcedChunkData.setTag("TicketList", ticketList);
|
||||
|
||||
Multimap<String, Ticket> ticketSet = tickets.get(worldServer);
|
||||
for (String modId : ticketSet.keySet())
|
||||
{
|
||||
NBTTagCompound ticketHolder = new NBTTagCompound();
|
||||
ticketList.appendTag(ticketHolder);
|
||||
|
||||
ticketHolder.setString("Owner", modId);
|
||||
NBTTagList tickets = new NBTTagList();
|
||||
ticketHolder.setTag("Tickets", tickets);
|
||||
|
||||
for (Ticket tick : ticketSet.get(modId))
|
||||
{
|
||||
NBTTagCompound ticket = new NBTTagCompound();
|
||||
tickets.appendTag(ticket);
|
||||
ticket.setByte("Type", (byte) tick.ticketType.ordinal());
|
||||
ticket.setByte("ChunkListDepth", (byte) tick.maxDepth);
|
||||
ticket.setCompoundTag("ModData", tick.modData);
|
||||
if (tick.ticketType == Type.ENTITY)
|
||||
{
|
||||
ticket.setInteger("entityX", MathHelper.floor_double(tick.entity.posX));
|
||||
ticket.setInteger("entityY", MathHelper.floor_double(tick.entity.posY));
|
||||
ticket.setInteger("entityZ", MathHelper.floor_double(tick.entity.posZ));
|
||||
ticket.setString("entityClass", tick.entity.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
CompressedStreamTools.write(forcedChunkData, chunkLoaderData);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLLog.log(Level.WARNING, e, "Unable to write forced chunk data to %s - chunkloading won't work", chunkLoaderData.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,11 +3,13 @@ package net.minecraftforge.common;
|
|||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import cpw.mods.fml.common.DummyModContainer;
|
||||
import cpw.mods.fml.common.LoadController;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
|
||||
import static net.minecraftforge.common.ForgeVersion.*;
|
||||
|
||||
|
@ -34,6 +36,13 @@ public class ForgeDummyContainer extends DummyModContainer
|
|||
@Override
|
||||
public boolean registerBus(EventBus bus, LoadController controller)
|
||||
{
|
||||
bus.register(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void preInit(FMLPreInitializationEvent evt)
|
||||
{
|
||||
ForgeChunkManager.loadConfiguration(evt.getModConfigurationDirectory());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -359,55 +359,4 @@ public class ForgeHooks
|
|||
player.joinEntityItemWithWorld(event.entityItem);
|
||||
return event.entityItem;
|
||||
}
|
||||
public static void dumpPersistentChunks(WorldInfo worldInfo, ListMultimap<ChunkCoordIntPair, String> persistentChunks)
|
||||
{
|
||||
worldInfo.forgeWorldData = new NBTTagCompound();
|
||||
|
||||
NBTTagList chunkDataList = new NBTTagList();
|
||||
for (Entry<ChunkCoordIntPair, Collection<String>> entry : persistentChunks.asMap().entrySet())
|
||||
{
|
||||
NBTTagCompound dataList = new NBTTagCompound();
|
||||
dataList.setIntArray("Chunk", new int[] { entry.getKey().chunkXPos, entry.getKey().chunkZPos });
|
||||
NBTTagList modList = new NBTTagList();
|
||||
for (String modId : entry.getValue())
|
||||
{
|
||||
modList.appendTag(new NBTTagString(modId, ""));
|
||||
}
|
||||
dataList.setTag("Mods", modList);
|
||||
chunkDataList.appendTag(dataList);
|
||||
}
|
||||
worldInfo.forgeWorldData.setTag("PersistentChunks", chunkDataList);
|
||||
}
|
||||
|
||||
public static ListMultimap<ChunkCoordIntPair, String> loadPersistentChunkData(WorldInfo worldInfo)
|
||||
{
|
||||
ArrayListMultimap<ChunkCoordIntPair, String> chunkList = ArrayListMultimap.<ChunkCoordIntPair, String>create();
|
||||
|
||||
if (worldInfo == null || worldInfo.forgeWorldData == null)
|
||||
{
|
||||
return chunkList;
|
||||
}
|
||||
|
||||
NBTTagList chunkDataList = worldInfo.forgeWorldData.getTagList("PersistentChunks");
|
||||
for (int i = 0; i < chunkDataList.tagCount(); i++)
|
||||
{
|
||||
NBTTagCompound dataList = (NBTTagCompound) chunkDataList.tagAt(i);
|
||||
int[] ccpairint = dataList.getIntArray("Chunk");
|
||||
ChunkCoordIntPair ccpair = new ChunkCoordIntPair(ccpairint[0], ccpairint[1]);
|
||||
NBTTagList modList = dataList.getTagList("Mods");
|
||||
for (int j = 0; j < modList.tagCount(); j++)
|
||||
{
|
||||
String modId = modList.tagAt(j).getName();
|
||||
if (Loader.isModLoaded(modId))
|
||||
{
|
||||
chunkList.put(ccpair, modId);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.warning("The mod %s is not present - it's chunks will not be persisted any longer", modId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunkList;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.minecraftforge.common;
|
|||
import net.minecraft.src.*;
|
||||
import net.minecraftforge.event.*;
|
||||
import net.minecraftforge.event.entity.*;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
|
||||
public class ForgeInternalHandler
|
||||
{
|
||||
|
@ -25,4 +26,16 @@ public class ForgeInternalHandler
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ForgeSubscribe(priority = EventPriority.HIGHEST)
|
||||
public void onDimensionLoad(WorldEvent.Load event)
|
||||
{
|
||||
ForgeChunkManager.loadWorld(event.world);
|
||||
}
|
||||
|
||||
@ForgeSubscribe(priority = EventPriority.HIGHEST)
|
||||
public void onDimensionSave(WorldEvent.Save event)
|
||||
{
|
||||
ForgeChunkManager.saveWorld(event.world);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,15 @@ import net.minecraftforge.event.entity.EntityEvent;
|
|||
public class MinecraftForge
|
||||
{
|
||||
/**
|
||||
* The core Forge EventBus, all events for Forge will be fired on this,
|
||||
* The core Forge EventBus, all events for Forge will be fired on this,
|
||||
* you should use this to register all your listeners.
|
||||
* This replaces every register*Handler() function in the old version of Forge.
|
||||
*/
|
||||
public static final EventBus EVENT_BUS = new EventBus();
|
||||
public static boolean SPAWNER_ALLOW_ON_INVERTED = false;
|
||||
private static final ForgeInternalHandler INTERNAL_HANDLER = new ForgeInternalHandler();
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register a new plant to be planted when bonemeal is used on grass.
|
||||
* @param block The block to place.
|
||||
* @param metadata The metadata to set for the block when being placed.
|
||||
|
@ -38,25 +38,25 @@ public class MinecraftForge
|
|||
ForgeHooks.grassList.add(new GrassEntry(block, metadata, weight));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Register a new seed to be dropped when breaking tall grass.
|
||||
*
|
||||
*
|
||||
* @param seed The item to drop as a seed.
|
||||
* @param weight The relative probability of the seeds,
|
||||
* @param weight The relative probability of the seeds,
|
||||
* where wheat seeds are 10.
|
||||
*/
|
||||
public static void addGrassSeed(ItemStack seed, int weight)
|
||||
{
|
||||
ForgeHooks.seedList.add(new SeedEntry(seed, weight));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
/**
|
||||
*
|
||||
* Register a tool as a tool class with a given harvest level.
|
||||
*
|
||||
* @param tool The custom tool to register.
|
||||
* @param toolClass The tool class to register as. The predefined tool
|
||||
* clases are "pickaxe", "shovel", "axe". You can add
|
||||
* clases are "pickaxe", "shovel", "axe". You can add
|
||||
* others for custom tools.
|
||||
* @param harvestLevel The harvest level of the tool.
|
||||
*/
|
||||
|
@ -65,7 +65,7 @@ public class MinecraftForge
|
|||
ForgeHooks.toolClasses.put(tool, Arrays.asList(toolClass, harvestLevel));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Register a block to be harvested by a tool class. This is the metadata
|
||||
* sensitive version, use it if your blocks are using metadata variants.
|
||||
* By default, this sets the block class as effective against that type.
|
||||
|
@ -86,13 +86,13 @@ public class MinecraftForge
|
|||
ForgeHooks.toolEffectiveness.add(key);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Remove a block effectiveness mapping. Since setBlockHarvestLevel
|
||||
* makes the tool class effective against the block by default, this can be
|
||||
* used to remove that mapping. This will force a block to be harvested at
|
||||
* the same speed regardless of tool quality, while still requiring a given
|
||||
* harvesting level.
|
||||
*
|
||||
*
|
||||
* @param block The block to remove effectiveness from.
|
||||
* @param metadata The metadata for the block subtype.
|
||||
* @param toolClass The tool class to remove the effectiveness mapping from.
|
||||
|
@ -104,7 +104,7 @@ public class MinecraftForge
|
|||
ForgeHooks.toolEffectiveness.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Register a block to be harvested by a tool class.
|
||||
* By default, this sets the block class as effective against that type.
|
||||
*
|
||||
|
@ -125,8 +125,8 @@ public class MinecraftForge
|
|||
ForgeHooks.toolEffectiveness.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Returns the block harvest level for a particular tool class.
|
||||
*
|
||||
* @param block The block to check.
|
||||
|
@ -147,13 +147,13 @@ public class MinecraftForge
|
|||
return harvestLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Remove a block effectiveness mapping. Since setBlockHarvestLevel
|
||||
* makes the tool class effective against the block by default, this can be
|
||||
* used to remove that mapping. This will force a block to be harvested at
|
||||
* the same speed regardless of tool quality, while still requiring a given
|
||||
* harvesting level.
|
||||
*
|
||||
*
|
||||
* @param block The block to remove effectiveness from.
|
||||
* @param toolClass The tool class to remove the effectiveness mapping from.
|
||||
* @see MinecraftForge#setToolClass for details on tool classes.
|
||||
|
@ -166,7 +166,7 @@ public class MinecraftForge
|
|||
ForgeHooks.toolEffectiveness.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method invoked by FML before any other mods are loaded.
|
||||
*/
|
||||
|
@ -197,47 +197,9 @@ public class MinecraftForge
|
|||
|
||||
EVENT_BUS.register(INTERNAL_HANDLER);
|
||||
}
|
||||
|
||||
|
||||
public static String getBrandingVersion()
|
||||
{
|
||||
return "Minecraft Forge "+ ForgeVersion.getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a chunk to remain loaded by the supplied mod
|
||||
*
|
||||
* @param chunk the chunk to keep loaded
|
||||
* @param world the world holding the chunk
|
||||
* @param mod the mod (either {@link Mod} or {@link BaseMod}) that wishes to force the load
|
||||
*/
|
||||
public static void forceChunkLoaded(ChunkCoordIntPair chunk, World world, Object mod)
|
||||
{
|
||||
ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod);
|
||||
if (mc == null)
|
||||
{
|
||||
FMLLog.warning("Attempt to force chunk load for a non-existent mod %s", mod.getClass().getName());
|
||||
return;
|
||||
}
|
||||
String modId = mc.getModId();
|
||||
world.getPersistentChunks().put(chunk, modId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop forcing the chunk to remain loaded by the supplied mod (other mods may still
|
||||
* keep the chunk loaded, however)
|
||||
* @param chunk the chunk to keep loaded
|
||||
* @param world the world holding the chunk
|
||||
* @param mod the mod (either {@link Mod} or {@link BaseMod}) that wishes to unforce the load
|
||||
*/
|
||||
public static void unforceChunkLoaded(ChunkCoordIntPair chunk, World world, Object mod)
|
||||
{
|
||||
ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod);
|
||||
if (mc == null)
|
||||
{
|
||||
FMLLog.warning("Attempt to unforce chunk load for a non-existent mod %s", mod.getClass().getName());
|
||||
return;
|
||||
}
|
||||
String modId = mc.getModId();
|
||||
world.getPersistentChunks().remove(chunk, modId);
|
||||
}
|
||||
}
|
||||
|
|
1
common/net/minecraftforge/common/test.jpage
Normal file
1
common/net/minecraftforge/common/test.jpage
Normal file
|
@ -0,0 +1 @@
|
|||
net.minecraftforge.common.ForgeChunkManager.loadConfiguration(new java.io.File("/tmp"));
|
|
@ -4,7 +4,7 @@
|
|||
{
|
||||
if (!this.currentServer.canNotSave)
|
||||
{
|
||||
+ for (ChunkCoordIntPair forced : currentServer.persistentChunks.keySet())
|
||||
+ for (ChunkCoordIntPair forced : currentServer.getPersistentChunks().keySet())
|
||||
+ {
|
||||
+ this.chunksToUnload.remove(ChunkCoordIntPair.chunkXZ2Int(forced.chunkXPos, forced.chunkZPos));
|
||||
+ }
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
--- ../src_base/common/net/minecraft/src/CompressedStreamTools.java
|
||||
+++ ../src_work/common/net/minecraft/src/CompressedStreamTools.java
|
||||
@@ -155,7 +155,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
- @SideOnly(Side.CLIENT)
|
||||
public static NBTTagCompound read(File par0File) throws IOException
|
||||
{
|
||||
if (!par0File.exists())
|
|
@ -1,12 +1,13 @@
|
|||
--- ../src_base/common/net/minecraft/src/World.java
|
||||
+++ ../src_work/common/net/minecraft/src/World.java
|
||||
@@ -10,8 +10,22 @@
|
||||
@@ -10,8 +10,27 @@
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
+import com.google.common.collect.ArrayListMultimap;
|
||||
+import com.google.common.collect.ListMultimap;
|
||||
+import com.google.common.collect.SetMultimap;
|
||||
+
|
||||
+import net.minecraftforge.common.ForgeChunkManager;
|
||||
+import net.minecraftforge.common.ForgeChunkManager.Ticket;
|
||||
+import net.minecraftforge.common.ForgeHooks;
|
||||
+import net.minecraftforge.common.MinecraftForge;
|
||||
+import net.minecraftforge.common.ForgeDirection;
|
||||
|
@ -19,7 +20,7 @@
|
|||
{
|
||||
+ /**
|
||||
+ * Used in the getEntitiesWithinAABB functions to expand the search area for entities.
|
||||
+ * Modders should change this variable to a higher value if it is less then the radius
|
||||
+ * Modders should change this variable to a higher value if it is less then the radius
|
||||
+ * of one of there entities.
|
||||
+ */
|
||||
+ public static double MAX_ENTITY_RADIUS = 2.0D;
|
||||
|
@ -27,13 +28,7 @@
|
|||
/**
|
||||
* boolean; if true updates scheduled by scheduleBlockUpdate happen immediately
|
||||
*/
|
||||
@@ -128,6 +145,7 @@
|
||||
*/
|
||||
public boolean isRemote;
|
||||
|
||||
+ protected ListMultimap<ChunkCoordIntPair, String> persistentChunks;
|
||||
/**
|
||||
@@ -132,6 +146,11 @@
|
||||
@@ -132,6 +151,11 @@
|
||||
* Gets the biome for a given set of x/z coordinates
|
||||
*/
|
||||
public BiomeGenBase getBiomeGenForCoords(int par1, int par2)
|
||||
|
@ -45,7 +40,7 @@
|
|||
{
|
||||
if (this.blockExists(par1, 0, par2))
|
||||
{
|
||||
@@ -167,6 +186,7 @@
|
||||
@@ -167,6 +191,7 @@
|
||||
this.chunkProvider = this.createChunkProvider();
|
||||
this.calculateInitialSkylight();
|
||||
this.calculateInitialWeather();
|
||||
|
@ -53,18 +48,15 @@
|
|||
}
|
||||
|
||||
public World(ISaveHandler par1ISaveHandler, String par2Str, WorldSettings par3WorldSettings, WorldProvider par4WorldProvider, Profiler par5Profiler)
|
||||
@@ -213,6 +233,7 @@
|
||||
@@ -213,6 +238,7 @@
|
||||
|
||||
this.calculateInitialSkylight();
|
||||
this.calculateInitialWeather();
|
||||
+
|
||||
+ persistentChunks = ForgeHooks.loadPersistentChunkData(this.worldInfo);
|
||||
+
|
||||
+ MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +290,8 @@
|
||||
@@ -269,7 +295,8 @@
|
||||
*/
|
||||
public boolean isAirBlock(int par1, int par2, int par3)
|
||||
{
|
||||
|
@ -74,7 +66,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +300,8 @@
|
||||
@@ -278,7 +305,8 @@
|
||||
public boolean blockHasTileEntity(int par1, int par2, int par3)
|
||||
{
|
||||
int var4 = this.getBlockId(par1, par2, par3);
|
||||
|
@ -84,7 +76,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -980,7 +1003,7 @@
|
||||
@@ -980,7 +1008,7 @@
|
||||
*/
|
||||
public boolean isDaytime()
|
||||
{
|
||||
|
@ -93,7 +85,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -1012,7 +1035,7 @@
|
||||
@@ -1012,7 +1040,7 @@
|
||||
int var12 = this.getBlockMetadata(var8, var9, var10);
|
||||
Block var13 = Block.blocksList[var11];
|
||||
|
||||
|
@ -102,7 +94,7 @@
|
|||
{
|
||||
MovingObjectPosition var14 = var13.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
|
||||
|
||||
@@ -1212,6 +1235,12 @@
|
||||
@@ -1212,6 +1240,12 @@
|
||||
*/
|
||||
public void playSoundAtEntity(Entity par1Entity, String par2Str, float par3, float par4)
|
||||
{
|
||||
|
@ -115,7 +107,7 @@
|
|||
if (par1Entity != null && par2Str != null)
|
||||
{
|
||||
Iterator var5 = this.worldAccesses.iterator();
|
||||
@@ -1312,6 +1341,11 @@
|
||||
@@ -1312,6 +1346,11 @@
|
||||
EntityPlayer var5 = (EntityPlayer)par1Entity;
|
||||
this.playerEntities.add(var5);
|
||||
this.updateAllPlayersSleepingFlag();
|
||||
|
@ -127,7 +119,7 @@
|
|||
}
|
||||
|
||||
this.getChunkFromChunkCoords(var2, var3).addEntity(par1Entity);
|
||||
@@ -1563,6 +1597,12 @@
|
||||
@@ -1563,6 +1602,12 @@
|
||||
* Calculates the color for the skybox
|
||||
*/
|
||||
public Vec3 getSkyColor(Entity par1Entity, float par2)
|
||||
|
@ -140,7 +132,7 @@
|
|||
{
|
||||
float var3 = this.getCelestialAngle(par2);
|
||||
float var4 = MathHelper.cos(var3 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
|
||||
@@ -1658,6 +1698,12 @@
|
||||
@@ -1658,6 +1703,12 @@
|
||||
@SideOnly(Side.CLIENT)
|
||||
public Vec3 drawClouds(float par1)
|
||||
{
|
||||
|
@ -153,7 +145,7 @@
|
|||
float var2 = this.getCelestialAngle(par1);
|
||||
float var3 = MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
|
||||
|
||||
@@ -1736,7 +1782,7 @@
|
||||
@@ -1736,7 +1787,7 @@
|
||||
{
|
||||
int var5 = var3.getBlockID(par1, var4, par2);
|
||||
|
||||
|
@ -162,7 +154,7 @@
|
|||
{
|
||||
return var4 + 1;
|
||||
}
|
||||
@@ -1751,6 +1797,12 @@
|
||||
@@ -1751,6 +1802,12 @@
|
||||
* How bright are stars in the sky
|
||||
*/
|
||||
public float getStarBrightness(float par1)
|
||||
|
@ -175,7 +167,7 @@
|
|||
{
|
||||
float var2 = this.getCelestialAngle(par1);
|
||||
float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.25F);
|
||||
@@ -1893,7 +1945,7 @@
|
||||
@@ -1893,7 +1950,7 @@
|
||||
|
||||
if (var8 != null)
|
||||
{
|
||||
|
@ -184,18 +176,18 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
@@ -1903,6 +1955,10 @@
|
||||
@@ -1903,6 +1960,10 @@
|
||||
|
||||
if (!this.entityRemoval.isEmpty())
|
||||
{
|
||||
+ for (Object tile : entityRemoval)
|
||||
+ {
|
||||
+ ((TileEntity)tile).onChunkUnload();
|
||||
+ ((TileEntity)tile).onChunkUnload();
|
||||
+ }
|
||||
this.loadedTileEntityList.removeAll(this.entityRemoval);
|
||||
this.entityRemoval.clear();
|
||||
}
|
||||
@@ -1923,7 +1979,9 @@
|
||||
@@ -1923,7 +1984,9 @@
|
||||
{
|
||||
this.loadedTileEntityList.add(var9);
|
||||
}
|
||||
|
@ -206,7 +198,7 @@
|
|||
if (this.chunkExists(var9.xCoord >> 4, var9.zCoord >> 4))
|
||||
{
|
||||
Chunk var10 = this.getChunkFromChunkCoords(var9.xCoord >> 4, var9.zCoord >> 4);
|
||||
@@ -1933,8 +1991,6 @@
|
||||
@@ -1933,8 +1996,6 @@
|
||||
var10.setChunkBlockTileEntity(var9.xCoord & 15, var9.yCoord, var9.zCoord & 15, var9);
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +207,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -1947,13 +2003,13 @@
|
||||
@@ -1947,13 +2008,13 @@
|
||||
|
||||
public void addTileEntity(Collection par1Collection)
|
||||
{
|
||||
|
@ -236,13 +228,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -1974,8 +2030,14 @@
|
||||
@@ -1973,9 +2034,17 @@
|
||||
{
|
||||
int var3 = MathHelper.floor_double(par1Entity.posX);
|
||||
int var4 = MathHelper.floor_double(par1Entity.posZ);
|
||||
- byte var5 = 32;
|
||||
-
|
||||
- if (!par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5))
|
||||
+ boolean isForced = persistentChunks.containsKey(new ChunkCoordIntPair(var3 >> 4, var4 >> 4));
|
||||
+
|
||||
+ boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var3 >> 4, var4 >> 4));
|
||||
+ byte var5 = isForced ? (byte)0 : 32;
|
||||
+ boolean canUpdate = !par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5);
|
||||
+ if (!canUpdate)
|
||||
|
@ -255,7 +249,7 @@
|
|||
{
|
||||
par1Entity.lastTickPosX = par1Entity.posX;
|
||||
par1Entity.lastTickPosY = par1Entity.posY;
|
||||
@@ -2210,6 +2272,14 @@
|
||||
@@ -2210,6 +2279,14 @@
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -270,7 +264,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
@@ -2516,25 +2586,21 @@
|
||||
@@ -2516,25 +2593,21 @@
|
||||
*/
|
||||
public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity)
|
||||
{
|
||||
|
@ -311,7 +305,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -2543,27 +2609,10 @@
|
||||
@@ -2543,27 +2616,10 @@
|
||||
*/
|
||||
public void removeBlockTileEntity(int par1, int par2, int par3)
|
||||
{
|
||||
|
@ -343,7 +337,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -2589,7 +2638,8 @@
|
||||
@@ -2589,7 +2645,8 @@
|
||||
*/
|
||||
public boolean isBlockNormalCube(int par1, int par2, int par3)
|
||||
{
|
||||
|
@ -353,7 +347,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -2597,8 +2647,7 @@
|
||||
@@ -2597,8 +2654,7 @@
|
||||
*/
|
||||
public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3)
|
||||
{
|
||||
|
@ -363,7 +357,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -2614,7 +2663,7 @@
|
||||
@@ -2614,7 +2670,7 @@
|
||||
if (var5 != null && !var5.isEmpty())
|
||||
{
|
||||
Block var6 = Block.blocksList[this.getBlockId(par1, par2, par3)];
|
||||
|
@ -372,7 +366,7 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
@@ -2645,8 +2694,7 @@
|
||||
@@ -2645,8 +2701,7 @@
|
||||
*/
|
||||
public void setAllowedSpawnTypes(boolean par1, boolean par2)
|
||||
{
|
||||
|
@ -382,7 +376,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -2662,6 +2710,11 @@
|
||||
@@ -2662,6 +2717,11 @@
|
||||
*/
|
||||
private void calculateInitialWeather()
|
||||
{
|
||||
|
@ -394,7 +388,7 @@
|
|||
if (this.worldInfo.isRaining())
|
||||
{
|
||||
this.rainingStrength = 1.0F;
|
||||
@@ -2677,6 +2730,11 @@
|
||||
@@ -2677,6 +2737,11 @@
|
||||
* Updates all weather states.
|
||||
*/
|
||||
protected void updateWeather()
|
||||
|
@ -406,7 +400,7 @@
|
|||
{
|
||||
if (!this.provider.hasNoSky)
|
||||
{
|
||||
@@ -2779,7 +2837,7 @@
|
||||
@@ -2779,12 +2844,14 @@
|
||||
|
||||
public void toggleRain()
|
||||
{
|
||||
|
@ -415,7 +409,14 @@
|
|||
}
|
||||
|
||||
protected void setActivePlayerChunksAndCheckLight()
|
||||
@@ -2891,6 +2949,11 @@
|
||||
{
|
||||
this.activeChunkSet.clear();
|
||||
+ this.activeChunkSet.addAll(getPersistentChunks().keySet());
|
||||
+
|
||||
this.theProfiler.startSection("buildList");
|
||||
int var1;
|
||||
EntityPlayer var2;
|
||||
@@ -2891,6 +2958,11 @@
|
||||
*/
|
||||
public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4)
|
||||
{
|
||||
|
@ -427,7 +428,7 @@
|
|||
BiomeGenBase var5 = this.getBiomeGenForCoords(par1, par3);
|
||||
float var6 = var5.getFloatTemperature();
|
||||
|
||||
@@ -2948,6 +3011,11 @@
|
||||
@@ -2948,6 +3020,11 @@
|
||||
* Tests whether or not snow can be placed at a given location
|
||||
*/
|
||||
public boolean canSnowAt(int par1, int par2, int par3)
|
||||
|
@ -439,7 +440,7 @@
|
|||
{
|
||||
BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
|
||||
float var5 = var4.getFloatTemperature();
|
||||
@@ -3041,7 +3109,7 @@
|
||||
@@ -3041,7 +3118,7 @@
|
||||
|
||||
private int computeBlockLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
|
||||
{
|
||||
|
@ -448,7 +449,7 @@
|
|||
int var8 = this.getSavedLightValue(EnumSkyBlock.Block, par2 - 1, par3, par4) - par6;
|
||||
int var9 = this.getSavedLightValue(EnumSkyBlock.Block, par2 + 1, par3, par4) - par6;
|
||||
int var10 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 - 1, par4) - par6;
|
||||
@@ -3309,10 +3377,10 @@
|
||||
@@ -3309,10 +3386,10 @@
|
||||
public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
|
||||
{
|
||||
this.entitiesWithinAABBExcludingEntity.clear();
|
||||
|
@ -463,7 +464,7 @@
|
|||
|
||||
for (int var7 = var3; var7 <= var4; ++var7)
|
||||
{
|
||||
@@ -3333,10 +3401,10 @@
|
||||
@@ -3333,10 +3410,10 @@
|
||||
*/
|
||||
public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB)
|
||||
{
|
||||
|
@ -478,7 +479,7 @@
|
|||
ArrayList var7 = new ArrayList();
|
||||
|
||||
for (int var8 = var3; var8 <= var4; ++var8)
|
||||
@@ -3425,11 +3493,14 @@
|
||||
@@ -3425,11 +3502,14 @@
|
||||
*/
|
||||
public void addLoadedEntities(List par1List)
|
||||
{
|
||||
|
@ -496,7 +497,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -3466,7 +3537,10 @@
|
||||
@@ -3466,7 +3546,10 @@
|
||||
{
|
||||
var9 = null;
|
||||
}
|
||||
|
@ -508,7 +509,7 @@
|
|||
return par1 > 0 && var9 == null && var10.canPlaceBlockOnSide(this, par2, par3, par4, par6);
|
||||
}
|
||||
}
|
||||
@@ -3656,7 +3730,7 @@
|
||||
@@ -3656,7 +3739,7 @@
|
||||
*/
|
||||
public void setWorldTime(long par1)
|
||||
{
|
||||
|
@ -517,7 +518,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -3664,12 +3738,12 @@
|
||||
@@ -3664,12 +3747,12 @@
|
||||
*/
|
||||
public long getSeed()
|
||||
{
|
||||
|
@ -532,7 +533,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -3677,13 +3751,13 @@
|
||||
@@ -3677,13 +3760,13 @@
|
||||
*/
|
||||
public ChunkCoordinates getSpawnPoint()
|
||||
{
|
||||
|
@ -548,7 +549,7 @@
|
|||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -3707,7 +3781,10 @@
|
||||
@@ -3707,7 +3790,10 @@
|
||||
|
||||
if (!this.loadedEntityList.contains(par1Entity))
|
||||
{
|
||||
|
@ -560,7 +561,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -3715,6 +3792,11 @@
|
||||
@@ -3715,6 +3801,11 @@
|
||||
* Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here.
|
||||
*/
|
||||
public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
|
||||
|
@ -572,7 +573,7 @@
|
|||
{
|
||||
return true;
|
||||
}
|
||||
@@ -3827,8 +3909,7 @@
|
||||
@@ -3827,8 +3918,7 @@
|
||||
*/
|
||||
public boolean isBlockHighHumidity(int par1, int par2, int par3)
|
||||
{
|
||||
|
@ -582,7 +583,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -3882,7 +3963,7 @@
|
||||
@@ -3882,7 +3972,7 @@
|
||||
*/
|
||||
public int getHeight()
|
||||
{
|
||||
|
@ -591,7 +592,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -3890,7 +3971,7 @@
|
||||
@@ -3890,7 +3980,7 @@
|
||||
*/
|
||||
public int getActualHeight()
|
||||
{
|
||||
|
@ -600,7 +601,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -3936,7 +4017,7 @@
|
||||
@@ -3936,7 +4026,7 @@
|
||||
*/
|
||||
public double getHorizon()
|
||||
{
|
||||
|
@ -609,7 +610,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -3964,4 +4045,65 @@
|
||||
@@ -3964,4 +4054,75 @@
|
||||
var7.destroyBlockPartially(par1, par2, par3, par4, par5);
|
||||
}
|
||||
}
|
||||
|
@ -618,7 +619,7 @@
|
|||
+ * Adds a single TileEntity to the world.
|
||||
+ * @param entity The TileEntity to be added.
|
||||
+ */
|
||||
+ public void addTileEntity(TileEntity entity)
|
||||
+ public void addTileEntity(TileEntity entity)
|
||||
+ {
|
||||
+ List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
|
||||
+ if(entity.canUpdate())
|
||||
|
@ -630,7 +631,7 @@
|
|||
+ /**
|
||||
+ * Determine if the given block is considered solid on the
|
||||
+ * specified side. Used by placement logic.
|
||||
+ *
|
||||
+ *
|
||||
+ * @param X Block X Position
|
||||
+ * @param Y Block Y Position
|
||||
+ * @param Z Block Z Position
|
||||
|
@ -645,7 +646,7 @@
|
|||
+ /**
|
||||
+ * Determine if the given block is considered solid on the
|
||||
+ * specified side. Used by placement logic.
|
||||
+ *
|
||||
+ *
|
||||
+ * @param X Block X Position
|
||||
+ * @param Y Block Y Position
|
||||
+ * @param Z Block Z Position
|
||||
|
@ -675,8 +676,13 @@
|
|||
+ return block.isBlockSolidOnSide(this, X, Y, Z, side);
|
||||
+ }
|
||||
+
|
||||
+ public ListMultimap<ChunkCoordIntPair, String> getPersistentChunks()
|
||||
+ /**
|
||||
+ * Get the persistent chunks for this world
|
||||
+ *
|
||||
+ * @return
|
||||
+ */
|
||||
+ SetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunks()
|
||||
+ {
|
||||
+ return persistentChunks;
|
||||
+ return ForgeChunkManager.getPersistentChunksFor(this);
|
||||
+ }
|
||||
}
|
||||
|
|
|
@ -7,32 +7,3 @@
|
|||
import cpw.mods.fml.common.Side;
|
||||
import cpw.mods.fml.common.asm.SideOnly;
|
||||
|
||||
@@ -59,6 +60,8 @@
|
||||
private boolean hardcore;
|
||||
private boolean allowCommands;
|
||||
private boolean initialized;
|
||||
+
|
||||
+ public NBTTagCompound forgeWorldData;
|
||||
|
||||
protected WorldInfo()
|
||||
{
|
||||
@@ -139,6 +142,10 @@
|
||||
{
|
||||
this.playerTag = par1NBTTagCompound.getCompoundTag("Player");
|
||||
this.dimension = this.playerTag.getInteger("Dimension");
|
||||
+ }
|
||||
+ if (par1NBTTagCompound.hasKey("ForgeData"))
|
||||
+ {
|
||||
+ this.forgeWorldData = par1NBTTagCompound.getCompoundTag("ForgeData");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +235,8 @@
|
||||
{
|
||||
par1NBTTagCompound.setCompoundTag("Player", par2NBTTagCompound);
|
||||
}
|
||||
+
|
||||
+ par1NBTTagCompound.setCompoundTag("ForgeData", forgeWorldData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
--- ../src_base/common/net/minecraft/src/WorldServer.java
|
||||
+++ ../src_work/common/net/minecraft/src/WorldServer.java
|
||||
@@ -10,6 +10,11 @@
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import cpw.mods.fml.common.Side;
|
||||
import cpw.mods.fml.common.asm.SideOnly;
|
||||
+
|
||||
+import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -10,6 +12,11 @@
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
@ -12,7 +21,7 @@
|
|||
|
||||
public class WorldServer extends World
|
||||
{
|
||||
@@ -71,6 +76,7 @@
|
||||
@@ -71,6 +78,7 @@
|
||||
{
|
||||
this.pendingTickListEntries = new TreeSet();
|
||||
}
|
||||
|
@ -20,7 +29,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -179,10 +185,7 @@
|
||||
@@ -179,10 +187,7 @@
|
||||
|
||||
private void resetRainAndThunder()
|
||||
{
|
||||
|
@ -32,7 +41,7 @@
|
|||
}
|
||||
|
||||
public boolean areAllPlayersAsleep()
|
||||
@@ -270,7 +273,7 @@
|
||||
@@ -270,7 +275,7 @@
|
||||
int var10;
|
||||
int var11;
|
||||
|
||||
|
@ -41,7 +50,7 @@
|
|||
{
|
||||
this.updateLCG = this.updateLCG * 3 + 1013904223;
|
||||
var8 = this.updateLCG >> 2;
|
||||
@@ -288,7 +291,7 @@
|
||||
@@ -288,7 +293,7 @@
|
||||
this.theProfiler.endStartSection("iceandsnow");
|
||||
int var13;
|
||||
|
||||
|
@ -55,22 +64,31 @@
|
|||
{
|
||||
NextTickListEntry var6 = new NextTickListEntry(par1, par2, par3, par4);
|
||||
- byte var7 = 8;
|
||||
+ boolean isForced = persistentChunks.containsKey(new ChunkCoordIntPair(var6.xCoord >> 4, var6.zCoord >> 4));
|
||||
+ boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var6.xCoord >> 4, var6.zCoord >> 4));
|
||||
+ byte var7 = isForced ? (byte)0 : 8;
|
||||
|
||||
if (this.scheduledUpdatesAreImmediate)
|
||||
{
|
||||
@@ -418,7 +424,7 @@
|
||||
*/
|
||||
public void updateEntities()
|
||||
{
|
||||
- if (this.playerEntities.isEmpty())
|
||||
+ if (this.playerEntities.isEmpty() && getPersistentChunks().isEmpty())
|
||||
{
|
||||
if (this.updateEntityTick++ >= 60)
|
||||
{
|
||||
@@ -462,7 +468,8 @@
|
||||
|
||||
this.pendingTickListEntries.remove(var4);
|
||||
this.field_73064_N.remove(var4);
|
||||
- byte var5 = 8;
|
||||
+ boolean isForced = persistentChunks.containsKey(new ChunkCoordIntPair(var4.xCoord >> 4, var4.zCoord >> 4));
|
||||
+ boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var4.xCoord >> 4, var4.zCoord >> 4));
|
||||
+ byte var5 = isForced ? (byte)0 : 8;
|
||||
|
||||
if (this.checkChunksExist(var4.xCoord - var5, var4.yCoord - var5, var4.zCoord - var5, var4.xCoord + var5, var4.yCoord + var5, var4.zCoord + var5))
|
||||
{
|
||||
@@ -559,15 +562,27 @@
|
||||
@@ -559,15 +566,27 @@
|
||||
public List getAllTileEntityInBox(int par1, int par2, int par3, int par4, int par5, int par6)
|
||||
{
|
||||
ArrayList var7 = new ArrayList();
|
||||
|
@ -96,7 +114,7 @@
|
|||
+ TileEntity entity = (TileEntity)obj;
|
||||
+ if (!entity.isInvalid())
|
||||
+ {
|
||||
+ if (entity.xCoord >= par1 && entity.yCoord >= par2 && entity.zCoord >= par3 &&
|
||||
+ if (entity.xCoord >= par1 && entity.yCoord >= par2 && entity.zCoord >= par3 &&
|
||||
+ entity.xCoord <= par4 && entity.yCoord <= par5 && entity.zCoord <= par6)
|
||||
+ {
|
||||
+ var7.add(entity);
|
||||
|
@ -107,7 +125,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -578,6 +593,11 @@
|
||||
@@ -578,6 +597,11 @@
|
||||
* Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here.
|
||||
*/
|
||||
public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
|
||||
|
@ -119,7 +137,7 @@
|
|||
{
|
||||
int var5 = MathHelper.abs_int(par2 - this.worldInfo.getSpawnX());
|
||||
int var6 = MathHelper.abs_int(par4 - this.worldInfo.getSpawnZ());
|
||||
@@ -587,7 +607,7 @@
|
||||
@@ -587,7 +611,7 @@
|
||||
var6 = var5;
|
||||
}
|
||||
|
||||
|
@ -128,7 +146,7 @@
|
|||
}
|
||||
|
||||
protected void initialize(WorldSettings par1WorldSettings)
|
||||
@@ -670,7 +690,7 @@
|
||||
@@ -670,7 +694,7 @@
|
||||
*/
|
||||
protected void createBonusChest()
|
||||
{
|
||||
|
@ -137,16 +155,7 @@
|
|||
|
||||
for (int var2 = 0; var2 < 10; ++var2)
|
||||
{
|
||||
@@ -702,6 +721,8 @@
|
||||
par2IProgressUpdate.displayProgressMessage("Saving level");
|
||||
}
|
||||
|
||||
+ ForgeHooks.dumpPersistentChunks(worldInfo, persistentChunks);
|
||||
+
|
||||
this.saveLevel();
|
||||
|
||||
if (par2IProgressUpdate != null)
|
||||
@@ -713,6 +733,7 @@
|
||||
@@ -713,6 +737,7 @@
|
||||
}
|
||||
|
||||
this.chunkProvider.saveChunks(par1, par2IProgressUpdate);
|
||||
|
@ -154,3 +163,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -971,4 +996,9 @@
|
||||
{
|
||||
return this.thePlayerManager;
|
||||
}
|
||||
+
|
||||
+ public File getChunkSaveLocation()
|
||||
+ {
|
||||
+ return ((AnvilChunkLoader)theChunkProviderServer.currentChunkLoader).chunkSaveLocation;
|
||||
+ }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue