UNPKG

dashtools

Version:

Library for interacting with Geometry Dash servers

825 lines (770 loc) 29.7 kB
import * as utils from "../utils.js" export const OBJECT_IDS = { DEFAULT_BLOCK: 1, DEFAULT_SPIKE: 8, NORMAL_GRAVITY_PORTAL: 10, REVERSE_GRAVITY_PORTAL: 11, CUBE_PORTAL: 12, SHIP_PORTAL: 13, BG_COLOR_TRIGGER: 29, GROUND_COLOR_TRIGGER: 30, START_POSITION: 31, YELLOW_PAD: 35, YELLOW_ORB: 36, MIRROR_PORTAL: 45, UNMIRROR_PORTAL: 46, BALL_PORTAL: 47, BLUE_PAD: 67, BLUE_ORB: 84, NORMAL_SIZE_PORTAL: 99, MINI_SIZE_PORTAL: 101, OBJ_COLOR_TRIGGER: 105, UFO_PORTAL: 111, PINK_PAD: 140, PINK_ORB: 141, SECRET_COIN: 142, BREAKABLE_BLOCK: 143, SLOW_SPEED_PORTAL: 200, NORMAL_SPEED_PORTAL: 201, FAST_SPEED_PORTAL: 202, VERY_FAST_SPEED_PORTAL: 203, COLOR_1_TRIGGER: 221, DUAL_PORTAL: 286, UNDUAL_PORTAL: 287, WAVE_PORTAL: 660, COLOR_2_TRIGGER: 717, COLOR_3_TRIGGER: 718, COLOR_4_TRIGGER: 743, THREEDLINE_COLOR_TRIGGER: 744, ROBOT_PORTAL: 745, TELEPORT_PORTAL: 747, COLOR_TRIGGER: 899, GROUND2_COLOR_TRIGGER: 900, MOVE_TRIGGER: 901, TEXT: 914, LINE_COLOR_TRIGGER: 915, PULSE_TRIGGER: 1006, ALPHA_TRIGGER: 1007, GREEN_ORB: 1022, TOGGLE_TRIGGER: 1049, SPAWN_TRIGGER: 1268, BLACK_ORB: 1330, SPIDER_PORTAL: 1331, RED_PAD: 1332, RED_ORB: 1333, VERY_VERY_FAST_SPEED_PORTAL: 1334, ROTATE_TRIGGER: 1346, TOGGLE_ORB: 1594, COUNT_TRIGGER: 1611, COUNTER: 1615, STOP_TRIGGER: 1616, DASH_ORB: 1704, PINK_DASH_ORB: 1751, D_BLOCK: 1755, INSTANT_COUNT_TRIGGER: 1811, J_BLOCK: 1813, COLLISION_TRIGGER: 1815, COLLISION_BLOCK: 1816, PICKUP_TRIGGER: 1817, S_BLOCK: 1829, H_BLOCK: 1859, RANDOM_TRIGGER: 1912, SWING_PORTAL: 1933, CHECKPOINT: 2063, ORANGE_TELEPORT_PORTAL: 2064, PARTICLE_EMITTER: 2065, SCALE_TRIGGER: 2067, SQUARE_FORCE_BLOCK: 2069, F_BLOCK: 2866, TEMPLATE_BLOCK: 2895, TEMPLATE_SLOPE: 2896, TEMPLATE_GENTLE_SLOPE: 2897, OPTIONS_TRIGGER: 2899, BLUE_TELEPORT_PORTAL: 2902, SHADER_TRIGGER: 2904, SHOCKWAVE_SHADER_TRIGGER: 2905, FLIP_GRAVITY_PORTAL: 2926, SPIDER_ORB: 3004, SPIDER_PAD: 3005, TELEPORT_ORB: 3027, END_TRIGGER: 3600, SFX_TRIGGER: 3602, EDIT_SFX_TRIGGER: 3603, EVENT_TRIGGER: 3604, EDIT_SONG_TRIGGER: 3605, BG_SPEED_TRIGGER: 3606, SEQUENCE_TRIGGER: 3607, SPAWN_PARTICLE_TRIGGER: 3608, INSTANT_COLLISION_TRIGGER: 3609, HAZARD_SQUARE: 3610, HAZARD_CIRCLE: 3611, MG_SPEED_TRIGGER: 3612, UI_TRIGGER: 3613, TIME_TRIGGER: 3614, TIME_EVENT_TRIGGER: 3615, TIME_CONTROL_TRIGGER: 3617, RESET_TRIGGER: 3618, ITEM_EDIT_TRIGGER: 3619, ITEM_COMP_TRIGGER: 3620, ITEM_PERS_TRIGGER: 3641, BPM_TRIGGER: 3642, CIRCLE_FORCE_BLOCK: 3645 } for (let i of Object.entries(OBJECT_IDS)) { OBJECT_IDS[i[1]] = i[0] } export const ROTATING_OBJECTS = [85, 86, 87, 88, 89, 97, 98, 137, 138, 139, 154, 155, 156, 180, 181, 182, 183, 184, 185, 186, 187, 188, 222, 223, 224, 375, 376, 377, 378, 394, 395, 396, 397, 398, 399, 675, 676, 677, 678, 679, 680, 740, 741, 742, 997, 998, 999, 1000, 1019, 1020, 1021, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1582, 1619, 1620, 1705, 1706, 1707, 1708, 1709, 1710, 1734, 1735, 1736, 1752, 1831, 1832, 1833, 1834] export const ROTATING_ORBS = [1022, 1330] export const ANIMATED_OBJECTS = [920, 921, 923, 924, 1050, 1051, 1052, 1053, 1054, 1329, 1516, 1518, 1519, 1583, 1591, 1592, 1593, 1618, 1697, 1698, 1699, 1839, 1840, 1841, 1842, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1860, 1936, 1937, 1938, 1939, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2223, 2246, 2605, 2629, 2630, 2694, 2864, 2865, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 3000, 3001, 3002, 3119, 3120, 3121, 3219, 3303, 3304, 3482, 3483, 3484, 3492, 3493, 4211, 4300] export const Z_LAYERS = { "-5": "B5", "-3": "B4", "-1": "B3", "1": "B2", "3": "B1", "5": "T1", "7": "T2", "9": "T3", "11": "T4", B5: -5, B4: -3, B3: -1, B2: 1, B1: 3, T1: 5, T2: 7, T3: 9, T4: 11 } export const TRIGGER_LAYERS = { BG: 1, MG: 2, B5: 3, B4: 4, B3: 5, B2: 6, B1: 7, P: 8, T1: 9, T2: 10, T3: 11, T4: 12, G: 13, UI: 14, MAX: 15, 1: "BG", 2: "MG", 3: "B5", 4: "B4", 5: "B3", 6: "B2", 7: "B1", 8: "P", 9: "T1", 10: "T2", 11: "T3", 12: "T4", 13: "G", 14: "UI", 15: "MAX" } export const EASINGS = { 0: "NONE", 1: "EASE_IN_OUT", 2: "EASE_IN", 3: "EASE_OUT", 4: "ELASTIC_IN_OUT", 5: "ELASTIC_IN", 6: "ELASTIC_OUT", 7: "BOUNCE_IN_OUT", 8: "BOUNCE_IN", 9: "BOUNCE_OUT", 10: "EXPONENTIAL_IN_OUT", 11: "EXPONENTIAL_IN", 12: "EXPONENTIAL_OUT", 13: "SINE_IN_OUT", 14: "SINE_IN", 15: "SINE_OUT", 16: "BACK_IN_OUT", 17: "BACK_IN", 18: "BACK_OUT", } export class LevelData { constructor(version) { version = Number(version) if (isNaN(version) || version < 10 || version > 22 || Math.floor(version) != version) { throw new Error("Invalid level version. Acceptable values are 10-22") } this.settings = new LevelSettings() this.objects = [] this.version = version } static fromString(string) { let b64 = utils.base64DecodeBuffer(string) let str = utils.tryUnzip(b64) if (Buffer.compare(b64, Buffer.from(str)) == 0) { str = string } return str } toString() { } addObject(object) { this.objects.push(object) } } export class LevelSettings { constructor(opts) { this.colors = {} for (let i of Object.entries(opts)) { this[i[0]] = i[1] } } toString() { } } export class LevelObject { constructor(id, x, y) { this.id = parseInt(id) || 1 this.x = parseFloat(x) || 0 this.y = parseFloat(y) || 0 } static fromString(string) { let dict = utils.robTopSplitDict(string.split(";")[0], ",") let obj = new LevelObject(dict["1"], dict["2"], dict["3"]) function importBool(key, name) { if (!!Number(dict[key])) obj[name] = true } function importInt(key, name) { if (Number(dict[key])) obj[name] = parseInt(dict[key]) || 0 } importBool("96", "noGlow") importBool("134", "passable") importBool("511", "extendedCollision") importBool("136", "nonStickX") importBool("289", "nonStickY") importBool("495", "extraSticky") importBool("496", "dontBoostY") importBool("509", "dontBoostX") importBool("356", "scaleStick") importBool("372", "noAudioScale") importInt("497", "singleColorType") importBool("137", "ice") importBool("193", "gripSlope") importBool("121", "noTouch") importInt("343", "enterChannel") importInt("446", "material") importBool("4", "flipH") importBool("5", "flipV") importInt("108", "linkedGroup") importInt("20", "layer") importInt("61", "layer2") importBool("103", "highDetail") if (dict["57"]) obj.groupIDs = dict["57"].split(".").map(e => parseInt(e)) if (dict["274"]) obj.groupParentIDs = dict["274"].split(".").map(e => parseInt(e)) importBool("64", "dontFade") importBool("67", "dontEnter") importBool("116", "noEffects") importBool("507", "noParticles") importInt("155", "unk155") importInt("156", "unk156") importInt("53", "unk53") importInt("25", "zOrder") importInt("131", "rotationY") importInt("132", "rotationX") if (!obj.rotationY && !obj.rotationX) importInt("6", "rotation") importInt("21", "baseColorID") importInt("22", "detailColorID") importInt("24", "zLayer") importInt("128", "scaleX") importInt("129", "scaleY") if (!obj.scaleY && !obj.scaleX) importInt("32", "scale") importBool("34", "groupParent") importBool("279", "areaParent") importBool("41", "baseHSVEnabled") importBool("42", "detailHSVEnabled") if (dict["43"]) obj.baseHSV = HSV.fromString(dict["43"]) if (dict["44"]) obj.detailHSV = HSV.fromString(dict["44"]) return obj } toString() { let str = `1,${this.id},2,${this.x},3,${this.y}` function exportBool(key, name) { if (this[name]) str += `,${key},1` } function exportInt(key, name, val) { if (!val) { if (this[name]) str += `,${key},${parseInt(this[name])}` } else { if (this[name] != val) str += `,${key},${parseInt(this[name])}` } } exportBool("96", "noGlow") exportBool("134", "passable") exportBool("511", "extendedCollision") exportBool("136", "nonStickX") exportBool("289", "nonStickY") exportBool("495", "extraSticky") exportBool("496", "dontBoostY") exportBool("509", "dontBoostX") exportBool("356", "scaleStick") exportBool("372", "noAudioScale") exportInt("497", "singleColorType") exportBool("137", "ice") exportBool("193", "gripSlope") exportBool("121", "noTouch") exportInt("343", "enterChannel") exportInt("446", "material") exportBool("4", "flipH") exportBool("5", "flipV") exportInt("108", "linkedGroup") exportInt("20", "layer") exportInt("61", "layer2") exportBool("103", "highDetail") if (this.groupIDs) str += `,57,${this.groupIDs.join(".")}` if (this.groupParentIDs) str += `,274,${this.groupParentIDs.join(".")}` exportBool("64", "dontFade") exportBool("67", "dontEnter") exportBool("116", "noEffects") exportBool("507", "noParticles") exportInt("155", "unk155") exportInt("156", "unk156") exportInt("53", "unk53") exportInt("25", "zOrder") if (this.rotation) { str += `,6,${this.rotation}` } else if (this.rotationX || this.rotationY) { if (this.rotationX == this.rotationY) { str += `,6,` } else { str += `,131,${parseInt(this.rotationY) || 0},132,` } str += `${parseInt(this.rotationX) || 0}` } exportInt("21", "baseColorID") exportInt("22", "detailColorID") exportInt("24", "zLayer") exportInt("32", "scale", 1) exportInt("128", "scaleX", 1) exportInt("129", "scaleY", 1) exportBool("34", "groupParent") exportBool("279", "areaParent") if (this.baseHSV) { str += `,41,1,43,${this.baseHSV}` } if (this.detailHSV) { str += `,42,1,44,${this.detailHSV}` } return str } } export class RotatingObject extends LevelObject { constructor(id, x, y, rotationSpeed, disableRotation) { super(id, x, y) this.rotationSpeed = parseInt(rotationSpeed) || 0 this.disableRotation = !!disableRotation } static fromString(string) { let dict = utils.robTopSplitDict(string.split(";")[0], ",") let obj = super.fromString(string) function importBool(key, name) { if (!!Number(dict[key])) obj[name] = true } function importInt(key, name) { if (Number(dict[key])) obj[name] = parseInt(dict[key]) || 0 } importInt("97", "rotationSpeed") importBool("98", "disableRotation") return obj } toString() { let str = super.toString() function exportBool(key, name) { if (this[name]) str += `,${key},1` } function exportInt(key, name, val) { if (!val) { if (this[name]) str += `,${key},${parseInt(this[name])}` } else { if (this[name] != val) str += `,${key},${parseInt(this[name])}` } } exportInt("97", "rotationSpeed") exportBool("98", "disableRotation") return str } } export class AnimatedObject extends LevelObject { constructor(id, x, y, rotationSpeed, disableRotation) { super(id, x, y) this.rotationSpeed = parseInt(rotationSpeed) || 0 this.disableRotation = !!disableRotation } static fromString(string) { let dict = utils.robTopSplitDict(string.split(";")[0], ",") let obj = super.fromString(string) function importBool(key, name) { if (!!Number(dict[key])) obj[name] = true } function importInt(key, name) { if (Number(dict[key])) obj[name] = parseInt(dict[key]) || 0 } function importFloat(key, name) { if (Number(dict[key])) obj[name] = parseFloat(dict[key]) || 0 } importBool("106", "randomizeStart") importBool("126", "disableDelayedLoop") importBool("122", "useSpeed") importFloat("107", "animationSpeed") importBool("127", "disableAnimShine") importBool("123", "animateOnTrigger") importBool("214", "onlyIfActive") importInt("462", "singleFrame") importBool("592", "offsetAnim") return obj } toString() { let str = super.toString() function exportBool(key, name) { if (this[name]) str += `,${key},1` } function exportInt(key, name, val) { if (!val) { if (this[name]) str += `,${key},${parseInt(this[name])}` } else { if (this[name] != val) str += `,${key},${parseInt(this[name])}` } } function exportFloat(key, name) { if (Number(dict[key])) obj[name] = parseFloat(dict[key]) || 0 } exportBool("106", "randomizeStart") exportBool("126", "disableDelayedLoop") exportBool("122", "useSpeed") exportFloat("107", "animationSpeed") exportBool("127", "disableAnimShine") exportBool("123", "animateOnTrigger") exportBool("214", "onlyIfActive") exportInt("462", "singleFrame") exportBool("592", "offsetAnim") return str } } export class ParticleEmitter extends AnimatedObject { constructor(x, y, particleData, animateOnTrigger, animateActiveOnly) { super(OBJECT_IDS.PARTICLE_EMITTER, x, y) this.particleData = particleData this.animateOnTrigger = !!animateOnTrigger this.onlyIfActive = !!animateActiveOnly } static fromString(string) { let dict = utils.robTopSplitDict(string.split(";")[0], ",") let obj = super.fromString(string) function importBool(key, name) { if (!!Number(dict[key])) obj[name] = true } if (dict["145"]) obj.particleData = ParticleData.fromString(dict["145"]) importBool("146", "useObjColor") if (!!Number(dict["147"])) obj.particleData.uniformObjColor = true importBool("211", "quickStart") return obj } toString() { let str = super.toString() function exportBool(key, name) { if (this[name]) str += `,${key},1` } if (this.particleData) str += `,145,${obj.particleData}` exportBool("146", "useObjColor") if (this.particleData.uniformObjColor) str += `,147,1` exportBool("211", "quickStart") return str } } export class Trigger extends LevelObject { constructor(id, x, y) { super(id, x, y) } } export class MoveTrigger extends LevelObject { constructor(x, y, groupId, ) { super(OBJECT_IDS.MOVE_TRIGGER, x, y) this.rotationSpeed = parseInt(rotationSpeed) || 0 this.disableRotation = !!disableRotation } static fromString(string) { let dict = utils.robTopSplitDict(string.split(";")[0], ",") let obj = super.fromString(string) function importBool(key, name) { if (!!Number(dict[key])) obj[name] = true } function importInt(key, name) { if (Number(dict[key])) obj[name] = parseInt(dict[key]) || 0 } importInt("97", "rotationSpeed") importBool("98", "disableRotation") return obj } toString() { let str = super.toString() function exportBool(key, name) { if (this[name]) str += `,${key},1` } function exportInt(key, name, val) { if (!val) { if (this[name]) str += `,${key},${parseInt(this[name])}` } else { if (this[name] != val) str += `,${key},${parseInt(this[name])}` } } exportInt("97", "rotationSpeed") exportBool("98", "disableRotation") return str } } export class Color { constructor(id, red, green, blue, opacity, blending) { this.id = id this.red = red this.green = green this.blue = blue this.opacity = opacity || 1 this.blending = !!blending this.enableOpacity = true } toString() { let string = `1_${this.red}_2_${this.green}_3_${this.blue}_6_${this.id}` if (this.playerColor) string += `_4_${this.playerColor}` if (this.blending) string += `_5_${Number(!!this.blending)}` if (this.opacity) string += `_7_${this.opacity}` if (this.enableOpacity != undefined) string += `_8_${Number(!!this.enableOpacity)}` if (this.copiedColor) string += `_9_${this.copiedColor}` if (this.hsv) string += `_10_${this.hsv.toString()}` if (this.copyOpacity) string += `_17_${Number(!!this.copyOpacity)}` } } export class TextObject extends LevelObject { constructor(x, y, text, kerning) { super(OBJECT_IDS.TEXT_OBJECT, x, y) this.text = text this.kerning = kerning || 0 } static fromString(string) { let dict = utils.robTopSplitDict(string.split(";")[0], ",") let obj = super.fromString(string) if (dict["31"]) obj.text = utils.base64Decode(dict["31"]) if (Number(dict["488"])) obj.kerning = parseInt(dict["488"]) || 0 return obj } toString() { let str = super.toString() if (this.text) str += `,31,${utils.base64Encode(this.text)}` if (Number(this.kerning)) str += `,488,${parseInt(this.kerning) || 0}` return str } } export class ShaderTrigger extends LevelObject { constructor(x, y, lowestLayer, highestLayer, noPlayerParticles, disableAll, touchTrigger, spawnTrigger, multiTrigger) { super(OBJECT_IDS.SHADER_TRIGGER, x, y) this.lowestLayer = parseInt(lowestLayer) || TRIGGER_LAYERS.BG this.highestLayer = parseInt(highestLayer) || TRIGGER_LAYERS.MAX this.shaderParam13 = !!noPlayerParticles this.shaderParam17 = !!disableAll this.touchTriggered = !!touchTrigger this.spawnTriggered = !!spawnTrigger this.multiTriggered = !!multiTrigger } } export class ShockwaveShaderTrigger extends LevelObject { constructor(x, y, opts, touchTrigger, spawnTrigger, multiTrigger) { // speed, strength, thickness, waveW, fadeIn, fadeOut, timeOff, maxSize, invert, target, relative, screenOffX, screenOffY, centerID, p1, p2, follow, inner, outer, animate, fadeTime, easing, super(OBJECT_IDS.SHOCKWAVE_SHADER_TRIGGER, x, y) this.shaderParam1 = parseFloat(opts.speed) || 1 this.shaderParam2 = parseFloat(opts.strength) || 1 this.shockTimeOff = parseFloat(opts.timeOff) || 0 this.shaderParam4 = parseFloat(opts.waveW) || 1 this.shaderParam5 = parseFloat(opts.thickness) || 1 this.shaderParam6 = parseFloat(opts.fadeIn) || 1 this.shaderParam7 = parseFloat(opts.fadeOut) || 1 this.shockWaveInner = parseFloat(opts.inner) || 0 this.shockInvert = !!opts.invert this.shaderParam13 = !!opts.target this.shaderParam15 = !!opts.follow this.shaderParam16 = parseFloat(opts.outer) || 1 this.targetGroupID = parseInt(opts.centerID) || 0 this.touchTriggered = !!touchTrigger this.spawnTriggered = !!spawnTrigger this.multiTriggered = !!multiTrigger } } export class HSV { constructor(hue, saturation, value, saturationAbsolute, valueAbsolute) { this.hue = (hue && !isNaN(Number(hue))) ? Number(hue) : 0 this.saturation = (saturation && !isNaN(Number(saturation))) ? Number(saturation) : 1 this.value = (value && !isNaN(Number(value))) ? Number(value) : 1 this.saturationAbsolute = !!saturationAbsolute this.valueAbsolute = !!valueAbsolute } static fromString(string) { let values = string.split("a") return new HSV(Number(values[0]), Number(values[1]), Number(values[2]), !!Number(values[3]), !!Number(values[4])) } toString() { return `${this.hue}a${this.saturation}a${this.value}a${Number(!!this.saturationAbsolute)}a${Number(!!this.valueAbsolute)}` } } export class ParticleData { constructor() { // 30a-1a1a0.3a30a90a90a29a0a11a0a0a0a0a0a0a0a2a1a0a0a1a0a1a0a1a0a1a0a1a1a0a0a1a0a1a0a1a0a1a0a0a0a0a0a0a0a0a0a0a0a0a2a1a0a0a0a0a0a0a0a0a0a0 this.maxParticles = 30 this.duration = -1 this.lifetime = 1 this.lifetimeMargin = 0.3 this.emission = 30 this.angle = 90 this.angleMargin = 90 this.speed = 29 this.speedMargin = 0 this.posVarX = 11 this.posVarY = 0 this.gravityX = 0 this.gravityY = 0 this.accelRad = 0 this.accelRadMargin = 0 this.accelTan = 0 this.accelTanMargin = 0 this.startSize = 2 this.startSizeMargin = 1 this.startSpin = 2 this.startSpinMargin = 1 this.startRed = 1 this.startRedMargin = 0 this.startGreen = 1 this.startGreenMargin = 0 this.startBlue = 1 this.startBlueMargin = 0 this.startAlpha = 1 this.startAlphaMargin = 0 this.endSize = 2 this.endSizeMargin = 1 this.endSpin = 2 this.endSpinMargin = 1 this.endRed = 1 this.endRedMargin = 0 this.endGreen = 1 this.endGreenMargin = 0 this.endBlue = 1 this.endBlueMargin = 0 this.endAlpha = 1 this.endAlphaMargin = 0 this.fadeIn = 0 this.fadeInMargin = 0 this.fadeOut = 0 this.fadeOutMargin = 0 this.startRad = 0 this.startRadMargin = 0 this.endRad = 0 this.endRadMargin = 0 this.rotSec = 0 this.rotSecMargin = 0 this.mode = 0 this.extraMode = 0 this.additiveColor = true this.startSpinEqualsEnd = false this.startRotIsDir = false this.dynamicRotation = false this.texture = 0 this.uniformObjColor = false this.frictionP = 0 this.frictionPMargin = 0 this.respawn = 0 this.respawnMargin = 0 this.orderSensitive = false this.startSizeEqualsEnd = false this.startRGBVarSync = false this.endRGBVarSync = false this.frictionS = 0 this.frictionSMargin = 0 this.frictionR = 0 this.frictionRMargin = 0 } static fromString(string) { let values = string.split("a") let particle = new ParticleData() particle.maxParticles = Number(values[0]) particle.duration = Number(values[1]) particle.lifetime = Number(values[2]) particle.lifetimeMargin = Number(values[3]) particle.emission = Number(values[4]) particle.angle = Number(values[5]) particle.angleMargin = Number(values[6]) particle.speed = Number(values[7]) particle.speedMargin = Number(values[8]) particle.posVarX = Number(values[9]) particle.posVarY = Number(values[10]) particle.gravityX = Number(values[11]) particle.gravityY = Number(values[12]) particle.accelRad = Number(values[13]) particle.accelRadMargin = Number(values[14]) particle.accelTan = Number(values[15]) particle.accelTanMargin = Number(values[16]) particle.startSize = Number(values[17]) particle.startSizeMargin = Number(values[18]) particle.startSpin = Number(values[19]) particle.startSpinMargin = Number(values[20]) particle.startRed = Number(values[21]) particle.startRedMargin = Number(values[22]) particle.startGreen = Number(values[23]) particle.startGreenMargin = Number(values[24]) particle.startBlue = Number(values[25]) particle.startBlueMargin = Number(values[26]) particle.startAlpha = Number(values[27]) particle.startAlphaMargin = Number(values[28]) particle.endSize = Number(values[29]) particle.endSizeMargin = Number(values[30]) particle.endSpin = Number(values[31]) particle.endSpinMargin = Number(values[32]) particle.endRed = Number(values[33]) particle.endRedMargin = Number(values[34]) particle.endGreen = Number(values[35]) particle.endGreenMargin = Number(values[36]) particle.endBlue = Number(values[37]) particle.endBlueMargin = Number(values[38]) particle.endAlpha = Number(values[39]) particle.endAlphaMargin = Number(values[40]) particle.fadeIn = Number(values[41]) particle.fadeInMargin = Number(values[42]) particle.fadeOut = Number(values[43]) particle.fadeOutMargin = Number(values[44]) particle.startRad = Number(values[45]) particle.startRadMargin = Number(values[46]) particle.endRad = Number(values[47]) particle.endRadMargin = Number(values[48]) particle.rotSec = Number(values[49]) particle.rotSecMargin = Number(values[50]) particle.mode = Number(values[51]) particle.extraMode = Number(values[52]) particle.additiveColor = !!Number(values[53]) particle.startSpinEqualsEnd = !!Number(values[54]) particle.startRotIsDir = !!Number(values[55]) particle.dynamicRotation = !!Number(values[56]) particle.texture = Number(values[57]) particle.uniformObjColor = !!Number(values[58]) particle.frictionP = Number(values[59]) particle.frictionPMargin = !!Number(values[60]) particle.respawn = Number(values[61]) particle.respawnMargin = Number(values[62]) particle.orderSensitive = !!Number(values[63]) particle.startSizeEqualsEnd = !!Number(values[64]) particle.startRGBVarSync = !!Number(values[65]) particle.endRGBVarSync = !!Number(values[66]) particle.frictionS = Number(values[67]) particle.frictionSMargin = Number(values[68]) particle.frictionR = Number(values[69]) particle.frictionRMargin = Number(values[70]) return particle } toString() { return `${Number(this.maxParticles)}a${Number(this.duration)}a${Number(this.lifetime)}a${Number(this.lifetimeMargin)}a${Number(this.emission)}a${Number(this.angle)}a${Number(this.angleMargin)}a${Number(this.speed)}a${Number(this.speedMargin)}a${Number(this.posVarX)}a${Number(this.posVarY)}a${Number(this.gravityX)}a${Number(this.gravityY)}a${Number(this.accelRad)}a${Number(this.accelRadMargin)}a${Number(this.accelTan)}a${Number(this.accelTanMargin)}a${Number(this.startSize)}a${Number(this.startSizeMargin)}a${Number(this.startSpin)}a${Number(this.startSpinMargin)}a${Number(this.startRed)}a${Number(this.startRedMargin)}a${Number(this.startGreen)}a${Number(this.startGreenMargin)}a${Number(this.startBlue)}a${Number(this.startBlueMargin)}a${Number(this.startAlpha)}a${Number(this.startAlphaMargin)}a${Number(this.endSize)}a${Number(this.endSizeMargin)}a${Number(this.endSpin)}a${Number(this.endSpinMargin)}a${Number(this.endRed)}a${Number(this.endRedMargin)}a${Number(this.endGreen)}a${Number(this.endGreenMargin)}a${Number(this.endBlue)}a${Number(this.endBlueMargin)}a${Number(this.endAlpha)}a${Number(this.endAlphaMargin)}a${Number(this.fadeIn)}a${Number(this.fadeInMargin)}a${Number(this.fadeOut)}a${Number(this.fadeOutMargin)}a${Number(this.startRad)}a${Number(this.startRadMargin)}a${Number(this.endRad)}a${Number(this.endRadMargin)}a${Number(this.rotSec)}a${Number(this.rotSecMargin)}a${Number(this.mode)}a${Number(this.extraMode)}a${Number(this.additiveColor)}a${Number(this.startSpinEqualsEnd)}a${Number(this.startRotIsDir)}a${Number(this.dynamicRotation)}a${Number(this.texture)}a${Number(this.uniformObjColor)}a${Number(this.frictionP)}a${Number(this.frictionPMargin)}a${Number(this.respawn)}a${Number(this.respawnMargin)}a${Number(this.orderSensitive)}a${Number(this.startSizeEqualsEnd)}a${Number(this.startRGBVarSync)}a${Number(this.endRGBVarSync)}a${Number(this.frictionS)}a${Number(this.frictionSMargin)}a${Number(this.frictionR)}a${Number(this.frictionRMargin)}` } }