olegbl / d2rmm

Mod Manager for Diablo II: Resurrected
https://www.nexusmods.com/diablo2resurrected/mods/169
MIT License
63 stars 13 forks source link

Make global scope available #10

Closed Caedendi closed 1 year ago

Caedendi commented 1 year ago

Hi,

Currently the global scope is not available in mod.js so we can't use Object,keys. I was wondering if there was some way for you to make this scope available, or explain why this is not possible.

I have run into multiple issues where the answer seems to be "use Object.keys", which I eventually have been able to circumvent each time. This time however, I want to extend Array but this leads to circular dependencies issues. I don't really know how the global scope works and how this is related, but I'd like to use the full feature pack of javascript so I can just use the stuff people on Stack Overflow recommend.


Example using extends:

class AwesomeArray extends Array {
  something() {
    this.push("something");
  }
}

Error: [mod] encountered a runtime error! TypeError: Class extends value undefined is not a constructor or null at 1:51


Example using prototype:

Array.prototype.something = function(x) {
  this.push(x);
}

Error: [mod] encountered a runtime error! TypeError: Cannot read properties of undefined (reading 'prototype') at 1:30


I also want to be able to import files/classes so I can split up mod.js into parts. Is that possible?

olegbl commented 1 year ago

Please see the Mod API section in https://www.nexusmods.com/diablo2resurrected/mods/169:

Note: The JavaScript inside this file is run without access to the global scope. (e.g. You’ll need to use for/in instead of Object.keys since Object is not available). The Math API is exposed for you, however.

To elaborate, this is to prevent mods from messing with other mods by overriding global scope functionality (intentionally or not).

For example, you may override the array's filter method on the prototype in a way that breaks another mod, and that's super hard for a user to debug because it looks like the other mod is broken.

There are pretty much no use cases that are blocked by this, however. For example:

class AwesomeArray {
  constructor(realArray) {
    this.realArray = realArray;
  }
  something() {
    this.realArray.push('something');
  }
}
const arr = [1,2,3];
const awesomeArr = new AwesomeArray(arr);
awesomeArr.something();

I also want to be able to import files/classes so I can split up mod.js into parts. Is that possible?

You can certainly do that in your work environment, so long as you run some build step that packages everything up into one mod.js before giving it to D2RMM. Similarly, you could use TypeScript or FlowLang instead of JS, and just compile it.

olegbl commented 1 year ago

Did some work to sandbox mods better (in isolated VMs) (https://github.com/olegbl/d2rmm/commit/8d7cae8a10c743820af2eae670f8c8da8b22f816), so it will no longer require removing global scope. Version 1.5.0 will have this fixed.