diff --git a/src/js/net/minecraft/client/GameSettings.js b/src/js/net/minecraft/client/GameSettings.js index 6f19de7..94c2e4c 100644 --- a/src/js/net/minecraft/client/GameSettings.js +++ b/src/js/net/minecraft/client/GameSettings.js @@ -3,6 +3,8 @@ window.GameSettings = class { constructor() { this.crouching = 'ShiftLeft'; this.sprinting = 'ControlLeft'; + this.togglePerspective = 'F5'; + this.thirdPersonView = 0; } load() { diff --git a/src/js/net/minecraft/client/Minecraft.js b/src/js/net/minecraft/client/Minecraft.js index c09b53d..d12b057 100644 --- a/src/js/net/minecraft/client/Minecraft.js +++ b/src/js/net/minecraft/client/Minecraft.js @@ -195,6 +195,10 @@ window.Minecraft = class { this.inventory.selectedSlotIndex = i - 1; } } + + if (button === this.settings.togglePerspective) { + this.settings.thirdPersonView = (this.settings.thirdPersonView + 1) % 3; + } } onMouseClicked(button) { diff --git a/src/js/net/minecraft/client/gui/screens/GuiControls.js b/src/js/net/minecraft/client/gui/screens/GuiControls.js index 8d83786..6872628 100644 --- a/src/js/net/minecraft/client/gui/screens/GuiControls.js +++ b/src/js/net/minecraft/client/gui/screens/GuiControls.js @@ -22,6 +22,11 @@ window.GuiControls = class extends GuiScreen { scope.init(); })); + this.buttonList.push(new GuiKeyButton("Toggle Perspective", settings.togglePerspective, this.width / 2 - 100, this.height / 2 + 30, 200, 20, function (key) { + settings.togglePerspective = key; + scope.init(); + })); + this.buttonList.push(new GuiButton("Done", this.width / 2 - 100, this.height / 2 + 70, 200, 20, function () { scope.minecraft.displayScreen(scope.previousScreen); })); diff --git a/src/js/net/minecraft/client/render/WorldRenderer.js b/src/js/net/minecraft/client/render/WorldRenderer.js index 6898955..dadb557 100644 --- a/src/js/net/minecraft/client/render/WorldRenderer.js +++ b/src/js/net/minecraft/client/render/WorldRenderer.js @@ -1,6 +1,7 @@ window.WorldRenderer = class { static RENDER_DISTANCE = 4; + static THIRD_PERSON_DISTANCE = 4; constructor(minecraft, window) { this.minecraft = minecraft; @@ -90,7 +91,10 @@ window.WorldRenderer = class { // Render entities for (let entity of this.minecraft.world.entities) { - this.renderEntity(entity); + if (entity === player && this.minecraft.settings.thirdPersonView === 0) { + continue; + } + this.renderEntity(entity, partialTicks); } // Render actual scene @@ -100,14 +104,37 @@ window.WorldRenderer = class { orientCamera(partialTicks) { let player = this.minecraft.player; - // Rotation - this.camera.rotation.y = -MathHelper.toRadians(player.yaw + 180); - this.camera.rotation.x = -MathHelper.toRadians(player.pitch); + let rotationY = -MathHelper.toRadians(player.yaw + 180); + let rotationX = -MathHelper.toRadians(player.pitch); // Position let x = player.prevX + (player.x - player.prevX) * partialTicks; let y = player.prevY + (player.y - player.prevY) * partialTicks; let z = player.prevZ + (player.z - player.prevZ) * partialTicks; + + // Add camera offset + let mode = this.minecraft.settings.thirdPersonView; + if (mode !== 0) { + // Flip for front view + if (mode === 2) { + rotationY += Math.PI; + } + + // Shift camera + let cameraOffsetX = Math.sin(rotationY) * Math.cos(rotationX); + let cameraOffsetY = Math.sin(-rotationX); + let cameraOffsetZ = Math.cos(rotationY) * Math.cos(rotationX); + + x += cameraOffsetX * WorldRenderer.THIRD_PERSON_DISTANCE; + y += cameraOffsetY * WorldRenderer.THIRD_PERSON_DISTANCE; + z += cameraOffsetZ * WorldRenderer.THIRD_PERSON_DISTANCE; + } + + // Update rotation + this.camera.rotation.y = rotationY; + this.camera.rotation.x = rotationX; + + // Update camera positionWC this.camera.position.set(x, y + player.getEyeHeight(), z); // Update frustum @@ -296,8 +323,8 @@ window.WorldRenderer = class { } } - renderEntity(entity) { + renderEntity(entity, partialTicks) { let entityRenderer = this.entityRenderManager.getEntityRendererByEntity(entity); - entityRenderer.render(entity); + entityRenderer.render(entity, partialTicks); } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/render/entity/EntityRenderer.js b/src/js/net/minecraft/client/render/entity/EntityRenderer.js index e79975f..52f4ada 100644 --- a/src/js/net/minecraft/client/render/entity/EntityRenderer.js +++ b/src/js/net/minecraft/client/render/entity/EntityRenderer.js @@ -5,11 +5,27 @@ window.EntityRenderer = class { } rebuild(tessellator, entity) { - this.model.rebuild(tessellator, entity); + this.model.rebuild(tessellator, entity.group); } - render(entity) { - this.model.render(0); + render(entity, partialTicks) { + let group = entity.group; + + // Interpolate entity position + let interpolatedX = entity.prevX + (entity.x - entity.prevX) * partialTicks; + let interpolatedY = entity.prevY + (entity.y - entity.prevY) * partialTicks; + let interpolatedZ = entity.prevZ + (entity.z - entity.prevZ) * partialTicks; + + // Translate using interpolated position + group.position.setX(interpolatedX); + group.position.setY(interpolatedY); + group.position.setZ(interpolatedZ); + + // Actual size of the entity + let scale = 7.0 / 120.0; + group.scale.set(scale, scale, scale); + + this.model.render(group, 0); } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/render/entity/entity/PlayerRenderer.js b/src/js/net/minecraft/client/render/entity/entity/PlayerRenderer.js index 8d3a736..1f23400 100644 --- a/src/js/net/minecraft/client/render/entity/entity/PlayerRenderer.js +++ b/src/js/net/minecraft/client/render/entity/entity/PlayerRenderer.js @@ -14,8 +14,8 @@ window.PlayerRenderer = class extends EntityRenderer { super.rebuild(tessellator, entity); } - render(entity) { - super.render(entity); + render(entity, partialTicks) { + super.render(entity, partialTicks); } diff --git a/src/js/net/minecraft/client/render/model/ModelBase.js b/src/js/net/minecraft/client/render/model/ModelBase.js index d6b5230..4c874a5 100644 --- a/src/js/net/minecraft/client/render/model/ModelBase.js +++ b/src/js/net/minecraft/client/render/model/ModelBase.js @@ -4,17 +4,19 @@ window.ModelBase = class { * Rebuild the model * * @param tessellator Tessellator to render vertices + * @param group Group to attach the built model */ - rebuild(tessellator, entity) { + rebuild(tessellator, group) { } /** * Render the model * + * @param group Group to render * @param time Animation offset */ - render(time) { + render(group, time) { } diff --git a/src/js/net/minecraft/client/render/model/model/ModelPlayer.js b/src/js/net/minecraft/client/render/model/model/ModelPlayer.js index e3a7015..96e898a 100644 --- a/src/js/net/minecraft/client/render/model/model/ModelPlayer.js +++ b/src/js/net/minecraft/client/render/model/model/ModelPlayer.js @@ -35,21 +35,24 @@ window.ModelPlayer = class extends ModelBase { this.leftLeg.setPosition(2.0, 12.0, 0.0); } - rebuild(tessellator, entity) { - this.head.rebuild(tessellator, entity); - this.body.rebuild(tessellator, entity); - this.leftArm.rebuild(tessellator, entity); - this.rightArm.rebuild(tessellator, entity); - this.leftLeg.rebuild(tessellator, entity); - this.rightLeg.rebuild(tessellator, entity); + rebuild(tessellator, group) { + super.rebuild(tessellator, group); + + this.head.rebuild(tessellator, group); + this.body.rebuild(tessellator, group); + this.leftArm.rebuild(tessellator, group); + this.rightArm.rebuild(tessellator, group); + this.leftLeg.rebuild(tessellator, group); + this.rightLeg.rebuild(tessellator, group); } /** * Render the model * + * @param group Group to update position and rotation of * @param time Animation offset */ - render(entity, time) { + render(group, time) { // Set rotation of cubes this.head.yRotation = Math.sin(time * 0.83); this.head.xRotation = Math.sin(time) * 0.8; @@ -61,12 +64,12 @@ window.ModelPlayer = class extends ModelBase { this.leftLeg.xRotation = Math.sin(time * 0.6662 + Math.PI) * 1.4; // Render cubes - this.head.render(entity); - this.body.render(entity); - this.rightArm.render(entity); - this.leftArm.render(entity); - this.rightLeg.render(entity); - this.leftLeg.render(entity); + this.head.render(group); + this.body.render(group); + this.rightArm.render(group); + this.leftArm.render(group); + this.rightLeg.render(group); + this.leftLeg.render(group); } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/render/model/renderer/ModelRenderer.js b/src/js/net/minecraft/client/render/model/renderer/ModelRenderer.js index bdb471b..127d3ab 100644 --- a/src/js/net/minecraft/client/render/model/renderer/ModelRenderer.js +++ b/src/js/net/minecraft/client/render/model/renderer/ModelRenderer.js @@ -17,6 +17,8 @@ window.ModelRenderer = class { this.x = 0; this.y = 0; this.z = 0; + + this.bone = new THREE.Object3D(); } /** @@ -128,7 +130,7 @@ window.ModelRenderer = class { this.z = z; } - rebuild(tessellator, entity) { + rebuild(tessellator, group) { // Start drawing tessellator.startDrawing(); @@ -139,18 +141,19 @@ window.ModelRenderer = class { } // Finish drawing - tessellator.draw(entity.group); + tessellator.draw(this.bone); + group.add(this.bone); } - render(entity) { - entity.group.position.setX(this.x); - entity.group.position.setY(this.y); - entity.group.position.setZ(this.z); + render(group) { + this.bone.position.setX(this.x); + this.bone.position.setY(this.y); + this.bone.position.setZ(this.z); - entity.group.rotation.order = 'ZYX'; - entity.group.rotation.x = this.xRotation; - entity.group.rotation.y = this.yRotation; - entity.group.rotation.z = this.zRotation; + this.bone.rotation.order = 'ZYX'; + this.bone.rotation.x = this.xRotation; + this.bone.rotation.y = this.yRotation; + this.bone.rotation.z = this.zRotation; } } \ No newline at end of file