make parent classes for renderer and chunks,

move GC into those parent classes
restrict the total amount of loaded Chunks
This commit is contained in:
HF 2023-01-16 21:49:57 +01:00
parent 060688337d
commit 90cd2016aa
21 changed files with 641 additions and 508 deletions

View File

@ -219,6 +219,30 @@ msgstr ""
msgid "You are not banned"
msgstr ""
#: src/routes/api/auth/logout.js:11
msgid "You are not even logged in."
msgstr ""
#: src/routes/api/auth/delete_account.js:55
#: src/routes/api/auth/logout.js:20
msgid "Server error when logging out."
msgstr ""
#: src/routes/api/auth/verify.js:26
#: src/routes/api/auth/verify.js:35
msgid "Mail verification"
msgstr ""
#: src/routes/api/auth/verify.js:27
msgid "You are now verified :)"
msgstr ""
#: src/routes/api/auth/verify.js:35
msgid ""
"Your mail verification code is invalid or already expired :(, please "
"request a new one."
msgstr ""
#: src/routes/api/auth/change_mail.js:21
#: src/routes/api/auth/register.js:24
msgid "This email provider is not allowed"
@ -256,15 +280,6 @@ msgstr ""
msgid "Failed to establish session after register :("
msgstr ""
#: src/routes/api/auth/logout.js:11
msgid "You are not even logged in."
msgstr ""
#: src/routes/api/auth/delete_account.js:55
#: src/routes/api/auth/logout.js:20
msgid "Server error when logging out."
msgstr ""
#: src/routes/api/auth/change_mail.js:43
#: src/routes/api/auth/change_passwd.js:34
#: src/routes/api/auth/delete_account.js:35
@ -277,21 +292,6 @@ msgstr ""
msgid "Incorrect password!"
msgstr ""
#: src/routes/api/auth/verify.js:26
#: src/routes/api/auth/verify.js:35
msgid "Mail verification"
msgstr ""
#: src/routes/api/auth/verify.js:27
msgid "You are now verified :)"
msgstr ""
#: src/routes/api/auth/verify.js:35
msgid ""
"Your mail verification code is invalid or already expired :(, please "
"request a new one."
msgstr ""
#: src/ssr/RedirectionPage.jsx:19
msgid "PixelPlanet.fun Accounts"
msgstr ""

View File

@ -46,136 +46,136 @@ msgstr ""
msgid "Hide Hidden Canvases"
msgstr ""
#: src/ui/PixelTransferController.js:63
#: src/ui/PixelTransferController.js:70
msgid "Error :("
msgstr ""
#: src/ui/PixelTransferController.js:64
#: src/ui/PixelTransferController.js:71
msgid "Didn't get an answer from pixelplanet. Maybe try to refresh?"
msgstr ""
#: src/ui/PixelTransferController.js:96
#: src/ui/PixelTransferController.js:103
msgid "Invalid Canvas"
msgstr ""
#: src/ui/PixelTransferController.js:97
#: src/ui/PixelTransferController.js:104
msgid "This canvas doesn't exist"
msgstr ""
#: src/ui/PixelTransferController.js:100
#: src/ui/PixelTransferController.js:104
#: src/ui/PixelTransferController.js:108
#: src/ui/PixelTransferController.js:107
#: src/ui/PixelTransferController.js:111
#: src/ui/PixelTransferController.js:115
msgid "Invalid Coordinates"
msgstr ""
#: src/ui/PixelTransferController.js:101
#: src/ui/PixelTransferController.js:108
msgid "x out of bounds"
msgstr ""
#: src/ui/PixelTransferController.js:105
#: src/ui/PixelTransferController.js:112
msgid "y out of bounds"
msgstr ""
#: src/ui/PixelTransferController.js:109
#: src/ui/PixelTransferController.js:116
msgid "z out of bounds"
msgstr ""
#: src/ui/PixelTransferController.js:112
#: src/ui/PixelTransferController.js:119
msgid "Wrong Color"
msgstr ""
#: src/ui/PixelTransferController.js:113
#: src/ui/PixelTransferController.js:120
msgid "Invalid color selected"
msgstr ""
#: src/ui/PixelTransferController.js:116
#: src/ui/PixelTransferController.js:123
msgid "Just for registered Users"
msgstr ""
#: src/ui/PixelTransferController.js:117
#: src/ui/PixelTransferController.js:124
msgid "You have to be logged in to place on this canvas"
msgstr ""
#: src/ui/PixelTransferController.js:120
#: src/ui/PixelTransferController.js:127
msgid "Place more :)"
msgstr ""
#: src/ui/PixelTransferController.js:122
#: src/ui/PixelTransferController.js:129
msgid "You can not access this canvas yet. You need to place more pixels"
msgstr ""
#: src/ui/PixelTransferController.js:125
#: src/ui/PixelTransferController.js:132
msgid "Pixel protected!"
msgstr ""
#: src/ui/PixelTransferController.js:132
#: src/ui/PixelTransferController.js:139
msgid "Please prove that you are human"
msgstr ""
#: src/ui/PixelTransferController.js:136
#: src/ui/PixelTransferController.js:143
msgid "No Proxies Allowed :("
msgstr ""
#: src/ui/PixelTransferController.js:137
#: src/ui/PixelTransferController.js:144
msgid "You are using a Proxy."
msgstr ""
#: src/ui/PixelTransferController.js:140
#: src/ui/PixelTransferController.js:147
msgid "Not allowed"
msgstr ""
#: src/ui/PixelTransferController.js:141
#: src/ui/PixelTransferController.js:148
msgid "Just the Top10 of yesterday can place here"
msgstr ""
#: src/ui/PixelTransferController.js:144
#: src/ui/PixelTransferController.js:151
msgid "You are weird"
msgstr ""
#: src/ui/PixelTransferController.js:146
#: src/ui/PixelTransferController.js:153
msgid "Server got confused by your pixels. Are you playing on multiple devices?"
msgstr ""
#: src/ui/PixelTransferController.js:149
#: src/ui/PixelTransferController.js:156
msgid "Banned"
msgstr ""
#: src/ui/PixelTransferController.js:153
#: src/ui/PixelTransferController.js:160
msgid "Range Banned"
msgstr ""
#: src/ui/PixelTransferController.js:154
#: src/ui/PixelTransferController.js:161
msgid "Your Internet Provider is banned from playing this game"
msgstr ""
#: src/ui/PixelTransferController.js:157
#: src/ui/PixelTransferController.js:164
msgid "Timeout"
msgstr ""
#: src/ui/PixelTransferController.js:159
#: src/ui/PixelTransferController.js:166
msgid ""
"Didn't get an answer from pixelplanet. Maybe try to refresh if problem "
"persists?"
msgstr ""
#: src/ui/PixelTransferController.js:162
#: src/ui/PixelTransferController.js:169
msgid "Weird"
msgstr ""
#: src/ui/PixelTransferController.js:163
#: src/ui/PixelTransferController.js:170
msgid "Couldn't set Pixel"
msgstr ""
#: src/ui/PixelTransferController.js:168
#: src/ui/PixelTransferController.js:175
#, javascript-format
msgid "Error ${ retCode }"
msgstr ""
#: src/ui/renderer.js:35
#: src/ui/rendererFactory.js:30
msgid "Canvas Error"
msgstr ""
#: src/ui/renderer.js:36
#: src/ui/rendererFactory.js:31
msgid "Can't render 3D canvas, do you have WebGL2 disabled?"
msgstr ""
@ -248,6 +248,11 @@ msgstr ""
msgid "Pixels placed"
msgstr ""
#: src/components/buttons/CanvasSwitchButton.jsx:20
#: src/components/windows/index.js:19
msgid "Canvas Selection"
msgstr ""
#: src/components/buttons/ChatButton.jsx:88
msgid "Close Chat"
msgstr ""
@ -256,11 +261,6 @@ msgstr ""
msgid "Open Chat"
msgstr ""
#: src/components/buttons/CanvasSwitchButton.jsx:20
#: src/components/windows/index.js:19
msgid "Canvas Selection"
msgstr ""
#: src/components/buttons/ExpandMenuButton.jsx:22
msgid "Close Menu"
msgstr ""
@ -310,13 +310,8 @@ msgstr ""
msgid "Resize"
msgstr ""
#: src/components/buttons/DownloadButton.jsx:36
msgid "Make Screenshot"
msgstr ""
#: src/components/buttons/LogInButton.jsx:20
#: src/components/windows/index.js:15
msgid "User Area"
#: src/components/buttons/GlobeButton.jsx:34
msgid "Globe View"
msgstr ""
#: src/components/buttons/PalselButton.jsx:30
@ -327,8 +322,9 @@ msgstr ""
msgid "Open Palette"
msgstr ""
#: src/components/buttons/GlobeButton.jsx:34
msgid "Globe View"
#: src/components/buttons/SettingsButton.jsx:21
#: src/components/windows/index.js:14
msgid "Settings"
msgstr ""
#: src/components/BanInfo.jsx:75
@ -337,9 +333,13 @@ msgstr ""
msgid "Help"
msgstr ""
#: src/components/buttons/SettingsButton.jsx:21
#: src/components/windows/index.js:14
msgid "Settings"
#: src/components/buttons/LogInButton.jsx:20
#: src/components/windows/index.js:15
msgid "User Area"
msgstr ""
#: src/components/buttons/DownloadButton.jsx:36
msgid "Make Screenshot"
msgstr ""
#: src/components/windows/index.js:16
@ -447,6 +447,99 @@ msgstr ""
msgid "Why?"
msgstr ""
#: src/components/windows/Settings.jsx:86
msgid "Show Grid"
msgstr ""
#: src/components/windows/Settings.jsx:91
msgid "Turn on grid to highlight pixel borders."
msgstr ""
#: src/components/windows/Settings.jsx:94
msgid "Show Pixel Activity"
msgstr ""
#: src/components/windows/Settings.jsx:99
msgid "Show circles where pixels are placed."
msgstr ""
#: src/components/windows/Settings.jsx:102
msgid "Disable Game Sounds"
msgstr ""
#: src/components/windows/Settings.jsx:108
msgid "All sound effects will be disabled."
msgstr ""
#: src/components/windows/Settings.jsx:112
msgid ""
"Your Browser doesn't allow us to use AudioContext to play sounds. Do you "
"have some privacy feature blocking us?"
msgstr ""
#: src/components/windows/Settings.jsx:118
msgid "Enable chat notifications"
msgstr ""
#: src/components/windows/Settings.jsx:122
msgid "Play a sound when new chat messages arrive"
msgstr ""
#: src/components/windows/Settings.jsx:125
msgid "Auto Zoom In"
msgstr ""
#: src/components/windows/Settings.jsx:130
msgid ""
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
"small."
msgstr ""
#: src/components/windows/Settings.jsx:133
msgid "Compact Palette"
msgstr ""
#: src/components/windows/Settings.jsx:138
msgid "Display Palette in a compact form that takes less screen space."
msgstr ""
#: src/components/windows/Settings.jsx:141
msgid "Potato Mode"
msgstr ""
#: src/components/windows/Settings.jsx:145
msgid "For when you are playing on a potato."
msgstr ""
#: src/components/Converter.jsx:376
#: src/components/windows/Settings.jsx:148
msgid "Light Grid"
msgstr ""
#: src/components/windows/Settings.jsx:152
msgid "Show Grid in white instead of black."
msgstr ""
#: src/components/windows/Settings.jsx:156
msgid "Historical View"
msgstr ""
#: src/components/windows/Settings.jsx:161
msgid "Check out past versions of the canvas."
msgstr ""
#: src/components/windows/Settings.jsx:166
msgid "Themes"
msgstr ""
#: src/components/windows/Settings.jsx:171
msgid "How pixelplanet should look like."
msgstr ""
#: src/components/windows/Settings.jsx:178
msgid "Select Language"
msgstr ""
#: src/components/windows/Help.jsx:42
msgid "Place color pixels on a large canvas with other players online!"
msgstr ""
@ -689,99 +782,6 @@ msgstr ""
msgid "Submit"
msgstr ""
#: src/components/windows/Settings.jsx:86
msgid "Show Grid"
msgstr ""
#: src/components/windows/Settings.jsx:91
msgid "Turn on grid to highlight pixel borders."
msgstr ""
#: src/components/windows/Settings.jsx:94
msgid "Show Pixel Activity"
msgstr ""
#: src/components/windows/Settings.jsx:99
msgid "Show circles where pixels are placed."
msgstr ""
#: src/components/windows/Settings.jsx:102
msgid "Disable Game Sounds"
msgstr ""
#: src/components/windows/Settings.jsx:108
msgid "All sound effects will be disabled."
msgstr ""
#: src/components/windows/Settings.jsx:112
msgid ""
"Your Browser doesn't allow us to use AudioContext to play sounds. Do you "
"have some privacy feature blocking us?"
msgstr ""
#: src/components/windows/Settings.jsx:118
msgid "Enable chat notifications"
msgstr ""
#: src/components/windows/Settings.jsx:122
msgid "Play a sound when new chat messages arrive"
msgstr ""
#: src/components/windows/Settings.jsx:125
msgid "Auto Zoom In"
msgstr ""
#: src/components/windows/Settings.jsx:130
msgid ""
"Zoom in instead of placing a pixel when you tap the canvas and your zoom is "
"small."
msgstr ""
#: src/components/windows/Settings.jsx:133
msgid "Compact Palette"
msgstr ""
#: src/components/windows/Settings.jsx:138
msgid "Display Palette in a compact form that takes less screen space."
msgstr ""
#: src/components/windows/Settings.jsx:141
msgid "Potato Mode"
msgstr ""
#: src/components/windows/Settings.jsx:145
msgid "For when you are playing on a potato."
msgstr ""
#: src/components/Converter.jsx:376
#: src/components/windows/Settings.jsx:148
msgid "Light Grid"
msgstr ""
#: src/components/windows/Settings.jsx:152
msgid "Show Grid in white instead of black."
msgstr ""
#: src/components/windows/Settings.jsx:156
msgid "Historical View"
msgstr ""
#: src/components/windows/Settings.jsx:161
msgid "Check out past versions of the canvas."
msgstr ""
#: src/components/windows/Settings.jsx:166
msgid "Themes"
msgstr ""
#: src/components/windows/Settings.jsx:171
msgid "How pixelplanet should look like."
msgstr ""
#: src/components/windows/Settings.jsx:178
msgid "Select Language"
msgstr ""
#: src/components/windows/CanvasSelect.jsx:29
msgid ""
"Select the canvas you want to use. Every canvas is unique and has "
@ -826,6 +826,14 @@ msgid ""
"how the canvas was at that time."
msgstr ""
#: src/components/windows/ForgotPassword.jsx:58
msgid "Sent you a mail with instructions to reset your password."
msgstr ""
#: src/components/windows/ForgotPassword.jsx:69
msgid "Enter your mail address and we will send you a new password:"
msgstr ""
#: src/components/windows/Chat.jsx:180
msgid "Start chatting here"
msgstr ""
@ -842,14 +850,6 @@ msgstr ""
msgid "Channel settings"
msgstr ""
#: src/components/windows/ForgotPassword.jsx:58
msgid "Sent you a mail with instructions to reset your password."
msgstr ""
#: src/components/windows/ForgotPassword.jsx:69
msgid "Enter your mail address and we will send you a new password:"
msgstr ""
#: src/components/Captcha.jsx:51
#: src/components/Captcha.jsx:105
msgid "Could not load captcha"
@ -931,6 +931,13 @@ msgstr ""
msgid "Password must be shorter than 60 characters."
msgstr ""
#: src/components/ChangeMail.jsx:91
#: src/components/ChangeName.jsx:68
#: src/components/ChangePassword.jsx:109
#: src/components/LanguageSelect.jsx:80
msgid "Save"
msgstr ""
#: src/components/GetIID.jsx:44
msgid "Get IID"
msgstr ""
@ -1121,13 +1128,6 @@ msgstr ""
msgid "Ranking updates every 5 min. Daily rankings get reset at midnight UTC."
msgstr ""
#: src/components/ChangeMail.jsx:91
#: src/components/ChangeName.jsx:68
#: src/components/ChangePassword.jsx:109
#: src/components/LanguageSelect.jsx:80
msgid "Save"
msgstr ""
#: src/components/CanvasItem.jsx:29
msgid "Online Users"
msgstr ""
@ -1201,6 +1201,24 @@ msgstr ""
msgid "LogIn"
msgstr ""
#: src/components/UserMessages.jsx:28
msgid ""
"Please verify your mail address or your account could get deleted after a "
"few days."
msgstr ""
#: src/components/UserMessages.jsx:49
msgid "A new verification mail is getting sent to you."
msgstr ""
#: src/components/UserMessages.jsx:53
msgid "Click here to request a new verification mail."
msgstr ""
#: src/components/ChangeName.jsx:64
msgid "New Username"
msgstr ""
#: src/components/ChangePassword.jsx:21
msgid "Passwords do not match."
msgstr ""
@ -1221,20 +1239,6 @@ msgstr ""
msgid "Confirm New Password"
msgstr ""
#: src/components/UserMessages.jsx:28
msgid ""
"Please verify your mail address or your account could get deleted after a "
"few days."
msgstr ""
#: src/components/UserMessages.jsx:49
msgid "A new verification mail is getting sent to you."
msgstr ""
#: src/components/UserMessages.jsx:53
msgid "Click here to request a new verification mail."
msgstr ""
#: src/components/ChangeMail.jsx:59
msgid ""
"Changed Mail successfully. We sent you a verification mail, "
@ -1245,14 +1249,34 @@ msgstr ""
msgid "New Mail"
msgstr ""
#: src/components/ChangeName.jsx:64
msgid "New Username"
msgstr ""
#: src/components/DeleteAccount.jsx:66
msgid "Yes, Delete My Account!"
msgstr ""
#: src/components/SocialSettings.jsx:35
msgid "Block DMs"
msgstr ""
#: src/components/SocialSettings.jsx:42
msgid "Block all Private Messages"
msgstr ""
#: src/components/SocialSettings.jsx:44
msgid "Private"
msgstr ""
#: src/components/SocialSettings.jsx:51
msgid "Don't show me in global stats"
msgstr ""
#: src/components/SocialSettings.jsx:57
msgid "Unblock Users"
msgstr ""
#: src/components/SocialSettings.jsx:82
msgid "You have no users blocked"
msgstr ""
#: src/components/ModCanvastools.jsx:168
msgid "Build image on canvas."
msgstr ""
@ -1346,6 +1370,54 @@ msgstr ""
msgid "Stop Cleaner"
msgstr ""
#: src/components/ModWatchtools.jsx:48
msgid "Interval is invalid"
msgstr ""
#: src/components/ModWatchtools.jsx:122
msgid "Check who placed in an area"
msgstr ""
#: src/components/ModWatchtools.jsx:123
msgid "Canvas"
msgstr ""
#: src/components/ModWatchtools.jsx:142
msgid "Interval"
msgstr ""
#: src/components/ModWatchtools.jsx:157
msgid "IID (optional)"
msgstr ""
#: src/components/ModWatchtools.jsx:236
msgid "Get Pixels"
msgstr ""
#: src/components/ModWatchtools.jsx:267
msgid "Get Users"
msgstr ""
#: src/components/ModIIDtools.jsx:20
msgid "You must enter a duration"
msgstr ""
#: src/components/ModIIDtools.jsx:24
msgid "You must enter an IID"
msgstr ""
#: src/components/ModIIDtools.jsx:53
msgid "IID Actions"
msgstr ""
#: src/components/ModIIDtools.jsx:80
msgid "Enter Reason"
msgstr ""
#: src/components/ModIIDtools.jsx:97
msgid "(0 = infinite)"
msgstr ""
#: src/components/Admintools.jsx:109
msgid "IP Actions"
msgstr ""
@ -1378,76 +1450,8 @@ msgstr ""
msgid "User Name"
msgstr ""
#: src/components/SocialSettings.jsx:35
msgid "Block DMs"
msgstr ""
#: src/components/SocialSettings.jsx:42
msgid "Block all Private Messages"
msgstr ""
#: src/components/SocialSettings.jsx:44
msgid "Private"
msgstr ""
#: src/components/SocialSettings.jsx:51
msgid "Don't show me in global stats"
msgstr ""
#: src/components/SocialSettings.jsx:57
msgid "Unblock Users"
msgstr ""
#: src/components/SocialSettings.jsx:82
msgid "You have no users blocked"
msgstr ""
#: src/components/ModIIDtools.jsx:20
msgid "You must enter a duration"
msgstr ""
#: src/components/ModIIDtools.jsx:24
msgid "You must enter an IID"
msgstr ""
#: src/components/ModIIDtools.jsx:53
msgid "IID Actions"
msgstr ""
#: src/components/ModIIDtools.jsx:80
msgid "Enter Reason"
msgstr ""
#: src/components/ModIIDtools.jsx:97
msgid "(0 = infinite)"
msgstr ""
#: src/components/ModWatchtools.jsx:48
msgid "Interval is invalid"
msgstr ""
#: src/components/ModWatchtools.jsx:122
msgid "Check who placed in an area"
msgstr ""
#: src/components/ModWatchtools.jsx:123
msgid "Canvas"
msgstr ""
#: src/components/ModWatchtools.jsx:142
msgid "Interval"
msgstr ""
#: src/components/ModWatchtools.jsx:157
msgid "IID (optional)"
msgstr ""
#: src/components/ModWatchtools.jsx:236
msgid "Get Pixels"
msgstr ""
#: src/components/ModWatchtools.jsx:267
msgid "Get Users"
#: src/components/contextmenus/ChannelContextMenu.jsx:46
msgid "Mute"
msgstr ""
#: src/components/contextmenus/UserContextMenu.jsx:49
@ -1462,10 +1466,6 @@ msgstr ""
msgid "Block"
msgstr ""
#: src/components/contextmenus/ChannelContextMenu.jsx:46
msgid "Mute"
msgstr ""
#: src/components/windows/Help.jsx:15
#: src/components/windows/Settings.jsx:87
msgctxt "keybinds"
@ -1478,6 +1478,11 @@ msgctxt "keybinds"
msgid "X"
msgstr ""
#: src/components/windows/Settings.jsx:103
msgctxt "keybinds"
msgid "M"
msgstr ""
#: src/components/windows/Help.jsx:17
#: src/components/windows/Settings.jsx:158
msgctxt "keybinds"
@ -1527,9 +1532,4 @@ msgstr ""
#: src/components/windows/Help.jsx:32
msgctxt "keybinds"
msgid "C"
msgstr ""
#: src/components/windows/Settings.jsx:103
msgctxt "keybinds"
msgid "M"
msgstr ""

View File

@ -17,8 +17,9 @@ import {
import pixelTransferController from './ui/PixelTransferController';
import store from './store/store';
import renderApp from './components/App';
import { initRenderer, getRenderer } from './ui/renderer';
import { initRenderer, getRenderer } from './ui/rendererFactory';
import socketClient from './socket/SocketClient';
import { GC_INTERVAL } from './core/constants';
persistStore(store, {}, () => {
window.addEventListener('message', store.dispatch);
@ -50,7 +51,7 @@ persistStore(store, {}, () => {
store.dispatch(fetchMe());
socketClient.initialize(store);
socketClient.initialize(store, pixelTransferController, getRenderer);
});
(function load() {
@ -64,27 +65,8 @@ persistStore(store, {}, () => {
// garbage collection
setInterval(() => {
const renderer = getRenderer();
const chunks = renderer.getAllChunks();
if (chunks) {
const curTime = Date.now();
let cnt = 0;
chunks.forEach((value, key) => {
if (curTime > value.timestamp + 300000) {
const [zc, xc, yc] = value.cell;
if (!renderer.isChunkInView(zc, xc, yc)) {
cnt++;
if (value.isBasechunk) {
socketClient.deRegisterChunk([xc, yc]);
}
chunks.delete(key);
value.destructor();
}
}
});
// eslint-disable-next-line no-console
console.log('Garbage collection cleaned', cnt, 'chunks');
}
}, 300000);
renderer.gc();
}, GC_INTERVAL);
document.removeEventListener('DOMContentLoaded', onLoad);
};

View File

@ -5,7 +5,7 @@
import React from 'react';
import { getRenderer } from '../ui/renderer';
import { getRenderer } from '../ui/rendererFactory';
const btnStyle = {
fontSize: 34,

View File

@ -8,7 +8,7 @@ import { MdFileDownload } from 'react-icons/md';
import fileDownload from 'js-file-download';
import { t } from 'ttag';
import { getRenderer } from '../../ui/renderer';
import { getRenderer } from '../../ui/rendererFactory';
/**
* https://jsfiddle.net/AbdiasSoftware/7PRNN/

View File

@ -96,3 +96,8 @@ export const MAX_CHAT_MESSAGES = 100;
export const EVENT_USER_NAME = 'event';
export const INFO_USER_NAME = 'info';
export const APISOCKET_USER_NAME = 'apisocket';
// maximum chunks to subscribe to
export const MAX_LOADED_CHUNKS = 2000;
export const MAX_CHUNK_AGE = 300000;
export const GC_INTERVAL = 300000;

View File

@ -10,7 +10,7 @@ import {
dehydrateRegCanvas,
dehydrateRegChunk,
dehydrateRegMChunks,
dehydrateDeRegChunk,
dehydrateDeRegMChunks,
dehydratePixelUpdate,
dehydratePing,
} from './packets/client';
@ -35,15 +35,15 @@ import {
fetchMe,
} from '../store/actions/thunks';
import { shardHost } from '../store/actions/fetch';
import pixelTransferController from '../ui/PixelTransferController';
const chunks = [];
class SocketClient {
store = null;
pixelTransferController = null;
ws = null;
getRenderer;
constructor() {
console.log('Creating WebSocketClient');
this.store = null;
this.ws = null;
this.channelId = 0;
/*
* properties set in connect and open:
@ -59,12 +59,18 @@ class SocketClient {
setInterval(this.checkHealth, 2000);
}
initialize(store) {
initialize(store, pixelTransferController, getRenderer) {
this.store = store;
if (pixelTransferController) {
this.pixelTransferController = pixelTransferController;
}
if (getRenderer) {
this.getRenderer = getRenderer;
}
return this.connect();
}
async connect() {
connect() {
this.readyState = WebSocket.CONNECTING;
if (this.ws) {
console.log('WebSocket already open, not starting');
@ -139,8 +145,13 @@ class SocketClient {
this.send(dehydrateRegCanvas(
this.store.getState().canvas.canvasId,
));
console.log(`Register ${chunks.length} chunks`);
this.send(dehydrateRegMChunks(chunks));
// register chunks
const chunkids = this.getRenderer().recChunkIds;
if (chunkids.length) {
console.log(`Register ${chunkids.length} chunks`);
this.send(dehydrateRegMChunks(chunkids));
}
// flush queue
this.processMsgQueue();
}
@ -151,29 +162,21 @@ class SocketClient {
console.log(
`Notify websocket server that we changed canvas to ${canvasId}`,
);
chunks.length = 0;
this.send(dehydrateRegCanvas(canvasId));
}
registerChunk(cell) {
const [i, j] = cell;
const chunkid = (i << 8) | j;
chunks.push(chunkid);
registerChunk(chunkid) {
const buffer = dehydrateRegChunk(chunkid);
if (this.readyState === WebSocket.OPEN) {
this.send(buffer);
}
}
deRegisterChunk(cell) {
const [i, j] = cell;
const chunkid = (i << 8) | j;
const buffer = dehydrateDeRegChunk(chunkid);
deRegisterChunks(chunkids) {
const buffer = dehydrateDeRegMChunks(chunkids);
if (this.readyState === WebSocket.OPEN) {
this.send(buffer);
}
const pos = chunks.indexOf(chunkid);
if (~pos) chunks.splice(pos, 1);
}
/*
@ -274,7 +277,11 @@ class SocketClient {
switch (opcode) {
case PIXEL_UPDATE_OP:
pixelTransferController.receivePixelUpdate(hydratePixelUpdate(data));
if (this.pixelTransferController) {
this.pixelTransferController.receivePixelUpdate(
hydratePixelUpdate(data),
);
}
break;
case PIXEL_RETURN_OP: {
const pos = this.reqQueue.findIndex((q) => q[0] === 'pu');

View File

@ -218,30 +218,31 @@ export function requestBigChunk(center) {
};
}
export function preLoadedBigChunk(
center,
) {
export function removeChunks(chunks) {
return {
type: 'REMOVE_CHUNKS',
chunks,
};
}
export function preLoadedBigChunk(center) {
return {
type: 'PRE_LOADED_BIG_CHUNK',
center,
};
}
export function receiveBigChunk(
center,
chunk,
) {
export function receiveBigChunk(chunk) {
return {
type: 'REC_BIG_CHUNK',
center,
chunk,
};
}
export function receiveBigChunkFailure(center, error) {
export function receiveBigChunkFailure(chunk, error) {
return {
type: 'REC_BIG_CHUNK_FAILURE',
center,
chunk,
error,
};
}

View File

@ -9,7 +9,7 @@
import {
getRenderer,
initRenderer,
} from '../../ui/renderer';
} from '../../ui/rendererFactory';
export default (store) => (next) => (action) => {
const { type } = action;

View File

@ -9,11 +9,21 @@ export default (store) => (next) => (action) => {
switch (action.type) {
case 'REC_BIG_CHUNK':
case 'REC_BIG_CHUNK_FAILURE': {
if (!action.center) {
break;
const { chunk } = action;
if (chunk.recUpdates) {
SocketClient.registerChunk(action.chunk.id);
}
break;
}
case 'REMOVE_CHUNKS': {
const { chunks } = action;
const ids = chunks
.filter((chunk) => chunk.recUpdates)
.map((chunk) => chunk.id);
if (ids.length) {
SocketClient.deRegisterChunks(ids);
}
const [, cx, cy] = action.center;
SocketClient.registerChunk([cx, cy]);
break;
}

View File

@ -42,15 +42,7 @@ export default function fetching(
};
}
case 'REC_BIG_CHUNK': {
const { fetchingChunks } = state;
return {
...state,
fetchingChunks: fetchingChunks - 1,
};
}
case 'REC_BIG_CHUNK':
case 'REC_BIG_CHUNK_FAILURE': {
const { fetchingChunks } = state;

37
src/ui/Chunk.js Normal file
View File

@ -0,0 +1,37 @@
/*
* parent class for Chunk
*/
/* eslint-disable class-methods-use-this */
class Chunk {
// if chunk receives updates via websocket
recUpdates = false;
// timestamp of last touch,
// mustbe regularly updated for GC,
// either by touch() or by setting directly
timestamp;
// coordiantes
z;
i;
j;
constructor(z, i, j) {
this.timestamp = Date.now();
this.z = z;
this.i = i;
this.j = j;
}
get id() {
return (this.i << 8) | this.j;
}
touch() {
this.timestamp = Date.now();
}
destructor() {}
}
export default Chunk;

View File

@ -1,47 +1,30 @@
import { TILE_SIZE } from '../core/constants';
import Chunk from './Chunk';
class ChunkRGB {
// array of coords [zoom, cx, cy]
// just an identifier, could be removed
cell;
class Chunk2D extends Chunk {
// HTMLCanvasElement of chunk
image;
// boolean if chunk loeaded (request done)
ready;
// boolean if chunk is empty
isEmpty;
// number timestamp of last load for garbage collection
timestamp;
// palette of canvas
palette;
// boolean if it is basechunk, rather than zoomtile
isBasechunk;
constructor(palette, zoom = 0, cx = 0, cy = 0) {
// isBasechunk gets set to true by REC_BIG_CHUNK
// if true => chunk got requested from api/chunk and
// receives websocket pixel updates
// if false => chunk is an zoomed png tile
this.isBasechunk = false;
super(zoom, cx, cy);
this.palette = palette;
this.image = document.createElement('canvas');
this.image.width = TILE_SIZE;
this.image.height = TILE_SIZE;
this.cell = [zoom, cx, cy];
this.ready = false;
this.isEmpty = false;
this.timestamp = Date.now();
}
// eslint-disable-next-line class-methods-use-this
destructor() {
return null;
}
// from Uint8Array
fromBuffer(chunkBuffer) {
this.isBasechunk = true;
this.recUpdates = true;
const imageData = new ImageData(TILE_SIZE, TILE_SIZE);
const imageView = new Uint32Array(imageData.data.buffer);
const { abgr } = this.palette;
@ -110,7 +93,7 @@ class ChunkRGB {
}
hasColorIn(cell, color) {
const index = ChunkRGB.getIndexFromCell(cell);
const index = Chunk2D.getIndexFromCell(cell);
const ctx = this.image.getContext('2d');
const imageData = ctx.getImageData(0, 0, TILE_SIZE, TILE_SIZE);
@ -128,4 +111,4 @@ class ChunkRGB {
}
}
export default ChunkRGB;
export default Chunk2D;

View File

@ -8,6 +8,7 @@
import * as THREE from 'three';
import Chunk from './Chunk';
import {
THREE_TILE_SIZE,
THREE_CANVAS_HEIGHT,
@ -73,8 +74,7 @@ const material = new THREE.MeshLambertMaterial({
});
class Chunk {
cell; // Array
class Chunk3D extends Chunk {
key; // string
ready = false;
palette; // Object
@ -83,13 +83,12 @@ class Chunk {
faceCnt; // number
lastPixel; // number
heightMap; // Array
timestamp; // number
constructor(palette, key, xc, zc) {
this.cell = [0, xc, zc];
super(0, xc, zc);
this.recUpdates = true;
this.key = key;
this.palette = palette;
this.timestamp = Date.now();
}
destructor() {
@ -106,7 +105,7 @@ class Chunk {
if (y < 0) return 1;
// z and y are swapped in api/pixel for compatibility
// with 2D canvas
const offset = Chunk.getOffsetOfVoxel(x, y, z);
const offset = Chunk3D.getOffsetOfVoxel(x, y, z);
return this.buffer[offset];
}
@ -139,7 +138,7 @@ class Chunk {
}
}
console.log(`Created buffer with ${cnt} voxels`);
const [faceCnt, lastPixel, heightMap] = Chunk.calculateMetaData(this.buffer);
const [faceCnt, lastPixel, heightMap] = Chunk3D.calculateMetaData(this.buffer);
this.faceCnt = faceCnt;
this.lastPixel = lastPixel;
this.heightMap = heightMap;
@ -196,7 +195,7 @@ class Chunk {
if (heighestPixel > totalHeight) {
// last total pixel
totalHeight = heighestPixel;
lastPixel = Chunk.getOffsetOfVoxel(x, heighestPixel, z);
lastPixel = Chunk3D.getOffsetOfVoxel(x, heighestPixel, z);
}
}
}
@ -233,7 +232,7 @@ class Chunk {
}
setVoxel(x, y, z, clr) {
const offset = Chunk.getOffsetOfVoxel(x, y, z);
const offset = Chunk3D.getOffsetOfVoxel(x, y, z);
this.setVoxelByOffset(offset, clr);
}
@ -247,7 +246,7 @@ class Chunk {
chunkBuffer.set(chunkBufferInpt);
}
this.buffer = chunkBuffer;
const [faceCnt, lastPixel, heightMap] = Chunk.calculateMetaData(
const [faceCnt, lastPixel, heightMap] = Chunk3D.calculateMetaData(
chunkBuffer,
);
this.faceCnt = faceCnt;
@ -383,4 +382,4 @@ class Chunk {
}
}
export default Chunk;
export default Chunk3D;

131
src/ui/ChunkLoader.js Normal file
View File

@ -0,0 +1,131 @@
/*
* parent class for storing chunks
*/
import {
requestBigChunk,
receiveBigChunk,
receiveBigChunkFailure,
removeChunks,
// fetching of preLoad chunk triggers rerender already
// lets keep this out for now, until needed
// preLoadedBigChunk,
} from '../store/actions';
import {
MAX_LOADED_CHUNKS,
MAX_CHUNK_AGE,
} from '../core/constants';
/* eslint-disable class-methods-use-this */
class ChunkLoader {
#store;
// Map of chunkId: chunkRGB
#chunks;
#canvasId;
constructor(store, canvasId) {
this.#store = store;
this.#chunks = new Map();
this.#canvasId = canvasId;
}
get canvasId() {
return this.#canvasId;
}
get recChunkIds() {
const ids = [];
this.#chunks.forEach((chunk) => {
if (chunk.recUpdates) {
ids.push(chunk.id);
}
});
return ids;
}
destructor() {
this.#chunks.forEach((chunk) => {
chunk.destructor();
});
this.#chunks = new Map();
}
cget(key) {
return this.#chunks.get(key);
}
cset(key, chunk) {
/*
* chunks are not neccessarily fully loaded here,
* but they are in bcRecChunk
*/
this.#chunks.set(key, chunk);
}
bcReqChunk(chunk) {
const { z, i, j } = chunk;
this.#store.dispatch(requestBigChunk([z, i, j]));
}
bcRecChunk(chunk) {
this.#store.dispatch(receiveBigChunk(chunk));
const { size } = this.#chunks;
if (size > MAX_LOADED_CHUNKS) {
// hysteresis of 10%
const amountToRem = size - Math.floor(MAX_LOADED_CHUNKS * 0.9);
const chunksByTs = Array.from(this.#chunks.entries())
.sort((a, b) => a[1].timestamp - b[1].timestamp)
.slice(0, amountToRem);
chunksByTs.forEach(([key]) => {
this.#chunks.delete(key);
});
const remChunks = chunksByTs.map((c) => c[1]);
this.bcRemoveChunks(remChunks);
// eslint-disable-next-line max-len, no-console
console.log(`Cleared ${remChunks.length} to cut amount of chunks to ${this.#chunks.size}`);
}
}
/*
* 404 (aka empty chunks) also trigger this
*/
bcReqChunkFail(chunk, error) {
this.#store.dispatch(receiveBigChunkFailure(chunk, error.message));
}
/*
* @param chunks chunks[]
*/
bcRemoveChunks(chunks) {
this.#store.dispatch(removeChunks(chunks));
}
/*
* delete chunks that didn't get seen for
* more than 5min
*/
gc(renderer) {
const threshold = Date.now() - MAX_CHUNK_AGE;
const chunks = this.#chunks;
const remChunks = [];
chunks.forEach((chunk, key) => {
if (threshold > chunk.timestamp) {
const {
z,
i,
j,
} = chunk;
if (!renderer.isChunkInView(z, i, j)) {
remChunks.push(chunk);
chunks.delete(key);
chunk.destructor();
}
}
});
this.bcRemoveChunks(remChunks);
// eslint-disable-next-line no-console
console.log(`GC cleaned ${remChunks.length} chunks.`);
}
}
export default ChunkLoader;

View File

@ -2,19 +2,14 @@
* Fetching and storing of 2D chunks
*/
import ChunkRGB from './ChunkRGB';
import ChunkLoader from './ChunkLoader';
import Chunk from './Chunk2D';
import { TILE_SIZE, TILE_ZOOM_LEVEL } from '../core/constants';
import { shardOrigin } from '../store/actions/fetch';
import {
loadingTiles,
loadImage,
} from './loadImage';
import {
requestBigChunk,
receiveBigChunk,
receiveBigChunkFailure,
// preLoadedBigChunk,
} from '../store/actions';
import {
getMaxTiledZoom,
getCellInsideChunk,
@ -22,18 +17,14 @@ import {
getHistoricalCanvasSize,
} from '../core/utils';
class ChunkLoader {
store = null;
canvasId;
class ChunkLoader2D extends ChunkLoader {
canvasMaxTiledZoom;
historicalMaxTiledZooms;
palette;
canvasSize;
chunks;
constructor(store, canvasId, palette, canvasSize, historicalSizes) {
this.store = store;
this.canvasId = canvasId;
super(store, canvasId);
this.palette = palette;
this.canvasSize = canvasSize;
this.canvasMaxTiledZoom = getMaxTiledZoom(canvasSize);
@ -46,12 +37,6 @@ class ChunkLoader {
} else {
this.historicalMaxTiledZooms = [];
}
this.chunks = new Map();
}
getAllChunks() {
return this.chunks;
}
getPixelUpdate(
@ -60,7 +45,7 @@ class ChunkLoader {
offset,
color,
) {
const chunk = this.chunks.get(`${this.canvasMaxTiledZoom}:${cx}:${cy}`);
const chunk = this.cget(`${this.canvasMaxTiledZoom}:${cx}:${cy}`);
if (chunk) {
const ix = offset % TILE_SIZE;
const iy = Math.floor(offset / TILE_SIZE);
@ -75,7 +60,7 @@ class ChunkLoader {
const { canvasSize } = this;
const [cx, cy] = getChunkOfPixel(canvasSize, x, y);
const key = `${this.canvasMaxTiledZoom}:${cx}:${cy}`;
const chunk = this.chunks.get(key);
const chunk = this.cget(key);
if (!chunk) {
return 0;
}
@ -107,7 +92,7 @@ class ChunkLoader {
if (historicalTime && historicalTime !== '0000') {
// eslint-disable-next-line max-len
const incrementialChunkKey = `${historicalDate}${historicalTime}:${cx}:${cy}`;
const incrementialChunk = this.chunks.get(incrementialChunkKey);
const incrementialChunk = this.cget(incrementialChunkKey);
if (incrementialChunk) {
const incrementialColor = incrementialChunk.getColorIndex(px, false);
incrementialChunk.timestamp = curTime;
@ -118,7 +103,7 @@ class ChunkLoader {
}
const chunkKey = `${historicalDate}:${cx}:${cy}`;
const chunk = this.chunks.get(chunkKey);
const chunk = this.cget(chunkKey);
if (!chunk) {
return null;
}
@ -157,9 +142,6 @@ class ChunkLoader {
const pcX = (cx % zoomDiffAbs) * TILE_SIZE / zoomDiffAbs;
const pcY = (cy % zoomDiffAbs) * TILE_SIZE / zoomDiffAbs;
chunkRGB.preLoad(plChunk, zoomDiffAbs, pcX, pcY);
// fetching of preLoad chunk triggers rerender already
// lets keep this commented out for now
// this.store.dispatch(preLoadedBigChunk([zoom, cx, cy]));
return chunkRGB.image;
}
} catch (error) {
@ -181,17 +163,17 @@ class ChunkLoader {
chunkPreLoading = true,
) {
const chunkKey = `${zoom}:${cx}:${cy}`;
let chunkRGB = this.chunks.get(chunkKey);
let chunkRGB = this.cget(chunkKey);
if (chunkRGB) {
if (chunkRGB.ready) {
return chunkRGB.image;
}
} else if (fetch) {
chunkRGB = new ChunkRGB(this.palette, zoom, cx, cy);
this.chunks.set(chunkKey, chunkRGB);
chunkRGB = new Chunk(this.palette, zoom, cx, cy);
this.cset(chunkKey, chunkRGB);
// fetch chunk
if (this.canvasMaxTiledZoom === zoom) {
this.fetchBaseChunk(zoom, cx, cy, chunkRGB);
this.fetchBaseChunk(cx, cy, chunkRGB);
} else {
this.fetchTile(zoom, cx, cy, chunkRGB);
}
@ -208,7 +190,7 @@ class ChunkLoader {
? `${historicalDate}${historicalTime}`
: historicalDate;
chunkKey += `:${cx}:${cy}`;
const chunk = this.chunks.get(chunkKey);
const chunk = this.cget(chunkKey);
const { canvasId } = this;
if (chunk) {
if (chunk.ready) {
@ -222,19 +204,18 @@ class ChunkLoader {
this.historicalMaxTiledZooms,
);
// fetch tile
const chunkRGB = new ChunkRGB(
const chunkRGB = new Chunk(
this.palette,
historicalCanvasMaxTiledZoom,
cx,
cy,
);
this.chunks.set(chunkKey, chunkRGB);
this.cset(chunkKey, chunkRGB);
this.fetchHistoricalChunk(
cx,
cy,
historicalDate,
historicalTime,
historicalCanvasMaxTiledZoom,
chunkRGB,
);
}
@ -246,12 +227,10 @@ class ChunkLoader {
cy,
historicalDate,
historicalTime,
historicalCanvasMaxTiledZoom,
chunkRGB,
) {
const { canvasId } = this;
const center = [historicalCanvasMaxTiledZoom, cx, cy];
// eslint-disable-next-line max-len
let url = `${window.ssv.backupurl}/${historicalDate.slice(0, 4)}/${historicalDate.slice(4, 6)}/${historicalDate.slice(6)}/`;
if (historicalTime) {
@ -261,13 +240,13 @@ class ChunkLoader {
// full tiles
url += `${canvasId}/tiles/${cx}/${cy}.png`;
}
this.store.dispatch(requestBigChunk(center));
this.bcReqChunk(chunkRGB);
try {
const img = await loadImage(url);
chunkRGB.fromImage(img);
this.store.dispatch(receiveBigChunk(center, chunkRGB));
this.bcRecChunk(chunkRGB);
} catch (error) {
this.store.dispatch(receiveBigChunkFailure(center, error.message));
this.bcReqChunkFail(chunkRGB, error);
if (historicalTime) {
chunkRGB.empty(true);
} else {
@ -276,9 +255,8 @@ class ChunkLoader {
}
}
async fetchBaseChunk(zoom, cx, cy, chunkRGB) {
const center = [zoom, cx, cy];
this.store.dispatch(requestBigChunk(center));
async fetchBaseChunk(cx, cy, chunkRGB) {
this.bcReqChunk(chunkRGB);
try {
const url = `${shardOrigin}/chunks/${this.canvasId}/${cx}/${cy}.bmp`;
const response = await fetch(url);
@ -290,30 +268,30 @@ class ChunkLoader {
} else {
throw new Error('Chunk response was invalid');
}
this.store.dispatch(receiveBigChunk(center, chunkRGB));
this.bcRecChunk(chunkRGB);
} else {
throw new Error('Network response was not ok.');
}
} catch (error) {
chunkRGB.empty();
this.store.dispatch(receiveBigChunkFailure(center, error.message));
chunkRGB.recUpdates = true;
this.bcReqChunkFail(chunkRGB, error);
}
}
async fetchTile(zoom, cx, cy, chunkRGB) {
const center = [zoom, cx, cy];
this.store.dispatch(requestBigChunk(center));
this.bcReqChunk(chunkRGB);
try {
// eslint-disable-next-line max-len
const url = `/tiles/${this.canvasId}/${zoom}/${cx}/${cy}.webp`;
const img = await loadImage(url);
chunkRGB.fromImage(img);
this.store.dispatch(receiveBigChunk(center, chunkRGB));
this.bcRecChunk(chunkRGB);
} catch (error) {
this.store.dispatch(receiveBigChunkFailure(center, error.message));
chunkRGB.empty();
this.bcReqChunkFail(chunkRGB, error);
}
}
}
export default ChunkLoader;
export default ChunkLoader2D;

View File

@ -3,37 +3,21 @@
*
*/
import Chunk from './ChunkRGB3D';
import {
requestBigChunk,
receiveBigChunk,
receiveBigChunkFailure,
} from '../store/actions';
import ChunkLoader from './ChunkLoader';
import Chunk from './Chunk3D';
import {
getChunkOfPixel,
getOffsetOfPixel,
} from '../core/utils';
import { shardOrigin } from '../store/actions/fetch';
class ChunkLoader {
store = null;
canvasId;
class ChunkLoader3D extends ChunkLoader {
palette;
chunks; // Map<string, Chunk>
constructor(store, canvasId, palette, canvasSize) {
this.store = store;
this.canvasId = canvasId;
super(store, canvasId);
this.palette = palette;
this.canvasSize = canvasSize;
this.chunks = new Map();
}
destructor() {
this.chunks.forEach((chunk) => {
chunk.destructor();
});
this.chunks = new Map();
}
getVoxel(x, y, z) {
@ -41,7 +25,7 @@ class ChunkLoader {
const [xc, zc] = getChunkOfPixel(canvasSize, x, y, z);
const offset = getOffsetOfPixel(canvasSize, x, y, z);
const key = `${xc}:${zc}`;
const chunk = this.chunks.get(key);
const chunk = this.cget(key);
if (chunk) {
const clr = chunk.getVoxelByOffset(offset);
return clr;
@ -49,10 +33,6 @@ class ChunkLoader {
return 0;
}
getAllChunks() {
return this.chunks;
}
getVoxelUpdate(
xc,
zc,
@ -60,7 +40,7 @@ class ChunkLoader {
color,
) {
const key = `${xc}:${zc}`;
const chunk = this.chunks.get(key);
const chunk = this.cget(key);
if (chunk) {
chunk.setVoxelByOffset(offset, color);
}
@ -69,10 +49,10 @@ class ChunkLoader {
getChunk(xc, zc, fetch) {
const chunkKey = `${xc}:${zc}`;
// console.log(`Get chunk ${chunkKey}`);
let chunk = this.chunks.get(chunkKey);
let chunk = this.cget(chunkKey);
if (chunk) {
if (chunk.ready) {
chunk.timestamp = Date.now();
chunk.touch();
return chunk.mesh;
}
return null;
@ -80,15 +60,14 @@ class ChunkLoader {
if (fetch) {
// fetch chunk
chunk = new Chunk(this.palette, chunkKey, xc, zc);
this.chunks.set(chunkKey, chunk);
this.cset(chunkKey, chunk);
this.fetchChunk(xc, zc, chunk);
}
return null;
}
async fetchChunk(cx, cz, chunk) {
const center = [0, cx, cz];
this.store.dispatch(requestBigChunk(center));
this.bcReqChunk(chunk);
try {
const url = `${shardOrigin}/chunks/${this.canvasId}/${cx}/${cz}.bmp`;
const response = await fetch(url);
@ -100,15 +79,15 @@ class ChunkLoader {
} else {
throw new Error('Chunk response was invalid');
}
this.store.dispatch(receiveBigChunk(center, chunk));
this.bcRecChunk(chunk);
} else {
throw new Error('Network response was not ok.');
}
} catch (error) {
chunk.empty();
this.store.dispatch(receiveBigChunkFailure(center, error));
this.bcReqChunkFail(chunk, error);
}
}
}
export default ChunkLoader;
export default ChunkLoader3D;

53
src/ui/Renderer.js Normal file
View File

@ -0,0 +1,53 @@
/*
* parent class for Renderer
*/
/* eslint-disable class-methods-use-this */
class Renderer {
store;
// needs to be known for lazy loading THREE
is3D = null;
// chunk loader must be set by subclass
chunkLoader = null;
constructor(store) {
this.store = store;
}
get chunks() {
return this.chunkLoader.chunks;
}
get recChunkIds() {
if (!this.chunkLoader) {
return [];
}
return this.chunkLoader.recChunkIds;
}
destructor() {
if (this.chunkLoader) {
this.chunkLoader.destructor();
}
}
render() {}
renderPixel() {}
updateCanvasData() {}
isChunkInView() {
return true;
}
gc() {
if (!this.chunkLoader) {
return;
}
this.chunkLoader.gc(this);
}
}
export default Renderer;

View File

@ -18,14 +18,14 @@ import {
} from './render2Delements';
import PixelPainterControls from '../controls/PixelPainterControls';
import Renderer from './Renderer';
import ChunkLoader from './ChunkLoader2D';
import pixelNotify from './PixelNotify';
class Renderer {
class Renderer2D extends Renderer {
is3D = false;
//
canvasId = null;
chunkLoader = null;
//--
centerChunk;
tiledScale;
@ -33,7 +33,6 @@ class Renderer {
hover;
//--
viewport = null;
store;
//--
forceNextRender;
forceNextSubrender;
@ -43,6 +42,7 @@ class Renderer {
oldHistoricalTime;
constructor(store) {
super(store);
this.centerChunk = [null, null];
this.tiledScale = 0;
this.tiledZoom = 4;
@ -71,23 +71,23 @@ class Renderer {
context.fillStyle = '#000000';
context.fillRect(0, 0, this.canvas.width, this.canvas.height);
//--
this.setStore(store);
const state = store.getState();
this.updateCanvasData(state);
this.updateScale(state);
this.controls = new PixelPainterControls(this, this.viewport, store);
}
destructor() {
this.controls.dispose();
window.removeEventListener('resize', this.onWindowResize);
this.viewport.remove();
super.destructor();
}
getViewport() {
return this.viewport;
}
getAllChunks() {
return this.chunkLoader.getAllChunks();
}
onWindowResize() {
this.viewport.width = window.innerWidth;
this.viewport.height = window.innerHeight;
@ -111,15 +111,6 @@ class Renderer {
this.forceNextRender = true;
}
// HAS to be set before any rendering can happen
setStore(store) {
this.store = store;
const state = store.getState();
this.updateCanvasData(state);
this.updateScale(state);
this.controls = new PixelPainterControls(this, this.viewport, store);
}
updateCanvasData(state) {
const {
canvasId,
@ -732,4 +723,4 @@ class Renderer {
}
export default Renderer;
export default Renderer2D;

View File

@ -8,6 +8,7 @@ import Sky from './Sky';
import InfiniteGridHelper from './InfiniteGridHelper';
import VoxelPainterControls from '../controls/VoxelPainterControls';
import Renderer from './Renderer';
import ChunkLoader from './ChunkLoader3D';
import {
getChunkOfPixel,
@ -24,11 +25,9 @@ import pixelTransferController from './PixelTransferController';
const renderDistance = 150;
class Renderer {
class Renderer3D extends Renderer {
is3D = true;
//--
store;
//--
scene;
camera;
rollOverMesh;
@ -48,14 +47,12 @@ class Renderer {
pressCdTime;
multitap;
//--
chunkLoader = null;
forceNextRender = false;
constructor(store) {
this.store = store;
super(store);
const state = store.getState();
this.objects = [];
this.chunkLoader = null;
// camera
const camera = new THREE.PerspectiveCamera(
@ -212,9 +209,7 @@ class Renderer {
const { domElement } = this.threeRenderer;
this.threeRenderer = null;
domElement.remove();
if (this.chunkLoader) {
this.chunkLoader.destructor();
}
super.destructor();
}
updateView() {
@ -266,11 +261,6 @@ class Renderer {
return null;
}
// TODO check if GC even works on 3D canvas
getAllChunks() {
return this.chunkLoader.getAllChunks();
}
renderPixel(
i,
j,
@ -669,4 +659,4 @@ class Renderer {
}
}
export default Renderer;
export default Renderer3D;

View File

@ -7,17 +7,12 @@
import { t } from 'ttag';
import Renderer from './Renderer';
import Renderer2D from './Renderer2D';
import { pAlert } from '../store/actions';
import { isWebGL2Available } from '../core/utils';
const dummyRenderer = {
is3D: null,
render: () => null,
destructor: () => null,
renderPixel: () => null,
updateCanvasData: () => null,
};
const dummyRenderer = new Renderer();
let renderer = dummyRenderer;