// The Update route protected virtual void LateUpdate() { try { // If a critical error is thrown in this method, flag it to be true, so we don't get into a spaming loop. if (CriticalError) { return; } // Delay the updating of hte indexes by the CheckDelay, which is 5seconds by default. if (nextCheck == 0.0f || nextCheck < Time.time) { nextCheck = Time.time + CheckDelay; SetRandomIndex("RandomIndex"); SetRandomIndex("WalkIndex"); SetRandomIndex("RunIndex"); SetRandomIndex("IdleIndex"); } if (this.entityAlive == null) { Log("The entity is null!"); CriticalError = true; } ActionTime -= Time.deltaTime; if (bipedTransform == null || !bipedTransform.gameObject.activeInHierarchy) { Log("Biped Transform was null!"); CriticalError = true; return; } if (anim == null || anim.avatar == null) { Log(string.Format("Animator or Animator Avatar is Null for {0}", modelTransform.name)); CriticalError = true; return; } if (anim.avatar.isValid && anim.enabled) { if (entityAlive.IsBreakingBlocks && !anim.GetBool(IsBreakingBlocks)) { anim.SetBool(IsBreakingBlocks, true); } else { anim.SetBool(IsBreakingBlocks, false); } if (entityAlive.IsBreakingDoors && !anim.GetBool(IsBreakingDoors)) { anim.SetBool(IsBreakingDoors, true); } else { anim.SetBool(IsBreakingDoors, false); } UpdateCurrentState(); if (this.timeSpecialAttackPlaying > 0f) { // it's playing special attack this.timeSpecialAttackPlaying -= Time.deltaTime; return; } // Test condition while we evaluate the effectiveness of using encroachment for state machine triggers. if (true) { if (this.timeSpecialAttackPlaying > 0f) { // it's playing special attack this.timeSpecialAttackPlaying -= Time.deltaTime; return; } Log("Last Distance: " + this.lastDistance); float playerDistanceX = 0.0f; float playerDistanceZ = 0.0f; float encroached = this.lastDistance; // Calculates how far away the entity is playerDistanceX = Mathf.Abs(this.entityAlive.position.x - this.entityAlive.lastTickPos[0].x) * 6f; playerDistanceZ = Mathf.Abs(this.entityAlive.position.z - this.entityAlive.lastTickPos[0].z) * 6f; if (!this.entityAlive.isEntityRemote) { if (Mathf.Abs(playerDistanceX - this.lastPlayerX) > 0.00999999977648258 || Mathf.Abs(playerDistanceZ - this.lastPlayerZ) > 0.00999999977648258) { encroached = Mathf.Sqrt(playerDistanceX * playerDistanceX + playerDistanceZ * playerDistanceZ); this.lastPlayerX = playerDistanceX; this.lastPlayerZ = playerDistanceZ; this.lastDistance = encroached; } } else if (playerDistanceX <= this.lastPlayerX && playerDistanceZ <= this.lastPlayerZ) { this.lastPlayerX *= 0.9f; this.lastPlayerZ *= 0.9f; this.lastDistance *= 0.9f; } else { encroached = Mathf.Sqrt((playerDistanceX * playerDistanceX + playerDistanceZ * playerDistanceZ)); this.lastPlayerX = playerDistanceX; this.lastPlayerZ = playerDistanceZ; this.lastDistance = encroached; } Log("LastPlayerX: " + this.lastPlayerX); Log("LastPlayerZ: " + this.lastPlayerZ); Log("Last Distance:" + this.lastDistance); Log("Encroachment: " + encroached); // if the entity is in water, flag it, so we'll do the swiming conditions before the movement. this.anim.SetBool("IsInWater", entityAlive.IsInWater()); Log("Entity is in Water: " + entityAlive.IsInWater()); Log("Movement State on Animation: " + this.anim.GetInteger("MovementState")); // this.entityAlive.world.IsMaterialInBounds(BoundsUtils.ExpandBounds(this.entityAlive.boundingBox, -0.1f, -0.4f, -0.1f), MaterialBlock.water); if (entityAlive.Electrocuted) { StartAnimationElectrocuted(); } else { this.IsElectrocuting = false; } if (entityAlive.HarvestingAnimation) { StartAnimationHarvesting(); } else { this.IsHarvesting = false; } if (entityAlive.IsEating) { StartEating(); } else { this.isEating = false; } if (encroached > 0.150000005960464) { // Running if above 1.0 if (encroached > 1.0) { this.anim.SetInteger(MovementState, 2); } else { this.anim.SetInteger(MovementState, 1); } } else { this.anim.SetInteger(MovementState, 0); } Log("Movement State on Animation: " + this.anim.GetInteger("MovementState")); } else { // this code uses a newer version of logic, but seems to be inconsistent var num = 0f; var num2 = 0f; if (!entityAlive.IsFlyMode.Value) { num = entityAlive.speedForward; num2 = entityAlive.speedStrafe; } var num3 = num2; if (num3 >= 1234f) { num3 = 0f; } anim.SetFloat(Forward, num); anim.SetFloat(Strafe, num3); var num4 = num * num + num3 * num3; if (!entityAlive.IsDead()) { anim.SetInteger(MovementState, num4 <= entityAlive.speedApproach * entityAlive.speedApproach ? (num4 <= entityAlive.speedWander * entityAlive.speedWander ? (num4 <= 0.001f ? 0 : 1) : 2) : 3); } if (Mathf.Abs(num) <= 0.01f && Mathf.Abs(num2) <= 0.01f) { anim.SetBool(IsMoving, false); } else { idleTime = 0f; anim.SetBool(IsMoving, true); } } var flag = false; if (anim != null && isInDeathAnim && !anim.IsInTransition(0) ) // this.DeathHash.Contains(this.currentBaseState.fullPathHash) ) { flag = true; } if (anim != null && isInDeathAnim && flag && (currentBaseState.normalizedTime >= 1f || anim.IsInTransition(0))) { isInDeathAnim = false; if (entityAlive.HasDeathAnim) { entityAlive.emodel.DoRagdoll(DamageResponse.New(true)); } } anim.SetFloat(IdleTime, idleTime); idleTime += Time.deltaTime; } } catch (Exception ex) { // Because errors in the LateUpdate are pretty fatal, we'll flag it as Critical so things won't get stuck in a spam update, and // the debug log will display all the time. Debug.Log(string.Format("Error in LateUpdate for {0} : {1}", this.modelTransform.name, ex.ToString())); CriticalError = true; } }