Moved many small class files into util

This commit is contained in:
Lucas Dower 2023-11-23 14:22:51 +00:00
parent 62f0ab181f
commit 64b8410aff
34 changed files with 340 additions and 589 deletions

View File

@ -1,17 +1,14 @@
import { NBT, TagType } from 'prismarine-nbt';
import { AppConstants } from '../constants';
import { ceilToNearest } from '../math';
import { AppTypes } from '../util';
import { ASSERT } from '../util/error_util';
import { saveNBT } from '../util/nbt_util';
import { Vector3 } from '../vector';
import { AppConstants } from '../util/constants';
import { Vector3 } from '../util/vector';
import { IExporter, TStructureExport } from './base_exporter';
import { OtS_BlockMesh } from '../ots_block_mesh';
import { ASSERT, OtS_Util } from '../util/util';
type BlockID = number;
type long = [number, number];
type BlockMapping = Map<AppTypes.TNamespacedBlockName, BlockID>;
type BlockMapping = Map<string, BlockID>;
export class Litematic extends IExporter {
public override getFormatFilter() {
@ -23,7 +20,7 @@ export class Litematic extends IExporter {
public override export(blockMesh: OtS_BlockMesh): TStructureExport {
const nbt = this._convertToNBT(blockMesh);
return { type: 'single', extension: '.litematic', content: saveNBT(nbt) };
return { type: 'single', extension: '.litematic', content: OtS_Util.NBT.saveNBT(nbt) };
}
/**
@ -108,7 +105,7 @@ export class Litematic extends IExporter {
stride = Math.max(2, stride);
const expectedLengthBits = blockBuffer.length * stride;
const requiredLengthBits = ceilToNearest(expectedLengthBits, 64);
const requiredLengthBits = OtS_Util.Numeric.ceilToNearest(expectedLengthBits, 64);
const startOffsetBits = requiredLengthBits - expectedLengthBits;
const requiredLengthBytes = requiredLengthBits / 8;

View File

@ -1,12 +1,10 @@
import { NBT, TagType } from 'prismarine-nbt';
import { AppConstants } from '../constants';
import { AppUtil } from '../util';
import { saveNBT } from '../util/nbt_util';
import { Vector3 } from '../vector';
import { AppConstants } from '../util/constants';
import { Vector3 } from '../util/vector';
import { IExporter, TStructureExport, TStructureRegion } from './base_exporter';
import { ASSERT } from '../util/error_util';
import { OtS_BlockMesh } from '../ots_block_mesh';
import { ASSERT, OtS_Util } from '../util/util';
export class NBTExporter extends IExporter {
public override getFormatFilter() {
@ -78,7 +76,7 @@ export class NBTExporter extends IExporter {
},
};
return saveNBT(nbt);
return OtS_Util.NBT.saveNBT(nbt);
}
public override export(blockMesh: OtS_BlockMesh) {
@ -98,7 +96,7 @@ export class NBTExporter extends IExporter {
palette.push({
Name: {
type: TagType.String,
value: AppUtil.Text.namespaceBlock(blockName),
value: OtS_Util.Text.namespaceBlock(blockName),
},
});
blockNameToIndex.set(blockName, palette.length - 1);

View File

@ -1,13 +1,10 @@
import { NBT, TagType } from 'prismarine-nbt';
import { AppConstants } from '../constants';
import { AppUtil } from '../util';
import { LOG } from '../util/log_util';
import { MathUtil } from '../util/math_util';
import { saveNBT } from '../util/nbt_util';
import { Vector3 } from '../vector';
import { AppConstants } from '../util/constants';
import { Vector3 } from '../util/vector';
import { IExporter, TStructureExport } from './base_exporter';
import { OtS_BlockMesh } from '../ots_block_mesh';
import { OtS_Util } from '../util/util';
export class SchemExporter extends IExporter {
private static SCHEMA_VERSION = 2;
@ -31,19 +28,17 @@ export class SchemExporter extends IExporter {
let blockIndex = 1;
for (const blockName of blockMesh.calcBlocksUsed()) {
const namespacedBlockName = AppUtil.Text.namespaceBlock(blockName);
const namespacedBlockName = OtS_Util.Text.namespaceBlock(blockName);
blockMapping[namespacedBlockName] = { type: TagType.Int, value: blockIndex };
++blockIndex;
}
LOG(blockMapping);
// const paletteObject = SchemExporter._createBlockStatePalette(blockMapping);
const blockData = new Array<number>(sizeVector.x * sizeVector.y * sizeVector.z).fill(0);
for (const { position, name } of blockMesh.getBlocks()) {
const indexVector = Vector3.sub(position, bounds.min);
const bufferIndex = SchemExporter._getBufferIndex(sizeVector, indexVector);
const namespacedBlockName = AppUtil.Text.namespaceBlock(name);
const namespacedBlockName = OtS_Util.Text.namespaceBlock(name);
blockData[bufferIndex] = blockMapping[namespacedBlockName].value;
}
@ -59,7 +54,7 @@ export class SchemExporter extends IExporter {
}
for (let i = 0; i < blockEncoding.length; ++i) {
blockEncoding[i] = MathUtil.int8(blockEncoding[i]);
blockEncoding[i] = OtS_Util.Numeric.int8(blockEncoding[i]);
}
const nbt: NBT = {
@ -77,7 +72,7 @@ export class SchemExporter extends IExporter {
},
};
return { type: 'single', extension: '.schem', content: saveNBT(nbt) };
return { type: 'single', extension: '.schem', content: OtS_Util.NBT.saveNBT(nbt) };
}
private static _getBufferIndex(dimensions: Vector3, vec: Vector3) {

View File

@ -1,10 +1,10 @@
import { NBT, TagType } from 'prismarine-nbt';
import { BLOCK_IDS } from '../../../Editor/res/block_ids';
import { saveNBT } from '../util/nbt_util';
import { Vector3 } from '../vector';
import { Vector3 } from '../util/vector';
import { IExporter, TStructureExport } from './base_exporter';
import { OtS_BlockMesh } from '../ots_block_mesh';
import { OtS_Util } from '../util/util';
export class Schematic extends IExporter {
public override getFormatFilter() {
@ -16,7 +16,7 @@ export class Schematic extends IExporter {
public override export(blockMesh: OtS_BlockMesh): TStructureExport {
const nbt = this._convertToNBT(blockMesh);
return { type: 'single', extension: '.schematic', content: saveNBT(nbt) };
return { type: 'single', extension: '.schematic', content: OtS_Util.NBT.saveNBT(nbt) };
}
private _convertToNBT(blockMesh: OtS_BlockMesh): NBT {

View File

@ -1,12 +1,12 @@
import { parse } from '@loaders.gl/core';
import { GLTFLoader } from '@loaders.gl/gltf';
import { UV } from '../util';
import { Vector3 } from '../vector';
import { Vector3 } from '../util/vector';
import { OtS_Mesh } from '../ots_mesh';
import { OtS_Texture } from '../ots_texture';
import { OtS_Importer } from './base_importer';
import { OtS_Colours } from '../colour';
import { OtS_Colours } from '../util/colour';
import { UV } from '../util/types';
export type OtS_GltfImporterError =
| { type: 'failed-to-parse' }

View File

@ -1,14 +1,11 @@
import { OtS_Colours, RGBAUtil } from '../colour';
import { OtS_Colours, RGBAUtil } from '../util/colour';
import { OtS_Mesh } from '../ots_mesh';
import { OtS_Texture } from '../ots_texture';
import { Triangle } from '../triangle';
import { UV } from '../util';
import { ASSERT } from '../util/error_util';
import { RegExpBuilder } from '../util/regex_util';
import { REGEX_NZ_ANY } from '../util/regex_util';
import { REGEX_NUMBER } from '../util/regex_util';
import { Vector3 } from '../vector';
import { Triangle } from '../util/triangle';
import { Vector3 } from '../util/vector';
import { OtS_Importer } from './base_importer';
import { UV } from '../util/types';
import { ASSERT, OtS_Util } from '../util/util';
export type OtS_ObjImporterError =
| { type: 'invalid-encoding' }
@ -39,41 +36,41 @@ export class OtS_Importer_Obj extends OtS_Importer {
// Parser context
private _linesToParse: string[] = [];
private static _REGEX_USEMTL = new RegExpBuilder()
private static _REGEX_USEMTL = new OtS_Util.Regex.RegExpBuilder()
.add(/^usemtl/)
.add(/ /)
.add(REGEX_NZ_ANY, 'name')
.add(OtS_Util.Regex.REGEX_NZ_ANY, 'name')
.toRegExp();
private static _REGEX_VERTEX = new RegExpBuilder()
private static _REGEX_VERTEX = new OtS_Util.Regex.RegExpBuilder()
.add(/^v/)
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'x')
.add(OtS_Util.Regex.REGEX_NUMBER, 'x')
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'y')
.add(OtS_Util.Regex.REGEX_NUMBER, 'y')
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'z')
.add(OtS_Util.Regex.REGEX_NUMBER, 'z')
.toRegExp();
private static _REGEX_NORMAL = new RegExpBuilder()
private static _REGEX_NORMAL = new OtS_Util.Regex.RegExpBuilder()
.add(/^vn/)
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'x')
.add(OtS_Util.Regex.REGEX_NUMBER, 'x')
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'y')
.add(OtS_Util.Regex.REGEX_NUMBER, 'y')
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'z')
.add(OtS_Util.Regex.REGEX_NUMBER, 'z')
.toRegExp();
private static _REGEX_TEXCOORD = new RegExpBuilder()
private static _REGEX_TEXCOORD = new OtS_Util.Regex.RegExpBuilder()
.add(/^vt/)
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'u')
.add(OtS_Util.Regex.REGEX_NUMBER, 'u')
.addNonzeroWhitespace()
.add(REGEX_NUMBER, 'v')
.add(OtS_Util.Regex.REGEX_NUMBER, 'v')
.toRegExp();
private static _REGEX_FACE = new RegExpBuilder()
private static _REGEX_FACE = new OtS_Util.Regex.RegExpBuilder()
.add(/^f/)
.addNonzeroWhitespace()
.add(/.*/, 'line')

View File

@ -1,76 +0,0 @@
export namespace AppMath {
export const RADIANS_0 = degreesToRadians(0.0);
export const RADIANS_90 = degreesToRadians(90.0);
export const RADIANS_180 = degreesToRadians(180.0);
export const RADIANS_270 = degreesToRadians(270.0);
export function lerp(value: number, start: number, end: number) {
return (1 - value) * start + value * end;
}
export function nearlyEqual(a: number, b: number, tolerance: number = 0.0001) {
return Math.abs(a - b) < tolerance;
}
export function degreesToRadians(degrees: number) {
return degrees * (Math.PI / 180.0);
}
/**
* Converts a float in [0, 1] to an int in [0, 255]
* @param decimal A number in [0, 1]
*/
export function uint8(decimal: number) {
return Math.floor(decimal * 255);
}
export function largestPowerOfTwoLessThanN(n: number) {
return Math.floor(Math.log2(n));
}
}
export const argMax = (array: [number]) => {
return array.map((x, i) => [x, i]).reduce((r, a) => (a[0] > r[0] ? a : r))[1];
};
export const clamp = (value: number, min: number, max: number) => {
return Math.max(Math.min(max, value), min);
};
export const floorToNearest = (value: number, base: number) => {
return Math.floor(value / base) * base;
};
export const ceilToNearest = (value: number, base: number) => {
return Math.ceil(value / base) * base;
};
export const roundToNearest = (value: number, base: number) => {
return Math.round(value / base) * base;
};
export const between = (value: number, min: number, max: number) => {
return min <= value && value <= max;
};
export const mapRange = (value: number, fromMin: number, fromMax: number, toMin: number, toMax: number) => {
return (value - fromMin) / (fromMax - fromMin) * (toMax - toMin) + toMin;
};
export const wayThrough = (value: number, min: number, max: number) => {
// ASSERT(value >= min && value <= max);
return (value - min) / (max - min);
};
/**
* Returs true if any number in args is NaN
*/
export const anyNaN = (...args: number[]) => {
return args.some((arg) => {
return isNaN(arg);
});
};
export const degreesToRadians = Math.PI / 180;

View File

@ -1,4 +1,4 @@
import { OtS_ColourAverager, OtS_Colours, RGBA } from "./colour";
import { OtS_ColourAverager, RGBA } from "./util/colour";
import { OtS_BlockData_PerBlock, OtS_BlockData_PerFace, OtS_FaceData } from "./ots_block_mesh_converter";
export class OtS_BlockDataBuilder {

View File

@ -4,7 +4,7 @@
* 1.20.2 blocks.
*/
import { RGBA } from "./colour";
import { RGBA } from "./util/colour";
import { OtS_BlockData_PerBlock } from "./ots_block_mesh_converter";
const PER_BLOCK: OtS_BlockData_PerBlock<RGBA> = [

View File

@ -1,7 +1,7 @@
import { Bounds } from "./bounds";
import { UV } from "./util";
import { Vector3 } from "./vector"
import { Bounds } from "./util/bounds";
import { UV } from "./util/types";
import { Vector3 } from "./util/vector"
export interface TextureInfo {
name: string,

View File

@ -1,10 +1,10 @@
import { OtS_VoxelMesh } from './ots_voxel_mesh';
import { OtS_BlockMesh } from './ots_block_mesh';
import { OtS_FaceVisibility, OtS_VoxelMesh_Neighbourhood } from './ots_voxel_mesh_neighbourhood';
import { ASSERT } from './util/error_util';
import { Vector3 } from './vector';
import { RGBA, OtS_Colours, RGBAUtil } from './colour';
import { Vector3 } from './util/vector';
import { RGBA, RGBAUtil } from './util/colour';
import { BLOCK_DATA_DEFAULT } from './ots_block_data_default';
import { ASSERT } from './util/util';
export type OtS_FaceData<T> = {
up: T,

View File

@ -1,5 +1,4 @@
import { RGBA, RGBAUtil } from "./colour";
//import { Material, OtS_Util } from "./materials";
import { RGBA, RGBAUtil } from "./util/colour";
import { OtS_Texture } from "./ots_texture";
export type OtS_MeshSection = { name: string, positionData: Float32Array, normalData: Float32Array, indexData: Uint32Array } & (
@ -40,36 +39,4 @@ export namespace OtS_MeshUtil {
};
}
}
}
/*
export class OtS_MaterialSlots {
private _slots: Map<number, Material>;
private constructor() {
this._slots = new Map();
}
public static create() {
return new OtS_MaterialSlots();
}
public setSlot(index: number, material: Material) {
this._slots.set(index, material);
}
public getSlot(index: number) {
return this._slots.get(index);
}
public copy() {
const clone = OtS_MaterialSlots.create();
this._slots.forEach((value, key) => {
clone.setSlot(key, OtS_Util.copyMaterial(value));
});
return clone;
}
}
*/
}

View File

@ -1,12 +1,10 @@
import { Bounds } from './bounds';
import { RGBA } from './colour';
import { degreesToRadians } from './math';
import { Bounds } from './util/bounds';
import { RGBA } from './util/colour';
import { OtS_MeshSection, OtS_MeshUtil } from './ots_materials';
import { OtS_Texture } from './ots_texture';
import { UV } from "./util";
import { ASSERT } from './util/error_util';
import { Result } from './util/type_util';
import { Vector3 } from "./vector";
import { Result, UV } from './util/types';
import { Vector3 } from "./util/vector";
import { ASSERT, OtS_Util } from './util/util';
type OtS_VertexData<T> = {
v0: T,
@ -116,14 +114,14 @@ export class OtS_Mesh {
}
public rotate(pitch: number, roll: number, yaw: number) {
const cosa = Math.cos(yaw * degreesToRadians);
const sina = Math.sin(yaw * degreesToRadians);
const cosa = Math.cos(OtS_Util.Numeric.degreesToRadians(yaw));
const sina = Math.sin(OtS_Util.Numeric.degreesToRadians(yaw));
const cosb = Math.cos(pitch * degreesToRadians);
const sinb = Math.sin(pitch * degreesToRadians);
const cosb = Math.cos(OtS_Util.Numeric.degreesToRadians(pitch));
const sinb = Math.sin(OtS_Util.Numeric.degreesToRadians(pitch));
const cosc = Math.cos(roll * degreesToRadians);
const sinc = Math.sin(roll * degreesToRadians);
const cosc = Math.cos(OtS_Util.Numeric.degreesToRadians(roll));
const sinc = Math.sin(OtS_Util.Numeric.degreesToRadians(roll));
const Axx = cosa*cosb;
const Axy = cosa*sinb*sinc - sina*cosc;

View File

@ -1,6 +1,6 @@
import { RGBA, RGBAUtil } from "./colour";
import { clamp } from "./math";
import { TTexelExtension, TTexelInterpolation } from "./util/type_util";
import { RGBA, RGBAUtil } from "./util/colour";
import { TTexelExtension, TTexelInterpolation } from "./util/types";
import { OtS_Util } from "./util/util";
export class OtS_Texture {
private _data: Uint8ClampedArray;
@ -100,8 +100,8 @@ export class OtS_Texture {
// Expects `x` and `y` to be integers
private _samplePixel(x: number, y: number): RGBA {
const cx = clamp(x, 0, this._width - 1);
const cy = clamp(y, 0, this._height - 1);
const cx = OtS_Util.Numeric.clamp(x, 0, this._width - 1);
const cy = OtS_Util.Numeric.clamp(y, 0, this._height - 1);
const index = 4 * (this._width * cy + cx);
@ -114,7 +114,7 @@ export class OtS_Texture {
}
private _clampValue(x: number) {
return clamp(x, 0.0, 1.0);
return OtS_Util.Numeric.clamp(x, 0.0, 1.0);
}
private _repeatValue(x: number) {

View File

@ -1,7 +1,7 @@
import { Bounds } from "./bounds";
import { RGBA, RGBAUtil } from './colour';
import { Vector3 } from "./vector"
import { Bounds } from "./util/bounds";
import { RGBA, RGBAUtil } from './util/colour';
import { Vector3 } from "./util/vector"
export type OtS_Voxel = {
position: Vector3,

View File

@ -1,12 +1,11 @@
import { OtS_ReplaceMode, OtS_VoxelMesh } from './ots_voxel_mesh';
import { TAxis } from './util/type_util';
import { Vector3 } from './vector';
import { Triangle } from './triangle';
import { OtS_Colours, RGBA, RGBAUtil } from './colour';
import { TAxis, UV } from './util/types';
import { Vector3 } from './util/vector';
import { Triangle } from './util/triangle';
import { OtS_Colours, RGBA, RGBAUtil } from './util/colour';
import { OtS_Mesh, OtS_Triangle } from './ots_mesh';
import { UV } from './util';
import { rayIntersectTriangleFastX, rayIntersectTriangleFastY, rayIntersectTriangleFastZ, RayIntersect } from './ray';
import { OtS_ArrayUtil } from './util/array_util';
import { rayIntersectTriangleFastX, rayIntersectTriangleFastY, rayIntersectTriangleFastZ, RayIntersect } from './util/ray';
import { OtS_Util } from './util/util';
export type OtS_VoxelMesh_ConverterConfig = {
constraintAxis: TAxis,
@ -72,7 +71,7 @@ export class OtS_VoxelMesh_Converter {
rayOrigin[a1] = y;
let hasHit = false;
const start = OtS_ArrayUtil.findFirstTrueIndex(bounds.max[a2] - bounds.min[a2] + 1, (index: number) => {
const start = OtS_Util.Array.findFirstTrueIndex(bounds.max[a2] - bounds.min[a2] + 1, (index: number) => {
rayOrigin[a2] = bounds.min[a2] + index;
return intersect(rayOrigin, triangle, edge1, edge2) !== undefined;
});

View File

@ -1,5 +1,5 @@
import { OtS_VoxelMesh } from "./ots_voxel_mesh";
import { Vector3 } from "./vector";
import { Vector3 } from "./util/vector";
export type OtS_Offset = -1 | 0 | 1;
export type OtS_NeighbourhoodMode = 'cardinal' | 'non-cardinal';

View File

@ -1,47 +0,0 @@
import { AppMath } from "./math";
import { TBrand } from "./util/type_util";
export namespace AppUtil {
export namespace Text {
export function capitaliseFirstLetter(text: string) {
return text.charAt(0).toUpperCase() + text.slice(1);
}
/**
* Namespaces a block name if it is not already namespaced
* For example `namespaceBlock('stone')` returns `'minecraft:stone'`
*/
export function namespaceBlock(blockName: string): AppTypes.TNamespacedBlockName {
// https://minecraft.fandom.com/wiki/Resource_location#Namespaces
return isNamespacedBlock(blockName) ? blockName : ('minecraft:' + blockName);
}
export function isNamespacedBlock(blockName: string): boolean {
return blockName.includes(':');
}
}
}
/* eslint-disable */
export enum EAction {
Settings = 0,
Import = 1,
Materials = 2,
Voxelise = 3,
Assign = 4,
Export = 5,
MAX = 6,
}
/* eslint-enable */
export namespace AppTypes {
export type TNamespacedBlockName = string;
}
export type UV = { u: number, v: number };
export type TOptional<T> = T | undefined;
export function getRandomID(): string {
return (Math.random() + 1).toString(36).substring(7);
}

View File

@ -1,41 +0,0 @@
import { AppMath } from "../math";
export namespace OtS_ArrayUtil {
export function findFirstTrueIndex(length: number, valueAt: (index: number) => boolean) {
let low = 0;
let high = length - 1;
let result = -1;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
if (valueAt(mid) === true) {
result = mid;
high = mid - 1;
} else {
low = mid + 1;
}
}
return result;
}
/**
* An optimised function for repeating a subarray contained within a buffer multiple times by
* repeatedly doubling the subarray's length.
*/
export function repeatedFill(buffer: Float32Array, start: number, startLength: number, desiredCount: number) {
const pow = AppMath.largestPowerOfTwoLessThanN(desiredCount);
let len = startLength;
for (let i = 0; i < pow; ++i) {
buffer.copyWithin(start + len, start, start + len);
len *= 2;
}
const finalLength = desiredCount * startLength;
buffer.copyWithin(start + len, start, start + finalLength - len);
}
}

View File

@ -1,4 +1,4 @@
import { TBrand } from './util/type_util';
import { TBrand } from './types';
export type RGBA = {
r: number,

View File

@ -1,5 +1,5 @@
import { RGBA_255 } from './colour';
import { ASSERT } from './util/error_util';
import { ASSERT } from './util';
import { Vector3 } from './vector';
export class Ditherer {

View File

@ -1,6 +0,0 @@
export function ASSERT(condition: any, errorMessage: string = 'Assertion Failed'): asserts condition {
if (!condition) {
Error(errorMessage);
throw Error(errorMessage);
}
}

View File

@ -1,184 +0,0 @@
/**
* Logs to console and file if logging `LOG` is enabled.
* This should be used for verbose logs.
* @see LOG_MAJOR
*/
export const LOG = (...data: any[]) => {
if (Logger.Get.isLOGEnabled()) {
// eslint-disable-next-line no-console
console.log(...data);
}
};
export const LOGF = LOG;
/**
* Logs to console and file if logging `LOG_MAJOR` is enabled.
* This is identical to `LOG` but can be enabled/disabled separately.
* This should be used for important logs.
* @see LOG
*/
export const LOG_MAJOR = (...data: any[]) => {
if (Logger.Get.isLOGMAJOREnabled()) {
// eslint-disable-next-line no-console
console.log(...data);
}
};
/**
* Logs a warning to the console and file if logging `LOG_WARN` is enabled.
*/
export const LOG_WARN = (...data: any[]) => {
if (Logger.Get.isLOGWARNEnabled()) {
// eslint-disable-next-line no-console
console.warn(...data);
}
};
/**
* Starts a timer.
* @see `TIME_END` To stop the timer.
* @param label The ID of this timer.
*/
export const TIME_START = (label: string) => {
if (Logger.Get.isLOGTIMEEnabled()) {
// eslint-disable-next-line no-console
console.time(label);
}
};
/**
* Stops a timer and prints the time elapsed. Not logged to file.
* @see `TIME_START` To start the timer.
* @param label The ID of this timer.
*/
export const TIME_END = (label: string) => {
if (Logger.Get.isLOGTIMEEnabled()) {
// eslint-disable-next-line no-console
console.timeEnd(label);
}
};
/**
* Logs an error to the console and file, always.
*/
export const LOG_ERROR = (...data: any[]) => {
// eslint-disable-next-line no-console
console.error(...data);
};
/**
* Logger controls enable/disabling the logging functions above.
*/
export class Logger {
/* Singleton */
private static _instance: Logger;
public static get Get() {
return this._instance || (this._instance = new this());
}
private _enabledLOG: boolean;
private _enabledLOGMAJOR: boolean;
private _enabledLOGWARN: boolean;
private _enabledLOGTIME: boolean;
private _enabledLogToFile?: boolean;
private constructor() {
this._enabledLOG = false;
this._enabledLOGMAJOR = false;
this._enabledLOGWARN = false;
this._enabledLOGTIME = false;
}
/**
* Allow `LOG` calls to be printed to the console and to the log file if setup.
*/
public enableLOG() {
this._enabledLOG = true;
}
/**
* Prevent `LOG` calls to be printed to the console and to the log file if setup.
*/
public disableLOG() {
this._enabledLOG = false;
}
/**
* Allow `LOG_MAJOR` calls to be printed to the console and to the log file if setup.
*/
public enableLOGMAJOR() {
this._enabledLOGMAJOR = true;
}
/**
* Prevent `LOG_MAJOR` calls to be printed to the console and to the log file if setup.
*/
public disableLOGMAJOR() {
this._enabledLOGMAJOR = false;
}
/**
* Allow `LOG_WARN` calls to be printed to the console and to the log file if setup.
*/
public enableLOGWARN() {
this._enabledLOGWARN = true;
}
/**
* Prevent `LOG_WARN` calls to be printed to the console and to the log file if setup.
*/
public disableLOGWARN() {
this._enabledLOGWARN = false;
}
/**
* Allow `TIME_START`/`TIME_END` calls to be printed to the console and to the log file if setup.
*/
public enableLOGTIME() {
this._enabledLOGTIME = true;
}
/**
* Prevent `TIME_START`/`TIME_END` calls to be printed to the console and to the log file if setup.
*/
public disableLOGTIME() {
this._enabledLOGTIME = false;
}
/**
* Prevent console log calls to logged to the log file if setup.
*/
public disableLogToFile() {
this._enabledLogToFile = false;
}
/**
* Whether or not `LOG` calls should be printed to the console and log file.
*/
public isLOGEnabled() {
return this._enabledLOG;
}
/**
* Whether or not `LOG_MAJOR` calls should be printed to the console and log file.
*/
public isLOGMAJOREnabled() {
return this._enabledLOGMAJOR;
}
/**
* Whether or not `LOG_WARN` calls should be printed to the console and log file.
*/
public isLOGWARNEnabled() {
return this._enabledLOGWARN;
}
/**
* Whether or not `TIME_START`/`TIME_END` calls should be printed to the console and log file.
*/
public isLOGTIMEEnabled() {
return this._enabledLOGTIME;
}
}

View File

@ -1,18 +0,0 @@
export namespace MathUtil {
export function uint8(x: number) {
return x & 0xFF;
}
export function int8(x: number) {
return uint8(x + 0x80) - 0x80;
}
export function uint32(x: number) {
return x >>> 0;
}
export function int32(x: number) {
return uint32(x + 0x80000000) - 0x80000000;
}
}

View File

@ -1,7 +0,0 @@
import { NBT, writeUncompressed } from 'prismarine-nbt';
import pako from 'pako';
export function saveNBT(nbt: NBT) {
const uncompressedBuffer = writeUncompressed(nbt, 'big');
return pako.gzip(uncompressedBuffer);
}

View File

@ -1,5 +1,5 @@
import { OtS_Triangle } from './ots_mesh';
import { ASSERT } from './util/error_util';
import { OtS_Triangle } from '../ots_mesh';
import { ASSERT } from './util';
import { Vector3 } from './vector';
const EPSILON = 0.0000001;

View File

@ -1,71 +0,0 @@
/** Regex for non-zero whitespace */
export const REGEX_NZ_WS = /[ \t]+/;
/** Regex for number */
export const REGEX_NUMBER = /[0-9eE+\.\-]+/;
export const REGEX_NZ_ANY = /.+/;
export function regexCapture(identifier: string, regex: RegExp) {
return new RegExp(`(?<${identifier}>${regex.source}`);
}
export function regexOptional(regex: RegExp) {
return new RegExp(`(${regex})?`);
}
export function buildRegex(...args: (string | RegExp)[]) {
return new RegExp(args.map((r) => {
if (r instanceof RegExp) {
return r.source;
}
return r;
}).join(''));
}
export class RegExpBuilder {
private _components: string[];
public constructor() {
this._components = [];
}
public add(item: string | RegExp, capture?: string, optional: boolean = false): RegExpBuilder {
let regex: string;
if (item instanceof RegExp) {
regex = item.source;
} else {
regex = item;
}
if (capture) {
regex = `(?<${capture}>${regex})`;
}
if (optional) {
regex = `(${regex})?`;
}
this._components.push(regex);
return this;
}
public addMany(items: (string | RegExp)[], optional: boolean = false): RegExpBuilder {
let toAdd: string = '';
for (const item of items) {
if (item instanceof RegExp) {
toAdd += item.source;
} else {
toAdd += item;
}
}
this._components.push(optional ? `(${toAdd})?` : toAdd);
return this;
}
public addNonzeroWhitespace(): RegExpBuilder {
this.add(REGEX_NZ_WS);
return this;
}
public toRegExp(): RegExp {
return new RegExp(this._components.join(''));
}
}

View File

@ -21,4 +21,8 @@ export type BlockPalette = Set<string>;
export type Result<T, E = Error> =
| { ok: true, value: T }
| { ok: false, error: { code: E, message?: string } };
| { ok: false, error: { code: E, message?: string } };
export type UV = { u: number, v: number };
export type TOptional<T> = T | undefined;

248
Core/src/util/util.ts Normal file
View File

@ -0,0 +1,248 @@
import { NBT, writeUncompressed } from 'prismarine-nbt';
import pako from 'pako';
export function ASSERT(condition: any, errorMessage: string = 'Assertion Failed'): asserts condition {
if (!condition) {
Error(errorMessage);
throw Error(errorMessage);
}
}
// TODO: Move to Editor
export enum EAction {
Settings = 0,
Import = 1,
Materials = 2,
Voxelise = 3,
Assign = 4,
Export = 5,
MAX = 6,
}
export namespace OtS_Util {
export namespace Regex {
/** Regex for non-zero whitespace */
export const REGEX_NZ_WS = /[ \t]+/;
/** Regex for number */
export const REGEX_NUMBER = /[0-9eE+\.\-]+/;
export const REGEX_NZ_ANY = /.+/;
export function regexCapture(identifier: string, regex: RegExp) {
return new RegExp(`(?<${identifier}>${regex.source}`);
}
export function regexOptional(regex: RegExp) {
return new RegExp(`(${regex})?`);
}
export function buildRegex(...args: (string | RegExp)[]) {
return new RegExp(args.map((r) => {
if (r instanceof RegExp) {
return r.source;
}
return r;
}).join(''));
}
export class RegExpBuilder {
private _components: string[];
public constructor() {
this._components = [];
}
public add(item: string | RegExp, capture?: string, optional: boolean = false): RegExpBuilder {
let regex: string;
if (item instanceof RegExp) {
regex = item.source;
} else {
regex = item;
}
if (capture) {
regex = `(?<${capture}>${regex})`;
}
if (optional) {
regex = `(${regex})?`;
}
this._components.push(regex);
return this;
}
public addMany(items: (string | RegExp)[], optional: boolean = false): RegExpBuilder {
let toAdd: string = '';
for (const item of items) {
if (item instanceof RegExp) {
toAdd += item.source;
} else {
toAdd += item;
}
}
this._components.push(optional ? `(${toAdd})?` : toAdd);
return this;
}
public addNonzeroWhitespace(): RegExpBuilder {
this.add(REGEX_NZ_WS);
return this;
}
public toRegExp(): RegExp {
return new RegExp(this._components.join(''));
}
}
}
export namespace Text {
export function capitaliseFirstLetter(text: string) {
return text.charAt(0).toUpperCase() + text.slice(1);
}
/**
* Namespaces a block name if it is not already namespaced
* For example `namespaceBlock('stone')` returns `'minecraft:stone'`
*/
export function namespaceBlock(blockName: string): string {
// https://minecraft.fandom.com/wiki/Resource_location#Namespaces
return isNamespacedBlock(blockName) ? blockName : ('minecraft:' + blockName);
}
export function isNamespacedBlock(blockName: string): boolean {
return blockName.includes(':');
}
}
export namespace Numeric {
export const RADIANS_0 = 0.0;
export const RADIANS_90 = 1.5708;
export const RADIANS_180 = 3.14159;
export const RADIANS_270 = 4.71239;
export function getRandomID(): string {
return (Math.random() + 1).toString(36).substring(7);
}
export function uint8(x: number) {
return x & 0xFF;
}
export function int8(x: number) {
return uint8(x + 0x80) - 0x80;
}
export function uint32(x: number) {
return x >>> 0;
}
export function int32(x: number) {
return uint32(x + 0x80000000) - 0x80000000;
}
export function lerp(value: number, start: number, end: number) {
return (1 - value) * start + value * end;
}
export function nearlyEqual(a: number, b: number, tolerance: number = 0.0001) {
return Math.abs(a - b) < tolerance;
}
export function degreesToRadians(degrees: number) {
return degrees * (Math.PI / 180.0);
}
export function largestPowerOfTwoLessThanN(n: number) {
return Math.floor(Math.log2(n));
}
export const argMax = (array: [number]) => {
return array.map((x, i) => [x, i]).reduce((r, a) => (a[0] > r[0] ? a : r))[1];
};
export const clamp = (value: number, min: number, max: number) => {
return Math.max(Math.min(max, value), min);
};
export const floorToNearest = (value: number, base: number) => {
return Math.floor(value / base) * base;
};
export const ceilToNearest = (value: number, base: number) => {
return Math.ceil(value / base) * base;
};
export const roundToNearest = (value: number, base: number) => {
return Math.round(value / base) * base;
};
export const between = (value: number, min: number, max: number) => {
return min <= value && value <= max;
};
export const mapRange = (value: number, fromMin: number, fromMax: number, toMin: number, toMax: number) => {
return (value - fromMin) / (fromMax - fromMin) * (toMax - toMin) + toMin;
};
export const wayThrough = (value: number, min: number, max: number) => {
// ASSERT(value >= min && value <= max);
return (value - min) / (max - min);
};
/**
* Returs true if any number in args is NaN
*/
export const anyNaN = (...args: number[]) => {
return args.some((arg) => {
return isNaN(arg);
});
};
}
export namespace Array {
export function findFirstTrueIndex(length: number, valueAt: (index: number) => boolean) {
let low = 0;
let high = length - 1;
let result = -1;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
if (valueAt(mid) === true) {
result = mid;
high = mid - 1;
} else {
low = mid + 1;
}
}
return result;
}
/**
* An optimised function for repeating a subarray contained within a buffer multiple times by
* repeatedly doubling the subarray's length.
*/
export function repeatedFill(buffer: Float32Array, start: number, startLength: number, desiredCount: number) {
const pow = Numeric.largestPowerOfTwoLessThanN(desiredCount);
let len = startLength;
for (let i = 0; i < pow; ++i) {
buffer.copyWithin(start + len, start, start + len);
len *= 2;
}
const finalLength = desiredCount * startLength;
buffer.copyWithin(start + len, start, start + finalLength - len);
}
}
export namespace NBT {
export function saveNBT(nbt: NBT) {
const uncompressedBuffer = writeUncompressed(nbt, 'big');
return pako.gzip(uncompressedBuffer);
}
}
}

View File

@ -1,5 +1,4 @@
import { ASSERT } from './util/error_util';
import { Vector3Hash } from './util/type_util';
import { Vector3Hash } from './types';
export class Vector3 {
public x: number;
@ -25,8 +24,7 @@ export class Vector3 {
}
static fromArray(arr: number[]) {
ASSERT(arr.length === 3);
return new Vector3(arr[0], arr[1], arr[2]);
return new Vector3(arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0);
}
toArray() {