MCP :: SRG Mapper

Apply SRG mappings to code.

/*jslint devel: true, browser: true, regexp: true, continue: true, plusplus: true, maxerr: 50, indent: 4 */
/*global unsafeWindow: false, $: false, toastr: false, JSZip: false */
/*global GM_setValue: false, GM_getValue: false, GM_listValues: false, GM_deleteValue: false, GM_addStyle: false, GM_getResourceText: false, GM_xmlhttpRequest: false */

// ==UserScript==
// @name           MCP :: SRG Mapper
// @namespace      Lunatrius
// @description    Apply SRG mappings to code.
// @author         Lunatrius <[email protected]>
// @include        https://github.com/MinecraftForge/FML*
// @include        https://github.com/MinecraftForge/MinecraftForge*
// @include        https://github.com/MinecraftForge/FML/pull/*/files
// @include        https://github.com/MinecraftForge/MinecraftForge/pull/*/files
// @include        https://gist.github.com/*/*
// @include        http://openeye.openmods.info/crashes/*
// @include        https://paste.ee/*
// @include        http://paste.ee/*
// @include        http://paste.feed-the-beast.com/view/*
// @include        http://pastebin.com/*
// @exclude        https://paste.ee/
// @exclude        http://paste.ee/
// @exclude        http://pastebin.com/
// @require        https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
// @require        https://cdnjs.cloudflare.com/ajax/libs/jquery.pjax/1.9.2/jquery.pjax.min.js
// @require        https://cdnjs.cloudflare.com/ajax/libs/jszip/2.4.0/jszip.min.js
// @require        https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.0/js/toastr.min.js
// @require        https://cdnjs.cloudflare.com/ajax/libs/chosen/1.1.0/chosen.jquery.min.js
// @resource       toast_css https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.0/css/toastr.css
// @resource       chosen_css https://cdnjs.cloudflare.com/ajax/libs/chosen/1.1.0/chosen.css
// @version        0.1.11
// @grant          GM_setValue
// @grant          GM_getValue
// @grant          GM_listValues
// @grant          GM_deleteValue
// @grant          GM_addStyle
// @grant          GM_getResourceText
// @grant          GM_xmlhttpRequest
// @grant          unsafeWindow
// @license        MIT
// ==/UserScript==

(function (window) {
    "use strict";

    try {
        if (window !== window.top) {
            return;
        }

        $.fn.outerHtml = function () {
            return $("<tmp></tmp>").append(this).html();
        };

        var mapper = {
            baseList: "http://export.mcpbot.bspk.rs/",
            baseMapping: "http://files.minecraftforge.net/maven/de/oceanlabs/mcp/",
            regexParse: /(func_[0-9]+_[a-z]+_?|field_[0-9]+_[a-z]+_?|p_i?[0-9]+_[0-9]+_?),([^,]+),/i,
            regexReplace: /\b(?:func_[0-9]+_[a-z]+_?|field_[0-9]+_[a-z]+_?|p_i?[0-9]+_[0-9]+_?)\b/gi,

            regexMapping: /^(\d+(?:\.\d+)+):((stable)(?:_nodoc)?_(\d+)|(snapshot)(?:_nodoc)?_(\d{8}))$/,

            mappingList: [],
            currentMapping: null,
            mappings: {},

            updateIntervalList: 1000 * 3600 * 12,
            updateIntervalMapping: 1000 * 3600 * 24 * 365,

            settings: {
                "github.com": {
                    tag: "li",
                    insert: "div.container ul.pagehead-actions",
                    container: "#files table tr td.blob-code, .file .type-diff table tr td.blob-code, .inline-review-comment table tr td.blob-code"
                },
                "gist.github.com": {
                    tag: "li",
                    insert: "div.container>ul.pagehead-actions",
                    container: "div.file>div.data table tr td.blob-code"
                },
                "openeye.openmods.info": {
                    tag: "div",
                    insert: "div.page-header",
                    container: "span.highlight_method",
                    css: [
                        "#remap_container { float: right; }",
                        "#remap_container a.minibutton { padding: 3px; border: 1px outset #DDDDDD; border-radius: 4px; cursor: pointer; }",
                        "#remap_container a.minibutton.selected { padding: 3px; border: 1px inset #DDDDDD; border-radius: 4px; cursor: pointer; }"
                    ].join("\n")
                },
                "paste.ee": {
                    tag: "span",
                    insert: ".container>.row>.row>.col-sm-12:has(#download)",
                    container: "#paste-content ol li div",
                    css: [
                        "#remap_container { float: right; }",
                        "#remap_container a.minibutton { padding: 3px; border: 1px outset #DDDDDD; border-radius: 4px; cursor: pointer; }",
                        "#remap_container a.minibutton.selected { padding: 3px; border: 1px inset #DDDDDD; border-radius: 4px; cursor: pointer; }"
                    ].join("\n")
                },
                "paste.feed-the-beast.com": {
                    tag: "span",
                    insert: "div.col-lg-12>div.detail.by:eq(0)",
                    container: ".CodeMirror ol li div",
                    css: [
                        "#remap_container { float: right; }",
                        "#remap_container a.minibutton { padding: 3px; border: 1px outset #DDDDDD; border-radius: 4px; cursor: pointer; }",
                        "#remap_container a.minibutton.selected { padding: 3px; border: 1px inset #DDDDDD; border-radius: 4px; cursor: pointer; }"
                    ].join("\n")
                },
                "pastebin.com": {
                    tag: "span",
                    insert: "#code_frame #code_buttons",
                    container: "#code_frame ol li span, #code_frame ol li div",
                    css: [
                        "#remap_container { float: right; margin-top: 4pt; }",
                        "#remap_container a.minibutton { padding: 3px; border: 1px outset #DDDDDD; border-radius: 4px; cursor: pointer; }",
                        "#remap_container a.minibutton.selected { padding: 3px; border: 1px inset #DDDDDD; border-radius: 4px; cursor: pointer; }"
                    ].join("\n")
                }
            },

            setCurrentMapping: function (mc, type, version) {
                if (type === undefined && version === undefined) {
                    var mapping = this.parseMapping(mc);
                    this.currentMapping = mapping[0] ? mapping[0] + ":" + mapping[1] + "_" + mapping[2] : null;
                } else {
                    this.currentMapping = mc + ":" + type + "_" + version;
                }

                return this.currentMapping;
            },

            parseMapping: function (mapping) {
                var m = mapping && mapping.match(/^(\d+(?:\.\d+)+):((stable)(?:_nodoc)?_(\d+)|(snapshot)(?:_nodoc)?_(\d{8}))$/);
                return m ? [m[1], m[3] || m[5], m[4] || m[6]] : [null, null, null];
            },

            set: function (key, val) {
                GM_setValue(key, JSON.stringify(val));
            },

            get: function (key, def) {
                try {
                    return JSON.parse(GM_getValue(key, def)) || def;
                } catch (ignore) {}
                return def;
            },

            list: function () {
                return GM_listValues();
            },

            del: function (key) {
                GM_deleteValue(key);
            },

            clean: function () {
                $.each(this.list(), function (index, value) {
                    this.del(value);
                }.bind(this));
            },

            time: function () {
                return new Date().getTime();
            },

            init: function () {
                var css = [
                    GM_getResourceText("toast_css"),
                    GM_getResourceText("chosen_css")
                ];

                this.settings = this.settings[location.host];
                if (!this.settings) {
                    GM_addStyle(css.join("\n"));
                    toastr.info("No settings for " + location.host + "... :(");
                    return this;
                }

                if (this.settings.css) {
                    css = css.concat(this.settings.css);
                }

                GM_addStyle(css.join("\n"));

                toastr.options.closeButton = true;
                toastr.options.showMethod = "slideDown";
                toastr.options.hideMethod = "slideUp";
                toastr.options.preventDuplicates = true;

                this.setCurrentMapping(this.get("selected", ""));

                this.mappingList = this.get("mappings", []);

                try {
                    var match = $("body").text().match(/(?:Minecraft|Minecraft Version:) (\d+\.\d+(?:\.\d+)?)/);
                    if (match) {
                        var split = this.currentMapping.split(/:/);

                        if (match[1] !== split[0]) {
                            var found = false;
                            $.each(this.mappingList, function (index, version) {
                                var split = version.split(/:/);
                                if (match[1] === split[0]) {
                                    found = version;
                                    return false;
                                }
                            });

                            if (found !== false) {
                                toastr.info("Switching mappings to " + found);
                                this.setCurrentMapping(found);
                                this.set("selected", this.currentMapping);
                            } else {
                                toastr.warning("Detected Minecraft " + match[1] + " but no mappings available!");
                            }
                        }
                    }
                } catch (ignore) {}

                $.each(this.list(), function (index, version) {
                    if (this.regexMapping.test(version) && $.inArray(version, this.mappingList) === -1) {
                        toastr.warning("Removing old mappings...<br/>" + version);
                        this.del(version);
                        this.del(version + "_update");
                    }
                }.bind(this));

                try {
                    this.main();
                } catch (e) {
                    console.log(e);
                }

                delete this.init;

                return this;
            },

            main: function () {
                this.update();

                $("<" + this.settings.tag + ">")
                    .attr("id", "remap_container")
                    .append($("<select></select>").change(this.changeMapping.bind(this)))
                    .append(" ")
                    .append($("<a></a>").addClass("minibutton btn btn-sm").text("Remap").click(this.remap.bind(this)))
                    .prependTo(this.settings.insert);

                this.populateMappings();
            },

            update: function () {
                if (this.get("mappings_update", 0) + this.updateIntervalList < this.time()) {
                    toastr.info("Fetching mapping list...");
                    this.query(this.baseList + "versions.json?limit=5", this.saveMappingList.bind(this), this.updateMapping.bind(this));
                    return true;
                } else {
                    return this.updateMapping();
                }
            },

            updateMapping: function () {
                if (this.setCurrentMapping(this.currentMapping) !== null) {
                    if (this.get(this.currentMapping + "_update", 0) + this.updateIntervalMapping < this.time()) {
                        toastr.info("Fetching mappings: " + this.currentMapping);
                        var mapping = this.parseMapping(this.currentMapping);
                        this.query(this.mappingUrl(mapping[0], mapping[1], mapping[2]), this.saveMappings.bind(this), function () {
                            $(this.settings.container).each(this.doRemap.bind(this));
                        }.bind(this));
                        return true;
                    } else {
                        this.mappings = this.get(this.currentMapping, []);
                        return false;
                    }
                } else {
                    toastr.info("No mappings selected.");
                }
                return false;
            },

            changeMapping: function (event) {
                this.setCurrentMapping($(event.target).val());
                this.set("selected", this.currentMapping);
            },

            remap: function (event) {
                var target = $(event.target);

                if (target.hasClass("selected")) {
                    target.removeClass("selected");

                    $(".processed").removeClass("processed").find("u[title]").each(this.undoRemap);
                } else {
                    target.addClass("selected");

                    this.setCurrentMapping($("#remap_container select").val());
                    this.mappings = this.get(this.currentMapping, []);

                    if (!this.update()) {
                        $(this.settings.container).each(this.doRemap.bind(this));
                    }
                }

                $("#remap_container .chosen-container").css("z-index", 9001).css("display", target.hasClass("selected") ? "none" : "");
            },

            undoRemap: function (index, node) {
                $(node).replaceWith($(node).attr("title"));
            },

            doRemap: function (index, node) {
                node = $(node);
                if (!node.hasClass("processed")) {
                    var html = node.html();
                    if (this.regexReplace.test(html)) {
                        node.html(html.replace(this.regexReplace, this.applyRemap.bind(this))).addClass("processed");
                    }
                }
            },

            applyRemap: function (token) {
                var mcpname, node;

                mcpname = this.mappings[token];
                node = $("<u></u>").attr("title", token);

                if (!mcpname) {
                    node.css("font-style", "italic");
                }

                return node.text(mcpname || token).outerHtml();
            },

            populateMappings: function () {
                $("#remap_container select").html("");
                this.mappingList.sort(this.cmpMapping.bind(this));
                $.each(this.mappingList, function (index, version) {
                    $("<option></option>").val(version).text(version).appendTo("#remap_container select");
                });
                $("#remap_container select").val(this.currentMapping).chosen();
            },

            cmpMapping: function (a, b) {
                a = a.split(/[:_]/i);
                b = b.split(/[:_]/i);

                if (a[0] != b[0]) {
                    return this.cmpVersion(a[0], b[0]);
                }

                if (a[1] != b[1]) {
                    return a[1] < b[1];
                }

                if (a[2] != b[2]) {
                    return a[2] < b[2];
                }

                return 0;
            },

            cmpVersion: function (a, b) {
                a = a.split(/\./gi);
                b = b.split(/\./gi);

                for (var i = 0 ; i < a.length && i < b.length; i++) {
                    if (a[i] !== b[i]) {
                        return parseInt(a[i]) < parseInt(b[i]);
                    }
                }

                return a.length < b.length;
            },

            saveMappingList: function (data, callback) {
                var json = JSON.parse(data);
                this.mappingList = [];

                $.each(json, function (mc, data) {
                    $.each(data, function (type, versions) {
                        $.each(versions, function (index, version) {
                            this.mappingList.push(mc + ":" + type + "_" + version);
                        }.bind(this));
                    }.bind(this));
                }.bind(this));

                this.set("mappings", this.mappingList);
                this.set("mappings_update", this.time());

                toastr.success("Saved mapping list.");

                this.populateMappings();

                if (callback) {
                    callback();
                }
            },

            mappingUrl: function (mc, type, version) {
                return this.baseMapping + "mcp_" + type + "_nodoc/" + version + "-" + mc + "/mcp_" + type + "_nodoc-" + version + "-" + mc + ".zip";
            },

            saveMappings: function (data, callback) {
                var zip, parse;

                zip = JSZip(data);

                parse = function (index, line) {
                    var m = line.match(this.regexParse);
                    if (m && m.length === 3) {
                        this.mappings[m[1]] = m[2];
                    }
                };

                this.mappings = {};
                $.each(zip.file("methods.csv").asText().split("\n"), parse.bind(this));
                $.each(zip.file("fields.csv").asText().split("\n"), parse.bind(this));
                $.each(zip.file("params.csv").asText().split("\n"), parse.bind(this));

                this.set(this.currentMapping, this.mappings);
                this.set(this.currentMapping + "_update", this.time());

                toastr.success("Saved mappings.");

                if (callback) {
                    callback();
                }
            },

            query: function (url, callback, innerCallback) {
                GM_xmlhttpRequest({
                    url: url,
                    method: "GET",
                    // should work but doesn't...
                    // responseType: "arraybuffer",
                    overrideMimeType: "text/plain; charset=x-user-defined",
                    onload: function (response) {
                        try {
                            callback(response.response, innerCallback);
                        } catch (e) {
                            toastr.error("Something went wrong!<br/>" + e.message);
                        }
                    }.bind(this)
                });
            }
        }.init();
    } catch (e) {
        toastr.error("Something went wrong!<br/>" + e.message + "<br/>" + e.fileName.replace(/^.*[\\\/]/, "") + ":" + e.lineNumber);
        console.error(e);
    }
}(unsafeWindow));

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址