use threejs module js, remove unused libraries, increase world generation seed to 64 bit, implement random world spawn, improve start script

This commit is contained in:
LabyStudio
2022-05-12 02:57:23 +02:00
parent 51c07050e9
commit 24c0451031
28 changed files with 50508 additions and 578 deletions
+15 -15
View File
@@ -34,9 +34,11 @@ Click [here](https://labystudio.github.io/js-minecraft/) for a demo!
- World
- 16x16x16 Chunks
- Block type, data, sky & block lightning
- Perlin world generation
- Cave generation
- Tree and big tree generation
- Minecraft Alpha Generator
- 64 bits seed
- Perlin terrain generation
- Perlin cave generation
- Perlin tree and big tree generation
- Camera
- Frustum Culling
- Fog
@@ -47,18 +49,18 @@ Click [here](https://labystudio.github.io/js-minecraft/) for a demo!
- First person item in hand
- GUI
- Screens
- Loading Screen
- InGame Menu
- Controls Screen
- Loading Screen
- InGame Menu
- Controls Screen
- Widgets
- Button
- KeyBinding
- Slider
- Switches
- Button
- KeyBinding
- Slider
- Switches
- Overlay
- Cross-hair
- Font rendering
- Hot-Bar
- Cross-hair
- Font rendering
- Hot-Bar
</details>
<hr>
@@ -72,8 +74,6 @@ _Note: All textures from the original game were used for the screenshots only!_
### Licensing
- The main rendering library is [three.js](https://github.com/mrdoob/three.js/)
- The [stats.js](https://github.com/mrdoob/stats.js/) library is used for performance tracking
- Safari render issues fixed by [context-filter-polyfill](https://github.com/davidenke/context-filter-polyfill)
- All used sound resources are taken from [freesounds.org](https://freesound.org/people/C418/downloaded_sounds/?page=8#sound)
<hr>
+2 -2
View File
@@ -11,12 +11,12 @@
<div id="content">
<div id="canvas-container" class="fullscreen"></div>
<span id="pre-status">Loading page...</span>
<span id="pre-status">Loading scripts...</span>
</div>
</body>
<script type="module" src="src/start.js"></script>
<script type="module" src="src/js/Start.js"></script>
</html>
-363
View File
@@ -1,363 +0,0 @@
!function() {
"use strict";
var t;
!function(t) {
t.None = "none",
t.Url = "url",
t.Blur = "blur",
t.Brightness = "brightness",
t.Contrast = "contrast",
t.DropShadow = "drop-shadow",
t.Grayscale = "grayscale",
t.HueRotate = "hue-rotate",
t.Invert = "invert",
t.Opacity = "opacity",
t.Saturate = "saturate",
t.Sepia = "sepia"
}(t || (t = {}));
var r = new Map
, a = function(t) {
var r = document.createElement("canvas");
return r.height = t.canvas.height,
r.width = t.canvas.width,
Object.defineProperty(r, "__skipFilterPatch", {
value: !0
}),
r.getContext("2d")
};
var e = ["__skipFilterPatch", "__currentPathMirror", "canvas", "filter", "getImageData"];
var n = ["clearRect", "drawImage", "fill", "fillRect", "fillText", "stroke", "strokeRect", "strokeText"]
, i = function(t, a) {
a.match(/([-a-z]+)(?:\(([\w\d\s\.%-]*)\))?/gim).map(function(t) {
return t.match(/([-a-z]+)(?:\((.*)\))?/i).slice(1, 3)
}).reduce(function(t, a) {
var e = a[0]
, n = a[1];
return r.has(e) ? r.get(e).apply(void 0, [t].concat((n || "").split(" "))) : t
}, t)
}
, o = function(t) {
var r = parseFloat(t);
return /%\s*?$/i.test(t) && (r /= 100),
r
}
, s = function(t) {
return parseFloat(t)
};
var c, h;
r.set(t.None, function(t) {
return t
}),
r.set(t.Blur, function(t, r) {
void 0 === r && (r = "0");
var a = s(r);
if (a <= 0)
return t;
for (var e, n, i, o, c = t.canvas, h = c.height, u = c.width, v = t.getImageData(0, 0, u, h), f = v.data, p = u - 1, g = h - 1, l = a + 1, d = [1, 57, 41, 21, 203, 34, 97, 73, 227, 91, 149, 62, 105, 45, 39, 137, 241, 107, 3, 173, 39, 71, 65, 238, 219, 101, 187, 87, 81, 151, 141, 133, 249, 117, 221, 209, 197, 187, 177, 169, 5, 153, 73, 139, 133, 127, 243, 233, 223, 107, 103, 99, 191, 23, 177, 171, 165, 159, 77, 149, 9, 139, 135, 131, 253, 245, 119, 231, 224, 109, 211, 103, 25, 195, 189, 23, 45, 175, 171, 83, 81, 79, 155, 151, 147, 9, 141, 137, 67, 131, 129, 251, 123, 30, 235, 115, 113, 221, 217, 53, 13, 51, 50, 49, 193, 189, 185, 91, 179, 175, 43, 169, 83, 163, 5, 79, 155, 19, 75, 147, 145, 143, 35, 69, 17, 67, 33, 65, 255, 251, 247, 243, 239, 59, 29, 229, 113, 111, 219, 27, 213, 105, 207, 51, 201, 199, 49, 193, 191, 47, 93, 183, 181, 179, 11, 87, 43, 85, 167, 165, 163, 161, 159, 157, 155, 77, 19, 75, 37, 73, 145, 143, 141, 35, 138, 137, 135, 67, 33, 131, 129, 255, 63, 250, 247, 61, 121, 239, 237, 117, 29, 229, 227, 225, 111, 55, 109, 216, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 48, 190, 47, 93, 185, 183, 181, 179, 178, 176, 175, 173, 171, 85, 21, 167, 165, 41, 163, 161, 5, 79, 157, 78, 154, 153, 19, 75, 149, 74, 147, 73, 144, 143, 71, 141, 140, 139, 137, 17, 135, 134, 133, 66, 131, 65, 129, 1][a], m = [0, 9, 10, 10, 14, 12, 14, 14, 16, 15, 16, 15, 16, 15, 15, 17, 18, 17, 12, 18, 16, 17, 17, 19, 19, 18, 19, 18, 18, 19, 19, 19, 20, 19, 20, 20, 20, 20, 20, 20, 15, 20, 19, 20, 20, 20, 21, 21, 21, 20, 20, 20, 21, 18, 21, 21, 21, 21, 20, 21, 17, 21, 21, 21, 22, 22, 21, 22, 22, 21, 22, 21, 19, 22, 22, 19, 20, 22, 22, 21, 21, 21, 22, 22, 22, 18, 22, 22, 21, 22, 22, 23, 22, 20, 23, 22, 22, 23, 23, 21, 19, 21, 21, 21, 23, 23, 23, 22, 23, 23, 21, 23, 22, 23, 18, 22, 23, 20, 22, 23, 23, 23, 21, 22, 20, 22, 21, 22, 24, 24, 24, 24, 24, 22, 21, 24, 23, 23, 24, 21, 24, 23, 24, 22, 24, 24, 22, 24, 24, 22, 23, 24, 24, 24, 20, 23, 22, 23, 24, 24, 24, 24, 24, 24, 24, 23, 21, 23, 22, 23, 24, 24, 24, 22, 24, 24, 24, 23, 22, 24, 24, 25, 23, 25, 25, 23, 24, 25, 25, 24, 22, 25, 25, 25, 24, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 23, 25, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 22, 25, 25, 23, 25, 25, 20, 24, 25, 24, 25, 25, 22, 24, 25, 24, 25, 24, 25, 25, 24, 25, 25, 25, 25, 22, 25, 25, 25, 24, 25, 24, 25, 18][a], _ = [], w = [], y = [], D = [], P = [], I = [], b = 3; b-- > 0; ) {
for (var M = 0, O = 0, k = 0; k < h; k++) {
for (var C = f[M] * l, x = f[M + 1] * l, F = f[M + 2] * l, j = f[M + 3] * l, R = 1; R <= a; R++)
e = M + ((R > p ? p : R) << 2),
C += f[e++],
x += f[e++],
F += f[e++],
j += f[e];
for (var S = 0; S < u; S++)
_[O] = C,
w[O] = x,
y[O] = F,
D[O] = j,
0 === k && (P[S] = ((e = S + l) < p ? e : p) << 2,
I[S] = (e = S - a) > 0 ? e << 2 : 0),
n = M + P[S],
i = M + I[S],
C += f[n++] - f[i++],
x += f[n++] - f[i++],
F += f[n++] - f[i++],
j += f[n] - f[i],
O++;
M += u << 2
}
for (S = 0; S < u; S++) {
var T = S;
for (C = _[T] * l,
x = w[T] * l,
F = y[T] * l,
j = D[T] * l,
R = 1; R <= a; R++)
C += _[T += R > g ? 0 : u],
x += w[T],
F += y[T],
j += D[T];
for (O = S << 2,
k = 0; k < h; k++)
f[O + 3] = o = j * d >>> m,
o > 0 ? (o = 255 / o,
f[O] = (C * d >>> m) * o,
f[O + 1] = (x * d >>> m) * o,
f[O + 2] = (F * d >>> m) * o) : f[O] = f[O + 1] = f[O + 2] = 0,
0 === S && (P[k] = ((e = k + l) < g ? e : g) * u,
I[k] = (e = k - a) > 0 ? e * u : 0),
n = S + P[k],
i = S + I[k],
C += _[n] - _[i],
x += w[n] - w[i],
F += y[n] - y[i],
j += D[n] - D[i],
O += u << 2
}
}
return t.putImageData(v, 0, 0),
t
}),
r.set(t.Brightness, function(t, r) {
if (void 0 === r && (r = "1"),
1 === (r = o(r)))
return t;
r < 0 && (r = 0);
for (var a = t.canvas, e = a.height, n = a.width, i = t.getImageData(0, 0, n, e), s = i.data, c = s.length, h = 0; h < c; h += 4)
s[h + 0] *= r,
s[h + 1] *= r,
s[h + 2] *= r;
return t.putImageData(i, 0, 0),
t
}),
r.set(t.Contrast, function(t, r) {
if (void 0 === r && (r = "1"),
1 === (r = o(r)))
return t;
r < 0 && (r = 0);
for (var a = t.canvas, e = a.height, n = a.width, i = t.getImageData(0, 0, n, e), s = i.data, c = s.length, h = 0; h < c; h += 4)
s[h + 0] = 255 * ((s[h + 0] / 255 - .5) * r + .5),
s[h + 1] = 255 * ((s[h + 1] / 255 - .5) * r + .5),
s[h + 2] = 255 * ((s[h + 2] / 255 - .5) * r + .5);
return t.putImageData(i, 0, 0),
t
}),
r.set(t.DropShadow, function(t, r, a, e, n) {
var i = document.createElement("canvas").getContext("2d");
i.shadowOffsetX = s(r),
i.shadowOffsetY = s(a),
i.shadowBlur = n ? s(e || "0") : 0,
i.shadowColor = n || e || "transparent",
i.drawImage(t.canvas, 0, 0);
var o = t.canvas
, c = o.width
, h = o.height;
return t.putImageData(i.getImageData(0, 0, c, h), 0, 0),
t
}),
r.set(t.Grayscale, function(t, r) {
if (void 0 === r && (r = "0"),
(r = o(r)) <= 0)
return t;
r > 1 && (r = 1);
for (var a = t.canvas, e = a.height, n = a.width, i = t.getImageData(0, 0, n, e), s = i.data, c = s.length, h = 0; h < c; h += 4) {
var u = .2126 * s[h] + .7152 * s[h + 1] + .0722 * s[h + 2];
s[h + 0] += (u - s[h + 0]) * r,
s[h + 1] += (u - s[h + 1]) * r,
s[h + 2] += (u - s[h + 2]) * r
}
return t.putImageData(i, 0, 0),
t
}),
r.set(t.HueRotate, function(t, r) {
void 0 === r && (r = "0deg");
var a = function(t) {
var r = parseFloat(t);
switch (t.slice(r.toString().length)) {
case "deg":
r /= 360;
break;
case "grad":
r /= 400;
break;
case "rad":
r /= 2 * Math.PI
}
return r
}(r);
if (a <= 0)
return t;
var e, n, i, o, s, c, h, u, v, f = t.canvas, p = f.height, g = f.width, l = t.getImageData(0, 0, g, p), d = l.data, m = (a % 1 + 1) % 1 * 3, _ = Math.floor(m), w = m - _, y = 1 - w;
switch (_) {
case 0:
e = y,
n = 0,
i = w,
o = w,
s = y,
c = 0,
h = 0,
u = w,
v = y;
break;
case 1:
e = 0,
n = w,
i = y,
o = y,
s = 0,
c = w,
h = w,
u = y,
v = 0;
break;
case 2:
e = w,
n = y,
i = 0,
o = 0,
s = w,
c = y,
h = y,
u = 0,
v = w
}
for (var D = 0, P = 0; P < p; ++P)
for (var I = 0; I < g; ++I) {
var b = d[0 + (D = 4 * (P * g + I))]
, M = d[D + 1]
, O = d[D + 2];
d[D + 0] = Math.floor(e * b + n * M + i * O),
d[D + 1] = Math.floor(o * b + s * M + c * O),
d[D + 2] = Math.floor(h * b + u * M + v * O)
}
return t.putImageData(l, 0, 0),
t
}),
r.set(t.Invert, function(t, r) {
if (void 0 === r && (r = "0"),
(r = o(r)) <= 0)
return t;
r > 1 && (r = 1);
for (var a = t.canvas, e = a.height, n = a.width, i = t.getImageData(0, 0, n, e), s = i.data, c = s.length, h = 0; h < c; h += 4)
s[h + 0] = Math.abs(s[h + 0] - 255 * r),
s[h + 1] = Math.abs(s[h + 1] - 255 * r),
s[h + 2] = Math.abs(s[h + 2] - 255 * r);
return t.putImageData(i, 0, 0),
t
}),
r.set(t.Opacity, function(t, r) {
if (void 0 === r && (r = "1"),
(r = o(r)) < 0)
return t;
r > 1 && (r = 1);
for (var a = t.canvas, e = a.height, n = a.width, i = t.getImageData(0, 0, n, e), s = i.data, c = s.length, h = 3; h < c; h += 4)
s[h] *= r;
return t.putImageData(i, 0, 0),
t
}),
r.set(t.Saturate, function(t, r) {
void 0 === r && (r = "1");
var a = o(r);
if (1 === a)
return t;
a < 0 && (a = 0);
for (var e = t.canvas, n = e.height, i = e.width, s = t.getImageData(0, 0, i, n), c = s.data, h = .3086 * (1 - a), u = .6094 * (1 - a), v = .082 * (1 - a), f = i << 2, p = 0; p < n; p++)
for (var g = p * f, l = 0; l < i; l++) {
var d = g + (l << 2)
, m = c[d + 0]
, _ = c[d + 1]
, w = c[d + 2];
c[d + 0] = (h + a) * m + u * _ + v * w,
c[d + 1] = h * m + (u + a) * _ + v * w,
c[d + 2] = h * m + u * _ + (v + a) * w
}
return t.putImageData(s, 0, 0),
t
}),
r.set(t.Sepia, function(t, r) {
if (void 0 === r && (r = "0"),
(r = o(r)) <= 0)
return t;
r > 1 && (r = 1);
for (var a = t.canvas, e = a.height, n = a.width, i = t.getImageData(0, 0, n, e), s = i.data, c = s.length, h = 0; h < c; h += 4) {
var u = s[h + 0]
, v = s[h + 1]
, f = s[h + 2];
s[h + 0] = (.393 * u + .769 * v + .189 * f) * r + u * (1 - r),
s[h + 1] = (.349 * u + .686 * v + .168 * f) * r + v * (1 - r),
s[h + 2] = (.272 * u + .534 * v + .131 * f) * r + f * (1 - r)
}
return t.putImageData(i, 0, 0),
t
}),
"filter"in CanvasRenderingContext2D.prototype || (c = HTMLCanvasElement,
h = CanvasRenderingContext2D,
Object.defineProperty(c.prototype, "__skipFilterPatch", {
writable: !0,
value: !1
}),
Object.defineProperty(c.prototype, "__currentPathMirror", {
writable: !0,
value: void 0
}),
Object.defineProperty(h.prototype, "filter", {
writable: !0,
value: t.None
}),
function(t) {
Object.keys(t.prototype).filter(function(t) {
return e.indexOf(t) < 0
}).map(function(r) {
return {
member: r,
descriptor: Object.getOwnPropertyDescriptor(t.prototype, r)
}
}).filter(function(t) {
return t.descriptor.set
}).forEach(function(r) {
var e = r.member
, n = r.descriptor;
Object.defineProperty(t.prototype, e, {
get: function() {
return this.canvas.__skipFilterPatch ? n.get.call(this) : this.canvas.__currentPathMirror[e]
},
set: function(t) {
if (this.canvas.__skipFilterPatch)
return n.set.call(this, t);
this.canvas.__currentPathMirror || (this.canvas.__currentPathMirror = a(this)),
this.canvas.__currentPathMirror[e] = t
}
})
})
}(CanvasRenderingContext2D),
function(t) {
Object.keys(t.prototype).filter(function(t) {
return e.indexOf(t) < 0
}).map(function(r) {
return {
member: r,
descriptor: Object.getOwnPropertyDescriptor(t.prototype, r)
}
}).filter(function(t) {
var r = t.descriptor;
return r.value && "function" == typeof r.value
}).forEach(function(r) {
var e = r.member
, o = r.descriptor.value;
Object.defineProperty(t.prototype, e, {
value: function() {
for (var t, r = [], s = 0; s < arguments.length; s++)
r[s] = arguments[s];
if (this.canvas.__skipFilterPatch)
return o.call.apply(o, [this].concat(r));
this.canvas.__currentPathMirror || (this.canvas.__currentPathMirror = a(this));
var c = (t = this.canvas.__currentPathMirror)[e].apply(t, r);
if (n.indexOf(e) > -1) {
i(this.canvas.__currentPathMirror, this.filter),
this.canvas.__skipFilterPatch = !0;
var h = void 0;
"getTransform"in this && (h = this.getTransform(),
this.setTransform(1, 0, 0, 1, 0, 0)),
this.drawImage(this.canvas.__currentPathMirror.canvas, 0, 0),
h && this.setTransform(h),
this.canvas.__skipFilterPatch = !1,
this.canvas.__currentPathMirror = a(this)
}
return c
}
})
})
}(CanvasRenderingContext2D))
}();
+1467
View File
File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
// stats.js - http://github.com/mrdoob/stats.js
(function(f,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"===typeof define&&define.amd?define(e):f.Stats=e()})(this,function(){var f=function(){function e(a){c.appendChild(a.dom);return a}function u(a){for(var d=0;d<c.children.length;d++)c.children[d].style.display=d===a?"block":"none";l=a}var l=0,c=document.createElement("div");c.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";c.addEventListener("click",function(a){a.preventDefault();
u(++l%c.children.length)},!1);var k=(performance||Date).now(),g=k,a=0,r=e(new f.Panel("FPS","#0ff","#002")),h=e(new f.Panel("MS","#0f0","#020"));if(self.performance&&self.performance.memory)var t=e(new f.Panel("MB","#f08","#201"));u(0);return{REVISION:16,dom:c,addPanel:e,showPanel:u,begin:function(){k=(performance||Date).now()},end:function(){a++;var c=(performance||Date).now();h.update(c-k,200);if(c>=g+1E3&&(r.update(1E3*a/(c-g),100),g=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/
1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){k=this.end()},domElement:c,setMode:u}};f.Panel=function(e,f,l){var c=Infinity,k=0,g=Math.round,a=g(window.devicePixelRatio||1),r=80*a,h=48*a,t=3*a,v=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=h;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,h);b.fillStyle=f;b.fillText(e,t,v);
b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(h,w){c=Math.min(c,h);k=Math.max(k,h);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=f;b.fillText(g(h)+" "+e+" ("+g(c)+"-"+g(k)+")",t,v);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,g((1-h/w)*p))}}};return f});
-6
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+51
View File
@@ -0,0 +1,51 @@
import Minecraft from './net/minecraft/client/Minecraft.js';
class Start {
constructor(preStatusElementId) {
this.preStatusElement = document.getElementById(preStatusElementId);
}
loadTextures(textures) {
let resources = [];
let index = 0;
return textures.reduce((currentPromise, texturePath) => {
return currentPromise.then(() => {
return new Promise((resolve, reject) => {
// Load texture
let image = new Image();
image.src = "src/resources/" + texturePath;
image.onload = () => resolve();
resources[texturePath] = image;
index++;
});
});
}, Promise.resolve()).then(() => {
return resources;
});
}
launch(canvasWrapperId) {
this.loadTextures([
"misc/grasscolor.png",
"gui/font.png",
"gui/gui.png",
"gui/background.png",
"gui/icons.png",
"terrain/terrain.png",
"terrain/sun.png",
"terrain/moon.png",
"char.png"
]).then((resources) => {
this.preStatusElement.remove();
// Launch actual game on canvas
window.app = new Minecraft(canvasWrapperId, resources);
});
}
}
// Launch game
new Start("pre-status").launch("canvas-container");
-11
View File
@@ -29,17 +29,6 @@ export default class GameWindow {
this.canvasItems = document.createElement('canvas');
this.wrapper.appendChild(this.canvasItems);
// Stats
this.statsFps = new Stats()
this.statsFps.showPanel(0);
this.statsFps.domElement.style.cssText = 'position:absolute;top:0px;right:80px;float:right';
//this.wrapper.appendChild(this.statsFps.dom);
this.statsMs = new Stats()
this.statsMs.showPanel(1);
this.statsMs.domElement.style.cssText = 'position:absolute;top:0px;right:160px;float:right';
//this.wrapper.appendChild(this.statsMs.dom);
// On resize
let scope = this;
+5 -14
View File
@@ -84,17 +84,14 @@ export default class Minecraft {
}
init() {
// Load spawn chunk
for (let x = -WorldRenderer.RENDER_DISTANCE; x <= WorldRenderer.RENDER_DISTANCE; x++) {
for (let z = -WorldRenderer.RENDER_DISTANCE; z <= WorldRenderer.RENDER_DISTANCE; z++) {
this.world.getChunkAt(x, z);
}
}
this.player.respawn();
// Start render loop
this.running = true;
this.requestNextFrame();
// Load spawn chunks and respawn player
this.world.findSpawn();
this.world.loadSpawnChunks();
this.player.respawn();
}
hasInGameFocus() {
@@ -112,9 +109,6 @@ export default class Minecraft {
}
onLoop() {
this.window.statsFps.begin();
this.window.statsMs.begin();
// Update the timer
this.timer.advanceTime();
@@ -135,9 +129,6 @@ export default class Minecraft {
this.lastTime += 1000;
this.frames = 0;
}
this.window.statsFps.end();
this.window.statsMs.end();
}
onRender(partialTicks) {
@@ -47,8 +47,8 @@ export default class PlayerEntity extends EntityLiving {
}
respawn() {
let spawnY = this.world.getHeightAt(0, 0);
this.setPosition(0, spawnY + 8, 0);
let spawn = this.world.getSpawn();
this.setPosition(spawn.x, spawn.y, spawn.z);
}
setPosition(x, y, z) {
@@ -1,3 +1,5 @@
import * as THREE from "../../../../../../libraries/three.module.js";
export default class Tessellator {
constructor() {
@@ -6,6 +6,7 @@ import Tessellator from "./Tessellator.js";
import ChunkSection from "../world/ChunkSection.js";
import Random from "../../util/Random.js";
import Vector3 from "../../util/Vector3.js";
import * as THREE from "../../../../../../libraries/three.module.js";
export default class WorldRenderer {
@@ -105,8 +106,8 @@ export default class WorldRenderer {
// Render chunks
let player = this.minecraft.player;
let cameraChunkX = Math.floor(player.x >> 4);
let cameraChunkZ = Math.floor(player.z >> 4);
let cameraChunkX = Math.floor(player.x) >> 4;
let cameraChunkZ = Math.floor(player.z) >> 4;
this.renderChunks(cameraChunkX, cameraChunkZ);
// Render sky
@@ -611,6 +612,13 @@ export default class WorldRenderer {
}
}
}
// Update render order of chunks
world.group.children.sort((a, b) => {
let distance1 = Math.floor(Math.pow(a.chunkX - cameraChunkX, 2) + Math.pow(a.chunkZ - cameraChunkZ, 2));
let distance2 = Math.floor(Math.pow(b.chunkX - cameraChunkX, 2) + Math.pow(b.chunkZ - cameraChunkZ, 2));
return distance2 - distance1;
});
}
rebuildAll() {
@@ -1,5 +1,6 @@
import Tessellator from "../Tessellator.js";
import MathHelper from "../../../util/MathHelper.js";
import * as THREE from "../../../../../../../libraries/three.module.js";
export default class EntityRenderer {
@@ -1,6 +1,7 @@
import ModelPlayer from "../../model/model/ModelPlayer.js";
import EntityRenderer from "../EntityRenderer.js";
import Block from "../../../world/block/Block.js";
import * as THREE from "../../../../../../../../libraries/three.module.js";
export default class PlayerRenderer extends EntityRenderer {
@@ -1,3 +1,5 @@
import * as THREE from "../../../../../../../libraries/three.module.js";
export default class ItemRenderer {
constructor(minecraft, window) {
@@ -1,5 +1,6 @@
import Polygon from "./Polygon.js";
import Vertex from "./Vertex.js";
import * as THREE from "../../../../../../../../libraries/three.module.js";
export default class ModelRenderer {
@@ -1,4 +1,5 @@
import Block from "../world/block/Block.js";
import * as THREE from "../../../../../../libraries/three.module.js";
export default class SoundManager {
@@ -2,6 +2,7 @@ import EnumSkyBlock from "../../util/EnumSkyBlock.js";
import Block from "./block/Block.js";
import World from "./World.js";
import ChunkSection from "./ChunkSection.js";
import * as THREE from "../../../../../../libraries/three.module.js";
export default class Chunk {
@@ -1,5 +1,6 @@
import EnumSkyBlock from "../../util/EnumSkyBlock.js";
import Block from "./block/Block.js";
import * as THREE from "../../../../../../libraries/three.module.js";
export default class ChunkSection {
+55 -18
View File
@@ -8,12 +8,16 @@ import EnumBlockFace from "../../util/EnumBlockFace.js";
import Vector3 from "../../util/Vector3.js";
import Vector4 from "../../util/Vector4.js";
import MetadataChunkBlock from "../../util/MetadataChunkBlock.js";
import Long from "../../../../../../libraries/long.js";
import * as THREE from "../../../../../../libraries/three.module.js";
import WorldRenderer from "../render/WorldRenderer.js";
import Random from "../../util/Random.js";
export default class World {
static TOTAL_HEIGHT = ChunkSection.SIZE * 8 - 1; // ChunkSection.SIZE * 16 - 1;
constructor(minecraft) {
constructor(minecraft, seed = Long.fromInt(Date.now() % 100000)) {
this.minecraft = minecraft;
this.entities = [];
@@ -25,10 +29,9 @@ export default class World {
this.lightUpdateQueue = [];
this.time = 0;
this.spawn = new Vector3(0, 0, 0);
// Load world
this.seed = Date.now() % 100000;
this.generator = new WorldGenerator(this, this.seed);
this.setSeed(seed);
// Update lights async
let scope = this;
@@ -41,18 +44,17 @@ export default class World {
}, 0);
}
setSeed(seed) {
this.seed = seed;
this.generator = new WorldGenerator(this, seed);
this.random = new Random(seed);
}
getSeed() {
return this.seed;
}
onTick() {
let player = this.minecraft.player;
let cameraChunkX = Math.floor(player.x >> 4);
let cameraChunkZ = Math.floor(player.z >> 4);
// Update render order of chunks
this.group.children.sort((a, b) => {
let distance1 = Math.floor(Math.pow(a.chunkX - cameraChunkX, 2) + Math.pow(a.chunkZ - cameraChunkZ, 2));
let distance2 = Math.floor(Math.pow(b.chunkX - cameraChunkX, 2) + Math.pow(b.chunkZ - cameraChunkZ, 2));
return distance2 - distance1;
});
// Update skylight subtracted (To make the night dark)
let lightLevel = this.calculateSkylightSubtracted(1.0);
if (lightLevel !== this.skylightSubtracted) {
@@ -108,9 +110,6 @@ export default class World {
}
getChunkAtBlock(x, y, z) {
if (!this.blockExists(x, y, z)) {
return null;
}
return this.getChunkAt(x >> 4, z >> 4).getSection(y >> 4);
}
@@ -617,4 +616,42 @@ export default class World {
}
return null;
}
getSpawn() {
return this.spawn;
}
setSpawn(x, z) {
let y = this.getHeightAt(x, z);
this.spawn = new Vector3(x, y + 8, z);
}
findSpawn() {
if (this.spawn.y <= 0) {
this.spawn.y = 64;
}
while (this.getBlockAboveSeaLevel(this.spawn.x, this.spawn.z) === 0) {
this.spawn.x += this.random.nextInt(8) - this.random.nextInt(8);
this.spawn.z += this.random.nextInt(8) - this.random.nextInt(8);
}
}
getBlockAboveSeaLevel(x, z) {
let y = this.generator.seaLevel;
while (this.getBlockAt(x, y + 1, z) !== 0) {
y++;
}
return this.getBlockAt(x, y, z);
}
loadSpawnChunks() {
for (let x = -WorldRenderer.RENDER_DISTANCE; x <= WorldRenderer.RENDER_DISTANCE; x++) {
for (let z = -WorldRenderer.RENDER_DISTANCE; z <= WorldRenderer.RENDER_DISTANCE; z++) {
this.getChunkAt(x + this.spawn.x >> 4, z + this.spawn.z >> 4);
}
}
this.spawn.y = this.getHeightAt(this.spawn.x, this.spawn.z) + 8;
}
}
@@ -1,4 +1,5 @@
import Random from "../../../util/Random.js";
import Long from "../../../../../../../libraries/long.js";
export default class Generator {
@@ -15,4 +16,23 @@ export default class Generator {
generateAtBlock(x, y, z, primer) {
}
generateSeedOffset() {
this.random.setSeed(this.seed);
let seedX = this.random.nextLong().divide(2).multiply(2).add(1);
let seedZ = this.random.nextLong().divide(2).multiply(2).add(1);
return {seedX, seedZ};
}
setSeedOffset(chunkX, chunkZ, seedX, seedZ) {
let seed = Long.fromInt(chunkX).multiply(seedX).add(Long.fromInt(chunkZ).multiply(seedZ)).xor(this.seed);
this.random.setSeed(seed);
}
setChunkSeed(chunkX, chunkZ) {
let {seedX, seedZ} = this.generateSeedOffset();
this.setSeedOffset(chunkX, chunkZ, seedX, seedZ);
}
}
@@ -20,12 +20,13 @@ export default class WorldGenerator extends Generator {
this.terrainGenerator4 = new NoiseGeneratorOctaves(this.random, 16);
this.terrainGenerator5 = new NoiseGeneratorOctaves(this.random, 16);
this.terrainGenerator3 = new NoiseGeneratorOctaves(this.random, 8);
this.terrainGenerator1 = new NoiseGeneratorOctaves(this.random, 10);
this.terrainGenerator2 = new NoiseGeneratorOctaves(this.random, 16);
this.natureGenerator1 = new NoiseGeneratorOctaves(this.random, 4);
this.natureGenerator2 = new NoiseGeneratorOctaves(this.random, 4);
this.terrainGenerator1 = new NoiseGeneratorOctaves(this.random, 10);
this.terrainGenerator2 = new NoiseGeneratorOctaves(this.random, 16);
this.populationNoiseGenerator = new NoiseGeneratorOctaves(this.random, 8);
}
@@ -52,18 +53,13 @@ export default class WorldGenerator extends Generator {
}
populateChunk(chunkX, chunkZ) {
// Reset seed
this.random.setSeed(this.seed);
// Set seed for chunk
let seedX = (this.random.nextInt() / 2) * 2 + 1;
let seedZ = (this.random.nextInt() / 2) * 2 + 1;
this.random.setSeed(chunkX * seedX + chunkZ * seedZ ^ this.seed);
this.setChunkSeed(chunkX, chunkZ);
// Access noise data for population
let absoluteX = chunkX * 16;
let absoluteY = chunkZ * 16;
let amount = Math.floor((this.populationNoiseGenerator.perlin(absoluteX * 0.5, absoluteY * 0.5) / 8 + this.random.nextFloat() * 4 + 4) / 3);
let amount = Math.floor((this.populationNoiseGenerator.perlin(absoluteX * 0.5, absoluteY * 0.5) / 8 + this.random.nextDouble() * 4 + 4) / 3);
if (amount < 0) {
amount = 0;
}
@@ -5,9 +5,9 @@ export default class NoiseGeneratorPerlin extends NoiseGenerator {
constructor(random) {
super();
this.offsetX = random.nextFloat() * 256;
this.offsetY = random.nextFloat() * 256;
this.offsetZ = random.nextFloat() * 256;
this.offsetX = random.nextDouble() * 256;
this.offsetY = random.nextDouble() * 256;
this.offsetZ = random.nextDouble() * 256;
this.permutations = [];
for (let i = 0; i < 256; i++) {
@@ -21,7 +21,7 @@ export default class BigTreeGenerator extends Generator {
}
generateAtBlock(x, y, z) {
let seed = this.random.nextInt();
let seed = this.random.nextLong();
this.random.setSeed(seed);
this.coords[0] = x;
@@ -11,18 +11,14 @@ export default class CaveGenerator extends Generator {
}
generateInChunk(originChunkX, originChunkZ, primer) {
// Reset seed
this.random.setSeed(this.seed);
let offset = this.chunkRange;
let seedX = (this.random.nextInt() / 2) * 2 + 1;
let seedZ = (this.random.nextInt() / 2) * 2 + 1;
let {seedX, seedZ} = this.generateSeedOffset();
// Generate entire cave over 16x16 chunk area
for (let chunkX = originChunkX - offset; chunkX <= originChunkX + offset; chunkX++) {
for (let chunkZ = originChunkZ - offset; chunkZ <= originChunkZ + offset; chunkZ++) {
// Set seed for position
this.random.setSeed(chunkX * seedX + chunkZ * seedZ ^ this.seed);
this.setSeedOffset(chunkX, chunkZ, seedX, seedZ);
// Generate entire cave
this.generateCave(chunkX, chunkZ, originChunkX, originChunkZ, primer);
@@ -50,10 +46,10 @@ export default class CaveGenerator extends Generator {
}
for (let j = 0; j < amount; j++) {
let num1 = this.random.nextFloat() * Math.PI * 2.0;
let num2 = ((this.random.nextFloat() - 0.5) * 2.0) / 8;
let num3 = this.random.nextFloat() * 2.0 + this.random.nextFloat();
this.generateCaveAtBlock(originChunkX, originChunkZ, primer, x, y, z, num3, num1, num2, 0, 0, 1.0);
let rotation1 = this.random.nextFloat() * Math.PI * 2.0;
let rotation2 = ((this.random.nextFloat() - 0.5) * 2.0) / 8;
let amplitude = this.random.nextFloat() * 2.0 + this.random.nextFloat();
this.generateCaveAtBlock(originChunkX, originChunkZ, primer, x, y, z, amplitude, rotation1, rotation2, 0, 0, 1.0);
}
}
}
@@ -67,47 +63,47 @@ export default class CaveGenerator extends Generator {
);
}
generateCaveAtBlock(originChunkX, originChunkZ, primer, absoluteX, absoluteY, absoluteZ, amplitude, rotation2, rotation1, progress, distance, strength) {
generateCaveAtBlock(originChunkX, originChunkZ, primer, absoluteX, absoluteY, absoluteZ, amplitude, rotation1, rotation2, progress, distance, strength) {
let centerX = originChunkX * 16 + 8;
let centerZ = originChunkZ * 16 + 8;
let motion2 = 0;
let motion1 = 0;
let random = new Random(this.random.nextInt());
let random = new Random(this.random.nextLong());
if (distance <= 0) {
let i1 = this.chunkRange * 16 - 16;
distance = i1 - random.nextInt(i1 / 4);
let range = this.chunkRange * 16 - 16;
distance = range - random.nextInt(Math.floor(range / 4));
}
let isBeginning = false;
if (progress === -1) {
progress = distance / 2;
progress = Math.floor(distance / 2);
isBeginning = true;
}
let maxProgress = random.nextInt(distance / 2) + distance / 4;
let maxProgress = random.nextInt(Math.floor(distance / 2)) + Math.floor(distance / 4);
let isStrong = random.nextInt(6) === 0;
for (; progress < distance; progress++) {
let value = 1.5 + (Math.sin((progress * Math.PI) / distance) * amplitude);
let valueWithStrength = value * strength;
let cos = Math.cos(rotation1);
let sin = Math.sin(rotation1);
let cos = Math.cos(rotation2);
let sin = Math.sin(rotation2);
absoluteX += Math.cos(rotation2) * cos;
absoluteX += Math.cos(rotation1) * cos;
absoluteY += sin;
absoluteZ += Math.sin(rotation2) * cos;
absoluteZ += Math.sin(rotation1) * cos;
if (isStrong) {
rotation1 *= 0.92;
rotation2 *= 0.92;
} else {
rotation1 *= 0.7;
rotation2 *= 0.7;
}
rotation1 += motion1 * 0.1;
rotation2 += motion2 * 0.1;
rotation2 += motion1 * 0.1;
rotation1 += motion2 * 0.1;
motion1 *= 0.9;
motion2 *= 0.75;
@@ -119,12 +115,12 @@ export default class CaveGenerator extends Generator {
this.generateCaveAtBlock(
originChunkX, originChunkZ, primer,
absoluteX, absoluteY, absoluteZ,
random.nextFloat() * 0.5 + 0.5, rotation2 - 1.570796, rotation1 / 3, progress, distance, 1.0
random.nextFloat() * 0.5 + 0.5, rotation1 - 1.570796, rotation2 / 3, progress, distance, 1.0
);
this.generateCaveAtBlock(
originChunkX, originChunkZ, primer,
absoluteX, absoluteY, absoluteZ,
random.nextFloat() * 0.5 + 0.5, rotation2 + 1.570796, rotation1 / 3, progress, distance, 1.0
random.nextFloat() * 0.5 + 0.5, rotation1 + 1.570796, rotation2 / 3, progress, distance, 1.0
);
return;
}
+65 -19
View File
@@ -1,32 +1,78 @@
import Long from "../../../../../libraries/long.js";
export default class Random {
static instances = 0;
constructor(seed = Date.now() % 1000000000 ^ Random.instances++ * 1000) {
this.mask = 0xffffffff;
this.multiplier = Long.fromString("25214903917");
this.mask = Long.fromInt(1).shiftLeft(48).subtract(1);
this.addend = Long.fromInt(0xB);
this.doubleUnit = 1.1102230246251565E-16;
this.setSeed(seed);
}
nextBoolean() {
return this.nextFloat() > 0.5;
}
nextInt(max = 0x7fffffff) {
return Math.floor(this.nextFloat() * (max + 1));
}
nextFloat() {
this.m_z = (36969 * (this.m_z & 65535) + (this.m_z >>> 16)) & this.mask;
this.m_w = (18000 * (this.m_w & 65535) + (this.m_w >>> 16)) & this.mask;
let result = ((this.m_z << 16) + (this.m_w & 65535)) >>> 0;
result /= 4294967296;
return result;
return this.next(24) / (1 << 24);
}
setSeed(seed) {
this.seed = seed;
this.m_w = (123456789 + seed) & this.mask;
this.m_z = (987654321 - seed) & this.mask;
nextDouble() {
return Long.fromInt(this.next(26)).shiftLeft(27).add(Long.fromInt(this.next(27))).toNumber() * this.doubleUnit;
}
nextInt(max = -1) {
if (max === -1) {
return this.next(32);
}
let r = this.next(31);
let m = max - 1;
if ((max & m) === 0) // i.e., bound is a power of 2
r = Long.fromInt(max).multiply(Long.fromInt(r)).shiftRightUnsigned(31).toNumber();
else {
for (let u = r;
u - (r = u % max) + m < 0;
u = this.next(31))
;
}
return r;
}
nextLong() {
return Long.fromInt(this.next(32)).shiftLeft(32).add(Long.fromInt(this.next(32)));
}
next(bits) {
let oldSeed;
let nextSeed;
do {
oldSeed = this.seed;
nextSeed = oldSeed.multiply(this.multiplier).add(this.addend).and(this.mask);
} while (!this._compareAndSet(oldSeed, nextSeed));
return nextSeed.shiftRight(48 - bits).toNumber();
}
_compareAndSet(expect, update) {
if (!this.seed.equals(expect)) {
return false;
}
this.seed = update;
return true;
}
setSeed(n) {
let long;
if (typeof n === "number") {
long = Long.fromInt(n);
} else if (n instanceof Long) {
long = n;
} else {
long = Long.fromString(n);
}
this.seed = long.xor(this.multiplier).and(this.mask);
}
}
-82
View File
@@ -1,82 +0,0 @@
import Minecraft from './js/net/minecraft/client/Minecraft.js';
let resources = [];
// Script loader
function loadScripts(scripts) {
let total = scripts.length;
let index = 0;
return scripts.reduce((currentPromise, scriptUrl) => {
return currentPromise.then(() => {
return new Promise((resolve, reject) => {
// Update status message
updatePreStatus("Loading scripts... " + index + "/" + total);
// Load script
let script = document.createElement('script');
script.async = true;
script.src = scriptUrl;
script.onload = () => resolve();
document.getElementsByTagName('head')[0].appendChild(script);
index++;
});
});
}, Promise.resolve());
}
// Texture loader
function loadTexture(textures) {
let total = textures.length;
let index = 0;
return textures.reduce((currentPromise, texturePath) => {
return currentPromise.then(() => {
return new Promise((resolve, reject) => {
// Update status message
updatePreStatus("Loading texture... " + index + "/" + total);
// Load texture
let image = new Image();
image.src = "src/resources/" + texturePath;
image.onload = () => resolve();
resources[texturePath] = image;
index++;
});
});
}, Promise.resolve());
}
function updatePreStatus(message) {
document.getElementById("pre-status").innerText = message;
}
// Load textures
loadTexture([
"misc/grasscolor.png",
"gui/font.png",
"gui/gui.png",
"gui/background.png",
"gui/icons.png",
"terrain/terrain.png",
"terrain/sun.png",
"terrain/moon.png",
"char.png"
]).then(() => {
// Load scripts
loadScripts([
// Dependencies
"libraries/three.min.js",
"libraries/stats.min.js",
"libraries/context-filter-polyfill.min.js"
]).then(() => {
// Remove pre status
document.getElementById("pre-status").remove();
// Start Minecraft
window.app = new Minecraft("canvas-container", resources);
});
});