Add files from before the Git repository
This commit is contained in:
parent
81729a9c39
commit
a0f9b644a4
46
README.md
46
README.md
@ -1,3 +1,47 @@
|
||||
# XVoxel-ASync
|
||||
|
||||
A voxel game based on OpenVoxelProject
|
||||
A voxel game based on OpenVoxelProject, it is able to run fully in a web browser.
|
||||
|
||||
## Philosophy
|
||||
|
||||
My goal for this game is for it to be light, extendable, pluggable and easy to mod without too much nonsense.
|
||||
- Light, unlike heavy as other games
|
||||
- Extendable, even its core
|
||||
- Pluggable, so you can add your own additions
|
||||
- Easy to mod, with an upcoming modding interface made to be easy and efficient
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [x] Basic menu
|
||||
- [x] 3D rendering
|
||||
- [ ] Resources
|
||||
- [ ] Textures (partially done)
|
||||
- [ ] Sounds
|
||||
- [ ] Models (as JSON)
|
||||
- [ ] Physics (have to decide which engine to use)
|
||||
- [ ] Settings
|
||||
- [ ] Video
|
||||
- [x] Field of View
|
||||
- [ ] Lighting
|
||||
- [ ] Audio
|
||||
- [ ] Sources
|
||||
- [ ] Channels (Mono, Stereo or Surround if supported)
|
||||
- [ ] Input (keyboard/mouse, touchscreen and gamepad)
|
||||
- [ ] Sensitivity
|
||||
- [ ] Keys
|
||||
- [ ] Networking
|
||||
- [x] Loading worlds
|
||||
- [ ] Saving worlds (implemented but unavailable in the menu)
|
||||
- [ ] Multiplayer
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
The libraries cited below are included in the "lib" folder for convenience, if you want your library's files removed from my project's, please kindly tell me via [e-mail](mailto:x3f200c@protonmail.com) or using any other contact information that can be found on [my main website](https://x3f200c.net/).
|
||||
- [Three.JS](https://github.com/mrdoob/three.js) under the MIT license, used for rendering worlds (and its GLTF loader for future work)
|
||||
- [Cannon ES](https://github.com/pmndrs/cannon-es) also under the MIT license, not used yet, will consider switching to it in order to use less WebAssembly and more vanilla JavaScript
|
||||
- [Ammo.JS](https://github.com/kripken/ammo.js) under the ZLib license, used to simulate physics in worlds
|
||||
- [FFlate](https://github.com/101arrowz/fflate) under the MIT license too, used to compress and decompress ZIP files (saving and loading worlds)
|
||||
- [Matrix JS SDK](https://github.com/matrix-org/matrix-js-sdk) under the Apache 2.0 license, used for networking (multiplayer, uploading, downloading worlds from the Matrix network)
|
||||
- [PeerJS](https://github.com/peers/peerjs) under the MIT license, will be used for alternative networking
|
||||
- [Olm](https://gitlab.matrix.org/matrix-org/olm) under the Apache 2.0 license too, used for encryption support in networking
|
||||
- Improved Perlin noise (I forgot where I found it and what its license was)
|
||||
|
BIN
assets/images/xvoxel.ico
Normal file
BIN
assets/images/xvoxel.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/images/xvoxel.png
Normal file
BIN
assets/images/xvoxel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
308
assets/stylesheets/game.css
Normal file
308
assets/stylesheets/game.css
Normal file
@ -0,0 +1,308 @@
|
||||
/* Variables */
|
||||
|
||||
:root {
|
||||
--background: rgba(255, 255, 255, 0);
|
||||
--background-titlebar: rgba(0, 0, 0, 0.24);
|
||||
--background-menu: rgba(168, 190, 210, 0.36);
|
||||
--background-menu-interactable: rgba(125, 135, 150, 0.48);
|
||||
--background-menu-interactable-hover: rgba(157, 172, 213, 0.48);
|
||||
--background-menu-uninteractable: rgba(79, 87, 99, 0.48);
|
||||
--text-color-default: rgba(235, 245, 245, 1);
|
||||
--cursor-default: default;
|
||||
--cursor-not-allowed: not-allowed;
|
||||
}
|
||||
|
||||
/* Rules */
|
||||
|
||||
* {
|
||||
background: var(--background);
|
||||
cursor: var(--cursor-default);
|
||||
color: var(--text-color-default);
|
||||
margin: 0px;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
header {
|
||||
z-index: 100;
|
||||
background: var(--background-titlebar);
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 3rem;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
#title {
|
||||
margin: 0.4rem;
|
||||
}
|
||||
|
||||
#actionbuttoncontainer {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
height: 100%;
|
||||
-webkit-app-region: no-drag;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.windowactionbutton {
|
||||
top: 0px;
|
||||
width: 6rem;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.windowactionbutton:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.windowactionbutton * {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
#minwin {
|
||||
right: calc(6rem + 6rem);
|
||||
}
|
||||
|
||||
#maxrestorewin {
|
||||
right: 6rem;
|
||||
}
|
||||
|
||||
#closewin {
|
||||
right: 0px;
|
||||
background: rgba(255, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
#closewin:hover {
|
||||
background: rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.initially-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fullscreen {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
z-index: 96;
|
||||
}
|
||||
|
||||
#renderers {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
#renderers > div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#gui {
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
#crosshair {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
mix-blend-mode: difference;
|
||||
z-index: 15
|
||||
}
|
||||
|
||||
#touchcontrols {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
#dpad {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
min-width: 16rem;
|
||||
min-height: 16rem;
|
||||
max-width: 48rem;
|
||||
max-height: 48rem;
|
||||
background: radial-gradient(rgba(180, 180, 180, 0.80) 0%, rgba(180, 180, 180, 0) 72%);
|
||||
z-index: 32;
|
||||
}
|
||||
|
||||
#secpad {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
min-width: calc(16rem / 3);
|
||||
min-height: calc(16rem / 3);
|
||||
max-width: calc(48rem / 3);
|
||||
max-height: calc(48rem / 3);
|
||||
margin: calc(16rem / 3);
|
||||
background: radial-gradient(rgba(180, 180, 180, 0.80) 0%, rgba(180, 180, 180, 0) 72%);
|
||||
z-index: 32;
|
||||
}
|
||||
|
||||
#menus {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-flow: row;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.menu {
|
||||
top: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
/* position: absolute; */
|
||||
background: var(--background-menu);
|
||||
height: calc(100% - 3rem);
|
||||
padding-top: 3rem;
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.void {
|
||||
height: inherit;
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
.closebutton {
|
||||
left: 0px;
|
||||
width: calc(100% - 1rem);
|
||||
bottom: 0px;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
#loadingscreen {
|
||||
background: rgba(32, 48, 64, 1);
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
z-index: 45;
|
||||
}
|
||||
|
||||
#loadingbar {
|
||||
position: absolute;
|
||||
min-width: 12rem;
|
||||
min-height: 3rem;
|
||||
width: 64%;
|
||||
height: 25%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgba(240, 24, 24, 1);
|
||||
}
|
||||
|
||||
#loadingtext {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 45;
|
||||
mix-blend-mode: difference;
|
||||
}
|
||||
|
||||
#loadingbarprogress {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background: rgba(24, 240, 48, 1);
|
||||
}
|
||||
|
||||
button:disabled, button:disabled:hover, input:disabled, input:disabled:hover {
|
||||
background: var(--background-menu-uninteractable);
|
||||
cursor: var(--cursor-not-allowed);
|
||||
}
|
||||
|
||||
button, input:not(input[type=checkbox]), select {
|
||||
appearance: none;
|
||||
background: var(--background-menu-interactable);
|
||||
border: 0.125rem solid black;
|
||||
padding: 0px;
|
||||
margin: 0.5rem;
|
||||
font-size: 1rem;
|
||||
width: calc(100% - 1rem);
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
|
||||
input:not(input[type=checkbox]) {
|
||||
width: calc(100% - 1.25rem);
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
button:hover, input:hover, select:hover {
|
||||
background: var(--background-menu-interactable-hover);
|
||||
}
|
||||
|
||||
input[type=text]::placeholder {
|
||||
color: rgba(235, 245, 245, 0.5);
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
background: rgba(125, 135, 150, 0.25);
|
||||
border: 0.125rem solid black;
|
||||
border-radius: 0px;
|
||||
width: 1.5rem;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-thumb {
|
||||
-moz-appearance: none;
|
||||
background: rgba(125, 135, 150, 0.25);
|
||||
border: 0.125rem solid black;
|
||||
border-radius: 0px;
|
||||
width: 1.5rem;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-thumb:hover {
|
||||
background: var(--background-menu-interactable-hover);
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-thumb:hover {
|
||||
background: var(--background-menu-interactable-hover);
|
||||
}
|
79
core.js
Normal file
79
core.js
Normal file
@ -0,0 +1,79 @@
|
||||
var modules = {
|
||||
"render": {
|
||||
"source": "./modules/render.js",
|
||||
"dependsOn": []
|
||||
},
|
||||
"input": {
|
||||
"source": "./modules/input.js",
|
||||
"dependsOn": ["render"]
|
||||
},
|
||||
"resources": {
|
||||
"source": "./modules/resources.js",
|
||||
"dependsOn": []
|
||||
},
|
||||
"world": {
|
||||
"source": "./modules/world.js",
|
||||
"dependsOn": []
|
||||
},
|
||||
"network": {
|
||||
"source": "./modules/network.js",
|
||||
"dependsOn": []
|
||||
}
|
||||
};
|
||||
|
||||
var plugins = {
|
||||
"splash": {
|
||||
"type": "plugin",
|
||||
"source": "./plugins/splash.js",
|
||||
"loadAs": "splash",
|
||||
"dependsOn": ["render"]
|
||||
}
|
||||
};
|
||||
|
||||
var loadings = {};
|
||||
|
||||
class GameCore extends global.utils.EventListener {
|
||||
constructor () {
|
||||
super();
|
||||
|
||||
this.modules = {};
|
||||
this.plugins = {};
|
||||
}
|
||||
init (meta) {
|
||||
return new Promise((function (resolve, reject) {
|
||||
for (var data in meta) {
|
||||
if (meta.hasOwnProperty(data)) {
|
||||
var metadata = meta[data];
|
||||
|
||||
if (loadings[data]) continue;
|
||||
|
||||
loadings[data] = this.loadModule(data);
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(Object.values(loadings)).then((function () {
|
||||
this.emit("pre-init", {});
|
||||
|
||||
resolve(this);
|
||||
}).bind(this)).catch(reject);
|
||||
}).bind(this));
|
||||
}
|
||||
loadModule (moduleName) {
|
||||
return load("./modules/" + moduleName + ".js").then((function (mod) {
|
||||
this.modules[moduleName] = mod;
|
||||
}).bind(this)).catch(throwError);
|
||||
}
|
||||
loadPlugin (pluginName) {
|
||||
return load("./plugins/" + pluginName + ".js").then((function (plugin) {
|
||||
this.plugins[pluginName] = plugin;
|
||||
}).bind(this)).catch(throwError);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
"GameCore": GameCore,
|
||||
"loadData": {
|
||||
"modules": modules,
|
||||
"plugins": plugins
|
||||
}
|
||||
};
|
BIN
data/resources/XVoxel.zip
Normal file
BIN
data/resources/XVoxel.zip
Normal file
Binary file not shown.
231
data/resources/XVoxel/models/character.json
Normal file
231
data/resources/XVoxel/models/character.json
Normal file
@ -0,0 +1,231 @@
|
||||
{
|
||||
"hitbox": [0.7, 1.8, 0.7],
|
||||
"control": {
|
||||
"camera": "head",
|
||||
"rotationX": "head"
|
||||
},
|
||||
"parts": {
|
||||
"root": {
|
||||
"type": "group",
|
||||
"position": [0, -0.25, 0],
|
||||
"children": [
|
||||
"body"
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.5, 0.75, 0.25],
|
||||
"position": [0, 0.375, 0],
|
||||
"uvMap": [
|
||||
[[0.25, 0.5], [0.3125, 0.6875]],
|
||||
[[0.4375, 0.5], [0.5, 0.6875]],
|
||||
[[0.3125, 0.5], [0.4375, 0.6875]],
|
||||
[[0.3125, 0.6875], [0.4375, 0.75]],
|
||||
[[0.4375, 0.6875], [0.5625, 0.75]],
|
||||
[[0.5, 0.6875], [0.625, 0.5]],
|
||||
[[0.3125, 0.6875], [0.3125, 0.5]]
|
||||
],
|
||||
"children": [
|
||||
"neck",
|
||||
"jacket",
|
||||
"left-shoulder",
|
||||
"right-shoulder",
|
||||
"left-pelvis",
|
||||
"right-pelvis"
|
||||
]
|
||||
},
|
||||
"neck": {
|
||||
"type": "group",
|
||||
"position": [0, 0.375, 0],
|
||||
"children": [
|
||||
"head"
|
||||
]
|
||||
},
|
||||
"head": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.5, 0.5, 0.5],
|
||||
"position": [0, 0.25, 0],
|
||||
"uvMap": [
|
||||
[[0.0, 0.75], [0.125, 0.875]],
|
||||
[[0.25, 0.75], [0.375, 0.875]],
|
||||
[[0.125, 0.875], [0.25, 1.0]],
|
||||
[[0.25, 0.875], [0.375, 1.0]],
|
||||
[[0.375, 0.75], [0.5, 0.875]],
|
||||
[[0.125, 0.75], [0.25, 0.875]]
|
||||
],
|
||||
"children": [
|
||||
"hat"
|
||||
]
|
||||
},
|
||||
"hat": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.56, 0.56, 0.56],
|
||||
"position": [0, 0, 0],
|
||||
"uvMap": [
|
||||
[[0.5, 0.75], [0.625, 0.875]],
|
||||
[[0.75, 0.75], [0.875, 0.875]],
|
||||
[[0.625, 0.875], [0.75, 1.0]],
|
||||
[[0.75, 0.875], [0.875, 1.0]],
|
||||
[[0.875, 0.75], [1.0, 0.875]],
|
||||
[[0.625, 0.75], [0.75, 0.875]]
|
||||
]
|
||||
},
|
||||
"jacket": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.6, 0.85, 0.35],
|
||||
"position": [0, 0, 0],
|
||||
"uvMap": [
|
||||
[[0.25, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.4375, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.3125, 0.125], [0.5, 0.0625]],
|
||||
[[0.4375, 0.125], [0.5, 0.0625]],
|
||||
[[0.5, 0.125], [0.5625, 0.1875]],
|
||||
[[0.3125, 0.125], [0.5625, 0.1875]]
|
||||
]
|
||||
},
|
||||
"left-shoulder": {
|
||||
"type": "group",
|
||||
"position": [-0.25, 0.25, 0],
|
||||
"children": [
|
||||
"left-arm"
|
||||
]
|
||||
},
|
||||
"left-arm": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.25, 0.75, 0.25],
|
||||
"position": [-0.125, -0.25, 0],
|
||||
"uvMap": [
|
||||
[[0.5, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.625, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.5625, 0.0625], [0.75, 0.0625]],
|
||||
[[0.625, 0.0625], [0.75, 0.0625]],
|
||||
[[0.6875, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.5625, 0.0625], [0.8125, 0.1875]]
|
||||
],
|
||||
"children": [
|
||||
"left-sleeve"
|
||||
]
|
||||
},
|
||||
"left-sleeve": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.35, 0.85, 0.35],
|
||||
"position": [0, 0, 0],
|
||||
"uvMap": [
|
||||
[[0.75, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.875, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.8125, 0.0625], [0.5, 0.0625]],
|
||||
[[0.875, 0.0625], [0.5, 0.0625]],
|
||||
[[60, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.8125, 0.0625], [0.5625, 0.1875]]
|
||||
]
|
||||
},
|
||||
"right-shoulder": {
|
||||
"type": "group",
|
||||
"position": [0.25, 0.25, 0],
|
||||
"children": [
|
||||
"right-arm"
|
||||
]
|
||||
},
|
||||
"right-arm": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.25, 0.75, 0.25],
|
||||
"position": [0.125, -0.25, 0],
|
||||
"uvMap": [
|
||||
[[0.625, 0.0625], [0.3125, 0.1875]],
|
||||
[[0.75, 0.0625], [0.3125, 0.1875]],
|
||||
[[0.6875, 0.0625], [0.25, 0.0625]],
|
||||
[[0.75, 0.0625], [0.25, 0.0625]],
|
||||
[[0.8125, 0.0625], [0.3125, 0.1875]],
|
||||
[[0.6875, 0.0625], [0.3125, 0.1875]]
|
||||
],
|
||||
"children": [
|
||||
"right-sleeve"
|
||||
]
|
||||
},
|
||||
"right-sleeve": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.35, 0.85, 0.35],
|
||||
"position": [0, 0, 0],
|
||||
"uvMap": [
|
||||
[[0.625, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.75, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.6875, 0.0625], [0.5, 0.0625]],
|
||||
[[0.75, 0.0625], [0.5, 0.0625]],
|
||||
[[0.8125, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.6875, 0.0625], [0.5625, 0.1875]]
|
||||
]
|
||||
},
|
||||
"left-pelvis": {
|
||||
"type": "group",
|
||||
"position": [-0.125, -0.375, 0],
|
||||
"children": [
|
||||
"left-leg"
|
||||
]
|
||||
},
|
||||
"left-leg": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.25, 0.75, 0.25],
|
||||
"position": [0, -0.375, 0],
|
||||
"uvMap": [
|
||||
[[0.25, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.375, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.3125, 0.0625], [0.75, 0.0625]],
|
||||
[[0.375, 0.0625], [0.75, 0.0625]],
|
||||
[[0.4375, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.3125, 0.0625], [0.8125, 0.1875]]
|
||||
],
|
||||
"children": [
|
||||
"left-leg-sleeve"
|
||||
]
|
||||
},
|
||||
"left-leg-sleeve": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.35, 0.85, 0.35],
|
||||
"position": [0, 0, 0],
|
||||
"uvMap": [
|
||||
[[0, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.125, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.0625, 0.0625], [0.75, 0.0625]],
|
||||
[[0.125, 0.0625], [0.75, 0.0625]],
|
||||
[[0.1875, 0.0625], [0.8125, 0.1875]],
|
||||
[[0.0625, 0.0625], [0.8125, 0.1875]]
|
||||
]
|
||||
},
|
||||
"right-pelvis": {
|
||||
"type": "group",
|
||||
"position": [0.125, -0.375, 0],
|
||||
"children": [
|
||||
"right-leg"
|
||||
]
|
||||
},
|
||||
"right-leg": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.25, 0.75, 0.25],
|
||||
"position": [0, -0.375, 0],
|
||||
"uvMap": [
|
||||
[[0, 0.0625], [0.3125, 0.1875]],
|
||||
[[0.125, 0.0625], [0.3125, 0.1875]],
|
||||
[[0.0625, 0.0625], [0.25, 0.0625]],
|
||||
[[0.125, 0.0625], [0.25, 0.0625]],
|
||||
[[0.1875, 0.0625], [0.3125, 0.1875]],
|
||||
[[0.0625, 0.0625], [0.3125, 0.1875]]
|
||||
],
|
||||
"children": [
|
||||
"right-leg-sleeve"
|
||||
]
|
||||
},
|
||||
"right-leg-sleeve": {
|
||||
"type": "geometry",
|
||||
"geometry": [0.35, 0.85, 0.35],
|
||||
"position": [0, 0, 0],
|
||||
"uvMap": [
|
||||
[[0, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.125, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.0625, 0.0625], [0.5, 0.0625]],
|
||||
[[0.125, 0.0625], [0.5, 0.0625]],
|
||||
[[0.1875, 0.0625], [0.5625, 0.1875]],
|
||||
[[0.0625, 0.0625], [0.5625, 0.1875]]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
54
data/resources/XVoxel/pack.json
Normal file
54
data/resources/XVoxel/pack.json
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "OpenVoxelProject",
|
||||
"description": "OpenVoxelProject's base resources",
|
||||
"textures": {
|
||||
"block-atlas": {
|
||||
"path": "textures/block-atlas.png",
|
||||
"size": [64, 64],
|
||||
"totalSize": [512, 512]
|
||||
},
|
||||
"grass": {
|
||||
"texture": "block-atlas",
|
||||
"sided": true,
|
||||
"sideMaps": [
|
||||
[3],
|
||||
[0, 1, 4, 5],
|
||||
[2]
|
||||
],
|
||||
"positions": [
|
||||
[0, 0],
|
||||
[64, 0],
|
||||
[128, 0]
|
||||
],
|
||||
"sizes": [
|
||||
[64, 64],
|
||||
[64, 64],
|
||||
[64, 64]
|
||||
]
|
||||
},
|
||||
"dirt": {
|
||||
"texture": "block-atlas",
|
||||
"position": [128, 0],
|
||||
"size": [64, 64]
|
||||
},
|
||||
"stone": {
|
||||
"texture": "block-atlas",
|
||||
"position": [192, 0],
|
||||
"size": [64, 64]
|
||||
},
|
||||
"glitch": {
|
||||
"texture": "block-atlas",
|
||||
"position": [256, 0],
|
||||
"size": [64, 64]
|
||||
},
|
||||
"character": {
|
||||
"path": "textures/character.png",
|
||||
"totalSize": [256, 256]
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"character": {
|
||||
"path": "models/character.json"
|
||||
}
|
||||
}
|
||||
}
|
BIN
data/resources/XVoxel/textures/block-atlas.png
Normal file
BIN
data/resources/XVoxel/textures/block-atlas.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
BIN
data/resources/XVoxel/textures/character.png
Normal file
BIN
data/resources/XVoxel/textures/character.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
32
data/strings/en-US.json
Normal file
32
data/strings/en-US.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"menu.main.play.label": "Play",
|
||||
"menu.main.settings.label": "Settings",
|
||||
"menu.main.quit.label": "Quit",
|
||||
"menu.play.singleplayer.label": "Singleplayer",
|
||||
"menu.play.multiplayer.label": "Multiplayer",
|
||||
"play.singleplayer.worldnameinput.label": "World name",
|
||||
"play.singleplayer.worldnameinput.placeholder": "Enter a world name here. ",
|
||||
"play.singleplayer.newgamebutton.label": "New game",
|
||||
"play.singleplayer.loadgamebutton.label": "Load game",
|
||||
"play.singleplayer.openworld.label": "Load world \"${WORLD_NAME}\"",
|
||||
"play.multiplayer.serveraddressinput.label": "Server address",
|
||||
"play.multiplayer.serveraddressinput.placeholder": "Enter a server address here. ",
|
||||
"play.multiplayer.serverconnectbutton.label": "Connect",
|
||||
"play.multiplayer.loadmatrixworldsbutton.label": "Load Matrix worlds",
|
||||
"menu.settings.user.label": "User",
|
||||
"menu.settings.video.label": "Video",
|
||||
"menu.settings.audio.label": "Audio",
|
||||
"menu.settings.input.label": "Input",
|
||||
"settings.user.username.label": "Username",
|
||||
"settings.user.username.placeholder": "Enter your username here. ",
|
||||
"settings.user.login.label": "Log in",
|
||||
"settings.login.homeserver-url.label": "Homeserver URL",
|
||||
"settings.login.mxid.label": "MXID (Matrix ID)",
|
||||
"settings.login.mxid.placeholder": "@user:domain.tld",
|
||||
"settings.login.password.label": "Password",
|
||||
"settings.login.password.placeholder": "T0p S3cr3t",
|
||||
"settings.video.fieldofview.label": "Field of view",
|
||||
"settings.video.fieldofview.text": "${ANGLE}${UNIT}",
|
||||
"settings.audio.mastervolume.label": "Master volume",
|
||||
"settings.audio.mastervolume.text": "${VOLUME}${UNIT}"
|
||||
}
|
32
data/strings/fr.json
Normal file
32
data/strings/fr.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"menu.main.play.label": "Jouer",
|
||||
"menu.main.settings.label": "Paramètres",
|
||||
"menu.main.quit.label": "Quitter",
|
||||
"menu.play.singleplayer.label": "Solo",
|
||||
"menu.play.multiplayer.label": "Multijoueur",
|
||||
"play.singleplayer.worldnameinput.label": "Nom du monde",
|
||||
"play.singleplayer.worldnameinput.placeholder": "Entrez un nom de monde ici. ",
|
||||
"play.singleplayer.newgamebutton.label": "Nouvelle partie",
|
||||
"play.singleplayer.loadgamebutton.label": "Charger une partie",
|
||||
"play.singleplayer.openworld.label": "Charger le monde \"${WORLD_NAME}\"",
|
||||
"play.multiplayer.serveraddressinput.label": "Adresse du serveur",
|
||||
"play.multiplayer.serveraddressinput.placeholder": "Entrez une adresse de serveur ici. ",
|
||||
"play.multiplayer.serverconnectbutton.label": "Se connecter",
|
||||
"play.multiplayer.loadmatrixworldsbutton.label": "Charger les mondes Matrix",
|
||||
"menu.settings.user.label": "Utilisateur",
|
||||
"menu.settings.video.label": "Vidéo",
|
||||
"menu.settings.audio.label": "Audio",
|
||||
"menu.settings.input.label": "Entrée",
|
||||
"settings.user.username.label": "Nom d'utilisateur",
|
||||
"settings.user.username.placeholder": "Entrez votre nom d'utilisateur ici. ",
|
||||
"settings.user.login.label": "Se connecter",
|
||||
"settings.login.homeserver-url.label": "URL de votre serveur",
|
||||
"settings.login.mxid.label": "MXID (Identifiant Matrix)",
|
||||
"settings.login.mxid.placeholder": "@utilisateur:domaine.tld",
|
||||
"settings.login.password.label": "Mot de passe",
|
||||
"settings.login.password.placeholder": "T0p S3cr3t",
|
||||
"settings.video.fieldofview.label": "Champ de vision",
|
||||
"settings.video.fieldofview.text": "${ANGLE}${UNIT}",
|
||||
"settings.audio.mastervolume.label": "Volume global",
|
||||
"settings.audio.mastervolume.text": "${VOLUME}${UNIT}"
|
||||
}
|
488
game.js
Normal file
488
game.js
Normal file
@ -0,0 +1,488 @@
|
||||
const loaderData = {
|
||||
"utils": {
|
||||
"type": "global",
|
||||
"source": "./lib/utils.js",
|
||||
"loadAs": "utils",
|
||||
"dependsOn": []
|
||||
},
|
||||
"three": {
|
||||
"type": "global",
|
||||
"source": "./lib/three.js",
|
||||
"loadAs": "three",
|
||||
"dependsOn": []
|
||||
},
|
||||
/*"cannon": {
|
||||
"type": "global",
|
||||
"source": "./lib/cannon-es.js",
|
||||
"loadAs": "cannon",
|
||||
"dependsOn": []
|
||||
},*/
|
||||
"fflate": {
|
||||
"type": "global",
|
||||
"source": "./lib/fflate.js",
|
||||
"loadAs": "fflate",
|
||||
"dependsOn": []
|
||||
},
|
||||
"olm": {
|
||||
"type": "global",
|
||||
"source": "./lib/olm.js",
|
||||
"loadAs": "olm",
|
||||
"dependsOn": []
|
||||
},
|
||||
"matrix": {
|
||||
"type": "global",
|
||||
"source": "./lib/browser-matrix.min.js",
|
||||
"loadAs": "matrix",
|
||||
"dependsOn": ["olm"]
|
||||
},
|
||||
"peer": {
|
||||
"type": "global",
|
||||
"source": "./lib/peer.js",
|
||||
"loadAs": "peer",
|
||||
"dependsOn": []
|
||||
},
|
||||
"gamecore": {
|
||||
"type": "global",
|
||||
"source": "./core.js",
|
||||
"loadAs": "gamecore",
|
||||
"dependsOn": ["utils"]
|
||||
},
|
||||
"locales": {
|
||||
"type": "global",
|
||||
"source": "./lib/locales.js",
|
||||
"loadAs": "locales",
|
||||
"dependsOn": []
|
||||
},
|
||||
"menu": {
|
||||
"type": "global",
|
||||
"source": "./menu.js",
|
||||
"loadAs": "menu",
|
||||
"dependsOn": ["locales"]
|
||||
}
|
||||
};
|
||||
|
||||
const throwError = window.throwError = function (err) {
|
||||
alert(err + "\n" + err.stack);
|
||||
throw err;
|
||||
};
|
||||
|
||||
var onLoadingFinished = function (modules) {
|
||||
var initPromises = {};
|
||||
var promiseReturners = {};
|
||||
|
||||
initPromises["render"] = new Promise(function (resolve, reject) {
|
||||
promiseReturners["render"] = {
|
||||
resolve,
|
||||
reject
|
||||
};
|
||||
});
|
||||
|
||||
initPromises["input"] = new Promise(function (resolve, reject) {
|
||||
promiseReturners["input"] = {
|
||||
resolve,
|
||||
reject
|
||||
};
|
||||
});
|
||||
|
||||
core.on("render-init", function () {
|
||||
promiseReturners["render"].resolve();
|
||||
|
||||
fetch("./data/resources/XVoxel.zip").then(function (response) {
|
||||
if (response.status != 200) return throwError(new Error("ENOENT"));
|
||||
|
||||
response.arrayBuffer().then(function (arrayBuffer) {
|
||||
core.modules["resources"].ResourcePack.loadFromZIP(arrayBuffer).then(function (pack) {
|
||||
window.resourcePacks.push(pack);
|
||||
|
||||
|
||||
}).catch(throwError);
|
||||
}).catch(throwError);
|
||||
}).catch(throwError);
|
||||
});
|
||||
|
||||
core.on("input-init", function () {
|
||||
promiseReturners["input"].resolve();
|
||||
});
|
||||
|
||||
Promise.all(Object.values(initPromises)).then(function () {
|
||||
addPlayer(0);
|
||||
});
|
||||
};
|
||||
|
||||
window.onload = function (event) {
|
||||
renderersContainer = document.querySelector("#renderers");
|
||||
var librariesToLoad = Object.keys(loaderData);
|
||||
|
||||
var libraryLoaders = [];
|
||||
|
||||
for (var l = 0; l < librariesToLoad.length; l++) {
|
||||
libraryLoaders.push(
|
||||
loadFromMeta(librariesToLoad[l], loaderData[librariesToLoad[l]])
|
||||
);
|
||||
}
|
||||
|
||||
Promise.all(libraryLoaders).then(function (libraries) {
|
||||
core = window.core = new window.gamecore.GameCore();
|
||||
|
||||
fetch("./data/strings/" + window.currentLanguage + ".json").then(function (response) {
|
||||
if (response.status != 200) return throwError(new Error("ENOENT"));
|
||||
|
||||
response.text().then(function (text) {
|
||||
window.locales.loadFromJSON(window.currentLanguage, JSON.parse(text));
|
||||
|
||||
menu.makeMenu();
|
||||
}).catch(throwError);
|
||||
}).catch(throwError);
|
||||
|
||||
onLoadingFinished(core.modules);
|
||||
|
||||
core.init(gamecore.loadData.modules).then(function (gameCore) {
|
||||
for (var moduleName in core.modules) {
|
||||
if (core.modules.hasOwnProperty(moduleName)) {
|
||||
var thisModule = core.modules[moduleName];
|
||||
|
||||
if ((typeof thisModule) != "object") continue;
|
||||
|
||||
if ("menus" in thisModule) {
|
||||
for (var menuName in thisModule.menus) {
|
||||
if (thisModule.menus.hasOwnProperty(menuName)) {
|
||||
if (!(menuName in menu.menuData)) {
|
||||
menu.menuData[menuName] = thisModule.menus[menuName];
|
||||
} else {
|
||||
var thisMenu = thisModule.menus[menuName];
|
||||
|
||||
if (!("elements" in thisMenu)) continue;
|
||||
|
||||
for (var e = 0; e < thisMenu.elements.length; e++) {
|
||||
menu.menuData[menuName].elements.push(thisMenu.elements[e]);
|
||||
}
|
||||
}
|
||||
|
||||
menu.menus[menuName] = menu.constructMenu(menuName, menu.menuData[menuName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.menu.showMenu("main", 0);
|
||||
}).catch(throwError);
|
||||
}).catch(throwError);
|
||||
};
|
||||
|
||||
var loadFromMeta = function (name, metadata) {
|
||||
return new Promise((function (resolve, reject) {
|
||||
var dependencies = [];
|
||||
|
||||
if (metadata.dependsOn) {
|
||||
for (var d = 0; d < metadata.dependsOn.length; d++) {
|
||||
var dependencyName = metadata.dependsOn[d];
|
||||
var dependency = loaderData[dependencyName];
|
||||
|
||||
if (!loadings[dependencyName]) {
|
||||
loadings[dependencyName] = loadFromMeta(dependencyName, dependency);
|
||||
}
|
||||
dependencies.push(loadings[dependencyName]);
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(dependencies).then((function (deps) {
|
||||
loadings[name] = load(metadata.source).then(function (mod) {
|
||||
window[metadata.loadAs || name] = mod;
|
||||
|
||||
resolve(mod);
|
||||
}).catch(throwError);
|
||||
}).bind(name)).catch(throwError);
|
||||
}).bind(name));
|
||||
};
|
||||
|
||||
var render = window.render = function (instanceIndex) {
|
||||
if (instanceWorlds[instanceIndex]) {
|
||||
renderers[instanceIndex].render(worlds[instanceWorlds[instanceIndex]], cameras[instanceIndex]);
|
||||
}
|
||||
};
|
||||
|
||||
var createWorld = window.createWorld = function (name, generator = "flat", options, generateInitialChunks = true) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
window.worlds[name] = new core.modules["world"].World({
|
||||
"generator": generator
|
||||
});
|
||||
|
||||
if (!generateInitialChunks) return resolve(window.worlds[name]);
|
||||
|
||||
var min = [-4, 0, -4];
|
||||
var max = [4, 8, 4];
|
||||
|
||||
var positions = [];
|
||||
|
||||
for (var x = min[0]; x < max[0]; x++) {
|
||||
for (var z = min[2]; z < max[2]; z++) {
|
||||
for (var y = min[1]; y < max[1]; y++) {
|
||||
positions.push([x, y, z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var chunkGenerators = [];
|
||||
|
||||
genNext = function (pos, p) {
|
||||
chunkGenerators.push(
|
||||
worlds[name].generateChunk(pos[p])
|
||||
.then(function (chunk) {
|
||||
if (pos[p + 1]) return genNext(pos, p + 1);
|
||||
|
||||
Promise.all(chunkGenerators).then(function (chunks) {
|
||||
resolve(worlds[name]);
|
||||
}).catch(throwError);
|
||||
})
|
||||
.catch(throwError)
|
||||
);
|
||||
};
|
||||
|
||||
genNext(positions, 0);
|
||||
});
|
||||
};
|
||||
|
||||
var startGame = window.startGame = function (instance, worldName) {
|
||||
instanceWorlds[instance] = worldName;
|
||||
renderers[instance].setAnimationLoop(render.bind(window, instance));
|
||||
|
||||
inputs[instance].grab();
|
||||
|
||||
var chunkSize = window.worlds[worldName].chunkSize;
|
||||
|
||||
var positions = [];
|
||||
|
||||
worlds[worldName].chunks.forEach(function (chunk, c) {
|
||||
positions.push(
|
||||
c.split(":")
|
||||
.map(coord => parseInt(coord))
|
||||
);
|
||||
});
|
||||
|
||||
if (positions.length > 0) {
|
||||
constructNext = function (pos, p) {
|
||||
worlds[worldName].constructChunk(pos[p]).then(function (chunk) {
|
||||
worlds[worldName].addChunk(chunk);
|
||||
|
||||
if (pos[p + 1]) return constructNext(pos, p + 1);
|
||||
}).catch(throwError);
|
||||
};
|
||||
|
||||
constructNext(positions, 0);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("resize", function (event) {
|
||||
reorganizeRenderers(false);
|
||||
|
||||
for (var r = 0; r < renderers.length; r++) {
|
||||
var rdr = renderers[r];
|
||||
var rdrDOM = rdr.domElement;
|
||||
|
||||
var cam = cameras[r];
|
||||
|
||||
rdr.setSize(rdrDOM.clientWidth, rdrDOM.clientHeight);
|
||||
|
||||
cam.aspect = rdrDOM.clientWidth / rdrDOM.clientHeight;
|
||||
cam.updateProjectionMatrix();
|
||||
}
|
||||
});
|
||||
|
||||
var reorganizeRenderers = function (remakeLayout = true) {
|
||||
var rows = [];
|
||||
var rowAmount = Math.round(Math.sqrt(renderers.length));
|
||||
|
||||
if (remakeLayout) {
|
||||
for (var r = renderersContainer.childElementCount - 1; r >= 0; r--) {
|
||||
renderersContainer.children.item(r).remove();
|
||||
}
|
||||
|
||||
for (var r = 0; r < rowAmount; r++) {
|
||||
rows[r] = document.createElement("div");
|
||||
|
||||
rows[r].style.width = "100%";
|
||||
rows[r].style.height = "calc(100% / " + rowAmount + ")";
|
||||
|
||||
renderersContainer.append(rows[r]);
|
||||
}
|
||||
|
||||
for (var r = 0; r < renderers.length; r++) {
|
||||
rows[Math.floor((r / renderers.length) * rowAmount)].append(renderers[r].domElement);
|
||||
}
|
||||
} else {
|
||||
for (var r = renderersContainer.childElementCount - 1; r >= 0; r--) {
|
||||
rows[r] = renderersContainer.children.item(r);
|
||||
}
|
||||
}
|
||||
|
||||
for (var r = 0; r < rowAmount; r++) {
|
||||
var row = rows[r];
|
||||
|
||||
for (var rd = 0; rd < row.childElementCount; rd++) {
|
||||
row.children[rd].style.width = "calc(100% / " + row.childElementCount + ")";
|
||||
row.children[rd].style.height = "100%";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var addPlayer = function (instance, controller) {
|
||||
renderers[instance] = new core.modules["render"].Renderer({
|
||||
"preserveDrawingBuffer": true,
|
||||
"autoResize": true
|
||||
});
|
||||
|
||||
var instanceDOMElement = renderers[instance].domElement;
|
||||
|
||||
reorganizeRenderers();
|
||||
|
||||
for (var r = 0; r < renderers.length; r++) {
|
||||
var rdr = renderers[r];
|
||||
var rdrDOM = rdr.domElement;
|
||||
|
||||
rdr.setSize(rdrDOM.clientWidth, rdrDOM.clientHeight, false);
|
||||
}
|
||||
|
||||
cameras[instance] = new core.modules["render"].PerspectiveCamera(130, instanceDOMElement.width / instanceDOMElement.height, 0.0005, 8192);
|
||||
|
||||
if (controller instanceof core.modules["input"].Controller) {
|
||||
inputs[instance] = controller;
|
||||
inputs[instance].domElement = instanceDOMElement;
|
||||
} else {
|
||||
inputs[instance] = new core.modules["input"].Controller("desktop", {
|
||||
"domElement": instanceDOMElement
|
||||
});
|
||||
}
|
||||
|
||||
renderers[instance].setAnimationLoop(render.bind(window, instance));
|
||||
};
|
||||
|
||||
var quitGame = window.quitGame = function (instance) {
|
||||
|
||||
};
|
||||
|
||||
var closeGame = window.closeGame = function () {
|
||||
window.close();
|
||||
};
|
||||
|
||||
var openSave = window.openSave = function (archive) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
window.fflate.unzip(new Uint8Array(archive), {}, function (error, data) {
|
||||
if (error) return reject(error);
|
||||
|
||||
var loadedWorlds = {};
|
||||
|
||||
for (var filePath in data) {
|
||||
if (data.hasOwnProperty(filePath)) {
|
||||
var matches = filePath.match(/([^\/]+)\/meta\.json/);
|
||||
|
||||
if (!matches) continue;
|
||||
if (matches[0] !== filePath) continue;
|
||||
if (!matches[1]) continue;
|
||||
|
||||
var worldFolderName = matches[1];
|
||||
|
||||
let worldMeta;
|
||||
try {
|
||||
worldMeta = JSON.parse(window.fflate.strFromU8(data["" + worldFolderName + "/meta.json"]));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
continue;
|
||||
}
|
||||
|
||||
var worldName = worldMeta.name;
|
||||
|
||||
loadedWorlds[worldName] = new core.modules["world"].World({
|
||||
"generator": worldMeta.generator
|
||||
});
|
||||
|
||||
var chunkFileNameMatcher = new RegExp(worldFolderName + "\/chunks\/(-?[0-9]+:-?[0-9]+:-?[0-9]+)\.json");
|
||||
|
||||
for (var fileName in data) {
|
||||
if (data.hasOwnProperty(fileName)) {
|
||||
var nameMatches = fileName.match(chunkFileNameMatcher);
|
||||
|
||||
if (!nameMatches) continue;
|
||||
if (nameMatches[0] !== fileName) continue;
|
||||
if (!nameMatches[1]) continue;
|
||||
|
||||
var chunkFileName = nameMatches[1];
|
||||
|
||||
let chunkData;
|
||||
try {
|
||||
chunkData = JSON.parse(window.fflate.strFromU8(data[worldFolderName + "/chunks/" + chunkFileName + ".json"]));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
continue;
|
||||
}
|
||||
|
||||
var thisChunk = new core.modules["world"].Chunk(chunkData.size, loadedWorlds[worldName]);
|
||||
|
||||
for (var b = 0; b < chunkData.blocks.length; b++) {
|
||||
thisChunk.blocks[b] = chunkData.blocks[b];
|
||||
}
|
||||
|
||||
var chunkPosition = chunkFileName.split(":").map(function (c) {
|
||||
return parseInt(c);
|
||||
});
|
||||
|
||||
loadedWorlds[worldName].setChunk(thisChunk, chunkPosition);
|
||||
loadedWorlds[worldName].add(thisChunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve(loadedWorlds);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var makeSave = window.makeSave = function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var files = {};
|
||||
|
||||
for (var world in worlds) {
|
||||
if (worlds.hasOwnProperty(world)) {
|
||||
var thisWorld = worlds[world].toJSON();
|
||||
|
||||
var worldMeta = {
|
||||
"name": world,
|
||||
"generator": thisWorld.generator
|
||||
};
|
||||
|
||||
files[world + "/meta.json"] = fflate.strToU8(JSON.stringify(worldMeta, null, "\t"));
|
||||
|
||||
for (var chunk in thisWorld.chunks) {
|
||||
if (thisWorld.chunks.hasOwnProperty(chunk)) {
|
||||
var thisChunk = thisWorld.chunks[chunk];
|
||||
|
||||
files[world + "/chunks/" + chunk + ".json"] = fflate.strToU8(JSON.stringify(thisChunk, null, "\t"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.fflate.zip(files, function (error, archive) {
|
||||
if (error) return reject(error);
|
||||
resolve(archive);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
let core;
|
||||
|
||||
var currentLanguage = window.currentLanguage = "en-US";
|
||||
|
||||
var instanceWorlds = window.instanceWorlds = [];
|
||||
|
||||
var renderers = window.renderers = [];
|
||||
var cameras = window.cameras = [];
|
||||
var inputs = window.inputs = [];
|
||||
|
||||
var loadings = {};
|
||||
|
||||
let resourcePacks = window.resourcePacks = [];
|
||||
let worlds = window.worlds = {};
|
||||
|
||||
let renderersContainer;
|
59
index.html
Normal file
59
index.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta charset="utf-8">
|
||||
<title>XVoxel</title>
|
||||
<link rel="stylesheet" href="./assets/stylesheets/game.css">
|
||||
<script src="./lib/loader.js" charset="utf-8"></script>
|
||||
<script src="./game.js" charset="utf-8"></script>
|
||||
|
||||
<meta name="application-name" content="XVoxel">
|
||||
<link rel="icon" type="image/png" href="./assets/images/xvoxel.png">
|
||||
<meta name="theme-color" content="#FF1493">
|
||||
<meta name="msapplication-TileColor" content="#FF1493">
|
||||
<meta name="apple-mobile-web-app-title" content="XVoxel">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="An open-source JavaScript voxel game and engine. ">
|
||||
|
||||
<meta property="og:title" content="XVoxel">
|
||||
<meta property="og:description" content="An open-source JavaScript voxel game and engine. ">
|
||||
<meta property="og:image" content="./assets/images/xvoxel.png">
|
||||
</head>
|
||||
<body>
|
||||
<header id="header">
|
||||
<h1 id="title">XVoxel</h1>
|
||||
<div id="actionbuttoncontainer">
|
||||
|
||||
</div>
|
||||
</header>
|
||||
<div id="gui">
|
||||
<div id="debug" style="display: none;">
|
||||
<span>Render : <p id="debugfps">NaN FPS</p> / <p id="debugms">NaN ms</p></span>
|
||||
</div>
|
||||
<div id="touchcontrols" style="display: none;">
|
||||
<div id="dpad">
|
||||
|
||||
</div>
|
||||
<div id="secpad">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<img id="crosshair" alt="crosshair" class="initially-hidden">
|
||||
</div>
|
||||
<div id="renderers" class="splitview">
|
||||
|
||||
</div>
|
||||
<div id="menus">
|
||||
|
||||
</div>
|
||||
<div id="loadingscreen" style="display: none;">
|
||||
<div id="loadingbar" class="progressbar">
|
||||
<p id="loadingtext">Loading...</p>
|
||||
<div id="loadingbarprogress" class="progress" style="width: 0%;">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
953
lib/ammo.js
Normal file
953
lib/ammo.js
Normal file
File diff suppressed because one or more lines are too long
18
lib/browser-matrix.min.js
vendored
Normal file
18
lib/browser-matrix.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
13009
lib/cannon-es.js
Normal file
13009
lib/cannon-es.js
Normal file
File diff suppressed because it is too large
Load Diff
1
lib/fflate.js
Normal file
1
lib/fflate.js
Normal file
File diff suppressed because one or more lines are too long
4398
lib/gltf-loader.js
Normal file
4398
lib/gltf-loader.js
Normal file
File diff suppressed because it is too large
Load Diff
74
lib/improved-noise.js
Normal file
74
lib/improved-noise.js
Normal file
@ -0,0 +1,74 @@
|
||||
// http://mrl.nyu.edu/~perlin/noise/
|
||||
|
||||
var ImprovedNoise = function () {
|
||||
|
||||
var p = [ 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10,
|
||||
23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87,
|
||||
174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211,
|
||||
133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208,
|
||||
89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5,
|
||||
202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119,
|
||||
248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232,
|
||||
178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249,
|
||||
14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205,
|
||||
93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 ];
|
||||
|
||||
for ( var i = 0; i < 256; i ++ ) {
|
||||
|
||||
p[ 256 + i ] = p[ i ];
|
||||
|
||||
}
|
||||
|
||||
function fade( t ) {
|
||||
|
||||
return t * t * t * ( t * ( t * 6 - 15 ) + 10 );
|
||||
|
||||
}
|
||||
|
||||
function lerp( t, a, b ) {
|
||||
|
||||
return a + t * ( b - a );
|
||||
|
||||
}
|
||||
|
||||
function grad( hash, x, y, z ) {
|
||||
|
||||
var h = hash & 15;
|
||||
var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
|
||||
return ( ( h & 1 ) == 0 ? u : - u ) + ( ( h & 2 ) == 0 ? v : - v );
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
noise: function ( x, y, z ) {
|
||||
|
||||
var floorX = Math.floor( x ), floorY = Math.floor( y ), floorZ = Math.floor( z );
|
||||
|
||||
var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255;
|
||||
|
||||
x -= floorX;
|
||||
y -= floorY;
|
||||
z -= floorZ;
|
||||
|
||||
var xMinus1 = x - 1, yMinus1 = y - 1, zMinus1 = z - 1;
|
||||
|
||||
var u = fade( x ), v = fade( y ), w = fade( z );
|
||||
|
||||
var A = p[ X ] + Y, AA = p[ A ] + Z, AB = p[ A + 1 ] + Z, B = p[ X + 1 ] + Y, BA = p[ B ] + Z, BB = p[ B + 1 ] + Z;
|
||||
|
||||
return lerp( w, lerp( v, lerp( u, grad( p[ AA ], x, y, z ),
|
||||
grad( p[ BA ], xMinus1, y, z ) ),
|
||||
lerp( u, grad( p[ AB ], x, yMinus1, z ),
|
||||
grad( p[ BB ], xMinus1, yMinus1, z ) ) ),
|
||||
lerp( v, lerp( u, grad( p[ AA + 1 ], x, y, zMinus1 ),
|
||||
grad( p[ BA + 1 ], xMinus1, y, zMinus1 ) ),
|
||||
lerp( u, grad( p[ AB + 1 ], x, yMinus1, zMinus1 ),
|
||||
grad( p[ BB + 1 ], xMinus1, yMinus1, zMinus1 ) ) ) );
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// export { ImprovedNoise };
|
32
lib/loader.js
Normal file
32
lib/loader.js
Normal file
@ -0,0 +1,32 @@
|
||||
if (!window.load) window.load = function (moduleName) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
fetch(moduleName).then(function (response) {
|
||||
if (response.status !== 200) return reject(new Error("Status code is not 200. "));
|
||||
|
||||
response.text().then(function (moduleContents) {
|
||||
try {
|
||||
var moduleObject = {
|
||||
"exports": {}
|
||||
};
|
||||
|
||||
var BoundFunction = Function.prototype.bind.apply(Function, [moduleObject]);
|
||||
var moduleFunction = new BoundFunction("global", "window", "module", "exports",
|
||||
"return eval(" + JSON.stringify(
|
||||
moduleContents
|
||||
+ "\n//# sourceURL=" + (new URL(moduleName, document.baseURI).href) + "\n"
|
||||
) + ");"
|
||||
).bind(moduleObject.exports);
|
||||
var result = moduleFunction.apply(window, [window, window, moduleObject, moduleObject.exports]);
|
||||
|
||||
resolve(moduleObject.exports);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}).catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
}).catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
32
lib/locales.js
Normal file
32
lib/locales.js
Normal file
@ -0,0 +1,32 @@
|
||||
module.exports = {
|
||||
"languages": {},
|
||||
"loadFromJSON": function (language, data) {
|
||||
if (!(language in module.exports.languages)) module.exports.languages[language] = {};
|
||||
|
||||
for (var dat in data) {
|
||||
if (data.hasOwnProperty(dat)) {
|
||||
module.exports.languages[language][dat] = data[dat];
|
||||
}
|
||||
}
|
||||
},
|
||||
"getRawString": function (language, stringName) {
|
||||
if (!(language in module.exports.languages)) return;
|
||||
if (!(stringName in module.exports.languages[language])) return;
|
||||
|
||||
return module.exports.languages[language][stringName];
|
||||
},
|
||||
"getFormattedString": function (language, stringName, variables) {
|
||||
if (!(language in module.exports.languages)) return;
|
||||
if (!(stringName in module.exports.languages[language])) return;
|
||||
|
||||
var formattedString = module.exports.languages[language][stringName];
|
||||
|
||||
for (var variable in variables) {
|
||||
if (variables.hasOwnProperty(variable)) {
|
||||
formattedString = formattedString.replaceAll("${" + variable + "}", variables[variable]);
|
||||
}
|
||||
}
|
||||
|
||||
return formattedString;
|
||||
}
|
||||
};
|
153
lib/olm.js
Normal file
153
lib/olm.js
Normal file
@ -0,0 +1,153 @@
|
||||
var Olm = (function() {
|
||||
var olm_exports = {};
|
||||
var onInitSuccess;
|
||||
var onInitFail;
|
||||
|
||||
|
||||
var Module = (function() {
|
||||
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
|
||||
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
|
||||
return (
|
||||
function(Module) {
|
||||
Module = Module || {};
|
||||
|
||||
|
||||
var a;a||(a=typeof Module !== 'undefined' ? Module : {});var aa;a.ready=new Promise(function(b){aa=b});var g;if("undefined"!==typeof window)g=function(b){window.crypto.getRandomValues(b)};else if(module.exports){var ba=require("crypto");g=function(b){var c=ba.randomBytes(b.length);b.set(c)};process=global.process}else throw Error("Cannot find global to attach library to");if("undefined"!==typeof OLM_OPTIONS)for(var ca in OLM_OPTIONS)OLM_OPTIONS.hasOwnProperty(ca)&&(a[ca]=OLM_OPTIONS[ca]);
|
||||
a.onRuntimeInitialized=function(){h=a._olm_error();olm_exports.PRIVATE_KEY_LENGTH=a._olm_pk_private_key_length();onInitSuccess&&onInitSuccess()};a.onAbort=function(b){onInitFail&&onInitFail(b)};var da={},l;for(l in a)a.hasOwnProperty(l)&&(da[l]=a[l]);var ea=!1,m=!1,fa=!1,ia=!1;ea="object"===typeof window;m="function"===typeof importScripts;fa="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node;ia=!ea&&!fa&&!m;var n="",ja,ka,la,ma;
|
||||
if(fa)n=m?require("path").dirname(n)+"/":__dirname+"/",ja=function(b,c){la||(la=require("fs"));ma||(ma=require("path"));b=ma.normalize(b);return la.readFileSync(b,c?null:"utf8")},ka=function(b){b=ja(b,!0);b.buffer||(b=new Uint8Array(b));b.buffer||q("Assertion failed: undefined");return b},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),process.on("uncaughtException",function(b){throw b;}),process.on("unhandledRejection",q),a.inspect=function(){return"[Emscripten Module object]"};
|
||||
else if(ia)"undefined"!=typeof read&&(ja=function(b){return read(b)}),ka=function(b){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(b));b=read(b,"binary");"object"===typeof b||q("Assertion failed: undefined");return b},"undefined"!==typeof print&&("undefined"===typeof console&&(console={}),console.log=print,console.warn=console.error="undefined"!==typeof printErr?printErr:print);else if(ea||m)m?n=self.location.href:document.currentScript&&(n=document.currentScript.src),_scriptDir&&
|
||||
(n=_scriptDir),0!==n.indexOf("blob:")?n=n.substr(0,n.lastIndexOf("/")+1):n="",ja=function(b){var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},m&&(ka=function(b){var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType="arraybuffer";c.send(null);return new Uint8Array(c.response)});var na=a.print||console.log.bind(console),oa=a.printErr||console.warn.bind(console);for(l in da)da.hasOwnProperty(l)&&(a[l]=da[l]);da=null;var pa;a.wasmBinary&&(pa=a.wasmBinary);var noExitRuntime;
|
||||
a.noExitRuntime&&(noExitRuntime=a.noExitRuntime);"object"!==typeof WebAssembly&&q("no native wasm support detected");
|
||||
function r(b){var c="i8";"*"===c.charAt(c.length-1)&&(c="i32");switch(c){case "i1":t[b>>0]=0;break;case "i8":t[b>>0]=0;break;case "i16":qa[b>>1]=0;break;case "i32":u[b>>2]=0;break;case "i64":ra=[0,(w=0,1<=+sa(w)?0<w?(ta(+ua(w/4294967296),4294967295)|0)>>>0:~~+va((w-+(~~w>>>0))/4294967296)>>>0:0)];u[b>>2]=ra[0];u[b+4>>2]=ra[1];break;case "float":wa[b>>2]=0;break;case "double":xa[b>>3]=0;break;default:q("invalid type for setValue: "+c)}}
|
||||
function ya(b,c){c=c||"i8";"*"===c.charAt(c.length-1)&&(c="i32");switch(c){case "i1":return t[b>>0];case "i8":return t[b>>0];case "i16":return qa[b>>1];case "i32":return u[b>>2];case "i64":return u[b>>2];case "float":return wa[b>>2];case "double":return xa[b>>3];default:q("invalid type for getValue: "+c)}return null}var za,Aa=new WebAssembly.Table({initial:9,maximum:9,element:"anyfunc"}),Ba=!1,Ca="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;
|
||||
function x(b,c){if(b){var d=y,e=b+c;for(c=b;d[c]&&!(c>=e);)++c;if(16<c-b&&d.subarray&&Ca)b=Ca.decode(d.subarray(b,c));else{for(e="";b<c;){var f=d[b++];if(f&128){var k=d[b++]&63;if(192==(f&224))e+=String.fromCharCode((f&31)<<6|k);else{var p=d[b++]&63;f=224==(f&240)?(f&15)<<12|k<<6|p:(f&7)<<18|k<<12|p<<6|d[b++]&63;65536>f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}b=e}}else b="";return b}
|
||||
function z(b,c,d,e){if(!(0<e))return 0;var f=d;e=d+e-1;for(var k=0;k<b.length;++k){var p=b.charCodeAt(k);if(55296<=p&&57343>=p){var v=b.charCodeAt(++k);p=65536+((p&1023)<<10)|v&1023}if(127>=p){if(d>=e)break;c[d++]=p}else{if(2047>=p){if(d+1>=e)break;c[d++]=192|p>>6}else{if(65535>=p){if(d+2>=e)break;c[d++]=224|p>>12}else{if(d+3>=e)break;c[d++]=240|p>>18;c[d++]=128|p>>12&63}c[d++]=128|p>>6&63}c[d++]=128|p&63}}c[d]=0;return d-f}
|
||||
function A(b){for(var c=0,d=0;d<b.length;++d){var e=b.charCodeAt(d);55296<=e&&57343>=e&&(e=65536+((e&1023)<<10)|b.charCodeAt(++d)&1023);127>=e?++c:c=2047>=e?c+2:65535>=e?c+3:c+4}return c}function Da(b,c){for(var d=0;d<b.length;++d)t[c++>>0]=b.charCodeAt(d)}var Ea,t,y,qa,u,wa,xa,Ga=a.INITIAL_MEMORY||262144;a.wasmMemory?za=a.wasmMemory:za=new WebAssembly.Memory({initial:Ga/65536,maximum:Ga/65536});za&&(Ea=za.buffer);Ga=Ea.byteLength;var B=Ea;Ea=B;a.HEAP8=t=new Int8Array(B);a.HEAP16=qa=new Int16Array(B);
|
||||
a.HEAP32=u=new Int32Array(B);a.HEAPU8=y=new Uint8Array(B);a.HEAPU16=new Uint16Array(B);a.HEAPU32=new Uint32Array(B);a.HEAPF32=wa=new Float32Array(B);a.HEAPF64=xa=new Float64Array(B);u[9584]=104032;function Ha(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var d=c.Nb;"number"===typeof d?void 0===c.Mb?a.dynCall_v(d):a.dynCall_vi(d,c.Mb):d(void 0===c.Mb?null:c.Mb)}}}var Ia=[],Ja=[],Ka=[],La=[];function Ma(){var b=a.preRun.shift();Ia.unshift(b)}
|
||||
var sa=Math.abs,va=Math.ceil,ua=Math.floor,ta=Math.min,C=0,Na=null,Oa=null;a.preloadedImages={};a.preloadedAudios={};function q(b){if(a.onAbort)a.onAbort(b);na(b);oa(b);Ba=!0;throw new WebAssembly.RuntimeError("abort("+b+"). Build with -s ASSERTIONS=1 for more info.");}function Pa(b){var c=D;return String.prototype.startsWith?c.startsWith(b):0===c.indexOf(b)}function Qa(){return Pa("data:application/octet-stream;base64,")}var D="olm.wasm";if(!Qa()){var Ra=D;D=a.locateFile?a.locateFile(Ra,n):n+Ra}
|
||||
function Sa(){try{if(pa)return new Uint8Array(pa);if(ka)return ka(D);throw"both async and sync fetching of the wasm failed";}catch(b){q(b)}}function Ta(){return pa||!ea&&!m||"function"!==typeof fetch||Pa("file://")?new Promise(function(b){b(Sa())}):fetch(D,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+D+"'";return b.arrayBuffer()}).catch(function(){return Sa()})}var w,ra;Ja.push({Nb:function(){Ua()}});
|
||||
var Va={a:function(b,c,d){y.copyWithin(b,c,c+d)},b:function(){q("OOM")},memory:za,table:Aa};
|
||||
(function(){function b(f){a.asm=f.exports;C--;a.monitorRunDependencies&&a.monitorRunDependencies(C);0==C&&(null!==Na&&(clearInterval(Na),Na=null),Oa&&(f=Oa,Oa=null,f()))}function c(f){b(f.instance)}function d(f){return Ta().then(function(k){return WebAssembly.instantiate(k,e)}).then(f,function(k){oa("failed to asynchronously prepare wasm: "+k);q(k)})}var e={a:Va};C++;a.monitorRunDependencies&&a.monitorRunDependencies(C);if(a.instantiateWasm)try{return a.instantiateWasm(e,b)}catch(f){return oa("Module.instantiateWasm callback failed with error: "+
|
||||
f),!1}(function(){if(pa||"function"!==typeof WebAssembly.instantiateStreaming||Qa()||Pa("file://")||"function"!==typeof fetch)return d(c);fetch(D,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,e).then(c,function(k){oa("wasm streaming compile failed: "+k);oa("falling back to ArrayBuffer instantiation");return d(c)})})})();return{}})();var Ua=a.___wasm_call_ctors=function(){return(Ua=a.___wasm_call_ctors=a.asm.c).apply(null,arguments)};
|
||||
a._olm_pk_encryption_last_error=function(){return(a._olm_pk_encryption_last_error=a.asm.d).apply(null,arguments)};a._olm_pk_encryption_size=function(){return(a._olm_pk_encryption_size=a.asm.e).apply(null,arguments)};a._olm_pk_encryption=function(){return(a._olm_pk_encryption=a.asm.f).apply(null,arguments)};a._olm_clear_pk_encryption=function(){return(a._olm_clear_pk_encryption=a.asm.g).apply(null,arguments)};
|
||||
a._olm_pk_encryption_set_recipient_key=function(){return(a._olm_pk_encryption_set_recipient_key=a.asm.h).apply(null,arguments)};a._olm_pk_key_length=function(){return(a._olm_pk_key_length=a.asm.i).apply(null,arguments)};a._olm_pk_ciphertext_length=function(){return(a._olm_pk_ciphertext_length=a.asm.j).apply(null,arguments)};a._olm_pk_mac_length=function(){return(a._olm_pk_mac_length=a.asm.k).apply(null,arguments)};
|
||||
a._olm_pk_encrypt_random_length=function(){return(a._olm_pk_encrypt_random_length=a.asm.l).apply(null,arguments)};a._olm_pk_encrypt=function(){return(a._olm_pk_encrypt=a.asm.m).apply(null,arguments)};a._olm_pk_decryption_last_error=function(){return(a._olm_pk_decryption_last_error=a.asm.n).apply(null,arguments)};a._olm_pk_decryption_size=function(){return(a._olm_pk_decryption_size=a.asm.o).apply(null,arguments)};a._olm_pk_decryption=function(){return(a._olm_pk_decryption=a.asm.p).apply(null,arguments)};
|
||||
a._olm_clear_pk_decryption=function(){return(a._olm_clear_pk_decryption=a.asm.q).apply(null,arguments)};a._olm_pk_private_key_length=function(){return(a._olm_pk_private_key_length=a.asm.r).apply(null,arguments)};a._olm_pk_generate_key_random_length=function(){return(a._olm_pk_generate_key_random_length=a.asm.s).apply(null,arguments)};a._olm_pk_key_from_private=function(){return(a._olm_pk_key_from_private=a.asm.t).apply(null,arguments)};
|
||||
a._olm_pk_generate_key=function(){return(a._olm_pk_generate_key=a.asm.u).apply(null,arguments)};a._olm_pickle_pk_decryption_length=function(){return(a._olm_pickle_pk_decryption_length=a.asm.v).apply(null,arguments)};a._olm_pickle_pk_decryption=function(){return(a._olm_pickle_pk_decryption=a.asm.w).apply(null,arguments)};a._olm_unpickle_pk_decryption=function(){return(a._olm_unpickle_pk_decryption=a.asm.x).apply(null,arguments)};
|
||||
a._olm_pk_max_plaintext_length=function(){return(a._olm_pk_max_plaintext_length=a.asm.y).apply(null,arguments)};a._olm_pk_decrypt=function(){return(a._olm_pk_decrypt=a.asm.z).apply(null,arguments)};a._olm_pk_get_private_key=function(){return(a._olm_pk_get_private_key=a.asm.A).apply(null,arguments)};a._olm_pk_signing_size=function(){return(a._olm_pk_signing_size=a.asm.B).apply(null,arguments)};a._olm_pk_signing=function(){return(a._olm_pk_signing=a.asm.C).apply(null,arguments)};
|
||||
a._olm_pk_signing_last_error=function(){return(a._olm_pk_signing_last_error=a.asm.D).apply(null,arguments)};a._olm_clear_pk_signing=function(){return(a._olm_clear_pk_signing=a.asm.E).apply(null,arguments)};a._olm_pk_signing_seed_length=function(){return(a._olm_pk_signing_seed_length=a.asm.F).apply(null,arguments)};a._olm_pk_signing_public_key_length=function(){return(a._olm_pk_signing_public_key_length=a.asm.G).apply(null,arguments)};
|
||||
a._olm_pk_signing_key_from_seed=function(){return(a._olm_pk_signing_key_from_seed=a.asm.H).apply(null,arguments)};a._olm_pk_signature_length=function(){return(a._olm_pk_signature_length=a.asm.I).apply(null,arguments)};a._olm_pk_sign=function(){return(a._olm_pk_sign=a.asm.J).apply(null,arguments)};a._olm_get_library_version=function(){return(a._olm_get_library_version=a.asm.K).apply(null,arguments)};a._olm_error=function(){return(a._olm_error=a.asm.L).apply(null,arguments)};
|
||||
a._olm_account_last_error=function(){return(a._olm_account_last_error=a.asm.M).apply(null,arguments)};a._olm_session_last_error=function(){return(a._olm_session_last_error=a.asm.N).apply(null,arguments)};a._olm_utility_last_error=function(){return(a._olm_utility_last_error=a.asm.O).apply(null,arguments)};a._olm_account_size=function(){return(a._olm_account_size=a.asm.P).apply(null,arguments)};a._olm_session_size=function(){return(a._olm_session_size=a.asm.Q).apply(null,arguments)};
|
||||
a._olm_utility_size=function(){return(a._olm_utility_size=a.asm.R).apply(null,arguments)};a._olm_account=function(){return(a._olm_account=a.asm.S).apply(null,arguments)};a._olm_session=function(){return(a._olm_session=a.asm.T).apply(null,arguments)};a._olm_utility=function(){return(a._olm_utility=a.asm.U).apply(null,arguments)};a._olm_clear_account=function(){return(a._olm_clear_account=a.asm.V).apply(null,arguments)};
|
||||
a._olm_clear_session=function(){return(a._olm_clear_session=a.asm.W).apply(null,arguments)};a._olm_clear_utility=function(){return(a._olm_clear_utility=a.asm.X).apply(null,arguments)};a._olm_pickle_account_length=function(){return(a._olm_pickle_account_length=a.asm.Y).apply(null,arguments)};a._olm_pickle_session_length=function(){return(a._olm_pickle_session_length=a.asm.Z).apply(null,arguments)};a._olm_pickle_account=function(){return(a._olm_pickle_account=a.asm._).apply(null,arguments)};
|
||||
a._olm_pickle_session=function(){return(a._olm_pickle_session=a.asm.$).apply(null,arguments)};a._olm_unpickle_account=function(){return(a._olm_unpickle_account=a.asm.aa).apply(null,arguments)};a._olm_unpickle_session=function(){return(a._olm_unpickle_session=a.asm.ba).apply(null,arguments)};a._olm_create_account_random_length=function(){return(a._olm_create_account_random_length=a.asm.ca).apply(null,arguments)};a._olm_create_account=function(){return(a._olm_create_account=a.asm.da).apply(null,arguments)};
|
||||
a._olm_account_identity_keys_length=function(){return(a._olm_account_identity_keys_length=a.asm.ea).apply(null,arguments)};a._olm_account_identity_keys=function(){return(a._olm_account_identity_keys=a.asm.fa).apply(null,arguments)};a._olm_account_signature_length=function(){return(a._olm_account_signature_length=a.asm.ga).apply(null,arguments)};a._olm_account_sign=function(){return(a._olm_account_sign=a.asm.ha).apply(null,arguments)};
|
||||
a._olm_account_one_time_keys_length=function(){return(a._olm_account_one_time_keys_length=a.asm.ia).apply(null,arguments)};a._olm_account_one_time_keys=function(){return(a._olm_account_one_time_keys=a.asm.ja).apply(null,arguments)};a._olm_account_mark_keys_as_published=function(){return(a._olm_account_mark_keys_as_published=a.asm.ka).apply(null,arguments)};a._olm_account_max_number_of_one_time_keys=function(){return(a._olm_account_max_number_of_one_time_keys=a.asm.la).apply(null,arguments)};
|
||||
a._olm_account_generate_one_time_keys_random_length=function(){return(a._olm_account_generate_one_time_keys_random_length=a.asm.ma).apply(null,arguments)};a._olm_account_generate_one_time_keys=function(){return(a._olm_account_generate_one_time_keys=a.asm.na).apply(null,arguments)};a._olm_account_generate_fallback_key_random_length=function(){return(a._olm_account_generate_fallback_key_random_length=a.asm.oa).apply(null,arguments)};
|
||||
a._olm_account_generate_fallback_key=function(){return(a._olm_account_generate_fallback_key=a.asm.pa).apply(null,arguments)};a._olm_account_fallback_key_length=function(){return(a._olm_account_fallback_key_length=a.asm.qa).apply(null,arguments)};a._olm_account_fallback_key=function(){return(a._olm_account_fallback_key=a.asm.ra).apply(null,arguments)};a._olm_create_outbound_session_random_length=function(){return(a._olm_create_outbound_session_random_length=a.asm.sa).apply(null,arguments)};
|
||||
a._olm_create_outbound_session=function(){return(a._olm_create_outbound_session=a.asm.ta).apply(null,arguments)};a._olm_create_inbound_session=function(){return(a._olm_create_inbound_session=a.asm.ua).apply(null,arguments)};a._olm_create_inbound_session_from=function(){return(a._olm_create_inbound_session_from=a.asm.va).apply(null,arguments)};a._olm_session_id_length=function(){return(a._olm_session_id_length=a.asm.wa).apply(null,arguments)};
|
||||
a._olm_session_id=function(){return(a._olm_session_id=a.asm.xa).apply(null,arguments)};a._olm_session_has_received_message=function(){return(a._olm_session_has_received_message=a.asm.ya).apply(null,arguments)};a._olm_session_describe=function(){return(a._olm_session_describe=a.asm.za).apply(null,arguments)};a._olm_matches_inbound_session=function(){return(a._olm_matches_inbound_session=a.asm.Aa).apply(null,arguments)};
|
||||
a._olm_matches_inbound_session_from=function(){return(a._olm_matches_inbound_session_from=a.asm.Ba).apply(null,arguments)};a._olm_remove_one_time_keys=function(){return(a._olm_remove_one_time_keys=a.asm.Ca).apply(null,arguments)};a._olm_encrypt_message_type=function(){return(a._olm_encrypt_message_type=a.asm.Da).apply(null,arguments)};a._olm_encrypt_random_length=function(){return(a._olm_encrypt_random_length=a.asm.Ea).apply(null,arguments)};
|
||||
a._olm_encrypt_message_length=function(){return(a._olm_encrypt_message_length=a.asm.Fa).apply(null,arguments)};a._olm_encrypt=function(){return(a._olm_encrypt=a.asm.Ga).apply(null,arguments)};a._olm_decrypt_max_plaintext_length=function(){return(a._olm_decrypt_max_plaintext_length=a.asm.Ha).apply(null,arguments)};a._olm_decrypt=function(){return(a._olm_decrypt=a.asm.Ia).apply(null,arguments)};a._olm_sha256_length=function(){return(a._olm_sha256_length=a.asm.Ja).apply(null,arguments)};
|
||||
a._olm_sha256=function(){return(a._olm_sha256=a.asm.Ka).apply(null,arguments)};a._olm_ed25519_verify=function(){return(a._olm_ed25519_verify=a.asm.La).apply(null,arguments)};a._olm_inbound_group_session_size=function(){return(a._olm_inbound_group_session_size=a.asm.Ma).apply(null,arguments)};a._olm_inbound_group_session=function(){return(a._olm_inbound_group_session=a.asm.Na).apply(null,arguments)};
|
||||
a._olm_clear_inbound_group_session=function(){return(a._olm_clear_inbound_group_session=a.asm.Oa).apply(null,arguments)};a._olm_inbound_group_session_last_error=function(){return(a._olm_inbound_group_session_last_error=a.asm.Pa).apply(null,arguments)};a._olm_init_inbound_group_session=function(){return(a._olm_init_inbound_group_session=a.asm.Qa).apply(null,arguments)};a._olm_import_inbound_group_session=function(){return(a._olm_import_inbound_group_session=a.asm.Ra).apply(null,arguments)};
|
||||
a._olm_pickle_inbound_group_session_length=function(){return(a._olm_pickle_inbound_group_session_length=a.asm.Sa).apply(null,arguments)};a._olm_pickle_inbound_group_session=function(){return(a._olm_pickle_inbound_group_session=a.asm.Ta).apply(null,arguments)};a._olm_unpickle_inbound_group_session=function(){return(a._olm_unpickle_inbound_group_session=a.asm.Ua).apply(null,arguments)};
|
||||
a._olm_group_decrypt_max_plaintext_length=function(){return(a._olm_group_decrypt_max_plaintext_length=a.asm.Va).apply(null,arguments)};a._olm_group_decrypt=function(){return(a._olm_group_decrypt=a.asm.Wa).apply(null,arguments)};a._olm_inbound_group_session_id_length=function(){return(a._olm_inbound_group_session_id_length=a.asm.Xa).apply(null,arguments)};a._olm_inbound_group_session_id=function(){return(a._olm_inbound_group_session_id=a.asm.Ya).apply(null,arguments)};
|
||||
a._olm_inbound_group_session_first_known_index=function(){return(a._olm_inbound_group_session_first_known_index=a.asm.Za).apply(null,arguments)};a._olm_inbound_group_session_is_verified=function(){return(a._olm_inbound_group_session_is_verified=a.asm._a).apply(null,arguments)};a._olm_export_inbound_group_session_length=function(){return(a._olm_export_inbound_group_session_length=a.asm.$a).apply(null,arguments)};
|
||||
a._olm_export_inbound_group_session=function(){return(a._olm_export_inbound_group_session=a.asm.ab).apply(null,arguments)};a._olm_sas_last_error=function(){return(a._olm_sas_last_error=a.asm.bb).apply(null,arguments)};a._olm_sas_size=function(){return(a._olm_sas_size=a.asm.cb).apply(null,arguments)};a._olm_sas=function(){return(a._olm_sas=a.asm.db).apply(null,arguments)};a._olm_clear_sas=function(){return(a._olm_clear_sas=a.asm.eb).apply(null,arguments)};
|
||||
a._olm_create_sas_random_length=function(){return(a._olm_create_sas_random_length=a.asm.fb).apply(null,arguments)};a._olm_create_sas=function(){return(a._olm_create_sas=a.asm.gb).apply(null,arguments)};a._olm_sas_pubkey_length=function(){return(a._olm_sas_pubkey_length=a.asm.hb).apply(null,arguments)};a._olm_sas_get_pubkey=function(){return(a._olm_sas_get_pubkey=a.asm.ib).apply(null,arguments)};a._olm_sas_set_their_key=function(){return(a._olm_sas_set_their_key=a.asm.jb).apply(null,arguments)};
|
||||
a._olm_sas_is_their_key_set=function(){return(a._olm_sas_is_their_key_set=a.asm.kb).apply(null,arguments)};a._olm_sas_generate_bytes=function(){return(a._olm_sas_generate_bytes=a.asm.lb).apply(null,arguments)};a._olm_sas_mac_length=function(){return(a._olm_sas_mac_length=a.asm.mb).apply(null,arguments)};a._olm_sas_calculate_mac=function(){return(a._olm_sas_calculate_mac=a.asm.nb).apply(null,arguments)};
|
||||
a._olm_sas_calculate_mac_long_kdf=function(){return(a._olm_sas_calculate_mac_long_kdf=a.asm.ob).apply(null,arguments)};a._olm_outbound_group_session_size=function(){return(a._olm_outbound_group_session_size=a.asm.pb).apply(null,arguments)};a._olm_outbound_group_session=function(){return(a._olm_outbound_group_session=a.asm.qb).apply(null,arguments)};a._olm_clear_outbound_group_session=function(){return(a._olm_clear_outbound_group_session=a.asm.rb).apply(null,arguments)};
|
||||
a._olm_outbound_group_session_last_error=function(){return(a._olm_outbound_group_session_last_error=a.asm.sb).apply(null,arguments)};a._olm_pickle_outbound_group_session_length=function(){return(a._olm_pickle_outbound_group_session_length=a.asm.tb).apply(null,arguments)};a._olm_pickle_outbound_group_session=function(){return(a._olm_pickle_outbound_group_session=a.asm.ub).apply(null,arguments)};
|
||||
a._olm_unpickle_outbound_group_session=function(){return(a._olm_unpickle_outbound_group_session=a.asm.vb).apply(null,arguments)};a._olm_init_outbound_group_session_random_length=function(){return(a._olm_init_outbound_group_session_random_length=a.asm.wb).apply(null,arguments)};a._olm_init_outbound_group_session=function(){return(a._olm_init_outbound_group_session=a.asm.xb).apply(null,arguments)};
|
||||
a._olm_group_encrypt_message_length=function(){return(a._olm_group_encrypt_message_length=a.asm.yb).apply(null,arguments)};a._olm_group_encrypt=function(){return(a._olm_group_encrypt=a.asm.zb).apply(null,arguments)};a._olm_outbound_group_session_id_length=function(){return(a._olm_outbound_group_session_id_length=a.asm.Ab).apply(null,arguments)};a._olm_outbound_group_session_id=function(){return(a._olm_outbound_group_session_id=a.asm.Bb).apply(null,arguments)};
|
||||
a._olm_outbound_group_session_message_index=function(){return(a._olm_outbound_group_session_message_index=a.asm.Cb).apply(null,arguments)};a._olm_outbound_group_session_key_length=function(){return(a._olm_outbound_group_session_key_length=a.asm.Db).apply(null,arguments)};a._olm_outbound_group_session_key=function(){return(a._olm_outbound_group_session_key=a.asm.Eb).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.Fb).apply(null,arguments)};
|
||||
a._free=function(){return(a._free=a.asm.Gb).apply(null,arguments)};var Wa=a.stackSave=function(){return(Wa=a.stackSave=a.asm.Hb).apply(null,arguments)},Xa=a.stackRestore=function(){return(Xa=a.stackRestore=a.asm.Ib).apply(null,arguments)},Ya=a.stackAlloc=function(){return(Ya=a.stackAlloc=a.asm.Jb).apply(null,arguments)};a.ALLOC_STACK=1;var Za;Oa=function $a(){Za||ab();Za||(Oa=$a)};
|
||||
function ab(){function b(){if(!Za&&(Za=!0,a.calledRun=!0,!Ba)){Ha(Ja);Ha(Ka);aa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();La.unshift(c)}Ha(La)}}if(!(0<C)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)Ma();Ha(Ia);0<C||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}
|
||||
a.run=ab;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();noExitRuntime=!0;ab();function E(){var b=a._olm_outbound_group_session_size();this.Lb=F(b);this.Kb=a._olm_outbound_group_session(this.Lb)}function H(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_outbound_group_session_last_error(arguments[0])),Error("OLM."+c);return c}}E.prototype.free=function(){a._olm_clear_outbound_group_session(this.Kb);I(this.Kb)};
|
||||
E.prototype.pickle=J(function(b){b=K(b);var c=H(a._olm_pickle_outbound_group_session_length)(this.Kb),d=L(b),e=L(c+1);try{H(a._olm_pickle_outbound_group_session)(this.Kb,d,b.length,e,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(e,c)});E.prototype.unpickle=J(function(b,c){b=K(b);var d=L(b);c=K(c);var e=L(c);try{H(a._olm_unpickle_outbound_group_session)(this.Kb,d,b.length,e,c.length)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}});
|
||||
E.prototype.create=J(function(){var b=H(a._olm_init_outbound_group_session_random_length)(this.Kb),c=N(b,g);H(a._olm_init_outbound_group_session)(this.Kb,c,b)});E.prototype.encrypt=function(b){try{var c=A(b);var d=H(a._olm_group_encrypt_message_length)(this.Kb,c);var e=F(c+1);z(b,y,e,c+1);var f=F(d+1);H(a._olm_group_encrypt)(this.Kb,e,c,f,d);r(f+d);return x(f,d)}finally{void 0!==e&&(M(e,c+1),I(e)),void 0!==f&&I(f)}};
|
||||
E.prototype.session_id=J(function(){var b=H(a._olm_outbound_group_session_id_length)(this.Kb),c=L(b+1);H(a._olm_outbound_group_session_id)(this.Kb,c,b);return x(c,b)});E.prototype.session_key=J(function(){var b=H(a._olm_outbound_group_session_key_length)(this.Kb),c=L(b+1);H(a._olm_outbound_group_session_key)(this.Kb,c,b);var d=x(c,b);M(c,b);return d});E.prototype.message_index=function(){return H(a._olm_outbound_group_session_message_index)(this.Kb)};olm_exports.OutboundGroupSession=E;
|
||||
function O(){var b=a._olm_inbound_group_session_size();this.Lb=F(b);this.Kb=a._olm_inbound_group_session(this.Lb)}function P(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_inbound_group_session_last_error(arguments[0])),Error("OLM."+c);return c}}O.prototype.free=function(){a._olm_clear_inbound_group_session(this.Kb);I(this.Kb)};
|
||||
O.prototype.pickle=J(function(b){b=K(b);var c=P(a._olm_pickle_inbound_group_session_length)(this.Kb),d=L(b),e=L(c+1);try{P(a._olm_pickle_inbound_group_session)(this.Kb,d,b.length,e,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(e,c)});O.prototype.unpickle=J(function(b,c){b=K(b);var d=L(b);c=K(c);var e=L(c);try{P(a._olm_unpickle_inbound_group_session)(this.Kb,d,b.length,e,c.length)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}});
|
||||
O.prototype.create=J(function(b){b=K(b);var c=L(b);try{P(a._olm_init_inbound_group_session)(this.Kb,c,b.length)}finally{for(M(c,b.length),c=0;c<b.length;c++)b[c]=0}});O.prototype.import_session=J(function(b){b=K(b);var c=L(b);try{P(a._olm_import_inbound_group_session)(this.Kb,c,b.length)}finally{for(M(c,b.length),c=0;c<b.length;c++)b[c]=0}});
|
||||
O.prototype.decrypt=J(function(b){try{var c=F(b.length);Da(b,c);var d=P(a._olm_group_decrypt_max_plaintext_length)(this.Kb,c,b.length);Da(b,c);var e=F(d+1);var f=L(4);var k=P(a._olm_group_decrypt)(this.Kb,c,b.length,e,d,f);r(e+k);return{plaintext:x(e,k),message_index:ya(f,"i32")}}finally{void 0!==c&&I(c),void 0!==e&&(M(e,k),I(e))}});O.prototype.session_id=J(function(){var b=P(a._olm_inbound_group_session_id_length)(this.Kb),c=L(b+1);P(a._olm_inbound_group_session_id)(this.Kb,c,b);return x(c,b)});
|
||||
O.prototype.first_known_index=J(function(){return P(a._olm_inbound_group_session_first_known_index)(this.Kb)});O.prototype.export_session=J(function(b){var c=P(a._olm_export_inbound_group_session_length)(this.Kb),d=L(c+1);H(a._olm_export_inbound_group_session)(this.Kb,d,c,b);b=x(d,c);M(d,c);return b});olm_exports.InboundGroupSession=O;function bb(){var b=a._olm_pk_encryption_size();this.Lb=F(b);this.Kb=a._olm_pk_encryption(this.Lb)}
|
||||
function Q(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_pk_encryption_last_error(arguments[0])),Error("OLM."+c);return c}}bb.prototype.free=function(){a._olm_clear_pk_encryption(this.Kb);I(this.Kb)};bb.prototype.set_recipient_key=J(function(b){b=K(b);var c=L(b);Q(a._olm_pk_encryption_set_recipient_key)(this.Kb,c,b.length)});
|
||||
bb.prototype.encrypt=J(function(b){try{var c=A(b);var d=F(c+1);z(b,y,d,c+1);var e=Q(a._olm_pk_encrypt_random_length)();var f=N(e,g);var k=Q(a._olm_pk_ciphertext_length)(this.Kb,c);var p=F(k+1);var v=Q(a._olm_pk_mac_length)(this.Kb),ha=L(v+1);r(ha+v);var V=Q(a._olm_pk_key_length)(),G=L(V+1);r(G+V);Q(a._olm_pk_encrypt)(this.Kb,d,c,p,k,ha,v,G,V,f,e);r(p+k);return{ciphertext:x(p,k),mac:x(ha,v),ephemeral:x(G,V)}}finally{void 0!==f&&M(f,e),void 0!==d&&(M(d,c+1),I(d)),void 0!==p&&I(p)}});
|
||||
function R(){var b=a._olm_pk_decryption_size();this.Lb=F(b);this.Kb=a._olm_pk_decryption(this.Lb)}function S(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_pk_decryption_last_error(arguments[0])),Error("OLM."+c);return c}}R.prototype.free=function(){a._olm_clear_pk_decryption(this.Kb);I(this.Kb)};
|
||||
R.prototype.init_with_private_key=J(function(b){var c=L(b.length);a.HEAPU8.set(b,c);var d=S(a._olm_pk_key_length)(),e=L(d+1);try{S(a._olm_pk_key_from_private)(this.Kb,e,d,c,b.length)}finally{M(c,b.length)}return x(e,d)});R.prototype.generate_key=J(function(){var b=S(a._olm_pk_private_key_length)(),c=N(b,g),d=S(a._olm_pk_key_length)(),e=L(d+1);try{S(a._olm_pk_key_from_private)(this.Kb,e,d,c,b)}finally{M(c,b)}return x(e,d)});
|
||||
R.prototype.get_private_key=J(function(){var b=Q(a._olm_pk_private_key_length)(),c=L(b);S(a._olm_pk_get_private_key)(this.Kb,c,b);var d=new Uint8Array(new Uint8Array(a.HEAPU8.buffer,c,b));M(c,b);return d});R.prototype.pickle=J(function(b){b=K(b);var c=S(a._olm_pickle_pk_decryption_length)(this.Kb),d=L(b),e=L(c+1);try{S(a._olm_pickle_pk_decryption)(this.Kb,d,b.length,e,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(e,c)});
|
||||
R.prototype.unpickle=J(function(b,c){b=K(b);var d=L(b),e=K(c),f=L(e);c=S(a._olm_pk_key_length)();var k=L(c+1);try{S(a._olm_unpickle_pk_decryption)(this.Kb,d,b.length,f,e.length,k,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(k,c)});
|
||||
R.prototype.decrypt=J(function(b,c,d){try{var e=A(d);var f=F(e+1);z(d,y,f,e+1);var k=K(b),p=L(k),v=K(c),ha=L(v);var V=S(a._olm_pk_max_plaintext_length)(this.Kb,e);var G=F(V+1);var Fa=S(a._olm_pk_decrypt)(this.Kb,p,k.length,ha,v.length,f,e,G,V);r(G+Fa);return x(G,Fa)}finally{void 0!==G&&(M(G,Fa+1),I(G)),void 0!==f&&I(f)}});function cb(){var b=a._olm_pk_signing_size();this.Lb=F(b);this.Kb=a._olm_pk_signing(this.Lb)}
|
||||
function db(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_pk_signing_last_error(arguments[0])),Error("OLM."+c);return c}}cb.prototype.free=function(){a._olm_clear_pk_signing(this.Kb);I(this.Kb)};cb.prototype.init_with_seed=J(function(b){var c=L(b.length);a.HEAPU8.set(b,c);var d=db(a._olm_pk_signing_public_key_length)(),e=L(d+1);try{db(a._olm_pk_signing_key_from_seed)(this.Kb,e,d,c,b.length)}finally{M(c,b.length)}return x(e,d)});
|
||||
cb.prototype.generate_seed=J(function(){var b=db(a._olm_pk_signing_seed_length)(),c=N(b,g),d=new Uint8Array(new Uint8Array(a.HEAPU8.buffer,c,b));M(c,b);return d});cb.prototype.sign=J(function(b){try{var c=A(b);var d=F(c+1);z(b,y,d,c+1);var e=db(a._olm_pk_signature_length)(),f=L(e+1);db(a._olm_pk_sign)(this.Kb,d,c,f,e);return x(f,e)}finally{void 0!==d&&(M(d,c+1),I(d))}});
|
||||
function T(){var b=a._olm_sas_size(),c=a._olm_create_sas_random_length(),d=N(c,g);this.Lb=F(b);this.Kb=a._olm_sas(this.Lb);a._olm_create_sas(this.Kb,d,c);M(d,c)}function U(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_sas_last_error(arguments[0])),Error("OLM."+c);return c}}T.prototype.free=function(){a._olm_clear_sas(this.Kb);I(this.Kb)};
|
||||
T.prototype.get_pubkey=J(function(){var b=U(a._olm_sas_pubkey_length)(this.Kb),c=L(b+1);U(a._olm_sas_get_pubkey)(this.Kb,c,b);return x(c,b)});T.prototype.set_their_key=J(function(b){b=K(b);var c=L(b);U(a._olm_sas_set_their_key)(this.Kb,c,b.length)});T.prototype.is_their_key_set=J(function(){return U(a._olm_sas_is_their_key_set)(this.Kb)?!0:!1});
|
||||
T.prototype.generate_bytes=J(function(b,c){b=K(b);var d=L(b),e=L(c);U(a._olm_sas_generate_bytes)(this.Kb,d,b.length,e,c);return new Uint8Array(new Uint8Array(a.HEAPU8.buffer,e,c))});T.prototype.calculate_mac=J(function(b,c){b=K(b);var d=L(b);c=K(c);var e=L(c),f=U(a._olm_sas_mac_length)(this.Kb),k=L(f+1);U(a._olm_sas_calculate_mac)(this.Kb,d,b.length,e,c.length,k,f);return x(k,f)});
|
||||
T.prototype.calculate_mac_long_kdf=J(function(b,c){b=K(b);var d=L(b);c=K(c);var e=L(c),f=U(a._olm_sas_mac_length)(this.Kb),k=L(f+1);U(a._olm_sas_calculate_mac_long_kdf)(this.Kb,d,b.length,e,c.length,k,f);return x(k,f)});var F=a._malloc,I=a._free,h;function N(b,c){var d=Ya(b);c(new Uint8Array(a.HEAPU8.buffer,d,b));return d}function L(b){return"number"==typeof b?N(b,function(c){c.fill(0)}):N(b.length,function(c){c.set(b)})}
|
||||
function K(b){if(b instanceof Uint8Array)var c=b;else c=Array(A(b)+1),b=z(b,c,0,c.length),c.length=b;return c}function J(b){return function(){var c=Wa();try{return b.apply(this,arguments)}finally{Xa(c)}}}function M(b,c){for(;0<c--;)a.HEAP8[b++]=0}function W(){var b=a._olm_account_size();this.Lb=F(b);this.Kb=a._olm_account(this.Lb)}function X(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_account_last_error(arguments[0])),Error("OLM."+c);return c}}
|
||||
W.prototype.free=function(){a._olm_clear_account(this.Kb);I(this.Kb)};W.prototype.create=J(function(){var b=X(a._olm_create_account_random_length)(this.Kb),c=N(b,g);X(a._olm_create_account)(this.Kb,c,b)});W.prototype.identity_keys=J(function(){var b=X(a._olm_account_identity_keys_length)(this.Kb),c=L(b+1);X(a._olm_account_identity_keys)(this.Kb,c,b);return x(c,b)});
|
||||
W.prototype.sign=J(function(b){var c=X(a._olm_account_signature_length)(this.Kb);b=K(b);var d=L(b),e=L(c+1);try{X(a._olm_account_sign)(this.Kb,d,b.length,e,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(e,c)});W.prototype.one_time_keys=J(function(){var b=X(a._olm_account_one_time_keys_length)(this.Kb),c=L(b+1);X(a._olm_account_one_time_keys)(this.Kb,c,b);return x(c,b)});W.prototype.mark_keys_as_published=J(function(){X(a._olm_account_mark_keys_as_published)(this.Kb)});
|
||||
W.prototype.max_number_of_one_time_keys=J(function(){return X(a._olm_account_max_number_of_one_time_keys)(this.Kb)});W.prototype.generate_one_time_keys=J(function(b){var c=X(a._olm_account_generate_one_time_keys_random_length)(this.Kb,b),d=N(c,g);X(a._olm_account_generate_one_time_keys)(this.Kb,b,d,c)});W.prototype.remove_one_time_keys=J(function(b){X(a._olm_remove_one_time_keys)(this.Kb,b.Kb)});
|
||||
W.prototype.generate_fallback_key=J(function(){var b=X(a._olm_account_generate_fallback_key_random_length)(this.Kb),c=N(b,g);X(a._olm_account_generate_fallback_key)(this.Kb,c,b)});W.prototype.fallback_key=J(function(){var b=X(a._olm_account_fallback_key_length)(this.Kb),c=L(b+1);X(a._olm_account_fallback_key)(this.Kb,c,b);return x(c,b)});
|
||||
W.prototype.pickle=J(function(b){b=K(b);var c=X(a._olm_pickle_account_length)(this.Kb),d=L(b),e=L(c+1);try{X(a._olm_pickle_account)(this.Kb,d,b.length,e,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(e,c)});W.prototype.unpickle=J(function(b,c){b=K(b);var d=L(b);c=K(c);var e=L(c);try{X(a._olm_unpickle_account)(this.Kb,d,b.length,e,c.length)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}});function Y(){var b=a._olm_session_size();this.Lb=F(b);this.Kb=a._olm_session(this.Lb)}
|
||||
function Z(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_session_last_error(arguments[0])),Error("OLM."+c);return c}}Y.prototype.free=function(){a._olm_clear_session(this.Kb);I(this.Kb)};Y.prototype.pickle=J(function(b){b=K(b);var c=Z(a._olm_pickle_session_length)(this.Kb),d=L(b),e=L(c+1);try{Z(a._olm_pickle_session)(this.Kb,d,b.length,e,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(e,c)});
|
||||
Y.prototype.unpickle=J(function(b,c){b=K(b);var d=L(b);c=K(c);var e=L(c);try{Z(a._olm_unpickle_session)(this.Kb,d,b.length,e,c.length)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}});Y.prototype.create_outbound=J(function(b,c,d){var e=Z(a._olm_create_outbound_session_random_length)(this.Kb),f=N(e,g);c=K(c);d=K(d);var k=L(c),p=L(d);try{Z(a._olm_create_outbound_session)(this.Kb,b.Kb,k,c.length,p,d.length,f,e)}finally{M(f,e)}});
|
||||
Y.prototype.create_inbound=J(function(b,c){c=K(c);var d=L(c);try{Z(a._olm_create_inbound_session)(this.Kb,b.Kb,d,c.length)}finally{for(M(d,c.length),b=0;b<c.length;b++)c[b]=0}});Y.prototype.create_inbound_from=J(function(b,c,d){c=K(c);var e=L(c);d=K(d);var f=L(d);try{Z(a._olm_create_inbound_session_from)(this.Kb,b.Kb,e,c.length,f,d.length)}finally{for(M(f,d.length),b=0;b<d.length;b++)d[b]=0}});
|
||||
Y.prototype.session_id=J(function(){var b=Z(a._olm_session_id_length)(this.Kb),c=L(b+1);Z(a._olm_session_id)(this.Kb,c,b);return x(c,b)});Y.prototype.has_received_message=function(){return Z(a._olm_session_has_received_message)(this.Kb)?!0:!1};Y.prototype.matches_inbound=J(function(b){b=K(b);var c=L(b);return Z(a._olm_matches_inbound_session)(this.Kb,c,b.length)?!0:!1});
|
||||
Y.prototype.matches_inbound_from=J(function(b,c){b=K(b);var d=L(b);c=K(c);var e=L(c);return Z(a._olm_matches_inbound_session_from)(this.Kb,d,b.length,e,c.length)?!0:!1});
|
||||
Y.prototype.encrypt=J(function(b){try{var c=Z(a._olm_encrypt_random_length)(this.Kb);var d=Z(a._olm_encrypt_message_type)(this.Kb);var e=A(b);var f=Z(a._olm_encrypt_message_length)(this.Kb,e);var k=N(c,g);var p=F(e+1);z(b,y,p,e+1);var v=F(f+1);Z(a._olm_encrypt)(this.Kb,p,e,k,c,v,f);r(v+f);return{type:d,body:x(v,f)}}finally{void 0!==k&&M(k,c),void 0!==p&&(M(p,e+1),I(p)),void 0!==v&&I(v)}});
|
||||
Y.prototype.decrypt=J(function(b,c){try{var d=F(c.length);Da(c,d);var e=Z(a._olm_decrypt_max_plaintext_length)(this.Kb,b,d,c.length);Da(c,d);var f=F(e+1);var k=Z(a._olm_decrypt)(this.Kb,b,d,c.length,f,e);r(f+k);return x(f,k)}finally{void 0!==d&&I(d),void 0!==f&&(M(f,e),I(f))}});Y.prototype.describe=J(function(){try{var b=F(256);Z(a._olm_session_describe)(this.Kb,b,256);return x(b)}finally{void 0!==b&&I(b)}});function eb(){var b=a._olm_utility_size();this.Lb=F(b);this.Kb=a._olm_utility(this.Lb)}
|
||||
function fb(b){return function(){var c=b.apply(this,arguments);if(c===h)throw c=x(a._olm_utility_last_error(arguments[0])),Error("OLM."+c);return c}}eb.prototype.free=function(){a._olm_clear_utility(this.Kb);I(this.Kb)};eb.prototype.sha256=J(function(b){var c=fb(a._olm_sha256_length)(this.Kb);b=K(b);var d=L(b),e=L(c+1);try{fb(a._olm_sha256)(this.Kb,d,b.length,e,c)}finally{for(M(d,b.length),d=0;d<b.length;d++)b[d]=0}return x(e,c)});
|
||||
eb.prototype.ed25519_verify=J(function(b,c,d){b=K(b);var e=L(b);c=K(c);var f=L(c);d=K(d);var k=L(d);try{fb(a._olm_ed25519_verify)(this.Kb,e,b.length,f,c.length,k,d.length)}finally{for(M(f,c.length),b=0;b<c.length;b++)c[b]=0}});olm_exports.Account=W;olm_exports.Session=Y;olm_exports.Utility=eb;olm_exports.PkEncryption=bb;olm_exports.PkDecryption=R;olm_exports.PkSigning=cb;olm_exports.SAS=T;
|
||||
olm_exports.get_library_version=J(function(){var b=L(3);a._olm_get_library_version(b,b+1,b+2);return[ya(b,"i8"),ya(b+1,"i8"),ya(b+2,"i8")]});
|
||||
|
||||
|
||||
return Module.ready
|
||||
}
|
||||
);
|
||||
})();
|
||||
if (typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = Module;
|
||||
else if (typeof define === 'function' && define['amd'])
|
||||
define([], function() { return Module; });
|
||||
else if (typeof exports === 'object')
|
||||
exports["Module"] = Module;
|
||||
var olmInitPromise;
|
||||
|
||||
olm_exports['init'] = function(opts) {
|
||||
if (olmInitPromise) return olmInitPromise;
|
||||
|
||||
if (opts) OLM_OPTIONS = opts;
|
||||
|
||||
olmInitPromise = new Promise(function(resolve, reject) {
|
||||
onInitSuccess = function() {
|
||||
resolve();
|
||||
};
|
||||
onInitFail = function(err) {
|
||||
reject(err);
|
||||
};
|
||||
Module();
|
||||
});
|
||||
return olmInitPromise;
|
||||
};
|
||||
|
||||
return olm_exports;
|
||||
|
||||
})();
|
||||
|
||||
if (typeof(window) !== 'undefined') {
|
||||
// We've been imported directly into a browser. Define the global 'Olm' object.
|
||||
// (we do this even if module.exports was defined, because it's useful to have
|
||||
// Olm in the global scope for browserified and webpacked apps.)
|
||||
window["Olm"] = Olm;
|
||||
}
|
||||
|
||||
if (typeof module === 'object') {
|
||||
// Emscripten sets the module exports to be its module
|
||||
// with wrapped c functions. Clobber it with our higher
|
||||
// level wrapper class.
|
||||
module.exports = Olm;
|
||||
}
|
||||
|
10318
lib/peer.js
Normal file
10318
lib/peer.js
Normal file
File diff suppressed because it is too large
Load Diff
36301
lib/three.js
Normal file
36301
lib/three.js
Normal file
File diff suppressed because one or more lines are too long
20
lib/utils.js
Normal file
20
lib/utils.js
Normal file
@ -0,0 +1,20 @@
|
||||
class EventListener {
|
||||
constructor () {
|
||||
this._listeners = {};
|
||||
}
|
||||
emit (eventName, ...data) {
|
||||
if (!this._listeners[eventName] || this._listeners[eventName].length == 0) return;
|
||||
|
||||
for (var e = 0; e < this._listeners[eventName].length; e++) {
|
||||
this._listeners[eventName][e](...data);
|
||||
}
|
||||
}
|
||||
on (eventName, callback) {
|
||||
if (!this._listeners[eventName]) this._listeners[eventName] = [];
|
||||
this._listeners[eventName].push(callback);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
"EventListener": EventListener
|
||||
};
|
34
lib/webfs.js
Normal file
34
lib/webfs.js
Normal file
@ -0,0 +1,34 @@
|
||||
/* Functions */
|
||||
|
||||
get = function (url, mode) {
|
||||
return fetch(url).then(function (response) {
|
||||
if (response.status == 200) {
|
||||
switch (mode) {
|
||||
case "text":
|
||||
return response.text();
|
||||
break;
|
||||
case "arraybuffer":
|
||||
return response.arrayBuffer();
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
} else {
|
||||
reject(new Error("Status code is not 200. "));
|
||||
}
|
||||
}).catch(function (err) {
|
||||
return err;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"get": function (path, mode, cb) {
|
||||
var href = window.location.href;
|
||||
var address = path.startsWith("./") ? href.substring(0, href.lastIndexOf("/")) + path.substring(1) : path;
|
||||
get(address, mode).then(function (data) {
|
||||
cb(null, data);
|
||||
}).catch(function (err) {
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
};
|
49
main.js
Normal file
49
main.js
Normal file
@ -0,0 +1,49 @@
|
||||
/* Dependencies */
|
||||
|
||||
const electron = require("electron");
|
||||
const path = require("node:path");
|
||||
|
||||
/* Initialization */
|
||||
|
||||
let gameWindow;
|
||||
|
||||
/* Functions */
|
||||
|
||||
function createWindow() {
|
||||
if (gameWindow) return;
|
||||
|
||||
gameWindow = new electron.BrowserWindow({
|
||||
"width": 800,
|
||||
"height": 450,
|
||||
"frame": false,
|
||||
"transparent": true,
|
||||
"backgroundColor": "#FFFFFFFF",
|
||||
"webPreferences": {
|
||||
"preload": path.join(__dirname, "preload.js"),
|
||||
"webgl": true
|
||||
},
|
||||
"title": "XVoxel",
|
||||
"icon": path.join("assets", "images", "xvoxel.png"),
|
||||
"show": false
|
||||
});
|
||||
|
||||
gameWindow.loadFile(path.join(__dirname, "index.html"));
|
||||
|
||||
gameWindow.once("ready-to-show", function () {
|
||||
gameWindow.show();
|
||||
});
|
||||
}
|
||||
|
||||
/* Events */
|
||||
|
||||
electron.app.on("ready", function (event) {
|
||||
createWindow();
|
||||
|
||||
electron.app.on("activate", function () {
|
||||
if (electron.BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||
});
|
||||
});
|
||||
|
||||
electron.app.on("window-all-closed", function () {
|
||||
if (process.platform !== "darwin") electron.app.quit();
|
||||
});
|
492
menu.js
Normal file
492
menu.js
Normal file
@ -0,0 +1,492 @@
|
||||
let menusContainer = document.getElementById("menus");
|
||||
|
||||
var menus = {};
|
||||
|
||||
var shownMenus = [];
|
||||
|
||||
var makeMenu = function () {
|
||||
module.exports.menuData = {
|
||||
"main": {
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.main.play.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["play", 1]
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.main.settings.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["settings", 1]
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.main.quit.label"),
|
||||
"action": "exit"
|
||||
}
|
||||
]
|
||||
},
|
||||
"play": {
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.play.singleplayer.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["gamesel", 2]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ingame": {
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"label": "Resume",
|
||||
"action": "run",
|
||||
"runnable": function () {
|
||||
global.inputs[0].grab();
|
||||
|
||||
hideMenus(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"label": "Quit",
|
||||
"action": "run",
|
||||
"runnable": global.quitGame
|
||||
}
|
||||
]
|
||||
},
|
||||
"gamesel": {
|
||||
"elements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "worldnameinput",
|
||||
"placeholder": "New World",
|
||||
"value": "New World",
|
||||
"action": "run",
|
||||
"runnable": function (event) {
|
||||
var newGameButton = global.document.getElementById("newgamebutton");
|
||||
|
||||
if (event.target.value.length < 1) {
|
||||
newGameButton.disabled = true;
|
||||
} else {
|
||||
newGameButton.disabled = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"id": "newgamebutton",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "play.singleplayer.newgamebutton.label"),
|
||||
"action": "run",
|
||||
"runnable": function () {
|
||||
var worldNameInputBox = global.document.getElementById("worldnameinput");
|
||||
|
||||
var worldName = worldNameInputBox.value;
|
||||
|
||||
if (worldName.length < 1) worldName = worldNameInputBox.placeholder;
|
||||
|
||||
global.createWorld(worldName).then(function (world) {
|
||||
global.startGame(0, worldName);
|
||||
hideMenus(0);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"id": "loadgamebutton",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "play.singleplayer.loadgamebutton.label"),
|
||||
"action": "run",
|
||||
"runnable": function () {
|
||||
var fileSelector = document.createElement("input");
|
||||
fileSelector.type = "file";
|
||||
fileSelector.accept = "application/zip";
|
||||
|
||||
fileSelector.click();
|
||||
|
||||
fileSelector.onchange = function (event) {
|
||||
if (!this.files || !this.files[0]) return;
|
||||
|
||||
this.files[0].arrayBuffer().then(function (buffer) {
|
||||
var fileU8 = new Uint8Array(buffer);
|
||||
|
||||
global.openSave(fileU8).then(function (worldList) {
|
||||
for (var worldName in worldList) {
|
||||
if (worldList.hasOwnProperty(worldName)) {
|
||||
var world = worldList[worldName];
|
||||
|
||||
global.worlds[worldName] = world;
|
||||
|
||||
var menuEntry = {
|
||||
"type": "button",
|
||||
"label": global.locales.getFormattedString(
|
||||
global.currentLanguage,
|
||||
"play.singleplayer.openworld.label",
|
||||
{
|
||||
"WORLD_NAME": worldName
|
||||
}),
|
||||
"action": "run",
|
||||
"runnable": (function (event) {
|
||||
hideMenus(0);
|
||||
|
||||
global.startGame(0, this);
|
||||
}).bind(worldName)
|
||||
};
|
||||
|
||||
module.exports.menuData["gamesel"].elements.push(menuEntry);
|
||||
}
|
||||
}
|
||||
|
||||
hideMenus(2);
|
||||
|
||||
menus["gamesel"] = constructMenu("gamesel", module.exports.menuData["gamesel"]);
|
||||
|
||||
showMenu("gamesel", 2);
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
delete fileSelector;
|
||||
};
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.settings.user.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["user-settings", 2]
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.settings.video.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["video-settings", 2]
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.settings.audio.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["audio-settings", 2]
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "menu.settings.input.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["input-settings", 2]
|
||||
}
|
||||
]
|
||||
},
|
||||
"user-settings": {
|
||||
"elements": [
|
||||
// {
|
||||
// "type": "text",
|
||||
// "name": "username",
|
||||
// "label": "Username",
|
||||
// "placeholder": "Username"
|
||||
// },
|
||||
{
|
||||
"type": "button",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "settings.user.login.label"),
|
||||
"action": "open-menu",
|
||||
"action-args": ["matrix-login", 3]
|
||||
}
|
||||
]
|
||||
},
|
||||
"matrix-login": {
|
||||
"expand": true,
|
||||
"elements": [
|
||||
{
|
||||
"type": "text",
|
||||
"name": "homeserver-url",
|
||||
"id": "homeserverinput",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "settings.login.homeserver-url.label"),
|
||||
"placeholder": "https://matrix.org/",
|
||||
"action": "run",
|
||||
"runnable": function (event) {
|
||||
var isValidURL = (/http.?:\/\/.+/g).test(event.target.value);
|
||||
var isValidMXID = (/@.+:.+/g).test(global.document.getElementById("mxidinput").value);
|
||||
var isValidPass = global.document.getElementById("mxpassinput").value.length > 0;
|
||||
|
||||
var loginButton = global.document.getElementById("mxloginbutton");
|
||||
|
||||
if (isValidURL && isValidMXID && isValidPass) {
|
||||
loginButton.disabled = false;
|
||||
} else {
|
||||
loginButton.disabled = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "mxid",
|
||||
"id": "mxidinput",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "settings.login.mxid.label"),
|
||||
"placeholder": global.locales.getRawString(global.currentLanguage, "settings.login.mxid.placeholder"),
|
||||
"action": "run",
|
||||
"runnable": function (event) {
|
||||
var isValidURL = (/http.?:\/\/.+/g).test(global.document.getElementById("homeserverinput").value);
|
||||
var isValidMXID = (/@.+:.+/g).test(event.target.value);
|
||||
var isValidPass = global.document.getElementById("mxpassinput").value.length > 0;
|
||||
|
||||
var loginButton = global.document.getElementById("mxloginbutton");
|
||||
|
||||
if (isValidURL && isValidMXID && isValidPass) {
|
||||
loginButton.disabled = false;
|
||||
} else {
|
||||
loginButton.disabled = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "password",
|
||||
"name": "password",
|
||||
"id": "mxpassinput",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "settings.login.password.label"),
|
||||
"placeholder": global.locales.getRawString(global.currentLanguage, "settings.login.password.placeholder"),
|
||||
"action": "run",
|
||||
"runnable": function (event) {
|
||||
var isValidURL = (/http.?:\/\/.+/g).test(global.document.getElementById("homeserverinput").value);
|
||||
var isValidMXID = (/@.+:.+/g).test(global.document.getElementById("mxidinput").value);
|
||||
var isValidPass = event.target.value.length > 0;
|
||||
|
||||
var loginButton = global.document.getElementById("mxloginbutton");
|
||||
|
||||
if (isValidURL && isValidMXID && isValidPass) {
|
||||
loginButton.disabled = false;
|
||||
} else {
|
||||
loginButton.disabled = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"id": "mxloginbutton",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "settings.user.login.label"),
|
||||
"disabled": true,
|
||||
"action": "run",
|
||||
"runnable": async function (event) {
|
||||
event.target.disabled = true;
|
||||
|
||||
var username = global.document.getElementById("mxidinput").value
|
||||
.substring(1)
|
||||
.split(":")[0];
|
||||
|
||||
if (!("matrixClient" in global.core.modules["network"])) {
|
||||
var matrixClient = await global.core.modules["network"].initMatrixClient(
|
||||
global.document.getElementById("homeserverinput").value,
|
||||
global.document.getElementById("mxidinput").value
|
||||
);
|
||||
}
|
||||
global.core.modules["network"].loginToMatrix(
|
||||
username,
|
||||
global.document.getElementById("mxpassinput").value
|
||||
).then(function () {
|
||||
localStorage.setItem("matrix_baseurl", global.document.getElementById("homeserverinput").value);
|
||||
localStorage.setItem("matrix_mxid", global.document.getElementById("mxidinput").value);
|
||||
localStorage.setItem("matrix_is_connected", true);
|
||||
|
||||
hideMenus(3);
|
||||
|
||||
event.target.disabled = false;
|
||||
}).catch(function (error) {
|
||||
event.target.disabled = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"video-settings": {
|
||||
"expand": true,
|
||||
"elements": [
|
||||
{
|
||||
"type": "slider",
|
||||
"name": "fieldofview",
|
||||
"label": "Field of view",
|
||||
"value": 70,
|
||||
"minimum": 30,
|
||||
"maximum": 150,
|
||||
"step": 1,
|
||||
"change": function (event) {
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio-settings": {
|
||||
"expand": true,
|
||||
"elements": [
|
||||
{
|
||||
"type": "slider",
|
||||
"name": "mastervolume",
|
||||
"label": "Master volume",
|
||||
"value": 100,
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"step": 1,
|
||||
"change": function (event) {
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
for (var name in module.exports.menuData) {
|
||||
if (module.exports.menuData.hasOwnProperty(name)) {
|
||||
var menu = module.exports.menuData[name];
|
||||
|
||||
menus[name] = constructMenu(name, menu);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var constructMenu = function (name, data) {
|
||||
var menuElement = document.createElement("div");
|
||||
menuElement.classList.add("menu");
|
||||
|
||||
for (var e = 0; e < data.elements.length; e++) {
|
||||
var element = data.elements[e];
|
||||
let dom;
|
||||
|
||||
switch (element.type) {
|
||||
case "button":
|
||||
dom = document.createElement("button");
|
||||
dom.innerText = element.label;
|
||||
if ("disabled" in element) dom.disabled = element.disabled;
|
||||
|
||||
switch (element.action) {
|
||||
case "open-menu":
|
||||
dom.onclick = (function (event) {
|
||||
showMenu(...this["action-args"]);
|
||||
}).bind(element);
|
||||
break;
|
||||
case "run":
|
||||
dom.onclick = element.runnable;
|
||||
break;
|
||||
case "exit":
|
||||
dom.classList.add("closebutton");
|
||||
dom.onclick = closeGame;
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
break;
|
||||
case "text":
|
||||
dom = document.createElement("input");
|
||||
dom.type = "text";
|
||||
|
||||
if (element.placeholder) dom.placeholder = element.placeholder;
|
||||
|
||||
if ("action" in element) {
|
||||
switch (element.action) {
|
||||
case "run":
|
||||
dom.oninput = element.runnable;
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "password":
|
||||
dom = document.createElement("input");
|
||||
dom.type = "password";
|
||||
|
||||
if ("disabled" in element) dom.disabled = element.disabled;
|
||||
|
||||
if (element.placeholder) dom.placeholder = element.placeholder;
|
||||
|
||||
if ("action" in element) {
|
||||
switch (element.action) {
|
||||
case "run":
|
||||
dom.oninput = element.runnable;
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "slider":
|
||||
dom = document.createElement("input");
|
||||
dom.type = "range";
|
||||
dom.name = element.name;
|
||||
|
||||
if ("disabled" in element) dom.disabled = element.disabled;
|
||||
|
||||
if (element.value) dom.value = element.value;
|
||||
if (element.minimum) dom.min = element.minimum;
|
||||
if (element.maximum) dom.max = element.maximum;
|
||||
if (element.step) dom.step = element.step;
|
||||
break;
|
||||
case "void":
|
||||
dom = document.createElement("div");
|
||||
dom.classList.add("void");
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
if (element.id) dom.id = element.id;
|
||||
|
||||
if ((element.type != "button") && element.label) {
|
||||
domLabel = document.createElement("label");
|
||||
domLabel.htmlFor = element.name;
|
||||
domLabel.innerText = element.label;
|
||||
menuElement.appendChild(domLabel);
|
||||
|
||||
dom.name = element.name;
|
||||
dom.label = domLabel;
|
||||
}
|
||||
|
||||
menuElement.appendChild(dom);
|
||||
}
|
||||
|
||||
return menuElement;
|
||||
};
|
||||
|
||||
var showMenu = function (name, offset) {
|
||||
if (shownMenus.length > 0 && (!shownMenus[offset - 1])) return;
|
||||
|
||||
if (shownMenus[offset] == menus[name]) {
|
||||
return hideMenus(offset);
|
||||
} else {
|
||||
hideMenus(offset);
|
||||
|
||||
var displayOffset = 0;
|
||||
|
||||
for (var m = 0; m < shownMenus.length; m++) {
|
||||
displayOffset += shownMenus[m].clientWidth;
|
||||
}
|
||||
|
||||
menus[name].style.left = displayOffset + "px";
|
||||
if (module.exports.menuData[name].expand) {
|
||||
menus[name].style.width = "calc(" + menusContainer.clientWidth + "px - " + (menusContainer.clientWidth - displayOffset) + "px)";
|
||||
} else {
|
||||
menus[name].style.width = "" + 16 + "rem";
|
||||
}
|
||||
menusContainer.appendChild(menus[name]);
|
||||
shownMenus.push(menus[name]);
|
||||
}
|
||||
};
|
||||
|
||||
var hideMenus = function (offset) {
|
||||
for (var m = shownMenus.length; m >= offset; --m) {
|
||||
if (shownMenus[m]) menusContainer.removeChild(shownMenus[m]);
|
||||
}
|
||||
|
||||
shownMenus.splice(offset, shownMenus.length - offset);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"menus": menus,
|
||||
"makeMenu": makeMenu,
|
||||
"constructMenu": constructMenu,
|
||||
"showMenu": showMenu,
|
||||
"hideMenus": hideMenus
|
||||
};
|
141
modules/input.js
Normal file
141
modules/input.js
Normal file
@ -0,0 +1,141 @@
|
||||
var controllerTypes = [
|
||||
"desktop",
|
||||
"mobile",
|
||||
"console"
|
||||
];
|
||||
|
||||
class Controller {
|
||||
constructor (type, options = {}) {
|
||||
if (controllerTypes.indexOf(type) < 0) return new Error(
|
||||
"Controller type must be \"desktop\", \"mobile\" or \"console\". "
|
||||
);
|
||||
this.type = type;
|
||||
|
||||
this.mappings = {};
|
||||
this.actions = {};
|
||||
|
||||
switch (this.type) {
|
||||
case "desktop":
|
||||
if (options.domElement) {
|
||||
this.domElement = options.domElement;
|
||||
} else {
|
||||
this.domElement = document.querySelector(":root");
|
||||
}
|
||||
break;
|
||||
case "mobile":
|
||||
if (options.domElements) {
|
||||
this.domElements = options.domElements;
|
||||
} else {
|
||||
this.domElements = {
|
||||
"main": document.querySelector(":root")
|
||||
};
|
||||
}
|
||||
break;
|
||||
case "console":
|
||||
if (!options.gamepad) return new Error("A gamepad object must be passed. ");
|
||||
this.gamepad = options.gamepad;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
registerMapping (mapping, action) {
|
||||
this.mappings[mapping] = action;
|
||||
}
|
||||
registerAction (action, callback) {
|
||||
this.actions[action] = callback;
|
||||
}
|
||||
unregisterMapping (mapping) {
|
||||
delete this.mappings[mapping];
|
||||
}
|
||||
unregisterAction (action) {
|
||||
delete this.actions[action];
|
||||
}
|
||||
grab () {
|
||||
switch (this.type) {
|
||||
case "desktop":
|
||||
this.domElement.requestPointerLock();
|
||||
|
||||
this.domElement.onkeyup = this.domElement.onkeydown = processKeyEvent.bind(this);
|
||||
|
||||
this.domElement.onmousemove = this.domElement.onmousedown = this.domElement.onmouseup = processMouseEvent.bind(this);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
release () {
|
||||
switch (this.type) {
|
||||
case "desktop":
|
||||
document.exitPointerLock();
|
||||
|
||||
this.domElement.onkeyup = this.domElement.onkeydown = null;
|
||||
|
||||
this.domElement.onmousemove = null;
|
||||
this.domElement.onmousedown = this.domElement.onmouseup = null;
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var processKeyEvent = function (event) {
|
||||
var mapping = this.mappings[event.code];
|
||||
if (!mapping) return;
|
||||
|
||||
let eventType;
|
||||
|
||||
switch (event.type) {
|
||||
case "keydown":
|
||||
eventType = "down";
|
||||
break;
|
||||
case "keyup":
|
||||
eventType = "up";
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
var action = this.actions[mapping];
|
||||
if (typeof action == "function") action(eventType);
|
||||
};
|
||||
|
||||
var processMouseEvent = function (event) {
|
||||
let eventType;
|
||||
let mappingName;
|
||||
let movement;
|
||||
|
||||
switch (eventType) {
|
||||
case "mousedown":
|
||||
eventType = "down";
|
||||
mappingName = "MouseDown" + event.which;
|
||||
break;
|
||||
case "mousemove":
|
||||
eventType = "move";
|
||||
mappingName = "MouseMove";
|
||||
|
||||
movement = [event.movementX, event.movementY];
|
||||
break;
|
||||
case "mouseup":
|
||||
eventType = "up";
|
||||
mappingName = "MouseUp" + event.which;
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
var mapping = this.mappings[mappingName];
|
||||
if (!mapping) return;
|
||||
|
||||
var action = this.actions[mapping];
|
||||
if (typeof action == "function") action(((eventType == "move") ? movement : eventType));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"Controller": Controller
|
||||
};
|
||||
|
||||
global.core.on("pre-init", function () {
|
||||
global.core.emit("input-init");
|
||||
});
|
358
modules/network.js
Normal file
358
modules/network.js
Normal file
@ -0,0 +1,358 @@
|
||||
const networkClock = 1000 / 16;
|
||||
|
||||
var allowedIDCharacters = "0123456789ABCDEF";
|
||||
var tokenCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-";
|
||||
|
||||
var generateAccessToken = function () {
|
||||
var token = "";
|
||||
|
||||
for (var c = 0; c < 64; c++) {
|
||||
token += tokenCharacters[
|
||||
Math.floor(
|
||||
Math.random() * tokenCharacters.length
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
return token;
|
||||
};
|
||||
|
||||
var initMatrixClient = function (baseURL, mxID, withCrypto = false) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var matrixAccessToken = localStorage.getItem("matrix_access_token");
|
||||
if (!matrixAccessToken) {
|
||||
matrixAccessToken = generateAccessToken();
|
||||
localStorage.setItem("matrix_access_token", matrixAccessToken);
|
||||
}
|
||||
|
||||
var matrixClient = global.matrixcs.createClient({
|
||||
"baseUrl": baseURL,
|
||||
"accessToken": matrixAccessToken,
|
||||
"userId": mxID,
|
||||
"deviceId": "XVoxel"
|
||||
});
|
||||
|
||||
module.exports.matrixClient = matrixClient;
|
||||
|
||||
resolve(matrixClient);
|
||||
|
||||
if (withCrypto) {
|
||||
matrixClient.initCrypto().then(function () {
|
||||
|
||||
}).catch(console.error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var loginToMatrix = function (username, password) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!("matrixClient" in module.exports)) return reject(new Error("Matrix client hasn't been initialized yet"));
|
||||
module.exports.matrixClient.loginWithPassword(username, password).then(function (result) {
|
||||
var matrixAccessToken = module.exports.matrixClient.getAccessToken();
|
||||
localStorage.setItem("matrix_access_token", matrixAccessToken);
|
||||
resolve(result);
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
var startMatrixClient = function () {
|
||||
module.exports.matrixClient.startClient();
|
||||
|
||||
module.exports.matrixClient.on("sync", function (state, previousState, response) {
|
||||
if (state === "PREPARED") {
|
||||
var buttonReadyInterval = setInterval(function () {
|
||||
var mxWJBtn = document.querySelector("#matrixworldjoin");
|
||||
|
||||
if (!mxWJBtn) return;
|
||||
|
||||
mxWJBtn.disabled = false;
|
||||
clearInterval(buttonReadyInterval);
|
||||
}, 256);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var createWorldRoom = function (name) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
module.exports.matrixClient.createRoom({
|
||||
"name": name,
|
||||
"visibility": "private",
|
||||
"topic": "A Voxel world",
|
||||
"creation_content": {
|
||||
"type": "m.world.voxel"
|
||||
}
|
||||
}).then(resolve).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
var getWorldRooms = function () {
|
||||
var rooms = module.exports.matrixClient.getRooms();
|
||||
|
||||
if (!rooms) return [];
|
||||
|
||||
return rooms.filter(room => room.getType() == "m.world.voxel");
|
||||
};
|
||||
|
||||
var syncWorldFromMatrixRoom = function (room) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
module.exports.matrixClient.getStateEvent(room.roomId, "m.world.voxel", "save").then(function (event) {
|
||||
fetch(module.exports.matrixClient.mxcUrlToHttp(event["save_uri"])).then(function (response) {
|
||||
response.arrayBuffer().then(function (arrayBuffer) {
|
||||
global.openSave(arrayBuffer).then(function (loadedWorlds) {
|
||||
for (var worldName in loadedWorlds) {
|
||||
if (loadedWorlds.hasOwnProperty(worldName)) {
|
||||
global.worlds[worldName] = loadedWorlds[worldName];
|
||||
}
|
||||
}
|
||||
|
||||
resolve(global.worlds[room.name]);
|
||||
}).catch(reject);
|
||||
}).catch(reject);
|
||||
}).catch(reject);
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
var syncWorldToMatrixRoom = function (room) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
global.makeSave().then(function (archive) {
|
||||
module.exports.matrixClient.uploadContent(archive, {
|
||||
"name": room.name + ".zip",
|
||||
"type": "application/zip"
|
||||
}).then(function (response) {
|
||||
module.exports.matrixClient.sendStateEvent(room.roomId, "m.world.voxel", {
|
||||
"save_uri": response.content_uri
|
||||
}, "save").then(resolve).catch(reject);
|
||||
}).catch(reject);
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
var connectMatrix = function (room) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var groupCall = module.exports.matrixClient.getGroupCallForRoom(room.roomId);
|
||||
if (!groupCall) {
|
||||
return module.exports.matrixClient.createGroupCall(
|
||||
room.roomId, global.matrixcs.GroupCallType["Voice"],
|
||||
false, global.matrixcs.GroupCallIntent["Room"], true
|
||||
).then(function (call) {
|
||||
call.initWithAudioMuted = true;
|
||||
call.initWithVideoMuted = true;
|
||||
call.setMicrophoneMuted(true);
|
||||
call.enter();
|
||||
resolve(call);
|
||||
}).catch(console.error);
|
||||
}
|
||||
groupCall.initWithAudioMuted = true;
|
||||
groupCall.initWithVideoMuted = true;
|
||||
groupCall.setMicrophoneMuted(true);
|
||||
groupCall.enter();
|
||||
resolve(groupCall);
|
||||
});
|
||||
};
|
||||
|
||||
if (localStorage.getItem("matrix_is_connected")) {
|
||||
initMatrixClient(
|
||||
localStorage.getItem("matrix_baseurl"),
|
||||
localStorage.getItem("matrix_mxid")
|
||||
).then(function (matrixClient) {
|
||||
module.exports.matrixClient = matrixClient;
|
||||
startMatrixClient();
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
localStorage.removeItem("matrix_is_connected");
|
||||
});
|
||||
}
|
||||
|
||||
var connectRTC = function (options) {
|
||||
var randomID = (options.username || "Guest") + "-";
|
||||
for (var c = 0; c < 16; c++) {
|
||||
randomID += allowedIDCharacters[
|
||||
Math.floor(
|
||||
Math.random() * allowedIDCharacters.length
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
var peerNetwork = new global.peer.default(randomID, {
|
||||
"host": options.host,
|
||||
"port": options.port,
|
||||
"path": options.path
|
||||
});
|
||||
|
||||
return peerNetwork;
|
||||
};
|
||||
|
||||
var connect = function (url) {
|
||||
try {
|
||||
var connectionURL = new URL(url);
|
||||
} catch (error) {
|
||||
global.throwError(error);
|
||||
}
|
||||
|
||||
var splitPathName = connectionURL.pathname.split(/[\/]/);
|
||||
|
||||
var pathNameParts = splitPathName[2].split("@");
|
||||
|
||||
if (pathNameParts.length > 1) {
|
||||
var pathNameCredentials = pathNameParts.split(":");
|
||||
|
||||
var pathNameUsername = pathNameCredentials[0];
|
||||
|
||||
if (pathNameCredentials.length > 1) {
|
||||
var pathNamePassword = pathNameCredentials[1];
|
||||
}
|
||||
|
||||
var pathNameConnectionDataIndex = 1;
|
||||
} else {
|
||||
var pathNameConnectionDataIndex = 0;
|
||||
}
|
||||
|
||||
var pathNameConnectionData = pathNameParts[pathNameConnectionDataIndex].split(":");
|
||||
|
||||
var pathNameAddress = pathNameConnectionData[0];
|
||||
|
||||
if (pathNameConnectionData.length > 1) {
|
||||
var pathNamePort = pathNameConnectionData[1];
|
||||
}
|
||||
|
||||
var pathNamePath = "/" + splitPathName.slice(3).join("/");
|
||||
|
||||
switch (connectionURL.protocol) {
|
||||
case "rtc:":
|
||||
return connectRTC({
|
||||
"host": pathNameAddress,
|
||||
"port": pathNamePort || 443,
|
||||
"path": pathNamePath || "/",
|
||||
"username": pathNameUsername || "Guest",
|
||||
"password": pathNamePassword || null
|
||||
});
|
||||
break;
|
||||
case "ws:":
|
||||
|
||||
break;
|
||||
case "wss:":
|
||||
|
||||
break;
|
||||
case "http:":
|
||||
|
||||
break;
|
||||
case "https:":
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"initMatrixClient": initMatrixClient,
|
||||
"loginToMatrix": loginToMatrix,
|
||||
"startMatrixClient": startMatrixClient,
|
||||
"createWorldRoom": createWorldRoom,
|
||||
"getWorldRooms": getWorldRooms,
|
||||
"connectMatrix": connectMatrix,
|
||||
"connect": connect,
|
||||
"menus": {
|
||||
"play": {
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"label": "Multiplayer",
|
||||
"action": "open-menu",
|
||||
"action-args": ["serversel", 2]
|
||||
}
|
||||
]
|
||||
},
|
||||
"serversel": {
|
||||
"elements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "serveraddressinput",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "play.multiplayer.serveraddressinput.label"),
|
||||
"placeholder": global.locales.getRawString(global.currentLanguage, "play.multiplayer.serveraddressinput.placeholder"),
|
||||
"value": "",
|
||||
"action": "run",
|
||||
"runnable": function (event) {
|
||||
var serverConnectButton = global.document.getElementById("serverconnectbutton");
|
||||
|
||||
if (event.path[0].value.length < 1) {
|
||||
serverConnectButton.disabled = true;
|
||||
} else {
|
||||
try {
|
||||
new URL(event.path[0].value);
|
||||
|
||||
serverConnectButton.disabled = false;
|
||||
} catch (e) {
|
||||
serverConnectButton.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"id": "serverconnectbutton",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "play.multiplayer.serverconnectbutton.label"),
|
||||
"disabled": true,
|
||||
"action": "run",
|
||||
"runnable": function (event) {
|
||||
var serverAddressInputBox = global.document.getElementById("serveraddressinput");
|
||||
|
||||
connect(serverAddressInputBox.value);
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"id": "matrixworldjoin",
|
||||
"label": global.locales.getRawString(global.currentLanguage, "play.multiplayer.loadmatrixworldsbutton.label"),
|
||||
"disabled": true,
|
||||
"action": "run",
|
||||
"runnable": function (event) {
|
||||
for (var e = module.exports.menus["serversel"].elements.length - 1; e >= 0; e--) {
|
||||
var menuElement = module.exports.menus["serversel"].elements[e];
|
||||
|
||||
if (("classes" in menuElement) && menuElement.classes.indexOf("mxworldjoinbtn") > -1) module.exports.menus["serversel"].elements.splice(e, 1);
|
||||
}
|
||||
|
||||
var matrixWorldRooms = getWorldRooms();
|
||||
|
||||
for (var r = 0; r < matrixWorldRooms.length; r++) {
|
||||
var matrixWorldRoom = matrixWorldRooms[r];
|
||||
|
||||
var menuEntry = {
|
||||
"type": "button",
|
||||
"label": global.locales.getFormattedString(
|
||||
global.currentLanguage,
|
||||
"play.singleplayer.openworld.label",
|
||||
{
|
||||
"WORLD_NAME": matrixWorldRoom.name
|
||||
}
|
||||
),
|
||||
"action": "run",
|
||||
"runnable": (function (event) {
|
||||
syncWorldFromMatrixRoom(this).then((function (world) {
|
||||
global.worlds[this.name] = world;
|
||||
global.startGame(0, this.name);
|
||||
}).bind(this)).catch(global.throwError);
|
||||
|
||||
global.menu.hideMenus(0);
|
||||
}).bind(matrixWorldRoom),
|
||||
"classes": [
|
||||
"mxworldjoinbtn"
|
||||
]
|
||||
};
|
||||
|
||||
module.exports.menus["serversel"].elements.push(menuEntry);
|
||||
}
|
||||
|
||||
global.menu.hideMenus(2);
|
||||
|
||||
global.menu.menus["serversel"] = global.menu.constructMenu("serversel", module.exports.menus["serversel"]);
|
||||
|
||||
global.menu.showMenu("serversel", 2);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
37
modules/render.js
Normal file
37
modules/render.js
Normal file
@ -0,0 +1,37 @@
|
||||
class Renderer extends global.three.WebGLRenderer {
|
||||
constructor (options = {}) {
|
||||
super(options);
|
||||
|
||||
// if (options.autoResize) this.autoResize = options.autoResize;
|
||||
// if (options.noAutoResize) this.autoResize = false;
|
||||
//
|
||||
// if (this.domElement && this.domElement.parentElement) {
|
||||
// this.domElement.parentElement.addEventListener("resize", function (event) {
|
||||
// if (this.autoResize) this.setSize(this.domElement.clientWidth, this.domElement.clientHeight);
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
class PerspectiveCamera extends global.three.PerspectiveCamera {
|
||||
constructor (...options) {
|
||||
super(...options);
|
||||
}
|
||||
get fieldOfView () {
|
||||
return this.fov;
|
||||
}
|
||||
set fieldOfView (value) {
|
||||
this.fov = value;
|
||||
|
||||
this.updateProjectionMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
"Renderer": Renderer,
|
||||
"PerspectiveCamera": PerspectiveCamera
|
||||
};
|
||||
|
||||
global.core.on("pre-init", function () {
|
||||
global.core.emit("render-init");
|
||||
});
|
169
modules/resources.js
Normal file
169
modules/resources.js
Normal file
@ -0,0 +1,169 @@
|
||||
class ResourcePack {
|
||||
constructor (data) {
|
||||
this.name = data.name;
|
||||
this.description = data.description;
|
||||
|
||||
this.meta = data.meta;
|
||||
|
||||
this.models = data.models || new global.Map();
|
||||
this.textures = data.textures || new global.Map();
|
||||
this.sounds = new global.Map();
|
||||
}
|
||||
static loadFromZIP (zipBuffer) {
|
||||
if (!zipBuffer) return Promise.reject(new Error("Missing argument zipBuffer. "));
|
||||
return new Promise(function (resolve, reject) {
|
||||
global.fflate.unzip(new Uint8Array(zipBuffer), {}, function (error, data) {
|
||||
if (error) return reject(error);
|
||||
if (!data["pack.json"]) return reject(new Error("pack.json not found in zip file. "));
|
||||
|
||||
let packMeta;
|
||||
try {
|
||||
packMeta = JSON.parse(global.fflate.strFromU8(data["pack.json"]));
|
||||
} catch (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
var packData = readPackMeta(packMeta, data);
|
||||
|
||||
packData.meta = packMeta;
|
||||
|
||||
var resourceLoadings = [];
|
||||
|
||||
resourceLoadings.push(loadU8Textures(packMeta, data).then(function (textureMap) {
|
||||
packData.textures = textureMap;
|
||||
}).catch(reject));
|
||||
|
||||
resourceLoadings.push(loadU8Models(packMeta, data).then(function (modelMap) {
|
||||
packData.models = modelMap;
|
||||
}).catch(reject));
|
||||
|
||||
Promise.all(resourceLoadings).then(function () {
|
||||
var resourcePack = new ResourcePack(packData);
|
||||
|
||||
global.core.emit("resourcepack-load", resourcePack);
|
||||
|
||||
resolve(resourcePack);
|
||||
}).catch(reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var readPackMeta = function (packMeta, packArchive) {
|
||||
var pack = {
|
||||
"name": packMeta.name,
|
||||
"description": packMeta.description
|
||||
};
|
||||
|
||||
return pack;
|
||||
};
|
||||
|
||||
var loadU8Textures = function (packMeta, packData) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var textureMap = new global.Map();
|
||||
|
||||
var textureLoadings = [];
|
||||
|
||||
var textureMeta = packMeta.textures;
|
||||
|
||||
for (var textureName in textureMeta) {
|
||||
if (textureMeta.hasOwnProperty(textureName)) {
|
||||
var textureData = textureMeta[textureName];
|
||||
|
||||
if (textureData.path) {
|
||||
var splitPath = textureData.path.split(/[\/\.]+/g);
|
||||
|
||||
var extension = splitPath[splitPath.length - 1].toLowerCase();
|
||||
if (extension == "jpg") extension = "jpeg";
|
||||
|
||||
if ((["png", "jpeg", "webp", "gif", "apng", "avif"]).indexOf(extension) > -1) {
|
||||
var type = "image";
|
||||
} else if ((["mp4", "mkv", "ogg", "webm"]).indexOf(extension) > -1) {
|
||||
var type = "video";
|
||||
}
|
||||
|
||||
var mimeType = type + "/" + extension;
|
||||
|
||||
if (!packData[textureData.path]) reject(new Error("Texture doesn't exist at " + textureData.path + ". "));
|
||||
|
||||
var textureBind = {
|
||||
"name": textureName
|
||||
};
|
||||
|
||||
textureLoadings.push(new Promise((function(res, rej) {
|
||||
var imageData = packData[textureData.path];
|
||||
|
||||
var imageBlob = new Blob([imageData.buffer], {"type": mimeType});
|
||||
|
||||
var imageObjectURL = URL.createObjectURL(imageBlob);
|
||||
|
||||
var texture = new global.three.Texture();
|
||||
var image = new global.Image();
|
||||
|
||||
texture.minFilter = global.three.NearestFilter;
|
||||
texture.magFilter = global.three.NearestFilter;
|
||||
|
||||
image.onload = (function () {
|
||||
texture.image = image;
|
||||
texture.needsUpdate = true;
|
||||
|
||||
var data = {
|
||||
"map": texture
|
||||
};
|
||||
|
||||
textureMap.set(this.name, data);
|
||||
|
||||
res(data);
|
||||
}).bind(textureBind);
|
||||
|
||||
image.src = imageObjectURL;
|
||||
}).bind(textureBind)));
|
||||
} else if (textureData.texture) {
|
||||
var data = {
|
||||
|
||||
};
|
||||
|
||||
textureMap.set(textureName, data);
|
||||
|
||||
textureLoadings.push(Promise.resolve(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(textureLoadings).then(function (textures) {
|
||||
resolve(textureMap);
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
var loadU8Models = function (packMeta, packData) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var modelMap = new global.Map();
|
||||
|
||||
var modelLoadings = [];
|
||||
|
||||
var modelMeta = packMeta.models;
|
||||
|
||||
for (var modelName in modelMeta) {
|
||||
if (modelMeta.hasOwnProperty(modelName)) {
|
||||
var modelData = modelMeta[modelName];
|
||||
|
||||
var modelString = global.fflate.strFromU8(packData[modelData.path]);
|
||||
|
||||
var modelJSON = JSON.parse(modelString);
|
||||
|
||||
modelMap.set(modelName, modelJSON);
|
||||
|
||||
modelLoadings.push(Promise.resolve(modelJSON));
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(modelLoadings).then(function (models) {
|
||||
resolve(modelMap);
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"ResourcePack": ResourcePack
|
||||
};
|
832
modules/world.js
Normal file
832
modules/world.js
Normal file
@ -0,0 +1,832 @@
|
||||
var neighborData = [
|
||||
{
|
||||
"position": [-1, 0, 0],
|
||||
"corners": [
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0],
|
||||
[0, 1, 0, 0, 1],
|
||||
[0, 1, 1, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [1, 0, 0],
|
||||
"corners": [
|
||||
[1, 0, 1, 0, 0],
|
||||
[1, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 1],
|
||||
[1, 1, 0, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, -1, 0],
|
||||
"corners": [
|
||||
[0, 0, 0, 0, 1],
|
||||
[1, 0, 0, 1, 1],
|
||||
[0, 0, 1, 0, 0],
|
||||
[1, 0, 1, 1, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, 1, 0],
|
||||
"corners": [
|
||||
[0, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 0],
|
||||
[0, 1, 0, 0, 1],
|
||||
[1, 1, 0, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, 0, -1],
|
||||
"corners": [
|
||||
[1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0],
|
||||
[1, 1, 0, 0, 1],
|
||||
[0, 1, 0, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, 0, 1],
|
||||
"corners": [
|
||||
[0, 0, 1, 0, 0],
|
||||
[1, 0, 1, 1, 0],
|
||||
[0, 1, 1, 0, 1],
|
||||
[1, 1, 1, 1, 1]
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var timePalette = {
|
||||
"21600": 0x081632, // Marine Blue (#081632)
|
||||
"25200": 0xFF7656,
|
||||
"28800": 0xBDE4F5,
|
||||
"61200": 0xBDE4F5,
|
||||
"64800": 0xFA88AF,
|
||||
"68400": 0x081632
|
||||
};
|
||||
|
||||
var textureData = {
|
||||
"resolution": [16, 16],
|
||||
"size": [256, 256],
|
||||
"textures": {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class World extends global.three.Scene {
|
||||
constructor (parameters) {
|
||||
super();
|
||||
|
||||
this.generator = parameters.generator || "flat";
|
||||
|
||||
this.chunks = new global.Map();
|
||||
this.chunkSize = parameters.chunkSize || [16, 16, 16];
|
||||
|
||||
this.background = new global.three.Color(0xBDE4F5);
|
||||
|
||||
this.ambientLight = new global.three.AmbientLight(0xFFFFFF, 1);
|
||||
this.directionalLight = new global.three.DirectionalLight(0xFFFFFF, 1);
|
||||
|
||||
this.directionalLight.position.set(1, 1, 1);
|
||||
|
||||
this.add(this.ambientLight);
|
||||
this.add(this.directionalLight);
|
||||
|
||||
this.worker = new global.Worker("./modules/world_worker.js");
|
||||
|
||||
this.callbackObjects = {};
|
||||
|
||||
global.core.on("resourcepack-load", (function (pack) {
|
||||
var textureData = {
|
||||
"resolution": pack.meta.textures["block-atlas"].size,
|
||||
"size": pack.meta.textures["block-atlas"].totalSize,
|
||||
"textures": pack.meta.textures
|
||||
};
|
||||
|
||||
this.worker.postMessage({
|
||||
"command": "config",
|
||||
"arguments": {
|
||||
"textureData": textureData
|
||||
}
|
||||
});
|
||||
|
||||
this.chunks.forEach((chunk, chunkID) => {
|
||||
chunk.material.map = pack.textures.get("block-atlas").map;
|
||||
});
|
||||
}).bind(this));
|
||||
|
||||
var resourcePackNames = Object.keys(global.resourcePacks);
|
||||
if (resourcePackNames.length > 0) {
|
||||
var pack = global.resourcePacks[resourcePackNames[0]];
|
||||
|
||||
var textureData = {
|
||||
"resolution": pack.meta.textures["block-atlas"].size,
|
||||
"size": pack.meta.textures["block-atlas"].totalSize,
|
||||
"textures": pack.meta.textures
|
||||
};
|
||||
|
||||
this.worker.postMessage({
|
||||
"command": "config",
|
||||
"arguments": {
|
||||
"world": {
|
||||
"chunkSize": this.chunkSize
|
||||
},
|
||||
"textureData": textureData
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.worker.postMessage({
|
||||
"command": "create-world",
|
||||
"arguments": {
|
||||
"uuid": this.uuid
|
||||
}
|
||||
});
|
||||
|
||||
this.worker.onmessage = (function (message) {
|
||||
var event = message.data["event"];
|
||||
var data = message.data["data"];
|
||||
|
||||
var callbackID = data["callbackID"];
|
||||
|
||||
var callbackObject = this.callbackObjects[callbackID];
|
||||
|
||||
switch (event) {
|
||||
case "generated":
|
||||
var newChunk = new Chunk(this.chunkSize, this);
|
||||
|
||||
for (var b = 0; b < data.blocks.length; b++) {
|
||||
var block = data.blocks[b];
|
||||
|
||||
if (!block) continue;
|
||||
newChunk.blocks[b] = block;
|
||||
}
|
||||
|
||||
this.setChunk(newChunk, callbackObject.position);
|
||||
callbackObject.resolve(newChunk);
|
||||
break;
|
||||
case "constructed":
|
||||
var properties = data.properties;
|
||||
var chunk = callbackObject.chunk;
|
||||
|
||||
chunk.geometry.setAttribute("position", new global.three.Float32BufferAttribute(properties["positions"], 3));
|
||||
chunk.geometry.setAttribute("normal", new global.three.Float32BufferAttribute(properties["normals"], 3));
|
||||
chunk.geometry.setAttribute("uv", new global.three.Float32BufferAttribute(properties["uvs"], 2));
|
||||
chunk.geometry.setIndex(properties["indexes"]);
|
||||
chunk.geometry.computeBoundingSphere();
|
||||
|
||||
var resourcePackNames = Object.keys(global.resourcePacks);
|
||||
if (resourcePackNames.length > 0) {
|
||||
var pack = global.resourcePacks[resourcePackNames[0]];
|
||||
|
||||
chunk.material.map = pack.textures.get("block-atlas").map;
|
||||
}
|
||||
|
||||
// this.worker.postMessage({
|
||||
// "command": "set-body",
|
||||
// "arguments": {
|
||||
// "uuid": chunk.uuid,
|
||||
// "position": [
|
||||
// chunk.position.x,
|
||||
// chunk.position.y,
|
||||
// chunk.position.z
|
||||
// ],
|
||||
// "shape": {
|
||||
// "vertices": chunk.geometry.attributes["position"].array,
|
||||
// "indices": chunk.geometry.index.array
|
||||
// },
|
||||
// "type": "static"
|
||||
// }
|
||||
// });
|
||||
|
||||
callbackObject.resolve(chunk);
|
||||
break;
|
||||
case "simulation-stepped":
|
||||
for (var uuid in data.updates) {
|
||||
if (data.updates.hasOwnProperty(uuid)) {
|
||||
var meshUpdate = data.updates[uuid];
|
||||
|
||||
var mesh = this.children.find(function (m) {
|
||||
return m.uuid === uuid;
|
||||
});
|
||||
|
||||
if (!mesh) continue;
|
||||
|
||||
mesh.position.set(
|
||||
meshUpdate.position[0],
|
||||
meshUpdate.position[1],
|
||||
meshUpdate.position[2]
|
||||
);
|
||||
|
||||
mesh.quaternion.set(
|
||||
meshUpdate.quaternion[0],
|
||||
meshUpdate.quaternion[1],
|
||||
meshUpdate.quaternion[2],
|
||||
meshUpdate.quaternion[3]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
callbackObject.resolve(data.updates);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}).bind(this);
|
||||
}
|
||||
addChunk (chunk) {
|
||||
if (!chunk) return new Error("First argument is not a chunk. ");
|
||||
if (!(chunk instanceof Chunk)) return new Error("First argument is not an instance of Chunk. ");
|
||||
|
||||
this.add(chunk);
|
||||
|
||||
var blockIndices = [];
|
||||
|
||||
for (var b = 0; b < chunk.blocks.length; b++) {
|
||||
if (chunk.blocks[b]) blockIndices.push(b);
|
||||
}
|
||||
|
||||
// this.worker.postMessage({
|
||||
// "command": "put-voxels",
|
||||
// "arguments": {
|
||||
// "worldUUID": this.uuid,
|
||||
// "chunkUUID": chunk.uuid,
|
||||
// "chunkPosition": chunk.position,
|
||||
// "indices": blockIndices
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
return chunk;
|
||||
}
|
||||
setChunk (chunk, position) {
|
||||
if (!chunk) return new Error("First argument is not a chunk. ");
|
||||
if (!(chunk instanceof Chunk)) return new Error("First argument is not an instance of Chunk. ");
|
||||
if (!position) return new Error("Second argument is not a position. ");
|
||||
|
||||
var worldPosition = [
|
||||
this.chunkSize[0] * position[0],
|
||||
this.chunkSize[1] * position[1],
|
||||
this.chunkSize[2] * position[2]
|
||||
];
|
||||
|
||||
if (this.chunks.has(position.join(":"))) {
|
||||
var oldChunk = this.chunks.get(position.join(":"));
|
||||
|
||||
var voxelIndices = [];
|
||||
|
||||
for (var b = 0; b < oldChunk.blocks.length; b++) {
|
||||
if (oldChunk.blocks[b]) voxelIndices.push(b);
|
||||
}
|
||||
|
||||
// this.worker.postMessage({
|
||||
// "command": "remove-voxels",
|
||||
// "arguments": {
|
||||
// "worldUUID": this.uuid,
|
||||
// "chunkUUID": oldChunk.uuid
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
var blockIndices = [];
|
||||
|
||||
for (var b = 0; b < chunk.blocks.length; b++) {
|
||||
if (chunk.blocks[b]) blockIndices.push(b);
|
||||
}
|
||||
|
||||
// this.worker.postMessage({
|
||||
// "command": "put-voxels",
|
||||
// "arguments": {
|
||||
// "worldUUID": this.uuid,
|
||||
// "chunkUUID": chunk.uuid,
|
||||
// "chunkPosition": position,
|
||||
// "indices": blockIndices
|
||||
// }
|
||||
// });
|
||||
|
||||
chunk.position.set(
|
||||
worldPosition[0],
|
||||
worldPosition[1],
|
||||
worldPosition[2]
|
||||
);
|
||||
|
||||
// this.worker.postMessage({
|
||||
// "command": "set-body",
|
||||
// "arguments": {
|
||||
// "uuid": chunk.uuid,
|
||||
// "position": worldPosition
|
||||
// }
|
||||
// });
|
||||
|
||||
return this.chunks.set(position.join(":"), chunk);
|
||||
}
|
||||
addEntity (entity) {
|
||||
if (!entity) return new Error("First argument is not an entity. ");
|
||||
if (!(entity instanceof Entity)) return new Error("First argument is not an instance of Entity. ");
|
||||
|
||||
this.add(entity);
|
||||
|
||||
this.worker.postMessage({
|
||||
"command": "add-body",
|
||||
"arguments": {
|
||||
"worldUUID": this.uuid,
|
||||
"bodyUUID": entity.uuid,
|
||||
"type": "dynamic"
|
||||
}
|
||||
});
|
||||
|
||||
return entity;
|
||||
}
|
||||
removeChunk (position) {
|
||||
if (!position) return new Error("First argument is not a position. ");
|
||||
|
||||
if (this.chunks.has(position.join(":"))) return this.chunks.delete(position.join(":"));
|
||||
return false;
|
||||
}
|
||||
generateChunk (position, data) {
|
||||
return new Promise((function (resolve, reject) {
|
||||
var callbackID = "G" + Math.round(Math.random() * 65536);
|
||||
|
||||
this.callbackObjects[callbackID] = {
|
||||
"position": position,
|
||||
"resolve": resolve,
|
||||
"reject": reject
|
||||
};
|
||||
|
||||
this.worker.postMessage({
|
||||
"command": "generate",
|
||||
"arguments": {
|
||||
"callbackID": callbackID,
|
||||
"position": position,
|
||||
"generator": this.generator
|
||||
}
|
||||
});
|
||||
}).bind(this));
|
||||
}
|
||||
constructChunk (position) {
|
||||
return new Promise((function (resolve, reject) {
|
||||
var callbackID = "C" + Math.round(Math.random() * 65536);
|
||||
|
||||
this.callbackObjects[callbackID] = {
|
||||
"chunk": this.chunks.get(position.join(":")),
|
||||
"position": position,
|
||||
"resolve": resolve,
|
||||
"reject": reject
|
||||
};
|
||||
|
||||
var neighbors = [];
|
||||
|
||||
for (var n = 0; n < neighborData.length; n++) {
|
||||
var neighborPosition = addPositions(position, neighborData[n].position);
|
||||
var neighborKey = neighborPosition.join(":");
|
||||
|
||||
if (this.chunks.has(neighborKey)) {
|
||||
neighbors.push(this.chunks.get(neighborKey).toJSON());
|
||||
} else {
|
||||
neighbors.push(null);
|
||||
}
|
||||
}
|
||||
|
||||
this.worker.postMessage({
|
||||
"command": "construct",
|
||||
"arguments": {
|
||||
"callbackID": callbackID,
|
||||
"position": position,
|
||||
"chunk": this.chunks.get(position.join(":")).toJSON(),
|
||||
"neighbors": neighbors
|
||||
}
|
||||
});
|
||||
}).bind(this));
|
||||
}
|
||||
stepSimulation (delta) {
|
||||
return new Promise((function (resolve, reject) {
|
||||
var callbackID = "C" + Math.round(Math.random() * 65536);
|
||||
|
||||
this.callbackObjects[callbackID] = {
|
||||
"resolve": resolve,
|
||||
"reject": reject
|
||||
};
|
||||
|
||||
this.worker.postMessage({
|
||||
"command": "step-simulation",
|
||||
"arguments": {
|
||||
"callbackID": callbackID,
|
||||
"uuid": this.uuid,
|
||||
"delta": delta
|
||||
}
|
||||
});
|
||||
}).bind(this));
|
||||
}
|
||||
toJSON () {
|
||||
var chunksObject = {};
|
||||
|
||||
this.chunks.forEach(function (value, key) {
|
||||
chunksObject[key] = value;
|
||||
});
|
||||
|
||||
return {
|
||||
"generator": this.generator,
|
||||
"chunks": chunksObject
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Chunk extends global.three.Mesh {
|
||||
constructor (size = [16, 16, 16], world) {
|
||||
super(
|
||||
new global.three.BufferGeometry(),
|
||||
new global.three.MeshStandardMaterial({
|
||||
"side": global.three.DoubleSide,
|
||||
"transparent": true,
|
||||
"alphaTest": 0.5
|
||||
})
|
||||
);
|
||||
|
||||
this._size = size;
|
||||
this.blocks = new global.Array(size[0] * size[1] * size[2]);
|
||||
|
||||
if (world instanceof World) {
|
||||
this.world = world;
|
||||
// world.worker.postMessage({
|
||||
// "command": "create-body",
|
||||
// "arguments": {
|
||||
// "uuid": this.uuid,
|
||||
// "type": "static"
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
get size () {
|
||||
return this._size;
|
||||
}
|
||||
setBlock (position, block) {
|
||||
if (!position) return new Error("First argument is not a position. ");
|
||||
if (!block) return new Error("Second argument is not a block. ");
|
||||
if (!(block instanceof Block)) return new Error("Second argument is not an instance of Block. ");
|
||||
|
||||
var blockIndex = computeBlockIndex(this.size, position);
|
||||
|
||||
if (this.world) {
|
||||
// this.world.worker.postMessage({
|
||||
// "command": "remove-body",
|
||||
// "arguments": {
|
||||
// "uuid": this.uuid + ";" + position.join(":")
|
||||
// }
|
||||
// });
|
||||
if (!this.blocks[blockIndex]) {
|
||||
this.world.worker.postMessage({
|
||||
"command": "create-body",
|
||||
"arguments": {
|
||||
"uuid": this.uuid + ";" + blockIndex,
|
||||
"type": "static",
|
||||
"position": [
|
||||
this.position.x + position[0],
|
||||
this.position.y + position[1],
|
||||
this.position.z + position[2],
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.blocks[blockIndex] = block;
|
||||
}
|
||||
removeBlock (position) {
|
||||
if (!position) return new Error("First argument is not a position. ");
|
||||
|
||||
var blockIndex = computeBlockIndex(this.size, position);
|
||||
|
||||
delete this.blocks[blockIndex];
|
||||
|
||||
if (this.world) {
|
||||
this.world.worker.postMessage({
|
||||
"command": "remove-body",
|
||||
"arguments": {
|
||||
"worldUUID": this.world.uuid,
|
||||
"bodyUUID": this.uuid + ";" + blockIndex
|
||||
}
|
||||
});
|
||||
this.world.worker.postMessage({
|
||||
"command": "destroy-body",
|
||||
"arguments": {
|
||||
"uuid": this.uuid + ";" + blockIndex
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
toJSON () {
|
||||
return {
|
||||
"size": this.size,
|
||||
"blocks": this.blocks
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Block extends global.Array {
|
||||
constructor (type, data = {}) {
|
||||
super();
|
||||
|
||||
if (!type) return new Error("Block type must be non-null. ");
|
||||
this[0] = type;
|
||||
this[1] = new global.Map();
|
||||
|
||||
for (var key in data) {
|
||||
if (data.hasOwnProperty(key)) {
|
||||
var value = data[key];
|
||||
|
||||
this[1].set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
get type () {
|
||||
return this[0];
|
||||
}
|
||||
get tags () {
|
||||
return this[1];
|
||||
}
|
||||
setTagValue (tag, value) {
|
||||
return this[1].set(tag, value);
|
||||
}
|
||||
removeTagValue (tag) {
|
||||
if (this[1].has(tag)) return this[1].delete(tag);
|
||||
return false;
|
||||
}
|
||||
toJSON () {
|
||||
var tagsObject = {};
|
||||
|
||||
this[1].forEach(function (value, key) {
|
||||
tagsObject[key] = value;
|
||||
});
|
||||
|
||||
return {
|
||||
"type": this[0],
|
||||
"tags": tagsObject
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Entity extends global.three.Mesh {
|
||||
constructor (type, world) {
|
||||
super(
|
||||
new global.three.BoxBufferGeometry(0.8, 0.8, 0.8),
|
||||
new global.three.MeshStandardMaterial({
|
||||
"side": global.three.DoubleSide,
|
||||
"transparent": true,
|
||||
"alphaTest": 0.5,
|
||||
"opacity": 0.0,
|
||||
"wireframe": true
|
||||
})
|
||||
);
|
||||
|
||||
this.type = type;
|
||||
this.parts = {};
|
||||
|
||||
this._texture = null;
|
||||
|
||||
for (var p = 0; p < global.resourcePacks.length; p++) {
|
||||
var pack = global.resourcePacks[p];
|
||||
|
||||
if (pack.models.has(this.type) && Object.keys(this.parts).length < 1) {
|
||||
this.model = pack.models.get(this.type);
|
||||
}
|
||||
if (pack.textures.has(this.type) && !this.material.map) {
|
||||
this.texture = pack.textures.get(this.type).map;
|
||||
}
|
||||
}
|
||||
|
||||
if (world instanceof World) {
|
||||
world.worker.postMessage({
|
||||
"command": "create-body",
|
||||
"arguments": {
|
||||
"uuid": this.uuid,
|
||||
"mass": 16,
|
||||
"shape": {
|
||||
"vertices": this.geometry.attributes["position"].array,
|
||||
"indices": this.geometry.index.array
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
get texture () {
|
||||
if (this._texture) return this._texture;
|
||||
|
||||
for (var partName in this.parts) {
|
||||
if (this.parts.hasOwnProperty(partName)) {
|
||||
var part = this.parts[partName];
|
||||
|
||||
if (!part.material || !part.material.map) continue;
|
||||
return part.material.map;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
set texture (texture) {
|
||||
this._texture = texture;
|
||||
|
||||
for (var partName in this.parts) {
|
||||
if (this.parts.hasOwnProperty(partName)) {
|
||||
var part = this.parts[partName];
|
||||
|
||||
if (part.isGroup) continue;
|
||||
|
||||
part.material.map = texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
set model (model) {
|
||||
this.geometry = new global.three.BoxBufferGeometry(
|
||||
model.hitbox[0],
|
||||
model.hitbox[1],
|
||||
model.hitbox[2]
|
||||
);
|
||||
|
||||
for (var partName in model.parts) {
|
||||
if (model.parts.hasOwnProperty(partName)) {
|
||||
var part = model.parts[partName];
|
||||
|
||||
let partObject;
|
||||
|
||||
switch (part.type) {
|
||||
case "group":
|
||||
partObject = new global.three.Group();
|
||||
break;
|
||||
case "geometry":
|
||||
partObject = new global.three.Mesh(
|
||||
new global.three.BoxBufferGeometry(
|
||||
part.geometry[0],
|
||||
part.geometry[1],
|
||||
part.geometry[2]
|
||||
),
|
||||
new global.three.MeshStandardMaterial({
|
||||
"side": global.three.FrontSide,
|
||||
"transparent": true,
|
||||
"alphaTest": 0.5,
|
||||
"map": this.texture
|
||||
})
|
||||
);
|
||||
|
||||
if ("uvMap" in part) {
|
||||
var uvArray = partObject.geometry.attributes["uv"].array;
|
||||
|
||||
for (var f = 0; f < part.uvMap.length; f++) {
|
||||
var faceMap = part.uvMap[f];
|
||||
|
||||
var firstUVIndex = f * 8;
|
||||
|
||||
uvArray[firstUVIndex + 0] = faceMap[0][0];
|
||||
uvArray[firstUVIndex + 1] = faceMap[1][1];
|
||||
uvArray[firstUVIndex + 2] = faceMap[1][0];
|
||||
uvArray[firstUVIndex + 3] = faceMap[1][1];
|
||||
uvArray[firstUVIndex + 4] = faceMap[0][0];
|
||||
uvArray[firstUVIndex + 5] = faceMap[0][1];
|
||||
uvArray[firstUVIndex + 6] = faceMap[1][0];
|
||||
uvArray[firstUVIndex + 7] = faceMap[0][1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
if (part.position) partObject.position.set(
|
||||
part.position[0],
|
||||
part.position[1],
|
||||
part.position[2]
|
||||
);
|
||||
|
||||
var modelPart = this.parts[partName] = partObject;
|
||||
}
|
||||
}
|
||||
|
||||
for (var partName in model.parts) {
|
||||
if (model.parts.hasOwnProperty(partName)) {
|
||||
var part = model.parts[partName];
|
||||
|
||||
if (part.children) {
|
||||
for (var c = 0; c < part.children.length; c++) {
|
||||
this.parts[partName].add(this.parts[part.children[c]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("root" in this.parts) this.add(this.parts["root"]);
|
||||
}
|
||||
setPosition (position) {
|
||||
this.position.set(
|
||||
position[0],
|
||||
position[1],
|
||||
position[2]
|
||||
);
|
||||
|
||||
if (this.parent instanceof World) {
|
||||
this.parent.worker.postMessage({
|
||||
"command": "set-body",
|
||||
"arguments": {
|
||||
"uuid": this.uuid,
|
||||
"position": position
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var computeBlockIndex = function (chunkSize, blockPosition) {
|
||||
var x = blockPosition[0] % chunkSize[0];
|
||||
var z = blockPosition[2] % chunkSize[2];
|
||||
var y = blockPosition[1] % chunkSize[1];
|
||||
|
||||
return (x * (chunkSize[1] * chunkSize[2])) + y + (z * chunkSize[1]);
|
||||
};
|
||||
|
||||
var computeBlockPosition = function (chunkSize, blockIndex) {
|
||||
var blockPosition = [0, 0, 0];
|
||||
var subtractedIndex = 0 + blockIndex;
|
||||
|
||||
blockPosition[1] = subtractedIndex % chunkSize[1];
|
||||
subtractedIndex -= blockPosition[1];
|
||||
|
||||
blockPosition[2] = (subtractedIndex / chunkSize[1]) % chunkSize[2];
|
||||
subtractedIndex -= blockPosition[2] * chunkSize[1];
|
||||
|
||||
blockPosition[0] = (subtractedIndex / (chunkSize[1] * chunkSize[2])) % chunkSize[0];
|
||||
subtractedIndex -= blockPosition[0] * chunkSize[0];
|
||||
|
||||
return blockPosition;
|
||||
};
|
||||
|
||||
var splitRGBComponents = function (hex) {
|
||||
var subtracted = hex;
|
||||
|
||||
var blue = hex % 0x100;
|
||||
subtracted -= blue;
|
||||
|
||||
var green = (subtracted / 0x100) % 0x100;
|
||||
subtracted -= subtracted * 0x100;
|
||||
|
||||
var red = (subtracted / 0x10000) % 0x100;
|
||||
subtracted -= subtracted * 0x10000;
|
||||
|
||||
return [red, green, blue];
|
||||
};
|
||||
|
||||
var computeTimeColor = function (palette, time) {
|
||||
var times = Object.keys(palette);
|
||||
if (times.length == 1) return palette[times[0]];
|
||||
|
||||
var seconds = ((time[0] * 3600) + (time[1] * 60) + time[2]);
|
||||
var timesBefore = times.filter(function (timeFloat) {
|
||||
return parseFloat(timeFloat) <= seconds;
|
||||
});
|
||||
var timesAfter = times.filter(function (timeFloat) {
|
||||
return parseFloat(timeFloat) > seconds;
|
||||
});
|
||||
let startTime, startTimeFloat;
|
||||
let endTime, endTimeFloat;
|
||||
if (timesBefore.length < 1) {
|
||||
startTime = times[times.length - 1];
|
||||
startTimeFloat = parseFloat(times[times.length - 1]) - (24 * 3600);
|
||||
}
|
||||
if (timesAfter.length < 1) {
|
||||
endTime = times[0];
|
||||
endTimeFloat = (24 * 3600) + parseFloat(times[0]);
|
||||
}
|
||||
|
||||
var startComponents = splitRGBComponents(palette[startTime]);
|
||||
var endComponents = splitRGBComponents(palette[endTime]);
|
||||
|
||||
var redDiff = endComponents[0] - startComponents[0];
|
||||
var greenDiff = endComponents[1] - startComponents[1];
|
||||
var blueDiff = endComponents[2] - startComponents[2];
|
||||
|
||||
progress = (seconds - startTimeFloat) / (endTimeFloat - startTimeFloat);
|
||||
|
||||
return (Math.round(startComponents[0] + (progress * redDiff)) * 65536)
|
||||
+ (Math.round((startComponents[1] + (progress * greenDiff))) * 256)
|
||||
+ Math.round(startComponents[2] + (progress * blueDiff));
|
||||
};
|
||||
|
||||
var addPositions = function (positionA, positionB) {
|
||||
var position = new Array(positionA.length);
|
||||
|
||||
for (var p = 0; p < position.length; p++) {
|
||||
position[p] = positionA[p] + positionB[p];
|
||||
}
|
||||
|
||||
return position;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"World": World,
|
||||
"Chunk": Chunk,
|
||||
"Block": Block,
|
||||
"Entity": Entity,
|
||||
"utils": {
|
||||
"computeBlockIndex": computeBlockIndex,
|
||||
"computeBlockPosition": computeBlockPosition,
|
||||
"splitRGBComponents": splitRGBComponents,
|
||||
"computeTimeColor": computeTimeColor,
|
||||
"addPositions": addPositions
|
||||
}
|
||||
};
|
772
modules/world_worker.js
Normal file
772
modules/world_worker.js
Normal file
@ -0,0 +1,772 @@
|
||||
importScripts("../lib/improved-noise.js");
|
||||
importScripts("../lib/cannon-es.js");
|
||||
importScripts("../lib/ammo.js");
|
||||
|
||||
var neighborData = [
|
||||
{
|
||||
"position": [-1, 0, 0],
|
||||
"corners": [
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0],
|
||||
[0, 1, 0, 0, 1],
|
||||
[0, 1, 1, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [1, 0, 0],
|
||||
"corners": [
|
||||
[1, 0, 1, 0, 0],
|
||||
[1, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 1],
|
||||
[1, 1, 0, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, -1, 0],
|
||||
"corners": [
|
||||
[0, 0, 0, 0, 1],
|
||||
[1, 0, 0, 1, 1],
|
||||
[0, 0, 1, 0, 0],
|
||||
[1, 0, 1, 1, 0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, 1, 0],
|
||||
"corners": [
|
||||
[0, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 0],
|
||||
[0, 1, 0, 0, 1],
|
||||
[1, 1, 0, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, 0, -1],
|
||||
"corners": [
|
||||
[1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0],
|
||||
[1, 1, 0, 0, 1],
|
||||
[0, 1, 0, 1, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
"position": [0, 0, 1],
|
||||
"corners": [
|
||||
[0, 0, 1, 0, 0],
|
||||
[1, 0, 1, 1, 0],
|
||||
[0, 1, 1, 0, 1],
|
||||
[1, 1, 1, 1, 1]
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
let worldConfig = {
|
||||
"chunkSize": [16, 16, 16]
|
||||
};
|
||||
|
||||
let textureData = {
|
||||
"resolution": [16, 16],
|
||||
"size": [256, 256],
|
||||
"blocks": {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var tasks = {
|
||||
"physics": {
|
||||
"running": false,
|
||||
"interval": setInterval(async function () {
|
||||
if (!tasks["physics"].running && (tasks["physics"].queue.length > 0)) {
|
||||
tasks["physics"].running = true;
|
||||
while (tasks["physics"].queue.length > 0) {
|
||||
tasks["physics"].queue[0].run(...tasks["physics"].queue[0].arguments);
|
||||
tasks["physics"].queue.splice(0, 1);
|
||||
}
|
||||
tasks["physics"].running = false;
|
||||
}
|
||||
}, 256),
|
||||
"queue": []
|
||||
}
|
||||
};
|
||||
|
||||
var ammoIsReady = false;
|
||||
|
||||
let world;
|
||||
|
||||
var worlds = {};
|
||||
|
||||
var bodies = {};
|
||||
|
||||
var onmessage = function (event) {
|
||||
var command = event.data["command"];
|
||||
var arguments = event.data["arguments"];
|
||||
|
||||
var callbackID = arguments["callbackID"];
|
||||
|
||||
switch (command) {
|
||||
case "config":
|
||||
if (arguments["world"]) worldConfig = arguments["world"];
|
||||
textureData = arguments["textureData"];
|
||||
break;
|
||||
case "generate":
|
||||
var generator = self.generators[arguments["generator"]];
|
||||
var data = arguments["data"];
|
||||
|
||||
if (!generator) return postMessage({
|
||||
"event": "generated",
|
||||
"data": {
|
||||
"callbackID": callbackID,
|
||||
"blocks": []
|
||||
}
|
||||
});
|
||||
|
||||
var position = arguments["position"];
|
||||
|
||||
var blocks = [];
|
||||
|
||||
var chunkWidth = worldConfig.chunkSize[0];
|
||||
var chunkHeight = worldConfig.chunkSize[1];
|
||||
var chunkDepth = worldConfig.chunkSize[2];
|
||||
|
||||
switch (generator.type) {
|
||||
case "stepped":
|
||||
for (var x = 0; x < chunkWidth; x++) {
|
||||
for (var z = 0; z < chunkDepth; z++) {
|
||||
for (var y = 0; y < chunkHeight; y++) {
|
||||
var block = generator.run([
|
||||
(position[0] * chunkWidth) + x,
|
||||
(position[1] * chunkHeight) + y,
|
||||
(position[2] * chunkDepth) + z
|
||||
], data, worldConfig.chunkSize);
|
||||
var blockIndex = computeBlockIndex(
|
||||
worldConfig.chunkSize,
|
||||
[
|
||||
x,
|
||||
y,
|
||||
z
|
||||
]
|
||||
);
|
||||
|
||||
if (block) blocks[blockIndex] = block;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "full":
|
||||
var blocks = generator.run(position, data, worldConfig.chunkSize);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
postMessage({
|
||||
"event": "generated",
|
||||
"data": {
|
||||
"callbackID": callbackID,
|
||||
"blocks": blocks
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "construct":
|
||||
var chunk = arguments["chunk"];
|
||||
var neighbors = arguments["neighbors"];
|
||||
|
||||
postMessage({
|
||||
"event": "constructed",
|
||||
"data": {
|
||||
"callbackID": callbackID,
|
||||
"properties": construct(chunk, neighbors)
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "create-world":
|
||||
// worlds[arguments["uuid"]] = new CANNON.World({
|
||||
// "allowSleep": arguments["allowSleep"] || true,
|
||||
// "gravity": ("gravity" in arguments) ? new CANNON.Vec3(
|
||||
// arguments["gravity"][0],
|
||||
// arguments["gravity"][1],
|
||||
// arguments["gravity"][2]
|
||||
// ) : new CANNON.Vec3(0, -9.82, 0),
|
||||
// "solver": new CANNON.GSSolver()
|
||||
// });
|
||||
|
||||
var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
|
||||
var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
|
||||
var overlappingPairCache = new Ammo.btDbvtBroadphase();
|
||||
var solver = new Ammo.btSequentialImpulseConstraintSolver();
|
||||
|
||||
world = new Ammo.btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
|
||||
world.setGravity(new Ammo.btVector3(0, -9.82, 0));
|
||||
|
||||
postMessage({
|
||||
"event": "world-created",
|
||||
"data": {
|
||||
"callbackID": callbackID
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "create-body":
|
||||
let bodyType;
|
||||
|
||||
switch (arguments["type"]) {
|
||||
case "dynamic":
|
||||
bodyType = CANNON.Body.DYNAMIC;
|
||||
break;
|
||||
case "static":
|
||||
bodyType = CANNON.Body.STATIC;
|
||||
break;
|
||||
case "kinematic":
|
||||
bodyType = CANNON.Body.KINEMATIC;
|
||||
break;
|
||||
default:
|
||||
bodyType = CANNON.Body.DYNAMIC;
|
||||
}
|
||||
|
||||
var bodyOptions = {
|
||||
"allowSleep": arguments["allowSleep"] || true,
|
||||
"fixedRotation": arguments["fixedRotation"] || false,
|
||||
"mass": arguments["mass"] || 0,
|
||||
"position": ("position" in arguments) ? new CANNON.Vec3(
|
||||
arguments["position"][0],
|
||||
arguments["position"][1],
|
||||
arguments["position"][2]
|
||||
) : new CANNON.Vec3(0, 0, 0),
|
||||
"quaternion": ("quaternion" in arguments) ? new CANNON.Quaternion(
|
||||
arguments["quaternion"][0],
|
||||
arguments["quaternion"][1],
|
||||
arguments["quaternion"][2],
|
||||
arguments["quaternion"][3]
|
||||
) : new CANNON.Quaternion(0, 0, 0, 1),
|
||||
"type": bodyType,
|
||||
"material": new CANNON.Material()
|
||||
/*"shape": ("shape" in arguments) ? new CANNON.ConvexPolyhedron({
|
||||
"vertices": (function (positions) {
|
||||
var vertices = [];
|
||||
|
||||
for (var v = 0; v < (positions.length / 3); v++) {
|
||||
var vertexOffset = v * 3;
|
||||
|
||||
vertices[v] = new CANNON.Vec3(
|
||||
positions[vertexOffset + 0],
|
||||
positions[vertexOffset + 1],
|
||||
positions[vertexOffset + 2]
|
||||
);
|
||||
}
|
||||
|
||||
return vertices;
|
||||
})(arguments["shape"].vertices),
|
||||
"faces": (function (indices) {
|
||||
var faces = [];
|
||||
|
||||
for (var f = 0; f < (indices.length / 3); f++) {
|
||||
var faceOffset = f * 3;
|
||||
|
||||
faces[f] = indices.slice(faceOffset, faceOffset + 3);
|
||||
}
|
||||
|
||||
return faces;
|
||||
})(arguments["shape"].indices)
|
||||
}) : new CANNON.Box(new CANNON.Vec3(1, 1, 1))*/
|
||||
};
|
||||
|
||||
var shape = ("shape" in arguments) ? new CANNON.Trimesh(
|
||||
arguments["shape"].vertices,
|
||||
arguments["shape"].indices
|
||||
) : new CANNON.Box(new CANNON.Vec3(1, 1, 1));
|
||||
|
||||
postMessage({
|
||||
"event": "body-created",
|
||||
"data": {
|
||||
"callbackID": callbackID
|
||||
}
|
||||
});
|
||||
|
||||
bodies[arguments["uuid"]] = (shape instanceof CANNON.Trimesh) ? trimeshToPolyhedron(bodyOptions, shape) : new CANNON.Body(bodyOptions);
|
||||
|
||||
if (shape instanceof CANNON.Box) bodies[arguments["uuid"]].addShape(shape);
|
||||
|
||||
bodies[arguments["uuid"]].uuid = arguments["uuid"];
|
||||
|
||||
break;
|
||||
case "set-body":
|
||||
if ("shape" in arguments) {
|
||||
var convexPolyhedronBody = trimeshToPolyhedron({}, new CANNON.Trimesh(
|
||||
arguments["shape"].vertices,
|
||||
arguments["shape"].indices
|
||||
));
|
||||
|
||||
for (var s = bodies[arguments["uuid"]].shapes.length - 1; s >= 0; s--) {
|
||||
bodies[arguments["uuid"]].removeShape(bodies[arguments["uuid"]].shapes[s]);
|
||||
}
|
||||
|
||||
for (var s = 0; s < convexPolyhedronBody.shapes.length; s++) {
|
||||
bodies[arguments["uuid"]].addShape(convexPolyhedronBody.shapes[s]);
|
||||
}
|
||||
|
||||
bodies[arguments["uuid"]].updateBoundingRadius();
|
||||
bodies[arguments["uuid"]].updateAABB();
|
||||
/*bodies[arguments["uuid"]].shapes[0] = new CANNON.ConvexPolyhedron({
|
||||
"vertices": (function (positions) {
|
||||
var vertices = [];
|
||||
|
||||
for (var v = 0; v < (positions.length / 3); v++) {
|
||||
var vertexOffset = v * 3;
|
||||
|
||||
vertices[v] = new CANNON.Vec3(
|
||||
positions[vertexOffset + 0],
|
||||
positions[vertexOffset + 1],
|
||||
positions[vertexOffset + 2]
|
||||
);
|
||||
}
|
||||
|
||||
return vertices;
|
||||
})(arguments["shape"].vertices),
|
||||
"faces": (function (indices) {
|
||||
var faces = [];
|
||||
|
||||
for (var f = 0; f < (indices.length / 3); f++) {
|
||||
var faceOffset = f * 3;
|
||||
|
||||
faces[f] = indices.slice(faceOffset, faceOffset + 3);
|
||||
}
|
||||
|
||||
return faces;
|
||||
})(arguments["shape"].indices)
|
||||
});*/
|
||||
}
|
||||
|
||||
if ("position" in arguments) {
|
||||
bodies[arguments["uuid"]].position.set(
|
||||
arguments["position"][0],
|
||||
arguments["position"][1],
|
||||
arguments["position"][2]
|
||||
);
|
||||
bodies[arguments["uuid"]].aabbNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if ("quaternion" in arguments) {
|
||||
bodies[arguments["uuid"]].quaternion.set(
|
||||
arguments["quaternion"][0],
|
||||
arguments["quaternion"][1],
|
||||
arguments["quaternion"][2],
|
||||
arguments["quaternion"][3]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "add-body":
|
||||
worlds[arguments["worldUUID"]].addBody(bodies[arguments["bodyUUID"]]);
|
||||
|
||||
postMessage({
|
||||
"event": "body-added",
|
||||
"data": {
|
||||
"callbackID": callbackID
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "step-simulation":
|
||||
worlds[arguments["uuid"]].step(arguments["delta"]);
|
||||
|
||||
var updates = {};
|
||||
|
||||
for (var b = 0; b < worlds[arguments["uuid"]].bodies.length; b++) {
|
||||
var body = worlds[arguments["uuid"]].bodies[b];
|
||||
|
||||
updates[body.uuid] = {
|
||||
"position": body.position.toArray(),
|
||||
"quaternion": body.quaternion.toArray()
|
||||
}
|
||||
}
|
||||
|
||||
postMessage({
|
||||
"event": "simulation-stepped",
|
||||
"data": {
|
||||
"callbackID": callbackID,
|
||||
"updates": updates
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "remove-body":
|
||||
worlds[arguments["worldUUID"]].removeBody(bodies[arguments["bodyUUID"]]);
|
||||
|
||||
postMessage({
|
||||
"event": "body-removed",
|
||||
"data": {
|
||||
"callbackID": callbackID
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "destroy-body":
|
||||
delete bodies[arguments["uuid"]];
|
||||
|
||||
postMessage({
|
||||
"event": "body-destroyed",
|
||||
"data": {
|
||||
"callbackID": callbackID
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "put-voxels":
|
||||
tasks["physics"].queue.push({
|
||||
"run": function (args) {
|
||||
var worldUUID = args["worldUUID"];
|
||||
var chunkUUID = args["chunkUUID"];
|
||||
var chunkPosition = args["chunkPosition"];
|
||||
var voxelIndices = args["indices"];
|
||||
|
||||
var bodyOptions = {
|
||||
"mass": 0,
|
||||
"type": CANNON.Body.STATIC,
|
||||
"material": new CANNON.Material(),
|
||||
"position": new CANNON.Vec3(
|
||||
chunkPosition[0] * worldConfig.chunkSize[0],
|
||||
chunkPosition[1] * worldConfig.chunkSize[1],
|
||||
chunkPosition[2] * worldConfig.chunkSize[2]
|
||||
)
|
||||
};
|
||||
|
||||
var chunk = bodies[chunkUUID] = new CANNON.Body(bodyOptions);
|
||||
|
||||
var shapes = [];
|
||||
|
||||
for (var i = 0; i < voxelIndices.length; i++) {
|
||||
var shape = shapes[i] = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5));
|
||||
var shapePosition = computeBlockPosition(worldConfig.chunkSize, voxelIndices[i]);
|
||||
|
||||
chunk.addShape(shape, new CANNON.Vec3(
|
||||
shapePosition[0],
|
||||
shapePosition[1],
|
||||
shapePosition[2]
|
||||
));
|
||||
}
|
||||
|
||||
worlds[worldUUID].addBody(chunk);
|
||||
},
|
||||
"arguments": [arguments]
|
||||
});
|
||||
break;
|
||||
case "remove-voxels":
|
||||
tasks["physics"].queue.push({
|
||||
"run": function (args) {
|
||||
var worldUUID = args["worldUUID"];
|
||||
var chunkUUID = args["chunkUUID"];
|
||||
|
||||
worlds[worldUUID].removeBody(bodies[chunkUUID]);
|
||||
|
||||
delete bodies[chunkUUID];
|
||||
},
|
||||
"arguments": [arguments]
|
||||
});
|
||||
break;
|
||||
case "destroy-world":
|
||||
delete worlds[arguments["uuid"]];
|
||||
|
||||
postMessage({
|
||||
"event": "world-destroyed",
|
||||
"data": {
|
||||
"callbackID": callbackID
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
self.generators = {
|
||||
"flat": {
|
||||
"type": "stepped",
|
||||
"run": function (position, data = {}) {
|
||||
if (position[1] >= 0 && position[1] <= 5) return ["glitch", {}];
|
||||
if (position[1] >= 6 && position[1] <= 57) return ["stone", {}];
|
||||
if (position[1] >= 58 && position[1] <= 62) return ["dirt", {}];
|
||||
if (position[1] == 63) return ["grass", {}];
|
||||
}
|
||||
},
|
||||
"sphere": {
|
||||
"type": "stepped",
|
||||
"run": function (position, data = {}) {
|
||||
var mustGenerate = ((position[0] ** 2) + (position[1] ** 2) + (position[2] ** 2)) <= 16 * 16;
|
||||
|
||||
if (mustGenerate) return ["stone", {}];
|
||||
}
|
||||
},
|
||||
"xr-flat": {
|
||||
"type": "stepped",
|
||||
"run": function (position, data = {}) {
|
||||
if (position[1] >= 0 && position[1] <= 1) return ["glitch", {}];
|
||||
if (position[1] >= 2 && position[1] <= 4) return ["stone", {}];
|
||||
if (position[1] >= 5 && position[1] <= 6) return ["dirt", {}];
|
||||
if (position[1] == 7) return ["grass", {}];
|
||||
}
|
||||
},
|
||||
"terrain": {
|
||||
"type": "full",
|
||||
"run": function (position, data = {}, chunkSize) {
|
||||
var chunkWidth = chunkSize[0];
|
||||
var chunkHeight = chunkSize[1];
|
||||
var chunkDepth = chunkSize[2];
|
||||
|
||||
var blocks = new Array(chunkSize[0] * chunkSize[1] * chunkSize[2]),
|
||||
perlin = new ImprovedNoise(),
|
||||
averageY = data["averageY"] || 64;
|
||||
|
||||
let quality = 25;
|
||||
|
||||
for (var x = 0; x < chunkWidth; x++) {
|
||||
for (var z = 0; z < chunkDepth; z++) {
|
||||
var absoluteCoords = [
|
||||
(position[0] * chunkWidth) + x,
|
||||
(position[2] * chunkDepth) + z
|
||||
];
|
||||
|
||||
var maxY = Math.round(
|
||||
perlin.noise(
|
||||
absoluteCoords[0] / quality,
|
||||
averageY / quality,
|
||||
absoluteCoords[1] / quality
|
||||
) * quality
|
||||
) + averageY;
|
||||
|
||||
for (var y = 0; y < chunkHeight; y++) {
|
||||
var absoluteY = (position[1] * chunkHeight) + y;
|
||||
|
||||
if (absoluteY >= (position[1] * chunkHeight)
|
||||
&& absoluteY <= ((position[1] * chunkHeight) + chunkHeight)) {
|
||||
if (absoluteY >= 0 && absoluteY <= 3) {
|
||||
blocks[computeBlockIndex(worldConfig.chunkSize, [
|
||||
x, y, z
|
||||
])] = ["glitch", {}];
|
||||
} else if (absoluteY >= 4 && absoluteY <= (maxY - 4)) {
|
||||
blocks[computeBlockIndex(worldConfig.chunkSize, [
|
||||
x, y, z
|
||||
])] = ["stone", {}];
|
||||
} else if (absoluteY >= (maxY - 3) && absoluteY <= (maxY - 1)) {
|
||||
blocks[computeBlockIndex(worldConfig.chunkSize, [
|
||||
x, y, z
|
||||
])] = ["dirt", {}];
|
||||
} else if (absoluteY == maxY) {
|
||||
blocks[computeBlockIndex(worldConfig.chunkSize, [
|
||||
x, y, z
|
||||
])] = ["grass", {}];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var construct = function (chunk, neighbors, chunkSize) {
|
||||
var positions = [];
|
||||
var normals = [];
|
||||
var uvs = [];
|
||||
var indexes = [];
|
||||
let texUV = [];
|
||||
|
||||
for (var b = 0; b < chunk.blocks.length; b++) {
|
||||
var blockPosition = computeBlockPosition(worldConfig.chunkSize, b);
|
||||
|
||||
if (chunk.blocks[b]) {
|
||||
var type = chunk.blocks[b][0];
|
||||
|
||||
var blockTexData = textureData.textures[type];
|
||||
|
||||
for (var n = 0; n < neighborData.length; n++) {
|
||||
var neighbor = neighborData[n];
|
||||
|
||||
var adjacentPosition = addPositions(blockPosition, neighbor.position);
|
||||
|
||||
let adjacentInNeighbor = false;
|
||||
if (
|
||||
adjacentPosition[0] < 0 || adjacentPosition[0] >= worldConfig.chunkSize[0] ||
|
||||
adjacentPosition[1] < 0 || adjacentPosition[1] >= worldConfig.chunkSize[1] ||
|
||||
adjacentPosition[2] < 0 || adjacentPosition[2] >= worldConfig.chunkSize[2]
|
||||
) adjacentInNeighbor = true;
|
||||
|
||||
let hasAdjacent = true;
|
||||
if (adjacentInNeighbor) {
|
||||
if (!neighbors[n]) hasAdjacent = false;
|
||||
|
||||
var positionInNeighbor = neighborPosition(adjacentPosition, worldConfig.chunkSize);
|
||||
var indexInNeighbor = computeBlockIndex(worldConfig.chunkSize, positionInNeighbor);
|
||||
|
||||
if (!neighbors[n] || !neighbors[n].blocks[indexInNeighbor]) hasAdjacent = false;
|
||||
} else {
|
||||
var blockIndex = computeBlockIndex(worldConfig.chunkSize, adjacentPosition);
|
||||
if (!chunk.blocks[blockIndex]) hasAdjacent = false;
|
||||
}
|
||||
|
||||
if (!hasAdjacent) {
|
||||
var index = positions.length / 3;
|
||||
|
||||
if (blockTexData.sided) {
|
||||
let sideMap;
|
||||
|
||||
for (var sm = 0; sm < blockTexData.sideMaps.length; sm++) {
|
||||
if (blockTexData.sideMaps[sm].includes(n)) sideMap = sm;
|
||||
}
|
||||
|
||||
texUV[0] = blockTexData.positions[sideMap][0] / blockTexData.sizes[sideMap][0];
|
||||
texUV[1] = blockTexData.positions[sideMap][1] / blockTexData.sizes[sideMap][1];
|
||||
} else {
|
||||
texUV[0] = blockTexData.position[0] / blockTexData.size[0];
|
||||
texUV[1] = blockTexData.position[1] / blockTexData.size[1];
|
||||
}
|
||||
var sideTexData = blockTexData[n];
|
||||
|
||||
// texUV[0] = sideTexData.end[0] - sideTexData.start[0];
|
||||
// texUV[1] = sideTexData.end[1] - sideTexData.start[1];
|
||||
|
||||
for (var c = 0; c < neighbor.corners.length; c++) {
|
||||
var corner = neighbor.corners[c];
|
||||
|
||||
var position = addPositions(blockPosition, corner);
|
||||
|
||||
positions.push(
|
||||
position[0],
|
||||
position[1],
|
||||
position[2]
|
||||
);
|
||||
normals.push(
|
||||
neighbor.position[0],
|
||||
neighbor.position[1],
|
||||
neighbor.position[2]
|
||||
);
|
||||
|
||||
var uv = corner.slice(3, 5);
|
||||
|
||||
uvs.push(
|
||||
(texUV[0] + uv[0]) *
|
||||
textureData.resolution[0] /
|
||||
textureData.size[0],
|
||||
1 - (texUV[1] + 1 - uv[1]) *
|
||||
textureData.resolution[1] /
|
||||
textureData.size[1]
|
||||
);
|
||||
}
|
||||
|
||||
indexes.push(
|
||||
index + 0, index + 1, index + 2,
|
||||
index + 2, index + 1, index + 3
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {positions, normals, uvs, indexes};
|
||||
};
|
||||
|
||||
var computeBlockIndex = function (chunkSize, blockPosition) {
|
||||
var x = blockPosition[0] % chunkSize[0];
|
||||
var z = blockPosition[2] % chunkSize[2];
|
||||
var y = blockPosition[1] % chunkSize[1];
|
||||
|
||||
return (x * (chunkSize[1] * chunkSize[2])) + y + (z * chunkSize[1]);
|
||||
};
|
||||
|
||||
var computeBlockPosition = function (chunkSize, blockIndex) {
|
||||
var blockPosition = [0, 0, 0];
|
||||
var subtractedIndex = 0 + blockIndex;
|
||||
|
||||
blockPosition[1] = subtractedIndex % chunkSize[1];
|
||||
subtractedIndex -= blockPosition[1];
|
||||
|
||||
blockPosition[2] = (subtractedIndex / chunkSize[1]) % chunkSize[2];
|
||||
subtractedIndex -= blockPosition[2] * chunkSize[1];
|
||||
|
||||
blockPosition[0] = (subtractedIndex / (chunkSize[1] * chunkSize[2])) % chunkSize[0];
|
||||
subtractedIndex -= blockPosition[0] * chunkSize[0];
|
||||
|
||||
return blockPosition;
|
||||
};
|
||||
|
||||
var neighborPosition = function (position, chunkSize) {
|
||||
var chunkPosition = position.slice(0, 3);
|
||||
|
||||
if (position[0] < 0) chunkPosition[0] = chunkSize[0] + position[0];
|
||||
if (position[0] >= chunkSize[0]) chunkPosition[0] = position[0] - chunkSize[0];
|
||||
if (position[1] < 0) chunkPosition[1] = chunkSize[1] + position[1];
|
||||
if (position[1] >= chunkSize[1]) chunkPosition[1] = position[1] - chunkSize[1];
|
||||
if (position[2] < 0) chunkPosition[2] = chunkSize[2] + position[2];
|
||||
if (position[2] >= chunkSize[2]) chunkPosition[2] = position[2] - chunkSize[2];
|
||||
|
||||
return chunkPosition;
|
||||
};
|
||||
|
||||
var addPositions = function (positionA, positionB) {
|
||||
var position = new Array(positionA.length);
|
||||
|
||||
for (var p = 0; p < position.length; p++) {
|
||||
position[p] = positionA[p] + positionB[p];
|
||||
}
|
||||
|
||||
return position;
|
||||
};
|
||||
|
||||
// Thanks to https://github.com/pmndrs/cannon-es/issues/21 (I slightly modified it)
|
||||
var trimeshToPolyhedron = function (bodyOptions, trimesh, upvector) {
|
||||
let p1 = new CANNON.Vec3(),
|
||||
p2 = new CANNON.Vec3(),
|
||||
p3 = new CANNON.Vec3(),
|
||||
p4 = new CANNON.Vec3(),
|
||||
mp = new CANNON.Vec3(),
|
||||
tmp = new CANNON.Vec3(),
|
||||
e1 = new CANNON.Vec3(),
|
||||
e2 = new CANNON.Vec3();
|
||||
|
||||
const body = new CANNON.Body(bodyOptions);
|
||||
|
||||
for (let i = 0; i < trimesh.indices.length / 3; i++) {
|
||||
mp.set(0, 0, 0);
|
||||
trimesh.getTriangleVertices(i, p1, p2, p3);
|
||||
trimesh.getNormal(i, p4);
|
||||
// if (upvector && p4.dot(upvector) < 0) p4.scale(-1, p4);
|
||||
p4.normalize();
|
||||
mp = mp.vadd(p1).vadd(p2).vadd(p3).scale(1/3);
|
||||
const vertices = [
|
||||
new CANNON.Vec3().copy(p1),
|
||||
new CANNON.Vec3().copy(p2),
|
||||
new CANNON.Vec3().copy(p3),
|
||||
mp.vadd(p4.scale(-1 / 2))
|
||||
];
|
||||
const faces = [
|
||||
[0, 1, 2],
|
||||
[0, 3, 1],
|
||||
[1, 3, 2],
|
||||
[2, 3, 0]
|
||||
];
|
||||
const normals = [
|
||||
new CANNON.Vec3().copy(p4)
|
||||
];
|
||||
for (let j = 0; j < 3; j++) {
|
||||
vertices[j].vsub(vertices[(j + 1) % 3], e1);
|
||||
vertices[(j + 1) % 3].vsub(p4, e2);
|
||||
tmp.set(0, 0, 0);
|
||||
const points = faces[j + 1];
|
||||
for (let p = 0; p < points.length; p++) {
|
||||
tmp.vadd(vertices[points[p]], tmp);
|
||||
}
|
||||
tmp.scale(1 / points.length, tmp);
|
||||
const normal = e1.cross(e2);
|
||||
normal.normalize();
|
||||
normal.scale(-1, normal);
|
||||
const angle = normal.dot(tmp);
|
||||
|
||||
if(angle < 0) normal.scale(-1, normal);
|
||||
normals.push(normal);
|
||||
}
|
||||
const polyhedron = new CANNON.ConvexPolyhedron({vertices, faces, normals});
|
||||
body.addShape(polyhedron);
|
||||
}
|
||||
|
||||
return body;
|
||||
};
|
||||
|
||||
Ammo().then(function () {
|
||||
ammoIsReady = true;
|
||||
}).catch(function (error) {
|
||||
|
||||
});
|
11
package.json
Normal file
11
package.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "xvoxel-async",
|
||||
"version": "1.0.0",
|
||||
"description": "Asynchronous fork of OpenVoxelProject",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "electron ."
|
||||
},
|
||||
"author": "X3F200C",
|
||||
"license": "ISC"
|
||||
}
|
9
plugins/splash.js
Normal file
9
plugins/splash.js
Normal file
@ -0,0 +1,9 @@
|
||||
global.core.on("post-init", function () {
|
||||
|
||||
});
|
||||
|
||||
var loadingScreen = global.document.createElement("div");
|
||||
loadingScreen.classList.add("fullscreen overlay");
|
||||
loadingScreen.id = "loading-screen";
|
||||
|
||||
global.document.body.appendChild(loadingScreen);
|
55
preload.js
Normal file
55
preload.js
Normal file
@ -0,0 +1,55 @@
|
||||
window.electron = require("electron");
|
||||
/* electron.contextBridge.exposeInMainWorld("load", function (moduleName) {
|
||||
try {
|
||||
return Promise.resolve(require(moduleName));
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}); */
|
||||
|
||||
var windowActionButtons = [
|
||||
{
|
||||
"divID": "minwin",
|
||||
"imgID": "mwi",
|
||||
"title": "Minimize",
|
||||
"click": function (event) {
|
||||
electron.ipcRenderer.send("ev", "minimize");
|
||||
}
|
||||
},
|
||||
{
|
||||
"divID": "maxrestorewin",
|
||||
"imgID": "mrwi",
|
||||
"title": "Maximize/Restore",
|
||||
"click": function (event) {
|
||||
electron.ipcRenderer.send("ev", "maximizerestore");
|
||||
}
|
||||
},
|
||||
{
|
||||
"divID": "closewin",
|
||||
"imgID": "cwi",
|
||||
"title": "Close",
|
||||
"click": function (event) {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function () {
|
||||
var actionButtonContainer = document.getElementById("actionbuttoncontainer");
|
||||
|
||||
for (var b = 0; b < windowActionButtons.length; b++) {
|
||||
var buttonData = windowActionButtons[b];
|
||||
|
||||
var button = document.createElement("div");
|
||||
button.id = buttonData.divID;
|
||||
button.title = buttonData.title;
|
||||
button.classList.add("windowactionbutton");
|
||||
button.onclick = buttonData.click;
|
||||
|
||||
var buttonImage = document.createElement("img");
|
||||
buttonImage.id = buttonData.imgID;
|
||||
|
||||
button.appendChild(buttonImage);
|
||||
actionButtonContainer.appendChild(button);
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue
Block a user