/// <summary>
        /// Saves the database.
        /// </summary>
        /// <param name="progress">The progress object.</param>
        /// <param name="eraseCommands">if set to <c>true</c> [erase commands].</param>
        public virtual void Save(IProgress progress, bool eraseCommands)
        {
            string     dbPath     = Path.GetDirectoryName(ProjectConfiguration.DatabasePath);
            string     subPath    = ProjectConfiguration.DatabasePath.Replace(dbPath + "\\", "");
            ServerType serverType = AllLoaders.GetServerType();

            try {
                BackupEngine.Instance.Start(SdeFiles.ServerDbPath);
                var dbs = _dbs.Values.ToList();

                for (int i = 0; i < dbs.Count; i++)
                {
                    var db = dbs[i];
                    db.WriteDb(dbPath, subPath, serverType);
                    progress.Progress = AProgress.LimitProgress((i + 1f) / dbs.Count * 100f);
                }

                if (eraseCommands)
                {
                    AllLoaders.UpdateStoredFiles();
                    Commands.ClearCommands();
                    _dbs.Values.ToList().ForEach(p => p.ClearCommands());
                    _dbs.Values.ToList().ForEach(p => p.BaseTable.ClearTupleStates());
                }
            }
            catch (Exception err) {
                ErrorHandler.HandleException(err);
            }
            finally {
                BackupEngine.Instance.Stop();
            }
        }
Beispiel #2
0
        public static void ItemGroupCopyEntries(List <ReadableTuple <int> > items, BaseDb gdb, TabControl control, ServerType serverType)
        {
            var parent = WpfUtilities.FindDirectParentControl <SdeEditor>(control);

            parent.AsyncOperation.SetAndRunOperation(new GrfThread(delegate {
                items = items.OrderBy(p => p.GetKey <int>()).ToList();

                StringBuilder builder = new StringBuilder();

                try {
                    AProgress.Init(parent);
                    DbLoaderErrorHandler.Start();

                    var dbItems = gdb.GetMeta <int>(ServerDbs.Items);

                    List <string> aegisNames = dbItems.FastItems.Select(p => p.GetStringValue(ServerItemAttributes.AegisName.Index)).ToList();
                    List <string> names      = dbItems.FastItems.Select(p => p.GetStringValue(ServerItemAttributes.Name.Index)).ToList();

                    for (int i = 0; i < items.Count; i++)
                    {
                        AProgress.IsCancelling(parent);
                        DbWriterMethods.DbItemGroupWriter2(items[i], serverType, builder, gdb, aegisNames, names);
                        parent.Progress = (i + 1f) / items.Count * 100f;
                    }
                }
                catch (OperationCanceledException) { }
                finally {
                    AProgress.Finalize(parent);
                    DbLoaderErrorHandler.Stop();
                }

                Clipboard.SetText(builder.ToString());
            }, parent, 200, null, true, true));
        }
Beispiel #3
0
        /// <summary>
        /// Reloads the database.
        /// </summary>
        /// <param name="progress">The progress object.</param>
        public void Reload(IProgress progress)
        {
            DbDebugHelper.OnUpdate("Reloading database...");
            OnPreviewReloaded();

            try {
                IOHelper.SetupFileManager();
                Commands.ClearCommands();
                DbPathLocator.ClearStoredFiles();
                ResetAllSettings();

                var dbs = _dbs.Values.ToList();

                for (int i = 0; i < dbs.Count; i++)
                {
                    dbs[i].Clear();
                    DbDebugHelper.OnCleared(dbs[i].DbSource, null, dbs[i]);
                }

                DbDebugHelper.OnUpdate("All database tables have been cleared.");

                for (int i = 0; i < dbs.Count; i++)
                {
                    var db = dbs[i];

                    if (db.CanBeLoaded)
                    {
                        CLHelper.CStart(i);

                        db.LoadDb();

                        if (progress != null)
                        {
                            progress.Progress = (i + 1f) / dbs.Count * 100f;
                            //ErrorHandler.HandleException("Now at " + progress.Progress + "% done.");
                        }

                        CLHelper.CStopAndDisplay(db.DbSource.DisplayName, i);
                    }

                    if (progress != null)
                    {
                        AProgress.IsCancelling(progress);
                    }
                }

                ClearCommands();
            }
            finally {
                DbDebugHelper.OnUpdate("Database reloaded...");
            }

            OnReloaded();
            SdeEditor.Instance.Dispatch(p => p.OnSelectionChanged());
        }
Beispiel #4
0
        private void _reloadDatabase(bool alreadyAsync)
        {
            try {
                if (!alreadyAsync)
                {
                    AProgress.Init(this);
                    _mainTabControl.Dispatch(p => p.IsEnabled = false);
                }

                _debugList.Dispatch(p => _debugItems.Clear());
                _debugList.Dispatch(p => ((TabItem)_mainTabControl.Items[1]).Header = new DisplayLabel {
                    DisplayText = "Error console", FontWeight = FontWeights.Bold
                });
                _clientDatabase.Reload(this);
                _delayedReloadDatabase = false;
            }
            catch (OperationCanceledException) {
                _mainTabControl.Dispatch(p => p.SelectedIndex = 0);
                _delayedReloadDatabase = true;
                GrfThread.Start(delegate {
                    Thread.Sleep(300);
                    _mainTabControl.Dispatch(p => Keyboard.Focus(_tviItemDb.TextBoxItem));
                });
            }
            catch (Exception err) {
                ErrorHandler.HandleException(err);
                _mainTabControl.Dispatch(p => p.SelectedIndex = 0);
                _delayedReloadDatabase = true;
                GrfThread.Start(delegate {
                    Thread.Sleep(300);
                    _mainTabControl.Dispatch(p => Keyboard.Focus(_tviItemDb.TextBoxItem));
                });
            }
            finally {
                if (!alreadyAsync)
                {
                    AProgress.Finalize(this);
                    _mainTabControl.Dispatch(p => p.IsEnabled = true);
                }

                _debugList.Dispatch(delegate {
                    if (_debugItems.Count > 0)
                    {
                        _debugList.Dispatch(p => ((TabItem)_mainTabControl.Items[1]).Header = new DisplayLabel {
                            DisplayText = "Error console *", FontWeight = FontWeights.Bold
                        });
                        _debugList.ScrollIntoView(_debugItems.Last());
                        ((TabItem)_mainTabControl.Items[1]).IsSelected = true;
                    }
                });
            }
        }
Beispiel #5
0
 private void _startTask(Action action)
 {
     try {
         AProgress.Init(this);
         action();
     }
     catch (OperationCanceledException) {
     }
     catch (Exception err) {
         ErrorHandler.HandleException(err);
     }
     finally {
         AProgress.Finalize(this);
     }
 }
Beispiel #6
0
        /// <summary>
        /// Saves the database.
        /// </summary>
        /// <param name="ap">The progress object.</param>
        /// <param name="progress"> </param>
        public virtual void Save(AsyncOperation ap, IProgress progress)
        {
            string     dbPath     = GrfPath.GetDirectoryName(ProjectConfiguration.DatabasePath);
            string     subPath    = ProjectConfiguration.DatabasePath.Replace(dbPath, "").TrimStart('\\', '/');
            ServerType serverType = DbPathLocator.GetServerType();

            DbDebugHelper.OnUpdate("Saving tables.");

            MetaGrf.Clear();

            try {
                BackupEngine.Instance.Start(ProjectConfiguration.DatabasePath);

                var dbs = _dbs.Values.ToList();

                IOHelper.SetupFileManager();

                for (int i = 0; i < dbs.Count; i++)
                {
                    var db = dbs[i];
                    db.WriteDb(dbPath, subPath, serverType);

                    if (progress != null)
                    {
                        progress.Progress = AProgress.LimitProgress((i + 1f) / dbs.Count * 100f);
                    }
                }

                foreach (var db in dbs)
                {
                    db.SaveCommandIndex();
                }

                Commands.SaveCommandIndex();
            }
            catch (Exception err) {
                ErrorHandler.HandleException(err);
            }
            finally {
                if (ap != null && progress != null)
                {
                    progress.Progress = ap.ProgressBar.GetIntermediateState("Backup manager");
                }

                BackupEngine.Instance.Stop();
                DbDebugHelper.OnUpdate("Finished saving tables.");
            }
        }
Beispiel #7
0
        private void _findResourceErrors(List <ValidationErrorView> errors)
        {
            var itemDb  = _database.GetMetaTable <int>(ServerDbs.Items);
            var citemDb = _database.GetMetaTable <int>(ServerDbs.CItems);

            HashSet <string> processed = new HashSet <string>();

            _helper = new PreviewHelper(
                new RangeListView(),
                _database.GetDb <int>(ServerDbs.Items),
                null,
                null,
                null,
                null
                );

            Dictionary <int, string> npcsIds = new Dictionary <int, string>();

            if (SdeAppConfiguration.VaResNpc)
            {
                string error;
                LuaHelper.GetIdToSpriteTable(_database.GetDb <int>(ServerDbs.Items), LuaHelper.ViewIdTypes.Npc, out npcsIds, out error);
            }

            int totalEntries = citemDb.Count + itemDb.Count + npcsIds.Count;
            int current      = 0;

            char[] invalid = Path.GetInvalidFileNameChars();

            foreach (var citem in citemDb.FastItems)
            {
                AProgress.IsCancelling(this);
                Progress = (float)current / totalEntries * 100f;
                current++;

                if (SdeAppConfiguration.VaResExistingOnly)
                {
                    if (itemDb.TryGetTuple(citem.Key) == null)
                    {
                        continue;
                    }
                }

                var idresource = citem.GetValue <string>(ClientItemAttributes.IdentifiedResourceName) ?? "";
                var unresource = citem.GetValue <string>(ClientItemAttributes.UnidentifiedResourceName) ?? "";

                if (idresource == "")
                {
                    if (SdeAppConfiguration.VaResEmpty)
                    {
                        errors.Add(new ResourceError(ValidationErrors.ResEmpty, citem.Key, "Empty identified resource.", ServerDbs.CItems, this, null));
                    }
                }
                else if (invalid.Any(idresource.Contains))
                {
                    if (SdeAppConfiguration.VaResInvalidCharacters)
                    {
                        errors.Add(new ResourceError(ValidationErrors.ResInvalidName, citem.Key, "Illegal characters found in resource name.", ServerDbs.CItems, this, null));
                    }
                }
                else
                {
                    _resource(citem, ResourceType.Identified, idresource, processed, errors);
                }

                if (unresource == "")
                {
                    if (SdeAppConfiguration.VaResEmpty)
                    {
                        errors.Add(new ResourceError(ValidationErrors.ResEmpty, citem.Key, "Empty identified resource.", ServerDbs.CItems, this, null));
                    }
                }
                else if (invalid.Any(unresource.Contains))
                {
                    if (SdeAppConfiguration.VaResInvalidCharacters)
                    {
                        errors.Add(new ResourceError(ValidationErrors.ResInvalidName, citem.Key, "Illegal characters found in resource name.", ServerDbs.CItems, this, null));
                    }
                }
                else
                {
                    _resource(citem, ResourceType.Unidentified, unresource, processed, errors);
                }
            }

            foreach (var item in itemDb.FastItems)
            {
                AProgress.IsCancelling(this);
                Progress = (float)current / totalEntries * 100f;
                current++;

                var citem = citemDb.TryGetTuple(item.Key);

                if (citem == null)
                {
                    if (SdeAppConfiguration.VaResClientItemMissing)
                    {
                        errors.Add(new ResourceError(ValidationErrors.ResClientMissing, item.Key, "Client Items: " + item.Key + " missing", ServerDbs.Items, this, null));
                    }

                    continue;
                }

                if (SdeAppConfiguration.VaResHeadgear)
                {
                    var sprites = _helper.TestItem(item, _database.MetaGrf, typeof(HeadgearPreview));

                    foreach (var sprite in sprites)
                    {
                        _checkResource(sprite, errors, item, processed, ValidationErrors.ResHeadgear, "Headgear", ServerDbs.Items);
                    }
                }

                if (SdeAppConfiguration.VaResShield)
                {
                    var sprites = _helper.TestItem(item, _database.MetaGrf, typeof(ShieldPreview));

                    foreach (var sprite in sprites)
                    {
                        _checkResource(sprite, errors, item, processed, ValidationErrors.ResShield, "Shield", ServerDbs.Items);
                    }
                }

                if (SdeAppConfiguration.VaResWeapon)
                {
                    var sprites = _helper.TestItem(item, _database.MetaGrf, typeof(WeaponPreview));

                    foreach (var sprite in sprites)
                    {
                        _checkResource(sprite, errors, item, processed, ValidationErrors.ResWeapon, "Weapon", ServerDbs.Items);
                    }
                }

                if (SdeAppConfiguration.VaResGarment)
                {
                    var sprites = _helper.TestItem(item, _database.MetaGrf, typeof(GarmentPreview));

                    foreach (var sprite in sprites)
                    {
                        _checkResource(sprite, errors, item, processed, ValidationErrors.ResGarment, "Garment", ServerDbs.Items);
                    }
                }
            }

            if (SdeAppConfiguration.VaResNpc)
            {
                NpcPreview preview = new NpcPreview();

                foreach (var id in npcsIds.OrderBy(p => p.Key))
                {
                    AProgress.IsCancelling(this);
                    Progress = (float)current / totalEntries * 100f;
                    current++;

                    _helper.ViewId = id.Key;
                    preview.Read(null, _helper, new List <Job>());
                    var sprite = preview.GetSpriteFromJob(null, _helper);

                    _checkResource(sprite, errors, id.Key, processed, ValidationErrors.ResNpc, "NPC", ServerDbs.Zero);

                    if (!sprite.EndsWith(".gr2", StringComparison.OrdinalIgnoreCase))
                    {
                        _checkResource(sprite.ReplaceExtension(".spr"), errors, id.Key, processed, ValidationErrors.ResNpc, "NPC", ServerDbs.Zero);
                    }
                }
            }
        }
Beispiel #8
0
        private void _listViewResults_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var item = _listViewResults.GetObjectAtPoint <ListViewItem>(e.GetPosition(_listViewResults));

            if (item != null)
            {
                HashSet <CmdInfo> commands = new HashSet <CmdInfo>();

                foreach (ValidationErrorView error in _listViewResults.SelectedItems)
                {
                    error.GetCommands(commands);
                }

                ContextMenu menu = new ContextMenu();

                foreach (var cmd in commands)
                {
                    var lcmd = cmd;

                    MenuItem mitem = new MenuItem {
                        Header = cmd.DisplayName, Icon = new Image {
                            Source = ApplicationManager.GetResourceImage(cmd.Icon)
                        }
                    };
                    mitem.Click += delegate {
                        var items = _listViewResults.SelectedItems.Cast <ValidationErrorView>().ToList();

                        _asyncOperation.SetAndRunOperation(new GrfThread(delegate {
                            List <object> dbs = new List <object>();

                            foreach (var serverDb in ServerDbs.ListDbs)
                            {
                                var db = _sdb.TryGetDb(serverDb);

                                if (db != null)
                                {
                                    if (db.AttributeList.PrimaryAttribute.DataType == typeof(int))
                                    {
                                        var adb = (AbstractDb <int>)db;
                                        dbs.Add(adb);
                                    }
                                    else if (db.AttributeList.PrimaryAttribute.DataType == typeof(string))
                                    {
                                        var adb = (AbstractDb <string>)db;
                                        dbs.Add(adb);
                                    }
                                }
                            }

                            foreach (var db in dbs)
                            {
                                _to <int>(db, _onBegin);
                                _to <string>(db, _onBegin);
                            }

                            try {
                                AProgress.Init(_validation);

                                _validation.Grf.Close();
                                _validation.Grf.Open(GrfPath.Combine(SdeAppConfiguration.ProgramDataPath, "missing_resources.grf"), GrfLoadOptions.OpenOrNew);

                                for (int i = 0; i < items.Count; i++)
                                {
                                    AProgress.IsCancelling(_validation);
                                    if (!lcmd.Execute(items[i], items))
                                    {
                                        return;
                                    }
                                    _validation.Progress = (float)i / items.Count * 100f;
                                }

                                if (_validation.Grf.IsModified)
                                {
                                    _validation.Progress = -1;
                                    _validation.Grf.QuickSave();
                                    _validation.Grf.Reload();
                                    _validation.Grf.Compact();
                                }
                            }
                            catch (OperationCanceledException) {
                            }
                            catch (Exception err) {
                                ErrorHandler.HandleException(err);
                            }
                            finally {
                                foreach (var db in dbs)
                                {
                                    _to <int>(db, _onEnd);
                                    _to <string>(db, _onEnd);
                                }

                                _validation.Grf.Close();
                                AProgress.Finalize(_validation);
                            }
                        }, _validation, 200, null, true, true));
                    };

                    menu.Items.Add(mitem);
                }

                item.ContextMenu        = menu;
                item.ContextMenu.IsOpen = true;
            }
            else
            {
                e.Handled = true;
            }
        }
Beispiel #9
0
        private void _menuItemMerge_Click(object sender, RoutedEventArgs e)
        {
            try {
                if (!_validateState())
                {
                    return;
                }

                string file = PathRequest.OpenFileMapcache("filter", "Grf and Dat Files (*.grf, *.dat)|*.grf;*.dat");

                if (file != null)
                {
                    if (file.IsExtension(".grf"))
                    {
                        _asyncOperation.SetAndRunOperation(new GrfThread(delegate {
                            AProgress.Init(_cache);

                            try {
                                _cache.Commands.Begin();

                                List <FileEntry> files = new List <FileEntry>();
                                int count = 0;

                                using (GrfHolder grf = new GrfHolder(file, GrfLoadOptions.Normal)) {
                                    files.AddRange(grf.FileTable.EntriesInDirectory("data\\", SearchOption.TopDirectoryOnly).Where(entry => entry.RelativePath.IsExtension(".gat")));

                                    foreach (var entry in files)
                                    {
                                        count++;
                                        AProgress.IsCancelling(_cache);
                                        FileEntry rswEntry = grf.FileTable.TryGet(entry.RelativePath.ReplaceExtension(".rsw"));

                                        if (rswEntry == null)
                                        {
                                            continue;
                                        }

                                        _cache.Progress = (float)count / files.Count * 100f;
                                        _cache.Commands.AddMap(Path.GetFileNameWithoutExtension(entry.DisplayRelativePath), entry.GetDecompressedData(), rswEntry.GetDecompressedData());
                                    }
                                }
                            }
                            catch (OperationCanceledException) {
                                _cache.IsCancelled = true;
                                _cache.Commands.CancelEdit();
                            }
                            catch (Exception err) {
                                _cache.Commands.CancelEdit();
                                ErrorHandler.HandleException(err);
                            }
                            finally {
                                _cache.Commands.End();
                                AProgress.Finalize(_cache);
                            }
                        }, _cache, 200));
                    }
                    else if (file.IsExtension(".dat"))
                    {
                        Mapcache cache = new Mapcache(file);

                        try {
                            _cache.Commands.Begin();

                            foreach (var map in cache.Maps)
                            {
                                _cache.Commands.AddMapRaw(map.MapName, map);
                            }
                        }
                        catch {
                            _cache.Commands.CancelEdit();
                            throw;
                        }
                        finally {
                            _cache.Commands.End();
                        }
                    }
                    else
                    {
                        throw new Exception("Unreognized file format.");
                    }
                }
            }
            catch (Exception err) {
                ErrorHandler.HandleException(err);
            }
        }
Beispiel #10
0
 private void _dull()
 {
     AProgress.Finalize(_cache);
 }
        private void _findClientItemErrors(List <ValidationErrorView> errors)
        {
            var itemDb  = _database.GetMetaTable <int>(ServerDbs.Items);
            var citemDb = _database.GetMetaTable <int>(ServerDbs.CItems);

            int current      = 0;
            int totalEntries = citemDb.FastItems.Count;

            Dictionary <int, int> viewIdToWepClass = _getWeaponClasses();

            //Expansion_Weapon_IDs
            foreach (var citem in citemDb.FastItems)
            {
                AProgress.IsCancelling(this);
                Progress = (float)current / totalEntries * 100f;
                current++;

                var sitem = itemDb.TryGetTuple(citem.Key);

                if (sitem == null)
                {
                    continue;
                }

                var itemType = sitem.GetValue <TypeType>(ServerItemAttributes.Type);

                if (itemType == TypeType.Weapon || itemType == TypeType.Armor)
                {
                    if (itemType == TypeType.Armor && !ItemParser.IsArmorType(sitem))
                    {
                        if (itemType == TypeType.Armor)
                        {
                            itemType = TypeType.Weapon;
                        }
                        else
                        {
                            itemType = TypeType.Armor;
                        }
                    }
                }

                var parameters = citem.GetValue <ParameterHolder>(ClientItemAttributes.Parameters);

                if (parameters != null)
                {
                    foreach (var param in ParameterHolder.KnownItemParameters)
                    {
                        try {
                            if (parameters.Values.ContainsKey(param))
                            {
                                var value = parameters.Values[param];

                                if (param == ParameterHolderKeys.Class && SdeAppConfiguration.VaCiClass)
                                {
                                    var sViewId  = sitem.GetIntNoThrow(ServerItemAttributes.ClassNumber);
                                    var location = sitem.GetIntNoThrow(ServerItemAttributes.Location);

                                    int cViewId;

                                    switch (itemType)
                                    {
                                    case TypeType.Weapon:
                                        var twoHanded        = (location & 34) == 34;
                                        var isWeaponLocation = (location & 2) != 0;

                                        if (!isWeaponLocation)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemLocation: server Location requires the 'Weapon' flag.", ServerDbs.Items, this));
                                        }

                                        ItemGeneratorEngine.WeaponTypeToViewId.TryGetValue(value, out cViewId);

                                        if (sViewId < 0)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemDescription: server View ID cannot be below 0.", ServerDbs.Items, this));
                                            continue;
                                        }

                                        if (sViewId >= ItemGeneratorEngine.WeaponTypes.Count)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemDescription: unknown server View ID, custom weapon?", ServerDbs.Items, this));
                                            continue;
                                        }

                                        if (cViewId == 0)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemDescription: found class '" + value + "', expected '" + ItemGeneratorEngine.WeaponTypes[sViewId] + "'", ServerDbs.CItems, this));
                                        }
                                        else if (cViewId != sViewId)
                                        {
                                            if (twoHanded)
                                            {
                                                if (ItemGeneratorEngine.TwoHandedWeapons.Contains(sViewId))
                                                {
                                                    errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemDescription: found class '" + value + "', expected '" + ItemGeneratorEngine.WeaponTypes[sViewId] + "'", ServerDbs.CItems, this));
                                                }
                                                else
                                                {
                                                    errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemDescription: found class '" + value + "', expected '" + ItemGeneratorEngine.WeaponTypes[sViewId] + "'. The server View ID doesn't belong to a two-handed weapon class.", ServerDbs.CItems, this));
                                                }
                                            }
                                            else
                                            {
                                                if (!ItemGeneratorEngine.TwoHandedWeapons.Contains(sViewId))
                                                {
                                                    errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemDescription: found class '" + value + "', expected '" + ItemGeneratorEngine.WeaponTypes[sViewId] + "'", ServerDbs.CItems, this));
                                                }
                                                else
                                                {
                                                    errors.Add(new CiError(ValidationErrors.CiItemClassUnknown, citem.Key, "ItemDescription: found class '" + value + "', expected '" + ItemGeneratorEngine.WeaponTypes[sViewId] + "'. The server View ID belongs to a two-handed weapon class.", ServerDbs.CItems, this));
                                                }
                                            }
                                        }

                                        break;

                                    default:

                                        break;
                                    }
                                }
                                else if (param == ParameterHolderKeys.Attack && SdeAppConfiguration.VaCiAttack)
                                {
                                    int ival;
                                    if (Int32.TryParse(value, out ival))
                                    {
                                        var sval = sitem.GetIntNoThrow(ServerItemAttributes.Attack);
                                        var name = sitem.GetValue <string>(ServerItemAttributes.Name);

                                        if (name.EndsWith(" Box"))
                                        {
                                            continue;
                                        }

                                        if (ival != sval)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiAttack, citem.Key, "Attack: found '" + value + "', expected '" + sval + "'.", ServerDbs.CItems, this));
                                        }
                                    }
                                    else
                                    {
                                        errors.Add(new CiError(ValidationErrors.CiParseError, citem.Key, "Parse: failed to parse Attack field, found '" + value + "'.", ServerDbs.CItems, this));
                                    }
                                }
                                else if (param == ParameterHolderKeys.Defense && SdeAppConfiguration.VaCiDefense)
                                {
                                    int ival;
                                    if (Int32.TryParse(value, out ival))
                                    {
                                        var sval = sitem.GetIntNoThrow(ServerItemAttributes.Defense);
                                        if (ival != sval)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiDefense, citem.Key, "Defense: found '" + value + "', expected '" + sval + "'.", ServerDbs.CItems, this));
                                        }
                                    }
                                    else
                                    {
                                        errors.Add(new CiError(ValidationErrors.CiParseError, citem.Key, "Parse: failed to parse Defense field, found '" + value + "'.", ServerDbs.CItems, this));
                                    }
                                }
                                else if (param == ParameterHolderKeys.Property && SdeAppConfiguration.VaCiProperty)
                                {
                                    var          script = sitem.GetValue <string>(ServerItemAttributes.Script);
                                    const string Bonus1 = "bonus bAtkEle";
                                    const string Bonus2 = "bonus bDefEle";

                                    if (script.Contains(Bonus1) || script.Contains(Bonus2))
                                    {
                                        var bonusScript = script.Contains(Bonus1) ? Bonus1 : Bonus2;

                                        int start = script.IndexOf(bonusScript, StringComparison.Ordinal) + bonusScript.Length;
                                        int end   = script.IndexOf(";", start, StringComparison.Ordinal);

                                        if (end < 0)
                                        {
                                            end = script.Length;
                                        }

                                        var bonus = script.Substring(start, end - start).Trim(',', ' ', ';');

                                        if (bonus.Length > 4)
                                        {
                                            var element = bonus.Substring(4);

                                            if (element != value)
                                            {
                                                if (value == "Shadow" && element == "Dark")
                                                {
                                                }
                                                else
                                                {
                                                    errors.Add(new CiError(ValidationErrors.CiProperty, citem.Key, "Property: found '" + value + "', expected '" + element + "'.", ServerDbs.CItems, this));
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        if (value != "Neutral")
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiProperty, citem.Key, "Property: found '" + value + "', expected no element or Neutral.", ServerDbs.CItems, this));
                                        }
                                    }
                                }
                                else if (param == ParameterHolderKeys.RequiredLevel && SdeAppConfiguration.VaCiRequiredLevel)
                                {
                                    int ival;
                                    if (Int32.TryParse(value, out ival))
                                    {
                                        var sval = sitem.GetIntNoThrow(ServerItemAttributes.EquipLevel);
                                        if (ival != sval)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiEquipLevel, citem.Key, "EquipLevel: found '" + value + "', expected '" + sval + "'.", ServerDbs.CItems, this));
                                        }
                                    }
                                    else
                                    {
                                        errors.Add(new CiError(ValidationErrors.CiParseError, citem.Key, "Parse: failed to parse EquipLevel field, found '" + value + "'.", ServerDbs.CItems, this));
                                    }
                                }
                                else if (param == ParameterHolderKeys.WeaponLevel && SdeAppConfiguration.VaCiWeaponLevel)
                                {
                                    int ival;

                                    if (Int32.TryParse(value, out ival))
                                    {
                                        var name = sitem.GetValue <string>(ServerItemAttributes.Name);
                                        var sval = sitem.GetIntNoThrow(ServerItemAttributes.WeaponLevel);

                                        if (name.EndsWith(" Box"))
                                        {
                                            continue;
                                        }

                                        if (ival != sval)
                                        {
                                            errors.Add(new CiError(ValidationErrors.CiWeaponLevel, citem.Key, "WeaponLevel: found '" + value + "', expected '" + sval + "'.", ServerDbs.CItems, this));
                                        }
                                    }
                                    else
                                    {
                                        errors.Add(new CiError(ValidationErrors.CiParseError, citem.Key, "Parse: failed to parse WeaponLevel field, found '" + value + "'.", ServerDbs.CItems, this));
                                    }
                                }
                                else if (param == ParameterHolderKeys.Weight && SdeAppConfiguration.VaCiWeight)
                                {
                                    int ival = (int)(FormatConverters.SingleConverter(value) * 10);

                                    var sval = sitem.GetIntNoThrow(ServerItemAttributes.Weight);
                                    if (ival != sval)
                                    {
                                        errors.Add(new CiError(ValidationErrors.CiWeight, citem.Key, "Weight: found '" + ival + "', expected '" + sval + "'.", ServerDbs.CItems, this));
                                    }
                                }
                                else if ((param == ParameterHolderKeys.Location || param == ParameterHolderKeys.EquippedOn) && SdeAppConfiguration.VaCiLocation)
                                {
                                    var name = sitem.GetValue <string>(ServerItemAttributes.Name);

                                    // Do not scan rental items
                                    if (name.EndsWith(" Box"))
                                    {
                                        continue;
                                    }

                                    string[] items = value.Split(',', '/', '-', '&').Select(p => p.Trim(' ')).ToArray();
                                    int      ival  = 0;

                                    foreach (string item in items)
                                    {
                                        if (item.ToLower() == "lower")
                                        {
                                            ival |= 1;
                                        }
                                        if (item.ToLower() == "mid" || item.ToLower() == "middle")
                                        {
                                            ival |= 512;
                                        }
                                        if (item.ToLower() == "upper")
                                        {
                                            ival |= 256;
                                        }
                                        if (item.ToLower() == "all slot")
                                        {
                                            ival |= 1023;
                                        }
                                    }

                                    var sval = sitem.GetIntNoThrow(ServerItemAttributes.Location);

                                    if ((sval & 7168) != 0)
                                    {
                                        // It's a costume ;x!
                                        ival = 0;

                                        foreach (string item in items)
                                        {
                                            if (item.ToLower() == "lower")
                                            {
                                                ival |= 4096;
                                            }
                                            if (item.ToLower() == "mid" || item.ToLower() == "middle")
                                            {
                                                ival |= 2048;
                                            }
                                            if (item.ToLower() == "upper")
                                            {
                                                ival |= 1024;
                                            }
                                        }
                                    }

                                    if (ival != sval)
                                    {
                                        errors.Add(new CiError(ValidationErrors.CiLocation, citem.Key, "Location: found '" + ival + "', expected '" + sval + "'.", ServerDbs.CItems, this));
                                    }
                                }
                                else if (param == ParameterHolderKeys.CompoundOn && SdeAppConfiguration.VaCiCompoundOn)
                                {
                                    var valueLower = value.ToLower();
                                    int location   = 0;

                                    switch (valueLower)
                                    {
                                    case "weapon":
                                        location = 2;
                                        break;

                                    case "headgear":
                                        location = 769;
                                        break;

                                    case "armor":
                                        location = 16;
                                        break;

                                    case "shield":
                                        location = 32;
                                        break;

                                    case "garment":
                                        location = 4;
                                        break;

                                    case "accessory":
                                        location = 136;
                                        break;

                                    case "shoes":
                                    case "footwear":
                                    case "foot gear":
                                    case "footgear":
                                        location = 64;
                                        break;

                                    default:
                                        errors.Add(new CiError(ValidationErrors.CiParseError, citem.Key, "CompoundOn: found '" + value + "'.", ServerDbs.CItems, this));
                                        break;
                                    }

                                    var sval = sitem.GetIntNoThrow(ServerItemAttributes.Location);

                                    if ((location & sval) != sval)
                                    {
                                        errors.Add(new CiError(ValidationErrors.CiCompoundOn, citem.Key, "CompoundOn: found '" + location + "', expected '" + sval + "'.", ServerDbs.CItems, this));
                                    }
                                }
                                else if (param == ParameterHolderKeys.ApplicableJob && SdeAppConfiguration.VaCiJob)
                                {
                                    //var jobs = JobList.GetApplicableJobs(value);
                                    //var jobHex = JobList.GetHexJob(jobs);
                                    //
                                    //var sJobHex = "0x" + sitem.GetValue<string>(ServerItemAttributes.ApplicableJob);
                                    //jobs = JobList.GetApplicableJobsFromHex(sJobHex);
                                    //sJobHex = JobList.GetHexJob(jobs);
                                    //
                                    //if (jobHex != sJobHex) {
                                    //	errors.Add(new CiError(ValidationErrors.CiCompoundOn, citem.Key, "ApplicableJob: found '" + jobHex + "', expected '" + sJobHex + "'.", ServerDbs.CItems, this));
                                    //}
                                }
                            }
                        }
                        catch {
                            errors.Add(new CiError(ValidationErrors.Generic, citem.Key, "Failed to analyse property '" + param + "'.", ServerDbs.Items, this));
                        }
                    }
                }
                // End of parameters

                if (itemType == TypeType.Weapon && SdeAppConfiguration.VaCiItemRange)
                {
                    var sVal = sitem.GetIntNoThrow(ServerItemAttributes.ClassNumber);

                    if (sVal < 24 && sVal > 0)
                    {
                        var range = _ranges[sVal];
                        var id    = sitem.Key;

                        bool found = false;

                        for (int i = 0; i < range.Length; i += 2)
                        {
                            if (range[i] < 0)
                            {
                                errors.Add(new CiError(ValidationErrors.CiItemRange, citem.Key, "ItemRange: found weapon class '" + sVal + "', which does not have any ID range.", ServerDbs.Items, this));
                                found = true;
                                break;
                            }

                            if (range[i] <= id && id <= range[i + 1])
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            string idRange = "";

                            for (int i = 0; i < range.Length; i += 2)
                            {
                                if (i > 0)
                                {
                                    idRange += ", ";
                                }

                                idRange += range[i] + "-" + range[i + 1];
                            }

                            errors.Add(new CiError(ValidationErrors.CiItemRange, citem.Key, "ItemRange: found weapon class '" + sVal + "', which has an ID range of [" + idRange + "].", ServerDbs.Items, this));
                        }
                    }
                }

                if (SdeAppConfiguration.VaCiNumberOfSlots)
                {
                    var sVal = sitem.GetIntNoThrow(ServerItemAttributes.NumberOfSlots);
                    var cVal = citem.GetIntNoThrow(ClientItemAttributes.NumberOfSlots);

                    if (sVal != cVal)
                    {
                        errors.Add(new CiError(ValidationErrors.CiNumOfSlots, citem.Key, "NumberOfSlots: found '" + cVal + "', expected '" + sVal + "'.", ServerDbs.CItems, this));
                    }

                    if (!ItemParser.IsArmorType(sitem) && !ItemParser.IsWeaponType(sitem))
                    {
                        if (sVal > 0)
                        {
                            errors.Add(new CiError(ValidationErrors.CiNumOfSlots, citem.Key, "NumberOfSlots: found '" + sVal + "', but the server item type is neither an armor or a weapon..", ServerDbs.Items, this));
                        }
                    }
                }

                if (SdeAppConfiguration.VaCiViewId)
                {
                    var sVal = sitem.GetIntNoThrow(ServerItemAttributes.ClassNumber);
                    var cVal = citem.GetIntNoThrow(ClientItemAttributes.ClassNumber);

                    if (sVal != cVal)
                    {
                        var nVal = cVal;

                        if (cVal > 24)
                        {
                            if (viewIdToWepClass.ContainsKey(cVal))
                            {
                                nVal = viewIdToWepClass[cVal];
                            }
                        }

                        if (sVal != nVal)
                        {
                            if (nVal != cVal)
                            {
// && nVal + 1 == sVal) {
                            }
                            else
                            {
                                bool showError = true;

                                if (cVal == 0)
                                {
                                    if ((citem.Key >= 18000 && citem.Key <= 18099) ||
                                        (citem.Key >= 13260 && citem.Key <= 13290))
                                    {
                                        showError = false;
                                    }
                                }

                                if (showError)
                                {
                                    errors.Add(new CiError(ValidationErrors.CiViewId, citem.Key, "ClassNumber: found '" + cVal + "', class '" + nVal + "', expected '" + sVal + "'.", ServerDbs.CItems, this));
                                }
                            }
                        }
                    }
                }

                if (SdeAppConfiguration.VaCiIsCard)
                {
                    var sVal = itemType;
                    var cVal = citem.GetValue <bool>(ClientItemAttributes.IsCard);

                    if ((sVal == TypeType.Card || cVal) && (sVal != TypeType.Card || !cVal))
                    {
                        errors.Add(new CiError(ValidationErrors.CiCardType, citem.Key, "TypeMismatch: client item IsCard '" + cVal + "', server type '" + sVal + "'.", ServerDbs.CItems, this));
                    }
                }

                if (SdeAppConfiguration.VaCiName)
                {
                    var sname = sitem.GetValue <string>(ServerItemAttributes.Name);
                    var cname = citem.GetValue <string>(ClientItemAttributes.IdentifiedDisplayName);

                    if (sname != cname)
                    {
                        int distance = Methods.LevenshteinDistance(sname, cname);

                        if (distance > 5)
                        {
                            errors.Add(new CiError(ValidationErrors.CiName, citem.Key, "NameMismatch: client name is '" + cname + "', server name is '" + sname + "', diff = " + distance + ".", ServerDbs.CItems, this));
                        }
                    }
                }
            }
        }