From 800134b26b83d648422ce781a14af9e576b473e0 Mon Sep 17 00:00:00 2001 From: LabyStudio Date: Mon, 2 May 2022 02:45:24 +0200 Subject: [PATCH] implement first person hand (cherry picked from commit bfe5a2eaca2858a7ccde1df847e2148dd79f4045) --- src/js/net/minecraft/client/GameSettings.js | 12 +- src/js/net/minecraft/client/GameWindow.js | 2 +- src/js/net/minecraft/client/Minecraft.js | 4 + src/js/net/minecraft/client/entity/Entity.js | 5 +- .../minecraft/client/entity/EntityLiving.js | 27 +++- .../minecraft/client/entity/PlayerEntity.js | 30 ++++ .../net/minecraft/client/gui/IngameOverlay.js | 5 - .../minecraft/client/render/BlockRenderer.js | 2 +- .../minecraft/client/render/WorldRenderer.js | 142 +++++++++++++++++- .../render/entity/EntityRenderManager.js | 6 +- .../client/render/entity/EntityRenderer.js | 44 +++--- .../render/entity/entity/PlayerRenderer.js | 45 +++++- .../client/render/gui/ItemRenderer.js | 30 +--- .../client/render/model/ModelBase.js | 8 +- .../client/render/model/model/ModelPlayer.js | 60 ++++---- .../render/model/renderer/ModelRenderer.js | 27 ++++ src/js/net/minecraft/client/world/World.js | 4 +- src/js/net/minecraft/util/MathHelper.js | 6 +- 18 files changed, 345 insertions(+), 114 deletions(-) diff --git a/src/js/net/minecraft/client/GameSettings.js b/src/js/net/minecraft/client/GameSettings.js index 380f9e8..8ffbb21 100644 --- a/src/js/net/minecraft/client/GameSettings.js +++ b/src/js/net/minecraft/client/GameSettings.js @@ -3,8 +3,10 @@ export default class GameSettings { constructor() { this.crouching = 'ShiftLeft'; this.sprinting = 'ControlLeft'; - this.togglePerspective = 'F5'; + this.togglePerspective = 'F5'; this.thirdPersonView = 0; + this.fov = 70; + this.viewBobbing = true; } load() { @@ -15,7 +17,11 @@ export default class GameSettings { let c = ca[i]; while (c.charAt(0) === ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) === 0) { - this[prop] = c.substring(nameEQ.length, c.length); + let value = c.substring(nameEQ.length, c.length); + if (value.match(/^[0-9]+$/)) { + value = parseInt(value); + } + this[prop] = value; } } } @@ -23,7 +29,7 @@ export default class GameSettings { save() { for (let prop in this) { - document.cookie = prop + "=" + (this[prop] || "") + "; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT"; + document.cookie = prop + "=" + this[prop] + "; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT"; } } diff --git a/src/js/net/minecraft/client/GameWindow.js b/src/js/net/minecraft/client/GameWindow.js index c040392..04f83cc 100644 --- a/src/js/net/minecraft/client/GameWindow.js +++ b/src/js/net/minecraft/client/GameWindow.js @@ -66,7 +66,7 @@ export default class GameWindow { }); // Mouse buttons - document.addEventListener('click', function (event) { + document.addEventListener('mousedown', function (event) { // Create sound engine (It has to be created after user interaction) if (!minecraft.soundManager.isCreated()) { minecraft.soundManager.create(minecraft.worldRenderer); diff --git a/src/js/net/minecraft/client/Minecraft.js b/src/js/net/minecraft/client/Minecraft.js index bc066b8..f676f8f 100644 --- a/src/js/net/minecraft/client/Minecraft.js +++ b/src/js/net/minecraft/client/Minecraft.js @@ -192,6 +192,9 @@ export default class Minecraft { // Tick world this.world.onTick(); + // Tick renderer + this.worldRenderer.onTick(); + // Tick the player this.player.onUpdate(); } @@ -218,6 +221,7 @@ export default class Minecraft { if (button === this.settings.togglePerspective) { this.settings.thirdPersonView = (this.settings.thirdPersonView + 1) % 3; + this.settings.save(); } } diff --git a/src/js/net/minecraft/client/entity/Entity.js b/src/js/net/minecraft/client/entity/Entity.js index 77fca87..e1a484f 100644 --- a/src/js/net/minecraft/client/entity/Entity.js +++ b/src/js/net/minecraft/client/entity/Entity.js @@ -7,7 +7,7 @@ export default class Entity { this.minecraft = minecraft; this.world = world; - this.group = new THREE.Object3D(); + this.renderer = this.minecraft.worldRenderer.entityRenderManager.createEntityRendererByEntity(this); this.x = 0; this.y = 0; @@ -30,6 +30,7 @@ export default class Entity { this.prevRotationYaw = 0; this.prevRotationPitch = 0; + this.prevDistanceWalked = 0; this.distanceWalked = 0; this.nextStepDistance = 1; @@ -47,6 +48,8 @@ export default class Entity { this.prevY = this.y; this.prevZ = this.z; + this.prevDistanceWalked = this.distanceWalked; + this.prevRotationPitch = this.rotationPitch; this.prevRotationYaw = this.rotationYaw; diff --git a/src/js/net/minecraft/client/entity/EntityLiving.js b/src/js/net/minecraft/client/entity/EntityLiving.js index dbc486d..20bd189 100644 --- a/src/js/net/minecraft/client/entity/EntityLiving.js +++ b/src/js/net/minecraft/client/entity/EntityLiving.js @@ -24,9 +24,11 @@ export default class EntityLiving extends Entity { this.prevRotationYawHead = 0; this.prevRenderYawOffset = 0; - this.limbSwing = 0; - this.limbSwingAmount = 0; - this.prevLimbSwingAmount = 0; + this.limbSwingProgress = 0; + this.limbSwingStrength = 0; + this.prevLimbSwingStrength = 0; + + this.health = 20.0; } onUpdate() { @@ -112,7 +114,7 @@ export default class EntityLiving extends Entity { } } - this.prevLimbSwingAmount = this.limbSwingAmount; + this.prevLimbSwingStrength = this.limbSwingStrength; let motionX = this.x - this.prevX; let motionZ = this.z - this.prevZ; @@ -121,8 +123,8 @@ export default class EntityLiving extends Entity { if (distance > 1.0) { distance = 1.0; } - this.limbSwingAmount += (distance - this.limbSwingAmount) * 0.4; - this.limbSwing += this.limbSwingAmount; + this.limbSwingStrength += (distance - this.limbSwingStrength) * 0.4; + this.limbSwingProgress += this.limbSwingStrength; } onEntityUpdate() { @@ -130,6 +132,11 @@ export default class EntityLiving extends Entity { this.prevRotationYawHead = this.rotationYawHead; this.prevSwingProgress = this.swingProgress; + this.prevRenderArmYaw = this.renderArmYaw; + this.prevRenderArmPitch = this.renderArmPitch; + this.renderArmPitch = (this.renderArmPitch + (this.rotationPitch - this.renderArmPitch) * 0.5); + this.renderArmYaw = (this.renderArmYaw + (this.rotationYaw - this.renderArmYaw) * 0.5); + this.updateArmSwingProgress(); super.onEntityUpdate(); @@ -191,6 +198,14 @@ export default class EntityLiving extends Entity { this.swingProgress = this.swingProgressInt / swingAnimationEnd; } + getSwingProgress(partialTicks) { + let swingProgressDiff = this.swingProgress - this.prevSwingProgress; + if (swingProgressDiff < 0.0) { + swingProgressDiff++; + } + return this.prevSwingProgress + swingProgressDiff * partialTicks; + } + computeAngleWithBound(value, subtract, limit) { let wrapped = MathHelper.wrapAngleTo180(value - subtract); if (wrapped < -limit) { diff --git a/src/js/net/minecraft/client/entity/PlayerEntity.js b/src/js/net/minecraft/client/entity/PlayerEntity.js index b4f8fb8..097ba9a 100644 --- a/src/js/net/minecraft/client/entity/PlayerEntity.js +++ b/src/js/net/minecraft/client/entity/PlayerEntity.js @@ -31,6 +31,18 @@ export default class PlayerEntity extends EntityLiving { this.prevFovModifier = 0; this.fovModifier = 0; this.timeFovChanged = 0; + + this.renderArmPitch = 0; + this.renderArmYaw = 0; + + this.prevRenderArmPitch = 0; + this.prevRenderArmYaw = 0; + + // For first person bobbing + this.cameraYaw = 0; + this.cameraPitch = 0; + this.prevCameraYaw = 0; + this.prevCameraPitch = 0; } respawn() { @@ -78,6 +90,9 @@ export default class PlayerEntity extends EntityLiving { } onLivingUpdate() { + this.prevCameraYaw = this.cameraYaw; + this.prevCameraPitch = this.cameraPitch; + if (this.sprintToggleTimer > 0) { --this.sprintToggleTimer; } @@ -127,6 +142,21 @@ export default class PlayerEntity extends EntityLiving { if (this.sprinting) { this.jumpMovementFactor = this.jumpMovementFactor + this.speedInAir * 0.3; } + + let speedXZ = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); + let speedY = (Math.atan(-this.motionY * 0.2) * 15.0); + + if (speedXZ > 0.1) { + speedXZ = 0.1; + } + if (!this.onGround || this.health <= 0.0) { + speedXZ = 0.0; + } + if (this.onGround || this.health <= 0.0) { + speedY = 0.0; + } + this.cameraYaw += (speedXZ - this.cameraYaw) * 0.4; + this.cameraPitch += (speedY - this.cameraPitch) * 0.8; } isInWater() { diff --git a/src/js/net/minecraft/client/gui/IngameOverlay.js b/src/js/net/minecraft/client/gui/IngameOverlay.js index 79534e0..9d7f7ae 100644 --- a/src/js/net/minecraft/client/gui/IngameOverlay.js +++ b/src/js/net/minecraft/client/gui/IngameOverlay.js @@ -18,11 +18,6 @@ export default class IngameOverlay extends Gui { this.renderCrosshair(stack, this.window.width / 2, this.window.height / 2) } - // Render holding item - if (this.minecraft.settings.thirdPersonView === 0) { - this.minecraft.itemRenderer.renderItemInHand(); - } - // Render hotbar this.renderHotbar(stack, this.window.width / 2 - 91, this.window.height - 22); diff --git a/src/js/net/minecraft/client/render/BlockRenderer.js b/src/js/net/minecraft/client/render/BlockRenderer.js index 67f2d3c..272fb54 100644 --- a/src/js/net/minecraft/client/render/BlockRenderer.js +++ b/src/js/net/minecraft/client/render/BlockRenderer.js @@ -260,7 +260,7 @@ export default class BlockRenderer { } } - renderBlockInHand(group, block, brightness) { + renderBlockInHandThirdPerson(group, block, brightness) { this.tessellator.startDrawing(); // Render block diff --git a/src/js/net/minecraft/client/render/WorldRenderer.js b/src/js/net/minecraft/client/render/WorldRenderer.js index 16f67dc..e1a0b97 100644 --- a/src/js/net/minecraft/client/render/WorldRenderer.js +++ b/src/js/net/minecraft/client/render/WorldRenderer.js @@ -35,6 +35,10 @@ export default class WorldRenderer { // Entity render manager this.entityRenderManager = new EntityRenderManager(this); + this.equippedProgress = 0; + this.prevEquippedProgress = 0; + this.itemToRender = 0; + this.initialize(); } @@ -51,6 +55,10 @@ export default class WorldRenderer { this.scene = new THREE.Scene(); this.scene.matrixAutoUpdate = false; + // Create overlay for first person model rendering + this.overlay = new THREE.Scene(); + this.overlay.matrixAutoUpdate = false; + // Create web renderer this.webRenderer = new THREE.WebGLRenderer({ canvas: this.window.canvas, @@ -77,6 +85,9 @@ export default class WorldRenderer { color: 0x000000, })); this.scene.add(this.blockHitBox); + + // Hand group + this.handGroup = new THREE.Object3D(); } render(partialTicks) { @@ -95,18 +106,57 @@ export default class WorldRenderer { // Render target block this.renderBlockHitBox(player, partialTicks); + // Hide all entities and make them visible during rendering + for (let entity of this.minecraft.world.entities) { + entity.renderer.group.visible = false; + } + // Render entities for (let entity of this.minecraft.world.entities) { if (entity === player && this.minecraft.settings.thirdPersonView === 0) { - entity.group.clear(); // Remove entity from scene - delete entity.group.buildMeta; // To trigger a rebuild on the next render continue; } - this.renderEntity(entity, partialTicks); + + // Render entity + entity.renderer.render(entity, partialTicks); + entity.renderer.group.visible = true; } + // Render hand + this.renderHand(partialTicks); + // Render actual scene this.webRenderer.render(this.scene, this.camera); + + // Render overlay with a static FOV + this.camera.fov = this.minecraft.settings.fov; + this.camera.updateProjectionMatrix(); + this.webRenderer.render(this.overlay, this.camera); + } + + onTick() { + this.prevEquippedProgress = this.equippedProgress; + + let player = this.minecraft.player; + let itemStack = player.inventory.getItemInSelectedSlot(); + + let showHand = false; + if (this.itemToRender != null && itemStack != null) { + if (this.itemToRender !== itemStack) { + showHand = true; + } + } else if (this.itemToRender == null && itemStack == null) { + showHand = false; + } else { + showHand = true; + } + + // Update equip progress + this.equippedProgress += MathHelper.clamp((showHand ? 0.0 : 1.0) - this.equippedProgress, -0.4, 0.4); + + if (this.equippedProgress < 0.1) { + this.itemToRender = itemStack; + } } orientCamera(partialTicks) { @@ -151,7 +201,7 @@ export default class WorldRenderer { this.frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse)); // Update FOV - this.camera.fov = 85 + player.getFOVModifier(); + this.camera.fov = this.minecraft.settings.fov + player.getFOVModifier(); this.camera.updateProjectionMatrix(); // Setup fog @@ -294,6 +344,83 @@ export default class WorldRenderer { this.skyGroup.rotation.set(angle * Math.PI * 2 + Math.PI / 2, 0, 0); } + renderHand(partialTicks) { + // Hide hand before rendering + let player = this.minecraft.player; + let stack = player.renderer.handGroup; + stack.visible = false; + + // Hide in third person + if (this.minecraft.settings.thirdPersonView !== 0) { + return; + } + + // Apply matrix mode (Put object in front of camera) + stack.position.copy(this.camera.position); + stack.rotation.copy(this.camera.rotation); + stack.rotation.order = 'ZYX'; + + // Scale down + stack.scale.set(0.0625, 0.0625, 0.0625); + + let equipProgress = this.prevEquippedProgress + (this.equippedProgress - this.prevEquippedProgress) * partialTicks; + let swingProgress = player.getSwingProgress(partialTicks); + + let pitchArm = player.prevRenderArmPitch + (player.renderArmPitch - player.prevRenderArmPitch) * partialTicks; + let yawArm = player.prevRenderArmYaw + (player.renderArmYaw - player.prevRenderArmYaw) * partialTicks; + + let factor = 0.8; + let zOffset = Math.sin(swingProgress * Math.PI); + let yOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI * 2.0); + let xOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI); + + let yRotation = Math.sin(Math.sqrt(swingProgress) * Math.PI); + let zRotation = Math.sin(swingProgress * swingProgress * Math.PI); + + // Bobbing animation + if (this.minecraft.settings.viewBobbing) { + let walked = -(player.prevDistanceWalked + (player.distanceWalked - player.prevDistanceWalked) * partialTicks); + let yaw = player.prevCameraYaw + (player.cameraYaw - player.prevCameraYaw) * partialTicks; + let pitch = player.prevCameraPitch + (player.cameraPitch - player.prevCameraPitch) * partialTicks; + this.translate( + stack, + Math.sin(walked * 3.141593) * yaw * 0.5, + -Math.abs(Math.cos(walked * Math.PI) * yaw), + 0.0 + ); + stack.rotateZ(MathHelper.toRadians(Math.sin(walked * Math.PI) * yaw * 3.0)); + stack.rotateX(MathHelper.toRadians(Math.abs(Math.cos(walked * Math.PI - 0.2) * yaw) * 5.0)); + stack.rotateX(MathHelper.toRadians(pitch)); + } + + // Camera rotation movement + stack.rotateX(MathHelper.toRadians((player.rotationPitch - pitchArm) * 0.1)); + stack.rotateY(MathHelper.toRadians((player.rotationYaw - yawArm) * 0.1)); + + // Initial offset on screen + this.translate(stack, -xOffset * 0.3, yOffset * 0.4, -zOffset * 0.4); + this.translate(stack, 0.8 * factor, -0.75 * factor - (1.0 - equipProgress) * 0.6, -0.9 * factor); + + // Rotation of hand + stack.rotateY(MathHelper.toRadians(45)); + stack.rotateY(MathHelper.toRadians(yRotation * 70)); + stack.rotateZ(MathHelper.toRadians(-zRotation * 20)); + + // Post transform + this.translate(stack, -1, 3.6, 3.5); + stack.rotateZ(MathHelper.toRadians(120)); + stack.rotateX(MathHelper.toRadians(200)); + stack.rotateY(MathHelper.toRadians(-135)); + this.translate(stack, 5.6, 0.0, 0.0); + + if (this.itemToRender === 0) { + // Render hand + player.renderer.renderRightArm(player, partialTicks); + } else { + // Render item + } + } + renderBlockHitBox(player, partialTicks) { let hitResult = player.rayTrace(5, partialTicks); let hitBoxVisible = !(hitResult === null); @@ -333,8 +460,9 @@ export default class WorldRenderer { } } - renderEntity(entity, partialTicks) { - let entityRenderer = this.entityRenderManager.getEntityRendererByEntity(entity); - entityRenderer.render(entity, partialTicks); + translate(stack, x, y, z) { + stack.translateX(x); + stack.translateY(y); + stack.translateZ(z); } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/render/entity/EntityRenderManager.js b/src/js/net/minecraft/client/render/entity/EntityRenderManager.js index 6baaf7c..f1d0c85 100644 --- a/src/js/net/minecraft/client/render/entity/EntityRenderManager.js +++ b/src/js/net/minecraft/client/render/entity/EntityRenderManager.js @@ -7,14 +7,14 @@ export default class EntityRenderManager { this.worldRenderer = worldRenderer; this.renderers = []; - this.push(PlayerEntity, new PlayerRenderer(worldRenderer)); + this.push(PlayerEntity, PlayerRenderer); } push(entityType, entityRenderer) { this.renderers[entityType.name] = entityRenderer; } - getEntityRendererByEntity(entity) { - return this.renderers[entity.constructor.name]; + createEntityRendererByEntity(entity) { + return new this.renderers[entity.constructor.name].prototype.constructor(this.worldRenderer); } } \ 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 4b383fd..37a47b6 100644 --- a/src/js/net/minecraft/client/render/entity/EntityRenderer.js +++ b/src/js/net/minecraft/client/render/entity/EntityRenderer.js @@ -6,22 +6,22 @@ export default class EntityRenderer { constructor(model) { this.model = model; this.tessellator = new Tessellator(); + this.group = new THREE.Object3D(); } rebuild(entity) { // Create meta for group - let group = entity.group; let meta = {}; this.fillMeta(entity, meta); - group.buildMeta = meta; + this.group.buildMeta = meta; // Clear meshes - group.clear(); + this.group.clear(); // Apply brightness and rebuild - let brightness = group.buildMeta.brightness; + let brightness = this.group.buildMeta.brightness; this.tessellator.setColor(brightness, brightness, brightness); - this.model.rebuild(this.tessellator, group); + this.model.rebuild(this.tessellator, this.group); } fillMeta(entity, meta) { @@ -30,30 +30,25 @@ export default class EntityRenderer { } isRebuildRequired(entity) { - let group = entity.group; - if (typeof group.buildMeta === "undefined") { + if (typeof this.group.buildMeta === "undefined") { return true; } // Compare meta of group let currentMeta = {}; this.fillMeta(entity, currentMeta); - let previousMeta = group.buildMeta; + let previousMeta = this.group.buildMeta; return JSON.stringify(currentMeta) !== JSON.stringify(previousMeta); } render(entity, partialTicks) { - if (this.isRebuildRequired(entity)) { - this.rebuild(entity); - } - - let group = entity.group; + this.prepareModel(entity); let rotationBody = this.interpolateRotation(entity.prevRenderYawOffset, entity.renderYawOffset, partialTicks); let rotationHead = this.interpolateRotation(entity.prevRotationYawHead, entity.rotationYawHead, partialTicks); - let limbSwing = entity.prevLimbSwingAmount + (entity.limbSwingAmount - entity.prevLimbSwingAmount) * partialTicks; - let limbSwingAmount = entity.limbSwing - entity.limbSwingAmount * (1.0 - partialTicks); + let limbSwingStrength = entity.prevLimbSwingStrength + (entity.limbSwingStrength - entity.prevLimbSwingStrength) * partialTicks; + let limbSwing = entity.limbSwingProgress - entity.limbSwingStrength * (1.0 - partialTicks); let yaw = rotationHead - rotationBody; let pitch = entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * partialTicks; @@ -64,20 +59,21 @@ export default class EntityRenderer { let interpolatedZ = entity.prevZ + (entity.z - entity.prevZ) * partialTicks; // Translate using interpolated position - group.position.setX(interpolatedX); - group.position.setY(interpolatedY + 1.4); - group.position.setZ(interpolatedZ); + this.group.position.setX(interpolatedX); + this.group.position.setY(interpolatedY + 1.4); + this.group.position.setZ(interpolatedZ); // Actual size of the entity let scale = 7.0 / 120.0; - group.scale.set(-scale, -scale, scale); + this.group.scale.set(-scale, -scale, scale); // Rotate entity model - group.rotation.y = MathHelper.toRadians(-rotationBody + 180); + this.group.rotation.y = MathHelper.toRadians(-rotationBody + 180); // Render entity model let timeAlive = entity.ticksExisted + partialTicks; - this.model.render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch, partialTicks); + let stack = entity.renderer.group; + this.model.render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks); } interpolateRotation(prevValue, value, partialTicks) { @@ -90,4 +86,10 @@ export default class EntityRenderer { return prevValue + partialTicks * factor; } + prepareModel(entity) { + if (this.isRebuildRequired(entity)) { + this.rebuild(entity); + } + } + } \ 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 076c496..a4aff1b 100644 --- a/src/js/net/minecraft/client/render/entity/entity/PlayerRenderer.js +++ b/src/js/net/minecraft/client/render/entity/entity/PlayerRenderer.js @@ -13,6 +13,11 @@ export default class PlayerRenderer extends EntityRenderer { this.textureCharacter = new THREE.TextureLoader().load('src/resources/char.png'); this.textureCharacter.magFilter = THREE.NearestFilter; this.textureCharacter.minFilter = THREE.NearestFilter; + + // First person right-hand holder + this.handModel = null; + this.handGroup = new THREE.Object3D(); + this.worldRenderer.overlay.add(this.handGroup); } rebuild(entity) { @@ -22,16 +27,52 @@ export default class PlayerRenderer extends EntityRenderer { // Render item in hand let group = this.model.rightArm.bone; let id = entity.inventory.getItemInSelectedSlot(); - if (id !== 0) { + if (id !== 0 && this.worldRenderer.minecraft.settings.thirdPersonView !== 0) { let block = Block.getById(id); - this.worldRenderer.blockRenderer.renderBlockInHand(group, block, entity.getEntityBrightness()); + this.worldRenderer.blockRenderer.renderBlockInHandThirdPerson(group, block, entity.getEntityBrightness()); } + + // Create first person right hand and attach it to the holder + this.handGroup.clear(); + this.handModel = this.model.rightArm.clone(); + this.handGroup.add(this.handModel.bone); + + // Copy material and update depth test of the hand + let mesh = this.handModel.bone.children[0]; + mesh.renerOrder = 999; + mesh.material = mesh.material.clone(); + mesh.material.depthTest = false; + mesh.material.depthWrite = false; } render(entity, partialTicks) { + let swingProgress = entity.swingProgress - entity.prevSwingProgress; + if (swingProgress < 0.0) { + swingProgress++; + } + this.model.swingProgress = entity.prevSwingProgress + swingProgress * partialTicks; + this.model.hasItemInHand = entity.inventory.getItemInSelectedSlot() !== 0; + this.model.isSneaking = entity.sneaking; + super.render(entity, partialTicks); } + renderRightArm(player, partialTicks) { + // Make sure the model is created + this.prepareModel(player); + + // Set transform of renderer + this.model.swingProgress = 0; + this.model.hasItemInHand = false; + this.model.isSneaking = false; + this.model.setRotationAngles(player, 0, 0, 0, 0, 0, 0); + this.handModel.copyTransformOf(this.model.rightArm); + + // Render the model + this.handGroup.visible = true; + this.handModel.render(); + } + fillMeta(entity, meta) { super.fillMeta(entity, meta); meta.itemInHand = entity.inventory.getItemInSelectedSlot(); diff --git a/src/js/net/minecraft/client/render/gui/ItemRenderer.js b/src/js/net/minecraft/client/render/gui/ItemRenderer.js index 56ac632..42a5431 100644 --- a/src/js/net/minecraft/client/render/gui/ItemRenderer.js +++ b/src/js/net/minecraft/client/render/gui/ItemRenderer.js @@ -1,5 +1,3 @@ -import Block from "../../world/block/Block.js"; - export default class ItemRenderer { constructor(minecraft, window) { @@ -7,15 +5,13 @@ export default class ItemRenderer { this.window = window; this.items = []; - this.itemInHand = null; - this.itemInHandGroup = new THREE.Object3D(); } 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.far = 100; this.camera.rotation.order = 'ZYX'; this.camera.up = new THREE.Vector3(0, 1, 0); @@ -37,8 +33,6 @@ export default class ItemRenderer { this.webRenderer.sortObjects = false; this.webRenderer.setClearColor(0x000000, 0); this.webRenderer.clear(); - - this.scene.add(this.itemInHandGroup); } render(partialTicks) { @@ -54,28 +48,6 @@ export default class ItemRenderer { this.webRenderer.render(this.scene, this.camera); } - renderItemInHand() { - let typeId = this.minecraft.player.inventory.getItemInSelectedSlot(); - if (typeId === this.itemInHand) { - return; // Skip rebuilding if the item hasn't changed - } - - // Clear previous mesh - this.itemInHandGroup.clear(); - - // Should render hand or item - if (typeId === 0) { - - } else { - let block = Block.getById(typeId); - - // this.minecraft.worldRenderer.blockRenderer.renderBlockInHand(block, this.itemInHandGroup, 1); - } - - // Store item in hand meta - this.itemInHand = typeId; - } - renderItemInGui(renderId, block, x, y) { let meta = this.items[renderId]; if (typeof meta === "undefined") { diff --git a/src/js/net/minecraft/client/render/model/ModelBase.js b/src/js/net/minecraft/client/render/model/ModelBase.js index 6d7a5ae..4adc8f9 100644 --- a/src/js/net/minecraft/client/render/model/ModelBase.js +++ b/src/js/net/minecraft/client/render/model/ModelBase.js @@ -10,8 +10,12 @@ export default class ModelBase { } - render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch) { - entity.group.updateMatrix(); + render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) { + stack.updateMatrix(); + } + + setRotationAngles(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) { + } } \ No newline at end of file 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 56c909b..fd86b3c 100644 --- a/src/js/net/minecraft/client/render/model/model/ModelPlayer.js +++ b/src/js/net/minecraft/client/render/model/model/ModelPlayer.js @@ -10,6 +10,10 @@ export default class ModelPlayer extends ModelBase { constructor() { super(); + this.swingProgress = 0; + this.hasItemInHand = false; + this.isSneaking = false; + let width = 64; let height = 32; @@ -59,20 +63,32 @@ export default class ModelPlayer extends ModelBase { this.rightLeg.rebuild(tessellator, group); } - render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch, partialTicks) { - let group = entity.group; + render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) { + this.setRotationAngles(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks); + // Render cubes + this.head.render(); + this.body.render(); + this.rightArm.render(); + this.leftArm.render(); + this.rightLeg.render(); + this.leftLeg.render(); + + super.render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks); + } + + setRotationAngles(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) { // Head rotation this.head.rotateAngleY = MathHelper.toRadians(yaw); this.head.rotateAngleX = MathHelper.toRadians(pitch); // Limb swing leg animation - this.rightArm.rotateAngleX = Math.cos(limbSwingAmount * 0.6662 + Math.PI) * 2.0 * limbSwing * 0.5; - this.leftArm.rotateAngleX = Math.cos(limbSwingAmount * 0.6662) * 2.0 * limbSwing * 0.5; + this.rightArm.rotateAngleX = Math.cos(limbSwing * 0.6662 + Math.PI) * 2.0 * limbSwingStrength * 0.5; + this.leftArm.rotateAngleX = Math.cos(limbSwing * 0.6662) * 2.0 * limbSwingStrength * 0.5; this.rightArm.rotateAngleZ = 0.0; this.leftArm.rotateAngleZ = 0.0; - this.rightLeg.rotateAngleX = Math.cos(limbSwingAmount * 0.6662) * 1.4 * limbSwing; - this.leftLeg.rotateAngleX = Math.cos(limbSwingAmount * 0.6662 + Math.PI) * 1.4 * limbSwing; + this.rightLeg.rotateAngleX = Math.cos(limbSwing * 0.6662) * 1.4 * limbSwingStrength; + this.leftLeg.rotateAngleX = Math.cos(limbSwing * 0.6662 + Math.PI) * 1.4 * limbSwingStrength; this.rightLeg.rotateAngleY = 0.0; this.leftLeg.rotateAngleY = 0.0; @@ -82,18 +98,12 @@ export default class ModelPlayer extends ModelBase { this.leftArm.rotateAngleY = 0.0; // Held item animation - if (entity.inventory.getItemInSelectedSlot() !== 0) { + if (this.hasItemInHand) { this.rightArm.rotateAngleX = this.rightArm.rotateAngleX * 0.5 - (Math.PI / 10); } - // Swing progress - let swingProgress = entity.swingProgress - entity.prevSwingProgress; - if (swingProgress < 0.0) { - swingProgress++; - } - let interpolatedSwingProgress = entity.prevSwingProgress + swingProgress * partialTicks; - if (interpolatedSwingProgress > -9990.0) { - let swingProgress = interpolatedSwingProgress; + if (this.swingProgress > -9990.0) { + let swingProgress = this.swingProgress; this.body.rotateAngleY = Math.sin(Math.sqrt(swingProgress) * Math.PI * 2.0) * 0.2; @@ -106,21 +116,21 @@ export default class ModelPlayer extends ModelBase { this.leftArm.rotateAngleY += this.body.rotateAngleY; this.leftArm.rotateAngleX += this.body.rotateAngleY; - swingProgress = 1.0 - interpolatedSwingProgress; + swingProgress = 1.0 - swingProgress; swingProgress = swingProgress * swingProgress; swingProgress = swingProgress * swingProgress; swingProgress = 1.0 - swingProgress; let value1 = Math.sin(swingProgress * Math.PI); - let value2 = Math.sin(interpolatedSwingProgress * Math.PI) * -(this.head.rotateAngleX - 0.7) * 0.75; + let value2 = Math.sin(swingProgress * Math.PI) * -(this.head.rotateAngleX - 0.7) * 0.75; this.rightArm.rotateAngleX = (this.rightArm.rotateAngleX - (value1 * 1.2 + value2)); this.rightArm.rotateAngleY += this.body.rotateAngleY * 2.0; - this.rightArm.rotateAngleZ += Math.sin(interpolatedSwingProgress * Math.PI) * -0.4; + this.rightArm.rotateAngleZ += Math.sin(swingProgress * Math.PI) * -0.4; } // Sneaking animation - if (entity.sneaking) { + if (this.isSneaking) { this.body.rotateAngleX = 0.5; this.rightArm.rotateAngleX += 0.4; this.leftArm.rotateAngleX += 0.4; @@ -130,7 +140,7 @@ export default class ModelPlayer extends ModelBase { this.leftLeg.rotationPointY = 9.0; this.head.rotationPointY = 1.0; - group.translateY(-0.2); + stack.translateY(-0.2); } else { this.body.rotateAngleX = 0.0; this.rightLeg.rotationPointZ = 0.1; @@ -145,16 +155,6 @@ export default class ModelPlayer extends ModelBase { this.leftArm.rotateAngleZ -= Math.cos(timeAlive * 0.09) * 0.05 + 0.05; this.rightArm.rotateAngleX += Math.sin(timeAlive * 0.067) * 0.05; this.leftArm.rotateAngleX -= Math.sin(timeAlive * 0.067) * 0.05; - - // Render cubes - this.head.render(); - this.body.render(); - this.rightArm.render(); - this.leftArm.render(); - this.rightLeg.render(); - this.leftLeg.render(); - - super.render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch); } } \ 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 0235729..7a9fceb 100644 --- a/src/js/net/minecraft/client/render/model/renderer/ModelRenderer.js +++ b/src/js/net/minecraft/client/render/model/renderer/ModelRenderer.js @@ -262,4 +262,31 @@ export default class ModelRenderer { this.bone.updateMatrix(); } + clone() { + let modelRenderer = new ModelRenderer(this.name, this.textureWidth, this.textureHeight); + modelRenderer.bone = this.bone.clone(); + modelRenderer.textureOffsetX = this.textureOffsetX; + modelRenderer.textureOffsetY = this.textureOffsetY; + modelRenderer.cubes = this.cubes; + modelRenderer.copyTransformOf(this); + + for (let i = 0; i < this.children.length; i++) { + let child = this.children[i]; + modelRenderer.addChild(child.clone()); + } + + return modelRenderer; + } + + copyTransformOf(modelRenderer) { + this.rotationPointX = modelRenderer.rotationPointX; + this.rotationPointY = modelRenderer.rotationPointY; + this.rotationPointZ = modelRenderer.rotationPointZ; + this.scaleX = modelRenderer.scaleX; + this.scaleY = modelRenderer.scaleY; + this.scaleZ = modelRenderer.scaleZ; + this.rotateAngleX = modelRenderer.rotateAngleX; + this.rotateAngleY = modelRenderer.rotateAngleY; + this.rotateAngleZ = modelRenderer.rotateAngleZ; + } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/world/World.js b/src/js/net/minecraft/client/world/World.js index 76e8701..616f949 100644 --- a/src/js/net/minecraft/client/world/World.js +++ b/src/js/net/minecraft/client/world/World.js @@ -521,13 +521,13 @@ export default class World { addEntity(entity) { this.entities.push(entity); - this.group.add(entity.group); + this.group.add(entity.renderer.group); } removeEntityById(id) { let entity = this.getEntityById(id); this.entities.remove(entity); - this.group.remove(entity.group); + this.group.remove(entity.renderer.group); } getEntityById(id) { diff --git a/src/js/net/minecraft/util/MathHelper.js b/src/js/net/minecraft/util/MathHelper.js index 6809284..4910e1c 100644 --- a/src/js/net/minecraft/util/MathHelper.js +++ b/src/js/net/minecraft/util/MathHelper.js @@ -1,5 +1,9 @@ export default class MathHelper { + static clamp(number, min, max) { + return Math.min(Math.max(number, min), max); + } + /** * Returns the greatest integer less than or equal to the double argument */ @@ -14,7 +18,7 @@ export default class MathHelper { static toRadians(degree) { return degree * (Math.PI / 180); - }; + } static calculateCelestialAngle(time, partialTicks) { let modTime = (time % 24000);