From 0b3ad3f76bb04ef18849b568f404e56f23cf73bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Fri, 27 May 2022 01:03:06 -0400 Subject: [PATCH 01/60] Refactoring, formatting, etc... --- iconkit/icon.js | 151 +++++++++++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 67 deletions(-) diff --git a/iconkit/icon.js b/iconkit/icon.js index c2bb1125..5a1416b6 100644 --- a/iconkit/icon.js +++ b/iconkit/icon.js @@ -18,7 +18,7 @@ function positionPart(part, partIndex, layer, formName, isGlow) { let tintInfo = iconData.robotAnimations.info[formName].tints let foundTint = tintInfo[partIndex] if (foundTint > 0) { - let darkenFilter = new PIXI.filters.ColorMatrixFilter(); + let darkenFilter = new PIXI.filters.ColorMatrixFilter() darkenFilter.brightness(0) darkenFilter.alpha = (255 - foundTint) / 255 layer.filters = [darkenFilter] @@ -26,9 +26,10 @@ function positionPart(part, partIndex, layer, formName, isGlow) { } } -function validNum(val, defaultVal) { +function sanitizeNum(val, defaultVal) { let colVal = +val - return isNaN(colVal) ? defaultVal : colVal + //yes, it also checks for NaN + return isFinite(colVal) ? colVal : defaultVal } function getGlowColor(colors) { @@ -37,8 +38,8 @@ function getGlowColor(colors) { return glowCol } -function validateIconID(id, form) { - let realID = Math.min(iconData.iconCounts[form], Math.abs(validNum(id, 1))) +function sanitizeIconID(id, form) { + let realID = Math.min(iconData.iconCounts[form], Math.abs(sanitizeNum(id, 1))) if (realID == 0 && !["player", "player_ball"].includes(form)) realID = 1 return realID } @@ -47,7 +48,7 @@ function parseIconColor(col) { if (!col) return WHITE else if (typeof col == "string" && col.length >= 6) return parseInt(col, 16) let rgb = iconData.colors[col] - return rgb ? rgbToDecimal(rgb) : WHITE; + return rgb ? rgb2Pac(rgb) : WHITE } function parseIconForm(form) { @@ -56,35 +57,41 @@ function parseIconForm(form) { } function loadIconLayers(form, id, cb) { - let texturesToLoad = Object.keys(iconData.gameSheet).filter(x => x.startsWith(`${form}_${padZero(validateIconID(id, form))}_`)) - loader.add(texturesToLoad.filter(x => !loader.resources[x]).map(x => ({ name: x, url: `/iconkit/icons/${x}` }))) + let texturesToLoad = Object.keys(iconData.gameSheet) + .filter(x => x.startsWith(`${form}_${padZero(sanitizeIconID(id, form))}_`)) + loader.add(texturesToLoad + .filter(x => !loader.resources[x]) + .map(x => ({ name: x, url: `/iconkit/icons/${x}` })) + ) loader.load(cb) } -function padZero(num) { - let numStr = num.toString() - if (num < 10) numStr = "0" + numStr - return numStr -} +function padZero(num) { return num.toString().padStart(2, "0") } -function rgbToDecimal(rgb) { - return (rgb.r << 16) + (rgb.g << 8) + rgb.b; -} +/* +name explanation: +`Number`s are not decimals, because they are not `String`s, and the internal representation is binary. +This means "rgbToDecimal" is a misleading name. +Converting independent color components into one number is called "color packing". +So I thougth it would be funny to rename "rgbToPacked" into "rgb2Pac". +Alternative names could be "rgbPacker" or "packRGB", IDK +*/ +function rgb2Pac(rgb) { return (rgb.r << 16) | (rgb.g << 8) | rgb.b } class Icon { constructor(data={}, cb) { this.app = data.app - this.sprite = new PIXI.Container(); + this.sprite = new PIXI.Container() this.form = data.form || "player" - this.id = validateIconID(data.id, this.form) + this.id = sanitizeIconID(data.id, this.form) this.colors = { - "1": validNum(data.col1, 0xafafaf), // primary - "2": validNum(data.col2, WHITE), // secondary - "g": validNum(data.colG, validNum(+data.colg, null)), // glow - "w": validNum(data.colW, validNum(+data.colw, WHITE)), // white - "u": validNum(data.colU, validNum(+data.colu, WHITE)), // ufo + "1": sanitizeNum(data.col1, 0xafafaf), // primary + "2": sanitizeNum(data.col2, WHITE), // secondary + "g": sanitizeNum(data.colG, sanitizeNum(+data.colg, null)), // glow + "w": sanitizeNum(data.colW, sanitizeNum(+data.colw, WHITE)), // white + "u": sanitizeNum(data.colU, sanitizeNum(+data.colu, WHITE)), // ufo } - + this.glow = !!data.glow this.layers = [] this.glowLayers = [] @@ -107,17 +114,17 @@ class Icon { x.name = iconData.robotAnimations.info[this.form].names[y] let part = new IconPart(this.form, this.id, this.colors, false, { part: x, skipGlow: true }) positionPart(x, y, part.sprite, this.form) - + let glowPart = new IconPart(this.form, this.id, this.colors, true, { part: x, onlyGlow: true }) positionPart(x, y, glowPart.sprite, this.form, true) glowPart.sprite.visible = this.glow this.glowLayers.push(glowPart) - + this.layers.push(part) this.sprite.addChild(part.sprite) }) - - let fullGlow = new PIXI.Container(); + + let fullGlow = new PIXI.Container() this.glowLayers.forEach(x => fullGlow.addChild(x.sprite)) this.sprite.addChildAt(fullGlow, 0) if (typeof Ease !== "undefined") this.ease = new Ease.Ease() @@ -134,14 +141,16 @@ class Icon { getAllLayers() { let allLayers = []; - (this.complex ? this.glowLayers : []).concat(this.layers).forEach(x => x.sections.forEach(s => allLayers.push(s))) + (this.complex ? this.glowLayers : []) + .concat(this.layers) + .forEach(x => x.sections.forEach(s => allLayers.push(s))) return allLayers } setColor(colorType, newColor, extra={}) { let colorStr = String(colorType).toLowerCase() - if (!colorType || !Object.keys(this.colors).includes(colorStr)) return - else this.colors[colorStr] = newColor + if (!colorType || this.colors[colorStr] === undefined) return + this.colors[colorStr] = newColor let newGlow = getGlowColor(this.colors) this.getAllLayers().forEach(x => { if (colorType != "g" && x.colorType == colorStr) x.setColor(newColor) @@ -153,13 +162,9 @@ class Icon { } } - formName() { - return formNames[this.form] || this.form - } + formName() { return formNames[this.form] || this.form } - isGlowing() { - return this.glowLayers[0].sprite.visible - } + isGlowing() { return this.glowLayers[0].sprite.visible } setGlow(toggle) { this.glow = !!toggle @@ -201,9 +206,9 @@ class Icon { let bothSections = [section, glowSection] bothSections.forEach((x, y) => { - let easing = this.ease.add(x.sprite, movementData, { duration: duration || 1, ease: 'linear' }) + let easing = this.ease.add(x.sprite, movementData, { duration: duration || 1, ease: "linear" }) let continueAfterEase = animData.frames.length > 1 && y == 0 && index == 0 && animName == this.animationName - if (continueAfterEase) easing.on('complete', () => { + if (continueAfterEase) easing.on("complete", () => { this.animationFrame++ if (this.animationFrame >= animData.frames.length) { if (animData.info.loop) this.animationFrame = 0 @@ -217,7 +222,7 @@ class Icon { autocrop() { // find actual icon size by reading pixel data (otherwise there's whitespace and shit) let spriteSize = [Math.round(this.sprite.width), Math.round(this.sprite.height)] - let pixels = this.app.renderer.plugins.extract.pixels(this.sprite); + let pixels = this.app.renderer.plugins.extract.pixels(this.sprite) let xRange = [spriteSize[0], 0] let yRange = [spriteSize[1], 0] @@ -245,7 +250,7 @@ class Icon { xRange[1] += 4 yRange[1] += 6 } - + let realWidth = xRange[1] - xRange[0] let realHeight = yRange[1] - yRange[0] @@ -264,29 +269,29 @@ class Icon { toDataURL(dataType="image/png") { this.autocrop() - this.app.renderer.render(this.app.stage); - let b64data = this.app.view.toDataURL(dataType); + this.app.renderer.render(this.app.stage) + let b64data = this.app.view.toDataURL(dataType) this.revertCrop() return b64data } pngExport() { let b64data = this.toDataURL() - let downloader = document.createElement('a'); + let downloader = document.createElement("a") downloader.href = b64data - downloader.setAttribute("download", `${this.formName()}_${this.id}.png`); - document.body.appendChild(downloader); - downloader.click(); - document.body.removeChild(downloader); + downloader.setAttribute("download", `${this.formName()}_${this.id}.png`) + document.body.appendChild(downloader) + downloader.click() + document.body.removeChild(downloader) } copyToClipboard() { this.autocrop() - this.app.renderer.render(app.stage); + this.app.renderer.render(app.stage) this.app.view.toBlob(blob => { - let item = new ClipboardItem({ "image/png": blob }); - navigator.clipboard.write([item]); - }); + let item = new ClipboardItem({ "image/png": blob }) + navigator.clipboard.write([item]) + }) this.revertCrop() } @@ -304,10 +309,10 @@ class Icon { function addPSDLayer(layer, parent, sprite) { allLayers.forEach(x => x.sprite.alpha = 0) layer.sprite.alpha = 255 - + let layerChild = { name: layer.colorName, canvas: renderer.plugins.extract.canvas(sprite) } if (layer.colorType == "g") { - if (parent.part) layerChild.name = parent.part.name + " glow" + if (parent.part) layerChild.name = `${parent.part.name} glow` else layerChild.blendMode = "linear dodge" if (!complex && !glowing) layerChild.hidden = true } @@ -332,13 +337,13 @@ class Icon { allLayers.forEach(x => x.sprite.alpha = 255) let output = agPsd.writePsd(psd) - let blob = new Blob([output]); - let downloader = document.createElement('a'); - downloader.href = URL.createObjectURL(blob); - downloader.setAttribute("download", `${this.formName()}_${this.id}.psd`); - document.body.appendChild(downloader); - downloader.click(); - document.body.removeChild(downloader); + let blob = new Blob([output]) + let downloader = document.createElement("a") + downloader.href = URL.createObjectURL(blob) + downloader.setAttribute("download", `${this.formName()}_${this.id}.psd`) + document.body.appendChild(downloader) + downloader.click() + document.body.removeChild(downloader) this.setGlow(glowing) } } @@ -349,11 +354,11 @@ class IconPart { if (colors[1] == 0 && !misc.skipGlow) glow = true // add glow if p1 is black let iconPath = `${form}_${padZero(id)}` - let partString = misc.part ? "_" + padZero(misc.part.part) : "" + let partString = misc.part ? `_${padZero(misc.part.part)}` : "" let sections = {} if (misc.part) this.part = misc.part - this.sprite = new PIXI.Container(); + this.sprite = new PIXI.Container() this.sections = [] if (!misc.skipGlow) { @@ -376,11 +381,23 @@ class IconPart { } } - let layerOrder = ["glow", "ufo", "col2", "col1", "white"].map(x => sections[x]).filter(x => x) - layerOrder.forEach(x => { + let layerOrder = ["glow", "ufo", "col2", "col1", "white"] + for (let x of layerOrder) { + x = sections[x] + if (!x) continue this.sections.push(x) this.sprite.addChild(x.sprite) - }) + }/* + if the compiler doesn't optimize enough, + this would iterate 3 times and make shallow copies of the array each call. + + layerOrder.map(x => sections[x]) + .filter(x => x) + .forEach(x => { + this.sections.push(x) + this.sprite.addChild(x.sprite) + }) + */ } } @@ -399,7 +416,7 @@ class IconLayer { } setColor(color) { - this.color = validNum(color, WHITE) + this.color = sanitizeNum(color, WHITE) this.sprite.tint = this.color } } \ No newline at end of file From 5886f33bb7e734cedfeb9454900be7fae1d2e2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Sat, 28 May 2022 22:12:25 -0400 Subject: [PATCH 02/60] Fixed some whitespaces --- misc/global.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/misc/global.js b/misc/global.js index fd994f2f..1a68b794 100644 --- a/misc/global.js +++ b/misc/global.js @@ -14,7 +14,6 @@ $(window).resize(function () { $('#everything').hide(); $('#tooSmall').show(); } - else { $('#everything').show(); $('#tooSmall').hide() @@ -22,7 +21,7 @@ $(window).resize(function () { }); function saveUrl() { - if (window.location.href.endsWith('?download')) return; + if (window.location.href.endsWith('?download')) return; sessionStorage.setItem('prevUrl', window.location.href); } @@ -153,4 +152,4 @@ $.fn.isInViewport = function () { let viewportTop = $(window).scrollTop(); let viewportBottom = viewportTop + $(window).height(); return elementBottom > viewportTop && elementTop < viewportBottom; -}; \ No newline at end of file +}; From 32d0dee7eac19cadd81b1626938cade35f69aadc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Sat, 28 May 2022 22:46:33 -0400 Subject: [PATCH 03/60] Replaced `if` by `||=` --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 865e2c9e..776fda7f 100644 --- a/index.js +++ b/index.js @@ -80,8 +80,8 @@ app.use(async function(req, res, next) { if (req.query.online > 0) req.offline = false req.gdParams = function(obj={}, substitute=true) { - Object.keys(app.config.params).forEach(x => { if (!obj[x]) obj[x] = app.config.params[x] }) - Object.keys(req.server.extraParams || {}).forEach(x => { if (!obj[x]) obj[x] = req.server.extraParams[x] }) + Object.keys(app.config.params).forEach(x => obj[x] ||= app.config.params[x]) + Object.keys(req.server.extraParams || {}).forEach(x => obj[x] ||= req.server.extraParams[x]) let ip = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] let params = {form: obj, headers: app.config.ipForwarding && ip ? {'x-forwarded-for': ip, 'x-real-ip': ip} : {}} @@ -379,4 +379,4 @@ app.use(function (err, req, res, next) { process.on('uncaughtException', (e) => { console.log(e) }); process.on('unhandledRejection', (e, p) => { console.log(e) }); -app.listen(app.config.port, () => console.log(`Site online! (port ${app.config.port})`)) \ No newline at end of file +app.listen(app.config.port, () => console.log(`Site online! (port ${app.config.port})`)) From 2cd72fa71b3cef0135b883d5222713ff715167ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Sat, 28 May 2022 23:27:36 -0400 Subject: [PATCH 04/60] Update index.js --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 776fda7f..b436aa96 100644 --- a/index.js +++ b/index.js @@ -24,7 +24,7 @@ const RL = rateLimit({ max: app.config.rateLimiting ? 100 : 0, // max requests per 5 minutes message: rlMessage, keyGenerator: function(req) { return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] }, - skip: function(req) { return ((req.url.includes("api/level") && !req.query.hasOwnProperty("download")) ? true : false) } + skip: function(req) { return (req.url.includes("api/level") && !req.query.hasOwnProperty("download")) } }) const RL2 = rateLimit({ @@ -173,7 +173,7 @@ app.parseResponse = function (responseBody, splitter=":") { } //xss bad -app.clean = function(text) {if (!text || typeof text != "string") return text; else return text.replace(/&/g, "&").replace(//g, ">").replace(/=/g, "=").replace(/"/g, """).replace(/'/g, "'")} +app.clean = function(text) {return !text || typeof text != "string" ? text : text.replace(/./gs, c => {"&": "&", "<": "<", ">": ">", "=": "=", '"': """, "'": "'"}[c] || c)} // ASSETS From b7eb348d079bb868125412dcb3fbecf97ee6ae47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Sat, 28 May 2022 23:33:10 -0400 Subject: [PATCH 05/60] Forgot parentheses lol --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index b436aa96..05f7a595 100644 --- a/index.js +++ b/index.js @@ -173,7 +173,7 @@ app.parseResponse = function (responseBody, splitter=":") { } //xss bad -app.clean = function(text) {return !text || typeof text != "string" ? text : text.replace(/./gs, c => {"&": "&", "<": "<", ">": ">", "=": "=", '"': """, "'": "'"}[c] || c)} +app.clean = function(text) {return !text || typeof text != "string" ? text : text.replace(/./gs, c => ({"&": "&", "<": "<", ">": ">", "=": "=", '"': """, "'": "'"}[c] || c))} // ASSETS From f7c5e12dfe4c8e9a5698fe678433a63fb31cc995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Sat, 28 May 2022 23:41:49 -0400 Subject: [PATCH 06/60] Using `Object.hasOwn` instead of checking `undefined` --- iconkit/icon.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iconkit/icon.js b/iconkit/icon.js index 5a1416b6..f0f66807 100644 --- a/iconkit/icon.js +++ b/iconkit/icon.js @@ -127,7 +127,7 @@ class Icon { let fullGlow = new PIXI.Container() this.glowLayers.forEach(x => fullGlow.addChild(x.sprite)) this.sprite.addChildAt(fullGlow, 0) - if (typeof Ease !== "undefined") this.ease = new Ease.Ease() + if (typeof Ease != "undefined") this.ease = new Ease.Ease() this.animationSpeed = Math.abs(Number(data.animationSpeed) || 1) if (data.animation) this.setAnimation(data.animation, data.animationForm) } @@ -149,7 +149,7 @@ class Icon { setColor(colorType, newColor, extra={}) { let colorStr = String(colorType).toLowerCase() - if (!colorType || this.colors[colorStr] === undefined) return + if (!colorType || !Object.hasOwn(this.colors, colorStr)) return this.colors[colorStr] = newColor let newGlow = getGlowColor(this.colors) this.getAllLayers().forEach(x => { @@ -419,4 +419,4 @@ class IconLayer { this.color = sanitizeNum(color, WHITE) this.sprite.tint = this.color } -} \ No newline at end of file +} From 6eb5accbf41c53f78259c17733d2ba2e01222980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 13:16:45 -0400 Subject: [PATCH 07/60] patch-1 --- iconkit/icon.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/iconkit/icon.js b/iconkit/icon.js index e099ed64..fa163a9d 100644 --- a/iconkit/icon.js +++ b/iconkit/icon.js @@ -7,8 +7,9 @@ const loadedNewIcons = {} let positionMultiplier = 4 function positionPart(part, partIndex, layer, formName, isNew, isGlow) { - layer.position.x += (part.pos[0] * positionMultiplier * (isNew ? 0.5 : 1)) - layer.position.y -= (part.pos[1] * positionMultiplier * (isNew ? 0.5 : 1)) + let truePosMultiplier = positionMultiplier / (isNew ? 2 : 1) + layer.position.x += (part.pos[0] * truePosMultiplier) + layer.position.y -= (part.pos[1] * truePosMultiplier) layer.scale.x = part.scale[0] layer.scale.y = part.scale[1] if (part.flipped[0]) layer.scale.x *= -1 @@ -22,7 +23,7 @@ function positionPart(part, partIndex, layer, formName, isNew, isGlow) { if (foundTint > 0) { let darkenFilter = new PIXI.filters.ColorMatrixFilter() darkenFilter.brightness(0) - darkenFilter.alpha = (255 - foundTint) / 255 + darkenFilter.alpha = (255 - foundTint) / 255 // same as `1 - foundTint / 0xff` layer.filters = [darkenFilter] } } @@ -124,7 +125,7 @@ function parseNewPlist(data) { let textureArr = keyData.slice(1, -1).split("},{").map(x => parseWeirdArray(x)) positionData[frameName].pos = textureArr[0] positionData[frameName].size = textureArr[1] - } + } } if (isRotated) positionData[frameName].size.reverse() @@ -160,9 +161,9 @@ class Icon { this.colors = { "1": sanitizeNum(data.col1, 0xafafaf), // primary "2": sanitizeNum(data.col2, WHITE), // secondary - "g": sanitizeNum(data.colG, sanitizeNum(+data.colg, null)), // glow - "w": sanitizeNum(data.colW, sanitizeNum(+data.colw, WHITE)), // white - "u": sanitizeNum(data.colU, sanitizeNum(+data.colu, WHITE)), // ufo + "g": sanitizeNum(data.colG, sanitizeNum(data.colg, null)), // glow + "w": sanitizeNum(data.colW, sanitizeNum(data.colw, WHITE)), // white + "u": sanitizeNum(data.colU, sanitizeNum(data.colu, WHITE)), // ufo } this.glow = !!data.glow @@ -188,7 +189,7 @@ class Icon { let part = new IconPart(this.form, this.id, this.colors, false, { part: x, skipGlow: true, new: this.new }) positionPart(x, y, part.sprite, this.form, this.new) - + let glowPart = new IconPart(this.form, this.id, this.colors, true, { part: x, onlyGlow: true, new: this.new }) positionPart(x, y, glowPart.sprite, this.form, this.new, true) @@ -265,7 +266,7 @@ class Icon { animData.frames[this.animationFrame].forEach((newPart, index) => { let section = this.layers[index] let glowSection = this.glowLayers[index] - let truePosMultiplier = this.new ? positionMultiplier * 0.5 : positionMultiplier + let truePosMultiplier = positionMultiplier / (this.new ? 2 : 1) if (!section) return // gd is weird with negative rotations @@ -371,7 +372,7 @@ class Icon { } psdExport() { - if (typeof agPsd === "undefined") throw new Error("ag-psd not imported!") + if (typeof agPsd == "undefined") throw new Error("ag-psd not imported!") let glowing = this.isGlowing() this.setGlow(true) @@ -461,9 +462,8 @@ class IconPart { if (!x) continue this.sections.push(x) this.sprite.addChild(x.sprite) - }/* - if the compiler doesn't optimize enough, - this would iterate 3 times and make shallow copies of the array each call. + } + /* alternative: layerOrder.map(x => sections[x]) .filter(x => x) From cf7313c7d6e92a61dde96a58520b87311f32f508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 13:35:15 -0400 Subject: [PATCH 08/60] patch-1 --- classes/XOR.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/classes/XOR.js b/classes/XOR.js index 87287ca0..b798ccb9 100644 --- a/classes/XOR.js +++ b/classes/XOR.js @@ -1,5 +1,8 @@ +//converts input base64 into its URL-safe variant +let toURLsafe = str => str.replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)) + module.exports = class XOR { - xor(str, key) { return String.fromCodePoint(...str.split('').map((char, i) => char.charCodeAt(0) ^ key.toString().charCodeAt(i % key.toString().length))) } - encrypt(str, key = 37526) { return Buffer.from(this.xor(str, key)).toString('base64').replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)); } - decrypt(str, key = 37526) { return this.xor(Buffer.from(str.replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)), 'base64').toString(), key) } + xor(str, key) { return String.fromCodePoint(...str.split('').map((c, i) => c.charCodeAt(0) ^ key.toString().charCodeAt(i % key.toString().length))) } + encrypt(str, key = 37526) { return toURLsafe(Buffer.from(this.xor(str, key)).toString('base64')) } + decrypt(str, key = 37526) { return this.xor(Buffer.from(toURLsafe(str), 'base64').toString(), key) } } From e9f84b69b17a2668aba1e83339758c2c663f657c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 13:51:49 -0400 Subject: [PATCH 09/60] patch-1 --- classes/XOR.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/classes/XOR.js b/classes/XOR.js index b798ccb9..692f5366 100644 --- a/classes/XOR.js +++ b/classes/XOR.js @@ -1,8 +1,8 @@ //converts input base64 into its URL-safe variant -let toURLsafe = str => str.replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)) - +//let toURLsafe = str => str.replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)) +//https://nodejs.org/docs/latest/api/buffer.html#buffers-and-character-encodings module.exports = class XOR { xor(str, key) { return String.fromCodePoint(...str.split('').map((c, i) => c.charCodeAt(0) ^ key.toString().charCodeAt(i % key.toString().length))) } - encrypt(str, key = 37526) { return toURLsafe(Buffer.from(this.xor(str, key)).toString('base64')) } - decrypt(str, key = 37526) { return this.xor(Buffer.from(toURLsafe(str), 'base64').toString(), key) } -} + encrypt(str, key = 37526) { return Buffer.from(this.xor(str, key)).toString('base64url') } + decrypt(str, key = 37526) { return this.xor(Buffer.from(str, 'base64').toString(), key) } +} \ No newline at end of file From e2f7bcbb4720f1b5ba1f29f2345c55deaadb676d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 14:16:00 -0400 Subject: [PATCH 10/60] p --- classes/XOR.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/classes/XOR.js b/classes/XOR.js index 692f5366..51bbb4e6 100644 --- a/classes/XOR.js +++ b/classes/XOR.js @@ -1,8 +1,16 @@ -//converts input base64 into its URL-safe variant -//let toURLsafe = str => str.replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)) //https://nodejs.org/docs/latest/api/buffer.html#buffers-and-character-encodings +//both only work on "binary strings" and "URI-safe B64" +let toB64 = str => Buffer.from(str).toString('base64url') +let fromB64 = str => Buffer.from(str, 'base64').toString() + +const defKey = 37526 + module.exports = class XOR { - xor(str, key) { return String.fromCodePoint(...str.split('').map((c, i) => c.charCodeAt(0) ^ key.toString().charCodeAt(i % key.toString().length))) } - encrypt(str, key = 37526) { return Buffer.from(this.xor(str, key)).toString('base64url') } - decrypt(str, key = 37526) { return this.xor(Buffer.from(str, 'base64').toString(), key) } + xor(str, key) { + key = key.toString() + return String.fromCodePoint(...str.split('') + .map((c, i) => c.charCodeAt(0) ^ key.charCodeAt(i % key.length))) + } + encrypt(str, key = defKey) { return toB64(this.xor(str, key)) } + decrypt(str, key = defKey) { return this.xor(fromB64(str), key) } } \ No newline at end of file From 0c6c1a1ac99b474f38f91de2e211103b8c379b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 14:45:29 -0400 Subject: [PATCH 11/60] Added radian converters --- iconkit/icon.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iconkit/icon.js b/iconkit/icon.js index fa163a9d..e60cd60e 100644 --- a/iconkit/icon.js +++ b/iconkit/icon.js @@ -5,6 +5,12 @@ const loader = PIXI.Loader.shared const loadedNewIcons = {} +const TAU = Math.PI * 2 +//by default, converts degrees to rads +const toRadians = (angle, perigon = 360) => TAU / perigon * angle +//by default, converts rad to deg +const fromRadians = (rad, perigon = 360) => rad / (TAU / perigon) + let positionMultiplier = 4 function positionPart(part, partIndex, layer, formName, isNew, isGlow) { let truePosMultiplier = positionMultiplier / (isNew ? 2 : 1) @@ -278,7 +284,7 @@ class Icon { y: newPart.pos[1] * truePosMultiplier * -1, scaleX: newPart.scale[0], scaleY: newPart.scale[1], - rotation: realRot * (Math.PI / 180) // radians + rotation: toRadians(realRot) } if (newPart.flipped[0]) movementData.scaleX *= -1 if (newPart.flipped[1]) movementData.scaleY *= -1 From e3e1342adbf13a99bbd144544f2b6edd5e24c48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 14:57:45 -0400 Subject: [PATCH 12/60] Replaced `perigon` by `scale` --- iconkit/icon.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iconkit/icon.js b/iconkit/icon.js index e60cd60e..6bafb3dd 100644 --- a/iconkit/icon.js +++ b/iconkit/icon.js @@ -7,9 +7,10 @@ const loadedNewIcons = {} const TAU = Math.PI * 2 //by default, converts degrees to rads -const toRadians = (angle, perigon = 360) => TAU / perigon * angle +const toRadians = (angle, scale = 360) => TAU / scale * angle //by default, converts rad to deg -const fromRadians = (rad, perigon = 360) => rad / (TAU / perigon) +const fromRadians = (rad, scale = 360) => rad / (TAU / scale) +//`scale` is the num of subdivisions in a cycle. More info: https://en.wikipedia.org/wiki/Turn_(angle) let positionMultiplier = 4 function positionPart(part, partIndex, layer, formName, isNew, isGlow) { From 3d68f0e464385c2b79d031a4b34d0d68cdcff606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 17:03:49 -0400 Subject: [PATCH 13/60] icon.js and global.js --- iconkit/icon.js | 9 +++++---- misc/global.js | 45 +++++++++++++++++++++++---------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/iconkit/icon.js b/iconkit/icon.js index 6bafb3dd..472bea1a 100644 --- a/iconkit/icon.js +++ b/iconkit/icon.js @@ -6,11 +6,12 @@ const loader = PIXI.Loader.shared const loadedNewIcons = {} const TAU = Math.PI * 2 -//by default, converts degrees to rads +// by default, converts degrees to rads const toRadians = (angle, scale = 360) => TAU / scale * angle -//by default, converts rad to deg +// by default, converts rad to deg const fromRadians = (rad, scale = 360) => rad / (TAU / scale) -//`scale` is the num of subdivisions in a cycle. More info: https://en.wikipedia.org/wiki/Turn_(angle) +// `scale` is the num of subdivisions in a cycle. More info: https://en.wikipedia.org/wiki/Turn_(angle) +// `scale = 400` corresponds to gradians, `256` to byte radians, and `100` to percentage of a turn let positionMultiplier = 4 function positionPart(part, partIndex, layer, formName, isNew, isGlow) { @@ -38,7 +39,7 @@ function positionPart(part, partIndex, layer, formName, isNew, isGlow) { function sanitizeNum(val, defaultVal) { let colVal = +val - //yes, it also checks for NaN + // yes, it also checks for NaN return isFinite(colVal) ? colVal : defaultVal } diff --git a/misc/global.js b/misc/global.js index 4a65a7b2..8e083877 100644 --- a/misc/global.js +++ b/misc/global.js @@ -10,26 +10,27 @@ $('body').append(` $(window).resize(function () { - if (window.innerHeight > window.innerWidth - 75) { - $('#everything').hide(); - $('#tooSmall').show(); - } - else { - $('#everything').show(); - $('#tooSmall').hide() - } + //these alternatives maybe helpful: https://stackoverflow.com/a/4917796 + let portrait = window.innerHeight > window.innerWidth - 75 + $('#everything')[portrait ? 'hide' : 'show']() + $('#tooSmall')[portrait ? 'show' : 'hide']() }); +let isDownloadURL = () => window.location.href.endsWith('?download') + function saveUrl() { - if (window.location.href.endsWith('?download')) return; - sessionStorage.setItem('prevUrl', window.location.href); + if ( !isDownloadURL() ) sessionStorage.setItem('prevUrl', window.location.href); } function backButton() { - if (window.history.length > 1 && document.referrer.startsWith(window.location.origin)){ - if (window.location.href.endsWith('?download') && sessionStorage.getItem('prevUrl') === window.location.href.replace('?download', '')) window.history.go(-2); - else window.history.back() - } + if (window.history.length > 1 && document.referrer.startsWith(window.location.origin)) { + let steps = ( + isDownloadURL() && + sessionStorage.getItem('prevUrl') === window.location.href.replace('?download', '') + ? -2 : -1 + ) + window.history.go(steps) + } else window.location.href = "../../../../../" } @@ -47,14 +48,14 @@ function Fetch(link) { }) } -let allowEsc = true; -let popupEsc = true; +let allowEsc = true +let popupEsc = true $(document).keydown(function(k) { if (k.keyCode == 27) { //esc if (!allowEsc) return k.preventDefault() - if (popupEsc && $('.popup').is(":visible")) $('.popup').hide(); + if (popupEsc && $('.popup').is(":visible")) $('.popup').hide(); else $('#backButton').trigger('click') } }); @@ -71,9 +72,9 @@ async function renderIcons() { if (overrideLoader) return let iconsToRender = $('gdicon:not([rendered], [dontload])') if (iconsToRender.length < 1) return - if (!iconData) iconData = await Fetch("../api/icons") - if (!iconCanvas) iconCanvas = document.createElement('canvas') - if (!iconRenderer) iconRenderer = new PIXI.Application({ view: iconCanvas, width: 300, height: 300, backgroundAlpha: 0}); + iconData ||= await Fetch("../api/icons") + iconCanvas ||= document.createElement('canvas') + iconRenderer ||= new PIXI.Application({ view: iconCanvas, width: 300, height: 300, backgroundAlpha: 0}); if (loader.loading) return overrideLoader = true buildIcon(iconsToRender, 0) } @@ -120,9 +121,9 @@ function finishIcon(currentIcon, name, data) { } // reset scroll -while ($(this).scrollTop() != 0) { +while ($(this).scrollTop() != 0) $(this).scrollTop(0); -} + $(document).ready(function() { $(window).trigger('resize'); From 6f700502fc3cf9485ad20ca4ac0d0943ab498149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 17:29:30 -0400 Subject: [PATCH 14/60] Finished `global.js` (I guess) --- misc/global.js | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/misc/global.js b/misc/global.js index 8e083877..2bac94a1 100644 --- a/misc/global.js +++ b/misc/global.js @@ -29,8 +29,8 @@ function backButton() { sessionStorage.getItem('prevUrl') === window.location.href.replace('?download', '') ? -2 : -1 ) - window.history.go(steps) - } + window.history.go(steps) + } else window.location.href = "../../../../../" } @@ -52,12 +52,11 @@ let allowEsc = true let popupEsc = true $(document).keydown(function(k) { - if (k.keyCode == 27) { //esc - if (!allowEsc) return - k.preventDefault() - if (popupEsc && $('.popup').is(":visible")) $('.popup').hide(); - else $('#backButton').trigger('click') - } + const ESC = 27 + if (k.keyCode != ESC || !allowEsc) return; + k.preventDefault() + if (popupEsc && $('.popup').is(":visible")) $('.popup').hide(); + else $('#backButton').trigger('click') }); let iconData = null @@ -126,32 +125,31 @@ while ($(this).scrollTop() != 0) $(document).ready(function() { - $(window).trigger('resize'); -}); + $(window).trigger('resize') +}) // Adds all necessary elements into the tab index (all buttons and links that aren't natively focusable) -const inaccessibleLinkSelector = "*:not(a) > img.gdButton, .leaderboardTab, .gdcheckbox, .diffDiv, .lengthDiv"; +const inaccessibleLinkSelector = "*:not(a) > img.gdButton, .leaderboardTab, .gdcheckbox, .diffDiv, .lengthDiv" -document.querySelectorAll(inaccessibleLinkSelector).forEach(elem => { - elem.setAttribute('tabindex', 0); -}) +document.querySelectorAll(inaccessibleLinkSelector) + .forEach(elem => { elem.setAttribute('tabindex', 0) }) document.getElementById('backButton')?.setAttribute('tabindex', 1); // Prioritize back button, first element to be focused // Event listener to run a .click() function if window.addEventListener("keydown", e => { - if(e.key !== 'Enter') return; + if(e.key !== 'Enter') return - const active = document.activeElement; - const isUnsupportedLink = active.hasAttribute('tabindex'); // Only click on links that aren't already natively supported to prevent double clicking - if(isUnsupportedLink) active.click(); + const active = document.activeElement + const isUnsupportedLink = active.hasAttribute('tabindex') // Only click on links that aren't already natively supported to prevent double clicking + if(isUnsupportedLink) active.click(); }) // stolen from stackoverflow $.fn.isInViewport = function () { - let elementTop = $(this).offset().top; - let elementBottom = elementTop + $(this).outerHeight(); - let viewportTop = $(window).scrollTop(); - let viewportBottom = viewportTop + $(window).height(); - return elementBottom > viewportTop && elementTop < viewportBottom; -}; + let elementTop = $(this).offset().top + let elementBottom = elementTop + $(this).outerHeight() + let viewportTop = $(window).scrollTop() + let viewportBottom = viewportTop + $(window).height() + return elementBottom > viewportTop && elementTop < viewportBottom +} From 51e676fee3d2088ddb85f85b5511854d241683ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 17:52:23 -0400 Subject: [PATCH 15/60] dragscroll.js --- misc/dragscroll.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/misc/dragscroll.js b/misc/dragscroll.js index 8646f7f9..948fc18d 100644 --- a/misc/dragscroll.js +++ b/misc/dragscroll.js @@ -1,7 +1,7 @@ function somethingSelected() { return typeof window.getSelection == 'function' && window.getSelection().toString() != ""; } -const remover = / |\n|\t/g; +const remover = / |\n|\t/g; //should it be /\s/g ? $('.dragscroll').each(function(_, el) { let previouslyMouseDown = false; el.addEventListener('mousemove', function(e) { @@ -13,13 +13,15 @@ $('.dragscroll').each(function(_, el) { } return; } - if (somethingSelected()) - return; + if (somethingSelected()) return; if (!previouslyMouseDown) { - for (let el of e.target.childNodes) { - if (el.nodeType === Node.TEXT_NODE && el.textContent.replace(remover, '').length) - return; - } + if ([...e.target.childNodes].some( + el => el.nodeType === Node.TEXT_NODE + && + el.textContent.replace(remover, '').length + ) + ) return; + el.style['user-select'] = 'none'; el.style['-webkit-user-select'] = 'none'; previouslyMouseDown = true; From 5b3da23417aa2559889bfba336270de47390ac9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Tue, 14 Jun 2022 17:56:06 -0400 Subject: [PATCH 16/60] I added too much indent, fixed now --- misc/dragscroll.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/misc/dragscroll.js b/misc/dragscroll.js index 948fc18d..c48589b6 100644 --- a/misc/dragscroll.js +++ b/misc/dragscroll.js @@ -16,11 +16,11 @@ $('.dragscroll').each(function(_, el) { if (somethingSelected()) return; if (!previouslyMouseDown) { if ([...e.target.childNodes].some( - el => el.nodeType === Node.TEXT_NODE - && - el.textContent.replace(remover, '').length - ) - ) return; + el => el.nodeType === Node.TEXT_NODE + && + el.textContent.replace(remover, '').length + ) + ) return; el.style['user-select'] = 'none'; el.style['-webkit-user-select'] = 'none'; From bc155225a4d000a040c71d3e6b5cb90230aca193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Wed, 15 Jun 2022 10:40:44 -0400 Subject: [PATCH 17/60] Added `randRange` --- html/home.html | 18 +++++++++--------- misc/global.js | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/html/home.html b/html/home.html index 99ed630f..6689b67e 100644 --- a/html/home.html +++ b/html/home.html @@ -40,14 +40,14 @@
- + - +
- +
- +
-
- +
+
@@ -35,8 +35,8 @@

Settings<

Cursed animations

(Hover over a setting for information)

- - + + @@ -45,14 +45,14 @@

Settings<

Enable 2.2 icons?

The newest update for Geometry Dash Lite revealed 500 new icons across all forms. Enabling this setting will reveal all these icons, however they will be lower quality since no UHD textures were provided.

THIS WILL REVEAL EVERY ICON.
PRESS CANCEL IF YOU DON'T WANT TO BE SPOILED!!!

- - - + + + -
- +
+
@@ -60,14 +60,14 @@
@@ -34,7 +34,7 @@

Saved!

[[NAME]] has been added to your saved levels list.

- + @@ -44,8 +44,8 @@

Delete Level

Are you sure you want to delete this level from your saved levels list?

- - + + @@ -55,15 +55,15 @@

Level Analysis

Level analysis is currently blocked by RobTop. We don't know when or if it will be re-enabled.
(click to try anyways)

- +
- +
- +
@@ -93,31 +93,31 @@

[[NAME]]

By [[AUTHOR]]

- - - + + +


#[[DAILYNUMBER]]

- +

[[DIFFICULTY]]

-

[[STARS]]


-

[[DIAMONDS]]

-

#[[DEMONLIST]]

+

[[STARS]]


+

[[DIAMONDS]]

+

#[[DEMONLIST]]

- +

[[DOWNLOADS]]


- +

[[LIKES]]


- +

[[LENGTH]]


- +

[[ORBS]]

@@ -129,16 +129,16 @@

[[ORBS]]

[[SONGNAME]]

By: [[SONGAUTHOR]]

- + --> +
- +
@@ -146,20 +146,20 @@

SongID: [[SONGID]]   

- +
-
-
- -
-
-
+
+
+ +
+
+
- +

- + - + @@ -29,9 +29,9 @@

GD Password

- - @@ -40,7 +40,7 @@

GD Password

- +
@@ -52,25 +52,25 @@

Messages
- + - -
- +
-
-
@@ -84,19 +84,19 @@

Delete

Are you sure you want to delete this message?

- - + + @@ -111,9 +111,9 @@

Bulk Delete

Are you sure you want to delete ?

- - @@ -121,12 +121,12 @@

Bulk Delete

Delete

Deleting ...

- + @@ -136,16 +136,16 @@

Delete

- - - + @@ -176,19 +176,19 @@

- +

Sending...

@@ -197,15 +197,15 @@

- +
- +
- +
@@ -213,7 +213,7 @@

- + - + @@ -15,7 +15,7 @@

RobTop's Purgatory

 

- +
- +
- +
- +
- +
- +
- +
- -
+ +
- + @@ -26,16 +26,16 @@

GD Password

- - + + @@ -58,43 +58,43 @@

User Info

Private Messages: [[DMS]]
Comment History: [[COMMENTS]]

- +
- +
- +
- +
-

[[RANK]]

+

[[RANK]]

- [[USERNAME]]


- [[STARS]] - [[DIAMONDS]] - [[COINS]] - [[USERCOINS]] - [[DEMONS]] - + [[STARS]] + [[DIAMONDS]] + [[COINS]] + [[USERCOINS]] + [[DEMONS]] +

- - + +

Account ID: [[ACCOUNTID]]
Player ID: [[PLAYERID]]

- - + + - - + + - +
- - - + + +
- +
- +
- +
@@ -153,9 +153,9 @@

- - - + + + - + @@ -18,15 +18,15 @@

Jump to Page


- - + +
- +
- +
@@ -37,8 +37,8 @@

Delete All

Delete all saved online levels?
Levels will be cleared from your browser.

- - + + @@ -49,16 +49,16 @@

Random Level

A random level cannot be picked with your current search filters! This is because there is no way to tell how many results were found, due to the GD servers inaccurately saying there's 9999.

- +
- +
- +
- +
- +
- +
- +
- +
- + - + @@ -16,44 +16,44 @@
- +
- +
- +
- - + +
@@ -92,7 +92,7 @@

Achievements

let formStr = ["Icon", "Ship", "Ball", "UFO", "Wave", "Robot", "Spider", "Trail", "Death Effect", "Primary Color", "Secondary Color", "Misc"] forms.concat(["trail", "deathEffect", "color1", "color2", "misc"]).forEach((x, y) => { - $('#forms').append(``) + $('#forms').append(``) }) function append(reset=true) { @@ -126,11 +126,10 @@

`) + $('#types').append(``) }) -achievements = ach.achievements -colors = ach.colors +{achievements, colors} = ach append() function label(labelName) { @@ -163,9 +162,8 @@

- + - - - + + + + @@ -19,13 +20,13 @@

Something Went Wrong!

An unknown error occured while trying to analyze this level.

- +

Analyzing level...

- +
- +
@@ -107,11 +108,13 @@

Level Data

let disabledPortals = [] let altTriggerSort = false -let formPortals = ['cube', 'ship', 'ball', 'ufo', 'wave', 'robot', 'spider'] -let speedPortals = ['-1x', '1x', '2x', '3x', '4x'] -let sizePortals = ['mini', 'big'] -let dualPortals = ['dual', 'single'] -let mirrorPortals = ['mirrorOn', 'mirrorOff'] +const PORTALS = { + form: ['cube', 'ship', 'ball', 'ufo', 'wave', 'robot', 'spider'], + speed: ['-1x', '1x', '2x', '3x', '4x'], + size: ['mini', 'big'], + dual: ['dual', 'single'], + mirror: ['mirrorOn', 'mirrorOff'] +} fetch(`/api${window.location.pathname}`).then(res => res.json()).then(res => { @@ -129,8 +132,8 @@

Level Data

$('#objectCount').text(commafy(res.objects) + " objects") document.title = "Analysis of " + res.level.name - $('#meta-title').attr('content', "Analysis of " + res.level.name) - $('#meta-desc').attr('content', `${res.portals.split(",").length}x portals, ${res.orbs.total || 0}x orbs, ${res.triggers.total || 0}x triggers, ${res.misc.glow || 0}x glow...`) + $('#meta-title').attr('content', "Analysis of " + res.level.name) + $('#meta-desc').attr('content', `${res.portals.split(",").length}x portals, ${res.orbs.total || 0}x orbs, ${res.triggers.total || 0}x triggers, ${res.misc.glow || 0}x glow...`) let hdPercent = (res.highDetail / res.objects) * 100 @@ -154,10 +157,10 @@

Level Data

function appendPortals() { $('#portals').html("") - if (res.settings.gamemode && res.settings.gamemode != "cube" && !disabledPortals.includes('form')) $('#portals').append(`

Start

`) - if (res.settings.startMini && !disabledPortals.includes('size')) $('#portals').append(`

Start

`) - if (res.settings.speed && res.settings.speed != "1x" && !disabledPortals.includes('speed')) $('#portals').append(`

Start

`) - if (res.settings.startDual && !disabledPortals.includes('dual')) $('#portals').append(`

Start

`) + if (res.settings.gamemode && res.settings.gamemode != "cube" && !disabledPortals.includes('form')) $('#portals').append(`

Start

`) + if (res.settings.startMini && !disabledPortals.includes('size')) $('#portals').append(`

Start

`) + if (res.settings.speed && res.settings.speed != "1x" && !disabledPortals.includes('speed')) $('#portals').append(`

Start

`) + if (res.settings.startDual && !disabledPortals.includes('dual')) $('#portals').append(`

Start

`) let dividerCount = $('.divider').length - 1 @@ -167,7 +170,7 @@

Level Data

portals.forEach(x => { if (!x || x[0] == "") return; - $('#portals').append(`

${x[1]}

`) + $('#portals').append(`

${x[1]}

`) } )} @@ -192,13 +195,13 @@

Level Data

else { $('#coinText').text(`User Coins (${res.coins.length})`) res.coins.forEach(x => { - $('#coins').append(`

${x}%

`) + $('#coins').append(`

${x}%

`) }) } triggerList.forEach(x => { if (x == "total") $('#triggerText').text(`Triggers (${commafy(res.triggers[x])})`) - else $('#triggers').append(`

x${commafy(res.triggers[x])}

`) + else $('#triggers').append(`

x${commafy(res.triggers[x])}

`) }) if (res.invisibleGroup) { @@ -208,16 +211,16 @@

Level Data

orbList.forEach(x => { if (x == "total") $('#orbText').text(`Jump Rings (${commafy(res.orbs[x])})`) - else $('#orbs').append(`

x${commafy(res.orbs[x])}

`) + else $('#orbs').append(`

x${commafy(res.orbs[x])}

`) }) blockList.forEach(x => { - $('#blocks').append(`

x${commafy(res.blocks[x])}

`) + $('#blocks').append(`

x${commafy(res.blocks[x])}

`) }) miscList.forEach(x => { if (x == "objects") return - else $('#misc').append(`

x${commafy(res.misc[x][0])}
${res.misc[x][1]}

`) + else $('#misc').append(`

x${commafy(res.misc[x][0])}
${res.misc[x][1]}

`) }) @@ -230,11 +233,11 @@

Level Data

if (!grCol) grCol = {r: 0, g: 102, b: 255} else if (grCol.r < 35 && grCol.g < 35 && grCol.b < 35) grCol = {r: 75, g: 75, b: 75} - $('#style').append(`
`) - $('#style').append(`
`) - $('#style').append(`
`) - $('#style').append(`
`) - if (res.settings.twoPlayer) $('#style').append(`
`) + $('#style').append(`
`) + $('#style').append(`
`) + $('#style').append(`
`) + $('#style').append(`
`) + if (res.settings.twoPlayer) $('#style').append(`
`) colorList.forEach((x, y) => { let c = res.colors[x] @@ -259,11 +262,8 @@

Level Data

else disabledPortals.push($(this).attr('portal')) portals = res.portals.split(", ").map(x => x.split(" ")) - if (disabledPortals.includes('form')) portals = portals.filter(x => !formPortals.includes(x[0])) - if (disabledPortals.includes('speed')) portals = portals.filter(x => !speedPortals.includes(x[0])) - if (disabledPortals.includes('size')) portals = portals.filter(x => !sizePortals.includes(x[0])) - if (disabledPortals.includes('dual')) portals = portals.filter(x => !dualPortals.includes(x[0])) - if (disabledPortals.includes('mirror')) portals = portals.filter(x => !mirrorPortals.includes(x[0])) + for (let P in PORTALS) + if (disabledPortals.includes(P)) portals = portals.filter(x => !PORTALS[P].includes(x[0])) if (disabledPortals.includes('dupe')) { portals.reverse().forEach((x, y) => {if (portals[y+1] && portals[y+1][0] == x[0]) portals[y][0] = null;}) @@ -273,7 +273,7 @@

Level Data

appendPortals() }) - let dataSize = [Number((res.dataLength / 1024 / 1024).toFixed(1)), "MB"] + let dataSize = [Number((res.dataLength / (1024 * 2)).toFixed(1)), "MB"] if (dataSize[0] < 1) dataSize = [Number((res.dataLength / 1024).toFixed(1)), "KB"] $('#codeLength').html(`${commafy(res.dataLength)} characters (${dataSize.join(" ")})`) @@ -293,7 +293,8 @@

Level Data

hsv.s = Number(hsv.s).toFixed(2) hsv.v = Number(hsv.v).toFixed(2) } - let hex = "#" + ((1 << 24) + (+col.r << 16) + (+col.g << 8) + +col.b).toString(16).slice(1) + // padded (fixed-size) RGB hex + let hex = "#" + ((1 << 24) | (col.r << 16) | (col.g << 8) | col.b).toString(16).slice(1) // remove sentinel nibble $('#colorStuff').html(`

${isNaN(col.channel) ? col.channel : "Color " + col.channel}

@@ -336,13 +337,12 @@

Brightness

` : `
`} -
`) +
`) $('#colorInfo').show() }) $('#loadingDiv').hide() $('#analysisDiv').show() -}); - +}) From 7a65f9ad4409f7c5d8d9b679ca18b60242edbfd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Sun, 3 Jul 2022 16:21:53 -0400 Subject: [PATCH 56/60] Reverted my bad MB conversion --- html/analyze.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/analyze.html b/html/analyze.html index e558eedd..0dd89c63 100644 --- a/html/analyze.html +++ b/html/analyze.html @@ -273,7 +273,7 @@

Level Data

appendPortals() }) - let dataSize = [Number((res.dataLength / (1024 * 2)).toFixed(1)), "MB"] + let dataSize = [Number((res.dataLength / 1024 / 1024).toFixed(1)), "MB"] if (dataSize[0] < 1) dataSize = [Number((res.dataLength / 1024).toFixed(1)), "KB"] $('#codeLength').html(`${commafy(res.dataLength)} characters (${dataSize.join(" ")})`) From 99e04c7892c7716d99b9a675c8790dd6845e5413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Thu, 1 Sep 2022 04:16:18 -0400 Subject: [PATCH 57/60] Add back a line --- iconkit/extradata/hardcodedUnlocks.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iconkit/extradata/hardcodedUnlocks.json b/iconkit/extradata/hardcodedUnlocks.json index 1b52f1ff..95e1ff9b 100644 --- a/iconkit/extradata/hardcodedUnlocks.json +++ b/iconkit/extradata/hardcodedUnlocks.json @@ -14,6 +14,7 @@ { "form": "icon", "id": 139, "type": "gauntlet", "gauntlet": "Crystal" }, { "form": "icon", "id": 141, "type": "gauntlet", "gauntlet": "spike" }, { "form": "icon", "id": 142, "type": "gauntlet", "gauntlet": "Monster" }, + { "form": "icon", "id": 154, "unlock": "Bully the Shopkeeper" }, { "form": "color1", "id": 41, "type": "treasureRoom", "keys": 1 }, @@ -50,4 +51,4 @@ { "form": "spider", "id": 7, "type": "treasureRoom", "keys": 1 }, { "form": "spider", "id": 10, "type": "gauntlet", "gauntlet": "Demon" }, { "form": "spider", "id": 17, "type": "treasureRoom", "keys": 5 } -] \ No newline at end of file +] From 0446668147f30822505312eb9296e9f5daded616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Thu, 1 Sep 2022 04:33:55 -0400 Subject: [PATCH 58/60] Update analyze.js Replaced `var` by `let`, and splitted 1 line. At `sortObj` --- api/analyze.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/analyze.js b/api/analyze.js index f1743942..1b1425ef 100644 --- a/api/analyze.js +++ b/api/analyze.js @@ -33,8 +33,9 @@ module.exports = async (app, req, res, level) => { } function sortObj(obj, sortBy) { - var sorted = {} - var keys = Object.keys(obj).sort((a,b) => sortBy ? obj[b][sortBy] - obj[a][sortBy] : obj[b] - obj[a]) + let keys = Object.keys(obj) + .sort((a,b) => sortBy ? obj[b][sortBy] - obj[a][sortBy] : obj[b] - obj[a]) + let sorted = {} keys.forEach(x => {sorted[x] = obj[x]}) return sorted } From 6e063050b0b83e543bdb7218091e40fffbb91975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Wed, 5 Oct 2022 10:05:35 -0400 Subject: [PATCH 59/60] Update analyze.js --- api/analyze.js | 113 ++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 43 deletions(-) diff --git a/api/analyze.js b/api/analyze.js index 1b1425ef..e7c55049 100644 --- a/api/analyze.js +++ b/api/analyze.js @@ -1,3 +1,4 @@ +//@ts-check "use strict"; const zlib = require('zlib') const blocks = require('../misc/analysis/blocks.json') @@ -6,7 +7,12 @@ const init = require('../misc/analysis/initialProperties.json') const properties = require('../misc/analysis/objectProperties.json') const ids = require('../misc/analysis/objects.json') -module.exports = async (app, req, res, level) => { +module.exports = async ( + app, + /**@type {{}}*/ req, + /**@type {{}}*/ res, + /**@type {{}}*/ level +) => { level ||= { name: (req.body.name || "Unnamed").slice(0, 64), @@ -32,7 +38,12 @@ module.exports = async (app, req, res, level) => { } } -function sortObj(obj, sortBy) { +/** + * Sorts any `Object` by its keys + * @param {{}} obj + * @param {PropertyKey} [sortBy] optional inner key to sort + */ +const sortObj = (obj, sortBy) => { let keys = Object.keys(obj) .sort((a,b) => sortBy ? obj[b][sortBy] - obj[a][sortBy] : obj[b] - obj[a]) let sorted = {} @@ -40,7 +51,14 @@ function sortObj(obj, sortBy) { return sorted } -function parse_obj(obj, splitter, name_arr, valid_only) { +/** + * game-object (**not** JS `Object`) parser + * @param {string} obj + * @param {string} splitter + * @param {string[]} name_arr + * @param {boolean} [valid_only] + */ +const parse_obj = (obj, splitter, name_arr, valid_only) => { const s_obj = obj.split(splitter) let robtop_obj = {} @@ -55,17 +73,23 @@ function parse_obj(obj, splitter, name_arr, valid_only) { return robtop_obj } +/** + * @param {{}} level + * @param {string} rawData + */ function analyze_level(level, rawData) { - let response = {} + let response = {}; - let blockCounts = {} - let miscCounts = {} - let triggerGroups = [] + let blockCounts = {}; + let miscCounts = {}; + /**@type {string[]}*/ + let triggerGroups = []; let highDetail = 0 - let alphaTriggers = [] + /**@type {{}[]}*/ + let alphaTriggers = []; - let misc_objects = {} - let block_ids = {} + let misc_objects = {}; + let block_ids = {}; for (const [name, object_ids] of Object.entries(ids.misc)) { const copied_ids = object_ids.slice(1) @@ -73,27 +97,28 @@ function analyze_level(level, rawData) { copied_ids.forEach(object_id => { misc_objects[object_id] = name }) } - for (const [name, object_ids] of Object.entries(blocks)) { - object_ids.forEach(object_id => { block_ids[object_id] = name }) - } + for (const [name, object_ids] of Object.entries(blocks)) + object_ids.forEach(object_id => { block_ids[object_id] = name }); + /**@type {(string|{})[]}*/ const data = rawData.split(";") const header = data.shift() - let level_portals = [] - let level_coins = [] - let level_text = [] + let level_portals = []; + let level_coins = []; + let level_text = []; - let orb_array = {} - let trigger_array = {} + // why are these Objects instead of Arrays? + let orb_array = {}; + let trigger_array = {}; let last = 0 const obj_length = data.length for (let i = 0; i < obj_length; ++i) { - obj = parse_obj(data[i], ',', properties) + let obj = parse_obj(data[i], ',', properties) - let id = obj.id + let {id} = obj if (id in ids.portals) { obj.portal = ids.portals[id] @@ -104,11 +129,8 @@ function analyze_level(level, rawData) { } else if (id in ids.orbs) { obj.orb = ids.orbs[id] - if (obj.orb in orb_array) { - orb_array[obj.orb]++ - } else { - orb_array[obj.orb] = 1 - } + const orb = orb_array[obj.orb] + orb_array[obj.orb] = orb ? +orb + 1 : 1 } else if (id in ids.triggers) { obj.trigger = ids.triggers[id] @@ -172,17 +194,18 @@ function analyze_level(level, rawData) { response.settings = {} // "I have no idea what to name this lmao" @Rudxain - let WTF = x => Math.floor(x.x / (Math.max(last, 529) + 340) * 100) + let WTF = (/**@type {{}}*/ x) => Math.floor(x.x / (Math.max(last, 529) + 340) * 100) response.portals = level_portals.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(x => x.portal + " " + WTF(x) + "%").join(", ") response.coins = level_coins.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(WTF) response.coinsVerified = level.verifiedCoins - const add = arr => arr.reduce((a, x) => a + x, 0) + /**@param {number[]} arr*/ + const sum = arr => arr.reduce((a, x) => a + x, 0) response.orbs = orb_array - response.orbs.total = add(Object.values(orb_array)) // we already have an array of objects, use it + response.orbs.total = sum(Object.values(orb_array)) // we already have an array of objects, use it response.triggers = trigger_array - response.triggers.total = add(Object.values(trigger_array)) + response.triggers.total = sum(Object.values(trigger_array)) response.triggerGroups = {} response.blocks = sortObj(blockCounts) @@ -213,17 +236,18 @@ function analyze_level(level, rawData) { return response } -function parse_header(header) { +function parse_header(/**@type {string}*/ header) { let response = {} response.settings = {} response.colors = [] const header_keyed = parse_obj(header, ',', init.values, true) - Object.keys(header_keyed).forEach(x => { - let val = init.values[x] + Object.keys(header_keyed).forEach(k => { + let val = init.values[k] + /**@type {string}*/ let name = val[0] - let property = header_keyed[x] + let property = header_keyed[k] switch (val[1]) { case 'list': val = init[(val[0] + "s")][property]; @@ -251,7 +275,7 @@ function parse_header(header) { // from here we touch the color object let currentChannel = response.colors.find(k => k.channel == channel) if (color == 'blend') currentChannel.blending = true // only one color has blending though lol - else if (color == 'pcol' && property != 0) currentChannel.pColor = property + if (color == 'pcol' && property != 0) currentChannel.pColor = property currentChannel[color] = property break @@ -272,8 +296,11 @@ function parse_header(header) { // from here stuff can continue as normal, ish if (colorObj.pColor == "-1" || colorObj.pColor == "0") delete colorObj.pColor colorObj.opacity = 1 // 1.9 colors don't have this! - if (colorObj.blending && colorObj.blending == '1') colorObj.blending = true // 1.9 colors manage to always think they're blending - they're not - else delete colorObj.blending + + if (colorObj?.blending === '1') + colorObj.blending = true // 1.9 colors manage to always think they're blending - they're not + else + delete colorObj.blending if (colorVal == '3DL') response.colors.splice(4, 0, colorObj) // hardcode the position of 3DL, it typically goes at the end due to how RobTop make the headers else if (colorVal == 'Line') { colorObj.blending = true; response.colors.push(colorObj) } // in line with 2.1 behavior @@ -282,10 +309,10 @@ function parse_header(header) { } case 'colors': { let colorList = property.split("|") - colorList.forEach((x, y) => { + colorList.forEach((/** @type {string} */ x, /** @type {string | number} */ y) => { const color = parse_obj(x, "_", colorStuff.properties) let colorObj = color - if (!color.channel) return colorList = colorList.filter((h, i) => y != i) + if (!color.channel) return colorList = colorList.filter((/** @type {any} */ h, /** @type {any} */ i) => y != i) if (colorStuff.channels[colorObj.channel]) colorObj.channel = colorStuff.channels[colorObj.channel] if (colorObj.channel > 1000) return @@ -296,7 +323,7 @@ function parse_header(header) { if (colorObj.copiedHSV) { let hsv = colorObj.copiedHSV.split("a") colorObj.copiedHSV = {} - hsv.forEach((x, y) => { colorObj.copiedHSV[colorStuff.hsv[y]] = x }) + hsv.forEach((/** @type {any} */ x, /** @type {string | number} */ y) => { colorObj.copiedHSV[colorStuff.hsv[y]] = x }) colorObj.copiedHSV['s-checked'] = colorObj.copiedHSV['s-checked'] == 1 colorObj.copiedHSV['v-checked'] = colorObj.copiedHSV['v-checked'] == 1 if (colorObj.copyOpacity == 1) colorObj.copyOpacity = true @@ -305,12 +332,12 @@ function parse_header(header) { colorList[y] = colorObj }) // we assume this is only going to be run once so... some stuff can go here - colorList = colorList.filter(x => typeof x == "object") - if (!colorList.find(x => x.channel == "Obj")) colorList.push({"r": "255", "g": "255", "b": "255", "channel": "Obj", "opacity": "1"}) + colorList = colorList.filter((/** @type {any} */ x) => typeof x == "object") + if (!colorList.find((/** @type {{ channel: string; }} */ x) => x.channel == "Obj")) colorList.push({"r": "255", "g": "255", "b": "255", "channel": "Obj", "opacity": "1"}) const specialSort = ["BG", "G", "G2", "Line", "Obj", "3DL"] - let specialColors = colorList.filter(x => isNaN(x.channel)).sort((a, b) => specialSort.indexOf(a.channel) > specialSort.indexOf(b.channel)) - let regularColors = colorList.filter(x => !isNaN(x.channel)).sort((a, b) => +a.channel - +b.channel) + let specialColors = colorList.filter((/** @type {{ channel: number; }} */ x) => isNaN(x.channel)).sort((/** @type {{ channel: string; }} */ a, /** @type {{ channel: string; }} */ b) => specialSort.indexOf(a.channel) > specialSort.indexOf(b.channel)) + let regularColors = colorList.filter((/** @type {{ channel: number; }} */ x) => !isNaN(x.channel)).sort((/** @type {{ channel: string | number; }} */ a, /** @type {{ channel: string | number; }} */ b) => +a.channel - +b.channel) response.colors = specialColors.concat(regularColors) break } From 5e86a886893cd9b57298f56315a8f370f43f2fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Fern=C3=A1ndez=20Serrata?= <76864299+Rudxain@users.noreply.github.com> Date: Wed, 5 Oct 2022 20:39:25 -0400 Subject: [PATCH 60/60] Update analyze.js --- api/analyze.js | 63 ++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/api/analyze.js b/api/analyze.js index e7c55049..68c54994 100644 --- a/api/analyze.js +++ b/api/analyze.js @@ -1,4 +1,3 @@ -//@ts-check "use strict"; const zlib = require('zlib') const blocks = require('../misc/analysis/blocks.json') @@ -7,12 +6,7 @@ const init = require('../misc/analysis/initialProperties.json') const properties = require('../misc/analysis/objectProperties.json') const ids = require('../misc/analysis/objects.json') -module.exports = async ( - app, - /**@type {{}}*/ req, - /**@type {{}}*/ res, - /**@type {{}}*/ level -) => { +module.exports = async (app, req, res, level) => { level ||= { name: (req.body.name || "Unnamed").slice(0, 64), @@ -108,7 +102,7 @@ function analyze_level(level, rawData) { let level_coins = []; let level_text = []; - // why are these Objects instead of Arrays? + // "why are these Objects instead of Arrays?" @Rudxain let orb_array = {}; let trigger_array = {}; @@ -194,7 +188,7 @@ function analyze_level(level, rawData) { response.settings = {} // "I have no idea what to name this lmao" @Rudxain - let WTF = (/**@type {{}}*/ x) => Math.floor(x.x / (Math.max(last, 529) + 340) * 100) + let WTF = x => Math.floor(x.x / (Math.max(last, 529) + 340) * 100) response.portals = level_portals.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(x => x.portal + " " + WTF(x) + "%").join(", ") response.coins = level_coins.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(WTF) response.coinsVerified = level.verifiedCoins @@ -266,7 +260,8 @@ function parse_header(/**@type {string}*/ header) { // these literally are keys set the value, and to convert this to the color list we have to do this fun messy thing that shouldn't exist // since i wrote the 1.9 color before this, a lot of explaination will be there instead const colorInfo = name.split('-') - const color = colorInfo[2] // r,g,b + /** r,g,b */ + const color = colorInfo[2] const channel = colorInfo[1] // first we create the color object @@ -294,7 +289,8 @@ function parse_header(/**@type {string}*/ header) { colorObj.channel = colorVal // from here stuff can continue as normal, ish - if (colorObj.pColor == "-1" || colorObj.pColor == "0") delete colorObj.pColor + if (colorObj.pColor == "-1" || colorObj.pColor == "0") + delete colorObj.pColor colorObj.opacity = 1 // 1.9 colors don't have this! if (colorObj?.blending === '1') @@ -302,17 +298,28 @@ function parse_header(/**@type {string}*/ header) { else delete colorObj.blending - if (colorVal == '3DL') response.colors.splice(4, 0, colorObj) // hardcode the position of 3DL, it typically goes at the end due to how RobTop make the headers - else if (colorVal == 'Line') { colorObj.blending = true; response.colors.push(colorObj) } // in line with 2.1 behavior - else response.colors.push(colorObj) // bruh whatever was done to make the color list originally was long + switch (colorVal) { + case '3DL': + response.colors.splice(4, 0, colorObj) // hardcode the position of 3DL, it typically goes at the end due to how RobTop make the headers + break + + case 'Line': { + colorObj.blending = true; response.colors.push(colorObj) // in line with 2.1 behavior + break + } + + default: + response.colors.push(colorObj) // bruh whatever was done to make the color list originally was long + break + } break } case 'colors': { let colorList = property.split("|") - colorList.forEach((/** @type {string} */ x, /** @type {string | number} */ y) => { + colorList.forEach((x, y) => { const color = parse_obj(x, "_", colorStuff.properties) let colorObj = color - if (!color.channel) return colorList = colorList.filter((/** @type {any} */ h, /** @type {any} */ i) => y != i) + if (!color.channel) return colorList = colorList.filter((_, i) => y != i) if (colorStuff.channels[colorObj.channel]) colorObj.channel = colorStuff.channels[colorObj.channel] if (colorObj.channel > 1000) return @@ -323,21 +330,21 @@ function parse_header(/**@type {string}*/ header) { if (colorObj.copiedHSV) { let hsv = colorObj.copiedHSV.split("a") colorObj.copiedHSV = {} - hsv.forEach((/** @type {any} */ x, /** @type {string | number} */ y) => { colorObj.copiedHSV[colorStuff.hsv[y]] = x }) + hsv.forEach((x, y) => { colorObj.copiedHSV[colorStuff.hsv[y]] = x }) colorObj.copiedHSV['s-checked'] = colorObj.copiedHSV['s-checked'] == 1 colorObj.copiedHSV['v-checked'] = colorObj.copiedHSV['v-checked'] == 1 - if (colorObj.copyOpacity == 1) colorObj.copyOpacity = true + if (colorObj.copyOpacity == 1) colorObj.copyOpacity = true } colorObj.opacity = +Number(colorObj.opacity).toFixed(2) colorList[y] = colorObj }) // we assume this is only going to be run once so... some stuff can go here - colorList = colorList.filter((/** @type {any} */ x) => typeof x == "object") - if (!colorList.find((/** @type {{ channel: string; }} */ x) => x.channel == "Obj")) colorList.push({"r": "255", "g": "255", "b": "255", "channel": "Obj", "opacity": "1"}) + colorList = colorList.filter(x => typeof x == "object") + if (!colorList.find(x => x.channel == "Obj")) colorList.push({"r": "255", "g": "255", "b": "255", "channel": "Obj", "opacity": "1"}) const specialSort = ["BG", "G", "G2", "Line", "Obj", "3DL"] - let specialColors = colorList.filter((/** @type {{ channel: number; }} */ x) => isNaN(x.channel)).sort((/** @type {{ channel: string; }} */ a, /** @type {{ channel: string; }} */ b) => specialSort.indexOf(a.channel) > specialSort.indexOf(b.channel)) - let regularColors = colorList.filter((/** @type {{ channel: number; }} */ x) => !isNaN(x.channel)).sort((/** @type {{ channel: string | number; }} */ a, /** @type {{ channel: string | number; }} */ b) => +a.channel - +b.channel) + let specialColors = colorList.filter(x => isNaN(x.channel)).sort((a, b) => specialSort.indexOf(a.channel) > specialSort.indexOf(b.channel)) + let regularColors = colorList.filter(x => !isNaN(x.channel)).sort((a, b) => a.channel - b.channel) response.colors = specialColors.concat(regularColors) break } @@ -345,12 +352,14 @@ function parse_header(/**@type {string}*/ header) { response.settings[name] = val }) - if (!response.settings.ground || response.settings.ground > 17) response.settings.ground = 1 - if (!response.settings.background || response.settings.background > 20) response.settings.background = 1 - if (!response.settings.font) response.settings.font = 1 + if (!response.settings.ground || response.settings.ground > 17) + response.settings.ground = 1 + if (!response.settings.background || response.settings.background > 20) + response.settings.background = 1 + if (!response.settings.font) + response.settings.font = 1 - if (response.settings.alternateLine == 2) response.settings.alternateLine = true - else response.settings.alternateLine = false + response.settings.alternateLine = response.settings.alternateLine == 2 Object.keys(response.settings).filter(k => { // this should be parsed into color list instead