/// <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); } }
/// <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); } }
/// <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)); }
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); } } } }
/// <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()); }
/// <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)); }
/// <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); } }
/// <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); }
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)); } } }
/// <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)); } } }
/// <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); }
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)); } } }
/// <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; } } }
/// <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; } } }
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 }
/// <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)); }
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); }