ScriptManager

Manage and download CustomNPCs scripts ingame!

// ==UserScript==
// @namespace          runonstof
// @name               ScriptManager
// @version            1.0.3
// @description        Manage and download CustomNPCs scripts ingame!
// @author             Runonstof
// @license            MIT
// @minecraft          1.20.1
// @match              https://customnpcs.com
// ==/UserScript==

function _arrayLikeToArray(r, a) {
  (null == a || a > r.length) && (a = r.length);
  for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
  return n;
}
function _arrayWithHoles(r) {
  if (Array.isArray(r)) return r;
}
function _assertThisInitialized(e) {
  if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  return e;
}
function _callSuper(t, o, e) {
  return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
}
function _classCallCheck(a, n) {
  if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
}
function _construct(t, e, r) {
  if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
  var o = [null];
  o.push.apply(o, e);
  var p = new (t.bind.apply(t, o))();
  return r && _setPrototypeOf(p, r.prototype), p;
}
function _defineProperties(e, r) {
  for (var t = 0; t < r.length; t++) {
    var o = r[t];
    o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
  }
}
function _createClass(e, r, t) {
  return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
    writable: !1
  }), e;
}
function _defineProperty(e, r, t) {
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
    value: t,
    enumerable: !0,
    configurable: !0,
    writable: !0
  }) : e[r] = t, e;
}
function _getPrototypeOf(t) {
  return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
    return t.__proto__ || Object.getPrototypeOf(t);
  }, _getPrototypeOf(t);
}
function _inherits(t, e) {
  if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
  t.prototype = Object.create(e && e.prototype, {
    constructor: {
      value: t,
      writable: !0,
      configurable: !0
    }
  }), Object.defineProperty(t, "prototype", {
    writable: !1
  }), e && _setPrototypeOf(t, e);
}
function _isNativeFunction(t) {
  try {
    return -1 !== Function.toString.call(t).indexOf("[native code]");
  } catch (n) {
    return "function" == typeof t;
  }
}
function _isNativeReflectConstruct() {
  try {
    var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
  } catch (t) {}
  return (_isNativeReflectConstruct = function () {
    return !!t;
  })();
}
function _iterableToArrayLimit(r, l) {
  var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
  if (null != t) {
    var e,
      n,
      i,
      u,
      a = [],
      f = !0,
      o = !1;
    try {
      if (i = (t = t.call(r)).next, 0 === l) {
        if (Object(t) !== t) return;
        f = !1;
      } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
    } catch (r) {
      o = !0, n = r;
    } finally {
      try {
        if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
      } finally {
        if (o) throw n;
      }
    }
    return a;
  }
}
function _nonIterableRest() {
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function ownKeys(e, r) {
  var t = Object.keys(e);
  if (Object.getOwnPropertySymbols) {
    var o = Object.getOwnPropertySymbols(e);
    r && (o = o.filter(function (r) {
      return Object.getOwnPropertyDescriptor(e, r).enumerable;
    })), t.push.apply(t, o);
  }
  return t;
}
function _objectSpread2(e) {
  for (var r = 1; r < arguments.length; r++) {
    var t = null != arguments[r] ? arguments[r] : {};
    r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
      _defineProperty(e, r, t[r]);
    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
      Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
    });
  }
  return e;
}
function _objectWithoutProperties(e, t) {
  if (null == e) return {};
  var o,
    r,
    i = _objectWithoutPropertiesLoose(e, t);
  if (Object.getOwnPropertySymbols) {
    var n = Object.getOwnPropertySymbols(e);
    for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
  }
  return i;
}
function _objectWithoutPropertiesLoose(r, e) {
  if (null == r) return {};
  var t = {};
  for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
    if (-1 !== e.indexOf(n)) continue;
    t[n] = r[n];
  }
  return t;
}
function _possibleConstructorReturn(t, e) {
  if (e && ("object" == typeof e || "function" == typeof e)) return e;
  if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
  return _assertThisInitialized(t);
}
function _setPrototypeOf(t, e) {
  return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
    return t.__proto__ = e, t;
  }, _setPrototypeOf(t, e);
}
function _slicedToArray(r, e) {
  return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
}
function _toPrimitive(t, r) {
  if ("object" != typeof t || !t) return t;
  var e = t[Symbol.toPrimitive];
  if (void 0 !== e) {
    var i = e.call(t, r || "default");
    if ("object" != typeof i) return i;
    throw new TypeError("@@toPrimitive must return a primitive value.");
  }
  return ("string" === r ? String : Number)(t);
}
function _toPropertyKey(t) {
  var i = _toPrimitive(t, "string");
  return "symbol" == typeof i ? i : i + "";
}
function _typeof(o) {
  "@babel/helpers - typeof";

  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
    return typeof o;
  } : function (o) {
    return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
  }, _typeof(o);
}
function _unsupportedIterableToArray(r, a) {
  if (r) {
    if ("string" == typeof r) return _arrayLikeToArray(r, a);
    var t = {}.toString.call(r).slice(8, -1);
    return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
  }
}
function _wrapNativeSuper(t) {
  var r = "function" == typeof Map ? new Map() : void 0;
  return _wrapNativeSuper = function (t) {
    if (null === t || !_isNativeFunction(t)) return t;
    if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function");
    if (void 0 !== r) {
      if (r.has(t)) return r.get(t);
      r.set(t, Wrapper);
    }
    function Wrapper() {
      return _construct(t, arguments, _getPrototypeOf(this).constructor);
    }
    return Wrapper.prototype = Object.create(t.prototype, {
      constructor: {
        value: Wrapper,
        enumerable: !1,
        writable: !0,
        configurable: !0
      }
    }), _setPrototypeOf(Wrapper, t);
  }, _wrapNativeSuper(t);
}

if (!Array.from) {
  Object.defineProperty(Array, 'from', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function value(arrayLike) {
      if (arrayLike == null) {
        throw new TypeError('Array.from requires an array-like object - not null or undefined');
      }

      // Handle array-like objects
      var len = arrayLike.length >>> 0;
      var result = new Array(len);
      for (var i = 0; i < len; i++) {
        result[i] = arrayLike[i];
      }
      return result;
    }
  });
}
if (!Array.prototype.flat) {
  Object.defineProperty(Array.prototype, 'flat', {
    value: function value(depth) {

      var array = this;
      var maxDepth = depth === Infinity ? Number.MAX_SAFE_INTEGER : parseInt((depth === null || depth === void 0 ? void 0 : depth.toString()) || '1', 10) || 1;
      var currentDepth = 0;

      // It's not an array or it's an empty array, return the object.
      if (!Array.isArray(array) || !array.length) {
        return array;
      }

      // If the first element is itself an array and we're not at maxDepth,
      // flatten it with a recursive call first.
      // If the first element is not an array, an array with just that element IS the
      // flattened representation.
      // **Edge case**: If the first element is an empty element/an "array hole", skip it.
      // (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat#Examples)
      var firstElemFlattened = Array.isArray(array[0]) && currentDepth < maxDepth ? array[0].flat(maxDepth - 1) : array[0] === undefined ? [] : [array[0]];
      return firstElemFlattened.concat(array.slice(1).flat(maxDepth - 1));
    },
    enumerable: false,
    configurable: true,
    writable: true
  });
}
if (!String.prototype.includes) {
  Object.defineProperty(String.prototype, 'includes', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function value(search, start) {
      if (typeof start !== 'number') {
        start = 0;
      }
      if (start + search.length > this.length) {
        return false;
      }
      return this.indexOf(search, start) !== -1;
    }
  });
}
if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function value(target) {
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }
      var to = Object(target);
      for (var i = 0; i < (arguments.length <= 1 ? 0 : arguments.length - 1); i++) {
        var nextSource = i + 1 < 1 || arguments.length <= i + 1 ? undefined : arguments[i + 1];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        var keysArray = Object.keys(Object(nextSource));
        for (var nextIndex = 0; nextIndex < keysArray.length; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
if (!Object.entries) {
  Object.defineProperty(Object, 'entries', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function value(obj) {
      var ownProps = Object.keys(obj);
      var i = ownProps.length;
      var resArray = new Array(i);
      while (i--) {
        resArray[i] = [ownProps[i], obj[ownProps[i]]];
      }
      return resArray;
    }
  });
}
if (!Object.fromEntries) {
  Object.defineProperty(Object, 'fromEntries', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function value(entries) {
      var obj = {};
      var entriesArray = Array.from(entries);
      for (var i = 0; i < entriesArray.length; i++) {
        var _entriesArray$i = _slicedToArray(entriesArray[i], 2),
          key = _entriesArray$i[0],
          value = _entriesArray$i[1];
        obj[key] = value;
      }
      return obj;
    }
  });
}
Java.type('java.util.Base64');
Java.type('java.lang.String');

function Color(hex) {
  this.hex = hex;
  this.alpha = function (alpha) {
    return new Color(this.hex & 0xFFFFFF00 | alpha * 255);
  };
  this.toHex = function () {
    return this.hex;
  };
}
var COLORS = {
  RED: new Color(0xFF0000FF),
  GREEN: new Color(0x00FF00FF),
  BLUE: new Color(0x0000FFFF),
  YELLOW: new Color(0xFFFF00FF),
  PURPLE: new Color(0xFF00FFFF),
  ORANGE: new Color(0xFFA500FF),
  PINK: new Color(0xFFC0CBFF),
  GRAY: new Color(0x808080FF),
  BLACK: new Color(0x000000FF),
  WHITE: new Color(0xFFFFFFFF)
};

var API = Java.type('noppes.npcs.api.NpcAPI').Instance();
var world = API.getIWorld('minecraft:overworld');
function dump() {
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }
  for (var _i = 0, _args = args; _i < _args.length; _i++) {
    var arg = _args[_i];
    if (!(arg instanceof Error) && _typeof(arg) === 'object') {
      arg = JSON.stringify(arg, null, 2);
    }
    world.broadcast(arg);
  }
}
function dd() {
  dump.apply(void 0, arguments);
  throw new Error('Dump and die');
}

var _GUI_IDS = {};
var _GUI_EVENT_LISTENERS = {};
function id(name) {
  // generate random name if name is not provided
  if (!name) {
    name = Math.random().toString(36).substring(2, 15);
  }
  return _GUI_IDS[name] = _GUI_IDS[name] || Object.keys(_GUI_IDS).length + 1;
}
function listen(id, callback) {
  if (!_GUI_EVENT_LISTENERS[id]) {
    _GUI_EVENT_LISTENERS[id] = [];
  }
  _GUI_EVENT_LISTENERS[id].push(callback);
}
function emit(id, data) {
  if (!_GUI_EVENT_LISTENERS[id]) {
    return;
  }
  _GUI_EVENT_LISTENERS[id].forEach(function (callback) {
    return callback(data);
  });
}
var BaseGui = /*#__PURE__*/function () {
  function BaseGui(id, width, height, player) {
    _classCallCheck(this, BaseGui);
    this.gui = API.createCustomGui(id, width, height, false, player);
    this.state = {};
    this.player = player;
  }
  return _createClass(BaseGui, [{
    key: "init",
    value: function init() {
      // Optional override
    }
  }, {
    key: "build",
    value: function build() {
      throw new Error('build method must be implemented');
    }
  }, {
    key: "update",
    value: function update() {
      throw new Error('update method must be implemented');
    }
  }, {
    key: "onClose",
    value: function onClose() {
      // Optional override
    }
  }]);
}();
var gui = {
  id: id,
  listen: listen,
  emit: emit
};

var URL = Java.type("java.net.URL");
var OutputStreamWriter = Java.type("java.io.OutputStreamWriter");
var BufferedReader = Java.type("java.io.BufferedReader");
var InputStreamReader = Java.type("java.io.InputStreamReader");

// Custom error class
var HttpError = /*#__PURE__*/function (_Error) {
  function HttpError(response, responseCode) {
    var _this;
    _classCallCheck(this, HttpError);
    _this = _callSuper(this, HttpError, ["HttpError: ".concat(responseCode)]);
    _this.response = response;
    return _this;
  }
  _inherits(HttpError, _Error);
  return _createClass(HttpError);
}(/*#__PURE__*/_wrapNativeSuper(Error));
function request(method, url) {
  var requestBody = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  url = new URL(url);
  var connection = url.openConnection();
  connection.setRequestMethod(method);
  if (method === "POST") {
    connection.setRequestProperty("Content-Type", "application/json");
    connection.setDoOutput(true);
    if (requestBody) {
      var writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
      writer.write(JSON.stringify(requestBody));
      writer.flush();
      writer.close();
    }
  } else {
    connection.setDoOutput(false);
  }
  var responseCode = connection.getResponseCode();
  var reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
  var response = "";
  var line;
  while ((line = reader.readLine()) != null) {
    response += line + '\n';
  }
  reader.close();
  if (!(responseCode >= 200 && responseCode < 400)) {
    throw new HttpError(response, responseCode);
  }
  connection.disconnect();
  return response;
}
function get(url) {
  return request("GET", url, null);
}
function post(url, requestBody) {
  return request("POST", url, requestBody);
}
function getJson(url) {
  return JSON.parse(get(url));
}
function postJson(url, requestBody) {
  return JSON.parse(post(url, requestBody));
}
var http = {
  get: get,
  post: post,
  getJson: getJson,
  postJson: postJson,
  request: request,
  HttpError: HttpError
};

// The Minecraft version this script is compatible with
// Used to check with downloadable scripts
var MINECRAFT_VERSION = '1.20.1';

// The GreasyFork Script ID of this script, for self-updating purposes
var SCRIPT_MANAGER_ID = 548277;

// The GreasyFork User IDs of trusted authors
// These authors have been verified to be trustworthy
// This is used to display a trusted badge next to the author name
var TRUSTED_AUTHOR_IDS = [1210996,
// Runonstof
1511915,
// Hank
1511928 // Etternal
// xxxxx, // TODO: Add Yellow
];

// Test data to mock API responses
var TEST_SCRIPTS = [{
  "id": SCRIPT_MANAGER_ID,
  "daily_installs": 0,
  "total_installs": 0,
  "fan_score": "5.0",
  "good_ratings": 0,
  "ok_ratings": 0,
  "bad_ratings": 0,
  "created_at": "2025-09-03T22:04:40.000Z",
  "code_updated_at": "2025-09-03T23:35:06.000Z",
  "namespace": "runonstof",
  "support_url": null,
  "contribution_url": null,
  "contribution_amount": null,
  "users": [{
    "id": 1210996,
    "name": "Runonstof",
    "created_at": "2023-11-04T23:03:12.000Z",
    "url": "https://greasyfork.org/users/1210996-runonstof"
  }],
  "name": "ScriptManager",
  "description": "Manage and download CustomNPCs scripts ingame!",
  "url": "https://greasyfork.org/scripts/548277-scriptmanager",
  "code_url": "https://update.greasyfork.org/scripts/548277/ScriptManager.user.js",
  "code_size": 6386,
  "license": "MIT License",
  "version": "1.0.1",
  "locale": "en",
  "deleted": false
}, {
  "id": 548379,
  "daily_installs": 0,
  "total_installs": 0,
  "fan_score": "5.0",
  "good_ratings": 0,
  "ok_ratings": 0,
  "bad_ratings": 0,
  "created_at": "2025-09-04T18:54:04.000Z",
  "code_updated_at": "2025-09-04T18:56:28.000Z",
  "namespace": "runonstof",
  "support_url": null,
  "contribution_url": null,
  "contribution_amount": null,
  "users": [{
    "id": 1210996,
    "name": "Runonstof",
    "created_at": "2023-11-04T23:03:12.000Z",
    "url": "https://greasyfork.org/users/1210996-runonstof"
  }],
  "name": "Debugger",
  "description": "Debugger tool for CustomNPCs scripts",
  "url": "https://greasyfork.org/scripts/548379-debugger",
  "code_url": "https://update.greasyfork.org/scripts/548379/Debugger.user.js",
  "code_size": 122188,
  "license": "MIT License",
  "version": "1.0.2",
  "locale": "en",
  "deleted": false
}, {
  "id": 485526,
  "daily_installs": 12,
  "total_installs": 482,
  "fan_score": "5.0",
  "good_ratings": 17,
  "ok_ratings": 2,
  "bad_ratings": 0,
  "created_at": "2025-09-04T18:54:04.000Z",
  "code_updated_at": "2025-09-04T18:56:28.000Z",
  "namespace": "runonstof",
  "support_url": null,
  "contribution_url": null,
  "contribution_amount": null,
  "users": [{
    "id": 1210996,
    "name": "Runonstof",
    "created_at": "2023-11-04T23:03:12.000Z",
    "url": "https://greasyfork.org/users/1210996-runonstof"
  }],
  "name": "Jump Block",
  "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nSuspendisse sit amet nulla in erat imperdiet rutrum id ut velit.\nSed cursus id enim vel interdum.\nSuspendisse potenti.\nMauris blandit mauris mauris, ac venenatis nunc iaculis sit amet.\nInteger interdum fringilla lorem, a sagittis ante blandit ut.\nCras sollicitudin ultricies mi, ac volutpat diam elementum vel.\nNullam quis risus sed tellus interdum blandit.\nNullam bibendum lorem sit amet neque faucibus, id hendrerit nunc vulputate.\nSed accumsan eros eros, a molestie mauris euismod id.\nVivamus facilisis turpis auctor orci viverra gravida.",
  "url": "https://greasyfork.org/scripts/485526-market-history",
  "code_url": "https://update.greasyfork.org/scripts/485526/Market History.user.js",
  "code_size": 122188,
  "license": "MIT License",
  "version": "1.0.2",
  "locale": "en",
  "deleted": false
}];

var ScriptsRepo = /*#__PURE__*/function () {
  function ScriptsRepo() {
    _classCallCheck(this, ScriptsRepo);
    this.baseUrl = 'https://greasyfork.org';
    this.baseCdnUrl = 'https://update.greasyfork.org';
    this.baseApiUrl = 'https://api.greasyfork.org';
    /**
     * @type {ScriptInfo[]}
     */
    this.scripts = [];
  }

  /**
   * Should be called in a thread
   */
  return _createClass(ScriptsRepo, [{
    key: "init",
    value: function init() {
      var _this = this;
      // this.scripts = http.getJson(`${this.baseApiUrl}/scripts/by-site/customnpcs.com.json`)
      //   .map(info => new ScriptInfo(this, info));
      this.scripts = TEST_SCRIPTS.map(function (info) {
        return new ScriptInfo(_this, info);
      });
    }
  }, {
    key: "getScriptInfo",
    value: function getScriptInfo(id) {
      return new ScriptInfo(this, http.getJson("".concat(this.baseUpdateUrl, "/scripts/").concat(id, ".js")));
    }
  }, {
    key: "getScriptMetadata",
    value: function getScriptMetadata(id) {
      return new ScriptMetadata(http.get("".concat(this.baseCdnUrl, "/scripts/").concat(id, "/script.meta.js")));
    }
  }, {
    key: "getScriptContents",
    value: function getScriptContents(id) {
      return http.get("".concat(this.baseCdnUrl, "/scripts/").concat(id, "/script.user.js"));
    }
  }]);
}();
var ScriptMetadata = /*#__PURE__*/function () {
  function ScriptMetadata(raw) {
    _classCallCheck(this, ScriptMetadata);
    this.raw = raw;
    this.properties = this._parse(raw);
  }
  return _createClass(ScriptMetadata, [{
    key: "value",
    value: function value(key) {
      var _this$properties$key;
      var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
      return (_this$properties$key = this.properties[key]) !== null && _this$properties$key !== void 0 && _this$properties$key.length ? this.properties[key][0] : defaultValue;
    }
  }, {
    key: "values",
    value: function values(key) {
      return this.properties[key] || [];
    }
  }, {
    key: "isCompatibleMcVersion",
    value: function isCompatibleMcVersion() {
      return this.values('minecraft').indexOf(MINECRAFT_VERSION) !== -1;
    }
  }, {
    key: "_parse",
    value: function _parse(raw) {
      var regex = /^\s*\/\/\s*@([^\s]+)\s+([^\s]+)$/;
      return raw.split(/[\r\n]+/).reduce(function (acc, line) {
        var match = regex.exec(line);
        if (match) {
          var _match = _slicedToArray(match, 3);
            _match[0];
            var key = _match[1],
            value = _match[2];
          if (!acc.hasOwnProperty(key)) {
            acc[key] = [];
          }
          acc[key].push(value);
        }
        return acc;
      }, {});
    }
  }]);
}();
var ScriptInfo = /*#__PURE__*/function () {
  function ScriptInfo(repo, data) {
    _classCallCheck(this, ScriptInfo);
    /**
     * @type {ScriptsRepo}
     */
    this._repo = repo;
    this._metadata = null;
    this.id = data.id;
    this.daily_installs = data.daily_installs;
    this.total_installs = data.total_installs;
    this.fan_score = data.fan_score;
    this.good_ratings = data.good_ratings;
    this.ok_ratings = data.ok_ratings;
    this.bad_ratings = data.bad_ratings;
    this.created_at = data.created_at;
    this.code_updated_at = data.code_updated_at;
    this.namespace = data.namespace;
    this.support_url = data.support_url;
    this.contribution_url = data.contribution_url;
    this.contribution_amount = data.contribution_amount;
    /**
     * @type {ScriptAuthor[]}
     */
    this.users = data.users.map(function (user) {
      return new ScriptAuthor(user);
    });
    this.name = data.name;
    this.description = data.description;
    this.url = data.url;
    this.code_url = data.code_url;
    this.code_size = data.code_size;
    this.license = data.license;
    this.version = data.version;
    this.locale = data.locale;
    this.deleted = data.deleted;
  }
  return _createClass(ScriptInfo, [{
    key: "getMetadata",
    value: function getMetadata() {
      if (!this._metadata) {
        this._metadata = this._repo.getScriptMetadata(this.id);
      }
      return this._metadata;
    }
  }, {
    key: "getContents",
    value: function getContents() {
      return this._repo.getScriptContents(this.id);
    }
  }, {
    key: "getReportUrl",
    value:
    /**
     * Get the url to report the script
     * @return {string}
     */
    function getReportUrl() {
      return "".concat(this._repo.baseUrl, "/reports/new?item_class=script&item_id=").concat(this.id);
    }
  }, {
    key: "getFeedbackUrl",
    value:
    /**
     * Get the url to feedback the script
     * @return {string}
     */
    function getFeedbackUrl() {
      return "".concat(this._repo.baseUrl, "/scripts/").concat(this.id, "/feedback");
    }
  }]);
}();
var ScriptAuthor = /*#__PURE__*/function () {
  function ScriptAuthor(data) {
    _classCallCheck(this, ScriptAuthor);
    this.id = data.id;
    this.name = data.name;
    this.created_at = data.created_at;
    this.url = data.url;
  }
  return _createClass(ScriptAuthor, [{
    key: "isTrusted",
    value: function isTrusted() {
      return TRUSTED_AUTHOR_IDS.indexOf(this.id) !== -1;
    }
  }, {
    key: "isBlacklisted",
    value: function isBlacklisted() {
      return BLACKLISTED_AUTHOR_IDS.indexOf(this.id) !== -1;
    }
  }]);
}();

var Thread = Java.type('java.lang.Thread');
function handleAsyncError(error) {
  // dd("§cError: " + error.message)
  // print(error);
  dd('§cError: ' + error.message + ' ' + error.fileName + ':' + error.lineNumber);
  dd('§cStack: ' + error.stack);
}
function doAsync(callback) {
  var thread = new Thread(function () {
    var result;
    try {
      result = callback();
    } catch (e) {
      handleAsyncError(e);
    }
    return result;
  });
  thread.start();
  return thread;
}

var ScriptManagerEvents = /*#__PURE__*/function () {
  /**
   *
   * @param {ScriptManager} gui
   */
  function ScriptManagerEvents(gui) {
    _classCallCheck(this, ScriptManagerEvents);
    this.gui = gui;
  }
  return _createClass(ScriptManagerEvents, [{
    key: "register",
    value: function register() {
      gui.listen(id('scrl_scripts'), this.onScriptSelected.bind(this));
    }

    /**
     *
     * @param {CustomGuiEvent.ScrollEvent} e
     */
  }, {
    key: "onScriptSelected",
    value: function onScriptSelected(e) {
      var _this$gui$state$selec,
        _this = this;
      /**
       * @type {ScriptInfo}
       */
      var script = this.gui.repo.scripts[e.scrollIndex];
      (_this$gui$state$selec = this.gui.state.selectedScript) === null || _this$gui$state$selec === void 0 ? void 0 : _this$gui$state$selec.id;

      // Set always to null when inbetween loading or selecting the same
      this.gui.state.selectedScript = null;
      this.gui.update();

      // if (selectedScriptId == script.id) {
      //     e.scroll.setSelection([]);
      //     this.gui.update(e.scroll);
      //     this.gui.update();
      //     return;
      // }

      doAsync(function () {
        _this.gui.state.loading = true;
        _this.gui.update();
        try {
          script.getMetadata();
        } catch (error) {
          _this.gui.state.loading = false;
          _this.gui.state.message = '§cHttpError';
          _this.gui.update();
          return;
        }
        _this.gui.state.loading = false;
        _this.gui.state.selectedScript = script;
        _this.gui.update();
        // dd('metadata', script.getMetadata());
      });
    }
  }]);
}();

function chunkate(string, length) {
  return string.split(/[\r\n]+/).reduce(function (acc, line) {
    // split the line into chunks of length using slice
    // for (let i = 0; i < line.length; i += length) {
    //     acc.push(line.slice(i, i + length));
    // }

    var words = line.split(' ');
    var pushLine = '';
    words.forEach(function (word) {
      if (pushLine.length + word.length > length) {
        acc.push(pushLine.trim());
        pushLine = word;
      } else {
        pushLine += word + ' ';
      }
    });
    if (pushLine) {
      acc.push(pushLine.trim());
    }
    return acc;
  }, []);
}

var _excluded = ["children"],
  _excluded2 = ["children"];
function createElement(type, _ref) {
  var _ref$children = _ref.children,
    children = _ref$children === void 0 ? [] : _ref$children,
    props = _objectWithoutProperties(_ref, _excluded);
  if (typeof children === 'function') {
    children = [children];
  }
  // Flatten children array
  children = children.flat(Infinity).filter(function (child) {
    return child !== null && child !== undefined && child !== false;
  });

  // Handle different element types
  if (typeof type === 'string') {
    return createGuiElementCallback(type, _objectSpread2(_objectSpread2({}, props), {}, {
      children: children
    }));
  } else if (typeof type === 'function') {
    // Handle functional components
    return type(_objectSpread2(_objectSpread2({}, props), {}, {
      children: children
    }));
  } else {
    throw new Error("Unknown element type: ".concat(type));
  }
}

// jsx function for single child elements
function jsx(type, props, key) {
  return createElement(type, props);
}

// jsxs function for multiple children elements
function jsxs(type, props, key) {
  return createElement(type, props);
}

// Fragment support
function Fragment(_ref2) {
  var children = _ref2.children,
    _ref2$x = _ref2.x,
    x = _ref2$x === void 0 ? 0 : _ref2$x,
    _ref2$y = _ref2.y,
    y = _ref2$y === void 0 ? 0 : _ref2$y;
  var parentContext = {
    x: x,
    y: y
  };
  return function (gui) {
    var higherParentContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var _higherParentContext$ = higherParentContext.x,
      hpX = _higherParentContext$ === void 0 ? 0 : _higherParentContext$,
      _higherParentContext$2 = higherParentContext.y,
      hpY = _higherParentContext$2 === void 0 ? 0 : _higherParentContext$2;
    var useParentContext = {
      x: hpX + parentContext.x,
      y: hpY + parentContext.y
    };
    children.forEach(function (child) {
      return typeof child === 'function' ? child(gui, useParentContext) : child;
    });
    return {
      children: children
    };
  };
}
function createGuiElementCallback(type, _ref3) {
  var children = _ref3.children,
    props = _objectWithoutProperties(_ref3, _excluded2);
  if (typeof props.id === 'undefined') {
    throw new Error("id property is required for ".concat(type));
  }
  var dynamicProps = ['enabled', 'visible', 'scale', 'centered', 'text', 'color', 'hoverText', 'thickness', 'hasSearch', 'list'];

  /**
   *
   * @param {ICustomGui} gui
   * @returns {ICustomGuiComponent}
   */
  var findOrCreateComponent = function findOrCreateComponent(gui) {
    var parentContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var component;
    if (type !== 'scrollpanel' && (component = gui.getComponent(id(props.id)))) {
      return component;
    }
    var sumParentContextProperty = function sumParentContextProperty(localProp) {
      var parentProp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
      var localDefault = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
      parentProp = parentProp || localProp;
      if (typeof parentContext[parentProp] === 'undefined') {
        return;
      }
      var localValue = props.hasOwnProperty(localProp) ? props[localProp] : localDefault;

      // CHECK: this can have side effects
      props[localProp] = parentContext[parentProp] + localValue;
    };
    sumParentContextProperty('x');
    sumParentContextProperty('y');
    switch (type) {
      case 'button':
        return gui.addButton(id(props.id), props.text, props.x || 0, props.y || 0, props.width || 0, props.height || 0);
      case 'label':
        return gui.addLabel(id(props.id), props.text, props.x || 0, props.y || 0, props.width || 0, props.height || 0, props.color || 0xFFFFFFFF);
      case 'textfield':
        return gui.addTextField(id(props.id), props.text || '', props.x || 0, props.y || 0, props.width || 0, props.height || 0, props.placeholder || '');
      case 'scroll':
        return gui.addScroll(id(props.id), props.x || 0, props.y || 0, props.width || 0, props.height || 0, props.list || []);
      case 'line':
        sumParentContextProperty('x1', 'x');
        sumParentContextProperty('y1', 'y');
        sumParentContextProperty('x2', 'x');
        sumParentContextProperty('y2', 'y');
        return gui.addColoredLine(id(props.id), props.x1 || 0, props.y1 || 0, props.x2 || 0, props.y2 || 0, props.color || 0xFFFFFFFF, props.thickness || 1);
      case 'scrollpanel':
        var panel = gui.getScrollingPanel();
        if (!props.initialized) {
          panel.init(props.x || 0, props.y || 0, props.width || 0, props.height || 0);
        }
        children.forEach(function (child) {
          return typeof child === 'function' ? child(panel) : child;
        });
        return panel;
    }
    throw new Error("Unknown element type: ".concat(type));
  };
  return function (gui) {
    var parentContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var component = findOrCreateComponent(gui, parentContext);
    for (var _i = 0, _dynamicProps = dynamicProps; _i < _dynamicProps.length; _i++) {
      var dynamicProp = _dynamicProps[_i];
      if (!props.hasOwnProperty(dynamicProp)) {
        continue;
      }

      // const getterFunction = `get${dynamicProp.charAt(0).toUpperCase() + dynamicProp.slice(1)}`;
      var setterFunction = "set".concat(dynamicProp.charAt(0).toUpperCase() + dynamicProp.slice(1));
      component[setterFunction](props[dynamicProp]);
    }
    return {
      component: component
    };
  };
}
function renderToGui(gui, element) {
  return element(gui);
}

function Rectangle(_ref) {
  var id = _ref.id,
    _ref$x = _ref.x,
    x = _ref$x === void 0 ? 0 : _ref$x,
    _ref$y = _ref.y,
    y = _ref$y === void 0 ? 0 : _ref$y,
    width = _ref.width,
    height = _ref.height;
  return jsxs(Fragment, {
    children: [jsx("line", {
      id: "".concat(id, "_top"),
      x1: x,
      y1: y,
      x2: x + width,
      y2: y,
      color: COLORS.GRAY.toHex(),
      thickness: 2
    }), jsx("line", {
      id: "".concat(id, "_right"),
      x1: x + width,
      y1: y,
      x2: x + width,
      y2: y + height,
      color: COLORS.GRAY.toHex(),
      thickness: 2
    }), jsx("line", {
      id: "".concat(id, "_bottom"),
      x1: x,
      y1: y + height,
      x2: x + width,
      y2: y + height,
      color: COLORS.GRAY.toHex(),
      thickness: 2
    }), jsx("line", {
      id: "".concat(id, "_left"),
      x1: x,
      y1: y,
      x2: x,
      y2: y + height,
      color: COLORS.GRAY.toHex(),
      thickness: 2
    })]
  });
}
function Loader(_ref2) {
  var id = _ref2.id,
    _ref2$x = _ref2.x,
    x = _ref2$x === void 0 ? 0 : _ref2$x,
    _ref2$y = _ref2.y,
    y = _ref2$y === void 0 ? 0 : _ref2$y,
    width = _ref2.width,
    height = _ref2.height,
    _ref2$visible = _ref2.visible,
    visible = _ref2$visible === void 0 ? true : _ref2$visible;
  return jsxs(Fragment, {
    children: [jsx("line", {
      id: "bg_".concat(id),
      x1: x,
      y1: y + height / 2,
      x2: x + width,
      y2: y + height / 2,
      color: COLORS.BLACK.alpha(visible ? 0.5 : 0).toHex(),
      thickness: height
    }), jsx("label", {
      id: "lbl_".concat(id),
      text: 'Loading...',
      x: x,
      y: y + height / 2 - 4,
      width: width,
      height: 16,
      color: COLORS.WHITE.toHex(),
      centered: true,
      visible: visible
    })]
  });
}
var ScriptManager = /*#__PURE__*/function (_BaseGui) {
  function ScriptManager(player) {
    var _this;
    _classCallCheck(this, ScriptManager);
    _this = _callSuper(this, ScriptManager, [id('gui_scriptmanager'), 384, 192, player]);
    _this.state = {
      categories: null,
      initialized: false,
      loading: false,
      message: '',
      /**
       * @type {ScriptInfo|null}
       */
      selectedScript: null
    };
    _this.renderInit = false;
    _this.repo = new ScriptsRepo();
    _this.events = new ScriptManagerEvents(_this);
    _this.descriptionLines = 20;
    _this.render();
    _this.events.register();
    player.showCustomGui(_this.gui);
    return _this;
  }
  _inherits(ScriptManager, _BaseGui);
  return _createClass(ScriptManager, [{
    key: "init",
    value: function init() {
      var _this2 = this;
      if (this.state.initialized) return;
      doAsync(function () {
        _this2.state.loading = true;
        _this2.update();
        _this2.repo.init();
        _this2.state.initialized = true;
        _this2.state.loading = false;
        _this2.update();
      });
    }
  }, {
    key: "render",
    value: function render() {
      var scrollProps = {
        enabled: false,
        visible: false
      };
      if (this.state.initialized) {
        scrollProps.enabled = true;
        scrollProps.visible = true;
      }
      var script = this.state.selectedScript;
      var author = (script === null || script === void 0 ? void 0 : script.users[0]) || null;
      var meta = (script === null || script === void 0 ? void 0 : script.getMetadata()) || null;
      var mcVersions = (meta === null || meta === void 0 ? void 0 : meta.values('minecraft')) || [];
      var mcVersionColor = meta !== null && meta !== void 0 && meta.isCompatibleMcVersion() ? '§a' : '§c';
      var mcVersionText = mcVersions.join(', ') + (meta !== null && meta !== void 0 && meta.isCompatibleMcVersion() ? '' : '§c (incompatible)');
      var scriptLines = chunkate((script === null || script === void 0 ? void 0 : script.description) || '', 42);
      var descriptionLines = Array.from({
        length: this.descriptionLines
      }).map(function (_, index) {
        return scriptLines[index] || '';
      });
      var isRenderInit = this.renderInit;
      this.renderInit = true;
      return renderToGui(this.gui, jsxs(Fragment, {
        children: [jsx("label", {
          id: "lbl_title",
          text: "\xA7eScriptManager",
          width: this.gui.getWidth(),
          height: 16,
          color: COLORS.WHITE.toHex(),
          scale: 2,
          centered: false
        }), jsxs(Fragment, {
          y: 20,
          children: [jsx("scroll", _objectSpread2({
            id: "scrl_scripts",
            width: 128,
            height: this.gui.getHeight(),
            hasSearch: false,
            list: this.repo.scripts.map(function (script) {
              return script.name;
            })
          }, scrollProps)), jsx(Rectangle, {
            id: "rect_scripts_info",
            width: this.gui.getWidth(),
            height: this.gui.getHeight()
          }), jsxs(Fragment, {
            x: 144,
            children: [jsx("label", {
              id: "lbl_scripts_info",
              y: 4,
              width: 128,
              height: 16,
              text: "\xA73\xA7n".concat(script === null || script === void 0 ? void 0 : script.name),
              visible: !!script,
              scale: 2
            }), jsx("label", {
              id: "lbl_scripts_author",
              y: 24,
              width: 128,
              height: 16,
              text: author ? "\xA77By ".concat(author.name) : '§7Unknown',
              visible: !!author
            }), jsx("label", {
              id: "lbl_scripts_version",
              y: 34,
              width: 128,
              height: 16,
              text: "\xA76v".concat(script === null || script === void 0 ? void 0 : script.version),
              visible: !!script
            }), jsx("label", {
              id: "lbl_scripts_mcversion",
              y: 44,
              width: 128,
              height: 16,
              text: "".concat(mcVersionColor, "MC ").concat(mcVersionText),
              visible: !!script
            }), jsx("scrollpanel", {
              id: "scrlp_scripts_info_description",
              y: 64,
              width: this.gui.getWidth() - 144,
              height: this.gui.getHeight() - 64 - 16,
              initialized: isRenderInit,
              children: descriptionLines.map(function (line, index) {
                return jsx("label", {
                  id: "lbl_scripts_info_description_".concat(index),
                  text: line,
                  visible: !!line,
                  y: index * 10,
                  width: 128,
                  height: 16,
                  color: COLORS.WHITE.toHex()
                });
              })
            })]
          }), jsxs(Fragment, {
            x: this.gui.getWidth() - 48,
            children: [jsx("label", {
              id: "lbl_scripts_rating_good",
              y: 4,
              width: 48,
              height: 16,
              text: "\xA7a\u2714\xA7f \xD7".concat(script === null || script === void 0 ? void 0 : script.good_ratings),
              hoverText: "\xA7aGood",
              visible: !!script
            }), jsx("label", {
              id: "lbl_scripts_rating_ok",
              y: 14,
              width: 48,
              height: 16,
              text: "\xA7e\xA7lO\xA7f \xD7".concat(script === null || script === void 0 ? void 0 : script.ok_ratings),
              hoverText: "\xA7eOk",
              visible: !!script
            }), jsx("label", {
              id: "lbl_scripts_rating_bad",
              y: 24,
              width: 48,
              height: 16,
              text: "\xA7c\u2716\xA7f \xD7".concat(script === null || script === void 0 ? void 0 : script.bad_ratings),
              hoverText: "\xA7cBad",
              visible: !!script
            })]
          }), jsxs(Fragment, {
            x: 144,
            y: this.gui.getHeight() - 16,
            children: [jsx("label", {
              id: "lbl_scripts_installs_today",
              width: 48,
              height: 16,
              text: "\xA79\u2193\xA7f \xD7".concat(script === null || script === void 0 ? void 0 : script.daily_installs),
              visible: !!script
            }), jsx("label", {
              id: "lbl_scripts_installs_total",
              x: 48,
              width: 48,
              height: 16,
              text: "\xA7a\u2193\xA7f \xD7".concat(script === null || script === void 0 ? void 0 : script.total_installs),
              visible: !!script
            })]
          }), jsx(Fragment, {
            x: this.gui.getWidth() / 3,
            y: this.gui.getHeight() / 3,
            children: jsx(Loader, {
              id: "loader",
              x: 0,
              y: 0,
              width: 128,
              height: 48,
              visible: this.state.loading
            })
          })]
        })]
      }));
    }
  }, {
    key: "update",
    value: function update() {
      this.render();
      this.gui.update();
    }
  }]);
}(BaseGui);

var global = {};

global.scriptManager = null;
function customGuiScroll(e) {
  if (e.gui.getID() !== global.scriptManager.gui.getID()) return;
  var shouldCancel = !e.scroll.getEnabled() || global.scriptManager.state.loading || global.scriptManager.state.message;
  if (shouldCancel) {
    e.scroll.setSelection([]);
    e.gui.update(e.scroll);
    e.gui.update();
    return;
  }

  // Scroll behaviour
  gui.emit(e.scrollId, e);
}
function chat(e) {
  if (e.message !== '!scripts') return;
  // Check if the player is in creative mode
  if (e.player.gamemode !== 1) return;
  e.setCanceled(true);
  global.scriptManager = new ScriptManager(e.player);
  global.scriptManager.init();
}