implement creative inventory, implement bedrock, glass and gravel, version 1.0.4

This commit is contained in:
LabyStudio
2022-05-20 01:30:31 +02:00
parent f85d84e2a3
commit 34b0015af6
35 changed files with 601 additions and 76 deletions
+1
View File
@@ -57,6 +57,7 @@ Click [here](https://labystudio.de/page/minecraft/) for a demo!
- Options Screen
- Controls Screen
- Chat Input Screen
- Creative Inventory Screen
- Widgets
- Button
- KeyBinding
+1 -1
View File
@@ -1,7 +1,7 @@
<html lang="en">
<head>
<title>Minecraft</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
<link rel="shortcut icon" href="src/resources/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style.css"/>
</head>
+2 -1
View File
@@ -40,7 +40,8 @@ class Start {
"gui/title/background/panorama_2.png",
"gui/title/background/panorama_3.png",
"gui/title/background/panorama_4.png",
"gui/title/background/panorama_5.png"
"gui/title/background/panorama_5.png",
"gui/container/creative.png"
]).then((resources) => {
// Launch actual game on canvas
window.app = new Minecraft(canvasWrapperId, resources);
@@ -5,6 +5,7 @@ export default class GameSettings {
this.keySprinting = 'ControlLeft';
this.keyTogglePerspective = 'F5';
this.keyOpenChat = 'KeyT';
this.keyOpenInventory = 'KeyE';
this.thirdPersonView = 0;
this.fov = 70;
@@ -12,6 +13,7 @@ export default class GameSettings {
this.ambientOcclusion = true;
this.sensitivity = 100;
this.viewDistance = 4;
this.debugOverlay = false;
}
load() {
+18 -8
View File
@@ -35,6 +35,10 @@ export default class GameWindow {
this.canvasItems = document.createElement('canvas');
this.wrapper.appendChild(this.canvasItems);
this.canvas.addEventListener("webglcontextlost", function (event) {
event.preventDefault();
}, false);
let mouseDownInterval = null;
// Request focus
@@ -48,13 +52,16 @@ export default class GameWindow {
// Focus listener
document.addEventListener('pointerlockchange', _ => this.onFocusChanged(), false);
document.addEventListener('pointerlockerror', e => {
e.preventDefault()
}, false);
// Mouse motion
document.addEventListener('mousemove', event => {
this.onMouseMove(event);
// Handle mouse move on screen
if (!(minecraft.currentScreen === null)) {
if (minecraft.currentScreen !== null) {
minecraft.currentScreen.mouseDragged(event.x / this.scaleFactor, event.y / this.scaleFactor, event.code);
}
}, false);
@@ -62,7 +69,7 @@ export default class GameWindow {
// Mouse release
document.addEventListener('mouseup', event => {
// Handle mouse release on screen
if (!(minecraft.currentScreen === null)) {
if (minecraft.currentScreen !== null) {
minecraft.currentScreen.mouseReleased(event.x / this.scaleFactor, event.y / this.scaleFactor, event.code);
}
@@ -71,7 +78,7 @@ export default class GameWindow {
// Losing focus event
this.canvas.addEventListener("mouseout", () => {
if (minecraft.currentScreen === null) {
if (minecraft.currentScreen === null && !this.actualMouseLocked) {
minecraft.displayScreen(new GuiIngameMenu());
}
@@ -102,19 +109,22 @@ export default class GameWindow {
}
// Handle mouse click on screen
if (!(minecraft.currentScreen === null)) {
if (minecraft.currentScreen !== null) {
minecraft.currentScreen.mouseClicked(event.x / this.scaleFactor, event.y / this.scaleFactor, event.code);
}
}, false);
// Mouse scroll
document.addEventListener('wheel', (event) => {
this.wrapper.addEventListener('wheel', (event) => {
event.preventDefault();
event.stopPropagation();
let delta = Math.sign(event.deltaY);
minecraft.onMouseScroll(delta);
}, false);
// Keyboard interaction with screen
window.addEventListener('keydown', (event) => {
window.addEventListener('keydown', event => {
if (event.code === "F11") {
return; // Toggle fullscreen
}
@@ -122,7 +132,7 @@ export default class GameWindow {
// Prevent key
event.preventDefault();
if (!(minecraft.currentScreen === null)) {
if (minecraft.currentScreen !== null) {
// Handle key type on screen
minecraft.currentScreen.keyTyped(event.code, event.key);
} else if (event.code === 'Escape') {
@@ -137,7 +147,7 @@ export default class GameWindow {
// Prevent key
event.preventDefault();
if (!(minecraft.currentScreen === null)) {
if (minecraft.currentScreen !== null) {
// Handle key release on screen
minecraft.currentScreen.keyReleased(event.code);
}
+27 -2
View File
@@ -18,10 +18,11 @@ import * as THREE from "../../../../../libraries/three.module.js";
import ParticleRenderer from "./render/particle/ParticleRenderer.js";
import GuiChat from "./gui/screens/GuiChat.js";
import CommandHandler from "./command/CommandHandler.js";
import GuiContainerCreative from "./gui/screens/container/GuiContainerCreative.js";
export default class Minecraft {
static VERSION = "1.0.3"
static VERSION = "1.0.4"
static URL_GITHUB = "https://github.com/labystudio/js-minecraft";
/**
@@ -113,6 +114,7 @@ export default class Minecraft {
// Create player
this.player = new PlayerEntity(this, this.world);
this.player.username = "Player" + Math.floor(Math.random() * 100);
this.world.addEntity(this.player);
// Load spawn chunks and respawn player
@@ -199,7 +201,7 @@ export default class Minecraft {
}
// Close previous screen
if (!(this.currentScreen === null)) {
if (this.currentScreen !== null) {
this.currentScreen.onClose();
}
@@ -275,20 +277,33 @@ export default class Minecraft {
}
onKeyPressed(button) {
// Select slot
for (let i = 1; i <= 9; i++) {
if (button === 'Digit' + i) {
this.player.inventory.selectedSlotIndex = i - 1;
}
}
// Toggle perspective
if (button === this.settings.keyTogglePerspective) {
this.settings.thirdPersonView = (this.settings.thirdPersonView + 1) % 3;
this.settings.save();
}
// Open chat
if (button === this.settings.keyOpenChat) {
this.displayScreen(new GuiChat());
}
// Toggle debug overlay
if (button === "F3") {
this.settings.debugOverlay = !this.settings.debugOverlay;
}
// Open inventory
if (button === this.settings.keyOpenInventory) {
this.displayScreen(new GuiContainerCreative(this.player));
}
}
onMouseClicked(button) {
@@ -331,6 +346,16 @@ export default class Minecraft {
if (hitResult != null) {
let typeId = this.world.getBlockAt(hitResult.x, hitResult.y, hitResult.z);
if (typeId !== 0) {
// Switch to slot if item is already in hotbar
for (const item of this.player.inventory.items) {
const index = this.player.inventory.items.indexOf(item);
if (item === typeId && index <= 8) {
this.player.inventory.selectedSlotIndex = index;
return;
}
}
// Set item in hotbar
this.player.inventory.setItemInSelectedSlot(typeId);
}
}
@@ -1,10 +1,10 @@
import Inventory from "../inventory/Inventory.js";
import EntityLiving from "./EntityLiving.js";
import Block from "../world/block/Block.js";
import MathHelper from "../../util/MathHelper.js";
import Keyboard from "../../util/Keyboard.js";
import Vector3 from "../../util/Vector3.js";
import {BlockRegistry} from "../world/block/BlockRegistry.js";
import InventoryPlayer from "../inventory/inventory/InventoryPlayer.js";
export default class PlayerEntity extends EntityLiving {
@@ -13,7 +13,8 @@ export default class PlayerEntity extends EntityLiving {
constructor(minecraft, world) {
super(minecraft, world);
this.inventory = new Inventory();
this.inventory = new InventoryPlayer();
this.username = "Player";
this.collision = false;
+2 -2
View File
@@ -20,8 +20,8 @@ export default class Gui {
this.minecraft.fontRenderer.drawString(stack, string, x - this.getStringWidth(stack, string), y, color);
}
drawString(stack, string, x, y, color = -1) {
this.minecraft.fontRenderer.drawString(stack, string, x, y, color);
drawString(stack, string, x, y, color = -1, shadow = true) {
this.minecraft.fontRenderer.drawString(stack, string, x, y, color, shadow);
}
getStringWidth(stack, string) {
@@ -1,6 +1,7 @@
import Gui from "../Gui.js";
import Block from "../../world/block/Block.js";
import ChatOverlay from "./ChatOverlay.js";
import Minecraft from "../../Minecraft.js";
export default class IngameOverlay extends Gui {
@@ -40,8 +41,12 @@ export default class IngameOverlay extends Gui {
let lightLevel = world.getTotalLightAt(x, y, z);
// Debug
this.drawString(stack, fps + " fps," + " " + lightUpdates + " light updates," + " " + chunkUpdates + " chunk updates", 1, 1);
this.drawString(stack, x + ", " + y + ", " + z + " (" + (x >> 4) + ", " + (y >> 4) + ", " + (z >> 4) + ")", 1, 1 + 9);
if (this.minecraft.settings.debugOverlay) {
this.drawString(stack, "js-minecraft " + Minecraft.VERSION, 1, 1);
this.drawString(stack, fps + " fps," + " " + lightUpdates + " light updates," + " " + chunkUpdates + " chunk updates", 1, 1 + 9 * 1);
this.drawString(stack, x + ", " + y + ", " + z + " (" + (x >> 4) + ", " + (y >> 4) + ", " + (z >> 4) + ")", 1, 1 + 9 * 2);
this.drawString(stack, "Light: " + lightLevel, 1, 1 + 9 * 3);
}
}
onTick() {
@@ -65,13 +70,17 @@ export default class IngameOverlay extends Gui {
24, 24
)
// To make the items darker
let brightness = this.minecraft.isPaused() ? 0.5 : 1; // TODO find a better solution
this.minecraft.itemRenderer.prepareRender("hotbar");
// Render items
for (let i = 0; i < 9; i++) {
let typeId = this.minecraft.player.inventory.getItemInSlot(i);
if (typeId !== 0) {
let renderId = "hotbar" + i;
let block = Block.getById(typeId);
this.minecraft.itemRenderer.renderItemInGui(renderId, block, Math.floor(x + i * 20 + 11), y + 11);
this.minecraft.itemRenderer.renderItemInGui("hotbar", i, block, Math.floor(x + i * 20 + 11), y + 11, brightness);
}
}
}
@@ -47,7 +47,7 @@ export default class GuiChat extends GuiScreen {
if (message.startsWith("/")) {
this.minecraft.commandHandler.handleMessage(message.substring(1));
} else {
this.minecraft.addMessageToChat(message);
this.minecraft.addMessageToChat("<" + this.minecraft.player.username + "> " + message);
}
return;
}
@@ -0,0 +1,136 @@
import GuiScreen from "../GuiScreen.js";
import Block from "../../world/block/Block.js";
export default class GuiContainer extends GuiScreen {
constructor(container) {
super();
this.inventoryWidth = 176;
this.inventoryHeight = 166;
this.container = container;
this.hoverSlot = null;
}
init() {
super.init();
this.x = Math.floor((this.width - this.inventoryWidth) / 2);
this.y = Math.floor((this.height - this.inventoryHeight) / 2);
}
drawScreen(stack, mouseX, mouseY, partialTicks) {
this.drawDefaultBackground(stack);
this.drawInventoryBackground(stack);
this.drawString(stack, "Creative Inventory", this.x + 8, this.y + 6, 0x404040);
// Rebuild items
if (this.container.dirty) {
this.container.dirty = false;
this.minecraft.itemRenderer.destroy("inventory");
this.minecraft.itemRenderer.scheduleDirty("hotbar");
}
// Draw slots
this.hoverSlot = null;
this.container.slots.forEach(slot => {
this.drawSlot(stack, slot, mouseX, mouseY);
});
// Draw item in cursor
let inventoryPlayer = this.minecraft.player.inventory;
let typeId = inventoryPlayer.itemInCursor;
if (typeId !== null && typeId !== 0) {
let block = Block.getById(typeId);
this.minecraft.itemRenderer.zIndex = 10;
this.minecraft.itemRenderer.renderItemInGui(
"inventory",
"cursor",
block,
mouseX,
mouseY
);
this.minecraft.itemRenderer.zIndex = 0;
} else {
this.minecraft.itemRenderer.destroy("inventory", "cursor");
}
// Draw title
this.drawTitle(stack);
super.drawScreen(stack, mouseX, mouseY, partialTicks);
}
mouseClicked(mouseX, mouseY, mouseButton) {
super.mouseClicked(mouseX, mouseY, mouseButton);
for (const slot of this.container.slots) {
if (this.isMouseOverSlot(slot, mouseX, mouseY)) {
this.container.onSlotClick(slot, this.minecraft.player);
}
}
}
keyTyped(key, character) {
// Swap to slot
for (let i = 1; i <= 9; i++) {
if (key === 'Digit' + i) {
this.container.swapWithHotbar(this.hoverSlot, this.minecraft.player.inventory, i - 1);
}
}
return super.keyTyped(key, character);
}
drawSlot(stack, slot, mouseX, mouseY) {
let x = this.x + slot.x;
let y = this.y + slot.y;
let inventory = slot.inventory;
let typeId = inventory.getItemInSlot(slot.index);
let isMouseOver = this.isMouseOverSlot(slot, mouseX, mouseY);
// Render item
if (typeId !== null && typeId !== 0) {
let block = Block.getById(typeId);
this.minecraft.itemRenderer.renderItemInGui(
"inventory",
inventory.name + ":" + slot.index,
block,
x + 8,
y + 8,
isMouseOver ? 1.5 : 1
);
}
// Hover rectangle
if (isMouseOver) {
this.drawRect(stack, x, y, x + 16, y + 16, '#ffffff', 0.5);
this.hoverSlot = slot;
}
}
onClose() {
super.onClose();
this.minecraft.player.inventory.itemInCursor = null;
this.minecraft.itemRenderer.destroy("inventory");
}
drawTitle(stack) {
}
drawInventoryBackground(stack) {
}
isMouseOverSlot(slot, mouseX, mouseY) {
let x = this.x + slot.x;
let y = this.y + slot.y;
return mouseX >= x && mouseX <= x + 16 && mouseY >= y && mouseY <= y + 16;
}
}
@@ -23,22 +23,26 @@ export default class GuiControls extends GuiScreen {
return name + ": " + value + "%";
}));
this.buttonList.push(new GuiKeyButton("Crouch", settings.keyCrouching, this.width / 2 - 100, y + 24, 200, 20, key => {
this.buttonList.push(new GuiKeyButton("Crouch", settings.keyCrouching, this.width / 2 - 100, y + 24, 98, 20, key => {
settings.keyCrouching = key;
}));
this.buttonList.push(new GuiKeyButton("Sprint", settings.keySprinting, this.width / 2 - 100, y + 24 * 2, 200, 20, key => {
this.buttonList.push(new GuiKeyButton("Sprint", settings.keySprinting, this.width / 2 + 2, y + 24, 98, 20, key => {
settings.keySprinting = key;
}));
this.buttonList.push(new GuiKeyButton("Toggle Perspective", settings.keyTogglePerspective, this.width / 2 - 100, y + 24 * 3, 200, 20, key => {
this.buttonList.push(new GuiKeyButton("Toggle Perspective", settings.keyTogglePerspective, this.width / 2 - 100, y + 24 * 2, 200, 20, key => {
settings.keyTogglePerspective = key;
}));
this.buttonList.push(new GuiKeyButton("Open Chat", settings.keyOpenChat, this.width / 2 - 100, y + 24 * 4, 200, 20, key => {
this.buttonList.push(new GuiKeyButton("Open Chat", settings.keyOpenChat, this.width / 2 - 100, y + 24 * 3, 200, 20, key => {
settings.keyOpenChat = key;
}));
this.buttonList.push(new GuiKeyButton("Open Inventory", settings.keyOpenInventory, this.width / 2 - 100, y + 24 * 4, 200, 20, key => {
settings.keyOpenInventory = key;
}));
this.buttonList.push(new GuiButton("Done", this.width / 2 - 100, y + 130, 200, 20, () => {
this.minecraft.displayScreen(this.previousScreen);
}));
@@ -0,0 +1,50 @@
import GuiContainer from "../GuiContainer.js";
import ContainerCreative from "../../../inventory/container/ContainerCreative.js";
import InventoryBasic from "../../../inventory/inventory/InventoryBasic.js";
export default class GuiContainerCreative extends GuiContainer {
static inventory = new InventoryBasic();
constructor(player) {
super(new ContainerCreative(player));
this.inventoryWidth = 195;
this.inventoryHeight = 136;
}
init() {
this.textureInventory = this.getTexture("gui/container/creative.png");
super.init();
}
drawTitle(stack) {
this.drawString(stack, "Creative Inventory", this.x + 8, this.y + 6, 0xff404040, false);
}
drawInventoryBackground(stack) {
this.drawSprite(
stack,
this.textureInventory,
0,
0,
this.inventoryWidth,
this.inventoryHeight,
this.x,
this.y,
this.inventoryWidth,
this.inventoryHeight
);
}
keyTyped(key, character) {
if (key === this.minecraft.settings.keyOpenInventory) {
this.minecraft.displayScreen(null);
return true;
}
return super.keyTyped(key, character);
}
}
@@ -0,0 +1,38 @@
export default class Container {
constructor() {
this.slots = [];
this.dirty = true;
}
addSlot(slot) {
this.slots.push(slot);
}
swapWithHotbar(slot, inventoryPlayer, hotbarIndex) {
let slotInventory = slot.inventory;
let typeId = slotInventory.getItemInSlot(slot.index);
let hotbarTypeId = inventoryPlayer.getItemInSlot(hotbarIndex);
slotInventory.setItem(slot.index, hotbarTypeId);
inventoryPlayer.setItem(hotbarIndex, typeId);
this.dirty = true;
}
onSlotClick(slot, player) {
let inventoryPlayer = player.inventory;
let typeId = slot.inventory.getItemInSlot(slot.index);
if(inventoryPlayer.itemInCursor === null || inventoryPlayer.itemInCursor === 0) {
slot.inventory.setItem(slot.index, 0);
inventoryPlayer.itemInCursor = typeId;
} else {
slot.inventory.setItem(slot.index, inventoryPlayer.itemInCursor);
inventoryPlayer.itemInCursor = typeId;
}
this.dirty = true;
}
}
@@ -1,37 +1,15 @@
export default class Inventory {
constructor() {
this.selectedSlotIndex = 0;
this.items = [];
// Default items in inventory
this.items[0] = 1;
this.items[1] = 2;
this.items[2] = 3;
this.items[3] = 5;
this.items[4] = 17;
this.items[5] = 18;
this.items[6] = 12;
this.items[7] = 50;
constructor(name) {
this.name = name;
}
setItemInSelectedSlot(typeId) {
this.items[this.selectedSlotIndex] = typeId;
getItemInSlot(index) {
}
getItemInSelectedSlot() {
return this.getItemInSlot(this.selectedSlotIndex);
setItem(index, typeId) {
}
shiftSelectedSlot(offset) {
if (this.selectedSlotIndex + offset < 0) {
this.selectedSlotIndex = 9 + (this.selectedSlotIndex + offset);
} else {
this.selectedSlotIndex = (this.selectedSlotIndex + offset) % 9;
}
}
getItemInSlot(slot) {
return this.items.hasOwnProperty(slot) ? this.items[slot] : 0;
}
}
@@ -0,0 +1,10 @@
export default class Slot {
constructor(inventory, index, x, y) {
this.inventory = inventory;
this.index = index;
this.x = x;
this.y = y;
}
}
@@ -0,0 +1,78 @@
import Container from "../Container.js";
import GuiContainerCreative from "../../gui/screens/container/GuiContainerCreative.js";
import Slot from "../Slot.js";
import Block from "../../world/block/Block.js";
import InventoryPlayer from "../inventory/InventoryPlayer.js";
export default class ContainerCreative extends Container {
constructor(player) {
super();
this.itemList = [];
let playerInventory = player.inventory;
// Add creative inventory slots
for (let y = 0; y < 5; ++y) {
for (let x = 0; x < 9; ++x) {
this.addSlot(new Slot(GuiContainerCreative.inventory, y * 9 + x, 9 + x * 18, 18 + y * 18));
}
}
// Add player hotbar
for (let x = 0; x < 9; ++x) {
this.addSlot(new Slot(playerInventory, x, 9 + x * 18, 112));
}
this.initItems();
this.scrollTo(0);
}
swapWithHotbar(slot, inventoryPlayer, hotbarIndex) {
let slotInventory = slot.inventory;
let typeId = slotInventory.getItemInSlot(slot.index);
inventoryPlayer.setItem(hotbarIndex, typeId);
this.dirty = true;
}
onSlotClick(slot, player) {
if (slot.inventory instanceof InventoryPlayer) {
super.onSlotClick(slot, player);
} else {
let inventoryPlayer = player.inventory;
inventoryPlayer.itemInCursor = slot.inventory.getItemInSlot(slot.index);
}
this.dirty = true;
}
scrollTo(scrollOffset) {
let xOffset = (this.itemList.length + 9 - 1) / 9 - 5;
let yOffset = Math.floor((scrollOffset * xOffset) + 0.5);
if (yOffset < 0) {
yOffset = 0;
}
for (let y = 0; y < 5; ++y) {
for (let x = 0; x < 9; ++x) {
let index = x + (y + yOffset) * 9;
if (index >= 0 && index < this.itemList.length) {
GuiContainerCreative.inventory.setItem(x + y * 9, this.itemList[index]);
} else {
GuiContainerCreative.inventory.setItem(x + y * 9, null);
}
}
}
}
initItems() {
Block.blocks.forEach((block) => {
this.itemList.push(block.getId());
});
}
}
@@ -0,0 +1,11 @@
import Container from "../Container.js";
export default class ContainerPlayer extends Container {
constructor() {
super();
}
}
@@ -0,0 +1,19 @@
import Inventory from "../Inventory.js";
export default class InventoryBasic extends Inventory {
constructor() {
super("basic");
this.items = [];
}
getItemInSlot(index) {
return this.items[index];
}
setItem(index, typeId) {
this.items[index] = typeId;
}
}
@@ -0,0 +1,36 @@
import Inventory from "../Inventory.js";
export default class InventoryPlayer extends Inventory {
constructor() {
super("player");
this.selectedSlotIndex = 0;
this.itemInCursor = null;
this.items = [];
}
setItem(index, typeId) {
this.items[index] = typeId === null ? 0 : typeId;
}
setItemInSelectedSlot(typeId) {
this.items[this.selectedSlotIndex] = typeId;
}
getItemInSelectedSlot() {
return this.getItemInSlot(this.selectedSlotIndex);
}
shiftSelectedSlot(offset) {
if (this.selectedSlotIndex + offset < 0) {
this.selectedSlotIndex = 9 + (this.selectedSlotIndex + offset);
} else {
this.selectedSlotIndex = (this.selectedSlotIndex + offset) % 9;
}
}
getItemInSlot(slot) {
return this.items.hasOwnProperty(slot) ? this.items[slot] : 0;
}
}
@@ -161,7 +161,7 @@ export default class BlockRenderer {
let block = typeId === 0 ? null : Block.getById(typeId);
// Does it contain air?
if (block === null || !block.isSolid()) {
if (block === null || block.isTranslucent()) {
// Sum up the light levels
totalLightLevel += world.getTotalLightAt(x + offsetX, y + offsetY, z + offsetZ);
totalBlocks++;
@@ -402,6 +402,6 @@ export default class BlockRenderer {
maxV += offset;
// Render item
this.addFace(null, EnumBlockFace.NORTH, false, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV);
this.addFace(null, EnumBlockFace.NORTH, false, 0, 0, 0, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV);
}
}
@@ -7,6 +7,7 @@ export default class FontRenderer {
static FIELD_SIZE = 8;
static COLOR_CODE_INDEX_LOOKUP = "0123456789abcdef";
static CHAR_INDEX_LOOKUP = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
constructor(minecraft) {
this.charWidths = [];
@@ -47,8 +48,8 @@ export default class FontRenderer {
return 2;
}
drawString(stack, string, x, y, color = -1) {
if (!this.isSafari) { // TODO Fix filter on Safari
drawString(stack, string, x, y, color = -1, shadow = true) {
if (!this.isSafari && shadow) { // TODO Fix filter on Safari
this.drawStringRaw(stack, string, x + 1, y + 1, color, true);
}
this.drawStringRaw(stack, string, x, y, color);
@@ -67,7 +68,7 @@ export default class FontRenderer {
// For each character
for (let i = 0; i < string.length; i++) {
let character = string[i];
let index = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000".indexOf(character);
let index = FontRenderer.CHAR_INDEX_LOOKUP.indexOf(character);
let code = character.charCodeAt(0);
// Handle color codes if character is &
@@ -7,13 +7,14 @@ export default class ItemRenderer {
this.window = window;
this.items = [];
this.zIndex = 0;
this.scheduledDirty = [];
}
initialize() {
// Create item camera
this.camera = new THREE.OrthographicCamera(0, 0, 0, 0, 0, 300);
this.camera.near = 0;
this.camera.far = 15;
this.camera = new THREE.OrthographicCamera(0, 0, 0, 0, -15, 15);
this.camera.rotation.order = 'ZYX';
this.camera.up = new THREE.Vector3(0, 1, 0);
@@ -50,33 +51,43 @@ export default class ItemRenderer {
this.webRenderer.render(this.scene, this.camera);
}
renderItemInGui(renderId, block, x, y) {
let meta = this.items[renderId];
prepareRender(groupId) {
if (this.scheduledDirty.includes(groupId)) {
this.scheduledDirty.splice(this.scheduledDirty.indexOf(groupId), 1);
this.destroy(groupId);
}
}
renderItemInGui(groupId, renderId, block, x, y, brightness = 1) {
let pairId = groupId + ':' + renderId;
let meta = this.items[pairId];
if (typeof meta === "undefined") {
let meta = {};
// To make the items darker
let paused = this.minecraft.isPaused();
// Render item
let group = new THREE.Group();
this.minecraft.worldRenderer.blockRenderer.renderGuiBlock(group, block, x, y, 10, paused ? 0.5 : 1);
this.minecraft.worldRenderer.blockRenderer.renderGuiBlock(group, block, x, y, 10, brightness);
group.position.z = this.zIndex;
group.updateMatrix();
this.scene.add(group);
// Create meta
meta.renderId = renderId;
meta.groupId = groupId;
meta.group = group;
meta.brightness = brightness;
meta.typeId = block.getId();
meta.x = x;
meta.y = y;
meta.dirty = false;
this.items[renderId] = meta;
this.items[pairId] = meta;
} else {
// Check if rendered item has changed
if (meta.dirty || meta.typeId !== block.getId() || meta.x !== x || meta.y !== y) {
if (meta.dirty || meta.typeId !== block.getId() || meta.x !== x || meta.y !== y || meta.brightness !== brightness) {
// Rebuild item
this.scene.remove(meta.group);
delete this.items[renderId];
this.renderItemInGui(renderId, block, x, y);
delete this.items[pairId];
this.renderItemInGui(groupId, renderId, block, x, y, brightness);
}
}
}
@@ -95,4 +106,27 @@ export default class ItemRenderer {
this.items = [];
this.webRenderer.clear();
}
scheduleDirty(groupId) {
if (this.scheduledDirty.includes(groupId)) {
return;
}
this.scheduledDirty.push(groupId);
}
destroy(groupId, renderId = null) {
let hit = false;
for (let i in this.items) {
if (this.items[i].groupId === groupId && (renderId === null || this.items[i].renderId === renderId)) {
this.scene.remove(this.items[i].group);
delete this.items[i];
hit = true;
}
}
if (hit) {
this.webRenderer.clear();
}
}
}
@@ -49,7 +49,7 @@ export default class Block {
shouldRenderFace(world, x, y, z, face) {
let typeId = world.getBlockAtFace(x, y, z, face);
return typeId === 0 || !Block.getById(typeId).isSolid();
return typeId === 0 || Block.getById(typeId).isTranslucent();
}
getColor(world, x, y, z, face) {
@@ -9,6 +9,10 @@ import BlockTorch from "./type/BlockTorch.js";
import Sound from "./sound/Sound.js";
import Block from "./Block.js";
import BlockWood from "./type/BlockWood.js";
import BlockBedrock from "./type/BlockBedrock.js";
import BlockGlass from "./type/BlockGlass.js";
import SoundGlass from "./sound/SoundGlass.js";
import BlockGravel from "./type/BlockGravel.js";
export class BlockRegistry {
@@ -20,14 +24,18 @@ export class BlockRegistry {
Block.sounds.grass = new Sound("grass", 1.0);
Block.sounds.cloth = new Sound("cloth", 1.0);
Block.sounds.sand = new Sound("sand", 1.0);
Block.sounds.glass = new SoundGlass("stone", 1.0);
// Blocks
BlockRegistry.STONE = new BlockStone(1, 0);
BlockRegistry.GRASS = new BlockGrass(2, 1);
BlockRegistry.DIRT = new BlockDirt(3, 2);
BlockRegistry.WOOD = new BlockWood(5, 10);
BlockRegistry.BEDROCK = new BlockBedrock(7, 11);
BlockRegistry.GRAVEL = new BlockGravel(13, 13);
BlockRegistry.LOG = new BlockLog(17, 4);
BlockRegistry.LEAVE = new BlockLeave(18, 6);
BlockRegistry.GLASS = new BlockGlass(20, 12);
BlockRegistry.WATER = new BlockWater(9, 7);
BlockRegistry.SAND = new BlockSand(12, 8)
BlockRegistry.TORCH = new BlockTorch(50, 9)
@@ -0,0 +1,13 @@
import Sound from "./Sound.js";
export default class SoundGlass extends Sound {
constructor(name, pitch) {
super(name, pitch);
}
getBreakSound() {
return "random.glass";
}
}
@@ -0,0 +1,9 @@
import Block from "../Block.js";
export default class BlockBedrock extends Block {
constructor(id, textureSlotId) {
super(id, textureSlotId);
}
}
@@ -0,0 +1,24 @@
import Block from "../Block.js";
export default class BlockGlass extends Block {
constructor(id, textureSlotId) {
super(id, textureSlotId);
// Sound
this.sound = Block.sounds.glass;
}
isTranslucent() {
return true;
}
shouldRenderFace(world, x, y, z, face) {
let typeId = world.getBlockAtFace(x, y, z, face);
return typeId === 0 || typeId !== this.id;
}
getOpacity() {
return 0;
}
}
@@ -0,0 +1,12 @@
import Block from "../Block.js";
export default class BlockGravel extends Block {
constructor(id, textureSlotId) {
super(id, textureSlotId);
// Sound
this.sound = Block.sounds.gravel;
}
}
@@ -9,6 +9,11 @@ export default class BlockLeave extends Block {
this.sound = Block.sounds.grass;
}
// TODO fix transparency of leaves
/*isTranslucent() {
return true;
}*/
getColor(world, x, y, z, face) {
// Inventory items have a default color
if (world === null) {
@@ -20,6 +25,12 @@ export default class BlockLeave extends Block {
return world.minecraft.grassColorizer.getColor(temperature, humidity);
}
// TODO fix transparency of leaves
/*shouldRenderFace(world, x, y, z, face) {
let typeId = world.getBlockAtFace(x, y, z, face);
return typeId === 0 || typeId === this.id;
}*/
getOpacity() {
return 0.3;
}
@@ -31,6 +31,10 @@ export default class BlockTorch extends Block {
return false;
}
isTranslucent() {
return true;
}
getRenderType() {
return BlockRenderType.TORCH;
}
@@ -34,7 +34,7 @@ export default class BlockWater extends Block {
getBoundingBox(world, x, y, z) {
let box = this.boundingBox.clone();
if (world.getBlockAt(x, y + 1, z) !== this.id) {
if (world !== null && world.getBlockAt(x, y + 1, z) !== this.id) {
box.maxY = 1.0 - 0.12;
}
return box;
@@ -205,8 +205,8 @@ export default class WorldGenerator extends Generator {
// For the entire height of the chunk
for (let y = 127; y >= 0; y--) {
// Set bedrock on floor level
if (y <= (this.random.nextInt(6)) - 1) {
primer.set(x, y, z, BlockRegistry.STONE.getId()); // TODO add bedrock block
if (y <= (this.random.nextInt(6)) - 1 || y === 0) {
primer.set(x, y, z, BlockRegistry.BEDROCK.getId());
continue;
}
@@ -238,7 +238,7 @@ export default class WorldGenerator extends Generator {
// Add gravel patches
if (gravelPatchNoise) {
topLayerTypeId = 0;
innerLayerTypeId = BlockRegistry.STONE.getId(); // TODO add gravel block
innerLayerTypeId = BlockRegistry.GRAVEL.getId();
}
// Add sand patches
Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB