private void DoUpdate(CameraUpdate update) { { var wasEnabled = IsEnabled; var isEnabled = CalculateEnabled(update); if (wasEnabled != isEnabled) { if (!isEnabled) { Stack.DisableAll(update); } IsEnabled = isEnabled; if (isEnabled) { OnEnabled(update); } else { OnDisabled(update); } } } if (IsEnabled) { OnUpdating(0); } if (IsEnabled) { if (Stabilize == null || Stabilize.ShouldRecreate(update.Target)) { Stabilize = new CameraStabilize(this, update.Target); } Stabilize?.Update(update.Target.StabilizeRootNode, update.Target.HeadNode, update); } Stack.Check(update); Stack.Update(update); update.Values.Update(Plugin.Time, IsEnabled); Hide.Update(update); { var isFpArms = IsEnabled && update.Values.Show1stPersonArms.CurrentValue >= 0.5; if (isFpArms != WasUsingFirstPersonArms) { WasUsingFirstPersonArms = isFpArms; } } if (IsEnabled) { var mode = update.Values.SkeletonMode.CurrentValue; var wantThird = true; if (mode <= -0.5) { wantThird = !WasUsingFirstPersonArms; } else if (mode >= 0.5) { wantThird = false; } //else wantThird = true; var showFirst = WasUsingFirstPersonArms; var showThird = !(DidCollideLastUpdate && Settings.Instance.HidePlayerWhenColliding == 2); UpdateSkeleton(showFirst, showThird, wantThird); } if (IsEnabled) { if (Stabilize == null || !Stabilize.Get(update.Target.StabilizeRootNode, BaseRoot.Transform)) { BaseRoot.Transform.CopyFrom(update.Target.HeadNode.WorldTransform); } BaseHead.Transform.CopyFrom(update.Target.HeadNode.WorldTransform); CameraResult cur = null; using (cur) { { var posRatio = update.Values.PositionFromHead.CurrentValue; switch (posRatio) { case 0.0: BaseResult.Transform.Position.CopyFrom(BaseRoot.Transform.Position); break; case 1.0: BaseResult.Transform.Position.CopyFrom(BaseHead.Transform.Position); break; default: { var pos = BaseResult.Transform.Position; var rootPos = BaseRoot.Transform.Position; var headPos = BaseHead.Transform.Position; pos.X = (float)((headPos.X - rootPos.X) * posRatio + rootPos.X); pos.Y = (float)((headPos.Y - rootPos.Y) * posRatio + rootPos.Y); pos.Z = (float)((headPos.Z - rootPos.Z) * posRatio + rootPos.Z); break; } } } // Calculate base rotation. { var rotRatio = update.Values.RotationFromHead.CurrentValue; switch (rotRatio) { case 0.0: BaseResult.Transform.Rotation.CopyFrom(BaseRoot.Transform.Rotation); break; case 1.0: BaseResult.Transform.Rotation.CopyFrom(BaseHead.Transform.Rotation); break; default: { var rot = BaseResult.Transform.Rotation; var rootRot = BaseRoot.Transform.Rotation; var headRot = BaseHead.Transform.Rotation; rootRot.Interpolate(headRot, (float)rotRatio, rot); break; } } } cur = BaseResult; // Calculate offset based on object rotation itself. { var root = update.Target.RootNode; if (root != null) { var x = Values.OffsetObjectPositionX.CurrentValue; var y = Values.OffsetObjectPositionY.CurrentValue; var z = Values.OffsetObjectPositionZ.CurrentValue; if (x != 0.0 || y != 0.0 || z != 0.0) { Offset1Result.Transform.Position.CopyFrom(BaseResult.Transform.Position); Offset1Result.Transform.Rotation.CopyFrom(root.WorldTransform.Rotation); ApplyPositionOffset(Offset1Result.Transform, (float)x, (float)y, (float)z, BaseResult.Transform.Position); } } } // Look down offset. if (Default._look_downoffset_ratio > 0.0f || Default._look_downoffset_ratio_leftrightmove > 0.0f) { var ratio = Default._look_downoffset_ratio; var root = update.Target.RootNode; if (root != null) { var x = Settings.Instance.DownOffsetX * ratio; var y = Settings.Instance.DownOffsetY * ratio; var z = Settings.Instance.DownOffsetZ * ratio; y += Settings.Instance.TryFixLeftRightMovementClipping * Default._look_downoffset_ratio_leftrightmove; if (x != 0.0f || y != 0.0f || z != 0.0f) { Offset1Result.Transform.Position.CopyFrom(BaseResult.Transform.Position); Offset1Result.Transform.Rotation.CopyFrom(root.WorldTransform.Rotation); ApplyPositionOffset(Offset1Result.Transform, x, y, z, BaseResult.Transform.Position); } } } // Calculate offset #1. { var rx = (float)Values.Offset1RotationX.CurrentValue; var ry = (float)Values.Offset1RotationY.CurrentValue; var px = (float)Values.Offset1PositionX.CurrentValue; var py = (float)Values.Offset1PositionY.CurrentValue; var pz = (float)Values.Offset1PositionZ.CurrentValue; var hasRot = rx != 0.0f || ry != 0.0f; var hasPos = px != 0.0f || py != 0.0f || pz != 0.0f; if (hasRot || hasPos) { Offset1Result.Transform.CopyFrom(cur.Transform); if (hasRot) { ApplyRotationOffset(Offset1Result.Transform.Rotation, rx, ry, Offset1Result.Transform.Rotation); } if (hasPos) { ApplyPositionOffset(Offset1Result.Transform, px, py, pz, Offset1Result.Transform.Position); } cur = Offset1Result; } } // Calculate input. { var extraX = 0.0f; var extraY = 0.0f; if (LastActorTurnFrames > 0) { LastActorTurnFrames--; extraX = LastActorTurnX; //extraY = this.LastActorTurnY; } var rx = (float)(Values.InputRotationX.CurrentValue + extraX) * (float)Values.InputRotationXMultiplier.CurrentValue; var ry = (float)(Values.InputRotationY.CurrentValue + extraY) * (float)Values.InputRotationYMultiplier.CurrentValue; if (rx != 0.0f || ry != 0.0f) { InputResult.Transform.CopyFrom(cur.Transform); ApplyRotationOffset(InputResult.Transform.Rotation, rx, ry, InputResult.Transform.Rotation); cur = InputResult; } } // Calculate offset #2. { var rx = (float)Values.Offset2RotationX.CurrentValue; var ry = (float)Values.Offset2RotationY.CurrentValue; var px = (float)Values.Offset2PositionX.CurrentValue; var py = (float)Values.Offset2PositionY.CurrentValue; var pz = (float)Values.Offset2PositionZ.CurrentValue; var hasRot = rx != 0.0f || ry != 0.0f; var hasPos = px != 0.0f || py != 0.0f || pz != 0.0f; if (hasRot || hasPos) { Offset2Result.Transform.CopyFrom(cur.Transform); if (hasRot) { ApplyRotationOffset(Offset2Result.Transform.Rotation, rx, ry, Offset2Result.Transform.Rotation); } if (hasPos) { ApplyPositionOffset(Offset2Result.Transform, px, py, pz, Offset2Result.Transform.Position); } cur = Offset2Result; } } // Apply tween from stabilize. { Stabilize?.ApplyTween(cur.Transform.Position, Plugin.Time); } // Apply collision of camera so we don't go inside walls, this can be done within the same transform. { DidCollideLastUpdate = CameraCollision.Apply(update, cur.Transform, cur.Transform.Position); } // Calculate final result. { FinalResult.Transform.CopyFrom(cur.Transform); } } update.GameCameraNode.LocalTransform.CopyFrom(FinalResult.Transform); update.GameCameraNode.Update(0.0f); Hide.UpdateFirstPersonSkeletonRotation(update); if (update.GameCameraState is ThirdPersonState third) { third.Position.CopyFrom(update.GameCameraNode.LocalTransform.Position); } if (WasUsingFirstPersonArms) { UpdateMagicNodePosition(update); } } else { DidCollideLastUpdate = false; } if (IsEnabled) { OnUpdating(1); } if (!IsEnabled && Settings.Instance.ReplaceDefaultCamera && update.GameCameraState.Id == TESCameraStates.FirstPerson && IsGameCameraSwitchControlsEnabled()) { update.GameCamera.EnterThirdPerson(); SetWantState(WantStates.EnabledFromTogglePOV); } FixSensitivityMode = IsEnabled && update.GameCameraState.Id == TESCameraStates.ThirdPerson2 && Memory.ReadUInt8(update.GameCameraState.Address + 0xDC) != 0; }