예제 #1
0
    public static List <IEntity> GetEntitiesWithinArea(Vector3 Center, float Radius)
    {
        //TODO: Make this more generic, more performant
        Assert.ActualAssert(Radius < ChunkSize);

        var Output = new List <IEntity>();

        var ChunkList = new List <Tuple <int, int> >();

        ChunkList.Add(GetChunkTuple(Center));

        ChunkList.Add(GetChunkTuple(Center + new Vector3(ChunkSize, 0, 0)));           //Forward
        ChunkList.Add(GetChunkTuple(Center + new Vector3(-ChunkSize, 0, 0)));          //Backward

        ChunkList.Add(GetChunkTuple(Center + new Vector3(0, 0, ChunkSize)));           //Right
        ChunkList.Add(GetChunkTuple(Center + new Vector3(0, 0, -ChunkSize)));          //Left

        ChunkList.Add(GetChunkTuple(Center + new Vector3(ChunkSize, 0, ChunkSize)));   //Forward right
        ChunkList.Add(GetChunkTuple(Center + new Vector3(ChunkSize, 0, -ChunkSize)));  //Forward left

        ChunkList.Add(GetChunkTuple(Center + new Vector3(-ChunkSize, 0, ChunkSize)));  //Backward right
        ChunkList.Add(GetChunkTuple(Center + new Vector3(-ChunkSize, 0, -ChunkSize))); //Backward left

        foreach (var ChunkTuple in ChunkList)
        {
            if (Chunks.TryGetValue(ChunkTuple, out ChunkClass Chunk))
            {
                Output = Output.Concat(Chunk.Entities).ToList();                 //TODO: Eww
            }
        }

        return(Output);
    }
예제 #2
0
    public static void ApplyEffectiveRecoil(float VerticalRecoil, float HorizontalRecoil)
    {
        Game.PossessedPlayer.MatchSome(
            (Plr) => {
            Assert.ActualAssert(NextRecoilDirection == 1 || NextRecoilDirection == -1);

            //Lessen recoil when ADS
            VerticalRecoil   *= Plr.AdsMultiplier;
            HorizontalRecoil *= Plr.AdsMultiplier;

            //Lessen recoil when crouching
            if (Plr.IsCrouching)
            {
                VerticalRecoil   *= CrouchAffectPercentage;
                HorizontalRecoil *= CrouchAffectPercentage;
            }

            Plr.ApplyLookVertical(VerticalRecoil);
            Plr.LookHorizontal += HorizontalRecoil * -NextRecoilDirection;
            Plr.RotationDegrees = new Vector3(0, Plr.LookHorizontal, 0);

            NextRecoilDirection = -NextRecoilDirection;
        }
            );
    }
예제 #3
0
    private void ReceiveTransferFromTo(NodePath FromPath, int FromSlot, NodePath ToPath, int ToSlot, Items.IntentCount CountMode)
    {
        Assert.ActualAssert(Net.Work.IsNetworkServer());

        var MaybeFrom = World.EntitiesRoot.GetNodeOrNull(FromPath);
        var MaybeTo   = World.EntitiesRoot.GetNodeOrNull(ToPath);

        if (MaybeFrom is IHasInventory From && MaybeTo is IHasInventory To)
        {
            From.Inventory.TransferTo(To, FromSlot, ToSlot, CountMode);
        }
예제 #4
0
    public override void _Ready()
    {
        Parent = GetParent <IProjectile>();
        Assert.ActualAssert(Parent != null);

        StartPoint = GetNode <Spatial>(StartPointPath);
        Assert.ActualAssert(StartPoint != null);

        EndPoint = GetNode <Spatial>(EndPointPath);
        Assert.ActualAssert(EndPoint != null);
    }
예제 #5
0
파일: Player.cs 프로젝트: van800/SkyOfSteel
    public void NotifyPickedUpItem()
    {
        if (!Possessed)
        {
            Assert.ActualAssert(Net.Work.IsNetworkServer());
            Net.SteelRpc(this, nameof(NotifyPickedUpItem));
            return;
        }

        SfxManager.FpPickup();
        SetCooldown(0, SlotSwitchCooldown, false);
    }
예제 #6
0
    public void NotifyPickedUpItem()
    {
        if (!Possessed)
        {
            Assert.ActualAssert(Net.Work.IsNetworkServer());
            RpcId(Id, nameof(NotifyPickedUpItem));
            return;
        }

        Sfx.PlayPlayer(Sfx.ID.ITEM_PICKUP, this);
        SetCooldown(0, SlotSwitchCooldown, false);
    }
예제 #7
0
    private void ReceivePhaseOut(string Identifier)
    {
        Node Entity = World.EntitiesRoot.GetNodeOrNull(Identifier);

        if (Entity is null)
        {
            return;
        }

        Assert.ActualAssert(Entity is IEntity);
        ((IEntity)Entity).PhaseOut();
    }
예제 #8
0
    private void ReceiveDestroy(string Identifier, params object[] Args)
    {
        Node Entity = World.EntitiesRoot.GetNodeOrNull(Identifier);

        if (Entity is null)
        {
            return;
        }

        Assert.ActualAssert(Entity is IEntity);
        ((IEntity)Entity).Destroy(Args);
    }
예제 #9
0
    public void InitialNetWorldLoad(int Id, Vector3 PlayerPosition, int RenderDistance)
    {
        if (!Net.Work.IsNetworkServer())
        {
            throw new Exception($"Attempted to run {nameof(InitialNetWorldLoad)} on client");
        }

        RequestChunks(Id, PlayerPosition, RenderDistance);

        Assert.ActualAssert(Net.Players[Id].Plr.HasValue);         //Todo: Spawn the player here
        Net.Players[Id].Plr.ValueOrFailure().SetFreeze(false);
        Net.Players[Id].Plr.ValueOrFailure().GiveDefaultItems();
    }
예제 #10
0
    private void ReceiveUpdate(string Identifier, params object[] Args)
    {
        Node Entity = World.EntitiesRoot.GetNodeOrNull(Identifier);

        if (Entity is null)
        {
            RpcId(Net.ServerId, nameof(PleaseSendMeCreate), Identifier);
            return;
        }

        Assert.ActualAssert(Entity is IEntity);
        ((IEntity)Entity).Update(Args);
    }
예제 #11
0
    public void MarkChunkLoaded(int X, int Z)     //Run on server by client after receiving all chunk load RPCs
    {
        if (!Net.Work.IsNetworkServer())
        {
            throw new Exception($"{nameof(MarkChunkLoaded)} was executed on a client");
        }

        int SenderId = Net.Work.GetRpcSenderId();

        Assert.ActualAssert(SenderId != 0);

        var ChunkTuple = new Tuple <int, int>(X, Z);

        RemoteLoadingChunks[SenderId].Remove(ChunkTuple);
        RemoteLoadedChunks[SenderId].Add(ChunkTuple);
    }
예제 #12
0
    private void ReceiveInventory(string Identifier, Items.ID[] Ids, int[] Counts)
    {
        Node Entity = World.EntitiesRoot.GetNodeOrNull(Identifier);

        if (Entity is null)
        {
            RpcId(Net.ServerId, nameof(PleaseSendMeCreate), Identifier);
            return;
        }

        Assert.ActualAssert(Entity is IEntity);
        if (Entity is IHasInventory HasInventory)
        {
            Assert.ActualAssert(Ids.Length == Counts.Length);
            Assert.ActualAssert(HasInventory.Inventory.Contents.Length == Ids.Length);

            int Index = 0;
            while (Index < Ids.Length)
            {
                if (Ids[Index] == Items.ID.NONE)
                {
                    HasInventory.Inventory.Contents[Index] = null;
                }
                else
                {
                    var Item = new Items.Instance(Ids[Index])
                    {
                        Count = Counts[Index]
                    };
                    HasInventory.Inventory.Contents[Index] = Item;
                }

                Index += 1;
            }
        }
        else
        {
            Console.ThrowLog("Received an inventory for an entity without an inventory");
        }
    }
예제 #13
0
    public void ServerExplode(Vector3 Position)
    {
        Assert.ActualAssert(Net.Work.IsNetworkServer());

        var WithinArea = World.GetEntitiesWithinArea(Position, MaxRocketDistance);

        foreach (Node Body in WithinArea)
        {
            if (Body is IPushable Pushable)
            {
                PhysicsDirectSpaceState      State   = GetWorld().DirectSpaceState;
                Godot.Collections.Dictionary Results = State.IntersectRay(Position, Pushable.Translation, new Godot.Collections.Array()
                {
                    Pushable
                }, 1);
                if (Results.Count > 0)
                {
                    continue;
                }

                Vector3 Push = CalculatePush(Pushable, Position);

                if (Pushable is Player Plr &&
                    Game.PossessedPlayer.HasValue &&
                    Plr != Game.PossessedPlayer.ValueOrFailure())
                {
                    continue;
                }

                Pushable.ApplyPush(Push);
                Entities.SendPush(Pushable, Push);
            }
        }

        ExplodeSoundVisual(Position);

        Entities.SendDestroy(Name, Position);
        QueueFree();
    }
예제 #14
0
    private void PleaseSendMeCreate(string Identifier)
    {
        if (!Net.Work.IsNetworkServer())
        {
            throw new Exception($"Cannot run {nameof(PleaseSendMeCreate)} on client");
        }

        int Requester = Net.Work.GetRpcSenderId();

        if (Requester == 0)
        {
            throw new Exception($"{nameof(PleaseSendMeCreate)} was run not as an RPC");
        }

        Node Entity = World.EntitiesRoot.GetNodeOrNull(Identifier);

        if (Entity is null)
        {
            return;
        }

        Assert.ActualAssert(Entity is IEntity);
        SendCreateTo(Requester, (IEntity)Entity);
    }
예제 #15
0
    public override void _Process(float Delta)
    {
        if (!Possessed)
        {
            NetUpdateDelta += Delta;
            return;
        }

        if (Dying)
        {
            return;
        }

        Assert.ActualAssert(MinAdsMultiplier > 0 && MinAdsMultiplier <= 1);
        AdsMultiplier =
            Ads
                                ? Clamp(AdsMultiplier - (Delta * (1 - MinAdsMultiplier) / AdsTime), MinAdsMultiplier, 1)
                                : Clamp(AdsMultiplier + (Delta * (1 - MinAdsMultiplier) / AdsTime), MinAdsMultiplier, 1);

        Cam.Fov = Game.Fov * AdsMultiplier;

        float Length = Clamp(ViewmodelMomentum.Length() - Delta * ViewmodelMomentumFriction, 0, 1);

        ViewmodelMomentum = ViewmodelMomentum.Normalized() * Length;

        ViewmodelItem.RotationDegrees = new Vector3(
            SafeSign(ViewmodelMomentum.y) * ViewmodelMomentum.y * ViewmodelMomentum.y * MaxViewmodelItemRotation * AdsMultiplier,
            180 - SafeSign(ViewmodelMomentum.x) * ViewmodelMomentum.x * ViewmodelMomentum.x * MaxViewmodelItemRotation * AdsMultiplier,
            0
            );
        ViewmodelArmJoint.RotationDegrees = new Vector3(
            -SafeSign(ViewmodelMomentum.y) * ViewmodelMomentum.y * ViewmodelMomentum.y * MaxViewmodelArmRotation * AdsMultiplier,
            -SafeSign(ViewmodelMomentum.x) * ViewmodelMomentum.x * ViewmodelMomentum.x * MaxViewmodelArmRotation * AdsMultiplier,
            0
            );
        ViewmodelArmJoint.Translation = new Vector3(
            NormalViewmodelArmX * ((AdsMultiplier - MinAdsMultiplier) * (1 / (1 - MinAdsMultiplier))),
            ViewmodelArmJoint.Translation.y,
            ViewmodelArmJoint.Translation.z
            );

        ApplyLookVertical(0);
        var ToRemove = new List <Hitscan.AdditiveRecoil>();

        foreach (Hitscan.AdditiveRecoil Instance in ActiveAdditiveRecoil)
        {
            Instance.Life += Delta;
            if (Instance.Life > Instance.Length)
            {
                ToRemove.Add(Instance);
            }
        }
        foreach (Hitscan.AdditiveRecoil Instance in ToRemove)
        {
            ActiveAdditiveRecoil.Remove(Instance);
        }

        if (Inventory[InventorySlot] != null)
        {
            Items.ID Id = Inventory[InventorySlot].Id;
            ViewmodelItem.Mesh = Items.Meshes[Id];

            ShaderMaterial Mat = new ShaderMaterial();
            Mat.Shader = Items.TileShader;
            Mat.SetShaderParam("texture_albedo", Items.Textures[Id]);
            ViewmodelItem.MaterialOverride = Mat;

            ViewmodelItem.Show();

            {
                Items.IdInfo Info = Items.IdInfos[Inventory[InventorySlot].Id];
                if (IsPrimaryFiring && CurrentCooldown >= CurrentMaxCooldown && Info.UseDelegate != null && Info.FullAuto)
                {
                    Items.UseItem(Inventory[InventorySlot], this);
                }
            }
        }
        else
        {
            ViewmodelItem.Hide();
        }
    }
예제 #16
0
 public void PhaseOut()
 {
     Assert.ActualAssert(!Possessed);
     Destroy();
 }
예제 #17
0
 public Option <int[]> ItemGive(Items.Instance ToGive)
 {
     Assert.ActualAssert(Net.Work.IsNetworkServer());
     return(Inventory.Give(ToGive));
 }
예제 #18
0
    public override void _Ready()
    {
        Cam = GetNode <Camera>("SteelCamera");

        ViewmodelItem = GetNode <MeshInstance>("SteelCamera/ViewmodelArmJoint/ViewmodelTiltJoint/ViewmodelItem");
        ViewmodelItem.RotationDegrees = new Vector3(0, 180, 0);
        ViewmodelItem.Hide();
        ViewmodelTiltJoint = GetNode <Position3D>("SteelCamera/ViewmodelArmJoint/ViewmodelTiltJoint");
        ViewmodelArmJoint  = GetNode <Position3D>("SteelCamera/ViewmodelArmJoint");
        ViewmodelArmJoint.RotationDegrees = new Vector3();
        NormalViewmodelArmX           = ViewmodelArmJoint.Translation.x;
        ViewmodelArmJoint.Translation = new Vector3(NormalViewmodelArmX, ViewmodelArmJoint.Translation.y, ViewmodelArmJoint.Translation.z);

        ProjectileEmitterHinge = GetNode <Spatial>("ProjectileEmitterHinge");
        ProjectileEmitter      = GetNode <Spatial>("ProjectileEmitterHinge/ProjectileEmitter");

        BodyCollision = GetNode <CollisionShape>("BodyCollision");
        BodyCapsule   = (CapsuleShape)BodyCollision.Shape;
        Assert.ActualAssert(BodyCapsule.Height == Height);

        if (Possessed)
        {
            Cam.MakeCurrent();
            GetNode <RayCast>("SteelCamera/RayCast").AddException(this);
            GetNode <Spatial>("BodyScene").Free();

            AddChild(HUDInstance);

            GhostInstance = (Ghost)GD.Load <PackedScene>("res://World/Ghost.tscn").Instance();
            GhostInstance.Hide();
            GetParent().CallDeferred("add_child", GhostInstance);

            SfxManager = GetNode <PlayerSfxManager>("PlayerSfxManager");
        }
        else
        {
            HeadJoint = GetNode("BodyScene").GetNode <Spatial>("HeadJoint");
            LegsJoint = GetNode("BodyScene").GetNode <Spatial>("LegsJoint");

            RightLegFlames = GetNode("BodyScene").GetNode <CPUParticles>("LegsJoint/RightLegFlames");
            LeftLegFlames  = GetNode("BodyScene").GetNode <CPUParticles>("LegsJoint/LeftLegFlames");

            ThirdPersonItem = GetNode("BodyScene").GetNode <MeshInstance>("ItemMesh");
            ShaderMaterial Mat = new ShaderMaterial();
            Mat.Shader = Items.TileShader;
            ThirdPersonItem.MaterialOverride = Mat;

            Spatial Body = GetNode <Spatial>("BodyScene");
            Body.GetNode <HitboxClass>("BodyHitbox").OwningPlayer           = this;
            Body.GetNode <HitboxClass>("HeadJoint/HeadHitbox").OwningPlayer = this;
            Body.GetNode <HitboxClass>("LegsJoint/LegsHitbox").OwningPlayer = this;

            World.AddEntityToChunk(this);
            return;
        }

        Reset();

        if (Net.Work.IsNetworkServer())
        {
            SetFreeze(false);
            GiveDefaultItems();
        }

        World.AddEntityToChunk(this);
    }
예제 #19
0
    public override void _Process(float Delta)     //NOTE: Only runs on server
    {
        Assert.ActualAssert(Net.Work.IsNetworkServer());

        TimeSinceUpdate += Delta;

        if (!DepreciatedCurrentChunkTuple.Equals(World.GetChunkTuple(Translation)))
        {
            World.Chunks[DepreciatedCurrentChunkTuple].Mobs.Remove(this);
            World.AddMobToChunk(this);
        }

        if (CurrentArea != GridClass.CalculateArea(Translation))
        {
            CurrentArea = GridClass.CalculateArea(Translation);
            World.Grid.QueueRemoveItem(this);
            World.Grid.AddItem(this);
        }

        UpdateFloor();
        CalcWants(Floor);

        if (OnFloor)
        {
            TargetPoint.Match(
                some: Target => {
                if (Target.Pos.Flattened().DistanceTo(Translation.Flattened()) <= 2)
                {
                    TargetPoint = PointData.None();
                }
                else
                {
                    //Apply push toward TargetPoint but don't go to fast
                    Momentum += ClampVec3(
                        Target.Pos.Flattened() - Translation.Flattened(),
                        Acceleration * Delta + Friction * Delta,
                        Acceleration * Delta + Friction * Delta
                        );
                    Vector3 Clamped = ClampVec3(Momentum.Flattened(), 0, TopSpeed);
                    Momentum.x      = Clamped.x;
                    Momentum.z      = Clamped.z;
                }
            },

                none: () => { }
                );

            //Friction
            Vector3 Horz = Momentum.Flattened();
            Horz       = Horz.Normalized() * Clamp(Horz.Length() - Friction * Delta, 0, TopSpeed);
            Momentum.x = Horz.x;
            Momentum.z = Horz.z;
        }
        else                                                                               //Not on floor
        {
            Momentum.y = Clamp(Momentum.y - Gravity * Delta, -MaxFallSpeed, MaxFallSpeed); //Apply gravity
        }
        var OriginalChunkTuple = World.GetChunkTuple(Translation);

        Momentum = Move(Momentum, Delta, 1, 60, TopSpeed);

        Entities.MovedTick(this, OriginalChunkTuple);

        Entities.AsServerMaybePhaseOut(this);
        Entities.SendUpdate(Name, Translation);
    }
예제 #20
0
    public static void SetupItems()
    {
        IdInfos = new Dictionary <ID, IdInfo>()
        {
            {
                ID.ERROR,

                new IdInfo {
                }
            },

            {
                ID.PLATFORM,

                new IdInfo {
                    PositionDelegate     = BuildingLogic.PlatformBuildPosition,
                    RotationDelegate     = BuildingLogic.PlatformBuildRotation,
                    UseDelegate          = null,
                    FullAuto             = false,
                    CanAds               = false,
                    DisallowedCollisions = new ID[] { ID.PLATFORM }
                }
            },

            {
                ID.WALL,

                new IdInfo {
                    PositionDelegate     = BuildingLogic.WallBuildPosition,
                    RotationDelegate     = BuildingLogic.WallBuildRotation,
                    UseDelegate          = null,
                    FullAuto             = false,
                    CanAds               = false,
                    DisallowedCollisions = new ID[] { ID.WALL, ID.TRIANGLE_WALL }
                }
            },

            {
                ID.SLOPE,

                new IdInfo {
                    PositionDelegate     = BuildingLogic.SlopeBuildPosition,
                    RotationDelegate     = BuildingLogic.SlopeBuildRotation,
                    UseDelegate          = null,
                    FullAuto             = false,
                    CanAds               = false,
                    DisallowedCollisions = new ID[] { ID.SLOPE, ID.PIPE, ID.PIPE_JOINT }
                }
            },

            {
                ID.TRIANGLE_WALL,

                new IdInfo {
                    PositionDelegate     = BuildingLogic.TriangleWallBuildPosition,
                    RotationDelegate     = BuildingLogic.TriangleWallBuildRotation,
                    UseDelegate          = null,
                    FullAuto             = false,
                    CanAds               = false,
                    DisallowedCollisions = new ID[] { ID.TRIANGLE_WALL, ID.WALL }
                }
            },

            {
                ID.PIPE,

                new IdInfo {
                    PositionDelegate     = BuildingLogic.PipeBuildPosition,
                    RotationDelegate     = BuildingLogic.PipeBuildRotation,
                    DisallowedCollisions = new ID[] { ID.SLOPE, ID.PIPE, ID.PIPE_JOINT }
                }
            },

            {
                ID.PIPE_JOINT,

                new IdInfo {
                    PositionDelegate     = BuildingLogic.PipeJointBuildPosition,
                    RotationDelegate     = BuildingLogic.PipeJointBuildRotation,
                    DisallowedCollisions = new ID[] { ID.SLOPE, ID.PIPE, ID.PIPE_JOINT }
                }
            },

            {
                ID.LOCKER,

                new IdInfo {
                    PositionDelegate     = BuildingLogic.LockerBuildPosition,
                    RotationDelegate     = BuildingLogic.LockerBuildRotation,
                    DisallowedCollisions = new ID[] { ID.LOCKER }
                }
            },

            {
                ID.ROCKET_JUMPER,

                new IdInfo {
                    UseDelegate = RocketJumper.Fire,
                    FullAuto    = false,
                    CanAds      = false
                }
            },

            {
                ID.THUNDERBOLT,

                new IdInfo {
                    UseDelegate = Thunderbolt.Fire,
                    FullAuto    = false,
                    CanAds      = true
                }
            },

            {
                ID.SCATTERSHOCK,

                new IdInfo {
                    UseDelegate = Scattershock.Fire,
                    FullAuto    = false,
                    CanAds      = true
                }
            },

            {
                ID.SWIFTSPARK,

                new IdInfo {
                    UseDelegate = SwiftSpark.Fire,
                    FullAuto    = true,
                    CanAds      = true
                }
            },

            {
                ID.SLIME_SPAWNER,

                new IdInfo {
                    UseDelegate = (Items.Instance Item, Player UsingPlayer) => {
                        Mobs.SpawnMob(Mobs.ID.Slime, UsingPlayer.Translation);
                    },
                    FullAuto = false,
                    CanAds   = false
                }
            }
        };

        //Lets make sure that every ID has an entry
        //This won't help mods but will help us greatly
        foreach (ID Type in System.Enum.GetValues(typeof(ID)))
        {
            if (Type == ID.NONE)
            {
                continue;
            }

            Assert.ActualAssert(IdInfos.ContainsKey(Type));
        }
    }
예제 #21
0
    public override void _Ready()
    {
        Assert.ActualAssert(GetParent() is PipeCoreLogic);

        Parent = GetParent() as PipeCoreLogic;
    }
예제 #22
0
    public override void DropData(Vector2 Pos, object Data)
    {
        if (Data is int FromSlot && ParentMenu.Source != null)
        {
            if (Source == ParentMenu.Source.Source && Slot == FromSlot)
            {
                return;                 //Same source and slot, we dropped on ourself
            }
            Items.Instance Moving = ParentMenu.Source.Source.Inventory[FromSlot];
            Assert.ActualAssert(Moving != null);
            if (Moving == null)
            {
                return;                            //Makes Roslyn happy
            }
            Items.Instance Original = Source.Inventory[Slot];

            int  RetrieveCount = ParentMenu.CalcRetrieveCount(Moving.Count);
            bool EmptyMoving   = RetrieveCount == Moving.Count; //If we are moving all, empty the the source slot

            if (Original == null)                               //Replace (no item at target)
            {
                if (Net.Work.IsNetworkServer())
                {
                    Source.NetUpdateInventorySlot(Slot, Moving.Id, RetrieveCount);
                    if (EmptyMoving)
                    {
                        ParentMenu.Source.Source.NetEmptyInventorySlot(FromSlot);
                    }
                    else
                    {
                        ParentMenu.Source.Source.NetUpdateInventorySlot(FromSlot, Moving.Id, Moving.Count - RetrieveCount);
                    }
                }
                else
                {
                    Source.RpcId(Net.ServerId, nameof(IHasInventory.NetUpdateInventorySlot), Slot, Moving.Id, RetrieveCount);
                    if (EmptyMoving)
                    {
                        ParentMenu.Source.Source.RpcId(Net.ServerId, nameof(IHasInventory.NetEmptyInventorySlot), FromSlot);
                    }
                    else
                    {
                        ParentMenu.Source.Source.RpcId(Net.ServerId, nameof(IHasInventory.NetUpdateInventorySlot), FromSlot, Moving.Id, Moving.Count - RetrieveCount);
                    }
                }
            }
            else
            {
                if (Moving.Id == Original.Id)                //Combine at target
                {
                    if (Net.Work.IsNetworkServer())
                    {
                        Source.NetUpdateInventorySlot(Slot, Original.Id, Original.Count + RetrieveCount);
                        if (EmptyMoving)
                        {
                            ParentMenu.Source.Source.NetEmptyInventorySlot(FromSlot);
                        }
                        else
                        {
                            ParentMenu.Source.Source.NetUpdateInventorySlot(FromSlot, Moving.Id, Moving.Count - RetrieveCount);
                        }
                    }
                    else
                    {
                        Source.RpcId(Net.ServerId, nameof(IHasInventory.NetUpdateInventorySlot), Slot, Original.Id, Original.Count + RetrieveCount);
                        if (EmptyMoving)
                        {
                            ParentMenu.Source.Source.RpcId(Net.ServerId, nameof(IHasInventory.NetEmptyInventorySlot), FromSlot);
                        }
                        else
                        {
                            ParentMenu.Source.Source.RpcId(Net.ServerId, nameof(IHasInventory.NetUpdateInventorySlot), FromSlot, Moving.Id, Moving.Count - RetrieveCount);
                        }
                    }
                }
                else if (RetrieveCount == Moving.Count)                //Swap, only if we are moving all from the source slot
                {
                    if (Net.Work.IsNetworkServer())
                    {
                        Source.NetUpdateInventorySlot(Slot, Moving.Id, Moving.Count);
                        ParentMenu.Source.Source.NetUpdateInventorySlot(FromSlot, Original.Id, Original.Count);
                    }
                    else
                    {
                        Source.RpcId(Net.ServerId, nameof(IHasInventory.NetUpdateInventorySlot), Slot, Moving.Id, Moving.Count);
                        ParentMenu.Source.Source.RpcId(Net.ServerId, nameof(IHasInventory.NetUpdateInventorySlot), FromSlot, Original.Id, Original.Count);
                    }
                }
            }
        }
    }