pixelplanet/src/ui/placePixel.js

278 lines
5.9 KiB
JavaScript
Raw Normal View History

/*
* Place pixel via Websocket
* Always just one pixelrequest, queue additional requests to send later
* Pixels get predicted on the client and reset if server refused
*
* TODO move stuff out of here and to actions / middleware
* clientPredictions could be in rendererHook
*
* */
import { t } from 'ttag';
import {
2022-08-15 19:35:55 +00:00
requestPlaceTimeout,
pAlert,
storeReceivePixelReturn,
2022-08-15 19:35:55 +00:00
requestPlacePixels,
2022-07-11 12:42:09 +00:00
} from '../store/actions';
import {
notify,
} from '../store/actions/thunks';
let pixelTimeout = null;
/*
* cache of pixels that still are to set
* [{i: i, j: j, pixels: [[offset, color],...]}, ...]
*/
let pixelQueue = [];
/*
* requests that got predicted on client and yet have to be
* received from the server
* [[i, j, offset, colorold, colornew], ...]
*/
let clientPredictions = [];
/*
* values of last request
* {i: i, j: j, pixels: [[offset, color], ...}
*/
let lastRequestValues = {};
/*
* request pixel placement from queue
*/
function requestFromQueue(store) {
if (!pixelQueue.length) {
pixelTimeout = null;
return;
}
/* timeout to warn user when Websocket is dysfunctional */
pixelTimeout = setTimeout(() => {
pixelQueue = [];
pixelTimeout = null;
2022-08-15 19:35:55 +00:00
store.dispatch(requestPlaceTimeout());
store.dispatch(pAlert(
t`Error :(`,
t`Didn't get an answer from pixelplanet. Maybe try to refresh?`,
'error',
));
2022-04-04 10:17:47 +00:00
}, 15000);
lastRequestValues = pixelQueue.shift();
const { i, j, pixels } = lastRequestValues;
2022-08-15 19:35:55 +00:00
store.dispatch(requestPlacePixels(i, j, pixels));
}
/*
* got pixel update from websocket
*/
export function receivePixelUpdate(
renderer,
i,
j,
offset,
color,
) {
2021-01-27 01:21:29 +00:00
for (let p = 0; p < clientPredictions.length; p += 1) {
const predPxl = clientPredictions[p];
if (predPxl[0] === i
&& predPxl[1] === j
&& predPxl[2] === offset
) {
if (predPxl[4] === color) {
2021-07-31 20:48:11 +00:00
clientPredictions.splice(p, 1);
}
return;
}
}
renderer.renderPixel(i, j, offset, color, true);
}
/*
* Revert predictions starting at given pixel
* @param i, j, offset data of the first pixel that got rejected
*/
function revertPredictionsAt(
renderer,
sI,
sJ,
sOffset,
) {
let p = 0;
while (p < clientPredictions.length) {
const predPxl = clientPredictions[p];
if (predPxl[0] === sI
&& predPxl[1] === sJ
&& predPxl[2] === sOffset
) {
break;
}
p += 1;
}
if (p >= clientPredictions.length) {
clientPredictions = [];
return;
}
while (p < clientPredictions.length) {
const [i, j, offset, color] = clientPredictions[p];
renderer.renderPixel(i, j, offset, color, false);
p += 1;
}
clientPredictions = [];
}
/*
* try to place a pixel
*/
export function tryPlacePixel(
renderer,
store,
i,
j,
offset,
color,
curColor,
) {
renderer.renderPixel(i, j, offset, color, false);
clientPredictions.push([i, j, offset, curColor, color]);
if (pixelQueue.length) {
const lastReq = pixelQueue[pixelQueue.length - 1];
const { i: lastI, j: lastJ } = lastReq;
if (i === lastI && j === lastJ) {
/* append to last request in queue if same chunk */
lastReq.pixels.push([offset, color]);
}
return;
}
pixelQueue.push({
i,
j,
pixels: [[offset, color]],
});
if (!pixelTimeout) {
requestFromQueue(store);
}
}
/*
* got return from pixel request
*/
export function receivePixelReturn(
store,
renderer,
args,
) {
clearTimeout(pixelTimeout);
store.dispatch(storeReceivePixelReturn(args));
const {
retCode,
coolDownSeconds,
pxlCnt,
} = args;
2021-01-29 01:14:17 +00:00
if (coolDownSeconds) {
store.dispatch(notify(coolDownSeconds));
}
if (retCode) {
/*
2021-01-29 01:14:17 +00:00
* one or more pixels didn't get set,
* revert predictions and clean queue
*/
2021-01-29 01:14:17 +00:00
const { i, j, pixels } = lastRequestValues;
const [offset] = pixels[pxlCnt];
revertPredictionsAt(renderer, i, j, offset);
2021-01-29 01:14:17 +00:00
pixelQueue = [];
}
2021-01-29 01:14:17 +00:00
let errorTitle = null;
let msg = null;
2022-08-06 03:59:33 +00:00
let type = 'error';
2021-01-29 01:14:17 +00:00
switch (retCode) {
case 0:
break;
case 1:
errorTitle = t`Invalid Canvas`;
msg = t`This canvas doesn't exist`;
2021-01-29 01:14:17 +00:00
break;
case 2:
errorTitle = t`Invalid Coordinates`;
msg = t`x out of bounds`;
2021-01-29 01:14:17 +00:00
break;
case 3:
errorTitle = t`Invalid Coordinates`;
msg = t`y out of bounds`;
2021-01-29 01:14:17 +00:00
break;
case 4:
errorTitle = t`Invalid Coordinates`;
msg = t`z out of bounds`;
2021-01-29 01:14:17 +00:00
break;
case 5:
errorTitle = t`Wrong Color`;
msg = t`Invalid color selected`;
2021-01-29 01:14:17 +00:00
break;
case 6:
errorTitle = t`Just for registered Users`;
msg = t`You have to be logged in to place on this canvas`;
2021-01-29 01:14:17 +00:00
break;
case 7:
errorTitle = t`Place more :)`;
2021-01-29 01:14:17 +00:00
// eslint-disable-next-line max-len
msg = t`You can not access this canvas yet. You need to place more pixels`;
2021-01-29 01:14:17 +00:00
break;
case 8:
store.dispatch(notify(t`Pixel protected!`));
2021-01-29 01:14:17 +00:00
break;
case 9:
// pixestack used up
break;
case 10:
2022-08-06 03:59:33 +00:00
errorTitle = 'Captcha';
msg = t`Please prove that you are human`;
type = 'captcha';
break;
2021-01-29 01:14:17 +00:00
case 11:
errorTitle = t`No Proxies Allowed :(`;
msg = t`You are using a Proxy.`;
2021-01-29 01:14:17 +00:00
break;
2022-01-05 19:40:09 +00:00
case 12:
errorTitle = t`Not allowed`;
msg = t`Just the Top10 of yesterday can place here`;
break;
2022-07-01 21:45:25 +00:00
case 13:
errorTitle = t`You are weird`;
// eslint-disable-next-line max-len
msg = t`Server got confused by your pixels. Are you playing on multiple devices?`;
break;
case 14:
2022-08-06 03:59:33 +00:00
errorTitle = t`Banned`;
2022-08-08 12:11:22 +00:00
type = 'ban';
2022-08-06 03:59:33 +00:00
break;
case 15:
errorTitle = t`Range Banned`;
msg = t`Your Internet Provider is banned from playing this game`;
break;
2021-01-29 01:14:17 +00:00
default:
errorTitle = t`Weird`;
msg = t`Couldn't set Pixel`;
2021-01-29 01:14:17 +00:00
}
2022-08-06 03:59:33 +00:00
if (msg || errorTitle) {
store.dispatch(pAlert(
(errorTitle || t`Error ${retCode}`),
2021-01-29 01:14:17 +00:00
msg,
2022-08-06 03:59:33 +00:00
type,
2021-01-29 01:14:17 +00:00
));
}
2021-01-29 01:14:17 +00:00
requestFromQueue(store);
}