pixel burst client side
add client prediction
This commit is contained in:
parent
277568fc9c
commit
1735643b32
|
@ -233,139 +233,6 @@ export function notify(notification: string) {
|
|||
};
|
||||
}
|
||||
|
||||
function gotCoolDownDelta(delta: number) {
|
||||
return {
|
||||
type: 'COOLDOWN_DELTA',
|
||||
delta,
|
||||
};
|
||||
}
|
||||
|
||||
let pixelTimeout = null;
|
||||
export function tryPlacePixel(
|
||||
i: number,
|
||||
j: number,
|
||||
offset: number,
|
||||
color: ColorIndex,
|
||||
): ThunkAction {
|
||||
return async (dispatch) => {
|
||||
pixelTimeout = Date.now() + 5000;
|
||||
await dispatch(setPlaceAllowed(false));
|
||||
|
||||
// TODO:
|
||||
// this is for resending after captcha returned
|
||||
// window is ugly, put it into redux or something
|
||||
window.pixel = {
|
||||
i,
|
||||
j,
|
||||
offset,
|
||||
color,
|
||||
};
|
||||
|
||||
dispatch({
|
||||
type: 'REQUEST_PLACE_PIXEL',
|
||||
i,
|
||||
j,
|
||||
offset,
|
||||
color,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function receivePixelReturn(
|
||||
retCode: number,
|
||||
wait: number,
|
||||
coolDownSeconds: number,
|
||||
): ThunkAction {
|
||||
return (dispatch) => {
|
||||
try {
|
||||
/*
|
||||
* the terms coolDown is used in a different meaning here
|
||||
* coolDown is the delta seconds of the placed pixel
|
||||
*/
|
||||
if (wait) {
|
||||
dispatch(setWait(wait));
|
||||
}
|
||||
if (coolDownSeconds) {
|
||||
dispatch(notify(coolDownSeconds));
|
||||
if (coolDownSeconds < 0) {
|
||||
dispatch(gotCoolDownDelta(coolDownSeconds));
|
||||
}
|
||||
}
|
||||
|
||||
let errorTitle = null;
|
||||
let msg = null;
|
||||
switch (retCode) {
|
||||
case 0:
|
||||
dispatch(placedPixel());
|
||||
break;
|
||||
case 1:
|
||||
errorTitle = 'Invalid Canvas';
|
||||
msg = 'This canvas doesn\'t exist';
|
||||
break;
|
||||
case 2:
|
||||
errorTitle = 'Invalid Coordinates';
|
||||
msg = 'x out of bounds';
|
||||
break;
|
||||
case 3:
|
||||
errorTitle = 'Invalid Coordinates';
|
||||
msg = 'y out of bounds';
|
||||
break;
|
||||
case 4:
|
||||
errorTitle = 'Invalid Coordinates';
|
||||
msg = 'z out of bounds';
|
||||
break;
|
||||
case 5:
|
||||
errorTitle = 'Wrong Color';
|
||||
msg = 'Invalid color selected';
|
||||
break;
|
||||
case 6:
|
||||
errorTitle = 'Just for registered Users';
|
||||
msg = 'You have to be logged in to place on this canvas';
|
||||
break;
|
||||
case 7:
|
||||
errorTitle = 'Place more :)';
|
||||
// eslint-disable-next-line max-len
|
||||
msg = 'You can not access this canvas yet. You need to place more pixels';
|
||||
break;
|
||||
case 8:
|
||||
dispatch(notify('Pixel protected!'));
|
||||
break;
|
||||
case 9:
|
||||
// pixestack used up
|
||||
dispatch(pixelWait());
|
||||
break;
|
||||
case 10:
|
||||
// captcha, reCaptcha or hCaptcha
|
||||
if (typeof window.hcaptcha !== 'undefined') {
|
||||
window.hcaptcha.execute();
|
||||
} else {
|
||||
window.grecaptcha.execute();
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
errorTitle = 'No Proxies Allowed :(';
|
||||
msg = 'You are using a Proxy.';
|
||||
break;
|
||||
default:
|
||||
errorTitle = 'Weird';
|
||||
msg = 'Couldn\'t set Pixel';
|
||||
}
|
||||
if (msg) {
|
||||
dispatch(pixelFailure());
|
||||
dispatch(sweetAlert(
|
||||
(errorTitle || `Error ${retCode}`),
|
||||
msg,
|
||||
'error',
|
||||
'OK',
|
||||
));
|
||||
}
|
||||
} finally {
|
||||
pixelTimeout = null;
|
||||
dispatch(setPlaceAllowed(true));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setViewCoordinates(view: Cell): Action {
|
||||
return {
|
||||
type: 'SET_VIEW_COORDINATES',
|
||||
|
@ -415,7 +282,6 @@ export function moveEast(): ThunkAction {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
export function setScale(scale: number, zoompoint: Cell): Action {
|
||||
return {
|
||||
type: 'SET_SCALE',
|
||||
|
@ -484,7 +350,7 @@ export function receiveCoolDown(
|
|||
};
|
||||
}
|
||||
|
||||
export function receivePixelUpdate(
|
||||
export function updatePixel(
|
||||
i: number,
|
||||
j: number,
|
||||
offset: number,
|
||||
|
@ -668,18 +534,6 @@ function getPendingActions(state): Array<Action> {
|
|||
else actions.push(endCoolDown());
|
||||
}
|
||||
|
||||
if (pixelTimeout && now > pixelTimeout) {
|
||||
actions.push(pixelFailure());
|
||||
pixelTimeout = null;
|
||||
actions.push(setPlaceAllowed(true));
|
||||
actions.push(sweetAlert(
|
||||
'Error :(',
|
||||
'Didn\'t get an answer from pixelplanet. Maybe try to refresh?',
|
||||
'error',
|
||||
'OK',
|
||||
));
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -849,6 +703,13 @@ export function startDm(query): PromiseAction {
|
|||
};
|
||||
}
|
||||
|
||||
export function gotCoolDownDelta(delta: number) {
|
||||
return {
|
||||
type: 'COOLDOWN_DELTA',
|
||||
delta,
|
||||
};
|
||||
}
|
||||
|
||||
export function setUserBlock(
|
||||
userId: number,
|
||||
userName: string,
|
||||
|
|
|
@ -39,12 +39,6 @@ export type Action =
|
|||
| { type: 'COOLDOWN_DELTA', delta: number }
|
||||
| { type: 'SELECT_COLOR', color: ColorIndex }
|
||||
| { type: 'SELECT_CANVAS', canvasId: number }
|
||||
| { type: 'REQUEST_PLACE_PIXEL',
|
||||
i: number,
|
||||
j: number,
|
||||
offset: number,
|
||||
color: ColorIndex,
|
||||
}
|
||||
| { type: 'PLACE_PIXEL' }
|
||||
| { type: 'PIXEL_WAIT' }
|
||||
| { type: 'PIXEL_FAILURE' }
|
||||
|
|
|
@ -7,7 +7,6 @@ import './styles/font.css';
|
|||
|
||||
import onKeyPress from './controls/keypress';
|
||||
import {
|
||||
receivePixelUpdate,
|
||||
fetchMe,
|
||||
fetchStats,
|
||||
initTimer,
|
||||
|
@ -15,12 +14,14 @@ import {
|
|||
receiveOnline,
|
||||
receiveCoolDown,
|
||||
receiveChatMessage,
|
||||
receivePixelReturn,
|
||||
addChatChannel,
|
||||
removeChatChannel,
|
||||
setMobile,
|
||||
tryPlacePixel,
|
||||
} from './actions';
|
||||
import {
|
||||
receivePixelUpdate,
|
||||
receivePixelReturn,
|
||||
} from './ui/placePixel';
|
||||
import store from './ui/store';
|
||||
|
||||
|
||||
|
@ -33,15 +34,18 @@ function init() {
|
|||
initRenderer(store, false);
|
||||
|
||||
ProtocolClient.on('pixelUpdate', ({
|
||||
i, j, offset, color,
|
||||
i, j, pixels,
|
||||
}) => {
|
||||
// remove protection
|
||||
store.dispatch(receivePixelUpdate(i, j, offset, color & 0x7F));
|
||||
pixels.forEach((pxl) => {
|
||||
const [offset, color] = pxl;
|
||||
// remove protection
|
||||
receivePixelUpdate(store, i, j, offset, color & 0x7F);
|
||||
});
|
||||
});
|
||||
ProtocolClient.on('pixelReturn', ({
|
||||
retCode, wait, coolDownSeconds,
|
||||
retCode, wait, coolDownSeconds, pxlCnt,
|
||||
}) => {
|
||||
store.dispatch(receivePixelReturn(retCode, wait, coolDownSeconds));
|
||||
receivePixelReturn(store, retCode, wait, coolDownSeconds, pxlCnt);
|
||||
});
|
||||
ProtocolClient.on('cooldownPacket', (coolDown) => {
|
||||
store.dispatch(receiveCoolDown(coolDown));
|
||||
|
@ -145,16 +149,13 @@ window.onCaptcha = async function onCaptcha(token: string) {
|
|||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
// https://github.com/github/fetch/issues/349
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
if (window.pixel) {
|
||||
const {
|
||||
i, j, offset, color,
|
||||
} = window.pixel;
|
||||
store.dispatch(tryPlacePixel(i, j, offset, color));
|
||||
}
|
||||
const {
|
||||
i, j, pixels,
|
||||
} = window.pixel;
|
||||
ProtocolClient.requestPlacePixels(i, j, pixels);
|
||||
|
||||
if (typeof window.hcaptcha !== 'undefined') {
|
||||
window.hcaptcha.reset();
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import keycode from 'keycode';
|
||||
|
||||
import {
|
||||
tryPlacePixel,
|
||||
setHover,
|
||||
unsetHover,
|
||||
setViewCoordinates,
|
||||
|
@ -21,6 +20,9 @@ import {
|
|||
moveEast,
|
||||
onViewFinishChange,
|
||||
} from '../actions';
|
||||
import {
|
||||
tryPlacePixel,
|
||||
} from '../ui/placePixel';
|
||||
import {
|
||||
screenToWorld,
|
||||
getChunkOfPixel,
|
||||
|
@ -162,7 +164,6 @@ class PixelPlainterControls {
|
|||
static placePixel(store, renderer, cell) {
|
||||
const state = store.getState();
|
||||
const { autoZoomIn } = state.gui;
|
||||
const { placeAllowed } = state.user;
|
||||
const {
|
||||
scale,
|
||||
isHistoricalView,
|
||||
|
@ -180,16 +181,17 @@ class PixelPlainterControls {
|
|||
// allow placing of pixel just on low zoomlevels
|
||||
if (scale < 3) return;
|
||||
|
||||
if (!placeAllowed) return;
|
||||
|
||||
if (selectedColor !== renderer.getColorIndexOfPixel(...cell)) {
|
||||
const curColor = renderer.getColorIndexOfPixel(...cell);
|
||||
if (selectedColor !== curColor) {
|
||||
const { canvasSize } = state.canvas;
|
||||
const [i, j] = getChunkOfPixel(canvasSize, ...cell);
|
||||
const offset = getOffsetOfPixel(canvasSize, ...cell);
|
||||
store.dispatch(tryPlacePixel(
|
||||
tryPlacePixel(
|
||||
store,
|
||||
i, j, offset,
|
||||
selectedColor,
|
||||
));
|
||||
curColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ class PixelCache {
|
|||
this.PXL_CACHE = new Map();
|
||||
|
||||
cache.forEach((pxls, chunkCanvasId) => {
|
||||
const canvasId = chunkCanvasId & 0xFF0000 >> 16;
|
||||
const canvasId = (chunkCanvasId & 0xFF0000) >> 16;
|
||||
const chunkId = chunkCanvasId & 0x00FFFF;
|
||||
webSockets.broadcastPixels(canvasId, chunkId, pxls);
|
||||
});
|
||||
|
|
|
@ -51,6 +51,7 @@ export async function drawByOffsets(
|
|||
return {
|
||||
wait,
|
||||
coolDown,
|
||||
pxlCnt,
|
||||
retCode: 1,
|
||||
};
|
||||
}
|
||||
|
@ -177,6 +178,7 @@ export async function drawByOffsets(
|
|||
return {
|
||||
wait,
|
||||
coolDown,
|
||||
pxlCnt,
|
||||
retCode,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ class ProtocolClient extends EventEmitter {
|
|||
* @param i, j chunk coordinates
|
||||
* @param pixel Array of [[offset, color],...] pixels within chunk
|
||||
*/
|
||||
requestPlacePixel(
|
||||
requestPlacePixels(
|
||||
i: number, j: number,
|
||||
pixels: Array,
|
||||
) {
|
||||
|
|
|
@ -390,6 +390,7 @@ class SocketServer extends WebSocketEvents {
|
|||
const {
|
||||
wait,
|
||||
coolDown,
|
||||
pxlCnt,
|
||||
retCode,
|
||||
} = await drawSafeByOffsets(
|
||||
ws.user,
|
||||
|
@ -397,7 +398,7 @@ class SocketServer extends WebSocketEvents {
|
|||
i, j,
|
||||
pixels,
|
||||
);
|
||||
ws.send(PixelReturn.dehydrate(retCode, wait, coolDown));
|
||||
ws.send(PixelReturn.dehydrate(retCode, wait, coolDown, pxlCnt));
|
||||
break;
|
||||
}
|
||||
case RegisterCanvas.OP_CODE: {
|
||||
|
|
|
@ -9,19 +9,22 @@ export default {
|
|||
const retCode = data.getUint8(1);
|
||||
const wait = data.getUint32(2);
|
||||
const coolDownSeconds = data.getInt16(6);
|
||||
const pxlCnt = data.getUint8(8);
|
||||
return {
|
||||
retCode,
|
||||
wait,
|
||||
coolDownSeconds,
|
||||
pxlCnt,
|
||||
};
|
||||
},
|
||||
dehydrate(retCode, wait, coolDown): Buffer {
|
||||
const buffer = Buffer.allocUnsafe(1 + 1 + 4 + 1 + 2);
|
||||
dehydrate(retCode, wait, coolDown, pxlCnt): Buffer {
|
||||
const buffer = Buffer.allocUnsafe(1 + 1 + 4 + 2 + 1);
|
||||
buffer.writeUInt8(OP_CODE, 0);
|
||||
buffer.writeUInt8(retCode, 1);
|
||||
buffer.writeUInt32BE(wait, 2);
|
||||
const coolDownSeconds = Math.round(coolDown / 1000);
|
||||
buffer.writeInt16BE(coolDownSeconds, 6);
|
||||
buffer.writeUInt8(pxlCnt, 8);
|
||||
return buffer;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -29,7 +29,7 @@ export default {
|
|||
*/
|
||||
const pixels = [];
|
||||
let off = data.byteLength;
|
||||
while (off >= 3) {
|
||||
while (off > 3) {
|
||||
const color = data.getUint8(off -= 1);
|
||||
const offsetL = data.getUint16(off -= 2);
|
||||
const offsetH = data.getUint8(off -= 1) << 16;
|
||||
|
|
|
@ -29,7 +29,7 @@ export default {
|
|||
* receive to 500
|
||||
*/
|
||||
let pxlcnt = 0;
|
||||
while (off >= 3 && pxlcnt < 500) {
|
||||
while (off > 3 && pxlcnt < 500) {
|
||||
const color = data.readUInt8(off -= 1);
|
||||
const offsetL = data.readUInt16BE(off -= 2);
|
||||
const offsetH = data.readUInt8(off -= 1) << 16;
|
||||
|
@ -46,7 +46,7 @@ export default {
|
|||
* @param pixels Buffer with offset and color of one or more pixels
|
||||
*/
|
||||
dehydrate(chunkId, pixels): Buffer {
|
||||
const index = new Uint8Array([OP_CODE, chunkId >> 8, chunkId && 0xFF]);
|
||||
const index = new Uint8Array([OP_CODE, chunkId >> 8, chunkId & 0xFF]);
|
||||
return Buffer.concat([index, pixels]);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -25,17 +25,6 @@ export default (store) => (next) => (action) => {
|
|||
break;
|
||||
}
|
||||
|
||||
case 'REQUEST_PLACE_PIXEL': {
|
||||
const {
|
||||
i, j, offset, color,
|
||||
} = action;
|
||||
ProtocolClient.requestPlacePixel(
|
||||
i, j, offset,
|
||||
color,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// nothing
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ import {
|
|||
} from '../core/constants';
|
||||
import {
|
||||
setHover,
|
||||
tryPlacePixel,
|
||||
selectColor,
|
||||
} from '../actions';
|
||||
import { tryPlacePixel } from './placePixel';
|
||||
|
||||
|
||||
const renderDistance = 150;
|
||||
|
@ -448,6 +448,8 @@ class Renderer {
|
|||
.add(intersect.face.normal.multiplyScalar(0.5))
|
||||
.floor()
|
||||
.addScalar(0.5);
|
||||
// TODO make rollOverMesh in a different color while placeAllowed false
|
||||
// instead of hiding it.... we can now queue Voxels
|
||||
if (!placeAllowed
|
||||
|| target.clone().sub(camera.position).length() > 50) {
|
||||
rollOverMesh.position.y = -10;
|
||||
|
@ -470,9 +472,16 @@ class Renderer {
|
|||
selectedColor,
|
||||
} = state.canvas;
|
||||
const chClr = (color === null) ? selectedColor : color;
|
||||
const curColor = (chClr === 0) ? this.chunkLoader.getVoxel(x, y, z) : 0;
|
||||
const [i, j] = getChunkOfPixel(canvasSize, x, y, z);
|
||||
const offset = getOffsetOfPixel(canvasSize, x, y, z);
|
||||
store.dispatch(tryPlacePixel(i, j, offset, chClr));
|
||||
tryPlacePixel(
|
||||
store,
|
||||
i, j,
|
||||
offset,
|
||||
chClr,
|
||||
curColor,
|
||||
);
|
||||
}
|
||||
|
||||
multiTapEnd() {
|
||||
|
@ -483,12 +492,6 @@ class Renderer {
|
|||
} = this;
|
||||
this.multitap = 0;
|
||||
const state = store.getState();
|
||||
const {
|
||||
placeAllowed,
|
||||
} = state.user;
|
||||
if (!placeAllowed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [px, py, pz] = mouseMoveStart;
|
||||
const [qx, qy, qz] = state.gui.hover;
|
||||
|
|
275
src/ui/placePixel.js
Normal file
275
src/ui/placePixel.js
Normal file
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* @flow
|
||||
* */
|
||||
import {
|
||||
notify,
|
||||
setPlaceAllowed,
|
||||
sweetAlert,
|
||||
gotCoolDownDelta,
|
||||
pixelFailure,
|
||||
setWait,
|
||||
placedPixel,
|
||||
pixelWait,
|
||||
updatePixel,
|
||||
} from '../actions';
|
||||
import ProtocolClient from '../socket/ProtocolClient';
|
||||
|
||||
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, color], ...]
|
||||
*/
|
||||
let clientPredictions = [];
|
||||
/*
|
||||
* values of last request
|
||||
* {i: i, j: j, pixels: [[offset, color], ...}
|
||||
*/
|
||||
let lastRequestValues = {};
|
||||
|
||||
|
||||
function requestFromQueue(store) {
|
||||
if (!pixelQueue.length) {
|
||||
pixelTimeout = null;
|
||||
return;
|
||||
}
|
||||
|
||||
/* timeout to warn user when Websocket is dysfunctional */
|
||||
pixelTimeout = setTimeout(() => {
|
||||
pixelQueue = [];
|
||||
pixelTimeout = null;
|
||||
store.dispatch(setPlaceAllowed(true));
|
||||
store.dispatch(sweetAlert(
|
||||
'Error :(',
|
||||
'Didn\'t get an answer from pixelplanet. Maybe try to refresh?',
|
||||
'error',
|
||||
'OK',
|
||||
));
|
||||
}, 5000);
|
||||
|
||||
lastRequestValues = pixelQueue.shift();
|
||||
const { i, j, pixels } = lastRequestValues;
|
||||
ProtocolClient.requestPlacePixels(i, j, pixels);
|
||||
store.dispatch(setPlaceAllowed(false));
|
||||
|
||||
// TODO:
|
||||
// this is for resending after captcha returned
|
||||
// window is ugly, put it into redux or something
|
||||
window.pixel = {
|
||||
i,
|
||||
j,
|
||||
pixels,
|
||||
};
|
||||
}
|
||||
|
||||
export function receivePixelUpdate(
|
||||
store,
|
||||
i: number,
|
||||
j: number,
|
||||
offset: number,
|
||||
color: ColorIndex,
|
||||
) {
|
||||
for (let p = 0; p < clientPredictions; p += 1) {
|
||||
const predPxl = clientPredictions[p];
|
||||
if (predPxl[0] === i
|
||||
&& predPxl[1] === j
|
||||
&& predPxl[2] === offset
|
||||
) {
|
||||
clientPredictions.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
store.dispatch(updatePixel(i, j, offset, color));
|
||||
}
|
||||
|
||||
/*
|
||||
* Revert predictions starting at given pixel
|
||||
* @param i, j, offset data of the first pixel that got rejected
|
||||
*/
|
||||
function revertPredictionsAt(
|
||||
store,
|
||||
sI: number,
|
||||
sJ: number,
|
||||
sOffset: number,
|
||||
) {
|
||||
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;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Reverting ${clientPredictions.length - p} client predictions`,
|
||||
);
|
||||
|
||||
while (p < clientPredictions.length) {
|
||||
const [i, j, offset, color] = clientPredictions[p];
|
||||
store.dispatch(updatePixel(i, j, offset, color));
|
||||
p += 1;
|
||||
}
|
||||
|
||||
clientPredictions = [];
|
||||
}
|
||||
|
||||
export function tryPlacePixel(
|
||||
store,
|
||||
i: number,
|
||||
j: number,
|
||||
offset: number,
|
||||
color: ColorIndex,
|
||||
curColor: ColorIndex,
|
||||
) {
|
||||
store.dispatch(updatePixel(i, j, offset, color));
|
||||
clientPredictions.push([i, j, offset, curColor]);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
export function receivePixelReturn(
|
||||
store,
|
||||
retCode: number,
|
||||
wait: number,
|
||||
coolDownSeconds: number,
|
||||
pxlCnt,
|
||||
) {
|
||||
clearTimeout(pixelTimeout);
|
||||
|
||||
try {
|
||||
/*
|
||||
* the terms coolDown is used in a different meaning here
|
||||
* coolDown is the delta seconds of the placed pixel
|
||||
*/
|
||||
if (wait) {
|
||||
store.dispatch(setWait(wait));
|
||||
}
|
||||
if (coolDownSeconds) {
|
||||
store.dispatch(notify(coolDownSeconds));
|
||||
if (coolDownSeconds < 0) {
|
||||
store.dispatch(gotCoolDownDelta(coolDownSeconds));
|
||||
}
|
||||
}
|
||||
|
||||
if (retCode) {
|
||||
/*
|
||||
* one or more pixels didn't get set,
|
||||
* revert predictions and clean queue
|
||||
*/
|
||||
const { i, j, pixels } = lastRequestValues;
|
||||
const [offset] = pixels[pxlCnt];
|
||||
revertPredictionsAt(store, i, j, offset);
|
||||
pixelQueue = [];
|
||||
}
|
||||
|
||||
let errorTitle = null;
|
||||
let msg = null;
|
||||
switch (retCode) {
|
||||
case 0:
|
||||
store.dispatch(placedPixel());
|
||||
break;
|
||||
case 1:
|
||||
errorTitle = 'Invalid Canvas';
|
||||
msg = 'This canvas doesn\'t exist';
|
||||
break;
|
||||
case 2:
|
||||
errorTitle = 'Invalid Coordinates';
|
||||
msg = 'x out of bounds';
|
||||
break;
|
||||
case 3:
|
||||
errorTitle = 'Invalid Coordinates';
|
||||
msg = 'y out of bounds';
|
||||
break;
|
||||
case 4:
|
||||
errorTitle = 'Invalid Coordinates';
|
||||
msg = 'z out of bounds';
|
||||
break;
|
||||
case 5:
|
||||
errorTitle = 'Wrong Color';
|
||||
msg = 'Invalid color selected';
|
||||
break;
|
||||
case 6:
|
||||
errorTitle = 'Just for registered Users';
|
||||
msg = 'You have to be logged in to place on this canvas';
|
||||
break;
|
||||
case 7:
|
||||
errorTitle = 'Place more :)';
|
||||
// eslint-disable-next-line max-len
|
||||
msg = 'You can not access this canvas yet. You need to place more pixels';
|
||||
break;
|
||||
case 8:
|
||||
store.dispatch(notify('Pixel protected!'));
|
||||
break;
|
||||
case 9:
|
||||
// pixestack used up
|
||||
store.dispatch(pixelWait());
|
||||
break;
|
||||
case 10:
|
||||
// captcha, reCaptcha or hCaptcha
|
||||
if (typeof window.hcaptcha !== 'undefined') {
|
||||
window.hcaptcha.execute();
|
||||
} else {
|
||||
window.grecaptcha.execute();
|
||||
}
|
||||
return;
|
||||
case 11:
|
||||
|
||||
errorTitle = 'No Proxies Allowed :(';
|
||||
msg = 'You are using a Proxy.';
|
||||
break;
|
||||
default:
|
||||
errorTitle = 'Weird';
|
||||
msg = 'Couldn\'t set Pixel';
|
||||
}
|
||||
if (msg) {
|
||||
store.dispatch(pixelFailure());
|
||||
store.dispatch(sweetAlert(
|
||||
(errorTitle || `Error ${retCode}`),
|
||||
msg,
|
||||
'error',
|
||||
'OK',
|
||||
));
|
||||
}
|
||||
} finally {
|
||||
store.dispatch(setPlaceAllowed(true));
|
||||
/* start next request if queue isn't empty */
|
||||
requestFromQueue(store);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user