IC Instance Restore on Ctrl + Z

Undo a craft with Ctrl + Z and redo with Ctrl + Y

目前为 2024-12-23 提交的版本,查看 最新版本

// ==UserScript==
// @name         IC Instance Restore on Ctrl + Z
// @namespace    http://tampermonkey.net/
// @version      1.6.2
// @license      MIT
// @description  Undo a craft with Ctrl + Z and redo with Ctrl + Y
// @icon         https://i.imgur.com/WlkWOkU.png
// @author       @activetutorial on discord
// @match        https://neal.fun/infinite-craft/
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    window.controlzdata = {
        ingredientInstances: {
            deletedInstances: [],
            InstanceIds: []
        },
        resultInstances: {
            deletedInstances: [],
            InstanceIds: []
        },
        infinitecraft: null,

        updateIds: function (oldId, newId) { // To fix the bug that I could't explain
            const replaceId = (list) => {
                for (let pair of list) {
                    const index = pair.indexOf(oldId);
                    if (index !== -1) {
                        pair[index] = newId;
                    }
                }
            };

            replaceId(this.resultInstances.InstanceIds);
            replaceId(this.ingredientInstances.InstanceIds);
        },

        deleteInstance: function (id) {
            const instances = this.infinitecraft.instances;
            const index = instances.findIndex(instance => instance.id === id);

            if (index !== -1) {
                const deletedInstance = { ...instances[index] };
                instances.splice(index, 1);
                return deletedInstance; // Return deleted instance
            }
            return null;
        },

        makeInstance: function (instanceCopy) {
            instanceCopy.left -= 10; // Move it in the oppisite direction that duplicateInstance does
            instanceCopy.top += 10;
            this.infinitecraft.duplicateInstance(instanceCopy);
            const newInstance = this.infinitecraft.instances.at(-1);

            if (newInstance) {
                this.updateIds(instanceCopy.id, newInstance.id);
            }

            return newInstance ? newInstance.id : null; // Return id of recreated instance
        },

        restoreInstances: function () {
            if (this.ingredientInstances.deletedInstances.length > 0) {
                const instancePair = this.ingredientInstances.deletedInstances.pop();
                const [instanceA, instanceB] = instancePair;

                const instanceAId = this.makeInstance(instanceA); // Reinstate ingredients
                const instanceBId = this.makeInstance(instanceB);

                if (instanceAId && instanceBId) {
                    this.ingredientInstances.InstanceIds.push([instanceAId, instanceBId]);
                }

                const resultInstanceId = this.resultInstances.InstanceIds.pop()?.[0];
                if (resultInstanceId) {
                    const deletedInstance = this.deleteInstance(resultInstanceId); // Delete result instance
                    if (deletedInstance) {
                        this.resultInstances.deletedInstances.push(deletedInstance);
                    }
                }
            }
        },

        unrestoreInstances: function () {
            if (this.ingredientInstances.InstanceIds.length > 0) {
                const lastRestoredIds = this.ingredientInstances.InstanceIds.pop();
                const [instanceAId, instanceBId] = lastRestoredIds;

                const instanceA = this.deleteInstance(instanceAId); // Delete ingredient instances
                const instanceB = this.deleteInstance(instanceBId);

                if (instanceA && instanceB) {
                    this.ingredientInstances.deletedInstances.push([instanceA, instanceB]);
                }

                if (this.resultInstances.deletedInstances.length > 0) {
                    const deletedInstance = this.resultInstances.deletedInstances.pop();
                    const newInstanceId = this.makeInstance(deletedInstance); // Make result instances
                    if (newInstanceId) {
                        this.resultInstances.InstanceIds.push([newInstanceId]);
                    }
                }
            }
        }
    };

    function start() {
        if (window.$nuxt && window.$nuxt.$root && window.$nuxt.$root.$children[1] && window.$nuxt.$root.$children[1].$children[0]) { // Wait for Nuxt

            window.controlzdata.infinitecraft = window.$nuxt.$root.$children[1].$children[0].$children[0]; // Assign Infinite Craft
            const ogGCR = window.controlzdata.infinitecraft.getCraftResponse;
            window.controlzdata.infinitecraft.getCraftResponse = async function (instanceA, instanceB) { // Patch getCraftResponse to intercept and save stuff
                const response = await ogGCR.apply(this, arguments);

                if (instanceA.elem && instanceB.elem) { // Used to detect if it's used through GUI or console
                    window.controlzdata.ingredientInstances.deletedInstances.push([{ ...instanceA }, { ...instanceB }]);
                    window.controlzdata.resultInstances.InstanceIds.push([this.instanceId += 2]);
                    window.controlzdata.resultInstances.deletedInstances = [];
                    window.controlzdata.ingredientInstances.InstanceIds = [];
                }

                return response;
            };

            document.addEventListener("keydown", function (event) { // To make the script acctually do something
                if (event.ctrlKey && event.key === "z") {
                    window.controlzdata.restoreInstances();
                }
                if (event.ctrlKey && event.key === "y") {
                    window.controlzdata.unrestoreInstances();
                }
            });
        } else {
            setTimeout(start, 2000); // Change the timeout if it still conflicts with outher scripts
        }
    }

    start();
})();