diff --git a/README.md b/README.md
index f241e32..9c0fb86 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/index.html b/index.html
index b6d3c8e..ab87660 100644
--- a/index.html
+++ b/index.html
@@ -1,7 +1,7 @@
Minecraft
-
+
diff --git a/src/js/Start.js b/src/js/Start.js
index 8d4774b..8ec2533 100644
--- a/src/js/Start.js
+++ b/src/js/Start.js
@@ -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);
diff --git a/src/js/net/minecraft/client/GameSettings.js b/src/js/net/minecraft/client/GameSettings.js
index 3558302..952543b 100644
--- a/src/js/net/minecraft/client/GameSettings.js
+++ b/src/js/net/minecraft/client/GameSettings.js
@@ -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() {
diff --git a/src/js/net/minecraft/client/GameWindow.js b/src/js/net/minecraft/client/GameWindow.js
index 3c510d5..89e1908 100644
--- a/src/js/net/minecraft/client/GameWindow.js
+++ b/src/js/net/minecraft/client/GameWindow.js
@@ -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);
}
diff --git a/src/js/net/minecraft/client/Minecraft.js b/src/js/net/minecraft/client/Minecraft.js
index 1352b90..f2bbac5 100644
--- a/src/js/net/minecraft/client/Minecraft.js
+++ b/src/js/net/minecraft/client/Minecraft.js
@@ -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);
}
}
diff --git a/src/js/net/minecraft/client/entity/PlayerEntity.js b/src/js/net/minecraft/client/entity/PlayerEntity.js
index e693d92..b37dac9 100644
--- a/src/js/net/minecraft/client/entity/PlayerEntity.js
+++ b/src/js/net/minecraft/client/entity/PlayerEntity.js
@@ -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;
diff --git a/src/js/net/minecraft/client/gui/Gui.js b/src/js/net/minecraft/client/gui/Gui.js
index a3e6537..f1d2161 100644
--- a/src/js/net/minecraft/client/gui/Gui.js
+++ b/src/js/net/minecraft/client/gui/Gui.js
@@ -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) {
diff --git a/src/js/net/minecraft/client/gui/overlay/IngameOverlay.js b/src/js/net/minecraft/client/gui/overlay/IngameOverlay.js
index ffae23d..c720c76 100644
--- a/src/js/net/minecraft/client/gui/overlay/IngameOverlay.js
+++ b/src/js/net/minecraft/client/gui/overlay/IngameOverlay.js
@@ -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);
}
}
}
diff --git a/src/js/net/minecraft/client/gui/screens/GuiChat.js b/src/js/net/minecraft/client/gui/screens/GuiChat.js
index 2912fc1..46dabb6 100644
--- a/src/js/net/minecraft/client/gui/screens/GuiChat.js
+++ b/src/js/net/minecraft/client/gui/screens/GuiChat.js
@@ -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;
}
diff --git a/src/js/net/minecraft/client/gui/screens/GuiContainer.js b/src/js/net/minecraft/client/gui/screens/GuiContainer.js
new file mode 100644
index 0000000..b92172b
--- /dev/null
+++ b/src/js/net/minecraft/client/gui/screens/GuiContainer.js
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/gui/screens/GuiControls.js b/src/js/net/minecraft/client/gui/screens/GuiControls.js
index d1a2f0d..4072fd0 100644
--- a/src/js/net/minecraft/client/gui/screens/GuiControls.js
+++ b/src/js/net/minecraft/client/gui/screens/GuiControls.js
@@ -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);
}));
diff --git a/src/js/net/minecraft/client/gui/screens/container/GuiContainerCreative.js b/src/js/net/minecraft/client/gui/screens/container/GuiContainerCreative.js
new file mode 100644
index 0000000..ccb15f1
--- /dev/null
+++ b/src/js/net/minecraft/client/gui/screens/container/GuiContainerCreative.js
@@ -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);
+ }
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/inventory/Container.js b/src/js/net/minecraft/client/inventory/Container.js
new file mode 100644
index 0000000..3908c87
--- /dev/null
+++ b/src/js/net/minecraft/client/inventory/Container.js
@@ -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;
+ }
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/inventory/Inventory.js b/src/js/net/minecraft/client/inventory/Inventory.js
index 9bf9b5d..cc5ac92 100644
--- a/src/js/net/minecraft/client/inventory/Inventory.js
+++ b/src/js/net/minecraft/client/inventory/Inventory.js
@@ -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;
- }
}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/inventory/Slot.js b/src/js/net/minecraft/client/inventory/Slot.js
new file mode 100644
index 0000000..f8cb01e
--- /dev/null
+++ b/src/js/net/minecraft/client/inventory/Slot.js
@@ -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;
+ }
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/inventory/container/ContainerCreative.js b/src/js/net/minecraft/client/inventory/container/ContainerCreative.js
new file mode 100644
index 0000000..5a91d14
--- /dev/null
+++ b/src/js/net/minecraft/client/inventory/container/ContainerCreative.js
@@ -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());
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/inventory/container/ContainerPlayer.js b/src/js/net/minecraft/client/inventory/container/ContainerPlayer.js
new file mode 100644
index 0000000..6bfba22
--- /dev/null
+++ b/src/js/net/minecraft/client/inventory/container/ContainerPlayer.js
@@ -0,0 +1,11 @@
+import Container from "../Container.js";
+
+export default class ContainerPlayer extends Container {
+
+ constructor() {
+ super();
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/inventory/inventory/InventoryBasic.js b/src/js/net/minecraft/client/inventory/inventory/InventoryBasic.js
new file mode 100644
index 0000000..c51dbe8
--- /dev/null
+++ b/src/js/net/minecraft/client/inventory/inventory/InventoryBasic.js
@@ -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;
+ }
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/inventory/inventory/InventoryPlayer.js b/src/js/net/minecraft/client/inventory/inventory/InventoryPlayer.js
new file mode 100644
index 0000000..663f9d9
--- /dev/null
+++ b/src/js/net/minecraft/client/inventory/inventory/InventoryPlayer.js
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/render/BlockRenderer.js b/src/js/net/minecraft/client/render/BlockRenderer.js
index f3ceed6..2ccd8dd 100644
--- a/src/js/net/minecraft/client/render/BlockRenderer.js
+++ b/src/js/net/minecraft/client/render/BlockRenderer.js
@@ -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);
}
}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/render/gui/FontRenderer.js b/src/js/net/minecraft/client/render/gui/FontRenderer.js
index 5b59693..8fba44b 100644
--- a/src/js/net/minecraft/client/render/gui/FontRenderer.js
+++ b/src/js/net/minecraft/client/render/gui/FontRenderer.js
@@ -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 &
diff --git a/src/js/net/minecraft/client/render/gui/ItemRenderer.js b/src/js/net/minecraft/client/render/gui/ItemRenderer.js
index 03159a8..b1e939a 100644
--- a/src/js/net/minecraft/client/render/gui/ItemRenderer.js
+++ b/src/js/net/minecraft/client/render/gui/ItemRenderer.js
@@ -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();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/world/block/Block.js b/src/js/net/minecraft/client/world/block/Block.js
index dfe5775..c9edf2f 100644
--- a/src/js/net/minecraft/client/world/block/Block.js
+++ b/src/js/net/minecraft/client/world/block/Block.js
@@ -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) {
diff --git a/src/js/net/minecraft/client/world/block/BlockRegistry.js b/src/js/net/minecraft/client/world/block/BlockRegistry.js
index 7617768..df0eaf9 100644
--- a/src/js/net/minecraft/client/world/block/BlockRegistry.js
+++ b/src/js/net/minecraft/client/world/block/BlockRegistry.js
@@ -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)
diff --git a/src/js/net/minecraft/client/world/block/sound/SoundGlass.js b/src/js/net/minecraft/client/world/block/sound/SoundGlass.js
new file mode 100644
index 0000000..015d590
--- /dev/null
+++ b/src/js/net/minecraft/client/world/block/sound/SoundGlass.js
@@ -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";
+ }
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/world/block/type/BlockBedrock.js b/src/js/net/minecraft/client/world/block/type/BlockBedrock.js
new file mode 100644
index 0000000..dbd597d
--- /dev/null
+++ b/src/js/net/minecraft/client/world/block/type/BlockBedrock.js
@@ -0,0 +1,9 @@
+import Block from "../Block.js";
+
+export default class BlockBedrock extends Block {
+
+ constructor(id, textureSlotId) {
+ super(id, textureSlotId);
+ }
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/world/block/type/BlockGlass.js b/src/js/net/minecraft/client/world/block/type/BlockGlass.js
new file mode 100644
index 0000000..9d5af5a
--- /dev/null
+++ b/src/js/net/minecraft/client/world/block/type/BlockGlass.js
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/world/block/type/BlockGravel.js b/src/js/net/minecraft/client/world/block/type/BlockGravel.js
new file mode 100644
index 0000000..a14a6a9
--- /dev/null
+++ b/src/js/net/minecraft/client/world/block/type/BlockGravel.js
@@ -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;
+ }
+
+}
\ No newline at end of file
diff --git a/src/js/net/minecraft/client/world/block/type/BlockLeave.js b/src/js/net/minecraft/client/world/block/type/BlockLeave.js
index a07e067..78764d5 100644
--- a/src/js/net/minecraft/client/world/block/type/BlockLeave.js
+++ b/src/js/net/minecraft/client/world/block/type/BlockLeave.js
@@ -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;
}
diff --git a/src/js/net/minecraft/client/world/block/type/BlockTorch.js b/src/js/net/minecraft/client/world/block/type/BlockTorch.js
index 830e0d2..6ffcb65 100644
--- a/src/js/net/minecraft/client/world/block/type/BlockTorch.js
+++ b/src/js/net/minecraft/client/world/block/type/BlockTorch.js
@@ -31,6 +31,10 @@ export default class BlockTorch extends Block {
return false;
}
+ isTranslucent() {
+ return true;
+ }
+
getRenderType() {
return BlockRenderType.TORCH;
}
diff --git a/src/js/net/minecraft/client/world/block/type/BlockWater.js b/src/js/net/minecraft/client/world/block/type/BlockWater.js
index f8736f4..2ca22b1 100644
--- a/src/js/net/minecraft/client/world/block/type/BlockWater.js
+++ b/src/js/net/minecraft/client/world/block/type/BlockWater.js
@@ -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;
diff --git a/src/js/net/minecraft/client/world/generator/WorldGenerator.js b/src/js/net/minecraft/client/world/generator/WorldGenerator.js
index c844d8c..8279e5d 100644
--- a/src/js/net/minecraft/client/world/generator/WorldGenerator.js
+++ b/src/js/net/minecraft/client/world/generator/WorldGenerator.js
@@ -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
diff --git a/src/resources/gui/container/creative.png b/src/resources/gui/container/creative.png
new file mode 100644
index 0000000..4776e62
Binary files /dev/null and b/src/resources/gui/container/creative.png differ
diff --git a/src/resources/terrain/terrain.png b/src/resources/terrain/terrain.png
index a530bfe..33634fb 100644
Binary files a/src/resources/terrain/terrain.png and b/src/resources/terrain/terrain.png differ