Achievements Browser!!!

This commit is contained in:
GDColon 2021-01-11 16:00:21 -05:00
parent 318e2f925c
commit c99c6ba553
91 changed files with 3006 additions and 20363 deletions

View file

@ -20,9 +20,10 @@ module.exports = async (app, req, res) => {
request.post(app.endpoint + 'getGJLevelScores211.php', params, async function(err, resp, body) {
if (err || body == '-1' || !body) return res.send("-1")
if (err || body == -1 || !body) return res.send("-1")
scores = body.split('|').map(x => app.parseResponse(x))
if (!(scores.filter(x => x[1]).length)) return res.send("-1")
else app.trackSuccess()
scores.forEach(x => {
let keys = Object.keys(x)

View file

@ -11,15 +11,12 @@ module.exports = async (app, req, res) => {
else amount = count;
}
let params = req.gdParams({
count: amount,
type: "top",
})
let params = {count: amount, type: "top"}
if (["creators", "creator", "cp"].some(x => req.query.hasOwnProperty(x) || req.query.type == x)) type = "creators"
else if (["week", "weekly"].some(x => req.query.hasOwnProperty(x) || req.query.type == x)) type = "weekly" // i think GDPS'es use this
if (["creators", "creator", "cp"].some(x => req.query.hasOwnProperty(x) || req.query.type == x)) params.type = "creators"
else if (["week", "weekly"].some(x => req.query.hasOwnProperty(x) || req.query.type == x)) params.type = "weekly" // i think GDPS'es use this
request.post(app.endpoint + 'getGJScores20.php', params, async function(err, resp, body) {
request.post(app.endpoint + 'getGJScores20.php', req.gdParams(params), async function(err, resp, body) {
if (err || body == '-1' || !body) return res.send("-1")
scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1])

View file

@ -15,7 +15,8 @@ module.exports = async (app, req, res) => {
request.post(app.endpoint + 'getGJUserInfo20.php', params, async function (err, resp, body) {
if (err || body == '-1' || body == '-2' || !body) return res.status(400).send("Error counting messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. (this is not an issue with gdbrowser)")
if (err || body == '-1' || body == '-2' || !body) return res.status(400).send(`Error counting messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
else app.trackSuccess()
let count = app.parseResponse(body)[38]
if (!count) return res.status(400).send("Error fetching unread messages!")
else res.status(200).send(count)

View file

@ -18,9 +18,9 @@ module.exports = async (app, req, res, api) => {
request.post(app.endpoint + 'deleteGJMessages20.php', req.gdParams(params), async function (err, resp, body) {
if (body != 1) return res.status(400).send("The Geometry Dash servers refused to delete the message! Make sure your username and password are entered correctly.")
if (body != 1) return res.status(400).send(`The Geometry Dash servers refused to delete the message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
else res.status(200).send(`${deleted == 1 ? "1 message" : `${deleted} messages`} deleted!`)
app.trackSuccess()
})
}

View file

@ -15,7 +15,8 @@ module.exports = async (app, req, res, api) => {
request.post(app.endpoint + 'downloadGJMessage20.php', params, async function (err, resp, body) {
if (err || body == '-1' || !body) return res.status(400).send("Error fetching message!")
if (err || body == '-1' || !body) return res.status(400).send(`Error fetching message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
else app.trackSuccess()
let x = app.parseResponse(body)
let msg = {}

View file

@ -17,7 +17,8 @@ module.exports = async (app, req, res, api) => {
request.post(app.endpoint + 'getGJMessages20.php', params, async function (err, resp, body) {
if (err || body == '-1' || body == '-2' || !body) return res.status(400).send("Error fetching messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. (this is not an issue with gdbrowser)")
if (err || body == '-1' || body == '-2' || !body) return res.status(400).send(`Error fetching messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
else app.trackSuccess()
let messages = body.split("|").map(msg => app.parseResponse(msg))
let messageArray = []

View file

@ -20,10 +20,9 @@ module.exports = async (app, req, res, api) => {
})
request.post(app.endpoint + 'uploadGJMessage20.php', params, async function (err, resp, body) {
if (body != 1) return res.status(400).send("The Geometry Dash servers refused to send the message! Make sure your username and password are entered correctly.")
if (body != 1) return res.status(400).send(`The Geometry Dash servers refused to send the message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
else res.status(200).send('Message sent!')
app.trackSuccess()
})
}

View file

@ -34,7 +34,8 @@ module.exports = async (app, req, res) => {
request.post(app.endpoint + 'likeGJItem211.php', req.gdParams(params), function (err, resp, body) {
if (err) return res.status(400).send("The Geometry Dash servers returned an error! Perhaps they're down for maintenance")
if (!body || body == "-1") return res.status(400).send("The Geometry Dash servers rejected your vote! Make sure your username and password are entered correctly.")
if (!body || body == "-1") return res.status(400).send(`The Geometry Dash servers rejected your vote! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
else app.trackSuccess()
res.status(200).send((params.like == 1 ? 'Successfully liked!' : 'Successfully disliked!') + " (this will only take effect if this is your first time doing so)")
})
}

View file

@ -42,12 +42,14 @@ module.exports = async (app, req, res) => {
request.post(app.endpoint + 'uploadGJComment21.php', req.gdParams(params), function (err, resp, body) {
if (err) return res.status(400).send("The Geometry Dash servers returned an error! Perhaps they're down for maintenance")
if (!body || body == "-1") return res.status(400).send("The Geometry Dash servers rejected your comment! Try again later, or make sure your username and password are entered correctly.")
if (!body || body == "-1") return res.status(400).send(`The Geometry Dash servers rejected your comment! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
if (body.startsWith("temp")) {
let banStuff = body.split("_")
return res.status(400).send(`You have been banned from commenting for ${(parseInt(banStuff[1]) / 86400).toFixed(0)} days. Reason: ${banStuff[2] || "None"}`)
}
res.status(200).send(`Comment posted to level ${params.levelID} with ID ${body}`)
app.trackSuccess()
rateLimit[req.body.username] = Date.now();
setTimeout(() => {delete rateLimit[req.body.username]; }, cooldown);
})

View file

@ -27,7 +27,8 @@ module.exports = async (app, req, res) => {
request.post(app.endpoint + 'uploadGJAccComment20.php', req.gdParams(params), function (err, resp, body) {
if (err) return res.status(400).send("The Geometry Dash servers returned an error! Perhaps they're down for maintenance")
if (!body || body == "-1") return res.status(400).send("The Geometry Dash servers rejected your profile post! Try again later, or make sure your username and password are entered correctly.")
else if (!body || body == "-1") return res.status(400).send(`The Geometry Dash servers rejected your profile post! Try again later, or make sure your username and password are entered correctly. Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`)
else app.trackSuccess()
res.status(200).send(`Comment posted to ${params.userName} with ID ${body}`)
})
}

BIN
assets/achievements.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
assets/achievements/gd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
assets/achievements/gdm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
assets/achievements/gdr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
assets/achievements/gds.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/achievements/gdw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1101,6 +1101,59 @@ input::-webkit-inner-spin-button {
outline-offset: -0.4vh;
}
.flex {
display: flex;
}
.flex img {
align-self: center;
}
.colorCircle {
border: 3.75px solid black;
border-radius: 420px;
}
.typeFilter {
background-color: rgba(0, 0, 0, 0.3);
padding: 0.75% 0.75%;
border-radius: 0.5vh;
}
.typeFilter.achDeselected, .gameFilter.achDeselected {
filter: brightness(30%) saturate(50%);
}
.rewardFilter.achDeselected {
filter: brightness(60%);
}
.typeFilter.achDeselected {
background-color: rgba(0, 0, 0, 0.75);
}
.labelHover {
color: yellow;
transform: scale(0.8);
}
.achSelect {
cursor: pointer;
z-index: 1;
user-select: none;
pointer-events: all;
}
.achSelect:active {
transform: scale(1.04);
}
.hidey {
opacity: 0%;
pointer-events: none;
transition-duration: 0s !important;
}
.red {
color: #ff0000 !important;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
assets/trails/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
assets/trails/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

BIN
assets/trails/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
assets/trails/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
assets/trails/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

BIN
assets/trails/6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
assets/trails/7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

192
html/achievements.html Normal file
View file

@ -0,0 +1,192 @@
<head>
<title>Achievements</title>
<meta charset="utf-8">
<link href="../assets/css/browser.css" type="text/css" rel="stylesheet">
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-135255146-3"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', 'UA-135255146-3');</script>
<link rel="icon" href="../assets/trophies/1.png">
<meta id="meta-title" property="og:title" content="Achievements">
<meta id="meta-desc" property="og:description" content="View the list of achievements in Geometry Dash!">
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/trophies/1.png">
</head>
<body class="levelBG" onbeforeunload="saveUrl()">
<div id="everything" style="overflow: auto;">
<div id="filters" class="popup">
<div class="brownBox bounce center supercenter" style="width: 110vh; height: 75%; padding-top: 0.3%; padding-bottom: 3.5%">
<img class="gdButton" src="../assets/close.png" width="10%" style="position: absolute; top: -7.5%; left: -5.5vh" onclick="$('#filters').hide()">
<h2 class="small" style="margin-bottom: 0%">Filters</h2><br>
<div id="rewardLabel">
<img filter="rewardFilter" class="achSelect selectAll" style="margin: 0% 2% 1.9% 0%" class="gdButton inline" src="../assets/select-all.png" height="5%">
<h1 class="smaller inline" style="margin-bottom: 1.5%">Reward</h1>
<img filter="rewardFilter" class="achSelect selectNone" style="margin: 0% 0% 1.9% 2%" class="gdButton inline" src="../assets/select-none.png" height="5%">
</div>
<div id="forms"></div>
<div id="typeLabel">
<img filter="typeFilter" class="achSelect selectAll" style="margin: 0% 2% 1.4% 0%" class="gdButton inline" src="../assets/select-all.png" height="5%">
<h1 class="smaller inline" style="margin-top: 3%; margin-bottom: 1%">Requirement</h1>
<img filter="typeFilter" class="achSelect selectNone" style="margin: 0% 0% 1.4% 2%" class="gdButton inline" src="../assets/select-none.png" height="5%">
</div>
<div id="types"></div>
<div id="gameLabel">
<img filter="gameFilter" class="achSelect selectAll" style="margin: 0% 2% 1.8% 0%" class="gdButton inline" src="../assets/select-all.png" height="5%">
<h1 class="smaller inline" style="margin-top: 1%; margin-bottom: 1.3%">Game</h1>
<img filter="gameFilter" class="achSelect selectNone" style="margin: 0% 0% 1.8% 2%" class="gdButton inline" src="../assets/select-none.png" height="5%">
</div>
<div id="games">
<img class="gdButton achFilter gameFilter" src="../assets/achievements/gd.png" height="12%" style="margin: 0% 1%" title="Geometry Dash" filter="gd">
<img class="gdButton achFilter gameFilter" src="../assets/achievements/gdm.png" height="12%" style="margin: 0% 1%" title="Geometry Dash Meltdown" filter="meltdown">
<img class="gdButton achFilter gameFilter" src="../assets/achievements/gdw.png" height="12%" style="margin: 0% 1%" title="Geometry Dash World" filter="world">
</div>
<img id="submitFilters" class="gdButton" style="margin: 2.5% 0.7%" src="../assets/btn-submit.png" height="10%">
</div>
</div>
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
</div>
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
</div>
<div id="searchBox" class="supercenter dragscroll" style="width: 128vh">
<div style="height: 4.5%"></div>
</div>
<div class="epicbox supercenter gs" style="width: 126vh; height: 80%; pointer-events: none"></div>
<div class="center" style="position:absolute; top: 8%; left: 0%; right: 0%">
<h1 class="pre" id="header">Achievements</h1>
</div>
<div style="position:absolute; top: 2%; left: 1.5%; width: 10%; height: 25%; pointer-events: none">
<img class="gdButton yesClick" id="backButton" src="../assets/back.png" height="30%" onclick="backButton()">
</div>
<div style="position:absolute; top: 2%; right: 1.5%; width: 9%; text-align: right">
<img class="gdButton" style="margin-bottom: 15%" src="../assets/plus.png" width="60%" onclick="$('#filters').show()">
<img id="check" class="gdButton" style="margin-bottom: 15%" src="../assets/check-off.png" width="60%"">
</div>
</div>
</body>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script async type="text/javascript" src="../sizecheck.js"></script>
<script type="text/javascript" src="../dragscroll.js"></script>
<script>
let disabledFilters = {reward: [], type: [], game: []}
let forms = ["cube", "ship", "ball", "ufo", "wave", "robot", "spider"]
let gameColors = {meltdown: "rgb(255, 100, 0)", world: "rgb(0, 225, 255)"}
let achievements = []
let colors = {}
let completed = false
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(`<img class="gdButton achFilter rewardFilter" filter="${x}" title="${formStr[y]}" src="../assets/${y > 8 ? "achievements" : "iconkitbuttons"}/${x}_on.png" height=9.5%" style="margin: 0% 0.75%">`)
})
function append(reset=true) {
$('#searchBox').html(`<div style="height: 4.5%"></div>`)
achievements.forEach(x => {
let iconImg = `"`;
if (forms.includes(x.rewardType)) iconImg = `../assets/previewicons/${x.rewardType}-${x.rewardID < 10 ? "0" : ""}${x.rewardID}.png" width="90%" title="${x.rewardType}_${x.rewardID < 10 ? "0" : ""}${x.rewardID}"`
else if (x.rewardType.startsWith("color")) {
let col = colors[x.rewardID]
let colType = x.rewardType.slice(5)
iconImg = `../assets/col${colType}.png" class="colorCircle" width="80%" title="${colType == 1 ? "Primary" : "Secondary"} Color ${x.rewardID}" style="background-color: rgb(${col.r}, ${col.g}, ${col.b})"`
}
else if (x.rewardType == "deathEffect") iconImg = `../assets/deatheffects/${x.rewardID}.png" width="85%" title="Death Effect ${x.rewardID}"`
else if (x.rewardType == "trail") iconImg = `../assets/trails/${x.rewardID}.png" width="85%" title="Trail ${x.rewardID}"`
else if (x.rewardType == "misc") iconImg = `../assets/coin.png" width="85%"`
$('#searchBox').append(`<div class="flex searchresult leaderboardSlot" style="height: 18%; width: 92%; padding-left: 3%; padding-top: 0%">
<div class="flex" style="width: 8%; margin-right: 2%"><img src="${iconImg}></div>
<div>
<h2 title="geometry.ach.${x.id}" smaller inline" style="font-size: 4.5vh; margin-top: 1vh; color: ${gameColors[x.game] || "default"}">${x.name}</h2>
<p style="margin-top: 2vh; color:${completed ? "yellow" : "white"}">${completed ? x.achievedDescription : x.description}</p>
</div>
</div>`)
})
$('#searchBox').append('<div style="height: 4.5%"></div>')
if (reset) $('#searchBox').scrollTop(0)
}
fetch('./api/achievements').then(res => res.json().then(ach => {
Object.keys(ach.types).forEach(x => {
$('#types').append(`<img class="gdButton achFilter typeFilter" filter="${ach.types[x][1].join(" ")}" src="../assets/achievements/${x}.png" title="${ach.types[x][0]}" height="8.5%" style="margin: 0.6% 0.4%">`)
})
achievements = ach.achievements
colors = ach.colors
append()
function label(labelName) {
let labelFilter = `.${labelName}Filter`
let labelID = `#${labelName}Label h1`
let labelButtons = `#${labelName}Label img`
$(labelFilter).hover(function() {
$(labelButtons).addClass('hidey')
$(labelID).attr('text', $(labelID)
.text()).text($(this).attr('title')).addClass("labelHover")
}, function() {
$(labelButtons).removeClass('hidey')
$(labelID).text($(labelID).attr('text')).removeClass("labelHover")
})
$(labelFilter).click(function() {
let filters = $(this).attr('filter').split(" ")
if (!$(this).hasClass('achDeselected')) {
$(this).addClass('achDeselected')
filters.forEach(x => disabledFilters[labelName].push(x))
if (labelName == "reward") $(this).attr('src', $(this).attr('src').replace("_on", "_off"))
}
else {
$(this).removeClass('achDeselected')
filters.forEach(x => disabledFilters[labelName] = disabledFilters[labelName].filter(y => y != x))
if (labelName == "reward") $(this).attr('src', $(this).attr('src').replace("_off", "_on"))
}
})
}
label("reward")
label("type")
label("game")
$(document).on('click', '.selectNone', function() { $(`.${$(this).attr('filter')}:not(.achDeselected)`).trigger('click'); $('#selectNone').hide(); $('#selectAll').show() })
$(document).on('click', '.selectAll', function() { $(`.${$(this).attr('filter')}.achDeselected`).trigger('click'); $('#selectNone').show(); $('#selectAll').hide() })
$('#submitFilters').click(function() {
$('.popup').hide()
if (!$('.rewardFilter:not(.achDeselected)').length) $('#rewardLabel .selectAll').trigger('click')
if (!$('.typeFilter:not(.achDeselected)').length) $('#typeLabel .selectAll').trigger('click')
if (!$('.gameFilter:not(.achDeselected)').length) $('#gameLabel .selectAll').trigger('click')
achievements = ach.achievements
.filter(x => !disabledFilters.reward.includes(x.rewardType))
.filter(x => !disabledFilters.type.some(y => x.id.startsWith(y)))
.filter(x => !disabledFilters.game.includes(x.game))
append()
})
$('#check').click(function() {
completed = !completed
if (completed) $('#check').attr('src', '../assets/check-on.png')
else $('#check').attr('src', '../assets/check-off.png')
append(false)
})
}))
</script>

View file

@ -28,6 +28,10 @@
<img id="creditsButton" class="gdButton" src="../assets/credits.png" width="60%" onclick="loadCredits()">
</div>
<div style="position:absolute; bottom: 2.5%; right: 1.5%; text-align: right; width: 14%;">
<a href="../achievements"><img class="gdButton" src="../assets/achievements.png" width="40%"></a>
</div>
<div style="position:absolute; top: -1.5%; right: 10%; text-align: right; width: 10%;">
<a href="../iconkit"><img class="iconRope" src="../assets/iconrope.png" width="40%"></a>
</div>

View file

@ -83,10 +83,8 @@
<p class="bigger center" style="line-height: 6vh; margin-top: 1.5vh;">
Are you sure you want to <span style="color: #F05C5C">delete</span> this message?
</p>
<img src="../assets/btn-cancel.png" height=29%; class="gdButton center"
onclick="$('#confirmDelete').hide()">
<img src="../assets/btn-delete.png" height=29%; id="deleteCurrentMessage"
class="gdButton center sideSpaceB">
<img src="../assets/btn-cancel.png" height=29%; class="gdButton center" onclick="$('#confirmDelete').hide()">
<img src="../assets/btn-delete.png" height=29%; id="deleteCurrentMessage" class="gdButton center sideSpaceB">
</div>
<div id="deleting" style="display: none">
@ -94,6 +92,13 @@
<p class="bigger center" style="line-height: 6vh; margin-top: 1.5vh;">Deleting message...</p>
<img src="../assets/loading.png" class="spin noSelect" style="height: 35%; margin-top: -2%">
</div>
<div id="delete-error" style="display: none;">
<img class="gdButton" src="../assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('#delete-error').hide(); $('#confirmDelete').hide(); $('#preDelete').show()">
<img src="../assets/exclamation.png" style="height: 40%">
<p class="bigger" style="margin-bottom: 0%; margin-top: 2.5%">Something went wrong!</p>
<p id="delError" style="font-size: 2.4vh; margin-top: 1%"></p>
</div>
</div>
</div>
@ -117,6 +122,13 @@
class="selectedAmount"></span>...</p>
<img src="../assets/loading.png" class="spin noSelect" style="height: 35%; margin-top: -2%">
</div>
<div id="bd-error" style="display: none;">
<img class="gdButton" src="../assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('#bd-error').hide(); $('#bulkDelete').hide(); $('#preBulkDelete').show()">
<img src="../assets/exclamation.png" style="height: 40%">
<p class="bigger" style="margin-bottom: 0%; margin-top: 2.5%">Something went wrong!</p>
<p id="bdError" style="font-size: 2.4vh; margin-top: 1%"></p>
</div>
</div>
</div>
@ -135,8 +147,7 @@
</div>
<div id="messageOptions">
<img class="gdButton" style="width: 8%" title="Reply" src="../assets/reply.png" id="replyButton">
<img class="gdButton" style="width: 8%" title="Delete" src="../assets/trash.png"
onclick="$('#confirmDelete').show()">
<img class="gdButton" style="width: 8%" title="Delete" src="../assets/trash.png" id="deleteButton" onclick="$('#confirmDelete').show()">
</div>
</div>
</div>
@ -280,7 +291,7 @@
appendMessages()
$('#messages').show()
let targetUser = window.location.search.match(/\?sendTo=(.+)/)
let targetUser = window.location.search.match(/(\?|&)sendTo=(.+)/)
if (targetUser) {
targetUser = decodeURIComponent(targetUser[1])
fetch(`../api/profile/${targetUser}`).then(res => res.json()).then(res => {
@ -317,7 +328,7 @@
.done(msgs => {
messages = msgs
appendMessages()
})
}).fail(e => { $('#msgList').html("") })
}
$(document).on('click', '.hitbox', function (x) {
@ -343,8 +354,12 @@
authorID = $(this).attr('authorID')
let subject = $(this).find('h3:first')
subject.html(subject.html().replace('<span style="color:#00E600">!</span>', "")) //lazy way to mark as read
$('#theMfMessage').attr('style', '')
$('#messageSubject').attr('style', `color: ${$(this).attr('browserColor') ? 'rgb(120, 200, 255)' : "white"}`).text(subject.text())
$('#messageAuthor').html($(this).find('.gdButton').html())
$('#replyButton').hide()
$('#deleteButton').hide()
$('#messageBody').text('').hide()
$('#messageLoad').show()
$('#selectedMessage').show()
@ -356,6 +371,8 @@
if (cache[messageID]) {
$('#messageBody').attr('style', `color: ${cache[messageID][1] ? 'rgb(255, 140, 255)' : "white"}`).text(cache[messageID][0]).show()
$('#messageLoad').hide()
$('#replyButton').show()
$('#deleteButton').show()
}
else $.post("../messages/" + messageID, { password, accountID })
@ -365,6 +382,8 @@
function loadMsg() {
$('#messageBody').attr('style', `color: ${msg.browserColor ? 'rgb(255, 140, 255)' : "white"}`).text(msg.content).show()
$('#messageLoad').hide()
$('#replyButton').show()
$('#deleteButton').show()
}
if (!messageStatus[msg.accountID]) fetch(`../api/profile/${msg.author}`).then(res => res.json()).then(res => {
@ -375,6 +394,13 @@
loadMsg()
}
})
.fail(e => {
$('#messageAuthor').html('&nbsp;')
$('#messageSubject').html('&nbsp;')
$('#messageLoad').hide()
$('#messageBody').html(e.responseText).show()
$('#theMfMessage').attr('style', 'background-color: rgba(0, 0, 0, 0)')
})
})
$('#deleteCurrentMessage').click(function () {
@ -392,6 +418,11 @@
$('#preDelete').show()
$('#deleting').hide()
})
.fail(e => {
$('#deleting').hide()
$('#delete-error').show()
$('#delError').html(e.responseText)
})
})
$('#purge').click(function () {
@ -418,8 +449,13 @@
}
allowEsc = true
$('#bulkDelete').hide()
$('#preBulkDelete').show()
$('#bulkDeleting').hide()
$('#preBulkDelete').show()
})
.fail(e => {
$('#bulkDeleting').hide()
$('#bd-error').show()
$('#bdError').html(e.responseText)
})
})

File diff suppressed because it is too large Load diff

View file

@ -1,13 +0,0 @@
const plist = require('plist');
const { readFileSync, writeFileSync } = require('fs');
const data = plist.parse(readFileSync('./GJ_GameSheet02-uhd.plist', 'utf8'));
for (let key in data.frames) {
let fileData = data.frames[key];
for (let innerKey in fileData) {
if (typeof fileData[innerKey]) {
if (innerKey != "spriteSize" && innerKey != "spriteOffset") delete fileData[innerKey] // remove useless stuff
else fileData[innerKey] = JSON.parse(fileData[innerKey].replace(/{/g, '[').replace(/}/g, ']'));
}
}
}
writeFileSync('./gameSheet.json', JSON.stringify(data.frames, null, 2).replace(/\[\n.+?(-?\d+),\n.+?(-?\d+)\n.+]/g, "[$1, $2]")); // regex to make it easier to read

View file

@ -9,6 +9,7 @@ app.offline = false // set to true to go into "offline" mode (in case of ip ban
app.config = require('./settings') // tweak settings in this file if you're using a GDPS
app.endpoint = app.config.endpoint // default is boomlings.com/database/
app.accountCache = {} // account IDs are cached here to shave off requests to getgjusers
app.lastSuccess = null // timestamp of the last time a gjp request was accepted my the servers
let rlMessage = "Rate limited ¯\\_(ツ)_/¯<br><br>Please do not spam my servers with a crazy amount of requests. It slows things down on my end and stresses RobTop's servers just as much." +
" If you really want to send a zillion requests for whatever reason, please download the GDBrowser repository locally - or even just send the request directly to the GD servers.<br><br>" +
@ -33,6 +34,8 @@ const RL2 = rateLimit({
let api = true;
let gdIcons = fs.readdirSync('./assets/previewicons')
let sampleIcons = require('./misc/sampleIcons.json')
let achievements = require('./misc/achievements.json')
let achievementTypes = require('./misc/achievementTypes.json')
let colorList = require('./icons/colors.json')
let forms = { "player": "cube", "bird": "ufo", "dart": "wave" }
let assetPage = fs.readFileSync('./html/assets.html', 'utf8')
@ -57,6 +60,19 @@ app.use(function(req, res, next) {
let directories = [""]
fs.readdirSync('./api').filter(x => !x.includes(".")).forEach(x => directories.push(x))
app.trackSuccess = function() {
// made this a function in case i wanna do more stuff in the future
app.lastSuccess = Date.now()
}
app.timeSince = function(time=app.lastSuccess) {
if (!time) return "[unknown]"
let secsPassed = Math.floor((Date.now() - time) / 1000)
let minsPassed = Math.floor(secsPassed / 60)
secsPassed -= 60 * minsPassed;
return `${minsPassed}m ${secsPassed}s`
}
app.run = {}
directories.forEach(d => {
fs.readdirSync('./api/' + d).forEach(x => {if (x.includes('.')) app.run[x.split('.')[0]] = require('./api/' + d + "/" + x) })
@ -103,7 +119,7 @@ app.get("/assets/:dir*?", function(req, res) {
if (dir.includes('.') || !req.path.endsWith("/")) {
if (!req.params[0]) main = ""
if (req.params.dir == "deatheffects") return res.sendFile(__dirname + "/assets/deatheffects/0.png")
if (req.params.dir == "deatheffects" || req.params.dir == "trails") return res.sendFile(__dirname + "/assets/deatheffects/0.png")
return res.send(`<p style="font-size: 20px; font-family: aller, helvetica, arial">Looks like this file doesn't exist ¯\\_(ツ)_/¯<br><a href='/assets/${main}'>View directory listing for <b>/assets/${main}</b></a></p>`)
}
@ -140,6 +156,7 @@ app.get("/", function(req, res) {
else res.sendFile(__dirname + "/html/home.html")
})
app.get("/achievements", function(req, res) { res.sendFile(__dirname + "/html/achievements.html") })
app.get("/analyze/:id", async function(req, res) { res.sendFile(__dirname + "/html/analyze.html") })
app.get("/api", function(req, res) { res.sendFile(__dirname + "/html/api.html") })
app.get("/boomlings", function(req, res) { res.sendFile(__dirname + "/html/boomlings.html") })
@ -193,6 +210,7 @@ app.get("/:id", function(req, res) { app.run.level(app, req, res) })
// MISC
app.get("/icon/:text", function(req, res) { app.run.icon(app, req, res) })
app.get("/api/achievements", function(req, res) { res.send({achievements, types: achievementTypes, colors: colorList }) })
app.get('/api/icons', function(req, res) {
let sample = [JSON.stringify(sampleIcons[Math.floor(Math.random() * sampleIcons.length)].slice(1))]
res.send({icons: gdIcons, colors: colorList, colorOrder, whiteIcons, sample});

View file

@ -0,0 +1,26 @@
{
"stars": ["Stars", ["stars"]],
"coins": ["Secret Coins", ["coins"]],
"usercoins": ["User Coins", ["usercoins"]],
"diamonds": ["Diamonds", ["diamonds"]],
"demons": ["Demons", ["demon"]],
"shardFire": ["Fire Shards", ["shardFire"]],
"shardIce": ["Ice Shards", ["shardIce"]],
"shardLava": ["Lava Shards", ["shardLava"]],
"shardPoison": ["Poison Shards", ["shardPoison"]],
"shardShadow": ["Shadow Shards", ["shardShadow"]],
"shardBonus": ["Bonus Shards", ["shardBonus"]],
"level": ["Official Levels", ["level", "mdlevel", "world.level", "steam"]],
"customLevels": ["Online Levels", ["custom"]],
"creator": ["Creator", ["creator", "submit"]],
"ultimate": ["3 Coins", ["demoncoin", "mdcoin"]],
"mappacks": ["Map Packs", ["mappacks"]],
"attempts": ["Attempts", ["attempt", "special"]],
"jumps": ["Jumping", ["jump"]],
"rating": ["Rating", ["like", "rateDiff"]],
"social": ["Social", ["followCreator", "friends"]],
"robtop": ["Support", ["rate", "mdrate", "twitter", "facebook", "youtube", "moreGames", "lite"]],
"secret": ["Secrets + Vault", ["secret"]],
"vaultOfSecrets": ["Vault of Secrets", ["v2.secret"]],
"chamberOfTime": ["Chamber of Time", ["v3.secret"]]
}

2576
misc/achievements.json Normal file

File diff suppressed because it is too large Load diff

68
misc/plistToJSON.js Normal file
View file

@ -0,0 +1,68 @@
let path = "C:/Program Files (x86)/Steam/steamapps/common/Geometry Dash/Resources/"
let files = ["AchievementsDesc", "AchievementsDescMD"]
let values = ["achievedDescription", "title", "icon", "unachievedDescription"]
let innerKey = null
let jsonValues = false
let exportName = "achievements"
// let files = ["GJ_GameSheet02-uhd"]
// let values = ["spriteSize", "spriteOffset"]
// let innerKey = "frames"
// let jsonValues = true
const plist = require('plist');
const fs = require('fs');
let final = {}
files.forEach(file => {
let data = plist.parse(fs.readFileSync(path + file + '.plist', 'utf8'));
if (innerKey) data = data[innerKey]
console.log(`Converting ${file}.plist...`)
for (let key in data) {
let fileData = data[key];
for (let innerKey in fileData) {
if (fileData[innerKey] && values.includes(innerKey)) {
if (!final[key]) final[key] = {}
if (jsonValues) final[key][innerKey] = JSON.parse(fileData[innerKey].replace(/{/g, '[').replace(/}/g, ']')); // for icon sheet
else final[key][innerKey] = fileData[innerKey]
}
}
}
})
console.log("Finishing up...")
if (exportName == "achievements") { // hardcoded shit starts here!
let achString = "geometry.ach."
let rewardTypes = {color: "color1", icon: "cube", bird: "ufo", dart: "wave", special: "trail", death: "deathEffect"}
let games = {"md": "meltdown", "world.": "world"}
let achArray = []
for (let k in final) {
let reward = final[k].icon ? final[k].icon.split("_") : []
let achObj = {
id: k.slice(achString.length),
game: "gd",
name: final[k].title,
rewardType: rewardTypes[reward[0]] || reward[0] || "misc",
rewardID: +reward[1] || -1,
description: final[k].unachievedDescription,
achievedDescription: final[k].achievedDescription
}
Object.keys(games).forEach(x => {
if (k.startsWith(achString + x)) achObj.game = games[x]
})
achArray.push(achObj)
}
data = achArray.filter(x => !x.id.startsWith("lite"))
data = data.filter(x => x.game == "gd").concat(data.filter(x => x.game != "gd"))
}
fs.writeFileSync(exportName + '.json', JSON.stringify(data, null, 2).replace(/\[\n.+?(-?\d+),\n.+?(-?\d+)\n.+]/g, "[$1, $2]")); // regex to make it easier to read
console.log("Successfully converted!")