private static void LoadBase(string fldatapath, string path, BaseData basedata, ILogController log) { try { var ini = new FLDataFile(path, true); foreach (FLDataFile.Section sec in ini.Sections) { string sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName == "baseinfo") { basedata.StartRoom = String.Format("{0:x}_{1}", basedata.BaseID, sec.GetSetting("start_room").Str(0)); basedata.StartRoomID = FLUtility.CreateID(basedata.StartRoom); } else if (sectionName == "room") { var room = new Room { Nickname = sec.GetSetting("nickname").Str(0).ToLowerInvariant() }; room.RoomID = FLUtility.CreateID(room.Nickname); path = fldatapath + Path.DirectorySeparatorChar + sec.GetSetting("file").Str(0); //I don't need room data at the moment. Yay. //TODO: make LoadRoom? //LoadRoom(fldatapath, path, basedata, room, log); basedata.Rooms[room.Nickname] = room; } } } catch (Exception e) { log.AddLog(LogType.ERROR, "error: '" + e.Message + "' when parsing '" + path); } }
//TODO: <s>use LoadRoom</s> private static void LoadRoom(string fldatapath, string path, BaseData basedata, Room room, ILogController log) { try { var ini = new FLDataFile(path, true); foreach (var sec in ini.Sections) { var sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName != "room_info") { continue; } if (!sec.SettingExists("set_script")) { continue; } var setScript = sec.GetSetting("set_script").Str(0); var thnText = File.ReadAllText(fldatapath + Path.DirectorySeparatorChar + setScript); var thn = new ThnParse(); thn.Parse(thnText); foreach (var e in thn.entities.Where(e => e.type.ToLowerInvariant() == "marker")) { //TODO: so what } } } catch (Exception e) { log.AddLog(LogType.ERROR, "error: '" + e.Message + "' when parsing '" + path); } }
/// <summary> /// Load base market data and setup the prices for goods at each base. /// </summary> /// <param name="path"></param> private static void LoadBaseMarketData(string path, ILogController log) { var ini = new FLDataFile(path, true); foreach (var sec in ini.Sections) { string sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName != "basegood") { continue; } var basedata = FindBase(sec.GetSetting("base").Str(0)); if (basedata == null) { log.AddLog(LogType.ERROR, "error: " + sec.Desc); continue; } foreach (FLDataFile.Setting set in sec.Settings) { var settingName = set.SettingName.ToLowerInvariant(); if (settingName != "marketgood") { continue; } var nickname = set.Str(0); var level_needed_to_buy = set.Float(1); var reputation_needed_to_buy = set.Float(2); var baseSells = (set.UInt(5) == 1); var basePriceMultiplier = 1.0f; if (set.NumValues() > 6) { basePriceMultiplier = set.Float(6); } var goodid = FLUtility.CreateID(nickname); var good = FindGood(goodid); if (good == null) { log.AddLog(LogType.ERROR, "error: " + set.Desc); continue; } if (baseSells) { basedata.GoodsForSale[goodid] = good.BasePrice * basePriceMultiplier; } basedata.GoodsToBuy[goodid] = good.BasePrice * basePriceMultiplier; } } }
/// <summary> /// Load shop information for equipment and commodities. /// </summary> /// <param name="path"></param> private static void LoadGoodData(string path, ILogController log) { var ini = new FLDataFile(path, true); foreach (FLDataFile.Section sec in ini.Sections) { var sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName != "good") { continue; } var good = new Good { Nickname = sec.GetSetting("nickname").Str(0) }; good.GoodID = FLUtility.CreateID(good.Nickname); string category = sec.GetSetting("category").Str(0); if (category == "equipment") { good.category = Good.Category.Equipment; good.BasePrice = sec.GetSetting("price").Float(0); uint archid = FLUtility.CreateID(sec.GetSetting("equipment").Str(0)); good.EquipmentOrShipArch = ArchetypeDB.Find(archid); } else if (category == "commodity") { good.category = Good.Category.Commodity; good.BasePrice = sec.GetSetting("price").Float(0); uint archid = FLUtility.CreateID(sec.GetSetting("equipment").Str(0)); good.EquipmentOrShipArch = ArchetypeDB.Find(archid); } else if (category == "shiphull") { good.category = Good.Category.ShipHull; good.BasePrice = sec.GetSetting("price").Float(0); uint archid = FLUtility.CreateID(sec.GetSetting("ship").Str(0)); good.EquipmentOrShipArch = ArchetypeDB.Find(archid); } else if (category == "ship") { good.category = Good.Category.ShipPackage; uint goodid = FLUtility.CreateID(sec.GetSetting("hull").Str(0)); good.Shiphull = Goods[goodid]; } else { log.AddLog(LogType.ERROR, "error: unknown category " + sec.Desc); } Goods[good.GoodID] = good; } }
// <summary> /// Load the factions from initial world. /// </summary> /// <param name="path"></param> private static void LoadFactions(string path, ILogController log) { var ini = new FLDataFile(path, true); foreach (FLDataFile.Section sec in ini.Sections) { string sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName == "group") { var faction = new Faction { Nickname = sec.GetSetting("nickname").Str(0) }; faction.FactionID = FLUtility.CreateFactionID(faction.Nickname); Factions[faction.Nickname] = faction; } } }
public static void Load(string flPath, ILogController log) { // Load the universe and systems and all other static data string flIniPath = flPath + Path.DirectorySeparatorChar + "EXE" + Path.DirectorySeparatorChar + "Freelancer.ini"; try { var flIni = new FLDataFile(flIniPath, true); string dataPath = Path.GetFullPath(Path.Combine(flPath + Path.DirectorySeparatorChar + "EXE", flIni.GetSetting("Freelancer", "data path").Str(0))); log.AddLog(LogType.GENERAL, "Loading loadouts"); foreach (var entry in flIni.GetSettings("Data", "loadouts")) { LoadLoadout(dataPath + Path.DirectorySeparatorChar + entry.Str(0), log); } log.AddLog(LogType.GENERAL, "Loading factions"); foreach (var entry in flIni.GetSettings("Data", "groups")) { LoadFactions(dataPath + Path.DirectorySeparatorChar + entry.Str(0), log); } log.AddLog(LogType.GENERAL, "Loading universe"); foreach (var entry in flIni.GetSettings("Data", "universe")) { LoadUniverse(dataPath + Path.DirectorySeparatorChar + entry.Str(0), log); } log.AddLog(LogType.GENERAL, "Loading goods"); foreach (var entry in flIni.GetSettings("Data", "goods")) { LoadGoodData(dataPath + Path.DirectorySeparatorChar + entry.Str(0), log); } log.AddLog(LogType.GENERAL, "Loading markets"); foreach (var entry in flIni.GetSettings("Data", "markets")) { LoadBaseMarketData(dataPath + Path.DirectorySeparatorChar + entry.Str(0), log); } } catch (Exception e) { log.AddLog(LogType.ERROR, "error: '" + e.Message + "' when parsing '" + flIniPath); } }
/// <summary> /// Load a single system /// </summary> /// <param name="path"></param> /// <param name="system"></param> /// <param name="log"></param> private static void LoadSystem(string path, StarSystem system, ILogController log) { try { var ini = new FLDataFile(path, true); foreach (FLDataFile.Section sec in ini.Sections) { string sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName == "zone") { var zone = new Zone { shape = null, nickname = sec.GetSetting("nickname").Str(0) }; zone.zoneid = FLUtility.CreateID(zone.nickname); Vector position = sec.GetSetting("pos").Vector(); var orientation = new Matrix(); double[] size = null; string shape = sec.GetSetting("shape").Str(0).ToLowerInvariant(); foreach (FLDataFile.Setting set in sec.Settings) { string settingName = set.SettingName.ToLowerInvariant(); switch (settingName) { case "rotation": orientation = Matrix.EulerDegToMatrix(set.Vector()); break; case "size": size = new double[set.NumValues()]; for (int a = 0; a < size.Length; a++) { size[a] = set.Float(a); } break; case "damage": zone.damage = set.Float(0); break; case "interference": zone.interference = set.Float(0); break; case "encounter": break; case "faction": break; case "density": zone.density = set.Float(0); break; } } if (size != null) { if (shape == "sphere" && size.Length == 1) { zone.shape = new Sphere(position, orientation, size[0]); } else if (shape == "cylinder" && size.Length == 2) { zone.shape = new Cylinder(position, orientation, size[0], size[1]); } else if (shape == "ellipsoid" && size.Length == 3) { zone.shape = new Ellipsoid(position, orientation, new Vector(size[0], size[1], size[2])); } else if (shape == "box" && size.Length == 3) { zone.shape = new Box(position, orientation, new Vector(size[0], size[1], size[2])); } else if (shape == "ring" && size.Length == 3) { zone.shape = new Ring(position, orientation, size[0], size[1], size[2]); } } system.Zones.Add(zone); } else if (sectionName == "object") { var solar = new Object.Solar.Solar(system, sec.GetSetting("nickname").Str(0)); if (sec.SettingExists("pos")) { solar.Position = sec.GetSetting("pos").Vector(); } if (sec.SettingExists("rotate")) { Vector euler = sec.GetSetting("rotate").Vector(); solar.Orientation = Matrix.EulerDegToMatrix(euler); } if (sec.SettingExists("base")) { // When a ship undocks, it undocks from the solar specified by baseid. // uint baseid = FLUtility.CreateID(sec.GetSetting("base").Str(0)); // FIXME: check base exists // solar.base_data = bases[baseid]; // bases[baseid].solar = solar; } if (sec.SettingExists("archetype")) { uint archetypeid = FLUtility.CreateID(sec.GetSetting("archetype").Str(0)); solar.Arch = ArchetypeDB.Find(archetypeid); solar.GetLoadout(); // FIXME: check archetype exists } if (sec.SettingExists("dock_with")) { uint baseid = FLUtility.CreateID(sec.GetSetting("dock_with").Str(0)); solar.BaseData = Bases[baseid]; } if (sec.SettingExists("goto")) { solar.DestinationObjid = FLUtility.CreateID(sec.GetSetting("goto").Str(1)); solar.DestinationSystemid = FLUtility.CreateID(sec.GetSetting("goto").Str(0)); } if (sec.SettingExists("prev_ring")) { solar.PrevRing = FLUtility.CreateID(sec.GetSetting("prev_ring").Str(0)); } if (sec.SettingExists("next_ring")) { solar.NextRing = FLUtility.CreateID(sec.GetSetting("next_ring").Str(0)); } if (sec.SettingExists("reputation")) { Faction faction = FindFaction(sec.GetSetting("reputation").Str(0)); if (faction == null) { log.AddLog(LogType.ERROR, "error: not valid faction={0}", sec.GetSetting("reputation").Str(0)); } else { solar.Faction = faction; } } // Rebuild the docking points from the archetype // to the solar position and rotation. foreach (DockingPoint dockingPoint in solar.Arch.DockingPoints) { var dockingObj = new DockingObject { Type = dockingPoint.Type, Solar = solar, Index = (uint)solar.Arch.DockingPoints.IndexOf(dockingPoint), DockingRadius = dockingPoint.DockingRadius, Position = solar.Orientation * dockingPoint.Position }; // rotate the hardpoint by the base orientation and then dockingObj.Position += solar.Position; // the ship launch rotation is the base rotation rotated by the hardpoint rotation dockingObj.Rotation = dockingPoint.Rotation * solar.Orientation; if (solar.BaseData != null) { solar.BaseData.LaunchObjs.Add(dockingObj); } solar.DockingObjs.Add(dockingObj); } // Store the solar. system.Solars[solar.Objid] = solar; Solars[solar.Objid] = solar; if (solar.Arch.Type == Archetype.ObjectType.JUMP_GATE || solar.Arch.Type == Archetype.ObjectType.JUMP_HOLE) { system.Gates.Add(solar); } } } } catch (Exception e) { log.AddLog(LogType.ERROR, "error: '" + e.Message + "' when parsing '" + path); if (e.InnerException != null) { log.AddLog(LogType.ERROR, "error: '" + e.InnerException.Message + "' when parsing '" + path); } } }
/// <summary> /// Load the universe /// </summary> /// <param name="path"></param> /// <param name="log"></param> private static void LoadUniverse(string path, ILogController log) { var universePath = Path.GetDirectoryName(path); var fldatapath = Directory.GetParent(universePath).FullName; var ini = new FLDataFile(path, true); foreach (FLDataFile.Section sec in ini.Sections) { string sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName == "system") { var system = new StarSystem { Nickname = sec.GetSetting("nickname").Str(0) }; system.SystemID = FLUtility.CreateID(system.Nickname); LoadSystem(universePath + Path.DirectorySeparatorChar + sec.GetSetting("file").Str(0), system, log); Systems[system.SystemID] = system; } else if (sectionName == "base") { var basedata = new BaseData { Nickname = sec.GetSetting("nickname").Str(0) }; basedata.BaseID = FLUtility.CreateID(basedata.Nickname); basedata.SystemID = FLUtility.CreateID(sec.GetSetting("system").Str(0)); LoadBase(fldatapath, fldatapath + Path.DirectorySeparatorChar + sec.GetSetting("file").Str(0), basedata, log); Bases[basedata.BaseID] = basedata; } } // FIXME: Might want to dump this information to disk foreach (var syspair1 in Systems) { var systemMinDist = new Dictionary <uint, PathData>(); var systemNext = new Dictionary <uint, PathData>(); foreach (var syspair2 in Systems) { systemMinDist.Add(syspair2.Key, syspair1.Key == syspair2.Key ? 0 : ((uint)Systems.Count + 1)); systemNext.Add(syspair2.Key, 0); } MinimumDistances.Add(syspair1.Key, systemMinDist); NextIndex.Add(syspair1.Key, systemNext); syspair1.Value.CalculatePathfinding(); } foreach (var syspair in Systems) { foreach (Object.Solar.Solar s in syspair.Value.Gates) { PathData pd = MinimumDistances[syspair.Key][s.DestinationSystemid]; if (s.Arch.Type == Archetype.ObjectType.JUMP_GATE) { pd.Shortest = pd.Legal = 1; } else { pd.Shortest = pd.Illegal = 1; } MinimumDistances[syspair.Key][s.DestinationSystemid] = pd; } } foreach (var k in Systems) { foreach (var i in Systems) { foreach (var j in Systems) { for (int x = -1; x <= 1; x++) { uint testDistance = MinimumDistances[i.Key][k.Key][x] + MinimumDistances[k.Key][j.Key][x]; if (testDistance < MinimumDistances[i.Key][j.Key][x]) { PathData min = MinimumDistances[i.Key][j.Key]; min[x] = testDistance; MinimumDistances[i.Key][j.Key] = min; PathData index = NextIndex[i.Key][j.Key]; index[x] = k.Key; NextIndex[i.Key][j.Key] = index; } } } } } }
private static void LoadLoadout(string path, ILogController log) { var ini = new FLDataFile(path, true); foreach (FLDataFile.Section sec in ini.Sections) { string sectionName = sec.SectionName.ToLowerInvariant(); if (sectionName == "loadout") { var loadout = new Loadout(); uint hpid = 34; foreach (FLDataFile.Setting set in sec.Settings) { if (set.SettingName == "nickname") { loadout.Nickname = set.Str(0); loadout.LoadoutID = FLUtility.CreateID(loadout.Nickname); } else if (set.SettingName == "equip") { var item = new ShipItem { arch = ArchetypeDB.Find(FLUtility.CreateID(set.Str(0))) }; if (item.arch == null) { continue; // TODO: log } item.hpname = ""; if (set.NumValues() > 1) { item.hpname = set.Str(1); } item.health = 1.0f; item.mission = false; item.mounted = true; item.count = 1; item.hpid = hpid++; loadout.Items.Add(item); } else if (set.SettingName == "cargo") { var item = new ShipItem { arch = ArchetypeDB.Find(FLUtility.CreateID(set.Str(0))) }; if (item.arch == null) { continue; // TODO: log } item.hpname = ""; item.health = 1.0f; item.mission = false; item.mounted = false; item.count = set.UInt(1); item.hpid = hpid++; loadout.Items.Add(item); } } Loadouts[loadout.LoadoutID] = loadout; } } }
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); } _dplay.GotMessage += _dplay_GotMessage; _dplay.PlayerConnected += _dplay_PlayerConnected; _dplay.PlayerDestroyed += _dplay_PlayerDestroyed; // 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; } }
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; } } }