Try and handle removal of mods a bit better. Currently no way to allow a world which has missing

blocks to load - but i have the code in place to allow it i think.
This commit is contained in:
Christian 2014-02-08 12:18:34 -05:00
parent 982f5c7e1b
commit 2d1f9f2811
14 changed files with 204 additions and 70 deletions

View File

@ -25,18 +25,7 @@
}
else
{
@@ -466,6 +470,10 @@
{
try
{
+ if (FMLCommonHandler.instance().shouldServerBeKilledQuietly())
+ {
+ return;
+ }
this.func_71260_j();
this.field_71316_v = true;
}
@@ -475,6 +483,8 @@
@@ -475,6 +479,8 @@
}
finally
{
@ -45,7 +34,7 @@
this.func_71240_o();
}
}
@@ -517,6 +527,7 @@
@@ -517,6 +523,7 @@
{
long i = System.nanoTime();
AxisAlignedBB.func_72332_a().func_72298_a();
@ -53,7 +42,7 @@
++this.field_71315_w;
if (this.field_71295_T)
@@ -570,6 +581,7 @@
@@ -570,6 +577,7 @@
this.field_71304_b.func_76319_b();
this.field_71304_b.func_76319_b();
@ -61,7 +50,7 @@
}
public void func_71190_q()
@@ -597,6 +609,7 @@
@@ -597,6 +605,7 @@
}
this.field_71304_b.func_76320_a("tick");
@ -69,7 +58,7 @@
CrashReport crashreport;
try
@@ -621,6 +634,7 @@
@@ -621,6 +630,7 @@
throw new ReportedException(crashreport);
}
@ -77,7 +66,7 @@
this.field_71304_b.func_76319_b();
this.field_71304_b.func_76320_a("tracker");
worldserver.func_73039_n().func_72788_a();
@@ -699,7 +713,7 @@
@@ -699,7 +709,7 @@
public String getServerModName()
{

View File

@ -1,15 +1,16 @@
--- ../src-base/minecraft/net/minecraft/world/storage/SaveHandler.java
+++ ../src-work/minecraft/net/minecraft/world/storage/SaveHandler.java
@@ -6,6 +6,8 @@
@@ -6,6 +6,9 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+
+import cpw.mods.fml.common.FMLCommonHandler;
+import cpw.mods.fml.common.registry.GameRegistryException;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
@@ -107,16 +109,24 @@
@@ -107,14 +110,22 @@
NBTTagCompound nbttagcompound;
NBTTagCompound nbttagcompound1;
@ -26,16 +27,14 @@
+ FMLCommonHandler.instance().handleWorldDataLoad(this, worldInfo, nbttagcompound);
+ return worldInfo;
}
+ catch (GameRegistryException gre)
+ {
+ throw gre;
+ }
catch (Exception exception1)
{
+ if (FMLCommonHandler.instance().shouldServerBeKilledQuietly())
+ {
+ throw (RuntimeException)exception1;
+ }
exception1.printStackTrace();
}
}
@@ -129,10 +139,16 @@
@@ -129,8 +140,14 @@
{
nbttagcompound = CompressedStreamTools.func_74796_a(new FileInputStream(file1));
nbttagcompound1 = nbttagcompound.func_74775_l("Data");
@ -44,16 +43,14 @@
+ FMLCommonHandler.instance().handleWorldDataLoad(this, worldInfo, nbttagcompound);
+ return worldInfo;
}
+ catch (GameRegistryException gre)
+ {
+ throw gre;
+ }
catch (Exception exception)
{
+ if (FMLCommonHandler.instance().shouldServerBeKilledQuietly())
+ {
+ throw (RuntimeException)exception;
+ }
exception.printStackTrace();
}
}
@@ -146,6 +162,8 @@
@@ -146,6 +163,8 @@
NBTTagCompound nbttagcompound2 = new NBTTagCompound();
nbttagcompound2.func_74782_a("Data", nbttagcompound1);
@ -62,7 +59,7 @@
try
{
File file1 = new File(this.field_75770_b, "level.dat_new");
@@ -184,6 +202,8 @@
@@ -184,6 +203,8 @@
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.func_74782_a("Data", nbttagcompound);

View File

@ -79,9 +79,12 @@ import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
import cpw.mods.fml.common.WrongMinecraftVersionException;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent.Action;
import cpw.mods.fml.common.eventhandler.EventBus;
import cpw.mods.fml.common.network.FMLNetworkEvent;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistryException;
import cpw.mods.fml.common.registry.LanguageRegistry;
import cpw.mods.fml.common.toposort.ModSortingException;
import cpw.mods.fml.relauncher.Side;
@ -588,13 +591,21 @@ public class FMLClientHandler implements IFMLSidedHandler
}
else
{
launchIntegratedServerCallback(dirName, saveName);
}
}
public void launchIntegratedServerCallback(String dirName, String saveName)
{
client.func_71371_a(dirName, saveName, (WorldSettings)null);
try
{
client.func_71371_a(dirName, saveName, (WorldSettings)null);
}
catch (GameRegistryException gre)
{
showGuiScreen(new GuiModItemsMissing(gre.getItems(), gre.getMessage()));
}
}
public void showInGameModOptions(GuiIngameMenu guiIngameMenu)
@ -742,6 +753,7 @@ public class FMLClientHandler implements IFMLSidedHandler
}
private CountDownLatch playClientBlock;
public void setPlayClient(NetHandlerPlayClient netHandlerPlayClient)
{
playClientBlock.countDown();
@ -776,4 +788,17 @@ public class FMLClientHandler implements IFMLSidedHandler
bus.post(new FMLNetworkEvent.CustomPacketRegistrationEvent<NetHandlerPlayServer>(manager, channelSet, channel, side, NetHandlerPlayServer.class));
}
}
public void setDefaultMissingAction(FMLMissingMappingsEvent.Action action)
{
this.defaultMissingAction = action;
}
private Action defaultMissingAction = FMLMissingMappingsEvent.Action.FAIL;
@Override
public Action getDefaultMissingAction()
{
return defaultMissingAction;
}
}

View File

@ -0,0 +1,58 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2013 cpw.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* cpw - implementation
*/
package cpw.mods.fml.client;
import java.util.List;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
public class GuiModItemsMissing extends GuiScreen
{
private List<String> missingItems;
private String message;
public GuiModItemsMissing(List<String> items, String message)
{
this.missingItems = items;
this.message = message;
}
@SuppressWarnings("unchecked")
@Override
public void func_73866_w_()
{
this.field_146292_n.add(new GuiButton(1, this.field_146294_l / 2 - 75, this.field_146295_m - 38, I18n.func_135052_a("gui.done")));
}
@Override
protected void func_146284_a(GuiButton p_73875_1_)
{
if (p_73875_1_.field_146124_l && p_73875_1_.field_146127_k == 1)
{
FMLClientHandler.instance().showGuiScreen(null);
}
}
@Override
public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_)
{
this.func_146276_q_();
int offset = 85;
this.func_73732_a(this.field_146289_q, "Forge Mod Loader could load this save", this.field_146294_l / 2, offset, 0xFFFFFF);
offset += 10;
this.func_73732_a(this.field_146289_q, String.format("There are %d unassigned blocks and items in this save", missingItems.size()), this.field_146294_l / 2, offset, 0xFFFFFF);
offset += 10;
this.func_73732_a(this.field_146289_q, "You will not be able to load until they are present again", this.field_146294_l / 2, offset, 0xFFFFFF);
super.func_73863_a(p_73863_1_, p_73863_2_, p_73863_3_);
}
}

View File

@ -39,6 +39,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.eventhandler.EventBus;
import cpw.mods.fml.common.gameevent.InputEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent;
@ -503,4 +504,9 @@ public class FMLCommonHandler
{
sidedDelegate.fireNetRegistrationEvent(bus(), manager, channelSet, channel, side);
}
public FMLMissingMappingsEvent.Action getDefaultMissingAction()
{
return sidedDelegate.getDefaultMissingAction();
}
}

View File

@ -15,21 +15,19 @@ package cpw.mods.fml.common;
import java.io.File;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.logging.log4j.Level;
import net.minecraft.item.Item;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
import org.apache.logging.log4j.Level;
import com.google.common.collect.Maps;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.client.FMLFileResourcePack;
import cpw.mods.fml.client.FMLFolderResourcePack;
import cpw.mods.fml.common.asm.FMLSanityChecker;
@ -38,6 +36,7 @@ import cpw.mods.fml.common.network.NetworkCheckHandler;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.internal.FMLNetworkHandler;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistryException;
import cpw.mods.fml.relauncher.Side;
/**
@ -173,10 +172,10 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
dataList.put(itemLabel, itemId);
}
}
boolean successfullyInjected = GameData.injectWorldIDMap(dataList, true);
if (!successfullyInjected)
List<String> failedElements = GameData.injectWorldIDMap(dataList, true, true);
if (!failedElements.isEmpty())
{
throw new RuntimeException("Failed to load the world - there are fatal block and item id issues");
throw new GameRegistryException("Failed to load the world - there are fatal block and item id issues", failedElements);
}
}
else if (tag.func_74764_b("ItemData"))
@ -188,10 +187,10 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
NBTTagCompound dataTag = list.func_150305_b(i);
dataList.put(dataTag.func_74779_i("K"), dataTag.func_74762_e("V"));
}
boolean successfullyInjected = GameData.injectWorldIDMap(dataList, true);
if (!successfullyInjected)
List<String> failedElements = GameData.injectWorldIDMap(dataList, true, true);
if (!failedElements.isEmpty())
{
throw new RuntimeException("Failed to load the world - there are fatal block and item id issues");
throw new GameRegistryException("Failed to load the world - there are fatal block and item id issues", failedElements);
}
}
}

View File

@ -18,6 +18,7 @@ import java.util.Set;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetworkManager;
import net.minecraft.server.MinecraftServer;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.eventhandler.EventBus;
import cpw.mods.fml.relauncher.Side;
@ -54,4 +55,6 @@ public interface IFMLSidedHandler
void waitForPlayClient();
void fireNetRegistrationEvent(EventBus bus, NetworkManager manager, Set<String> channelSet, String channel, Side side);
FMLMissingMappingsEvent.Action getDefaultMissingAction();
}

View File

@ -23,9 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.logging.log4j.Level;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
@ -47,7 +45,6 @@ import com.google.common.collect.Ordering;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultimap;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.ModContainer.Disableable;
import cpw.mods.fml.common.discovery.ModDiscoverer;
@ -845,7 +842,7 @@ public class Loader
return true;
}
public boolean fireMissingMappingEvent(ArrayListMultimap<String,String> missing)
public List<String> fireMissingMappingEvent(ArrayListMultimap<String,String> missing, boolean isLocalWorld)
{
if (!missing.isEmpty())
{
@ -859,14 +856,26 @@ public class Loader
}
FMLMissingMappingsEvent missingEvent = new FMLMissingMappingsEvent(missingMappings);
modController.propogateStateMessage(missingEvent);
if (!missingMappings.isEmpty())
if (!missingMappings.isEmpty() && isLocalWorld)
{
FMLLog.severe("There are unidentified mappings in this world - it cannot be loaded");
throw new RuntimeException("Mod IDs are missing");
FMLLog.severe("There are unidentified mappings in this world - we are going to attempt to process anyway");
for (java.util.Map.Entry<String, MissingMapping> missed : missingMappings.entries())
{
remaps.add(missed.getValue());
}
}
return GameData.processIdRematches(remaps);
else if (!missingMappings.isEmpty() && !isLocalWorld)
{
List<String> missedMapping = Lists.newArrayList();
for (java.util.Map.Entry<String, MissingMapping> missed : missingMappings.entries())
{
missedMapping.add(missed.getKey()+ ":" + missed.getValue().name);
}
return ImmutableList.copyOf(missedMapping);
}
return GameData.processIdRematches(remaps, isLocalWorld);
}
return true;
return ImmutableList.of();
}
public void fireRemapEvent(Map<String, Integer[]> remaps)
{

View File

@ -5,7 +5,9 @@ import java.util.List;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.registry.GameRegistry;
/**
* This event is fired if a world is loaded that has block and item mappings referring the mod that are not
@ -16,29 +18,28 @@ import cpw.mods.fml.common.ModContainer;
*
*/
public class FMLMissingMappingsEvent extends FMLEvent {
public static enum Type { BLOCK, ITEM }
/**
* Actions you can take with this missing mapping.
* <ul>
* <li>{@link #IGNORE} means this missing mapping will be ignored.
* <li>{@link #WARN} means this missing mapping will generate a warning.
* <li>{@link #FAIL} means this missing mapping will prevent the world from loading.
* </ul>
* @author cpw
*
*/
public static enum Action { IGNORE, WARN }
public static enum Action { IGNORE, WARN, FAIL }
public static class MissingMapping {
public final Type type;
public final GameRegistry.Type type;
public final String name;
private Action action;
private List<MissingMapping> remaps;
public MissingMapping(String name, List<MissingMapping> remaps)
{
this.type = name.charAt(0) == '\u0001' ? Type.BLOCK : Type.ITEM;
this.type = name.charAt(0) == '\u0001' ? GameRegistry.Type.BLOCK : GameRegistry.Type.ITEM;
this.name = name;
this.remaps = remaps;
this.action = Action.WARN;
this.action = FMLCommonHandler.instance().getDefaultMissingAction();
}
public void setAction(Action target)
{

View File

@ -1,5 +1,6 @@
package cpw.mods.fml.common.network.handshake;
import java.util.List;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import cpw.mods.fml.common.FMLLog;
@ -84,10 +85,13 @@ enum FMLHandshakeClientState implements IHandshakeState<FMLHandshakeClientState>
public FMLHandshakeClientState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg)
{
FMLHandshakeMessage.ModIdData modIds = (FMLHandshakeMessage.ModIdData)msg;
if (!GameData.injectWorldIDMap(modIds.dataList(), false))
List<String> locallyMissing = GameData.injectWorldIDMap(modIds.dataList(), false, false);
if (!locallyMissing.isEmpty())
{
NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
dispatcher.rejectHandshake("Fatally missing blocks and items");
FMLLog.severe("Failed to connect to server: there are %d missing blocks and items", locallyMissing.size());
FMLLog.fine("Missing list: %s", locallyMissing);
return ERROR;
}
ctx.writeAndFlush(new FMLHandshakeMessage.HandshakeAck(ordinal())).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);

View File

@ -30,6 +30,7 @@ import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@ -224,7 +225,7 @@ public class GameData {
}
}
public static boolean injectWorldIDMap(Map<String, Integer> dataList, boolean injectFrozenData)
public static List<String> injectWorldIDMap(Map<String, Integer> dataList, boolean injectFrozenData, boolean isLocalWorld)
{
Map<String, Integer[]> remaps = Maps.newHashMap();
ArrayListMultimap<String,String> missing = ArrayListMultimap.create();
@ -269,12 +270,12 @@ public class GameData {
itemRegistry.reassignMapping(itemName, newId);
}
}
boolean successfullyLoaded = Loader.instance().fireMissingMappingEvent(missing);
if (!successfullyLoaded)
List<String> missedMappings = Loader.instance().fireMissingMappingEvent(missing, isLocalWorld);
if (!missedMappings.isEmpty())
{
blockRegistry.revertSwap();
itemRegistry.revertSwap();
return false;
return missedMappings;
}
if (injectFrozenData)
@ -322,10 +323,11 @@ public class GameData {
blockRegistry.dump();
itemRegistry.dump();
Loader.instance().fireRemapEvent(remaps);
return true;
return ImmutableList.of();
}
public static boolean processIdRematches(List<MissingMapping> remaps)
public static List<String> processIdRematches(List<MissingMapping> remaps, boolean isLocalWorld)
{
List<String> failed = Lists.newArrayList();
List<String> ignored = Lists.newArrayList();
List<String> warned = Lists.newArrayList();
@ -336,21 +338,30 @@ public class GameData {
{
ignored.add(remap.name);
}
else if (action == FMLMissingMappingsEvent.Action.FAIL)
{
failed.add(remap.name);
}
else
{
warned.add(remap.name);
}
}
if (!failed.isEmpty())
{
FMLLog.severe("This world contains blocks and items that refuse to be remapped. The world will not be loaded");
return failed;
}
if (!warned.isEmpty())
{
FMLLog.severe("This world contains block and item mappings that may cause world breakage");
return false;
return failed;
}
else if (!ignored.isEmpty())
{
FMLLog.fine("There were %d missing mappings that have been ignored", ignored.size());
}
return true;
return failed;
}
public static void freezeData()
@ -366,4 +377,5 @@ public class GameData {
blockRegistry.revertToFrozen();
itemRegistry.revertToFrozen();
}
}

View File

@ -140,6 +140,11 @@ public class GameRegistry
return item;
}
public static void addAlias(String alias, String forName, GameRegistry.Type type)
{
}
/**
* Register a block with the specified mod specific name
* @param block The block to register
@ -377,7 +382,8 @@ public class GameRegistry
}
}
/**
public static enum Type { BLOCK, ITEM }
/**
* Look up the mod identifier data for a block.
* Returns null if there is no mod specified mod identifier data, or it is part of a
* custom itemstack definition {@link #registerCustomItemStack}

View File

@ -0,0 +1,19 @@
package cpw.mods.fml.common.registry;
import java.util.List;
public class GameRegistryException extends RuntimeException {
private static final long serialVersionUID = 1L;
private List<String> items;
public GameRegistryException(String message, List<String> items)
{
super(message);
this.items = items;
}
public List<String> getItems()
{
return this.items;
}
}

View File

@ -23,6 +23,7 @@ import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.IFMLSidedHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.eventhandler.EventBus;
import cpw.mods.fml.common.network.FMLNetworkEvent;
import cpw.mods.fml.common.registry.LanguageRegistry;
@ -179,4 +180,9 @@ public class FMLServerHandler implements IFMLSidedHandler
{
bus.post(new FMLNetworkEvent.CustomPacketRegistrationEvent<NetHandlerPlayServer>(manager, channelSet, channel, side, NetHandlerPlayServer.class));
}
@Override
public FMLMissingMappingsEvent.Action getDefaultMissingAction()
{
return FMLMissingMappingsEvent.Action.valueOf(System.getProperty("fml.missingBlockAction", "FAIL"));
}
}