コード例 #1
0
        /// <summary>
        /// Patches the given minecraft version and returns the new patched version.
        /// The patcher will create a new version directory and create a new jar file.
        /// The jar file is based on the original <paramref name="version"/>.
        /// The patcher will copy any assets from the orignal jar file.
        /// The content of the META-INF directory will not be copied.
        /// All classes will be analysed and scanned for a keyPressed method.
        /// The patcher will replace 0x110102 from the keyPressed methods.
        /// 0x11 (sipush) is the java bytecode instruction that loads the next two
        /// bytes as short value onto the stack. Where 0x0102 is the short value for
        /// 258 which is the minecraft keycode for tab. 0x0102 will be replaced with
        /// 0xFFFF which is an invalid keycode.
        /// </summary>
        /// <param name="version"></param>
        /// <param name="postfix"></param>
        /// <returns></returns>
        private static MinecraftVersion Patch(MinecraftVersion version, string postfix)
        {
            Console.WriteLine("Start pathching '{0}'...", version.ID);
            Console.WriteLine("------------------------------------------------------");

            // Creates a new version
            var parentPath = Path.GetDirectoryName(version.Path);

            // Searches for the next free directory.
            // Is this really necessary?
            var template = version.ID + "-" + postfix;
            var id       = template;
            var path     = Path.Combine(parentPath, id);
            var counter  = 1;

            while (Directory.Exists(path))
            {
                counter++;
                id   = template + counter;
                path = Path.Combine(parentPath, id);
            }

            Console.WriteLine("Creating patched version '{0}'...", id);

            // Creates the patched version
            var patchedVersion = new MinecraftVersion(path);

            // The copy buffer
            var buffer = new byte[1024 * 8];

            // Opens the java file
            using (var javaFile = version.OpenJavaFile())
            {
                // Creates the output file
                using (var output = new FileStream(patchedVersion.PathJar, FileMode.Create))
                {
                    // Creates the output zip stream
                    using (var outputZip = new ZipOutputStream(output))
                    {
                        // Do not use 64 bit zip
                        outputZip.UseZip64 = UseZip64.Off;

                        var files = javaFile.Zip.Count;
                        for (int i = 0; i < files; i++)
                        {
                            var entry = javaFile.Zip[i];


                            // Ignore the META-INF folder
                            if (entry.Name.Contains("META-INF/"))
                            {
                                continue;
                            }

                            // Creates the output entry file
                            var outputEntry = new ZipEntry(entry.Name);
                            outputEntry.DateTime = entry.DateTime;
                            outputEntry.Size     = entry.Size;
                            outputZip.PutNextEntry(outputEntry);

                            // This is a class file
                            if (Path.GetExtension(entry.Name) == ".class")
                            {
                                // Loads the class
                                var javaClass = javaFile.GetClass(entry);

                                // Gets the class info
                                var javaClassInfo = javaClass.GetConstant <JavaConstantClassInfo>(javaClass.ThisClass);
                                var javaClassName = javaClass.GetConstantUtf8(javaClassInfo.NameIndex);

                                // Gets the method
                                var javaMethod = javaClass.GetMethod("keyPressed");


                                if (javaMethod != null)
                                {
                                    // Gets the method info
                                    var javaMethodName       = javaClass.GetConstantUtf8(javaMethod.NameIndex);
                                    var javaMethodDescriptor = javaClass.GetConstantUtf8(javaMethod.DescriptorIndex);

                                    // Gets the code attribute of the method
                                    var javaCodeAttribute = javaMethod.GetCodeAttribute();
                                    if (javaCodeAttribute != null)
                                    {
                                        var code  = javaCodeAttribute.Code;
                                        var index = 0;
                                        while ((index = Utils.BinaryIndexOf(code, OrginalCode, index)) >= 0)
                                        {
                                            Console.WriteLine("Patching bytecode from '{0}.{1}{2}' at position {3}...", javaClassName, javaMethodName, javaMethodDescriptor, index);

                                            // Change the code
                                            code[index + 1] = 0xFF;
                                            code[index + 2] = 0xFF;


                                            index++;
                                        }
                                    }
                                }

                                // Writes the class
                                javaClass.Write(outputZip);
                            }
                            else
                            {
                                // Just copy the file
                                using (var inputStream = javaFile.GetFileStream(entry))
                                {
                                    StreamUtils.Copy(inputStream, outputZip, buffer);
                                }
                            }
                        }
                    }
                }
            }

            Console.WriteLine("Creating json file...");

            // Creates the json file
            var patchedInfo = new MinecraftVersionInfo()
            {
                ID                     = id,
                InheritsFrom           = version.ID,
                Type                   = "custom",
                MainClass              = "net.minecraft.client.main.Main",
                MinimumLauncherVersion = 21,
            };

            // Write the version json
            patchedVersion.WriteJsonFile(patchedInfo);

            Console.WriteLine("Version got patched!");

            return(patchedVersion);
        }