internal void ChangeSlotInternal(EquiPlayerAttachmentComponent.Slot slot, float randSeed) { this.GetLogger().Debug($"Changing slot for {Entity} to {slot?.Controllable?.Entity}#{slot?.Definition.Name}"); var old = _controlledSlot; _controlledSlot = slot; var oldAnimData = old?.Definition.ByIndex(_saveData.AnimationId); EquiPlayerAttachmentComponentDefinition.AnimationDesc?newAnimData = null; if (slot != null && _saveData.ControlledSlot == slot.Definition.Name) { newAnimData = slot.Definition.ByIndex(_saveData.AnimationId); } if (!newAnimData.HasValue) { newAnimData = slot?.Definition.SelectAnimation(Entity.DefinitionId ?? default(MyDefinitionId), randSeed, out _saveData.AnimationId); } // Handles animation controller switching var animController = Entity.Components.Get <MyAnimationControllerComponent>(); if (animController != null) { if (oldAnimData.HasValue) { animController.TriggerAction(oldAnimData.Value.Stop); } if (newAnimData.HasValue) { AddScheduledCallback(CommitAnimationStart); } } // Handle restoring character's position if (slot == null && old?.Controllable?.Entity != null && old.Controllable.Entity.InScene) { var relMatrix = _saveData.RelativeOrientation.GetMatrix(); if (relMatrix.Scale.AbsMax() < 1) { relMatrix = MatrixD.Identity; } var outPos = relMatrix * old.AttachMatrix; var transformedCenter = Vector3.TransformNormal(Entity.PositionComp.LocalAABB.Center, outPos); var orientation = Quaternion.CreateFromRotationMatrix(Entity.PositionComp.WorldMatrix.GetOrientation()); var halfExtents = Entity.PositionComp.LocalAABB.HalfExtents; halfExtents.X *= 0.25f; halfExtents.Z *= 0.25f; var translate = MyEntities.FindFreePlace(outPos.Translation + transformedCenter, orientation, halfExtents, 200, 20, 0.1f, false); if (translate.HasValue) { outPos.Translation = translate.Value - transformedCenter; } else { outPos = old.AttachMatrix; } var gravity = Vector3.Normalize(MyGravityProviderSystem.CalculateTotalGravityInPoint(outPos.Translation)); if (MyAPIGateway.Physics.CastRay(outPos.Translation - gravity, outPos.Translation + 10 * gravity, out var hit)) { outPos.Translation = hit.Position; } Entity.PositionComp.SetWorldMatrix(outPos, Entity.Parent, true); } // Handles storing the character's position when attaching if (slot != null) { _saveData.RelativeOrientation = new MyPositionAndOrientation(MatrixD.Normalize(Entity.WorldMatrix * MatrixD.Invert(slot.AttachMatrix))); } // Handle keeping the physics in check if (Entity.Physics != null) { var wantsPhysicsEnabled = slot == null; if (wantsPhysicsEnabled && !Entity.Physics.Enabled) { Entity.Physics.Activate(); } else if (!wantsPhysicsEnabled && Entity.Physics.Enabled) { Entity.Physics.Deactivate(); } if (slot == null) { var oldPhys = old?.Controllable?.Entity.ParentedPhysics(); if (oldPhys != null) { Entity.Physics.LinearVelocity = oldPhys.GetVelocityAtPoint(old.Controllable.Entity.WorldMatrix.Translation); } } } _saveData.ControlledEntity = slot?.Controllable.Entity.EntityId ?? 0; _saveData.ControlledSlot = slot?.Definition.Name; if (slot == null) { _tracker.Unlink(Entity.EntityId); } else { _tracker.Link(Entity.EntityId, new ControlledId(slot)); } if (old?.Controllable != null) { RemoveFixedUpdate(FixPosition); } if (slot?.Controllable != null) { AddFixedUpdate(FixPosition, PriorityOverride); } FixPosition(); if (old != null) { old.AttachedCharacter = null; } if (slot != null) { slot.AttachedCharacter = Entity; } ControlledChanged?.Invoke(this, old, slot); _tracker.RaiseControlledChange(this, old, slot); }
internal void ChangeSlotInternal(EquiPlayerAttachmentComponent.Slot slot, float randSeed) { this.GetLogger().Debug($"Changing slot for {Entity} to {slot?.Controllable?.Entity}#{slot?.Definition.Name}"); var old = _controlledSlot; _controlledSlot = slot; var oldAnimData = old?.Definition.ByIndex(_saveData.AnimationId); EquiPlayerAttachmentComponentDefinition.AnimationDesc?newAnimData = null; if (slot != null && _saveData.ControlledSlot == slot.Definition.Name) { newAnimData = slot.Definition.ByIndex(_saveData.AnimationId); } if (!newAnimData.HasValue) { newAnimData = slot?.Definition.SelectAnimation(Entity.DefinitionId ?? default(MyDefinitionId), randSeed, out _saveData.AnimationId); } // Handles animation controller switching var animController = Entity.Components.Get <MyAnimationControllerComponent>(); if (animController != null) { if (oldAnimData.HasValue) { animController.TriggerAction(oldAnimData.Value.Stop); } if (newAnimData.HasValue) { AddScheduledCallback(CommitAnimationStart); } } // Handle restoring character's position if (slot == null && old?.Controllable?.Entity != null && old.Controllable.Entity.InScene) { var relMatrix = _saveData.RelativeOrientation.GetMatrix(); if (relMatrix.Scale.AbsMax() < 1) { relMatrix = MatrixD.Identity; } var outPos = relMatrix * old.AttachMatrix; var gravity = Vector3.Normalize(MyGravityProviderSystem.CalculateTotalGravityInPoint(outPos.Translation)); var rightCandidate = Vector3.Cross(gravity, (Vector3)outPos.Forward); if (rightCandidate.LengthSquared() < 0.5f) { rightCandidate = MyUtils.GetRandomVector3(); } var correctedForward = Vector3.Normalize(Vector3.Cross(rightCandidate, gravity)); outPos = MatrixD.CreateWorld(outPos.Translation, correctedForward, -gravity); var transformedCenter = Vector3.TransformNormal(Entity.PositionComp.LocalAABB.Center, outPos); var orientation = Quaternion.CreateFromRotationMatrix(outPos); var originalHalfExtents = Entity.PositionComp.LocalAABB.HalfExtents; var halfExtents = new Vector3(originalHalfExtents.X * 0.8f, originalHalfExtents.Y, originalHalfExtents.Z * 0.8f); const int maxUpwardShifts = 4; var shiftDistance = 0f; for (var i = 0; i <= maxUpwardShifts; i++) { shiftDistance = (float)Math.Pow(i, 1.5f); var outPosCenter = outPos.Translation + transformedCenter - gravity * shiftDistance; if (i < maxUpwardShifts) { var translate = FindFreePlaceImproved(outPosCenter, orientation, halfExtents, gravity); if (!translate.HasValue) { continue; } outPos.Translation = translate.Value - transformedCenter; break; } else { var translate = MyEntities.FindFreePlace(outPosCenter, orientation, halfExtents, 1000, 50, 0.1f, /* on the last try push to the surface */ true); if (translate.HasValue) { outPos.Translation = translate.Value - transformedCenter; } else { outPos.Translation = old.AttachMatrix.Translation; } break; } } // Final clean up with minor shift to get out of overlapping any surfaces var finalShift = MyEntities.FindFreePlace(outPos.Translation + transformedCenter, orientation, originalHalfExtents * 1.05f, 250, 50, 0.025f, false); if (finalShift.HasValue) { outPos.Translation = finalShift.Value - transformedCenter; } if (MyAPIGateway.Physics.CastRay(outPos.Translation - gravity, outPos.Translation + (1 + shiftDistance) * gravity, out var hit)) { outPos.Translation = hit.Position; } Entity.PositionComp.SetWorldMatrix(outPos, Entity.Parent, true); // Give the player 5 seconds of health immunity when they leave a chair to prevent collisions from killing them if we couldn't // find a free space Entity?.Get <MyCharacterDamageComponent>()?.AddTemporaryHealthImmunity(2); } // Handles storing the character's position when attaching if (slot != null) { _saveData.RelativeOrientation = new MyPositionAndOrientation(MatrixD.Normalize(Entity.WorldMatrix * MatrixD.Invert(slot.AttachMatrix))); } // Handle keeping the physics in check if (Entity.Physics != null) { var wantsPhysicsEnabled = slot == null; if (wantsPhysicsEnabled && !Entity.Physics.Enabled) { Entity.Physics.Activate(); } else if (!wantsPhysicsEnabled && Entity.Physics.Enabled) { Entity.Physics.Deactivate(); } if (slot == null) { var oldPhys = old?.Controllable?.Entity.ParentedPhysics(); if (oldPhys != null) { Entity.Physics.LinearVelocity = oldPhys.GetVelocityAtPoint(old.Controllable.Entity.WorldMatrix.Translation); } } } _saveData.ControlledEntity = slot?.Controllable.Entity.EntityId ?? 0; _saveData.ControlledSlot = slot?.Definition.Name; if (slot == null) { _tracker.Unlink(Entity.EntityId); } else { _tracker.Link(Entity.EntityId, new ControlledId(slot)); } if (old?.Controllable != null) { RemoveFixedUpdate(FixPosition); } if (slot?.Controllable != null) { AddFixedUpdate(FixPosition, PriorityOverride); } FixPosition(); if (old != null) { old.AttachedCharacter = null; } if (slot != null) { slot.AttachedCharacter = Entity; } ControlledChanged?.Invoke(this, old, slot); _tracker.RaiseControlledChange(this, old, slot); }