isaacscript-common
Version:
Helper functions and features for IsaacScript mods.
162 lines (161 loc) • 6.55 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearTable = clearTable;
exports.copyUserdataValuesToTable = copyUserdataValuesToTable;
exports.getBooleansFromTable = getBooleansFromTable;
exports.getNumbersFromTable = getNumbersFromTable;
exports.getStringsFromTable = getStringsFromTable;
exports.isTableEmpty = isTableEmpty;
exports.iterateTableInOrder = iterateTableInOrder;
exports.tableHasKeys = tableHasKeys;
const types_1 = require("./types");
const utils_1 = require("./utils");
/**
* In a `Map`, you can use the `clear` method to delete every element. However, in a `LuaMap`, the
* `clear` method does not exist. Use this helper function as a drop-in replacement for this.
*/
function clearTable(luaMap) {
for (const [key] of luaMap) {
luaMap.delete(key);
}
}
/** Helper function to copy specific values from a userdata object (e.g. `Vector`) to a table. */
function copyUserdataValuesToTable(object, keys, luaMap) {
if (!(0, types_1.isUserdata)(object)) {
error(`Failed to copy an object values to a table, since the object was of type: ${type(object)}`);
}
// We can access values on userdata objects similar to a normal table.
const userdata = object;
for (const key of keys) {
const value = userdata.get(key);
luaMap.set(key, value);
}
}
/**
* Helper function to safely get boolean values from a Lua table. Will throw an error if the
* specific value does not exist on the table.
*
* This function is variadic, meaning that you can specify N arguments to get N values.
*/
function getBooleansFromTable(luaMap, objectName, ...keys) {
const booleans = [];
for (const key of keys) {
const value = luaMap.get(key);
(0, utils_1.assertDefined)(value, `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`);
if ((0, types_1.isBoolean)(value)) {
booleans.push(value);
}
else {
error(`Failed to get the boolean for the "${key}" value of a table representing a "${objectName}" object because the type was: ${typeof value}`);
}
}
return booleans;
}
/**
* Helper function to safely get number values from specific keys on a Lua table. If the values are
* strings, they will be converted to numbers. Will throw an error if the specific value does not
* exist on the table or if it cannot be converted to a number.
*
* This function is variadic, meaning that you can specify N arguments to get N values.
*/
function getNumbersFromTable(luaMap, objectName, ...keys) {
const numbers = [];
for (const key of keys) {
const value = luaMap.get(key);
(0, utils_1.assertDefined)(value, `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`);
if ((0, types_1.isNumber)(value)) {
numbers.push(value);
}
else if ((0, types_1.isString)(value)) {
const number = tonumber(value);
(0, utils_1.assertDefined)(number, `Failed to convert the "${key}" value of a table representing a "${objectName}" object to a number: ${value}`);
numbers.push(number);
}
else {
error(`Failed to get the number for the "${key}" value of a table representing a "${objectName}" object because the type was: ${typeof value}`);
}
}
return numbers;
}
/**
* Helper function to safely get string values from a Lua table. Will throw an error if the specific
* value does not exist on the table.
*
* This function is variadic, meaning that you can specify N arguments to get N values.
*/
function getStringsFromTable(luaMap, objectName, ...keys) {
const strings = [];
for (const key of keys) {
const value = luaMap.get(key);
(0, utils_1.assertDefined)(value, `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`);
if ((0, types_1.isString)(value)) {
strings.push(value);
}
else {
const string = tostring(value);
strings.push(string);
}
}
return strings;
}
/** Helper function to check if a Lua table has 0 keys. */
function isTableEmpty(luaMap) {
// Using `next` does not seem to work properly, so we use `pairs` instead.
// eslint-disable-next-line no-unreachable-loop
for (const [_key, _value] of luaMap) {
return false;
}
return true;
}
/**
* Helper function to iterate over a table deterministically. This is useful because by default, the
* `pairs` function will return the keys of a Lua table in a random order.
*
* This function will sort the table entries based on the value of the key.
*
* This function will only work on tables that have number keys or string keys. It will throw a
* run-time error if it encounters a key of another type.
*
* @param luaMap The table to iterate over.
* @param func The function to run for each iteration.
* @param inOrder Optional. Whether to iterate in order. True by default. You can dynamically set to
* false in situations where iterating randomly would not matter and you need the
* extra performance.
*/
function iterateTableInOrder(luaMap, func, inOrder = true) {
// First, handle the trivial case of a non-deterministic iteration.
if (!inOrder) {
for (const [key, value] of luaMap) {
func(key, value);
}
return;
}
const keys = Object.keys(luaMap);
const hasAllNumberKeys = keys.every((key) => (0, types_1.isNumber)(key));
const hasAllStringKeys = keys.every((key) => (0, types_1.isString)(key));
if (!hasAllNumberKeys && !hasAllStringKeys) {
// Since the table has non-homogenous keys, we won't be able to sort it. Revert to
// non-deterministic iteration in this case.
for (const [key, value] of luaMap) {
func(key, value);
}
return;
}
keys.sort(); // eslint-disable-line @typescript-eslint/require-array-sort-compare
for (const key of keys) {
const keyIndex = key;
const value = luaMap.get(keyIndex);
if (value !== undefined) {
func(keyIndex, value);
}
}
}
/**
* Helper function to check if a Lua table has all of the provided keys.
*
* This function is variadic, meaning that you can specify as many arguments as you want to check
* for.
*/
function tableHasKeys(luaMap, ...keys) {
return keys.every((key) => luaMap.has(key));
}