예제 #1
0
        /// <summary>
        /// Changes the ship's area appropriately.
        /// Handles associated player if player.ActiveShipId == ship.Id
        /// Initiates a handoff, if the destination is a system and is non-local
        /// </summary>
        /// <param name="newAreaID"></param>
        /// <param name="ship"></param>
        /// <param name="isWarping"></param>
        /// <param name="databaseManager">Set to null if area is local</param>
        /// <param name="isDestinationSystem">True if newAreaID corresponds to a system. False otherwise.</param>
        public async Task ChangeArea(int newAreaID, IShip ship, bool isWarping, bool writeToDb = true)
        {
            Player p = ship.GetPlayer();

            if (!_areaLocator.IsLocalArea(newAreaID))
            {
                var nextArea = await _databaseManager.GetAreaAsync(newAreaID);

                if (nextArea == null)
                {
                    throw new InvalidOperationException("AreaID not found in database!");
                }

                await HandoffInitiateAreaChange(newAreaID, nextArea.AreaType, ship, ship.GetPlayer());

                return;
            }
            else
            {
                bool  isActiveShip = p.ActiveShipId == ship.Id;
                IArea currentArea  = _areaLocator.GetArea(ship.CurrentAreaId);
                IArea newArea      = _areaLocator.GetArea(newAreaID);

                MoveShipLocal(ship, newAreaID);
                if (isActiveShip)
                {
                    MovePlayerLocal(ship.GetPlayer(), newAreaID, isWarping);
                }

                if (writeToDb)
                {
                    var writeTasks = new List <Task>()
                    {
                        _databaseManager.SaveAsync(ship),
                        _databaseManager.SaveAsync(_areaLocator.GetArea(newAreaID))
                    };
                    if (isActiveShip)
                    {
                        writeTasks.Add(_databaseManager.SaveAsync(p));
                    }

                    if (currentArea != null)
                    {
                        writeTasks.Add(_databaseManager.SaveAsync(currentArea));
                    }

                    await Task.WhenAll(writeTasks);
                }

                ValidateState(ship, p, newArea, currentArea);
            }
        }
예제 #2
0
        /// <summary>
        /// Returns null if either ship is already trading.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        ShipShipTrade TryInitializeTrade(IShip a, IShip b)
        {
            lock (TRADELOCK)
            {
                if (_shipIDToTradeID.ContainsKey(a.Id))
                {
                    return(null);
                }
                if (_shipIDToTradeID.ContainsKey(b.Id))
                {
                    return(null);
                }

                Player aPlayer = a.GetPlayer();
                Player bPlayer = b.GetPlayer();

                if (!aPlayer.IsOnline || !bPlayer.IsOnline)
                {
                    return(null);
                }

                if (_tradingPlayerIDs.Contains(aPlayer.Id) || _tradingPlayerIDs.Contains(bPlayer.Id))
                {
                    return(null);
                }

                ShipShipTrade t = new ShipShipTrade(a, b, _tradeIDManager.PopFreeID(), DateTime.Now, (int)_slaveIDProvider.SlaveID, TimeKeeper.MsSinceInitialization);
                _shipShipTrades.TryAdd(t.Id, t);
                _tradingPlayerIDs.Add(aPlayer.Id);
                _tradingPlayerIDs.Add(bPlayer.Id);
                _shipIDToTradeID.TryAdd(a.Id, t.Id);
                _shipIDToTradeID.TryAdd(b.Id, t.Id);
                return(t);
            }
        }
예제 #3
0
        /// <summary>
        /// Changes IShip and notifies client.
        /// </summary>
        /// <param name="s">Ship of the player</param>
        /// <param name="shs">Ship to switch to</param>
        /// <param name="w">Weapon to switch to</param>
        public void ChangePlayersShip(IShip s, ShipStats shs)
        {
            s.ChangeShipType(shs);
            var data = s.GetNetworkData(false, false, false, true);

            s.GetPlayer().SendMessage(new NetworkMessageContainer(data, MessageTypes.ChangeShipType));
        }
예제 #4
0
        public void Update()
        {
            foreach (var kvp in _ships)
            {
                IShip s = kvp.Value;

                float oldHealth = s.CurrentHealth;
                s.Update();


                if (oldHealth != s.CurrentHealth && TimeKeeper.MsSinceInitialization - s.LastHealthUpdateTime >= s.HealthUpdatePeriod)
                {
                    var data = new MessageSetHealth();
                    data.HealthData.Add(new HealthData()
                    {
                        Health = (int)s.CurrentHealth, Shields = (int)s.Shields.CurrentShields, Energy = (int)s.CurrentEnergy
                    });

                    s.GetPlayer().SendMessage(new NetworkMessageContainer(data, MessageTypes.SetHealth));

                    s.LastHealthUpdateTime = TimeKeeper.MsSinceInitialization;
                }

                if (s.IsDead)
                {
                    if (TimeKeeper.MsSinceInitialization - s.KillTimeStamp > s.RespawnTimeDelay)
                    {
                        ReviveShip(s.Id, _areaLocator.GetArea(s.ReviveAreaID == null?_areaLocator.SolAreaID:s.ReviveAreaID), .2f, 0);
                    }
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Call this to begin changing area when handing off a local client.
        /// </summary>
        /// <param name="newArea"></param>
        /// <param name="ship"></param>
        /// <param name="isWarping"></param>
        async Task HandoffInitiateAreaChange(int destinationAreaID, AreaTypes newAreaType, IShip ship, Player warpingPlayer)
        {
            var shipSaveTask          = _databaseManager.SaveAsync(warpingPlayer);
            var playerSaveTask        = _databaseManager.SaveAsync(ship);
            var shipSaveHandoffTask   = _databaseManager.HandoffSaveAsync(ship);//If these collections aren't empty on server startup, a server crashed mid handoff and there could be ships/players which aren't stored in any area and might not be loaded.
            var playerSaveHandoffTask = _databaseManager.HandoffSaveAsync(warpingPlayer);

            //Ensure that db versions of ship and player are most recent, since they'll be loaded by slave
            List <Task> tasklist = new List <Task>
            {
                shipSaveTask,
                shipSaveHandoffTask,
                playerSaveTask,
                playerSaveHandoffTask,
            };

            await Task.WhenAll(tasklist);

            if (!(shipSaveTask.Result.IsAcknowledged && shipSaveHandoffTask.Result.IsAcknowledged && playerSaveTask.Result.IsAcknowledged && playerSaveHandoffTask.Result.IsAcknowledged))
            {
                throw new InvalidOperationException("Error: db write failed during handoff, handoff aborted.");
            }

            //Send handoff to be handled by server
            NetworkMessageContainer redismsg = new NetworkMessageContainer(new MessageClientHandoff((int)warpingPlayer.AccountID, (int)warpingPlayer.ActiveShipId, destinationAreaID, ((LidgrenOutgoingMessageService)warpingPlayer.MessageService).Connection.RemoteEndPoint.Address.GetAddressBytes()), MessageTypes.Redis_ClientHandoff);

            _redisServer.PublishObject(MessageTypes.Redis_ClientHandoff, redismsg);

            IArea currentArea = null;

            if (ship.CurrentAreaId != null)
            {
                currentArea = _areaLocator.GetArea((int)ship.CurrentAreaId);
            }

            OnAreaExit(ship, currentArea, newAreaType);

            currentArea.RemovePlayer(ship.GetPlayer()); //There doesn't seem to be a convenient way to avoid putting this here
            currentArea.RemoveShip(ship);               //Sends removeship Command to clients in area
            ConsoleManager.WriteLine("Initiated Handoff");
            ship.GetPlayer().IsHandedOff = true;

            _registrationManager.DeRegisterObject(warpingPlayer);
            _registrationManager.DeRegisterObject(ship);
            _accountManager.DeregisterAccount(warpingPlayer.GetAccount());
        }
예제 #6
0
        /// <summary>
        /// Sends a revive Command to the player owning IShip s
        /// </summary>
        /// <param name="s"></param>
        public void SendReviveMessage(IShip s, int health, int shields)
        {
            Player p = s.GetPlayer();

            var data = new MessageRemoveKillRevive();

            data.ActionType = ActionType.Revive;
            data.ObjectType = RemovableObjectTypes.Ship;
            data.ObjectIDs.Add(s.Id);
            p.SendMessage(new NetworkMessageContainer(data, MessageTypes.RemoveKillRevive));
        }
예제 #7
0
        /// <summary>
        /// Returns true if colonization succesful
        /// </summary>
        /// <param name="colonizingShip"></param>
        /// <param name="xPos">ref in case positions are modified to accomodate placement (e.g. snap to nearest tile)</param>
        /// <param name="yPos">ref in case positions are modified to accomodate placement (e.g. snap to nearest tile)</param>
        /// <returns></returns>
        public bool TryColonizePlanet(Planet planet, IShip colonizingShip, WarpManager wm, LocatorService ls, float xPos, float yPos, out string resultMessage, IDatabaseManager databaseManager)
        {
            if (planet.IsColonized)
            {
                resultMessage = "Planet is already colonized!";
                return(false);
            }
            else if (colonizingShip.CurrentEnergy != colonizingShip.ShipStats.Energy)//Is energy full?
            {
                resultMessage = "Not enough energy.";
                return(false);
            }
            else if (!planet.GetValidStructurePosition(new CommandCenterStats(), ref xPos, ref yPos))//Check for wall overlap here
            {
                resultMessage = "Invalid placement location.";
                return(false);
            }
            else if (colonizingShip.Cargo.GetCargoAmount(StatelessCargoTypes.Biodome) > 0)
            {//if everything checks out
                ColonyFactory.CreateColony(xPos, yPos, colonizingShip.GetPlayer(), planet, ls);

                List <IShip> ShipsToMove = new List <IShip>(1);
                //Kick all non-allied players into space
                foreach (var s in planet.GetShips())
                {
                    if (s.Value != colonizingShip)
                    {
                        if (s.Value is NPCShip && !_teamLocator.AreAllied(((NPCShip)s.Value), planet.GetOwner()))
                        {
                            ShipsToMove.Add(s.Value);
                        }
                        else if (s.Value is PlayerShip && !_teamLocator.AreAllied(s.Value.GetPlayer(), planet.GetOwner()))
                        {
                            ShipsToMove.Add(s.Value);
                        }
                    }
                }

                foreach (var s in ShipsToMove)
                {
                    wm.ChangeArea((int)planet.ParentAreaID, s, false, true);
                }
                resultMessage = "Colonization Successful.";
                return(true);
            }
            else
            {
                resultMessage = "No biodome found in ship cargo.";
                return(false);
            }
        }
예제 #8
0
 /// <summary>
 /// Safely moves the player and the specified ship to the specified area
 /// </summary>
 /// <param name="destinationArea"></param>
 /// <param name="player"></param>
 public static void DebugWarp(IArea destinationArea, Player player, IShip playerShip)
 {
     ConsoleManager.WriteLine("Warping player " + player.Username + " to " + destinationArea.AreaName, ConsoleMessageType.Debug);
     destinationArea.MovePlayerHere(player, false);
     try
     {
         playerShip.GetPlayer().SetArea(destinationArea);
     }
     catch (Exception e)
     {
         Console.WriteLine("fase");
     }
     destinationArea.MoveShipHere(playerShip);
     playerShip.SetArea(destinationArea);
 }
예제 #9
0
 public void NotifyCargoRemoved(object sender, ITransactionRemoveStatefulCargo transaction)
 {
     if (transaction.CargoHolder is IShip)
     {
         IShip  s = transaction.CargoHolder as IShip;
         Player p = s.GetPlayer();
         if (p.IsOnline)
         {
             var data = new MessageRemoveCargoFromShip {
                 ShipID = s.Id
             };
             data.StatefulCargoIDs.Add((int)transaction.CargoID);
             p.SendMessage(new NetworkMessageContainer(data, MessageTypes.RemoveCargoFromShip));
         }
     }
 }
예제 #10
0
        /// <summary>
        /// Notifies a player, if online, of a module added to his ship
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="transaction"></param>
        public void NotifyCargoAdded(object sender, ITransactionAddStatefulCargo transaction)
        {
            if (transaction.CargoHolder is IShip)
            {
                IShip  s = transaction.CargoHolder as IShip;
                Player p = s.GetPlayer();
                if (p.IsOnline)
                {
                    StatefulCargo         m    = transaction.CargoObject;
                    MessageAddCargoToShip data = new MessageAddCargoToShip();
                    data.ShipID = s.Id;
                    data.StatefulCargoData.Add(m.GetNetworkObject());

                    p.SendMessage(new NetworkMessageContainer(data, MessageTypes.AddCargoToShip));
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Revives a player and sends him to sendHere
        /// </summary>
        public IShip ReviveShip(IShip s, IArea sendHere, float healthMultiplier, float shieldsMultipler)
        {
            s.CurrentHealth = s.ShipStats.MaxHealth;
            s.IsDead        = false;
            _warpManager.ChangeArea(sendHere.Id, s, false, sendHere.AreaType == AreaTypes.System);

            if (!s.GetPlayer().IsOnline)
            {
                return(s);
            }

            var health  = (int)(s.MaxHealth * healthMultiplier);
            var shields = (int)(s.MaxShields * shieldsMultipler);

            _messageManager.SendReviveMessage(s, health, shields);

            return(s);
        }
예제 #12
0
        public void NotifyCargoAdded(object sender, ITransactionAddStatelessCargo transaction)
        {
            if (transaction.CargoHolder is IShip)
            {
                IShip  s = transaction.CargoHolder as IShip;
                Player p = s.GetPlayer();
                if (p.IsOnline)
                {
                    var data = new MessageAddCargoToShip();
                    data.ShipID = s.Id;
                    data.StatelessCargoData.Add(new StatelessCargoData {
                        CargoType = transaction.CargoType, Quantity = transaction.Quantity
                    });

                    p.SendMessage(new NetworkMessageContainer(data, MessageTypes.AddCargoToShip));
                }
            }
        }
예제 #13
0
        /// <summary>
        /// To be called just before a IShip warps
        /// </summary>
        /// <param name="s"></param>
        /// <param name="currentArea">The area the IShip is about to leave</param>
        /// <param name="newArea">The area the IShip is about to warp to</param>
        void OnAreaExit(IShip s, IArea currentArea, AreaTypes newArea)
        {
            if (currentArea == null)
            {
                return;
            }

            var player = s.GetPlayer();

            if (player.ActiveShipId == s.Id)
            {
                switch (currentArea.AreaType)
                {
                case AreaTypes.StarBase:
                case AreaTypes.Port:
                    switch (newArea)
                    {
                    case AreaTypes.StarBase:
                    case AreaTypes.Port:
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has entered a wormhole.");
                        break;

                    case AreaTypes.System:
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has undocked.");
                        break;
                    }
                    break;

                case AreaTypes.System:
                    switch (newArea)
                    {
                    case AreaTypes.StarBase:
                    case AreaTypes.Port:
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has docked at the port.");
                        break;

                    case AreaTypes.System:
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has warped out of the system.");
                        break;
                    }
                    break;
                }
            }
        }
예제 #14
0
        /// <summary>
        /// To be called just after a IShip warps
        /// </summary>
        /// <param name="s"></param>
        /// <param name="currentArea">The area that the IShip warped into</param>
        /// <param name="oldArea">The area that the IShip left</param>
        void OnAreaChange(IShip s, IArea currentArea, AreaTypes oldArea)
        {
            if (currentArea == null)
            {
                return;
            }

            var player = s.GetPlayer();

            if (player?.ActiveShipId == s.Id)
            {
                switch (currentArea.AreaType)
                {
                case AreaTypes.StarBase:
                case AreaTypes.Port:
                    switch (oldArea)
                    {
                    case AreaTypes.StarBase:
                    case AreaTypes.Port:         // How the heck will you ever get here? I dunno bro, just go with it.
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has gone through a wormhole.");
                        break;

                    case AreaTypes.System:
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has entered the port.");
                        break;
                    }
                    break;

                case AreaTypes.System:
                    switch (oldArea)
                    {
                    case AreaTypes.StarBase:
                    case AreaTypes.Port:
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has undocked from the port.");
                        break;

                    case AreaTypes.System:
                        _chatManager.BroadcastChatAlert(currentArea, player.Id, player.Username + " has warped into the system.");
                        break;
                    }
                    break;
                }
            }
        }
예제 #15
0
        public override void AddShip(IShip s, bool suspendNetworking)
        {
            _model.ShipIDs.Add(s.Id);
            _shipCache.Add(s.Id, s);

            #region Send RecieveNewShip message to all clients in new area

            if (_onlinePlayerIDs.Count >= 1 && !suspendNetworking)
            {
                var messageData = new MessageReceiveNewPortShip();
                messageData.Id       = s.Id;
                messageData.Username = s.GetPlayer().Username;
                messageData.PortID   = Id;

                BroadcastMessage(new NetworkMessageContainer(messageData, MessageTypes.ReceiveNewPortShip), s.PlayerID);
            }

            #endregion
        }
예제 #16
0
        /// <summary>
        /// Set debuffsToAdd to null if there are none to add
        /// </summary>
        /// <param name="s"></param>
        /// <param name="debuffsToAdd">Debuffs added since the last damage was sent</param>
        public void SendShipDamage(IShip s, Dictionary <DebuffTypes, int> debuffsToAdd = null)
        {
            MessageSetHealth data = new MessageSetHealth();
            HealthData       hd   = new HealthData()
            {
                ShipID = s.Id, Health = (int)s.CurrentHealth, Shields = (int)s.Shields.CurrentShields, Energy = (int)s.CurrentEnergy
            };

            if (debuffsToAdd != null)
            {
                foreach (var kvp in debuffsToAdd)
                {
                    hd.DebuffTypesToAdd.Add(kvp.Key);
                    hd.DebuffCountsToAdd.Add(kvp.Value);
                }
            }
            data.HealthData.Add(hd);

            s.GetPlayer().SendMessage(new NetworkMessageContainer(data, MessageTypes.SetHealth));
        }
예제 #17
0
        public IShip KillShip(IShip s, ICanFire killingObject)
        {
            if (s.IsDead)
            {
                ConsoleManager.WriteLine("Killing a ship which was already dead.", ConsoleMessageType.Warning);
                return(s);
            }


            s.IsDead           = true;
            s.KillTimeStamp    = TimeKeeper.MsSinceInitialization;
            s.RespawnTimeDelay = 3000;//TODO: This will be a problem later, if a IShip warps into a new system where a dead IShip is waiting to respawn, the warping IShip will see a live ship. Needs to be fully implemented.
            s.CurrentHealth    = 0;

            if (s.GetPlayer().IsTrading)
            {
                _tradeTerminator.TerminateTrade(s.Id, true);
            }

            var currentArea = s.GetArea();

            if (currentArea.NumOnlinePlayers > 0)
            {
                MessageRemoveKillRevive msgData = new MessageRemoveKillRevive();
                msgData.ActionType = ActionType.Kill;
                msgData.ObjectType = RemovableObjectTypes.Ship;
                msgData.ObjectIDs.Add(s.Id);

                currentArea.BroadcastMessage(new NetworkMessageContainer(msgData, MessageTypes.RemoveKillRevive));

                // Send chat messages
                if (killingObject is IShip)
                {
                    ((IShip)killingObject).GetPlayer().PlayersKilled++;
                    var killingPlayer = ((IShip)killingObject).GetPlayer();

                    killingPlayer.PlayersKilled++;

                    var killText = string.Format("{0} was shot down by {1}!", s.GetPlayer().Username, killingPlayer.Username);

                    _chatManager.BroadcastSimpleChat(s.GetArea(), "", killText, ChatTypes.None);
                }
                else if (killingObject is Turret)
                {
                    _playerLocator.GetPlayerAsync(((Turret)killingObject).OwnerID).Result.PlayersKilled++;

                    var killedPlayer = s.GetPlayer();

                    var defensesOwner = _playerLocator.GetPlayerAsync(((Turret)killingObject).OwnerID).Result.Username;

                    var killText = string.Format("{0} was shot down by defenses of {1}!", killedPlayer.Username, defensesOwner);

                    _chatManager.BroadcastSimpleChat(s.GetArea(), "", killText, ChatTypes.None);
                }
            }

            #region Modules
            //For now, just make the ship drop one mod to space. Later we'll figure out how many to destroy/keep with the ship
            var moduleToRemove = s.Cargo.GetAnyStatefulCargo(StatefulCargoTypes.Module);
            if (moduleToRemove != null)
            {
                var ct = new TransactionRemoveStatefulCargo(s, StatefulCargoTypes.Module, moduleToRemove.Id);
                ct.OnCompletion += s.CargoRemoved;
                ct.OnCompletion += _messageManager.NotifyCargoRemoved;
                ct.OnCompletion += _addCargoToArea;


                var mod = moduleToRemove as Module;
                mod.PosX       = s.PosX;
                mod.PosY       = s.PosY;
                mod.Rotation   = s.Rotation;
                mod.NextAreaID = (int)s.CurrentAreaId;

                _cargoSynchronizer.RequestTransaction(ct);
            }


            #endregion


            s.CurrentHealth = s.ShipStats.MaxHealth;
            //s.IsDead = false;
            float tempx = 0;
            float tempy = 0;
            SpatialOperations.GetRandomPointInRadius(ref tempx, ref tempy, 10, 20);

            s.PosX = tempx;
            s.PosY = tempy;


            return(s);
        }