internal void RaiseControlledChange(EquiEntityControllerComponent controller, EquiPlayerAttachmentComponent.Slot controlledOld,
                                            EquiPlayerAttachmentComponent.Slot controlledNew)
        {
            ControlledChanged?.Invoke(controller, controlledOld, controlledNew);

            if (controller.Entity == MyAPIGateway.Session.ControlledObject)
            {
                CheckAttachedControls();
            }
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }