コード例 #1
0
ファイル: ArchetypeDB.cs プロジェクト: Friendly0Fire/flos
        public MunitionArchetype(string datapath, FLDataFile.Section sec, ILogController log)
            : base(datapath, sec, log)
        {
            if (sec.SettingExists("hull_damage"))
            {
                HullDamage = sec.GetSetting("hull_damage").Float(0);
            }
            if (sec.SettingExists("energy_damage"))
            {
                EnergyDamage = sec.GetSetting("energy_damage").Float(0);
            }
            if (sec.SettingExists("weapon_type"))
            {
                WeaponType = ArchetypeDB.FindWeaponType(sec.GetSetting("weapon_type").Str(0));
                if (WeaponType == null)
                {
                    log.AddLog(LogType.ERROR, "error: weapon_type not found " + sec.Desc);
                }
            }
            if (sec.SettingExists("seeker"))
            {
                Seeker = sec.GetSetting("seeker").Str(0);
            }
            if (sec.SettingExists("time_to_lock"))
            {
                TimeToLock = sec.GetSetting("time_to_lock").Float(0);
            }
            if (sec.SettingExists("seeker_range"))
            {
                SeekerRange = sec.GetSetting("seeker_range").Float(0);
            }
            if (sec.SettingExists("seeker_fov_deg"))
            {
                SeekerFovDeg = sec.GetSetting("seeker_fov_deg").Float(0);
            }
            if (sec.SettingExists("detonation_dist"))
            {
                DetonationDist = sec.GetSetting("detonation_dist").Float(0);
            }
            if (sec.SettingExists("cruise_disruptor"))
            {
                CruiseDisruptor = sec.GetSetting("cruise_disruptor").Str(0) == "true";
            }
            if (sec.SettingExists("max_angular_velocity"))
            {
                MaxAngularVelocity = sec.GetSetting("max_angular_velocity").Float(0);
            }

            if (sec.SettingExists("motor"))
            {
                uint motorID = FLUtility.CreateID(sec.GetSetting("motor").Str(0));
                MotorArch = ArchetypeDB.Find(motorID) as MotorArchetype;
                if (MotorArch == null)
                {
                    log.AddLog(LogType.ERROR, "error: motor not found " + sec.Desc);
                }
            }
        }
コード例 #2
0
        /// <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;
                }
            }
        }
コード例 #3
0
ファイル: ArchetypeDB.cs プロジェクト: Friendly0Fire/flos
        public LauncherArchetype(string datapath, FLDataFile.Section sec, ILogController log)
            : base(datapath, sec, log)
        {
            if (sec.SettingExists("damage_per_fire"))
            {
                DamagePerFire = sec.GetSetting("damage_per_fire").Float(0);
            }
            if (sec.SettingExists("power_usage"))
            {
                PowerUsage = sec.GetSetting("power_usage").Float(0);
            }
            if (sec.SettingExists("refire_delay"))
            {
                RefireDelay = sec.GetSetting("refire_delay").Float(0);
            }

            if (sec.SettingExists("muzzle_velocity"))
            {
                MuzzleVelocity = new Vector(0, 0, -sec.GetSetting("muzzle_velocity").Float(0));
            }

            if (sec.SettingExists("projectile_archetype"))
            {
                uint projectileArchID = FLUtility.CreateID(sec.GetSetting("projectile_archetype").Str(0));
                ProjectileArch = ArchetypeDB.Find(projectileArchID) as ProjectileArchetype;
                if (ProjectileArch == null)
                {
                    log.AddLog(LogType.ERROR, "error: projectile not found: " + sec.Desc);
                }
            }
        }
コード例 #4
0
 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);
     }
 }
コード例 #5
0
        //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);
            }
        }
コード例 #6
0
 public void SetState(IPlayerState newstate)
 {
     if (_state != newstate)
     {
         Log.AddLog(LogType.GENERAL, "change state: old={0} new={1}", _state.StateName(), newstate.StateName());
         _state = newstate;
         _state.EnterState(this);
         if (_state.StateName() == "in-base-state")
         {
             Ship.IsDestroyed = false;
         }
     }
 }
コード例 #7
0
        /// <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;
            }
        }
コード例 #8
0
ファイル: News.cs プロジェクト: Friendly0Fire/flos
        public static void Load(string flPath, ILogController log)
        {
            string flIniPath = flPath + Path.DirectorySeparatorChar + "EXE" + Path.DirectorySeparatorChar +
                               "Freelancer.ini";

            try
            {
                var flIni    = new FLDataFile(flIniPath, true);
                var dataPath =
                    Path.GetFullPath(Path.Combine(flPath + Path.DirectorySeparatorChar + "EXE",
                                                  flIni.GetSetting("Freelancer", "data path").Str(0)));
                LoadMBaseFile(new FLDataFile(dataPath + "\\missions\\mbases.ini", true), log);
                LoadNewsFile(new FLDataFile(dataPath + "\\missions\\news.ini", true), log);
                LoadGenericScripts(new FLDataFile(dataPath + "\\scripts\\gcs\\genericscripts.ini", true), log);
            }
            catch (Exception e)
            {
                log.AddLog(LogType.ERROR, "error: '" + e.Message + "' when parsing '" + flIniPath);
            }
        }
コード例 #9
0
        private void AddDockingPoint(string type, string hpname, float dockingRadius,
                                     Dictionary <string, HardpointData> hardpoints, ILogController log)
        {
            if (!hardpoints.ContainsKey(hpname))
            {
                log.AddLog(LogType.ERROR, "error: hardpoint not found arch={0} hpname={1}", Nickname, hpname);
                return;
            }

            var dp = new DockingPoint
            {
                Type =
                    (DockingPoint.DockingSphere)
                    Enum.Parse(typeof(DockingPoint.DockingSphere), type.ToUpperInvariant()),
                HpName        = hpname,
                DockingRadius = dockingRadius,
                Position      = hardpoints[hpname].Position,
                Rotation      = hardpoints[hpname].Rotation
            };

            DockingPoints.Add(dp);
        }
コード例 #10
0
        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);
            }
        }
コード例 #11
0
        private static void Load(string datapath, string path, ILogController log)
        {
            var ini = new FLDataFile(path, true);

            // Load elements by dependency order; slower, but avoids issues with file ordering

            // Second order dependencies: motors
            foreach (FLDataFile.Section sec in ini.Sections)
            {
                try
                {
                    string sectionName = sec.SectionName.ToLowerInvariant();
                    if (sectionName == "motor")
                    {
                        AddArchetype(new MotorArchetype(datapath, sec, log));
                    }
                }
                catch (Exception ex)
                {
                    log.AddLog(LogType.ERROR, "ArchetypeDB load error: \"" + ex.Message + "\", item skipped");
                }
            }

            // First order dependencies: munitions
            foreach (var sec in ini.Sections)
            {
                try
                {
                    var sectionName = sec.SectionName.ToLowerInvariant();
                    switch (sectionName)
                    {
                    case "munition":
                        AddArchetype(new MunitionArchetype(datapath, sec, log));
                        break;

                    case "mine":
                        AddArchetype(new MineArchetype(datapath, sec, log));
                        break;

                    case "countermeasure":
                        AddArchetype(new CounterMeasureArchetype(datapath, sec, log));
                        break;
                    }
                }
                catch (Exception ex)
                {
                    log.AddLog(LogType.ERROR, "ArchetypeDB load error: \"" + ex.Message + "\", item skipped");
                }
            }

            // Zeroth order dependencies: everything else
            foreach (var sec in ini.Sections)
            {
                try
                {
                    var sectionName = sec.SectionName.ToLowerInvariant();


                    switch (sectionName)
                    {
                    case "ship":
                        AddArchetype(new ShipArchetype(datapath, sec, log));
                        break;

                    case "gun":
                        AddArchetype(new GunArchetype(datapath, sec, log));
                        break;

                    case "countermeasuredropper":
                        AddArchetype(new CounterMeasureDropperArchetype(datapath, sec, log));
                        break;

                    case "minedropper":
                        AddArchetype(new MineDropperArchetype(datapath, sec, log));
                        break;

                    case "shieldgenerator":
                        AddArchetype(new ShieldGeneratorArchetype(datapath, sec, log));
                        break;

                    case "power":
                        AddArchetype(new PowerArchetype(datapath, sec, log));
                        break;

                    case "armor":
                        AddArchetype(new ArmorArchetype(datapath, sec, log));
                        break;

                    case "thruster":
                        AddArchetype(new ThrusterArchetype(datapath, sec, log));
                        break;

                    case "engine":
                        AddArchetype(new EngineArchetype(datapath, sec, log));
                        break;

                    case "repairkit":
                        AddArchetype(new RepairKitArchetype(datapath, sec, log));
                        break;

                    case "shieldbattery":
                        AddArchetype(new ShieldBatteryArchetype(datapath, sec, log));
                        break;

                    case "scanner":
                        AddArchetype(new ScannerArchetype(datapath, sec, log));
                        break;

                    case "simple":
                    case "cloakingdevice":
                    case "tractor":
                    case "shield":
                    case "attachedfx":
                    case "internalfx":
                    case "tradelane":
                    case "commodity":
                    case "lootcrate":
                    case "cargopod":
                    case "light":
                    case "dynamicasteroid":
                    case "asteroidmine":
                    case "asteroid":
                    case "solar":
                        AddArchetype(new Archetype(datapath, sec, log));
                        break;
                    }
                }
                catch (Exception ex)
                {
                    log.AddLog(LogType.ERROR, "ArchetypeDB load error: \"" + ex.Message + "\", item skipped");
                }
            }
        }
コード例 #12
0
ファイル: News.cs プロジェクト: Friendly0Fire/flos
        private static void LoadNewsFile(FLDataFile ini, ILogController log)
        {
            foreach (FLDataFile.Section sec in ini.Sections)
            {
                string section_name = sec.SectionName.ToLowerInvariant();
                if (section_name == "newsitem")
                {
                    var item = new NewsItem
                    {
                        Category = sec.GetSetting("category").UInt(0),
                        Headline = sec.GetSetting("headline").UInt(0)
                    };

                    var icon = sec.GetSetting("icon").Str(0);
                    switch (icon)
                    {
                    case "critical":
                        item.Icon = 1;
                        break;

                    case "world":
                        item.Icon = 2;
                        break;

                    case "mission":
                        item.Icon = 3;
                        break;

                    case "system":
                        item.Icon = 4;
                        break;

                    case "faction":
                        item.Icon = 5;
                        break;

                    case "universe":
                        item.Icon = 6;
                        break;

                    default:
                        item.Icon = 0;
                        break;
                    }

                    item.Text  = sec.GetSetting("text").UInt(0);
                    item.Audio = sec.SettingExists("audio");
                    item.Logo  = sec.GetSetting("logo").Str(0);
                    foreach (var set in sec.Settings)
                    {
                        if (set.SettingName != "base")
                        {
                            continue;
                        }
                        var basename = set.Str(0);

                        var bd = UniverseDB.FindBase(basename);
                        if (bd == null)
                        {
                            log.AddLog(LogType.ERROR, "basename in news item not found, category={0} base={1}",
                                       item.Category, basename);
                        }
                        else
                        {
                            bd.News.Add(item);
                        }
                    }
                }
            }
        }
コード例 #13
0
ファイル: News.cs プロジェクト: Friendly0Fire/flos
        /// <summary>
        /// </summary>
        /// <param name="ini"></param>
        /// <param name="log"></param>
        /// First value is "minimum" mission difficulty. Second value is "maximum" mission difficulty.
        /// The server uses a funky formula for that, but preferably (and I've requested a hack applied
        /// to FLServer) it should just use those bare values. Third value is only used in the faction
        /// headers, and is the percentage chance for a mission for that faction to appear - the total
        /// of all mission lines of all factions for any given base should be 100.
        /// The difficulty then determines the payout and the various ships and solars that may appear.
        /// - Get as close to the max value of the difficulty by adding ships and solars in the waves
        /// in that mission, using the NPCRankToDiff.ini and MissionSolars.ini file for guidance
        /// - Then calculate the actual difficulty of the mission, and use the Diff2Money.ini file
        /// for calculating the mission payout. Then post the mission.
        private static void LoadMBaseFile(FLDataFile ini, ILogController log)
        {
            BaseData bd = null;

            foreach (var sec in ini.Sections)
            {
                string sectionName = sec.SectionName.ToLowerInvariant();
                if (sectionName == "mbase")
                {
                    string nickname = sec.GetSetting("nickname").Str(0);
                    bd = UniverseDB.FindBase(nickname);
                }
                else if (sectionName == "mvendor")
                {
                }
                else if (sectionName == "basefaction")
                {
                    var bf = new BaseFaction
                    {
                        Faction        = UniverseDB.FindFaction(sec.GetSetting("faction").Str(0)),
                        Weight         = sec.GetSetting("weight").Float(0),
                        OffersMissions = sec.SettingExists("offers_missions")
                    };

                    foreach (FLDataFile.Setting set in sec.Settings)
                    {
                        if (set.SettingName == "mission_type")
                        {
                            string mission_type = set.Str(0);
                        }
                        else if (set.SettingName == "npc")
                        {
                            string npcname = set.Str(0);
                        }
                    }
                }
                else if (sectionName == "gf_npc")
                {
                    var bc = new BaseCharacter {
                        Nickname = sec.GetSetting("nickname").Str(0).ToLowerInvariant()
                    };

                    if (sec.SettingExists("base_appr"))
                    {
                        // fixme
                        // var body;
                        // var head;
                        // var lefthead;
                        // var righthand;
                    }
                    else
                    {
                        bc.Body      = Utilities.CreateID(sec.GetSetting("body").Str(0));
                        bc.Head      = Utilities.CreateID(sec.GetSetting("head").Str(0));
                        bc.Lefthand  = Utilities.CreateID(sec.GetSetting("lefthand").Str(0));
                        bc.Righthand = Utilities.CreateID(sec.GetSetting("righthand").Str(0));
                    }

                    bc.IndividualName = sec.GetSetting("individual_name").UInt(0);
                    bc.Faction        = UniverseDB.FindFaction(sec.GetSetting("affiliation").Str(0));
                    bc.Voice          = Utilities.CreateID(sec.GetSetting("voice").Str(0));
                    if (sec.SettingExists("room"))
                    {
                        bc.Room   = String.Format("{0:x}_{1}", bd.BaseID, sec.GetSetting("room").Str(0));
                        bc.RoomID = Utilities.CreateID(bc.Room);
                    }

                    foreach (var set in sec.Settings)
                    {
                        if (set.SettingName == "bribe")
                        {
                            var bb = new BaseBribe
                            {
                                Faction = UniverseDB.FindFaction(set.Str(0)),
                                Cost    = set.UInt(1),
                                Text    = set.UInt(2)
                            };
                            bc.Bribes.Add(bb);
                        }
                        else if (set.SettingName == "rumor")
                        {
                            var br = new BaseRumor {
                                Text = set.UInt(3)
                            };
                            bc.Rumors.Add(br);
                        }
                    }

                    if (bd != null)
                    {
                        bd.Chars[bc.Nickname] = bc;
                    }
                    else
                    {
                        log.AddLog(LogType.ERROR, "Character {0} can't find base", bc.Nickname);
                    }
                }
                else if (sectionName == "mroom")
                {
                    string nickname = sec.GetSetting("nickname").Str(0).ToLowerInvariant();
                    if (sec.SettingExists("character_density"))
                    {
                        bd.Rooms[nickname].CharacterDensity = sec.GetSetting("character_density").UInt(0);
                    }

                    foreach (FLDataFile.Setting set in sec.Settings)
                    {
                        if (set.SettingName == "fixture")
                        {
                            string name          = set.Str(0).ToLowerInvariant();
                            string roomLocation  = set.Str(1);
                            string fidget_script = set.Str(2);
                            string type          = set.Str(3).ToLowerInvariant();

                            if (!bd.Chars.ContainsKey(name))
                            {
                                log.AddLog(LogType.ERROR, "character not found at {0}", set.Desc);
                                continue;
                            }

                            bd.Chars[name].Room         = String.Format("{0:x}_{1}", bd.BaseID, nickname);
                            bd.Chars[name].RoomID       = Utilities.CreateID(bd.Chars[name].Room);
                            bd.Chars[name].RoomLocation = roomLocation;
                            bd.Chars[name].FidgetScript = fidget_script;
                            bd.Chars[name].Type         = type;
                        }
                    }
                }
            }
        }
コード例 #14
0
ファイル: ArchetypeDB.cs プロジェクト: Friendly0Fire/flos
        /// <summary>
        ///     Load the architecture database.
        /// </summary>
        /// <param name="flPath"></param>
        /// <param name="log"></param>
        public static void Load(string flPath, ILogController log)
        {
            log.AddLog(LogType.GENERAL, "Loading archetypes");

            // 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, false);

                string dataPath =
                    Path.GetFullPath(Path.Combine(flPath + Path.DirectorySeparatorChar + "EXE",
                                                  flIni.GetSetting("Freelancer", "data path").Str(0)));
                foreach (FLDataFile.Setting entry in flIni.GetSettings("Data", "WeaponModDB"))
                {
                    LoadWeaponModDB(dataPath, dataPath + Path.DirectorySeparatorChar + entry.Str(0), log);
                }
                foreach (FLDataFile.Setting entry in flIni.GetSettings("Data", "solar"))
                {
                    Load(dataPath, dataPath + Path.DirectorySeparatorChar + entry.Str(0), log);
                }
                foreach (FLDataFile.Setting entry in flIni.GetSettings("Data", "debris"))
                {
                    Load(dataPath, dataPath + Path.DirectorySeparatorChar + entry.Str(0), log);
                }
                foreach (FLDataFile.Setting entry in flIni.GetSettings("Data", "asteroids"))
                {
                    Load(dataPath, dataPath + Path.DirectorySeparatorChar + entry.Str(0), log);
                }
                foreach (FLDataFile.Setting entry in flIni.GetSettings("Data", "equipment"))
                {
                    Load(dataPath, dataPath + Path.DirectorySeparatorChar + entry.Str(0), log);
                }
                foreach (FLDataFile.Setting entry in flIni.GetSettings("Data", "ships"))
                {
                    Load(dataPath, dataPath + Path.DirectorySeparatorChar + entry.Str(0), log);
                }
            }
            catch (Exception e)
            {
                log.AddLog(LogType.ERROR, "Error '" + e.Message + "' when parsing '" + flIniPath);
            }

            //Compare our archetype db to flserver's db generated by adoxa's packetdump.
            //List<uint> validids = new List<uint>();
            //byte[] x = File.ReadAllBytes(Properties.Settings.Default.FLPath + "\\EXE\\largeid.dat");
            //for (int i=0; i<x.Length; i+=4)
            //{
            //    uint id = BitConverter.ToUInt32(x, i);
            //    validids.Add(id);
            //}
            //for (int i = 0; i < validids.Count; i++)
            //{
            //    if (validids[i] != archetypes_by_small_id[i].archetypeid)
            //    {
            //        Archetype a1 = Find(validids[i]);
            //        Archetype a2 = archetypes_by_small_id[i];
            //        log.AddLog(String.Format("short id mismatch index={0} validid={1} {2} ourid={3} {4}", i, validids[i], a1.nickname,
            //            a2.archetypeid, a2.nickname));
            //    }
            //}
            //log.AddLog(String.Format("Archetypes loaded, large_count={0} small_count={1} valid_ids={2}", archetypes_by_large_id.Count, archetypes_by_small_id.Count, validids.Count));
        }
コード例 #15
0
ファイル: ArchetypeDB.cs プロジェクト: Friendly0Fire/flos
        public Archetype(string datapath, FLDataFile.Section sec, ILogController log)
        {
            Nickname    = sec.GetSetting("nickname").Str(0);
            ArchetypeID = FLUtility.CreateID(Nickname);

            // Load the hardpoints and animation data for the model
            Hardpoints = new Dictionary <string, HardpointData>();

            if (sec.SettingExists("loot_appearance"))
            {
                LootAppearance = sec.GetSetting("loot_appearance").Str(0);
            }
            if (sec.SettingExists("pod_appearance"))
            {
                PodAppearance = sec.GetSetting("loot_appearance").Str(0);
            }

            if (sec.SettingExists("DA_archetype"))
            {
                ModelPath = datapath + Path.DirectorySeparatorChar + sec.GetSetting("DA_archetype").Str(0);
                var      utf  = new UTFFile();
                TreeNode root = utf.LoadUTFFile(ModelPath);

                CmpFixData    fix;
                CmpRevData    rev;
                CmpPrisData   pris;
                CmpSphereData sphere;

                var file_to_object   = new Dictionary <string, string>();
                var cons_parent      = new Dictionary <string, string>();
                var cons_position    = new Dictionary <string, Vector>();
                var cons_orientation = new Dictionary <string, Matrix>();

                if (root.Nodes.ContainsKey("Cmpnd"))
                {
                    TreeNode cmpnd = root.Nodes["Cmpnd"];

                    foreach (TreeNode n in cmpnd.Nodes)
                    {
                        if (n.Name == "Cons")
                        {
                            TreeNode cons = n;
                            if (cons.Nodes.ContainsKey("Fix"))
                            {
                                TreeNode fixNode = cons.Nodes["Fix"];
                                try
                                {
                                    fix = new CmpFixData(fixNode.Tag as byte[]);
                                    foreach (CmpFixData.Part p in fix.Parts)
                                    {
                                        cons_parent[p.ChildName]   = p.ParentName;
                                        cons_position[p.ChildName] = new Vector(p.OriginX, p.OriginY, p.OriginZ);
                                        var m = new Matrix
                                        {
                                            M00 = p.RotMatXX,
                                            M01 = p.RotMatXY,
                                            M02 = p.RotMatXZ,
                                            M10 = p.RotMatYX,
                                            M11 = p.RotMatYY,
                                            M12 = p.RotMatYZ,
                                            M20 = p.RotMatZX,
                                            M21 = p.RotMatZY,
                                            M22 = p.RotMatZZ
                                        };

                                        cons_orientation[p.ChildName] = m;
                                    }
                                }
                                catch (Exception)
                                {
                                    fix = null;
                                }
                            }

                            if (cons.Nodes.ContainsKey("Pris"))
                            {
                                TreeNode prisNode = cons.Nodes["Pris"];
                                try
                                {
                                    pris = new CmpPrisData(prisNode.Tag as byte[]);
                                    foreach (CmpPrisData.Part p in pris.Parts)
                                    {
                                        cons_parent[p.ChildName]   = p.ParentName;
                                        cons_position[p.ChildName] = new Vector(p.OriginX, p.OriginY, p.OriginZ);
                                        var m = new Matrix
                                        {
                                            M00 = p.RotMatXX,
                                            M01 = p.RotMatXY,
                                            M02 = p.RotMatXZ,
                                            M10 = p.RotMatYX,
                                            M11 = p.RotMatYY,
                                            M12 = p.RotMatYZ,
                                            M20 = p.RotMatZX,
                                            M21 = p.RotMatZY,
                                            M22 = p.RotMatZZ
                                        };

                                        cons_orientation[p.ChildName] = m;
                                    }
                                }
                                catch (Exception)
                                {
                                    pris = null;
                                }
                            }

                            if (cons.Nodes.ContainsKey("Rev"))
                            {
                                TreeNode revNode = cons.Nodes["Rev"];
                                try
                                {
                                    rev = new CmpRevData(revNode.Tag as byte[]);
                                    foreach (CmpRevData.Part p in rev.Parts)
                                    {
                                        cons_parent[p.ChildName]   = p.ParentName;
                                        cons_position[p.ChildName] = new Vector(p.OriginX, p.OriginY, p.OriginZ);
                                        var m = new Matrix
                                        {
                                            M00 = p.RotMatXX,
                                            M01 = p.RotMatXY,
                                            M02 = p.RotMatXZ,
                                            M10 = p.RotMatYX,
                                            M11 = p.RotMatYY,
                                            M12 = p.RotMatYZ,
                                            M20 = p.RotMatZX,
                                            M21 = p.RotMatZY,
                                            M22 = p.RotMatZZ
                                        };

                                        cons_orientation[p.ChildName] = m;
                                    }
                                }
                                catch (Exception)
                                {
                                    rev = null;
                                }
                            }

                            if (cons.Nodes.ContainsKey("Sphere"))
                            {
                                TreeNode sphereNode = cons.Nodes["Sphere"];
                                try
                                {
                                    sphere = new CmpSphereData(sphereNode.Tag as byte[]);
                                    foreach (CmpSphereData.Part p in sphere.Parts)
                                    {
                                        cons_parent[p.ChildName]   = p.ParentName;
                                        cons_position[p.ChildName] = new Vector(p.OriginX, p.OriginY, p.OriginZ);
                                        var m = new Matrix
                                        {
                                            M00 = p.RotMatXX,
                                            M01 = p.RotMatXY,
                                            M02 = p.RotMatXZ,
                                            M10 = p.RotMatYX,
                                            M11 = p.RotMatYY,
                                            M12 = p.RotMatYZ,
                                            M20 = p.RotMatZX,
                                            M21 = p.RotMatZY,
                                            M22 = p.RotMatZZ
                                        };

                                        cons_orientation[p.ChildName] = m;
                                    }
                                }
                                catch (Exception)
                                {
                                    sphere = null;
                                }
                            }
                        }
                        else
                        {
                            if (n.Nodes.ContainsKey("Object name") && n.Nodes.ContainsKey("File name"))
                            {
                                file_to_object.Add(Utilities.GetString(n.Nodes["File name"]),
                                                   Utilities.GetString(n.Nodes["Object name"]));
                            }
                        }
                    }
                }

                foreach (TreeNode hp in utf.Hardpoints.Nodes)
                {
                    TreeNode   hpnode = null, parentnode = null;
                    TreeNode[] matches = root.Nodes.Find(hp.Name, true);

                    foreach (TreeNode m in matches)
                    {
                        hpnode     = m;
                        parentnode = hpnode.Parent.Parent.Parent;
                        if (file_to_object.ContainsKey(parentnode.Name))
                        {
                            break;
                        }
                    }

                    if (hpnode == null)
                    {
                        continue;
                    }

                    var hpd = new HardpointData(hpnode);

                    if (parentnode != root)
                    {
                        string consName = file_to_object[parentnode.Name];

                        var positionOffset = new Vector();
                        var rotationOffset = new Matrix();
                        while (consName.ToLowerInvariant() != "root")
                        {
                            positionOffset += cons_position[consName];
                            rotationOffset *= cons_orientation[consName];

                            consName = cons_parent[consName];
                        }

                        hpd.Position += positionOffset;
                        hpd.Rotation *= rotationOffset;
                    }

                    Hardpoints[hpd.Name.ToLowerInvariant()] = hpd;
                    if (hpd.Name.ToLowerInvariant() == "hpmount")
                    {
                        HpMount = hpd;
                    }
                }
            }

            if (ModelPath != null)
            {
                string surPath = Path.ChangeExtension(ModelPath, ".sur");
                if (File.Exists(surPath))
                {
                    try
                    {
                        new SurFile(surPath);
                    }
                    catch
                    {
                        log.AddLog(LogType.ERROR, "sur load failed for " + surPath);
                    }
                }
            }

            if (sec.SettingExists("mass"))
            {
                Mass = sec.GetSetting("mass").Float(0);
            }

            if (sec.SettingExists("hit_pts"))
            {
                HitPts = sec.GetSetting("hit_pts").Float(0);
            }

            if (sec.SettingExists("type"))
            {
                try
                {
                    Type =
                        (ObjectType)Enum.Parse(typeof(ObjectType), sec.GetSetting("type").Str(0).ToUpperInvariant());
                }
                catch (Exception)
                {
                    Type = ObjectType.NONE;
                }
            }

            // Load the docking points for the model
            foreach (FLDataFile.Setting set in sec.Settings)
            {
                if (set.SettingName == "docking_sphere")
                {
                    string moortype      = set.Str(0).ToLowerInvariant();
                    string hpname        = set.Str(1).ToLowerInvariant();
                    float  dockingRadius = set.Float(2);
                    AddDockingPoint(moortype, hpname, dockingRadius, Hardpoints, log);
                }
            }

            if (sec.SettingExists("loadout"))
            {
                Loadout = sec.GetSetting("loadout").Str(0);
            }

            // If this is a tradelane ring, load the docking points for it
            if (Type == ObjectType.TRADELANE_RING)
            {
                AddDockingPoint("tradelane_ring", "hpleftlane", 0, Hardpoints, log);
                AddDockingPoint("tradelane_ring", "hprightlane", 0, Hardpoints, log);
            }

            // FIXME: Load or build and surface used for collision detection for this model.
        }
コード例 #16
0
        /// <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);
                }
            }
        }
コード例 #17
0
        /// <summary>
        ///     Load the specified character file, resetting all character specific
        ///     content for this player and notifying all players of the name.
        /// </summary>
        /// <param name="account">Player account</param>
        /// <param name="log"></param>
        /// <returns>Returns null on successful load otherwise returns error message as a string.</returns>
        public string LoadCharFile(Account account, ILogController log)
        {
            if (account == null)
            {
                log.AddLog(LogType.ERROR, "Broken account found!");
                return("Account is null!");
            }
            //null checks made earlier
            // ReSharper disable once PossibleInvalidOperationException
            PlayerAccount = account;
            Wgrp          = new WeaponGroup();

// ReSharper disable once PossibleNullReferenceException
            Name  = PlayerAccount.CharName;
            Money = PlayerAccount.Money;

            var arch = ArchetypeDB.Find(PlayerAccount.Ship);

            if (arch is ShipArchetype)
            {
                Ship.Arch = arch;
            }
            else
            {
                return("invalid ship");
            }

            if (ShipState.RepGroup == "")
            {
                Ship.faction = new Faction();
            }
            else
            {
                Ship.faction = UniverseDB.FindFaction(ShipState.RepGroup);
                if (Ship.faction == null)
                {
                    return("invalid faction");
                }
            }

            Ship.System = UniverseDB.FindSystem(PlayerAccount.System);
            if (Ship.System == null)
            {
                return("invalid system");
            }

            if (ShipState.Base == null)
            {
                Ship.Basedata = null;
            }
            else
            {
                Ship.Basedata = UniverseDB.FindBase(ShipState.Base);
                if (Ship.Basedata == null)
                {
                    return("invalid base");
                }
            }

            if (ShipState.LastBase == "")
            {
                Ship.RespawnBasedata = null;
                return("no respawn base");
            }

            Ship.RespawnBasedata = UniverseDB.FindBase(ShipState.LastBase);
            if (Ship.RespawnBasedata == null)
            {
                return("invalid respawn base");
            }



            if (Ship.Basedata == null)
            {
                if (ShipState.Position != null)
                {
                    Ship.Position = ShipState.Position;
                }

                if (ShipState.Rotate != null)
                {
                    Ship.Orientation = Matrix.EulerDegToMatrix(ShipState.Rotate);
                }
            }

            //TODO: why ShipState.Hull is always true
            Ship.Health = ShipState.Hull;
            if (Ship.Health <= 0)
            {
                Ship.Health = 0.05f;
            }

            Ship.voiceid = FLUtility.CreateID(Appearance.Voice);

            //TODO: calculate rank
// ReSharper disable once PossibleNullReferenceException
            Ship.Rank = PlayerAccount.Rank;

            Ship.com_body      = Appearance.Body;
            Ship.com_head      = Appearance.Head;
            Ship.com_lefthand  = Appearance.LeftHand;
            Ship.com_righthand = Appearance.RightHand;

            Ship.Items.Clear();

            uint hpid = 34;

            foreach (var set in Equipment)
            {
                var si = new ShipItem
                {
                    arch    = ArchetypeDB.Find(set.Arch),
                    hpname  = set.HpName,
                    health  = set.Health,
                    count   = 1,
                    mission = false,
                    mounted = true,
                    hpid    = hpid++
                };
                Ship.Items[si.hpid] = si;
            }

            foreach (var set in Cargo)
            {
                var si = new ShipItem
                {
                    arch    = ArchetypeDB.Find(set.Arch),
                    hpname  = "",
                    count   = set.Count,
                    health  = 1.0f,
                    mission = false,
                    mounted = false,
                    hpid    = hpid++
                };
                Ship.Items[si.hpid] = si;
            }

            Ship.Reps.Clear();


            foreach (var set in RepDictionary)
            {
                float rep     = set.Value;
                var   faction = UniverseDB.FindFaction(set.Key);
                if (faction == null)
                {
// ReSharper disable once PossibleNullReferenceException
                    log.AddLog(LogType.ERROR, "error: faction not found char={0} faction={1}", account.CharName,
                               set.Value);
                }
                else
                {
                    Ship.Reps[faction] = rep;
                }
            }


            //Visits.Clear();
            //foreach (var set in Visits)
            //{
            //    Visits[set.Key] = set.Value;
            //}

            Ship.CurrentAction = null;

            return(null);
        }
コード例 #18
0
        /**
         * This function is called when a connection from a freelancer player is made to the server.
         */

        public void dps_PlayerCreated(Session session)
        {
            _log.AddLog(LogType.GENERAL, "Player created name={0}", session.Client);
            AddEvent(new DPSessionConnectedEvent(session));
        }
コード例 #19
0
        /// <summary>
        ///     Send a message to the dplay stack for transmission to a freelancer client.
        ///     Compress the message if it's longer than 80 bytes or so.
        /// </summary>
        /// <param name="dplayid"></param>
        /// <param name="msg"></param>
        public void SendMessage(Session session, byte[] msg)
        {
            if (msg[0] != 0xFF)
            {
                _log.AddLog(LogType.FL_MSG, "s>c client={0} tx={1}", session.Client, msg);
            }

            if (msg.Length > 0x50)
            {
                using (var ms = new MemoryStream())
                {
                    using (var zs = new ZlibStream(ms, CompressionMode.Compress))
                        zs.Write(msg, 0, msg.Length);
                    msg = ms.ToArray();
                }
            }

            _dplay.SendTo(session, msg);
        }
コード例 #20
0
        public void ProcessPktFromClient(byte[] pkt, IPEndPoint client)
        {
            _log.AddLog(LogType.DPLAY_MSG, "c>s client={0} pkt={1}", client, pkt);

            // If this message is too short, chuck it away
            if (pkt.Length < 2)
            {
                return;
            }

            // If this message is a enum server status then reply to the query. This tricks people
            // into thinking the server has a better ping than it does.
            int  pos = 0;
            uint cmd = FLMsgType.GetUInt8(pkt, ref pos);

            if (cmd == 0x00 && pkt.Length >= 4)
            {
                uint opcode = FLMsgType.GetUInt8(pkt, ref pos);
                if (opcode == 0x02 && pkt.Length >= 4)
                {
                    uint enum_payload = FLMsgType.GetUInt16(pkt, ref pos);
                    SendCmdEnumResponse(client, (ushort)enum_payload);
                }
            }

            // If the data is at least 12 bytes and the first byte is
            // either 0x80 or 0x88 (PACKET_COMMAND_CFRAME or PACKET_COMMAND_CFRAME |
            // PACKET_COMMAND_POLL), it MUST process the message as a CFRAME
            // (section 3.1.5.1) command frame.
            else if ((cmd == 0x80 || cmd == 0x88) && pkt.Length >= 12)
            {
                uint opcode = FLMsgType.GetUInt8(pkt, ref pos);

                // The CONNECT packet is used to request a connection. If accepted, the response
                // is a CONNECTED (section 2.2.1.2) packet
                if (opcode == 0x01)
                {
                    byte msg_id = FLMsgType.GetUInt8(pkt, ref pos);
                    byte rsp_id = FLMsgType.GetUInt8(pkt, ref pos);

                    uint version   = FLMsgType.GetUInt32(pkt, ref pos);
                    uint dplayid   = FLMsgType.GetUInt32(pkt, ref pos);
                    uint timestamp = FLMsgType.GetUInt32(pkt, ref pos);

                    // Create a new session.
                    Session sess = GetSession(client);
                    if (sess == null)
                    {
                        sess         = new Session(client);
                        sess.DPlayID = dplayid;
                        lock (_dplaySessions)
                        {
                            _dplaySessions[client] = sess;
                        }
                    }

                    lock (sess)
                    {
                        // If the session id has changed, assume that the server is wrong
                        // and kill the existing connection and start a new one.
                        // This behaviour differs from the dplay specification.
                        if (sess.DPlayID != 0 && sess.DPlayID != dplayid)
                        {
                            Destroy(sess, "changed dsessid");
                        }

                        // If the session is fully connected because the client has
                        // sent us a connect acknowledge then ignore this.
                        if (sess.SessionState == Session.State.CONNECTED)
                        {
                            return;
                        }

                        // Otherwise this is a new connection. Reset the session information.
                        sess.SessionState     = Session.State.CONNECTING;
                        sess.LastClientRxTime = DateTime.UtcNow;
                        sess.StartTime        = DateTime.Now;

                        sess.Rtt     = 200;
                        sess.LostRx  = 0;
                        sess.BytesRx = 0;
                        sess.LostTx  = 0;
                        sess.BytesTx = 0;

                        sess.NextRxSeq = 0;
                        sess.NextTxSeq = 0;

                        sess.MsgID = 0;
                        sess.OutOfOrder.Clear();
                        sess.UserData.Clear();
                        sess.UserDataPendingAck.Clear();

                        sess.MultipleDframePacket = false;
                        sess.SessionTimer         = new Timer(SessionTimer, sess, 100, 20);

                        SendCmdConnectAccept(sess, msg_id);
                    }
                }
                // Receive a SACK and process it
                else if (opcode == 0x06)
                {
                    byte flags = FLMsgType.GetUInt8(pkt, ref pos);
                    byte retry = FLMsgType.GetUInt8(pkt, ref pos);
                    // The seq field indicates the seq of the next message that the client will send.
                    byte seq = FLMsgType.GetUInt8(pkt, ref pos);
                    // The next_rx field indicates the message seq that the client is waiting to receive
                    byte nrcv = FLMsgType.GetUInt8(pkt, ref pos);
                    pos += 2; // skip padding
                    uint timestamp = FLMsgType.GetUInt32(pkt, ref pos);

                    // Ignore packets for sessions that don't exist
                    Session sess = GetSession(client);
                    if (sess == null)
                    {
                        return;
                    }

                    lock (sess)
                    {
                        sess.LastClientRxTime = DateTime.UtcNow;
                        sess.BytesRx         += pkt.Length;

                        // If the hi sack mask is present, resend any requested packets.
                        if ((flags & 0x02) == 0x02)
                        {
                            uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                            DoRetryOnSACKMask(sess, mask, nrcv);
                        }

                        // If the hi sack mask is present, resend any requested packets.
                        if ((flags & 0x04) == 0x04)
                        {
                            uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                            DoRetryOnSACKMask(sess, mask, (byte)(nrcv + 32));
                        }

                        // At this point bSeq sequence ID is valid, the bNRcv field
                        // is to be inspected. All previously sent TRANS_USERDATA_HEADER packets that
                        // are covered by the bNRcv sequence ID, that is, those packets that had been sent
                        // with bSeq values less than bNRcv (accounting for 8-bit counter wrapping) are
                        // acknowledged. These packets do not have to be remembered any longer, and their
                        // retry timers can be canceled.
                        DoAcknowledgeUserData(sess, nrcv);

                        // Try to send data if there's data waiting to be sent and send a
                        // selective acknowledgement if we didn't sent a dframe and the client
                        // requested an acknowledgement.
                        if (!SendDFrame(sess) && cmd == 0x88)
                        {
                            SendCmdSACK(sess);
                        }
                    }
                }
            }

            // If a packet arrives, the recipient SHOULD first check whether
            // it is large enough to be a minimal data frame (DFRAME) (4 bytes)
            // and whether the first byte has the low bit (PACKET_COMMAND_DATA) set.
            else if ((cmd & 0x01) == 0x01 && pkt.Length >= 4)
            {
                uint control = FLMsgType.GetUInt8(pkt, ref pos);
                byte seq     = FLMsgType.GetUInt8(pkt, ref pos);
                byte nrcv    = FLMsgType.GetUInt8(pkt, ref pos);

                // Ignore packets for sessions that don't exist
                Session sess = GetSession(client);
                if (sess == null)
                {
                    return;
                }

                lock (sess)
                {
                    sess.LastClientRxTime = DateTime.UtcNow;
                    sess.BytesRx         += pkt.Length;

                    // This is a disconnect. We ignore the soft disconnect and immediately
                    // drop the session repeating the disconnect a few times to improve the
                    // probability of it getting through.
                    if ((control & 0x08) == 0x08)
                    {
                        Destroy(sess, "client request");
                        return;
                    }

                    // TRANS_USERDATA_HEADER bSeq field MUST be either the next sequence
                    // ID expected or within 63 packets beyond the ID expected by the receiver.
                    // If the sequence ID is not within this range, the payload MUST be ignored.
                    // In addition, a SACK packet SHOULD be sent indicating the expected sequence ID.
                    if (!InWindow(seq, sess.NextRxSeq))
                    {
                        SendCmdSACK(sess);
                        return;
                    }

                    // If the sequence ID is out of order, but still within 63 packets,
                    // the receiver SHOULD queue the payload until it receives either:
                    // - A delayed or retried transmission of the missing packet or packets,
                    // and can now process the sequence in order.
                    // - A subsequent packet with a send mask indicating that the missing
                    // packet or packets did not use PACKET_COMMAND_RELIABLE and will never
                    // be retried. Therefore, the receiver should advance its sequence as if
                    // it had already received and processed the packets.
                    if (seq != sess.NextRxSeq)
                    {
                        _log.AddLog(LogType.DPLAY_MSG,
                                    "c>s out of order pkt received client={0} queuing seq={1:X} next_rx_seq={2:X}",
                                    sess.Client, seq, sess.NextRxSeq);
                        sess.OutOfOrder[seq] = pkt;
                        SendCmdSACK(sess);
                        return;
                    }

                    //Test code to simulate packet loss
                    //if (rand.Next(5) == 1)
                    //{
                    //    log.AddLog(String.Format("c>s: DROPPING THE PACKET NOW {0:X}", seq));
                    //    return;
                    //}

                    // Note if this was a retried dframe.
                    if ((control & 0x01) == 0x01)
                    {
                        sess.LostRx++;
                    }

                    // When one or both of the optional SACK mask 32-bit fields is present, and one
                    // or more bits are set in the fields, the sender is indicating that it received a
                    // packet or packets out of order, presumably due to packet loss. The two 32-bit,
                    // little-endian fields MUST be considered as one 64-bit field, where dwSACKMask1
                    // is the low 32 bits and dwSACKMask2 is the high 32 bits. If either 32-bit field
                    // is not available, the entire contents of the 64-bit field MUST be considered as all 0.

                    // The receiver of a SACK mask SHOULD loop through each bit of the combined 64-bit value
                    // in the ascending order of significance. Each bit corresponds to a sequence ID after
                    // bNRcv. If the bit is set, it indicates that the corresponding packet was received
                    // out of order.

                    // The receiver of a SACK mask SHOULD shorten the retry timer for the first frame of
                    // the window to speed recovery from the packet loss. The recommended duration is
                    // 10 milliseconds. This value can be modified according to application and network
                    // requirements. The receiver MAY also choose to remove the selectively acknowledged
                    // packets from its list to retry.
                    if ((control & 0x10) == 0x10)
                    {
                        uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                        DoRetryOnSACKMask(sess, mask, nrcv);
                    }
                    if ((control & 0x20) == 0x20)
                    {
                        uint mask = FLMsgType.GetUInt32(pkt, ref pos);
                        DoRetryOnSACKMask(sess, mask, (byte)(nrcv + 32));
                    }


                    // When one or both of the optional send mask 32-bit fields is present, and one or
                    // more bits are set the fields, the sender is indicating that it sent a packet or
                    // packets that were not marked as reliable and did not receive an acknowledgement yet.
                    // The two 32-bit, little-endian fields MUST be considered as one 64-bit field, where
                    // dwSendMask1 is the low 32 bits and dwSendMask2 is the high 32 bits. If either 32-bit
                    // field is not available, the entire contents of the 64-bit field MUST be considered
                    // as all 0.

                    // The receiver of a send mask SHOULD loop through each bit of the combined 64-bit
                    // value from the least significant bit to the most significant in little-endian byte
                    // order. Each bit corresponds to a sequence ID prior to bSeq, and if that is the bit
                    // that is set, it indicates that the corresponding packet was not sent reliably and
                    // will not be retried. If the recipient of the send mask had not received the packet
                    // and had not already processed a send mask that identified the sequence ID, it SHOULD
                    // consider the packet as dropped and release its placeholder in the sequence. That is,
                    // any sequential messages that could not be indicated because of the gap in the sequence
                    // where the packet that was not marked as reliable had been SHOULD now be reported to
                    // the upper layer.
                    if ((control & 0x40) == 0x40)
                    {
                        FLMsgType.GetUInt32(pkt, ref pos);
                    }
                    if ((control & 0x80) == 0x80)
                    {
                        FLMsgType.GetUInt32(pkt, ref pos);
                    }
                    // However, freelancer always uses reliable packets and so ignore sendmasks.

                    // At this point, we've received the packet we wanted to. Advance the sequence number count
                    // and process this message.
                    sess.NextRxSeq++;
                    ProcessTransUserData(sess, pkt, pos);

                    // If there are queued out of order packets, try to process these.
                    while (sess.OutOfOrder.ContainsKey(sess.NextRxSeq))
                    {
                        _log.AddLog(LogType.DPLAY_MSG, "c>s unqueuing out of order pkt client={0} seq={1:X}",
                                    sess.Client,
                                    sess.NextRxSeq);
                        pkt = sess.OutOfOrder[sess.NextRxSeq];
                        sess.OutOfOrder.Remove(sess.NextRxSeq);
                        sess.NextRxSeq++;
                        ProcessTransUserData(sess, pkt, pos); // fixme: pos could be wrong if we received a sack mask
                    }

                    // At this point bSeq sequence ID is valid, the bNRcv field
                    // is to be inspected. All previously sent TRANS_USERDATA_HEADER packets that
                    // are covered by the bNRcv sequence ID, that is, those packets that had been sent
                    // with bSeq values less than bNRcv (accounting for 8-bit counter wrapping) are
                    // acknowledged. These packets do not have to be remembered any longer, and their
                    // retry timers can be canceled.
                    DoAcknowledgeUserData(sess, nrcv);

                    // We always do an immediate acknowledge as bandwidth isn't a particular concern
                    // but fast recovery from lost packets is.
                    if (!SendDFrame(sess))
                    {
                        SendCmdSACK(sess);
                    }
                }
            }
        }