· 5 years ago · Feb 27, 2021, 10:16 PM
1function loadjscssfile(filename, filetype) {
2 let cssNode;
3 if (filetype == "js") {
4 cssNode = document.createElement("script");
5 cssNode.setAttribute("type", "text/javascript");
6 cssNode.setAttribute("src", filename);
7 } else if (filetype == "css") {
8 cssNode = document.createElement("link");
9 cssNode.setAttribute("rel", "stylesheet");
10 cssNode.setAttribute("type", "text/css");
11 cssNode.setAttribute("href", filename);
12 }
13 if (typeof cssNode != "undefined")
14 document.getElementsByTagName("head")[0].appendChild(cssNode);
15}
16
17loadjscssfile("https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.min.js", "js");
18var flags = {
19 SCALE_IGNORE: 1,
20 SCALE_USE_MODD: 2,
21 SCALE_USE_SCALE3D: 4,
22 NAME_OWNER_HIDE: 8,
23 NAME_OWNER_USE_MODD: 16,
24 NAME_OWNER_USE_MODD_AUTOSCALE: 32,
25 NAME_OWNER_USE_MODD_USE_OFFSET3D: 64,
26 ROTATE_IGNORE: 128,
27 ROTATE_USE_MODD: 256,
28 ROTATE_USE_ROTATE3D: 512,
29 ROTATE_USE_QUATERNION: 1024,
30 POSITION_IGNORE: 2048,
31 POSITION_USE_MODD: 4096,
32 POSITION_USE_TRANSLATE: 8192
33};
34
35function rgb8uint(r, g, b) {
36 return (
37 (r << 16) +
38 (g << 8) +
39 (b)
40 );
41}
42
43function rgb8unorm(r, g, b) {
44 return (
45 (Math.floor(r * 255) << 16) +
46 (Math.floor(g * 255) << 8) +
47 (Math.floor(b * 255))
48 );
49}
50
51// eslint-disable-next-line no-unused-vars
52function rgba8uint(r, g, b, a) {
53 return (
54 (r << 24) +
55 (g << 16) +
56 (b << 8) +
57 (a)
58 );
59}
60
61// eslint-disable-next-line no-unused-vars
62function rgba8unorm(r, g, b, a) {
63 return (
64 (Math.floor(r * 255) << 24) +
65 (Math.floor(g * 255) << 16) +
66 (Math.floor(b * 255) << 8) +
67 (Math.floor(a * 255))
68 );
69}
70
71// eslint-disable-next-line no-unused-vars
72function bgr8uint(r, g, b) {
73 return (
74 (b << 16) +
75 (g << 8) +
76 (r)
77 );
78}
79
80// eslint-disable-next-line no-unused-vars
81function bgr8unorm(r, g, b) {
82 return (
83 (Math.floor(b * 255) << 16) +
84 (Math.floor(g * 255) << 8) +
85 (Math.floor(r * 255))
86 );
87}
88
89// eslint-disable-next-line no-unused-vars
90function bgra8uint(r, g, b, a) {
91 return (
92 (b << 24) +
93 (g << 16) +
94 (r << 8) +
95 (a)
96 );
97}
98
99// eslint-disable-next-line no-unused-vars
100function bgra8unorm(r, g, b, a) {
101 return (
102 (Math.floor(b * 255) << 24) +
103 (Math.floor(g * 255) << 16) +
104 (Math.floor(r * 255) << 8) +
105 (Math.floor(a * 255))
106 );
107}
108
109function Begin() {
110 THREE = window.THREE;
111 // HELPER FUNCTION REGION - DO NOT TOUCH
112 /**
113 * @name label
114 * @description Assigns a label to a three.js mesh. Required for instantiating.
115 * @param {*} obj The three.js mesh to label
116 * @param {*} name The label to give the mesh
117 */
118 function label(obj, name) {
119 obj.userData.label = name;
120 return obj;
121 }
122 /**
123 * @name instantiate
124 * @description Instantiates a three.js mesh to the game
125 * @param {*} obj A three.js object to add to the game
126 */
127 function instantiate(obj) {
128 objects[obj.userData.label] = obj;
129 player.scene.add(obj);
130 }
131 /**
132 * @name deinstantiate
133 * @description Deinstantiates an object by it's three.js mesh object from the game.
134 * @param {THREE.Mesh} obj A three.js object to remove from the game.
135 */
136 // eslint-disable-next-line no-unused-vars
137 function deinstantiate(obj) {
138 objects[obj.userData.label] = null;
139 player.scene.remove(obj);
140 }
141
142 /**
143 * @name deinstantiateByName
144 * @description Deinstantiates an object by a name from the game.
145 * @param {String} name The object name to find and deinstantiate
146 */
147 function deinstantiateByName(name) {
148 objects[name] = null;
149 player.scene.remove(
150 player.scene.children.filter(((obj) => obj.userData.label == name))[0]
151 );
152 }
153
154 THREE.PointerLockControls = function ( camera, domElement ) {
155
156 if ( domElement === undefined ) {
157
158 console.warn( "THREE.PointerLockControls: The second parameter \"domElement\" is now mandatory." );
159 domElement = document.body;
160
161 }
162
163 this.domElement = domElement;
164 this.isLocked = false;
165
166 // Set to constrain the pitch of the camera
167 // Range is 0 to Math.PI radians
168 this.minPolarAngle = 0; // radians
169 this.maxPolarAngle = Math.PI; // radians
170
171 //
172 // internals
173 //
174
175 var scope = this;
176
177 var changeEvent = { type: "change" };
178 var lockEvent = { type: "lock" };
179 var unlockEvent = { type: "unlock" };
180
181 var euler = new THREE.Euler( 0, 0, 0, "YXZ" );
182
183 var PI_2 = Math.PI / 2;
184
185 var vec = new THREE.Vector3();
186
187 function onMouseMove( event ) {
188
189 if ( scope.isLocked === false ) return;
190
191 var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
192 var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
193
194 euler.setFromQuaternion( camera.quaternion );
195
196 euler.y -= movementX * 0.002;
197 euler.x -= movementY * 0.002;
198
199 euler.x = Math.max( PI_2 - scope.maxPolarAngle, Math.min( PI_2 - scope.minPolarAngle, euler.x ) );
200
201 camera.quaternion.setFromEuler( euler );
202
203 scope.dispatchEvent( changeEvent );
204
205 }
206
207 function onPointerlockChange() {
208
209 if ( scope.domElement.ownerDocument.pointerLockElement === scope.domElement ) {
210
211 scope.dispatchEvent( lockEvent );
212
213 scope.isLocked = true;
214
215 } else {
216
217 scope.dispatchEvent( unlockEvent );
218
219 scope.isLocked = false;
220
221 }
222
223 }
224
225 function onPointerlockError() {
226
227 console.error( "THREE.PointerLockControls: Unable to use Pointer Lock API" );
228
229 }
230
231 this.connect = function () {
232
233 scope.domElement.ownerDocument.addEventListener( "mousemove", onMouseMove );
234 scope.domElement.ownerDocument.addEventListener( "pointerlockchange", onPointerlockChange );
235 scope.domElement.ownerDocument.addEventListener( "pointerlockerror", onPointerlockError );
236
237 };
238
239 this.disconnect = function () {
240
241 scope.domElement.ownerDocument.removeEventListener( "mousemove", onMouseMove );
242 scope.domElement.ownerDocument.removeEventListener( "pointerlockchange", onPointerlockChange );
243 scope.domElement.ownerDocument.removeEventListener( "pointerlockerror", onPointerlockError );
244
245 };
246
247 this.dispose = function () {
248
249 this.disconnect();
250
251 };
252
253 this.getObject = function () { // retaining this method for backward compatibility
254
255 return camera;
256
257 };
258
259 this.getDirection = function () {
260
261 var direction = new THREE.Vector3( 0, 0, - 1 );
262
263 return function ( v ) {
264
265 return v.copy( direction ).applyQuaternion( camera.quaternion );
266
267 };
268
269 }();
270
271 this.moveForward = function ( distance ) {
272
273 // move forward parallel to the xz-plane
274 // assumes camera.up is y-up
275
276 vec.setFromMatrixColumn( camera.matrix, 0 );
277
278 vec.crossVectors( camera.up, vec );
279
280 camera.position.addScaledVector( vec, distance );
281
282 };
283
284 this.moveRight = function ( distance ) {
285
286 vec.setFromMatrixColumn( camera.matrix, 0 );
287
288 camera.position.addScaledVector( vec, distance );
289
290 };
291
292 this.lock = function () {
293
294 this.domElement.requestPointerLock();
295
296 };
297
298 this.unlock = function () {
299
300 scope.domElement.ownerDocument.exitPointerLock();
301
302 };
303
304 this.connect();
305
306 };
307
308 THREE.PointerLockControls.prototype = Object.create( THREE.EventDispatcher.prototype );
309 THREE.PointerLockControls.prototype.constructor = THREE.PointerLockControls;
310
311 // HELPER FUNCTION REGION - DO NOT TOUCH
312
313
314
315 let clflags = {
316 nodeJs: (typeof require != "undefined"),
317 webGPU: true
318 };
319
320 var labels = [];
321
322 var player = {
323 position: new THREE.Vector3(0, 0, 0),
324 cameraOffset: new THREE.Vector3(0, 100, 500),
325 cameraAngleOffset: new THREE.Euler(0, 0, 0),
326 lookingDirection: new THREE.Vector2(0, 0), // orbital coordinates
327
328 camera: new THREE.PerspectiveCamera,
329 scene: new THREE.Scene,
330 renderer: new THREE.WebGLRenderer,
331 controls: null,
332
333 fov: 75,
334 _ws: null,
335 _chatBox: document.querySelector("#chat-history"),
336 hostPlayerName: "unknown",
337 selfHandle: null
338 };
339
340 var construct = {
341 "#start": function () {
342 var autostart = [
343 label(construct["map"](), "map")
344 ];
345 return autostart;
346 },
347 player: function () {
348 var material = new THREE.MeshStandardMaterial({
349 color: rgb8unorm(0.0, 1.0, 0.0),
350 emissive: rgb8unorm(0.0, 0.2, 0.2)
351 });
352 var geometry = new THREE.SphereBufferGeometry(54, 32, 32);
353 var mesh = new THREE.Mesh(geometry, material);
354 var light = new THREE.PointLight(rgb8uint(0, 255, 255), 1, 1000, 1);
355 mesh.add(light);
356
357 return mesh;
358 },
359 map: function () {
360 var texture = utils.getTexture("https://cache.modd.io/asset/spriteImage/1614462535089_01a344c50286d5a679a51786d29f500d.jpg");
361
362 texture.wrapS = THREE.RepeatWrapping;
363 texture.wrapT = THREE.RepeatWrapping;
364 texture.repeat = new THREE.Vector2(32, 32);
365
366 var material = new THREE.MeshPhongMaterial({
367 map: texture,
368 emissiveMap: texture,
369 emissive: rgb8unorm(0.1, 0.1, 0.1)
370 });
371 console.log(texture);
372 var geometry = new THREE.BoxBufferGeometry(8192, 2, 8192);
373
374 var ground = new THREE.Mesh(geometry, material);
375 ground.position.y = -56;
376 ground.position.x = 2048;
377 ground.position.z = 2048;
378 const spotLight = new THREE.SpotLight(0xffffff);
379 spotLight.position.set(1024, 1000, 1024);
380
381 spotLight.castShadow = true;
382
383 spotLight.shadow.mapSize.width = 1024;
384 spotLight.shadow.mapSize.height = 1024;
385
386 spotLight.shadow.camera.near = 5;
387 spotLight.shadow.camera.far = 4000;
388 spotLight.shadow.camera.fov = 60;
389
390 var map = new THREE.Object3D();
391 map.add(ground);
392 //map.add(spotLight);
393
394 return map;
395 },
396 "Unit: human": function () {
397 var material = new THREE.MeshStandardMaterial({
398 color: rgb8unorm(0.0, 1.0, 0.0)
399 });
400 var geometry = new THREE.SphereBufferGeometry(5, 32, 32);
401 var mesh = new THREE.Mesh(geometry, material);
402 return mesh;
403 },
404 "Unit: zombie": function () {
405 var material = new THREE.MeshStandardMaterial({
406 color: rgb8unorm(1.0, 0.0, 0.0)
407 });
408 var geometry = new THREE.SphereBufferGeometry(5, 32, 32);
409 var mesh = new THREE.Mesh(geometry, material);
410 return mesh;
411 }
412 };
413
414 var utils = {
415 textureAssetStore: {},
416 loader: new THREE.TextureLoader(),
417 /**
418 * @name getTexture
419 * @description Gets a texture from a given URL. MAKE SURE IT DOES NOT SCREW WITH CORS, OTHERWISE YOUR TEXURE WON'T LOAD!!!
420 * @param {*} url The texture URL to load it from
421 * @returns {THREE.Texture}
422 */
423 getTexture: function(url) {
424 if (url in this.textureAssetStore) {
425 return this.textureAssetStore[url].map;
426 } else {
427 var texture = this.loader.load(url);
428 this.textureAssetStore[url] = {
429 map: texture
430 };
431 return texture;
432 }
433 }
434 };
435
436 if (clflags.nodeJs) {
437 var THREE = require("three.js");
438 }
439
440 // eslint-disable-next-line no-undef
441 if ("local" in user) {
442 // eslint-disable-next-line no-undef
443 player.hostPlayerName = user.local.username;
444 }
445
446
447 function HookWS() {
448 WebSocket.prototype.baseSend = WebSocket.prototype.send;
449 WebSocket.prototype.send = function (e) {
450 var send = true;
451 try {
452
453 var f = JSON.parse(e);
454 if (Array.isArray(f)) {
455 // we want to filter out the arctan and cursor pos
456 switch (f[0]) {
457 case "\u0004":
458 if (player.hostPlayerName == "unknown") {
459 player.hostPlayerName = "user" + f[1].number;
460 }
461 send = true;
462 break;
463 }
464 if (!player._ws) {
465 console.log("Found a good websocket, hooking..");
466 player._ws = this;
467 player._ws.addEventListener("message", (e) => {
468 // eslint-disable-next-line no-undef
469 var de = LZString.decompressFromUTF16(e.data);
470 var dj = JSON.parse(de);
471 HandleSnapshot(dj);
472
473 });
474 }
475 HandleSnapshot(f);
476 }
477
478 } catch {}
479 if (send) this.baseSend(JSON.stringify(f));
480 };
481 }
482
483 var game = {
484 units: {
485
486 },
487 players: {
488
489 }
490 };
491
492 function HandleSnapshot(dt) {
493 var kind = dt[0];
494 var data = dt[1];
495 switch (kind) {
496 case "\u0003":
497 data.forEach(cdata => {
498 switch (cdata[0]) {
499 case "A":
500 var entityType = cdata[1][0];
501 var entityId = cdata[1][1];
502 // eslint-disable-next-line no-unused-vars
503 var scene = cdata[1][2];
504 // eslint-disable-next-line no-unused-vars
505 var transform = cdata[1][3];
506 var entityData = cdata[1][4];
507
508 // eslint-disable-next-line no-prototype-builtins
509 if (game.units.hasOwnProperty(entityId)) return;
510
511 switch (entityType) {
512 case "Unit":
513 var mesh = label(construct["player"](entityData.name), entityId);
514 game.units[entityId] = {
515 object3D: mesh,
516 id: entityId,
517 name: entityData.name,
518 ownerPlayer: entityData.ownerPlayerId,
519 flags: flags.SCALE_IGNORE + flags.NAME_OWNER_USE_MODD_AUTOSCALE + flags.ROTATE_USE_MODD + flags.POSITION_USE_MODD,
520 self: player.hostPlayerName == entityData.name,
521 type: entityData.type
522 };
523 instantiate(mesh);
524
525 if (player.hostPlayerName == entityData.name) {
526 player.selfHandle = game.units[entityId];
527 }
528
529 break;
530 case "Player":
531 game.players[entityId] = {
532 name: entityData.name,
533 coins: entityData.coins,
534 clientId: entityData.clientId,
535 userId: entityData.userId
536 };
537 }
538 break;
539 case "C":
540 var left = cdata[1][1];
541 // eslint-disable-next-line no-prototype-builtins
542 if (game.units.hasOwnProperty(left)) {
543 deinstantiateByName(left);
544 game.units[left] = null;
545 }
546 // eslint-disable-next-line no-prototype-builtins
547 if (game.players.hasOwnProperty(left)) {
548 game.players[left] = null;
549 }
550 break;
551 default:
552
553 if (typeof cdata == "string" && cdata.startsWith("D")) {
554 var dat = cdata.split("&");
555 var handle = game.units[dat[0].substring(1)];
556 if (handle.flags & flags.POSITION_USE_MODD > 0) {
557 var pos = new THREE.Vector3(Number.parseInt(dat[1], 16), 0, Number.parseInt(dat[2], 16));
558 handle.object3D.position.copy(pos);
559 if (handle.self) {
560 player.camera.position.copy(pos.clone());
561 }
562 }
563 if (handle.flags & flags.ROTATE_USE_MODD > 0) {
564 // todo: add rotation, Number.parseInt(dat[3], 16)
565 }
566 }
567 break;
568 }
569 });
570 break;
571 }
572 }
573
574 var objects = {};
575
576 if (clflags.webGPU) {
577 if (!navigator.gpu || !document.createElement("canvas").getContext("gpuweb")) {
578 console.log("It is listed to use WebGPU in flags - but sadly your browser doesn't support it");
579 clflags.webGPU = false;
580 }
581 }
582 if (clflags.webGPU) {
583 console.log("You are using an experimental version of a rendering engine. Be careful!");
584 } else {
585 // fallback to WebGL
586 try {
587 player.scene = new THREE.Scene();
588 player.camera = new THREE.PerspectiveCamera(player.fov, window.innerWidth / window.innerHeight, 0.1, 100000);
589 player.renderer = new THREE.WebGLRenderer({
590 logarithmicDepthBuffer: true,
591 antialias: true
592 });
593 player.camera.rotation.order = "YXZ";
594 player.renderer.setSize(window.innerWidth, window.innerHeight);
595
596 window.addEventListener( "resize", onWindowResize, false );
597
598
599 } catch (e) {
600 LogError("Scene creation failed. (1057)");
601 return;
602 }
603 }
604
605 function onWindowResize(){
606
607 player.camera.aspect = window.innerWidth / window.innerHeight;
608 player.camera.updateProjectionMatrix();
609
610 player.renderer.setSize( window.innerWidth, window.innerHeight );
611
612 }
613
614 // Let's start the mayhem!
615 // 1. Let's autostart
616 try {
617 var autostart = construct["#start"]();
618
619 autostart.forEach(e => {
620 instantiate(e);
621 });
622 } catch (e) {
623 LogError("Autostart script(s) failed. This can be a game issue. (1061)");
624 console.log(e);
625 return;
626 }
627 // 2. Turn off the lights and append
628
629 try {
630 var crap = document.getElementById("igeFrontBuffer");
631 crap.parentNode.removeChild(crap);
632
633 document.querySelector("#game-div").appendChild(player.renderer.domElement);
634 } catch (e) {
635 LogError("Renderer append failed. (1065)");
636 return;
637 }
638
639 HookWS();
640 player.controls = new THREE.PointerLockControls(player.camera, document.body);
641 player.renderer.domElement.addEventListener("click", function() {
642 player.controls.lock();
643 });
644 player.scene.add(player.controls.getObject());
645 window.player = player;
646
647 player.controls.addEventListener("change", function() {
648 var angle = player.controls.getObject().rotation.y;
649 player._ws.send("[\"\\r\"," + angle*2 + "]");
650 player._ws.send("[\"\\u000b\",[" + (-Math.sin(angle) * 100 + player.selfHandle.object3D.position.x) + "," + (-Math.cos(angle) * 100 + player.selfHandle.object3D.position.z) + "]]");
651 });
652
653
654 function LogError(message) {
655 var errorDiv = document.createElement("div");
656 errorDiv.innerHTML = `
657 <span style="color: rgb(227, 26, 0);">
658 --- Error ---
659 </span>
660 `;
661 var detailsDiv = document.createElement("div");
662 detailsDiv.innerHTML = `
663 <span style="color: rgb(227, 26, 0);">
664 Details: ` + message + `
665 </span>
666 `;
667 errorDiv.style.verticalAlign = "middle";
668 errorDiv.style.textAlign = "center";
669 player._chatBox.appendChild(errorDiv);
670 player._chatBox.appendChild(detailsDiv);
671 }
672
673 /*
674 Error key:
675 1053 - no reliable rendering context found
676 1057 - scene creation failed
677 1061 - autorun error
678 1065 - renderer dom append failed
679 */
680
681 function animate() {
682 requestAnimationFrame(animate);
683 labels.forEach(lab => {
684 lab.quaternion.copy(player.camera.quaternion);
685 });
686 player.renderer.render(player.scene, player.camera);
687 }
688 animate();
689}
690var int = setInterval(() => {
691 if (typeof THREE != "undefined") {
692 clearInterval(int);
693 Begin();
694 }
695}, 1000);