League-of-Foundry-Developers / foundryvtt-devMode

A module with some tools to help enable Foundry VTT package developers.
MIT License
12 stars 15 forks source link

LibWrapperPackageError in FVTT 11 #57

Open trdischat opened 1 year ago

trdischat commented 1 year ago

Environment Details

Describe the bug Enabling libWrapper and dev-mode triggers this error:

image

To Reproduce Enabled both the libWrapper and Developer Mode modules and reload the world.

Expected behavior No error.

trdischat commented 1 year ago

The same error is still present in Foundry Version 11 Stable, Build 300, using the DnD5e System Version 2.2.1. Has this module been abandoned?

Eunomiac commented 1 year ago

There's an easy fix you can implement yourself by editing your ../modules/_dev-mode/foundryvtt-devMode.mjs file:

Go to line 48, and comment out (or delete) these six lines of code:

libWrapper.register(
  DevMode.MODULE_ID,
  'Game.prototype._displayUsabilityErrors',
  _devModeDisplayUsabilityErrors,
  'MIXED',
);

Since this isn't being updated, you shouldn't have to worry about an update overwriting your changes ... until it is updated, in which case, hooray!

While I'm here: To remove the isObjectEmpty() deprecation warning from your console, open up module\_dev-mode\module\classes\DevMode.mjs and change line 203 (with the isObjectEmpty() call) to the following:

if (Object.keys(compatibilityWarnings).length === 0 || !CONFIG.compatibility) return;
trdischat commented 1 year ago

Thanks, @Eunomiac for the fix. Does it make sense to make this into a PR, or is this module already at risk of abandonment?

Eunomiac commented 1 year ago

@trdischat It really does make sense to make this a pull request, but I ... uh ... couldn't remember how to do it and gave up after a few false starts :) If your git-fu is superior to mine, please go ahead and make that PR with my code if you like!

Eunomiac commented 10 months ago

I've finally managed to re-enable the "suppress screen resolution notice" feature, and expanded it so that you can customize any other notifications you wish to suppress.

To enable this in your own workspace, copy the code below and paste it into ../modules/_dev-mode/foundryvtt-devMode.mjs at line 13, immediately after the imports (after making any changes you wish to the strings used to identify notifications to suppress, right at the bottom):

/**
 * This function applies a style to the <head> element to hide notifications in the UI
 * that have been intercepted by the `InitNotificationsProxy` function.
 *
 * This function should be run during the "init" Hook call.
 */
function ApplyHideNotificationStyles() {
    // Create a style element to hide intercepted notifications in the UI.
    const style = document.createElement("style");
    style.textContent = "#notifications .do-not-display { visibility: hidden; }";
    // Append it to the <head> element
    document.head.appendChild(style);
}

/**
 * This function initializes a Proxy to intercept changes to the `ui.notifications.queue` array.
 * It accepts an array of strings to match against any notification that would be added to the queue.
 * If a notification matches, the Proxy will modify it to prevent it from logging anything to the
 *  console, and to hide it in the UI.
 *
 * This function should be run during the "ready" Hook call.
 */
function InitNotificationsProxy(patternsToHide = []) {
    // Do nothing if no patterns are provided.
    if (!patternsToHide.length) { return; }

    // Get the original array of queued notifications, and store a constant reference to it
    const notificationQueue = ui.notifications.queue;

    // Convert the provided patterns into regular expressions
    const regExpPatterns = patternsToHide.map((pattern) => new RegExp(pattern));

    // Define a handler for the proxy that will be used to intercept notifications
    const handler = {
        set: function (target, property, value) {
            // Handle changes to the array length property
            if (property === "length") {
                // Perform the default behavior for length changes
                target.length = value;
                return true; // Indicate success
            }
            // Handle directly setting the value for non-index properties (necessary for array methods like 'next')
            else if (typeof property === "string" && isNaN(Number(property))) {
                // Perform the default behavior for non-index properties.
                target[property] = value;
                return true; // Indicate success
            }
            // Handle setting array indices
            else if (!isNaN(Number(property))) {
                // If the value is a notification and its content matches one of the provided patterns ...
                if (value
                    && typeof value === "object"
                    && "message" in value
                    && typeof value.message === "string"
                    && regExpPatterns.some((pattern) => pattern.exec(value.message))) {
                    // ... edit the notification to:
                    Object.assign(value, {
                        console: false, // ... prevent logging it to the console
                        permanent: false, // ... ensure the notification element is removed automatically
                        type: "do-not-display" // ... 'hack' the type to add the 'do-not-display' class
                    });
                }
                // Otherwise, perform the default behavior for setting index properties.
                target[Number(property)] = value;
                return true; // Indicate success
            }
            return false; // Indicate failure for all other cases
        }
    };

    // Replace the notifications queue array with a Proxy defined by the above handler.
    ui.notifications.queue = new Proxy(notificationQueue, handler);
}

// Apply the <style> element that will hide the UI notification during the 'init' hook
Hooks.once("init", ApplyHideNotificationStyles);

// Initialize the notifications proxy during the 'ready' hook, after ui.notifications has been defined
Hooks.once("ready", () => {
    // I've hard-coded the two notifications I want to hide, but this could easily be a
    //   user setting, allowing users to customize which notifications are silenced.
    InitNotificationsProxy([
        "Foundry Virtual Tabletop requires a minimum screen resolution",
        "not displayed because the game Canvas is disabled"
    ]);
});