Add Top 10 only canvas

This commit is contained in:
HF 2022-01-05 20:40:09 +01:00
parent e4fa56fd73
commit b79d44ce4a
19 changed files with 1794 additions and 434 deletions

View File

@ -124,28 +124,27 @@ Notes:
- The HTML for SocialMedia logins is in src/componets/UserAreaModal.js , delete stuff from there if you don't need it
- The HTML for the Help Screen is in src/components/HelpModal.js
Canvas specific configuartion like colors and cooldown is in `canvases.json` for all canvases. The titles and descriptions of the canvases are also in `src/canvasesDesc.js` for translation reasons. Changing them requires a rebuild.
Canvas specific configuartion like colors and cooldown is in `canvases.json` for all canvases. The titles and descriptions of the canvases are in `src/canvasesDesc.js` for translation reasons. Changing them requires a rebuild.
Meaning of some values:
| Key | Description |
|--------|:--------------------------------------------------|
| ident | Unique character used in the url |
| title | Title |
| size | canvas size, power of 4 and between 256 and 65536 |
| bcd | Base cooldown for unset pixels |
| pcd | Cooldown for placing on set pixels |
| cds | Stack time of Cooldown |
| cli | Number of colors on the palette to ignore |
| ranked | If pixels on canvas count on player statistic |
| req | requieremt to place on the canvas |
| sd | Start-date of the canvas for historical view |
| desc | Small desctiption text |
| v | If 3D voxel canvas (boolean) |
| hid | Hidden canvases, can be just seen by pressing P |
| Key | Description |
|--------|:----------------------------------------------------------------|
| ident | Unique character used in the url |
| size | canvas size, power of 4 and between 256 and 65536 |
| bcd | Base cooldown for unset pixels |
| pcd | Cooldown for placing on set pixels (defaults to same as bcd) |
| cds | Stack time of Cooldown |
| cli | Number of leading colors on the palette to ignore (default: 0) |
| ranked | If pixels on canvas count on player statistic (default: false) |
| req | requieremt to place on the canvas |
| sd | Start-date of the canvas for historical view |
| v | If 3D voxel canvas (boolean) (default: false) |
| hid | Hidden canvases, can be just seen by pressing P (default: false)|
Values that have defaults and `req` are optional.
The canvas size limit can be surpassed by changing the websocket packages in src/socket/packages/ to send chunk coordinates in 16bit.
req is an integer and if >0 is the amount of total pixels placed before being allowed to play there, if -1 it has no requirement and if 0 it is limited to registered users.
The colors that are ignored via cli are used for making the canvas (blue ocean and white continents) and to know if the pixel is already set by a user or not.
If `req` is 0, the canvas is only available for registered Useers. If it is a number >0 it is the amount of total pixels placed before a player is allowed to play there. If it is `top`, then it is only accessible for the Top10 players of the previous day.
The colors that are ignored via `cli` are used for making the canvas (blue ocean and white continents) and to know if the pixel is already set by a user or not.
If you want to add a new canvas, be sure that you additionally create `public/loading${canvasId}.png`, `public/assets3d/normal${canvasId}.jpg`, `public/preview${canvasId}.png` and `public/assets3d/specular${canvasId}.jpg`, check out the existing ones to see what those files are for.
The default configuration values can be seen in `src/core/config.js` and for the canvases in `src/core/constats.js`

File diff suppressed because it is too large Load Diff

View File

@ -10,61 +10,57 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals = 2; plural = (n != 1);\n"
"X-Generator: Poedit 2.4.3\n"
"X-Generator: Poedit 3.0.1\n"
#: src/core/ChatProvider.js:287
#: src/core/ChatProvider.js:327
msgid "You can not send chat messages with proxy"
msgstr "Du kannst keine Nachrichten senden wenn du ein Proxy benutzt"
#: src/core/ChatProvider.js:292
msgid "Couldn't send your message, pls log out and back in again."
msgstr "Konnte die Nachricht nicht senden, bitte logge duch aus und wieder an."
#: src/core/ChatProvider.js:306
#: src/core/ChatProvider.js:341
#, javascript-format
msgid "You are sending messages too fast, you have to wait ${ waitTime }s :("
msgstr "Du sendest zu viele Nachrichten, du musst ${ waitTime }s warten :("
#: src/core/ChatProvider.js:310
#: src/core/ChatProvider.js:345
msgid "You don't have access to this channel"
msgstr "Du hast keinen Zugriff zu diesen Kanal"
#: src/core/ChatProvider.js:326
#: src/core/ChatProvider.js:361
msgid "Your mail has to be verified in order to chat"
msgstr "E-Mail muss verifiziert sein um Nachrichten zu senden"
#: src/core/ChatProvider.js:331
#: src/core/ChatProvider.js:366
msgid "You are permanently muted, join our guilded to apppeal the mute"
msgstr ""
"Du bsit permanent stummgeschaltet, gehe zu unser guilded um dagegen "
"einzusprechen"
#: src/core/ChatProvider.js:336
#: src/core/ChatProvider.js:371
#, javascript-format
msgid "You are muted for another ${ timeMin } minutes"
msgstr "Du bist für ${ timeMin } Minuten stummgeschaltet"
#: src/core/ChatProvider.js:338
#: src/core/ChatProvider.js:373
msgid "You are muted for another ${ muted } seconds"
msgstr "Du bist for ${ muted } Sekunden stummgeschaltet"
#: src/core/ChatProvider.js:346
#: src/core/ChatProvider.js:381
msgid "Ow no! Spam protection decided to mute you"
msgstr "Oh nein! Spam-Schutz hat dich stummgeschaltet"
#: src/core/ChatProvider.js:357
#: src/core/ChatProvider.js:392
msgid "You can't send a message this long :("
msgstr "Do kannst keine so langen Nachrichten senden"
#: src/core/ChatProvider.js:361
#: src/core/ChatProvider.js:396
msgid "Please use int channel"
msgstr "Bitte benutze int Kanal"
#: src/core/ChatProvider.js:365
#: src/core/ChatProvider.js:400
msgid "Your country is temporary muted from chat"
msgstr "Dein Land ist temporär stummgeschaltet"
#: src/core/ChatProvider.js:373
#: src/core/ChatProvider.js:408
msgid "Stop flooding."
msgstr "Stoppe zu spamen."
@ -84,39 +80,39 @@ msgstr "PixelPlanet.Fun 3D Globus"
msgid "A 3D globe of our whole map"
msgstr "Ein interaktvier 3D Globus unserer gesamten Karte"
#: src/ssr-components/Main.jsx:73
#: src/ssr-components/Main.jsx:70
msgid "PixelPlanet.fun"
msgstr "PixelPlanet.Fun"
#: src/ssr-components/Main.jsx:75
#: src/ssr-components/Main.jsx:72
msgid "Place color pixels on an map styled canvas with other players online"
msgstr "Zeichne mit farbigen Pixel auf einer Weltkarte mit anderen Spielern"
#: src/routes/reset_password.js:58
#: src/routes/reset_password.js:41
msgid "You sent an empty password or invalid data :("
msgstr "Du hast ein ungültiges Passwort oder Daten gesendet :("
#: src/routes/reset_password.js:70
#: src/routes/reset_password.js:53
msgid "This password-reset link isn't valid anymore :("
msgstr "Dieser Passwort-Wiederherstellungslink ist nichtmehr gültig :("
#: src/routes/reset_password.js:81
#: src/routes/reset_password.js:64
msgid "Your passwords do not match :("
msgstr "Passwörter stimmen nicht überein :("
#: src/routes/reset_password.js:96
#: src/routes/reset_password.js:79
msgid "User doesn't exist in our database :("
msgstr "Spieler existiert nicht in unserer Datenbank :("
#: src/routes/reset_password.js:108
#: src/routes/reset_password.js:91
msgid "Passowrd successfully changed."
msgstr "Passwort erfolgreich geändert."
#: src/routes/reset_password.js:127
#: src/routes/reset_password.js:110
msgid "Invalid url :( Please check your mail again."
msgstr "Ungültige Adresse :( Bitte kontrolliere die Mail nochmal."
#: src/routes/reset_password.js:140
#: src/routes/reset_password.js:123
msgid ""
"This passwort reset link is wrong or already expired, please request a new "
"one (Note: you can use those links just once)"
@ -331,10 +327,6 @@ msgstr "Konnte keinen neuen Benutzer erstellen :("
msgid "Failed to establish session after register :("
msgstr "Konnte keine Sitzung nach registrierung starten :("
#: src/routes/api/auth/logout.js:13
msgid "You are not even logged in."
msgstr "Du bist nichteinmal angemeldet."
#: src/routes/api/auth/verify.js:25 src/routes/api/auth/verify.js:32
msgid "Mail verification"
msgstr "E-Mail verifizieren"
@ -351,6 +343,10 @@ msgstr ""
"Dein E-Mail verifikations Code ist ungültig oder bereits abgelaufen :(, "
"bitte fordere einen neuen an."
#: src/routes/api/auth/logout.js:13
msgid "You are not even logged in."
msgstr "Du bist nichteinmal angemeldet."
#: src/routes/api/auth/change_mail.js:41
#: src/routes/api/auth/change_passwd.js:37
#: src/routes/api/auth/delete_account.js:38
@ -376,34 +372,38 @@ msgstr "Oder ${ clickHere } um zu pixelplanet zurückzukehren"
msgid "PixelPlanet.fun Accounts"
msgstr "PixelPlanet.Fun Konten"
#: src/canvasesDesc.js:19
#: src/canvasesDesc.js:18
msgid "Earth"
msgstr "Erde"
#: src/canvasesDesc.js:20
#: src/canvasesDesc.js:19
msgid "Moon"
msgstr "Mond"
#: src/canvasesDesc.js:21
#: src/canvasesDesc.js:20
msgid "3D Canvas"
msgstr "3D Leinwand"
#: src/canvasesDesc.js:22
#: src/canvasesDesc.js:21
msgid "Coronavirus"
msgstr "Coronavirus"
#: src/canvasesDesc.js:23
#: src/canvasesDesc.js:22
msgid "PixelZone"
msgstr "PixelZone"
#: src/canvasesDesc.js:24
#: src/canvasesDesc.js:23
msgid "PixelCanvas"
msgstr "PixelCanvas"
#: src/canvasesDesc.js:25
#: src/canvasesDesc.js:24
msgid "1bit"
msgstr "1bit"
#: src/canvasesDesc.js:25
msgid "Top10"
msgstr "Top10"
#: src/canvasesDesc.js:28
msgid "Our main canvas, a huge map of the world. Place everywhere you like"
msgstr ""
@ -437,6 +437,21 @@ msgstr "Kopie von PixelCanvas"
msgid "Black and White canvas"
msgstr "Schwarz/Weiß Leinwand"
#: src/canvasesDesc.js:35
msgid ""
"A canvas for the most active players from the the previous day. Daily "
"ranking updates at 00:00 UTC."
msgstr ""
"Eine Leinwand für die zehn aktivsten Spieler des Vortages. Tägliche Reihung "
"wird um 00:00 UTC aktualisiert."
#~ msgid "Top10 Only Canvas"
#~ msgstr "Tip10 Exklusiv"
#~ msgid "Couldn't send your message, pls log out and back in again."
#~ msgstr ""
#~ "Konnte die Nachricht nicht senden, bitte logge duch aus und wieder an."
#~ msgid "Could not connect to server, please try again later :("
#~ msgstr ""
#~ "Konnte nicht zum Server verbinden, bitte versuche es später erneut :("

View File

@ -77,31 +77,31 @@ msgstr ""
msgid "Place color pixels on an map styled canvas with other players online"
msgstr ""
#: src/routes/reset_password.js:58
#: src/routes/reset_password.js:41
msgid "You sent an empty password or invalid data :("
msgstr ""
#: src/routes/reset_password.js:70
#: src/routes/reset_password.js:53
msgid "This password-reset link isn't valid anymore :("
msgstr ""
#: src/routes/reset_password.js:81
#: src/routes/reset_password.js:64
msgid "Your passwords do not match :("
msgstr ""
#: src/routes/reset_password.js:96
#: src/routes/reset_password.js:79
msgid "User doesn't exist in our database :("
msgstr ""
#: src/routes/reset_password.js:108
#: src/routes/reset_password.js:91
msgid "Passowrd successfully changed."
msgstr ""
#: src/routes/reset_password.js:127
#: src/routes/reset_password.js:110
msgid "Invalid url :( Please check your mail again."
msgstr ""
#: src/routes/reset_password.js:140
#: src/routes/reset_password.js:123
msgid ""
"This passwort reset link is wrong or already expired, please request a new "
"one (Note: you can use those links just once)"
@ -374,32 +374,42 @@ msgstr ""
msgid "1bit"
msgstr ""
#: src/canvasesDesc.js:27
msgid "Our main canvas, a huge map of the world. Place everywhere you like"
#: src/canvasesDesc.js:25
msgid "Top10"
msgstr ""
#: src/canvasesDesc.js:28
msgid "Our main canvas, a huge map of the world. Place everywhere you like"
msgstr ""
#: src/canvasesDesc.js:29
msgid ""
"Moon canvas. Safe space for art. No flags or large text (unless part of "
"art) or art larger than 1.5k x 1.5k pixels."
msgstr ""
#: src/canvasesDesc.js:29
#: src/canvasesDesc.js:30
msgid "Place Voxels on a 3D canvas with others"
msgstr ""
#: src/canvasesDesc.js:30
#: src/canvasesDesc.js:31
msgid "Special canvas to spread awareness of SARS-CoV2"
msgstr ""
#: src/canvasesDesc.js:31
#: src/canvasesDesc.js:32
msgid "Mirror of PixelZone"
msgstr ""
#: src/canvasesDesc.js:32
#: src/canvasesDesc.js:33
msgid "Mirror of PixelCanvas"
msgstr ""
#: src/canvasesDesc.js:33
#: src/canvasesDesc.js:34
msgid "Black and White canvas"
msgstr ""
#: src/canvasesDesc.js:35
msgid ""
"A canvas for the most active players from the the previous day. Daily "
"ranking updates at 00:00 UTC."
msgstr ""

File diff suppressed because it is too large Load Diff

BIN
public/loading8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
public/preview8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,7 +1,6 @@
{
"0": {
"ident":"d",
"title": "Earth",
"colors": [
[ 202, 227, 255 ],
[ 255, 255, 255 ],
@ -37,19 +36,15 @@
[ 130, 0, 128 ]
],
"size": 65536,
"hid": false,
"cli": 2,
"bcd": 4000,
"pcd" : 7000,
"cds": 60000,
"ranked" : true,
"req": -1,
"sd": "2020-01-07",
"desc": "Our main canvas, a huge map of the world. Place everywhere you like"
"sd": "2020-01-07"
},
"1": {
"ident": "m",
"title": "Moon",
"colors" : [
[ 49, 46, 47 ],
[ 99, 92, 90 ],
@ -91,19 +86,15 @@
4096
]
],
"hid": false,
"cli": 2,
"bcd": 15000,
"pcd": 15000,
"cds": 900000,
"ranked" : true,
"req": 20000,
"sd": "2020-01-08",
"desc": "Moon canvas. Safe space for art. No flags or large text (unless part of art)"
"sd": "2020-01-08"
},
"2": {
"ident":"v",
"title": "3D Canvas",
"colors": [
[ 255, 255, 255 ],
[ 255, 255, 255 ],
@ -169,20 +160,15 @@
[ 174, 215, 185 ]
],
"size": 1024,
"hid": false,
"v": true,
"cli": 2,
"bcd": 2000,
"pcd" : 2000,
"cds": 60000,
"ranked" : false,
"req": 0,
"sd": "2020-01-08",
"desc": "Place Voxels on a 3D canvas with others"
"sd": "2020-01-08"
},
"3": {
"ident": "c",
"title": "Coronavirus",
"colors" : [
[ 226, 218, 0 ],
[ 33, 28, 15 ],
@ -208,19 +194,14 @@
[ 230, 206, 172 ]
],
"size" : 256,
"hid": false,
"cli": 2,
"bcd": 500,
"pcd": 500,
"cds": 60000,
"ranked" : false,
"req": 0,
"sd": "2020-03-15",
"desc": "Special canvas to spread awareness of SARS-CoV2"
"sd": "2020-03-15"
},
"5": {
"ident": "y",
"title": "PixelZone",
"colors": [
[ 38, 38, 38 ],
[ 0, 0, 0 ],
@ -241,18 +222,12 @@
],
"size": 16384,
"hid": true,
"cli": 0,
"bcd": 4000,
"pcd": 4000,
"cds": 4000,
"ranked": false,
"req": -1,
"sd": "2020-07-05",
"desc": "Mirror of PixelZone"
"sd": "2020-07-05"
},
"6": {
"ident": "z",
"title": "PixelCanvas",
"colors": [
[ 255, 255, 255 ],
[ 228, 228, 228 ],
@ -273,18 +248,12 @@
],
"size": 16384,
"hid": true,
"cli": 0,
"bcd": 10000,
"pcd": 10000,
"cds": 10000,
"ranked": false,
"req": -1,
"sd": "2020-07-05",
"desc": "Mirror of PixelCanvas"
"sd": "2020-07-05"
},
"7": {
"ident": "w",
"title": "1bit",
"colors": [
[ 0, 0, 0 ],
[ 255, 255, 255 ],
@ -292,14 +261,46 @@
[ 255, 255, 255 ]
],
"size": 65536,
"hid": false,
"cli": 2,
"bcd": 7000,
"pcd": 15000,
"cds": 1000000,
"ranked": true,
"req": 5000,
"sd": "2020-11-09",
"desc": "Black and White canvas"
"sd": "2020-11-09"
},
"8": {
"ident": "t",
"colors": [
[ 197, 204, 184 ],
[ 111, 103, 118 ],
[ 154, 154, 151 ],
[ 139, 85, 128 ],
[ 195, 136, 144 ],
[ 165, 147, 165 ],
[ 102, 96, 146 ],
[ 154, 79, 80 ],
[ 194, 141, 117 ],
[ 124, 161, 192 ],
[ 65, 106, 163 ],
[ 141, 98, 104 ],
[ 190, 149, 92 ],
[ 104, 172, 169 ],
[ 56, 112, 128 ],
[ 110, 105, 98 ],
[ 147, 161, 103 ],
[ 110, 170, 120 ],
[ 85, 112, 100 ],
[ 157, 159, 127 ],
[ 126, 158, 153 ],
[ 93, 104, 114 ],
[ 67, 52, 85 ],
[ 0, 0, 0 ]
],
"size": 1024,
"bcd": 15000,
"cds": 900000,
"req": "top",
"sd": "2022-01"
}
}

View File

@ -22,6 +22,7 @@ function getCanvases(t) {
5: t`PixelZone`,
6: t`PixelCanvas`,
7: t`1bit`,
8: t`Top10`,
};
const canvasDesc = {
0: t`Our main canvas, a huge map of the world. Place everywhere you like`,
@ -31,6 +32,7 @@ function getCanvases(t) {
5: t`Mirror of PixelZone`,
6: t`Mirror of PixelCanvas`,
7: t`Black and White canvas`,
8: t`A canvas for the most active players from the the previous day. Daily ranking updates at 00:00 UTC.`,
};
/*
* no edit below here needed when adding/removing canvas
@ -42,8 +44,12 @@ function getCanvases(t) {
for (let i = 0; i < canvasKeys.length; i += 1) {
const key = canvasKeys[i];
localicedCanvases[key] = { ...canvases[key] };
localicedCanvases[key].desc = canvasDesc[key] || `Canvas ${key}`;
localicedCanvases[key].title = canvasTitles[key] || `Canvas ${key}`;
localicedCanvases[key].desc = canvasDesc[key]
|| canvases[key].desc
|| `Canvas ${key}`;
localicedCanvases[key].title = canvasTitles[key]
|| canvases[key].title
|| `Canvas ${key}`;
}
return localicedCanvases;

View File

@ -34,7 +34,7 @@ const CanvasItem = ({
<span className="modalinfo">{canvas.desc}</span><br />
{t`Cooldown`}:&nbsp;
<span className="modalinfo">
{(canvas.bcd !== canvas.pcd)
{(canvas.pcd && canvas.bcd !== canvas.pcd)
? <span> {canvas.bcd / 1000}s / {canvas.pcd / 1000}s</span>
: <span> {canvas.bcd / 1000}s</span>}
</span><br />
@ -45,14 +45,23 @@ const CanvasItem = ({
(canvas.ranked) ? t`Yes` : t`No`
}
</span><br />
{(canvas.req !== -1) ? <span>{t`Requirements`}:<br /></span> : null}
<span className="modalinfo">
{(canvas.req !== -1) ? <span>{t`User Account`} </span> : null}
{(canvas.req > 0)
? <span> {t`and ${canvas.req} Pixels set`}</span>
: null}
</span>
{(canvas.req !== -1) ? <br /> : null}
{(canvas.req !== undefined) && (
<>
<span>
{t`Requirements`}:<br />
<span className="modalinfo">
{(typeof canvas.req === 'number')
? <span>{t`User Account`} </span> : null}
{(canvas.req > 0)
? <span> {t`and ${canvas.req} Pixels set`} </span>
: null}
{(canvas.req === 'top')
&& <span>{t`Top 10 Daily Ranking`}</span>}
</span>
</span>
<br />
</>
)}
{t`Dimensions`}:&nbsp;
<span className="modalinfo"> {canvas.size} x {canvas.size}
{(canvas.v)

View File

@ -126,7 +126,7 @@ function Converter() {
if (inputImageCanvas) {
const canvas = canvases[selectedCanvas];
renderOutputImage({
colors: canvas.colors.slice(canvas.cli),
colors: (canvas.cli) ? canvas.colors.slice(canvas.cli) : canvas.colors,
imgCanvas: inputImageCanvas,
ditherOpts: {
strategy: selectedStrategy,
@ -184,11 +184,6 @@ function Converter() {
}, [scaleData.enabled]);
const gimpLink = <a href="https://www.gimp.org">GIMP</a>;
const starhouseLink = (
<a href="https://twitter.com/starhousedev">
starhouse
</a>
);
return (
<div style={{ textAlign: 'center' }}>
@ -237,9 +232,6 @@ function Converter() {
>
Download
</button>
<p>
{jt`Credit for the Palette of the Moon goes to ${starhouseLink}.`}
</p>
</div>
<h3 className="modaltitle">{t`Image Converter`}</h3>
<p className="modalcotext">{t`Convert an image to canvas colors`}</p>

View File

@ -1,6 +1,5 @@
/**
*
* @flow
*/
import React from 'react';
@ -31,6 +30,8 @@ const Help = () => {
const bindShift = <kbd> {c('keybinds').t`Shift`}</kbd>;
const bindC = <kbd>{c('keybinds').t`C`}</kbd>;
const starhouseLink = <a href="https://twitter.com/starhousedev">starhouse </a>;
const vinikLink = <a href="https://twitter.com/Vinikdev">Vinikdev</a>;
const guildedLink = <a href="https://pixelplanet.fun/guilded">guilded</a>;
const getIPLink = <a href="https://www.whatismyip.com/">{t`your IP`}</a>;
const mailLink = <a href="mailto:pixelplanetdev@gmail.com">pixelplanetdev@gmail.com</a>;
@ -84,7 +85,17 @@ can be downloaded from mega.nz here: `}<a href="https://mega.nz/#!JpkBwAbJ!EnSLl
{jt`${mouseSymbol} Right click or ${touchSymbol} double-tap to remove a pixel`}<br />
{jt`Click ${mouseSymbol} middle mouse button or ${touchSymbol} long-tap to select current hovering color`}<br />
</div>
<p>{t`Partners:`} <a href="https://www.crazygames.com/c/io" target="_blank" rel="noopener noreferrer">crazygames.com</a></p>
<h3 className="modaltitle">Palette Credits</h3>
<div className="modaltext">
{jt`We thanks those artists very much, they offered their palettes to the public on`}&nbsp;
<a href="https://lospec.com/">lospec.com</a>
<p>
{jt`Credit for the Palette of the Moon goes to ${starhouseLink}.`}
</p>
<p>
{jt`Credit for the Palette of the Top10 canvas goes to ${vinikLink}.`}
</p>
</div>
</div>
);
};

View File

@ -13,6 +13,7 @@ import {
setPixelByOffset,
setPixelByCoords,
} from './setPixel';
import rankings from './ranking';
import rpgEvent from './event';
// eslint-disable-next-line import/no-unresolved
import canvases from './canvases.json';
@ -46,18 +47,16 @@ export async function drawByOffsets(
let pxlCnt = 0;
const canvas = canvases[canvasId];
if (!canvas) {
// canvas doesn't exist
return {
wait,
coolDown,
pxlCnt,
retCode: 1,
};
}
const { size: canvasSize, v: is3d } = canvas;
try {
if (!canvas) {
// canvas doesn't exist
throw new Error(1);
}
const canvasSize = canvas.size;
const is3d = !!canvas.v;
wait = await user.getWait(canvasId);
const tileSize = (is3d) ? THREE_TILE_SIZE : TILE_SIZE;
@ -74,19 +73,26 @@ export async function drawByOffsets(
// (we don't have to check for <0 becaue it is received as uint)
throw new Error(3);
}
if (canvas.req !== -1) {
const isAdmin = (user.userlvl === 1);
if (canvas.req !== undefined && !isAdmin) {
if (user.id === null) {
// not logged in
throw new Error(6);
}
const totalPixels = await user.getTotalPixels();
if (totalPixels < canvas.req) {
// not enough pixels placed yet
throw new Error(7);
if (canvas.req > 0) {
const totalPixels = await user.getTotalPixels();
if (totalPixels < canvas.req) {
// not enough pixels placed yet
throw new Error(7);
}
}
if (canvas.req === 'top' && !rankings.prevTop.includes(user.id)) {
throw new Error(12);
}
}
const isAdmin = (user.userlvl === 1);
let coolDownFactor = 1;
if (rpgEvent.success) {
if (rpgEvent.success === 1) {
@ -118,6 +124,8 @@ export async function drawByOffsets(
offset,
);
const clrIgnore = canvas.cli || 0;
/*
* pixel validation
*/
@ -128,7 +136,7 @@ export async function drawByOffsets(
throw new Error(4);
}
if (color >= canvas.colors.length
|| (color < canvas.cli && !(canvas.v && color === 0))
|| (color < clrIgnore && !(canvas.v && color === 0))
) {
// color out of bounds
throw new Error(5);
@ -145,7 +153,8 @@ export async function drawByOffsets(
throw new Error(8);
}
coolDown = (setColor & 0x3F) < canvas.cli ? canvas.bcd : canvas.pcd;
coolDown = ((setColor & 0x3F) >= clrIgnore && canvas.pcd)
? canvas.pcd : canvas.bcd;
if (isAdmin) {
coolDown = 0.0;
} else {
@ -191,6 +200,7 @@ export async function drawByOffsets(
*
* Old version of draw that returns explicit error messages
* used for http json api/pixel, used with coordinates
* Is not used anywhere currently, but we keep it around.
* @param user
* @param canvasId
* @param x
@ -206,13 +216,14 @@ export async function drawByCoords(
y,
z = null,
) {
if (!({}.hasOwnProperty.call(canvases, canvasId))) {
const canvas = canvases[canvasId];
if (!canvas) {
return {
error: 'This canvas does not exist',
success: false,
};
}
const canvas = canvases[canvasId];
const canvasMaxXY = canvas.size / 2;
const canvasMinXY = -canvasMaxXY;
@ -222,6 +233,9 @@ export async function drawByCoords(
success: false,
};
}
const clrIgnore = canvas.cli || 0;
if (canvas.v) {
if (z < canvasMinXY || z >= canvasMaxXY) {
return {
@ -254,7 +268,7 @@ export async function drawByCoords(
success: false,
};
}
if (color < canvas.cli) {
if (color < clrIgnore) {
return {
error: 'Invalid color selected',
success: false,
@ -301,7 +315,11 @@ export async function drawByCoords(
const isAdmin = (user.userlvl === 1);
const setColor = await RedisCanvas.getPixel(canvasId, x, y, z);
let coolDown = (setColor & 0x3F) < canvas.cli ? canvas.bcd : canvas.pcd;
/*
* bitwise operation to get rid of protection
*/
let coolDown = ((setColor & 0x3F) >= clrIgnore && canvas.pcd)
? canvas.pcd : canvas.bcd;
if (isAdmin) {
coolDown = 0.0;
} else if (rpgEvent.success) {

View File

@ -6,6 +6,7 @@
import Sequelize from 'sequelize';
import Model from '../data/sequelize';
import RegUser from '../data/models/RegUser';
import { saveDailyTop, loadDailyTop } from '../data/models/prevDayTop';
import logger from './logger';
import { MINUTE } from './constants';
@ -17,12 +18,21 @@ class Ranks {
constructor() {
this.updateRanking = this.updateRanking.bind(this);
this.resetDailyRanking = this.resetDailyRanking.bind(this);
this.prevTop = [];
this.ranks = {
dailyRanking: [],
ranking: [],
};
this.ranks = {};
this.loadPrevDayTop();
setInterval(this.updateRanking, 5 * MINUTE);
DailyCron.hook(this.resetDailyRanking);
}
async loadPrevDayTop() {
this.prevTop = await loadDailyTop();
}
async updateRanking() {
// recalculate ranking column
await Model.query(
@ -36,6 +46,7 @@ class Ranks {
// populate dictionaries
const ranking = await RegUser.findAll({
attributes: [
'id',
'name',
'totalPixels',
'ranking',
@ -57,6 +68,7 @@ class Ranks {
});
const dailyRanking = await RegUser.findAll({
attributes: [
'id',
'name',
'totalPixels',
'ranking',
@ -81,6 +93,7 @@ class Ranks {
}
async resetDailyRanking() {
this.prevTop = await saveDailyTop(this.ranks.dailyRanking);
logger.info('Resetting Daily Ranking');
await RegUser.update({ dailyTotalPixels: 0 }, { where: {} });
await this.updateRanking();

View File

@ -88,8 +88,7 @@ class RedisCanvas {
const key = `ch:${canvasId}:${i}:${j}`;
if (!chunks.has(key)) {
const is3D = canvases[canvasId].v;
if (is3D) {
if (canvases[canvasId].v) {
await redis.setAsync(key, THREE_EMPTY_CHUNK_BUFFER, 'NX');
} else {
await redis.setAsync(key, EMPTY_CHUNK_BUFFER, 'NX');

View File

@ -0,0 +1,30 @@
/*
* saving and loading the top 10 of the previous day
*/
import redis from '../redis';
import logger from '../../core/logger';
const PREV_DAILY_TOP_KEY = 'prevtop';
/*
* saves the top 10 into redis
* @param dailyRanking Array of dailyRanking
*/
export async function saveDailyTop(dailyRanking) {
const top10 = dailyRanking.slice(10).map((user) => user.id);
const jsonTop = JSON.stringify(top10);
logger.info(`Saving current daily top 10 into redis: ${jsonTop}`);
await redis.setAsync(PREV_DAILY_TOP_KEY, jsonTop);
return top10;
}
/*
* load top10 from redis
* @return Promis<Array> Array of user IDs of the top 10
*/
export async function loadDailyTop() {
const jsonTop = await redis.getAsync(PREV_DAILY_TOP_KEY);
logger.info(`Loaded current daily top 10 into redis: ${jsonTop}`);
return (jsonTop) ? JSON.parse(jsonTop) : [];
}

View File

@ -62,9 +62,9 @@ function getViewFromURL(canvases: Object) {
const canvas = (canvasId === null)
? canvases[DEFAULT_CANVAS_ID]
: canvases[canvasId];
const clrIgnore = canvas.cli || 0;
const {
colors,
cli: clrIgnore,
sd: canvasStartDate,
size: canvasSize,
} = canvas;
@ -120,8 +120,8 @@ function getViewFromURL(canvases: Object) {
canvasStartDate: null,
canvasMaxTiledZoom: getMaxTiledZoom(canvasd.size),
palette: new Palette(canvasd.colors, 0),
clrIgnore: canvasd.cli,
selectedColor: canvasd.cli,
clrIgnore: canvasd.cli || 0,
selectedColor: canvasd.cli || 0,
view: [0, 0, 0],
viewscale: DEFAULT_SCALE,
scale: DEFAULT_SCALE,
@ -267,12 +267,12 @@ export default function canvasReducer(
canvasId = DEFAULT_CANVAS_ID;
canvas = canvases[DEFAULT_CANVAS_ID];
}
const clrIgnore = canvas.cli || 0;
const {
size: canvasSize,
sd: canvasStartDate,
ident: canvasIdent,
v: is3D,
cli: clrIgnore,
colors,
} = canvas;
// get previous view, scale and viewscale if possible
@ -334,13 +334,14 @@ export default function canvasReducer(
canvasId = DEFAULT_CANVAS_ID;
canvasIdent = canvases[DEFAULT_CANVAS_ID].ident;
}
const canvas = canvases[canvasId];
const clrIgnore = canvas.cli || 0;
const is3D = !!canvases.v;
const {
size: canvasSize,
sd: canvasStartDate,
v: is3D,
cli: clrIgnore,
colors,
} = canvases[canvasId];
} = canvas;
const palette = new Palette(colors, 0);
if (!is3D) {

View File

@ -242,6 +242,10 @@ export function receivePixelReturn(
errorTitle = t`No Proxies Allowed :(`;
msg = t`You are using a Proxy.`;
break;
case 12:
errorTitle = t`Not allowed`;
msg = t`Just the Top10 of yesterday can place here`;
break;
default:
errorTitle = t`Weird`;
msg = t`Couldn't set Pixel`;

View File

@ -178,11 +178,12 @@ export function buildWebpackClientConfig(
chunkModules: false,
},
cache: {
type: 'filesystem',
name: (development) ? `${locale}-dev` : locale,
buildDependencies,
},
cache: (extract) ? false
: {
type: 'filesystem',
name: (development) ? `${locale}-dev` : locale,
buildDependencies,
},
};
}