From e3186f7f41d63666fd748b68c3cb7c83146f5003 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sat, 16 Apr 2022 09:50:46 +0300 Subject: [PATCH] loader --- src/client/game.ts | 10 +-- src/client/object/model/pony.ts | 4 +- src/client/object/resource/cubemap.ts | 5 +- src/client/object/resource/loading-manager.ts | 43 ++++++++++++ src/client/object/resource/pony-loader.ts | 7 +- src/client/object/resource/texture.ts | 3 +- ...Shader.ts => client-world-chunk-shader.ts} | 11 +-- ...tWorldLoader.ts => client-world-loader.ts} | 3 +- ...ldManifest.ts => client-world-manifest.ts} | 0 ...orldTexture.ts => client-world-texture.ts} | 3 +- .../world/{ClientWorld.ts => client-world.ts} | 4 +- src/client/scss/index.scss | 68 +++++++++++++++++++ 12 files changed, 138 insertions(+), 23 deletions(-) create mode 100644 src/client/object/resource/loading-manager.ts rename src/client/object/world/{ClientWorldChunkShader.ts => client-world-chunk-shader.ts} (97%) rename src/client/object/world/{ClientWorldLoader.ts => client-world-loader.ts} (82%) rename src/client/object/world/{ClientWorldManifest.ts => client-world-manifest.ts} (100%) rename src/client/object/world/{ClientWorldTexture.ts => client-world-texture.ts} (78%) rename src/client/object/world/{ClientWorld.ts => client-world.ts} (95%) diff --git a/src/client/game.ts b/src/client/game.ts index afaad62..6ec1a19 100644 --- a/src/client/game.ts +++ b/src/client/game.ts @@ -12,13 +12,13 @@ import { CubeMap } from './object/resource/cubemap'; import { VideoPlayer } from './object/other/video-player'; import { Player } from './object/player'; import { PlayerEntity } from './object/player-entity'; -import { ClientWorld } from './object/world/ClientWorld'; -import { ClientWorldLoader } from './object/world/ClientWorldLoader'; -import { ClientWorldManifest } from './object/world/ClientWorldManifest'; import { Renderer } from './renderer'; -import { to2D } from '../common/convert'; import { Grass } from './object/model/grass'; import { BaseTexture } from './object/resource/texture'; +import { ClientWorld } from './object/world/client-world'; +import { ClientWorldManifest } from './object/world/client-world-manifest'; +import { ClientWorldLoader } from './object/world/client-world-loader'; +import { LoadingManagerWrapper } from './object/resource/loading-manager'; export class Game { public players: (Player | PlayerEntity)[] = []; @@ -38,6 +38,8 @@ export class Game { constructor(public socket: Socket) {} async initialize(): Promise { + LoadingManagerWrapper.getInstance().initialize(); + const worldManifest = await ClientWorldManifest.loadManifest(); this.world = new ClientWorld(new ClientWorldLoader(), worldManifest); diff --git a/src/client/object/model/pony.ts b/src/client/object/model/pony.ts index 0ace9d5..3212904 100644 --- a/src/client/object/model/pony.ts +++ b/src/client/object/model/pony.ts @@ -14,7 +14,7 @@ import { FullStatePacket, CharacterPacket } from '../../../common/types/packet'; import { CanvasUtils } from '../canvas-utils'; import { NameTag } from '../nametag'; import { PonyModelLoader } from '../resource/pony-loader'; -import { ClientWorld } from '../world/ClientWorld'; +import { ClientWorld } from '../world/client-world'; import { PonyEyes } from './eyes'; const nameTagBuilder = new CanvasUtils({ @@ -124,7 +124,7 @@ export class PonyEntity { } public jump() { - this.velocity.y = 16; + this.velocity.y = 12; } public setColor(color: number | string) { diff --git a/src/client/object/resource/cubemap.ts b/src/client/object/resource/cubemap.ts index 143d585..42de8e9 100644 --- a/src/client/object/resource/cubemap.ts +++ b/src/client/object/resource/cubemap.ts @@ -1,6 +1,9 @@ import { CubeTextureLoader, CubeTexture } from 'three'; +import { LoadingManagerWrapper } from './loading-manager'; -const loader = new CubeTextureLoader(); +const loader = new CubeTextureLoader( + LoadingManagerWrapper.getInstance().manager, +); export class CubeMap { constructor(public source: string, public texture: CubeTexture) {} diff --git a/src/client/object/resource/loading-manager.ts b/src/client/object/resource/loading-manager.ts new file mode 100644 index 0000000..322641d --- /dev/null +++ b/src/client/object/resource/loading-manager.ts @@ -0,0 +1,43 @@ +import { LoadingManager } from 'three'; + +let instance: LoadingManagerWrapper; +export class LoadingManagerWrapper { + public manager = new LoadingManager(); + public element = document.createElement('div'); + private _inner = document.createElement('div'); + private _status = document.createElement('span'); + private _barWrapper = document.createElement('div'); + private _bar = document.createElement('div'); + + public static getInstance(): LoadingManagerWrapper { + if (!instance) { + instance = new LoadingManagerWrapper(); + } + return instance; + } + + public initialize() { + this.element.classList.add('loading__wrapper'); + this._inner.classList.add('loading'); + this._status.classList.add('loading__status'); + this._barWrapper.classList.add('loading__bar'); + this._bar.classList.add('loading__bar-inner'); + + this._barWrapper.append(this._bar); + this._inner.append(this._status, this._barWrapper); + this.element.append(this._inner); + + this._status.innerText = 'Loading (0 %)'; + this.manager.onProgress = (url, loaded, total) => { + const percent = (loaded / total) * 100; + this._status.innerText = `Loading (${Math.floor(percent)} %)`; + this._bar.style.setProperty('--loading-percentage', `${percent}%`); + }; + + this.manager.onLoad = () => { + this.element.classList.add('loading--complete'); + }; + + document.body.prepend(this.element); + } +} diff --git a/src/client/object/resource/pony-loader.ts b/src/client/object/resource/pony-loader.ts index 170f97b..9a7277c 100644 --- a/src/client/object/resource/pony-loader.ts +++ b/src/client/object/resource/pony-loader.ts @@ -1,11 +1,14 @@ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; +import { LoadingManagerWrapper } from './loading-manager'; // Instantiate a loader -const loader = new GLTFLoader(); +const loader = new GLTFLoader(LoadingManagerWrapper.getInstance().manager); // Optional: Provide a DRACOLoader instance to decode compressed mesh data -const dracoLoader = new DRACOLoader(); +const dracoLoader = new DRACOLoader( + LoadingManagerWrapper.getInstance().manager, +); dracoLoader.setDecoderPath('/examples/js/libs/draco/'); loader.setDRACOLoader(dracoLoader); diff --git a/src/client/object/resource/texture.ts b/src/client/object/resource/texture.ts index ba965d0..466c191 100644 --- a/src/client/object/resource/texture.ts +++ b/src/client/object/resource/texture.ts @@ -1,6 +1,7 @@ import { TextureLoader, Texture } from 'three'; +import { LoadingManagerWrapper } from './loading-manager'; -const loader = new TextureLoader(); +const loader = new TextureLoader(LoadingManagerWrapper.getInstance().manager); export class BaseTexture { constructor(public source: string, public texture: Texture) {} diff --git a/src/client/object/world/ClientWorldChunkShader.ts b/src/client/object/world/client-world-chunk-shader.ts similarity index 97% rename from src/client/object/world/ClientWorldChunkShader.ts rename to src/client/object/world/client-world-chunk-shader.ts index 7700bac..adabf34 100644 --- a/src/client/object/world/ClientWorldChunkShader.ts +++ b/src/client/object/world/client-world-chunk-shader.ts @@ -1,13 +1,6 @@ -import { - Color, - MultiplyOperation, - ShaderMaterial, - UniformsLib, - UniformsUtils, - Vector3, -} from 'three'; +import { ShaderMaterial, UniformsLib, UniformsUtils } from 'three'; import { WorldChunk } from '../../../common/world/WorldChunk'; -import { ClientWorldTexture } from './ClientWorldTexture'; +import { ClientWorldTexture } from './client-world-texture'; // Adapted from the Lambert Material shader // https://github.com/mrdoob/three.js/blob/44837d13a1bc0cf59824f3a6ddfab19ecd5ff435/src/renderers/shaders/ShaderLib/meshlambert.glsl.js diff --git a/src/client/object/world/ClientWorldLoader.ts b/src/client/object/world/client-world-loader.ts similarity index 82% rename from src/client/object/world/ClientWorldLoader.ts rename to src/client/object/world/client-world-loader.ts index b8b2a61..8805d4b 100644 --- a/src/client/object/world/ClientWorldLoader.ts +++ b/src/client/object/world/client-world-loader.ts @@ -1,8 +1,9 @@ import { ImageLoader } from 'three'; import { WorldLoader } from '../../../common/world/WorldLoader'; import { CanvasUtils } from '../canvas-utils'; +import { LoadingManagerWrapper } from '../resource/loading-manager'; -const loader = new ImageLoader(); +const loader = new ImageLoader(LoadingManagerWrapper.getInstance().manager); const canvasUtil = new CanvasUtils(); const worldPath = '/assets/terrain/region'; diff --git a/src/client/object/world/ClientWorldManifest.ts b/src/client/object/world/client-world-manifest.ts similarity index 100% rename from src/client/object/world/ClientWorldManifest.ts rename to src/client/object/world/client-world-manifest.ts diff --git a/src/client/object/world/ClientWorldTexture.ts b/src/client/object/world/client-world-texture.ts similarity index 78% rename from src/client/object/world/ClientWorldTexture.ts rename to src/client/object/world/client-world-texture.ts index e1dad4c..07f74d5 100644 --- a/src/client/object/world/ClientWorldTexture.ts +++ b/src/client/object/world/client-world-texture.ts @@ -1,6 +1,7 @@ import { RepeatWrapping, Texture, TextureLoader } from 'three'; +import { LoadingManagerWrapper } from '../resource/loading-manager'; -const loader = new TextureLoader(); +const loader = new TextureLoader(LoadingManagerWrapper.getInstance().manager); export class ClientWorldTexture { constructor(public source: string, public texture: Texture) {} diff --git a/src/client/object/world/ClientWorld.ts b/src/client/object/world/client-world.ts similarity index 95% rename from src/client/object/world/ClientWorld.ts rename to src/client/object/world/client-world.ts index f0319ae..ce1c90d 100644 --- a/src/client/object/world/ClientWorld.ts +++ b/src/client/object/world/client-world.ts @@ -1,8 +1,8 @@ import { Object3D, Vector2, Vector3 } from 'three'; import { WorldChunk } from '../../../common/world/WorldChunk'; import { WorldManager } from '../../../common/world/WorldManager'; -import { ClientWorldChunkShader } from './ClientWorldChunkShader'; -import { ClientWorldTexture } from './ClientWorldTexture'; +import { ClientWorldChunkShader } from './client-world-chunk-shader'; +import { ClientWorldTexture } from './client-world-texture'; import { QuadtreeMesher } from './quadtree/quadtree-mesher'; // TODO: distance loading diff --git a/src/client/scss/index.scss b/src/client/scss/index.scss index 1baed6b..011720f 100644 --- a/src/client/scss/index.scss +++ b/src/client/scss/index.scss @@ -177,3 +177,71 @@ body { width: 100%; } } + +.loading { + display: flex; + flex-direction: column; + max-width: 400px; + width: 100vw; + margin: 10% auto; + text-align: center; + font-size: 2rem; + padding: 2rem; + + &__wrapper { + position: absolute; + z-index: 3000; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-color: #202020; + color: #fff; + transition: opacity 1s linear; + opacity: 1; + pointer-events: none; + + &.loading--complete { + opacity: 0; + } + } + + &__bar { + width: 100%; + height: 20px; + margin-top: 2rem; + background-color: #141414; + border-radius: 4px; + overflow: hidden; + + &-inner { + width: var(--loading-percentage); + height: 20px; + background-color: #1098ab; + transition: width 50ms linear; + + background-image: linear-gradient( + -45deg, + rgba(255, 255, 255, .2) 25%, + transparent 25%, + transparent 50%, + rgba(255, 255, 255, .2) 50%, + rgba(255, 255, 255, .2) 75%, + transparent 75%, + transparent + ); + z-index: 1; + background-size: 50px 50px; + animation: move 2s linear infinite; + } + } +} + +@keyframes move { + 0% { + background-position: 0 0; + } + 100% { + background-position: 50px 50px; + } +}