diff --git a/conf/build.gradle.forge b/conf/build.gradle.forge index be0731f..71d1da2 100644 --- a/conf/build.gradle.forge +++ b/conf/build.gradle.forge @@ -41,7 +41,7 @@ compile 'org.scala-lang:scala-xml_2.11:1.0.2' compile 'net.sf.jopt-simple:jopt-simple:4.5' compile 'lzma:lzma:0.0.1' - compile 'com.mojang:realms:1.2.9' + compile 'com.mojang:realms:1.3.1' compile 'org.apache.commons:commons-compress:1.8.1' compile 'org.apache.httpcomponents:httpclient:4.3.3' compile 'commons-logging:commons-logging:1.1.3' @@ -62,7 +62,7 @@ compile 'net.java.jinput:jinput:2.0.5' compile 'net.java.jutils:jutils:1.0.0' compile 'com.google.code.gson:gson:2.2.4' - compile 'com.mojang:authlib:1.5.13' + compile 'com.mojang:authlib:1.5.16' compile 'org.apache.logging.log4j:log4j-api:2.0-beta9' compile 'org.apache.logging.log4j:log4j-core:2.0-beta9' compile 'org.lwjgl.lwjgl:lwjgl:2.9.1' diff --git a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java index cc02906..ebb682f 100644 --- a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java +++ b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java @@ -820,10 +820,17 @@ playClientBlock = new CountDownLatch(1); } + public void connectToRealmsServer(String host, int port) + { + playClientBlock = new CountDownLatch(1); + } + private CountDownLatch playClientBlock; public void setPlayClient(NetHandlerPlayClient netHandlerPlayClient) { + if (playClientBlock == null) + playClientBlock = new CountDownLatch(1); playClientBlock.countDown(); this.currentPlayClient = new WeakReference(netHandlerPlayClient); } diff --git a/src/main/java/cpw/mods/fml/client/FMLConfigGuiFactory.java b/src/main/java/cpw/mods/fml/client/FMLConfigGuiFactory.java index cf220bc..6e8635b 100644 --- a/src/main/java/cpw/mods/fml/client/FMLConfigGuiFactory.java +++ b/src/main/java/cpw/mods/fml/client/FMLConfigGuiFactory.java @@ -10,6 +10,7 @@ import cpw.mods.fml.client.config.ConfigGuiType; import cpw.mods.fml.client.config.DummyConfigElement; import cpw.mods.fml.client.config.GuiConfig; +import cpw.mods.fml.client.config.GuiConfigEntries.NumberSliderEntry; import cpw.mods.fml.client.config.IConfigElement; import cpw.mods.fml.client.config.DummyConfigElement.DummyCategoryElement; import cpw.mods.fml.client.config.DummyConfigElement.DummyListElement; @@ -74,8 +75,10 @@ // Numbers category numbersList.add((new DummyConfigElement("basicInteger", 42, ConfigGuiType.INTEGER, "fml.config.sample.basicInteger"))); numbersList.add((new DummyConfigElement("boundedInteger", 42, ConfigGuiType.INTEGER, "fml.config.sample.boundedInteger", -1, 256))); + numbersList.add((new DummyConfigElement("sliderInteger", 42, ConfigGuiType.INTEGER, "fml.config.sample.sliderInteger", -1, 256)).setCustomListEntryClass(NumberSliderEntry.class)); numbersList.add(new DummyConfigElement("basicDouble", 42.4242D, ConfigGuiType.DOUBLE, "fml.config.sample.basicDouble")); numbersList.add(new DummyConfigElement("boundedDouble", 42.4242D, ConfigGuiType.DOUBLE, "fml.config.sample.boundedDouble", -1.0D, 256.256D)); + numbersList.add(new DummyConfigElement("sliderDouble", 42.4242D, ConfigGuiType.DOUBLE, "fml.config.sample.sliderDouble", -1.0D, 256.256D).setCustomListEntryClass(NumberSliderEntry.class)); list.add(new DummyCategoryElement("numbers", "fml.config.sample.ctgy.numbers", numbersList)); diff --git a/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java b/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java index fe8eb11..d71533f 100644 --- a/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java +++ b/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java @@ -66,7 +66,16 @@ FMLLog.info("Capturing current state of world %s into file %s", saveName, zip.getAbsolutePath()); try { - ZipperUtil.zip(new File(FMLClientHandler.instance().getSavesDir(), dirName), zip); + String skip = System.getProperty("fml.doNotBackup"); + if (skip == null || !"true".equals(skip)) + { + ZipperUtil.zip(new File(FMLClientHandler.instance().getSavesDir(), dirName), zip); + } + else + { + for (int x = 0; x < 10; x++) + FMLLog.severe("!!!!!!!!!! UPDATING WORLD WITHOUT DOING BACKUP !!!!!!!!!!!!!!!!"); + } } catch (IOException e) { FMLLog.log(Level.WARN, e, "There was a problem saving the backup %s. Please fix and try again", zip.getName()); diff --git a/src/main/java/cpw/mods/fml/client/config/GuiConfig.java b/src/main/java/cpw/mods/fml/client/config/GuiConfig.java index 69f2864..9ec63a4 100644 --- a/src/main/java/cpw/mods/fml/client/config/GuiConfig.java +++ b/src/main/java/cpw/mods/fml/client/config/GuiConfig.java @@ -82,11 +82,11 @@ * * @param parentScreen the parent GuiScreen object * @param configElements a List of IConfigProperty objects - * @param areAllPropsHotLoadable send true if every property on this screen is able to be modified on the fly while a world is running * @param modID the mod ID for the mod whose config settings will be edited * @param configID an identifier that will be passed to the OnConfigChanged and PostConfigChanged events. Setting this value will force * the save action to be called when the Done button is pressed on this screen if any configElements were changed. * @param allRequireWorldRestart send true if all configElements on this screen require a world restart + * @param allRequireMcRestart send true if all configElements on this screen require MC to be restarted * @param title the desired title for this screen. For consistency it is recommended that you pass the path of the config file being * edited. */ @@ -102,9 +102,9 @@ * * @param parentScreen the parent GuiScreen object * @param configElements a List of IConfigProperty objects - * @param areAllPropsHotLoadable send true if every property on this screen is able to be modified on the fly while a world is running * @param modID the mod ID for the mod whose config settings will be edited * @param allRequireWorldRestart send true if all configElements on this screen require a world restart + * @param allRequireMcRestart send true if all configElements on this screen require MC to be restarted * @param title the desired title for this screen. For consistency it is recommended that you pass the path of the config file being * edited. */ @@ -122,6 +122,7 @@ * @param configElements a List of IConfigProperty objects * @param modID the mod ID for the mod whose config settings will be edited * @param allRequireWorldRestart send true if all configElements on this screen require a world restart + * @param allRequireMcRestart send true if all configElements on this screen require MC to be restarted * @param title the desired title for this screen. For consistency it is recommended that you pass the path of the config file being * edited. * @param titleLine2 the desired title second line for this screen. Typically this is used to send the category name of the category @@ -144,6 +145,7 @@ * @param modID the mod ID for the mod whose config settings will be edited * @param configID an identifier that will be passed to the OnConfigChanged and PostConfigChanged events * @param allRequireWorldRestart send true if all configElements on this screen require a world restart + * @param allRequireMcRestart send true if all configElements on this screen require MC to be restarted * @param title the desired title for this screen. For consistency it is recommended that you pass the path of the config file being * edited. * @param titleLine2 the desired title second line for this screen. Typically this is used to send the category name of the category diff --git a/src/main/java/cpw/mods/fml/client/config/GuiConfigEntries.java b/src/main/java/cpw/mods/fml/client/config/GuiConfigEntries.java index 9377507..e86c3c2 100644 --- a/src/main/java/cpw/mods/fml/client/config/GuiConfigEntries.java +++ b/src/main/java/cpw/mods/fml/client/config/GuiConfigEntries.java @@ -779,6 +779,104 @@ } /** + * NumberSliderEntry + * + * Provides a slider for numeric properties. + */ + public static class NumberSliderEntry extends ButtonEntry + { + protected final double beforeValue; + + public NumberSliderEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement configElement) + { + super(owningScreen, owningEntryList, configElement, new GuiSlider(0, owningEntryList.controlX, 0, owningEntryList.controlWidth, 18, + "", "", Double.valueOf(configElement.getMinValue().toString()), Double.valueOf(configElement.getMaxValue().toString()), + Double.valueOf(configElement.get().toString()), configElement.getType() == ConfigGuiType.DOUBLE, true)); + + if (configElement.getType() == ConfigGuiType.INTEGER) + this.beforeValue = Integer.valueOf(configElement.get().toString()); + else + this.beforeValue = Double.valueOf(configElement.get().toString()); + } + + @Override + public void updateValueButtonText() + { + ((GuiSlider) this.btnValue).updateSlider(); + } + + @Override + public void valueButtonPressed(int slotIndex) {} + + @Override + public boolean isDefault() + { + if (configElement.getType() == ConfigGuiType.INTEGER) + return (int) ((GuiSlider) this.btnValue).getValue() == Integer.valueOf(configElement.getDefault().toString()); + else + return ((GuiSlider) this.btnValue).getValue() == Double.valueOf(configElement.getDefault().toString()); + } + + @Override + public void setToDefault() + { + if (this.enabled()) + { + ((GuiSlider) this.btnValue).setValue(Double.valueOf(configElement.getDefault().toString())); + ((GuiSlider) this.btnValue).updateSlider(); + } + } + + @Override + public boolean isChanged() + { + if (configElement.getType() == ConfigGuiType.INTEGER) + return (int) ((GuiSlider) this.btnValue).getValue() != (int) beforeValue; + else + return ((GuiSlider) this.btnValue).getValue() != beforeValue; + } + + @Override + public void undoChanges() + { + if (this.enabled()) + { + ((GuiSlider) this.btnValue).setValue(beforeValue); + ((GuiSlider) this.btnValue).updateSlider(); + } + } + + @Override + public boolean saveConfigElement() + { + if (this.enabled() && this.isChanged()) + { + if (configElement.getType() == ConfigGuiType.INTEGER) + configElement.set((int) ((GuiSlider) this.btnValue).getValue()); + else + configElement.set(((GuiSlider) this.btnValue).getValue()); + return configElement.requiresMcRestart(); + } + return false; + } + + @Override + public Object getCurrentValue() + { + if (configElement.getType() == ConfigGuiType.INTEGER) + return (int) ((GuiSlider) this.btnValue).getValue(); + else + return ((GuiSlider) this.btnValue).getValue(); + } + + @Override + public Object[] getCurrentValues() + { + return new Object[] { getCurrentValue() }; + } + } + + /** * ButtonEntry * * Provides a basic GuiButton entry to be used as a base for other entries that require a button for the value. @@ -789,9 +887,14 @@ public ButtonEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement configElement) { + this(owningScreen, owningEntryList, configElement, new GuiButtonExt(0, owningEntryList.controlX, 0, owningEntryList.controlWidth, 18, + configElement.get() != null ? I18n.format(String.valueOf(configElement.get())) : "")); + } + + public ButtonEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement configElement, GuiButtonExt button) + { super(owningScreen, owningEntryList, configElement); - this.btnValue = new GuiButtonExt(0, this.owningEntryList.controlX, 0, this.owningEntryList.controlWidth, 18, - configElement.get() != null ? I18n.format(String.valueOf(configElement.get())) : ""); + this.btnValue = button; } /** diff --git a/src/main/java/cpw/mods/fml/client/config/GuiSlider.java b/src/main/java/cpw/mods/fml/client/config/GuiSlider.java new file mode 100644 index 0000000..e61eb95 --- /dev/null +++ b/src/main/java/cpw/mods/fml/client/config/GuiSlider.java @@ -0,0 +1,201 @@ +package cpw.mods.fml.client.config; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; + +import org.lwjgl.opengl.GL11; + +/** + * This class is blatantly stolen from iChunUtils with permission. + * + * @author iChun + */ +public class GuiSlider extends GuiButtonExt +{ + /** The value of this slider control. */ + public double sliderValue = 1.0F; + + public String dispString = ""; + + /** Is this slider control being dragged. */ + public boolean dragging = false; + public boolean showDecimal = true; + + public double minValue = 0.0D; + public double maxValue = 5.0D; + public int precision = 1; + + public ISlider parent = null; + + public String suffix = ""; + + public boolean drawString = true; + + public GuiSlider(int id, int xPos, int yPos, int width, int height, String prefix, String suf, double minVal, double maxVal, double currentVal, boolean showDec, boolean drawStr) + { + this(id, xPos, yPos, width, height, prefix, suf, minVal, maxVal, currentVal, showDec, drawStr, null); + } + + public GuiSlider(int id, int xPos, int yPos, int width, int height, String prefix, String suf, double minVal, double maxVal, double currentVal, boolean showDec, boolean drawStr, ISlider par) + { + super(id, xPos, yPos, width, height, prefix); + minValue = minVal; + maxValue = maxVal; + sliderValue = (currentVal - minValue) / (maxValue - minValue); + dispString = prefix; + parent = par; + suffix = suf; + showDecimal = showDec; + String val; + + if (showDecimal) + { + val = Double.toString(sliderValue * (maxValue - minValue) + minValue); + precision = Math.min(val.substring(val.indexOf(".") + 1).length(), 4); + } + else + { + val = Integer.toString((int)Math.round(sliderValue * (maxValue - minValue) + minValue)); + precision = 0; + } + + displayString = dispString + val + suffix; + + drawString = drawStr; + if(!drawString) + { + displayString = ""; + } + } + + public GuiSlider(int id, int xPos, int yPos, String displayStr, double minVal, double maxVal, double currentVal, ISlider par) + { + this(id, xPos, yPos, 150, 20, displayStr, "", minVal, maxVal, currentVal, true, true, par); + } + + /** + * Returns 0 if the button is disabled, 1 if the mouse is NOT hovering over this button and 2 if it IS hovering over + * this button. + */ + public int getHoverState(boolean par1) + { + return 0; + } + + /** + * Fired when the mouse button is dragged. Equivalent of MouseListener.mouseDragged(MouseEvent e). + */ + protected void mouseDragged(Minecraft par1Minecraft, int par2, int par3) + { + if (this.visible) + { + if (this.dragging) + { + this.sliderValue = (par2 - (this.xPosition + 4)) / (float)(this.width - 8); + updateSlider(); + } + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.xPosition + (int)(this.sliderValue * (float)(this.width - 8)), this.yPosition, 0, 66, 4, 20); + this.drawTexturedModalRect(this.xPosition + (int)(this.sliderValue * (float)(this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20); + } + } + + /** + * Returns true if the mouse has been pressed on this control. Equivalent of MouseListener.mousePressed(MouseEvent + * e). + */ + public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) + { + if (super.mousePressed(par1Minecraft, par2, par3)) + { + this.sliderValue = (float)(par2 - (this.xPosition + 4)) / (float)(this.width - 8); + updateSlider(); + this.dragging = true; + return true; + } + else + { + return false; + } + } + + public void updateSlider() + { + if (this.sliderValue < 0.0F) + { + this.sliderValue = 0.0F; + } + + if (this.sliderValue > 1.0F) + { + this.sliderValue = 1.0F; + } + + String val; + + if (showDecimal) + { + val = Double.toString(sliderValue * (maxValue - minValue) + minValue); + + if (val.substring(val.indexOf(".") + 1).length() > precision) + { + val = val.substring(0, val.indexOf(".") + precision + 1); + + if (val.endsWith(".")) + { + val = val.substring(0, val.indexOf(".") + precision); + } + } + else + { + while (val.substring(val.indexOf(".") + 1).length() < precision) + { + val = val + "0"; + } + } + } + else + { + val = Integer.toString((int)Math.round(sliderValue * (maxValue - minValue) + minValue)); + } + + if(drawString) + { + displayString = dispString + val + suffix; + } + + if (parent != null) + { + parent.onChangeSliderValue(this); + } + } + + /** + * Fired when the mouse button is released. Equivalent of MouseListener.mouseReleased(MouseEvent e). + */ + public void mouseReleased(int par1, int par2) + { + this.dragging = false; + } + + public int getValueInt() + { + return (int)Math.round(sliderValue * (maxValue - minValue) + minValue); + } + + public double getValue() + { + return sliderValue * (maxValue - minValue) + minValue; + } + + public void setValue(double d) + { + this.sliderValue = (d - minValue) / (maxValue - minValue); + } + + public static interface ISlider + { + void onChangeSliderValue(GuiSlider slider); + } +} \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/Loader.java b/src/main/java/cpw/mods/fml/common/Loader.java index 646e1b3..8a2bd19 100644 --- a/src/main/java/cpw/mods/fml/common/Loader.java +++ b/src/main/java/cpw/mods/fml/common/Loader.java @@ -504,12 +504,12 @@ public void preinitializeMods() { - ObjectHolderRegistry.INSTANCE.findObjectHolders(discoverer.getASMTable()); if (!modController.isInState(LoaderState.PREINITIALIZATION)) { FMLLog.warning("There were errors previously. Not beginning mod initialization phase"); return; } + ObjectHolderRegistry.INSTANCE.findObjectHolders(discoverer.getASMTable()); modController.distributeStateMessage(LoaderState.PREINITIALIZATION, discoverer.getASMTable(), canonicalConfigDir); ObjectHolderRegistry.INSTANCE.applyObjectHolders(); modController.transition(LoaderState.INITIALIZATION, false); diff --git a/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java b/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java index a19ff26..abcbff9 100644 --- a/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java +++ b/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java @@ -106,41 +106,10 @@ readMapFile(rulesFile); } - AccessTransformer(JarFile jar) throws IOException - { - Manifest manifest = jar.getManifest(); - String atList = manifest.getMainAttributes().getValue("FMLAT"); - if (atList == null) return; - for (String at : atList.split(" ")) - { - JarEntry jarEntry = jar.getJarEntry("META-INF/"+at); - if (jarEntry != null) - { - processATFile(new JarByteSource(jar,jarEntry).asCharSource(Charsets.UTF_8)); - } - } - FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer mod jar file %s\n", modifiers.size(), jar.getName()); - } - AccessTransformer(Class dummyClazz) { // This is a noop } - private class JarByteSource extends ByteSource { - private JarFile jar; - private JarEntry entry; - public JarByteSource(JarFile jar, JarEntry entry) - { - this.jar = jar; - this.entry = entry; - } - @Override - public InputStream openStream() throws IOException - { - return jar.getInputStream(entry); - } - - } void readMapFile(String rulesFile) throws IOException { File file = new File(rulesFile); @@ -156,7 +125,7 @@ processATFile(Resources.asCharSource(rulesResource, Charsets.UTF_8)); FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer config file %s\n", modifiers.size(), rulesFile); } - private void processATFile(CharSource rulesResource) throws IOException + protected void processATFile(CharSource rulesResource) throws IOException { rulesResource.readLines(new LineProcessor() { diff --git a/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java b/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java index eb442d7..c1a66dd 100644 --- a/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java +++ b/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java @@ -1,34 +1,71 @@ package cpw.mods.fml.common.asm.transformers; import java.io.IOException; -import java.util.List; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; +import java.util.jar.Manifest; +import com.google.common.base.Charsets; +import com.google.common.collect.Maps; +import com.google.common.io.ByteSource; +import com.google.common.io.CharSource; +import cpw.mods.fml.relauncher.FMLRelaunchLog; public class ModAccessTransformer extends AccessTransformer { - private static List embedded = Lists.newArrayList(); - public ModAccessTransformer() throws IOException + private static Map embedded = Maps.newHashMap(); //Needs to be primitive so that both classloaders get the same class. + public ModAccessTransformer() throws Exception { super(ModAccessTransformer.class); - for (AccessTransformer at : embedded) - { - mergeModifiers(at.getModifiers()); - } - } + //We are in the new ClassLoader here, so we need to get the static field from the other ClassLoader. + ClassLoader classLoader = this.getClass().getClassLoader().getClass().getClassLoader(); //Bit odd but it gets the class loader that loaded our current class loader yay java! + Class otherClazz = Class.forName(this.getClass().getName(), true, classLoader); + Field otherField = otherClazz.getDeclaredField("embedded"); + otherField.setAccessible(true); + embedded = (Map)otherField.get(null); - private void mergeModifiers(Multimap modifiers) - { - getModifiers().putAll(modifiers); + for (Map.Entry e : embedded.entrySet()) + { + int old_count = getModifiers().size(); + processATFile(CharSource.wrap(e.getValue())); + int added = getModifiers().size() - old_count; + if (added > 0) + { + FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer mod jar file %s\n", added, e.getKey()); + } + } } public static void addJar(JarFile jar) throws IOException { - AccessTransformer at = new AccessTransformer(jar); - if (!at.isEmpty()) + Manifest manifest = jar.getManifest(); + String atList = manifest.getMainAttributes().getValue("FMLAT"); + if (atList == null) return; + for (String at : atList.split(" ")) { - embedded.add(at); + JarEntry jarEntry = jar.getJarEntry("META-INF/"+at); + if (jarEntry != null) + { + embedded.put(String.format("%s!META-INF/%s", jar.getName(), at), + new JarByteSource(jar,jarEntry).asCharSource(Charsets.UTF_8).read()); + } } } + private static class JarByteSource extends ByteSource + { + private JarFile jar; + private JarEntry entry; + public JarByteSource(JarFile jar, JarEntry entry) + { + this.jar = jar; + this.entry = entry; + } + @Override + public InputStream openStream() throws IOException + { + return jar.getInputStream(entry); + } + } } \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/asm/transformers/TerminalTransformer.java b/src/main/java/cpw/mods/fml/common/asm/transformers/TerminalTransformer.java new file mode 100644 index 0000000..cb406de --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/asm/transformers/TerminalTransformer.java @@ -0,0 +1,113 @@ +package cpw.mods.fml.common.asm.transformers; + +import org.objectweb.asm.*; + +import cpw.mods.fml.relauncher.FMLRelaunchLog; +import cpw.mods.fml.relauncher.FMLSecurityManager.ExitTrappedException; +import net.minecraft.launchwrapper.IClassTransformer; + +public class TerminalTransformer implements IClassTransformer +{ + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) + { + ClassReader reader = new ClassReader(basicClass); + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); + + ClassVisitor visitor = writer; + visitor = new ExitVisitor(visitor); + + reader.accept(visitor, 0); + return writer.toByteArray(); + } + + public static class ExitVisitor extends ClassVisitor + { + private String clsName = null; + private static final String callbackOwner = org.objectweb.asm.Type.getInternalName(ExitVisitor.class); + + private ExitVisitor(ClassVisitor cv) + { + super(Opcodes.ASM4, cv); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) + { + super.visit(version, access, name, signature, superName, interfaces); + this.clsName = name; + } + + @Override + public MethodVisitor visitMethod(int mAccess, final String mName, final String mDesc, String mSignature, String[] mExceptions) + { + final boolean warn = !clsName.equals("net/minecraft/client/Minecraft") && + !clsName.equals("net/minecraft/server/dedicated/DedicatedServer") && + !clsName.equals("cpw/mods/fml/common/FMLCommonHandler"); + + return new MethodVisitor(Opcodes.ASM4, super.visitMethod(mAccess, mName, mDesc, mSignature, mExceptions)) + { + public void visitMethodInsn(int opcode, String owner, String name, String desc) + { + if (opcode == Opcodes.INVOKESTATIC && owner.equals("java/lang/System") && name.equals("exit") && desc.equals("(I)V")) + { + if (warn) + { + FMLRelaunchLog.warning("============================================================="); + FMLRelaunchLog.warning("MOD HAS DIRECT REFERENCE System.exit() THIS IS NOT ALLOWED REROUTING TO FMLCommonHandler!"); + FMLRelaunchLog.warning("Offendor: %s.%s%s", ExitVisitor.this.clsName, mName, mDesc); + FMLRelaunchLog.warning("============================================================="); + } + owner = ExitVisitor.callbackOwner; + name = "systemExitCalled"; + } + else if (opcode == Opcodes.INVOKEVIRTUAL && owner.equals("java/lang/Runtime") && name.equals("exit") && desc.equals("(I)V")) + { + if (warn) + { + FMLRelaunchLog.warning("============================================================="); + FMLRelaunchLog.warning("MOD HAS DIRECT REFERENCE Runtime.exit() THIS IS NOT ALLOWED REROUTING TO FMLCommonHandler!"); + FMLRelaunchLog.warning("Offendor: %s.%s%s", ExitVisitor.this.clsName, mName, mDesc); + FMLRelaunchLog.warning("============================================================="); + } + opcode = Opcodes.INVOKESTATIC; + owner = ExitVisitor.callbackOwner; + name = "runtimeExitCalled"; + desc = "(Ljava/lang/Runtime;I)V"; + } + + super.visitMethodInsn(opcode, owner, name, desc); + } + }; + } + + // Intercept System.exit, and check if the caller is allowed to use it, if not wrap it in a ExitTrappedException + public static void systemExitCalled(int status) + { + ExitVisitor.checkAccess(); + System.exit(status); + } + // Intercept Runtime.getRuntime().exit, and check if the caller is allowed to use it, if not wrap it in a ExitTrappedException + public static void runtimeExitCalled(Runtime runtime, int status) + { + ExitVisitor.checkAccess(); + runtime.exit(status); + } + + private static void checkAccess() + { + StackTraceElement[] cause = Thread.currentThread().getStackTrace(); + + String callingClass = cause.length > 2 ? cause[3].getClassName() : "none"; + String callingParent = cause.length > 3 ? cause[4].getClassName() : "none"; + // FML is allowed to call system exit and the Minecraft applet (from the quit button), and the dedicated server (from itself) + if (!(callingClass.startsWith("cpw.mods.fml.") || + ("net.minecraft.client.Minecraft".equals(callingClass) && "net.minecraft.client.Minecraft".equals(callingParent)) || + ("net.minecraft.server.dedicated.DedicatedServer".equals(callingClass) && "net.minecraft.server.MinecraftServer".equals(callingParent))) + ) + { + throw new ExitTrappedException(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java b/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java index 4ad84e2..d42067a 100644 --- a/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java +++ b/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java @@ -6,6 +6,7 @@ import cpw.mods.fml.relauncher.CoreModManager; import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; /** @@ -30,6 +31,9 @@ { // We sort the tweak list here so that it obeys the tweakordering CoreModManager.sortTweakList(); + @SuppressWarnings("unchecked") + List newTweaks = (List) Launch.blackboard.get("TweakClasses"); + newTweaks.add("cpw.mods.fml.common.launcher.TerminalTweaker"); } run = true; } diff --git a/src/main/java/cpw/mods/fml/common/launcher/FMLTweaker.java b/src/main/java/cpw/mods/fml/common/launcher/FMLTweaker.java index 1b7141b..2f8600e 100644 --- a/src/main/java/cpw/mods/fml/common/launcher/FMLTweaker.java +++ b/src/main/java/cpw/mods/fml/common/launcher/FMLTweaker.java @@ -29,6 +29,7 @@ public FMLTweaker() { + System.setProperty("java.net.preferIPv4Stack", "true"); //Lets do this as early as possible. Vanilla does it in Main.main try { System.setSecurityManager(new FMLSecurityManager()); diff --git a/src/main/java/cpw/mods/fml/common/launcher/TerminalTweaker.java b/src/main/java/cpw/mods/fml/common/launcher/TerminalTweaker.java new file mode 100644 index 0000000..3fd43d0 --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/launcher/TerminalTweaker.java @@ -0,0 +1,32 @@ +package cpw.mods.fml.common.launcher; + +import java.io.File; +import java.util.List; +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.LaunchClassLoader; + +public final class TerminalTweaker implements ITweaker { + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) + { + classLoader.registerTransformer("cpw.mods.fml.common.asm.transformers.TerminalTransformer"); + } + + @Override + public String getLaunchTarget() + { + return null; + } + + @Override + public String[] getLaunchArguments() + { + return new String[0]; + } + + @Override + public void acceptOptions(List args, File gameDir, File assetsDir, String profile) + { + + } +} \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/launcher/Yggdrasil.java b/src/main/java/cpw/mods/fml/common/launcher/Yggdrasil.java index c28f559..ac5f49c 100644 --- a/src/main/java/cpw/mods/fml/common/launcher/Yggdrasil.java +++ b/src/main/java/cpw/mods/fml/common/launcher/Yggdrasil.java @@ -6,127 +6,49 @@ import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.Proxy; import java.net.URL; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; import com.google.common.base.Charsets; +import com.google.common.base.Throwables; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.mojang.authlib.Agent; +import com.mojang.authlib.exceptions.*; +import com.mojang.authlib.yggdrasil.*; /** * Basic implementation of Mojang's 'Yggdrasil' login system, purely intended as a dev time bare bones login. * Login errors are not handled. */ -@SuppressWarnings("unused") -public class Yggdrasil { - private static class Request { - Agent agent = new Agent(); - String username; - String password; - String clientToken = null; - boolean requestUser = true; - - public Request(String username, String password){ - this.username = username; - this.password = password; - } - - private static class Agent { - String name = "Minecraft"; - int version = 1; - } - } - - private static class Response { - String error; - String errorMessage; - String cause; - String accessToken; - String clientToken; - Profile selectedProfile; - Profile[] availableProfiles; - User user; - - private static class Profile { - String id; - String name; - boolean legacy; - } - - private static class User { - String id; - List properties; - - private static class Property { - String name; - String value; - } - } - } - - private static void close(Closeable c) - { - if (c != null) { - try { - c.close(); - } catch (IOException e){} - } - } - +public class Yggdrasil +{ public static void login(Map args) { if (!args.containsKey("--username") || !args.containsKey("--password")) return; - - String username = args.get("--username"); - String password = args.remove("--password"); - - Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - String request = GSON.toJson(new Request(username, password)); - - OutputStream out = null; - InputStream in = null; + YggdrasilUserAuthentication auth = (YggdrasilUserAuthentication) new YggdrasilAuthenticationService(Proxy.NO_PROXY, "1").createUserAuthentication(Agent.MINECRAFT); + auth.setUsername(args.get("--username")); + auth.setPassword(args.remove("--password")); try { - HttpURLConnection con = (HttpURLConnection)(new URL("https://authserver.mojang.com/authenticate")).openConnection(); - con.setConnectTimeout(15000); - con.setReadTimeout(15000); - con.setUseCaches(false); - - byte[] data = request.getBytes(Charsets.UTF_8); - - con.setRequestProperty("Content-Type", "application/json; charset=utf-8"); - con.setRequestProperty("Content-Length", Integer.toString(data.length)); - con.setDoOutput(true); - - out = con.getOutputStream(); - out.write(data); - - in = con.getInputStream(); - Response result = GSON.fromJson(IOUtils.toString(in, Charsets.UTF_8), Response.class); - - if (result.selectedProfile != null) - { - args.put("--username", result.selectedProfile.name); - args.put("--uuid", result.selectedProfile.id); - args.put("--accessToken", result.accessToken); - } + auth.logIn(); } - catch (MalformedURLException e) + catch (AuthenticationException e) { - e.printStackTrace(); + LogManager.getLogger("FMLTWEAK").error("-- Login failed! " + e.getMessage()); + Throwables.propagate(e); + return; // dont set other variables } - catch (IOException e) - { - e.printStackTrace(); - } - finally - { - close(out); - close(in); - } + + args.put("--username", auth.getSelectedProfile().getName()); + args.put("--uuid", auth.getSelectedProfile().getId().toString().replace("-", "")); + args.put("--accessToken", auth.getAuthenticatedToken()); + args.put("--userProperties", auth.getUserProperties().toString()); } } \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java index 274c0a0..25e5dc3 100644 --- a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java +++ b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java @@ -454,6 +454,7 @@ public void abortClientHandshake(String type) { + FMLLog.log(Level.INFO, "Aborting client handshake \"%s\"", type); FMLCommonHandler.instance().waitForPlayClient(); completeClientSideConnection(ConnectionType.valueOf(type)); } diff --git a/src/main/java/cpw/mods/fml/common/registry/GameData.java b/src/main/java/cpw/mods/fml/common/registry/GameData.java index 2b317a4..a14cec6 100644 --- a/src/main/java/cpw/mods/fml/common/registry/GameData.java +++ b/src/main/java/cpw/mods/fml/common/registry/GameData.java @@ -369,7 +369,16 @@ // backup try { - ZipperUtil.backupWorld(); + String skip = System.getProperty("fml.doNotBackup"); + if (skip == null || !"true".equals(skip)) + { + ZipperUtil.backupWorld(); + } + else + { + for (int x = 0; x < 10; x++) + FMLLog.severe("!!!!!!!!!! UPDATING WORLD WITHOUT DOING BACKUP !!!!!!!!!!!!!!!!"); + } } catch (IOException e) { @@ -618,7 +627,16 @@ try { - ZipperUtil.backupWorld(); + String skip = System.getProperty("fml.doNotBackup"); + if (skip == null || !"true".equals(skip)) + { + ZipperUtil.backupWorld(); + } + else + { + for (int x = 0; x < 10; x++) + FMLLog.severe("!!!!!!!!!! UPDATING WORLD WITHOUT DOING BACKUP !!!!!!!!!!!!!!!!"); + } } catch (IOException e) { diff --git a/src/main/java/net/minecraft/client/gui/GuiNewChat.java b/src/main/java/net/minecraft/client/gui/GuiNewChat.java index 5183e97..6294836 100644 --- a/src/main/java/net/minecraft/client/gui/GuiNewChat.java +++ b/src/main/java/net/minecraft/client/gui/GuiNewChat.java @@ -99,6 +99,7 @@ byte b0 = 0; int j2 = -j1 * 9; drawRect(b0, j2 - 9, b0 + i1 + 4, j2, i2 / 2 << 24); + GL11.glEnable(GL11.GL_BLEND); // FORGE: BugFix MC-36812 Chat Opacity Broken in 1.7.x String s = chatline.func_151461_a().getFormattedText(); this.mc.fontRenderer.drawStringWithShadow(s, b0, j2 - 8, 16777215 + (i2 << 24)); GL11.glDisable(GL11.GL_ALPHA_TEST); diff --git a/src/main/java/net/minecraft/client/network/NetHandlerPlayClient.java b/src/main/java/net/minecraft/client/network/NetHandlerPlayClient.java index 29ec0fd..2eaace2 100644 --- a/src/main/java/net/minecraft/client/network/NetHandlerPlayClient.java +++ b/src/main/java/net/minecraft/client/network/NetHandlerPlayClient.java @@ -391,7 +391,8 @@ public void handleSpawnExperienceOrb(S11PacketSpawnExperienceOrb p_147286_1_) { - EntityXPOrb entityxporb = new EntityXPOrb(this.clientWorldController, (double)p_147286_1_.func_148984_d(), (double)p_147286_1_.func_148983_e(), (double)p_147286_1_.func_148982_f(), p_147286_1_.func_148986_g()); + EntityXPOrb entityxporb = new EntityXPOrb(this.clientWorldController, (double)p_147286_1_.func_148984_d() / 32.0D, (double)p_147286_1_.func_148983_e() / 32.0D, (double)p_147286_1_.func_148982_f() / 32.0D, p_147286_1_.func_148986_g()); + // FORGE: BugFix MC-12013 Wrong XP orb clientside spawn position entityxporb.serverPosX = p_147286_1_.func_148984_d(); entityxporb.serverPosY = p_147286_1_.func_148983_e(); entityxporb.serverPosZ = p_147286_1_.func_148982_f(); diff --git a/src/main/java/net/minecraft/client/resources/LanguageManager.java b/src/main/java/net/minecraft/client/resources/LanguageManager.java index 750528b..74b7d12 100644 --- a/src/main/java/net/minecraft/client/resources/LanguageManager.java +++ b/src/main/java/net/minecraft/client/resources/LanguageManager.java @@ -84,8 +84,8 @@ arraylist.add(this.currentLanguage); } - currentLocale.loadLocaleDataFiles(p_110549_1_, arraylist); LanguageRegistry.instance().loadLanguageTable(currentLocale.field_135032_a, this.currentLanguage); + currentLocale.loadLocaleDataFiles(p_110549_1_, arraylist); StringTranslate.replaceWith(currentLocale.field_135032_a); } diff --git a/src/main/java/net/minecraft/enchantment/Enchantment.java b/src/main/java/net/minecraft/enchantment/Enchantment.java index ea54c06..fc45843 100644 --- a/src/main/java/net/minecraft/enchantment/Enchantment.java +++ b/src/main/java/net/minecraft/enchantment/Enchantment.java @@ -50,7 +50,7 @@ if (enchantmentsList[p_i1926_1_] != null) { - throw new IllegalArgumentException("Duplicate enchantment id!"); + throw new IllegalArgumentException("Duplicate enchantment id! " + this.getClass() + " and " + enchantmentsList[p_i1926_1_].getClass() + " Enchantment ID:" + p_i1926_1_); } else { diff --git a/src/main/java/net/minecraft/item/ItemSkull.java b/src/main/java/net/minecraft/item/ItemSkull.java index 5b65160..85e0c88 100644 --- a/src/main/java/net/minecraft/item/ItemSkull.java +++ b/src/main/java/net/minecraft/item/ItemSkull.java @@ -36,11 +36,16 @@ public boolean onItemUse(ItemStack p_77648_1_, EntityPlayer p_77648_2_, World p_77648_3_, int p_77648_4_, int p_77648_5_, int p_77648_6_, int p_77648_7_, float p_77648_8_, float p_77648_9_, float p_77648_10_) { + if(p_77648_3_.getBlock(p_77648_4_, p_77648_5_, p_77648_6_).isReplaceable(p_77648_3_, p_77648_4_, p_77648_5_, p_77648_6_) && p_77648_7_ != 0) + { + p_77648_7_ = 1; + p_77648_5_--; + } if (p_77648_7_ == 0) { return false; } - else if (!p_77648_3_.getBlock(p_77648_4_, p_77648_5_, p_77648_6_).getMaterial().isSolid()) + else if (!p_77648_3_.isSideSolid(p_77648_4_, p_77648_5_, p_77648_6_, net.minecraftforge.common.util.ForgeDirection.getOrientation(p_77648_7_))) { return false; } @@ -71,8 +76,11 @@ ++p_77648_4_; } + } + { if (!p_77648_3_.isRemote) { + if (!Blocks.skull.canPlaceBlockOnSide(p_77648_3_, p_77648_4_, p_77648_5_, p_77648_6_, p_77648_7_)) return false; p_77648_3_.setBlock(p_77648_4_, p_77648_5_, p_77648_6_, Blocks.skull, p_77648_7_, 2); int i1 = 0; diff --git a/src/main/java/net/minecraft/realms/RealmsConnect.java b/src/main/java/net/minecraft/realms/RealmsConnect.java index 086a29a..21bb6b1 100644 --- a/src/main/java/net/minecraft/realms/RealmsConnect.java +++ b/src/main/java/net/minecraft/realms/RealmsConnect.java @@ -40,6 +40,7 @@ try { + cpw.mods.fml.client.FMLClientHandler.instance().connectToRealmsServer(p_connect_1_, p_connect_2_); inetaddress = InetAddress.getByName(p_connect_1_); if (RealmsConnect.this.aborted) diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index 37b63a3..240a7b5 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -319,7 +319,7 @@ { ImageIO.setUseCache(false); //Disable on-disc stream cache should speed up texture pack reloading. PixelFormat format = new PixelFormat().withDepthBits(24); - if (!ForgeModContainer.enableStencilBits) + if (!ForgeModContainer.enableStencilBits || Boolean.parseBoolean(System.getProperty("forge.forceNoStencil", "false"))) { Display.create(format); stencilBits = 0; diff --git a/src/main/java/net/minecraftforge/common/ForgeChunkManager.java b/src/main/java/net/minecraftforge/common/ForgeChunkManager.java index 311c4cb..9cfc009 100644 --- a/src/main/java/net/minecraftforge/common/ForgeChunkManager.java +++ b/src/main/java/net/minecraftforge/common/ForgeChunkManager.java @@ -93,17 +93,17 @@ private static Configuration config; private static int playerTicketLength; private static int dormantChunkCacheSize; - + public static final List MOD_PROP_ORDER = new ArrayList(2); private static Set warnedMods = Sets.newHashSet(); - + static { MOD_PROP_ORDER.add("maximumTicketCount"); MOD_PROP_ORDER.add("maximumChunksPerTicket"); } - + /** * All mods requiring chunkloading need to implement this to handle the * re-registration of chunk tickets at world loading time @@ -833,6 +833,7 @@ forcedChunkData.setTag("TicketList", ticketList); Multimap ticketSet = tickets.get(worldServer); + if (ticketSet == null) return; for (String modId : ticketSet.keySet()) { NBTTagCompound ticketHolder = new NBTTagCompound(); @@ -943,7 +944,7 @@ } syncConfigDefaults(); } - + /** * Synchronizes the local fields with the values in the Configuration object. */ @@ -955,7 +956,7 @@ config.setCategoryComment("defaults", "Default configuration for forge chunk loading control") .setCategoryRequiresWorldRestart("defaults", true); - + Property temp = config.get("defaults", "enabled", true); temp.comment = "Are mod overrides enabled?"; temp.setLanguageKey("forge.configgui.enableModOverrides"); @@ -969,7 +970,7 @@ temp.setMinValue(0); defaultMaxChunks = temp.getInt(25); propOrder.add("maximumChunksPerTicket"); - + temp = config.get("defaults", "maximumTicketCount", 200); temp.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."; @@ -993,7 +994,7 @@ dormantChunkCacheSize = temp.getInt(0); propOrder.add("dormantChunkCacheSize"); FMLLog.info("Configured a dormant chunk cache size of %d", temp.getInt(0)); - + config.setCategoryPropertyOrder("defaults", propOrder); config.addCustomCategoryComment("Forge", "Sample mod specific control section.\n" + @@ -1014,23 +1015,23 @@ config.get(mod, "maximumTicketCount", 200).setLanguageKey("forge.configgui.maximumTicketCount").setMinValue(0); config.get(mod, "maximumChunksPerTicket", 25).setLanguageKey("forge.configgui.maximumChunksPerTicket").setMinValue(0); } - + if (config.hasChanged()) { config.save(); } } - + public static Configuration getConfig() { return config; } - + public static ConfigCategory getDefaultsCategory() { return config.getCategory("defaults"); } - + public static List getModCategories() { List list = new ArrayList(); diff --git a/src/main/java/net/minecraftforge/common/config/Configuration.java b/src/main/java/net/minecraftforge/common/config/Configuration.java index 03f46f6..3d88c38 100644 --- a/src/main/java/net/minecraftforge/common/config/Configuration.java +++ b/src/main/java/net/minecraftforge/common/config/Configuration.java @@ -93,6 +93,7 @@ public Configuration(File file, String configVersion) { this.file = file; + this.definedConfigVersion = configVersion; String basePath = ((File)(FMLInjectionData.data()[6])).getAbsolutePath().replace(File.separatorChar, '/').replace("/.", ""); String path = file.getAbsolutePath().replace(File.separatorChar, '/').replace("/./", "/").replace(basePath, ""); if (PARENT != null) @@ -1719,4 +1720,4 @@ { return file; } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/fml/lang/en_US.lang b/src/main/resources/assets/fml/lang/en_US.lang index 2274c18..09a4eb1 100644 --- a/src/main/resources/assets/fml/lang/en_US.lang +++ b/src/main/resources/assets/fml/lang/en_US.lang @@ -52,6 +52,10 @@ fml.config.sample.modIDSelector=Mod ID Selector fml.config.sample.patternString.tooltip=A string property that is validated using a Pattern object. fml.config.sample.patternString=Pattern Validated String +fml.config.sample.sliderDouble.tooltip=A double property with defined bounds using a slider control. +fml.config.sample.sliderDouble=Slider Double +fml.config.sample.sliderInteger.tooltip=An integer property with defined bounds using a slider control. +fml.config.sample.sliderInteger=Slider Integer fml.config.sample.stringList.tooltip=A basic string list with no validation. fml.config.sample.stringList=Basic String List fml.config.sample.stringListFixed.tooltip=A string list that has a fixed length of 7. diff --git a/src/main/resources/fmlversion.properties b/src/main/resources/fmlversion.properties index aa47058..ffef58b 100644 --- a/src/main/resources/fmlversion.properties +++ b/src/main/resources/fmlversion.properties @@ -1,6 +1,6 @@ fmlbuild.major.number=7 fmlbuild.minor.number=10 -fmlbuild.revision.number=11 -fmlbuild.build.number=58 +fmlbuild.revision.number=23 +fmlbuild.build.number=62 fmlbuild.mcversion=1.7.10 fmlbuild.mcpversion=9.05