void player_RunnerUpdate(Player.Player sender) { // A game thread has sent a notification to say that the player has changed - either // name, rank or system. We might change the assigned thread as a result. // In any case, we notify all game threads of the current name, rank and system. //var serverEvent = nextEvent as DPGameRunnerPlayerUpdateEvent; // Find runner for this system and if it's changed tell the old and new runners // of the change in ownership. var currRunner = sender.Runner; if (sender.Ship.System == null) { return; } var newRunner = _runners[sender.Ship.System]; if (newRunner == currRunner || newRunner == null) { return; } sender.Runner = newRunner; newRunner.LinkPlayer(sender); sender.Update(); // Notify all game threads of the current player info so they can update their // player lists. //foreach (var runner in _runners.Values) //runner.AddEvent(serverEvent); }
public string GetConnectionInformation(Player.Player player) { return(String.Format("ping={0} loss={1}/{2} rx/tx={3}/{4} tx_queue={5}", player.DPSess.Rtt, player.DPSess.LostRx, player.DPSess.LostTx, player.DPSess.BytesRx, player.DPSess.BytesTx, player.DPSess.UserData.Count + player.DPSess.UserDataPendingAck.Count )); }
public void EnterState(Player.Player player) { // Send a connection acknowledgement to inform the client of the flplayerid. { // FLPACKET_SERVER_CONNECTRESPONSE byte[] omsg = { 0x01, 0x02 }; FLMsgType.AddUInt32(ref omsg, player.FLPlayerID); player.SendMsgToClient(omsg); } Packets.SendMiscObjUpdate(player, Player.Player.MiscObjUpdateType.NEWS, player.Runner.Server.server_news); }
public DPGameRunnerPlayerUpdateEvent(Player.Player player) { this.player = player; runner = player.Runner; flplayerid = player.FLPlayerID; name = player.Name; rank = player.Ship.Rank; system = player.Ship.System; @group = player.Group; groupInvited = player.GroupInvited; }
void _dplay_PlayerConnected(object sender, Session e) { _log.AddLog(LogType.GENERAL, "Player created name={0}", e.Client); var defaultRunner = _runners.ElementAt(_rand.Next(_runners.Count - 1)).Value; var player = new Player.Player(e, _log, NewPlayerID(), defaultRunner); player.RunnerUpdate += player_RunnerUpdate; Players[e] = player; defaultRunner.LinkPlayer(player); player.Update(); }
/// <summary> /// For the specified player, check all simulation objects and spawn or destroy /// any objects in range of the player. /// </summary> /// <param name="player"></param> public void CheckMonitoredObjsList(Player.Player player) { foreach (var obj in Objects.Values) { CheckIfShouldCreateDestroyObject(player, obj); } // Remove any inactive sim objects from monitoring. var deleted_objs = new List <uint>(); foreach (var obj in player.MonitoredObjs.Values) { if (!Objects.ContainsKey(obj.Objid)) { deleted_objs.Add(obj.Objid); player.SendMsgToClient(BuildDestroyObj(obj, true)); } } foreach (uint objid in deleted_objs) { player.MonitoredObjs.Remove(objid); } }
public void RxMsgFromClient(Player.Player player, byte[] msg) { if (msg[0] == 0x01 && msg.Length == 1) { // Keepalive byte[] omsg = { 0xFF }; player.SendMsgToClient(omsg); } else if (msg[0] == 0x01 && msg.Length == 75) { // Save login information. int pos = 3; string accountid = FLMsgType.GetUnicodeStringLen16(msg, ref pos); //string accDirPath = player.Runner.Server.AcctPath + Path.DirectorySeparatorChar + // FLMsgType.FLNameToFile(accountid); // If the account directory does not exist, create it and save the account id file. //if (!Directory.Exists(accDirPath)) // Directory.CreateDirectory(accDirPath); //FLUtility.WriteAccountID(accDirPath, accountid); byte[] omsg = { 0x02, 0x02 }; // If the account is banned kick the player. var accs = Old.CharacterDB.Database.GetAccount(accountid); //TODO: check if banning works; possibly make separate table for ID bans bool isbanned = false; if (accs != null) { if (accs[0].IsBanned) { isbanned = true; } } //if (File.Exists(accDirPath + Path.DirectorySeparatorChar + "banned")) //{ // FLMsgType.AddUInt8(ref omsg, FLMsgType.MSG_TYPE_LOGIN_REPORT_TYPE_BANNED); //} // If the account is already logged in, reject the login // fixme: this is not thread safe //else if (isbanned) { FLMsgType.AddUInt8(ref omsg, FLMsgType.MSG_TYPE_LOGIN_REPORT_TYPE_BANNED); } else if (player.Runner.Server.FindPlayerByAccountID(accountid) != null) { FLMsgType.AddUInt8(ref omsg, FLMsgType.MSG_TYPE_LOGIN_REPORT_TYPE_INUSE); } else { FLMsgType.AddUInt8(ref omsg, FLMsgType.MSG_TYPE_LOGIN_REPORT_TYPE_OKAY); } player.AccountID = accountid; player.SendMsgToClient(omsg); } else if (msg[0] == 0x05 && msg[1] == 0x03) { // char info request player.SaveCharFile(); player.SetState(DPCSelectingCharacterState.Instance()); } else { // Unexpected packet. Log and ignore it. player.Log.AddLog(LogType.FL_MSG, "Unexpected message: client rx", player.DPSess, msg); } }
public void RxMsgFromClient(Player.Player player, byte[] msg) { if (msg[0] == 0x01 && msg.Length == 1) { // Keepalive byte[] omsg = { 0xFF }; player.SendMsgToClient(omsg); } else if (msg[0] == 0x05 && msg[1] == 0x03) { // FLPACKET_CLIENT_REQUESTCHARINFO player.Log.AddLog(LogType.FL_MSG, "FLPACKET_CLIENT_REQUESTCHARINFO"); Packets.SendCharInfoRequestResponse(player); } else if (msg[0] == 0x06 && msg[1] == 0x03) { // FLPACKET_CLIENT_SELECTCHARACTER var nameBefore = player.Name; var pos = 2; var charfilename = FLMsgType.GetAsciiStringLen16(msg, ref pos); var acct = Old.CharacterDB.Database.GetOneAccount(player.AccountID, charfilename); var result = player.LoadCharFile(acct, player.Log); if (result != null) { player.Log.AddLog(LogType.ERROR, "error: cannot load character accdir={0} charfile={1} reason={2}", acct.CharName, result); return; } player.Log.AddLog(LogType.GENERAL, "FLPACKET_CLIENT_SELECTCHARACTER charfilename={0} name={1} system={2}", charfilename, player.Name, player.Ship.System.Nickname); if (player.Ship != null && player.Ship.Objid != 0) { player.Runner.DelSimObject(player.Ship); } player.OnCharacterSelected(nameBefore == player.Name, nameBefore == null); player.Update(); } else if (msg[0] == 0x39 && msg[1] == 0x03) { player.Log.AddLog(LogType.FL_MSG, "FLPACKET_CLIENT_CREATENEWCHAR"); // New character int pos = 2; string charname = FLMsgType.GetUnicodeStringLen16(msg, ref pos); //TODO: do nothing when charname exists? if (Old.CharacterDB.Database.GetAccount(@"CharName", charname) != null) { return; } Old.CharacterDB.Database.AddAccount(player.AccountID, charname); //string charfile = player.Runner.Server.AcctPath + // Path.DirectorySeparatorChar + FLMsgType.FLNameToFile(player.AccountID) + // Path.DirectorySeparatorChar + FLMsgType.FLNameToFile(charname) + ".fl"; //if (!File.Exists(charfile)) //{ // var file = // new FLDataFile(player.Runner.Server.AcctPath + Path.DirectorySeparatorChar + "default.fl", true); // file.AddSetting("Player", "name", new object[] {FLUtility.EncodeUnicodeHex(charname)}); // file.SaveSettings(charfile, false); //} Packets.SendCharInfoRequestResponse(player); } else if (msg[0] == 0x3a && msg[1] == 0x03) { player.Log.AddLog(LogType.FL_MSG, "FLPACKET_CLIENT_DESTROYCHAR"); // Delete character var pos = 2; var charfile = FLMsgType.GetAsciiStringLen16(msg, ref pos); Old.CharacterDB.Database.DelAccount(player.AccountID, charfile); Packets.SendCharInfoRequestResponse(player); } else { // Unexpected packet. Log and ignore it. player.Log.AddLog(LogType.ERROR, "Unexpected message: client rx", player.DPSess, msg); } }
/// <summary> /// Send the current player list and list of characters this player /// has in their account. /// </summary> /// <param name="player"></param> public void EnterState(Player.Player player) { player.PlayerAccount = null; Packets.SendCharInfoRequestResponse(player); }
public void ThreadRun() { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try { _cfgFile = new FLDataFile("flopenserver.cfg", false); FLPath = _cfgFile.GetSetting("server", "fl_path").Str(0); AcctPath = _cfgFile.GetSetting("server", "acct_path").Str(0); if (AcctPath == "") { AcctPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\My Games\Freelancer\Accts\MultiPlayer"; } if (_cfgFile.SettingExists("server", "server_id")) { ServerID = _cfgFile.GetSetting("server", "server_id").Str(0); } if (_cfgFile.SettingExists("server", "version")) { server_version = _cfgFile.GetSetting("server", "version").Str(0); } if (server_version == "") { FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(FLPath + @"\EXE\Freelancer.exe"); var ver = new int[4]; ver[0] = myFileVersionInfo.FileMajorPart; ver[1] = myFileVersionInfo.FileMinorPart; ver[2] = myFileVersionInfo.FileBuildPart; ver[3] = myFileVersionInfo.FilePrivatePart; var sb = new StringBuilder(); foreach (var num in ver) { sb.Append("."); if (num < 10) { sb.Append("0"); } sb.Append(num); } server_version = sb.ToString().Substring(1); } ServerDescription = _cfgFile.GetSetting("server", "description").Str(0); server_news = _cfgFile.GetSetting("server", "news").Str(0); foreach (FLDataFile.Setting set in _cfgFile.GetSettings("intro_msg")) { IntroMsg += set.Line; } foreach (FLDataFile.Setting set in _cfgFile.GetSettings("banner_msg")) { BannerMsg += set.Line; } foreach (FLDataFile.Setting set in _cfgFile.GetSettings("user_help_msg")) { UserHelpMsg += set.Line; } foreach (FLDataFile.Setting set in _cfgFile.GetSettings("admin_help_msg")) { AdminHelpMsg += set.Line; } } catch (Exception e) { _log.AddLog(LogType.ERROR, "error: flopenserver.cfg not found or missing parameter " + e.Message); return; } string name = _cfgFile.GetSetting("server", "name").Str(0); uint port = _cfgFile.GetSetting("server", "port").UInt(0); var max_players = (int)_cfgFile.GetSetting("server", "max_players").UInt(0); if (ServerID == null) { ReadFLDefaults(); } _log.AddLog(LogType.GENERAL, "cfg_file = " + _cfgFile.FilePath); _log.AddLog(LogType.GENERAL, "fl_path = " + FLPath); _log.AddLog(LogType.GENERAL, "acct_path = " + AcctPath); _log.AddLog(LogType.GENERAL, "server_id = " + ServerID); _log.AddLog(LogType.GENERAL, "version = " + server_version); _log.AddLog(LogType.GENERAL, "name = " + name); _log.AddLog(LogType.GENERAL, "port = " + port); _log.AddLog(LogType.GENERAL, "max_players = " + max_players); ArchetypeDB.Load(FLPath, _log); UniverseDB.Load(FLPath, _log); News.Load(FLPath, _log); _log.AddLog(LogType.GENERAL, "Ready to start"); try { string[] arg = server_version.Split('.'); uint major = uint.Parse(arg[0]) & 0xFF; uint minor = uint.Parse(arg[1]) & 0xFF; uint patch = uint.Parse(arg[2]) & 0xFF; uint build = uint.Parse(arg[3]) & 0xFF; uint version = (major << 24) | (minor << 16) | (patch << 8) | build; server_version = version.ToString(CultureInfo.InvariantCulture); } catch { _log.AddLog(LogType.ERROR, "invalid server version string"); server_version = "0"; } // Try to start the direct play server. Complain if it fails but don't pass the exception on. try { _dplay = new DirectPlayServer(this, _log, (int)port) { server_name = name + "\0", server_id = ServerID, server_description = ServerDescription + "\0", server_version = server_version, max_players = (uint)max_players }; _log.AddLog(LogType.GENERAL, "Server started"); } catch (Exception e) { _log.AddLog(LogType.ERROR, "Cannot open socket reason={0}", e.Message); } // Kick off the game runner threads. We have one thread per system. New // players who have not selected a character are assigned to a random // runner thread. uint baseObjid = 1; foreach (var starSystem in UniverseDB.Systems.Values) { _runners[starSystem] = new DPGameRunner(this, _log, baseObjid, starSystem); baseObjid += 10000; } // Run the event/timer processing loop for this thread. var currentTime = Utilities.GetTime(); var running = true; while (running) { // Calculate the delta time. var delta = Utilities.GetTime() - currentTime; currentTime += delta; // Call the reactor to return the next event the process // and run any timer functions. var nextEvent = Run(currentTime, delta); if (nextEvent is DPSessionConnectedEvent) { // On receipt of a new connection, create a new player assigning it to a // random game thread. Notify all game threads of the new player. var serverEvent = nextEvent as DPSessionConnectedEvent; var defaultRunner = _runners.ElementAt(_rand.Next(_runners.Count - 1)).Value; var player = new Player.Player(serverEvent.dplayid, _log, NewPlayerID(), defaultRunner); Players[serverEvent.dplayid] = player; foreach (var runner in _runners.Values) { runner.AddEvent(new DPGameRunnerPlayerUpdateEvent(player)); } } else if (nextEvent is DPSessionTerminatedEvent) { // The session has died. Tell all game threads that it is dead and the player // is gone. // TODO: save player? var serverEvent = nextEvent as DPSessionTerminatedEvent; if (Players.ContainsKey(serverEvent.dplayid)) { var player = Players[serverEvent.dplayid]; Players.Remove(serverEvent.dplayid); foreach (var runner in _runners.Values) { runner.AddEvent(new DPGameRunnerPlayerDeletedEvent(player.FLPlayerID)); } } // Kill the dplay connection if it is not already dead try { /* fixme: dplay.DestroyClient(server_event.dplayid, null); */ } catch { } } else if (nextEvent is DPGameRunnerPlayerUpdateEvent) { // A game thread has sent a notification to say that the player has changed - either // name, rank or system. We might change the assigned thread as a result. // In any case, we notify all game threads of the current name, rank and system. var serverEvent = nextEvent as DPGameRunnerPlayerUpdateEvent; // Find runner for this system and if it's changed tell the old and new runners // of the change in ownership. var currRunner = serverEvent.runner; var newRunner = _runners[serverEvent.system]; if (newRunner != currRunner) { serverEvent.runner = newRunner; } // Notify all game threads of the current player info so they can update their // player lists. foreach (var runner in _runners.Values) { runner.AddEvent(serverEvent); } } else if (nextEvent is DPSessionRxMessageFromClient) { var server_event = nextEvent as DPSessionRxMessageFromClient; if (Players.ContainsKey(server_event.dplayid)) { Player.Player player = Players[server_event.dplayid]; player.Runner.AddEvent(new DPGameRunnerRxMsgEvent(player, server_event.msg)); } } else if (nextEvent is ReactorShutdownEvent) { foreach (DPGameRunner runner in _runners.Values) { runner.AddEvent(new ReactorShutdownEvent()); } running = false; } } }
/// <summary> /// For the specified player, check the single objects and spawn or destroy /// any objects in range of the player. /// </summary> /// <param name="player"></param> /// <param name="obj"></param> public void CheckIfShouldCreateDestroyObject(Player.Player player, SimObject obj) { // Ignore the player's own ship or an uninitialised ship if (player.Ship.Objid == obj.Objid || player.Ship.Objid == 0) { return; } if (obj is Object.Solar.Solar) { return; } var shouldMonitor = true; if (obj is Ship.Ship && (obj as Ship.Ship).Basedata != null) { shouldMonitor = false; } else if (player.Ship.Basedata != null) { shouldMonitor = false; } // TODO: use bucket? else if (!player.Ship.ScanBucket.Contains(obj)) { shouldMonitor = false; } if (shouldMonitor) { if (player.MonitoredObjs.ContainsKey(obj.Objid)) { return; } player.MonitoredObjs[obj.Objid] = obj; if (obj is Ship.Ship) { player.SendMsgToClient(BuildCreateShip(obj as Ship.Ship)); player.SendSetReputation(obj as Ship.Ship); } else if (obj is Missile) { player.SendMsgToClient(BuildCreateMissile(obj as Missile)); } else if (obj is CounterMeasure) { player.SendMsgToClient(BuildCreateCounterMeasure(obj as CounterMeasure)); } else if (obj is Loot) { player.SendCreateLoot(player.Ship, obj as Loot); } } else { if (!player.MonitoredObjs.ContainsKey(obj.Objid)) { return; } player.MonitoredObjs.Remove(obj.Objid); player.SendMsgToClient(BuildDestroyObj(obj, true)); } }
/// <summary> /// Send a dplay message to a client. /// </summary> /// <param name="player"></param> /// <param name="pkt"></param> public void SendMessage(Player.Player player, byte[] pkt) { Server.SendMessage(player.DPSess, pkt); }
public DPGRBeam(Player.Player player, BaseData target_base) { Player = player; TargetBase = target_base; }
public DPGRAddCash(Player.Player player, Int32 cash) { this.player = player; this.cash = cash; }
/// <summary> /// Start and run the simulation for this system. /// </summary> public void GameThreadRun() { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; CurrentTime = Utilities.GetTime(); AddTimer(new UpdateMonitoredObjs(this)); AddTimer(new SpawnBackgroundNPCs(this)); bool running = true; while (running) { // Calculate the delta time. double delta = Utilities.GetTime() - CurrentTime; CurrentTime += delta; // Call the reactor to return the next event the process // and run any timer functions. ReactorEvent next_event = Run(CurrentTime, delta); if (next_event is DPGameRunnerRxMsgEvent) { var revent = next_event as DPGameRunnerRxMsgEvent; // Process a message from this player. If the message isn't for this runner because // the runner ownership changes, requeue in the right place. if (revent.player.Runner != this) { Log.AddLog(LogType.FL_MSG, "Warning: requeued rx msg onto changed runner"); revent.player.Runner.AddEvent(revent); } else { revent.player.RxMsgFromClient(revent.msg); } } else if (next_event is DPGameRunnerPlayerUpdateEvent) { var revent = next_event as DPGameRunnerPlayerUpdateEvent; // If the player is assigned to this runner, make sure we've got it in our // owned player list Player.Player player = revent.player; if (revent.runner == this) { if (!Players.ContainsKey(player.FLPlayerID)) { Log.AddLog(LogType.GENERAL, "Player control gained runner={0} flplayerid={1}", system.Nickname, player.FLPlayerID); Players.Add(player.FLPlayerID, player); if (player.Ship.Objid != 0) { AffObjects[player.Ship.Objid] = player.Ship; } Objects[player.Ship.Objid] = player.Ship; player.Runner = this; player.Ship.Runner = this; AddTimer(player.Ship); } } // If the player is not assigned to this runner, make sure it's not in our // owned player list. else { if (Players.ContainsKey(player.FLPlayerID)) { Log.AddLog(LogType.GENERAL, "Player control lost runner={0} flplayerid={1}", system.Nickname, player.FLPlayerID); if (player.Ship.Objid != 0) { AffObjects.Remove(player.Ship.Objid); } Objects.Remove(player.Ship.Objid); DelTimer(player.Ship); Players.Remove(player.FLPlayerID); } } PlayerListItem update; update = !Playerlist.ContainsKey(revent.flplayerid) ? new PlayerListItem() : Playerlist[revent.flplayerid]; update.Player = revent.player; update.FlPlayerID = revent.flplayerid; update.Name = revent.name; update.Rank = revent.rank; update.System = revent.system; update.Group = revent.group; update.GroupInvited = revent.groupInvited; Playerlist[revent.flplayerid] = update; // Notify all owned players of the player list update foreach (Player.Player p in Players.Values) { p.SendPlayerListUpdate(update); } } else if (next_event is DPGameRunnerPlayerDeletedEvent) { var revent = next_event as DPGameRunnerPlayerDeletedEvent; // fixme: might crash if the player leaves if (!Players.ContainsKey(revent.FlPlayerID)) { continue; } var player = Players[revent.FlPlayerID]; Players.Remove(revent.FlPlayerID); if (player.Ship.Objid != 0) { DelSimObject(player.Ship); } if (Playerlist.ContainsKey(revent.FlPlayerID)) { Playerlist.Remove(revent.FlPlayerID); } foreach (PlayerListItem item in Playerlist.Values) { item.Player.SendPlayerListDepart(player); } } else if (next_event is ReactorShutdownEvent) { running = false; } else if (next_event is DPGRAddCash) { var revent = next_event as DPGRAddCash; if (revent.player.Runner != this) { Log.AddLog(LogType.FL_MSG, "Warning: requeued rx msg onto changed runner"); revent.player.Runner.AddEvent(revent); } else { revent.player.Money += revent.cash; revent.player.SendSetMoney(); } } else if (next_event is DPGRSetCash) { var revent = next_event as DPGRSetCash; if (revent.player.Runner != this) { Log.AddLog(LogType.FL_MSG, "Warning: requeued rx msg onto changed runner"); revent.player.Runner.AddEvent(revent); } else { revent.player.Money = revent.cash; revent.player.SendSetMoney(); } } else if (next_event is DPGRBeam) { var revent = next_event as DPGRBeam; if (revent.Player.Runner != this) { Log.AddLog(LogType.FL_MSG, "Warning: requeued rx msg onto changed runner"); revent.Player.Runner.AddEvent(revent); } else { revent.Player.MonitoredObjs.Clear(); revent.Player.Ship.Basedata = revent.TargetBase; revent.Player.Ship.RespawnBasedata = revent.TargetBase; revent.Player.Ship.System = UniverseDB.FindSystem(revent.TargetBase.SystemID); revent.Player.Ship.IsDestroyed = false; revent.Player.SendServerLand(revent.Player.Ship, 0, revent.Player.Ship.Basedata.BaseID); revent.Player.Runner.Server.AddEvent(new DPGameRunnerPlayerUpdateEvent(revent.Player)); } } } }
public DPGameRunnerRxMsgEvent(Player.Player player, byte[] msg) { this.player = player; this.msg = msg; }