Inheritance: DbContext
        internal static void SetupDatabase(Entry plugin)
        {
            #if ENTITY_FRAMEWORK_6
            Storage.IsAvailable = OTA.Data.EF6.OTAContext.HasConnection;

            if (Storage.IsAvailable) ProgramLog.Admin.Log("Entity framework has a registered connection.");
            else ProgramLog.Admin.Log("Entity framework has no registered connection.");

            //if (Storage.IsAvailable)
            //    using (var ctx = new TContext())
            //    {
            //        ctx.APIAccounts.Add(new TDSM.Core.Data.Models.APIAccount()
            //        {
            //            Username = "******",
            //            Password = "******"
            //        });

            //        ctx.SaveChanges();
            //    }

            #elif !ENTITY_FRAMEWORK_7
            using (var ctx = new TContext())
            {
            ctx.Database.EnsureCreated();
            Storage.IsAvailable = true;
            }

            #endif
        }
        public static Character GetCharacter(TContext ctx, CharacterMode mode, string auth, string clientUUID)
        {
            int userId = 0;
            if (mode == CharacterMode.AUTH)
            {
                var user = AuthenticatedUsers.GetUser(auth);

                if (user == null)
                {
                    OTA.Logging.ProgramLog.Error.Log("No user found ");
                    return null;
                }

                userId = user.Id;
            }
            else if (mode != CharacterMode.UUID)
                return null;

            if (mode == CharacterMode.AUTH)
            {
                return ctx.Characters.SingleOrDefault(x => x.UserId == userId);
            }
            else
            {
                return ctx.Characters.SingleOrDefault(x => x.UUID == clientUUID);
            }
        }
        /// <summary>
        /// Creates a user.
        /// </summary>
        /// <returns><c>true</c>, if user was created, <c>false</c> otherwise.</returns>
        /// <param name="name">The players name.</param>
        /// <param name="password">Password.</param>
        /// <param name="op">If set to <c>true</c> op.</param>
        public static DbPlayer CreatePlayer(string name, string password, bool op = false)
        {
#if DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                {
                    var player = new DbPlayer(name, password)
                    {
                        Operator  = op,
                        DateAdded = DateTime.UtcNow
                    };
                    player.Id = ctx.Insert(player, transaction: txn);

                    var hc = new HookContext();
                    var ha = new Events.HookArgs.PlayerRegistered()
                    {
                        Connection  = ctx,
                        Transaction = txn,
                        Player      = player
                    };

                    Events.HookPoints.PlayerRegistered.Invoke(ref hc, ref ha);

                    if (hc.Result == HookResult.DEFAULT)
                    {
                        txn.Commit();
                        return(player);
                    }
                    else
                    {
                        txn.Rollback();
                        return(null);
                    }
                }
            }
#else
            using (var ctx = new TContext())
            {
                DbPlayer player;
                ctx.Players.Add(player = new DbPlayer(name, password)
                {
                    Operator     = op,
                    DateAddedUTC = DateTime.UtcNow
                });

                ctx.SaveChanges();

                return(player);
            }
#endif
        }
 public static Character NewCharacter(
     TContext ctx,
     CharacterMode mode,
     string auth,
     string clientUUID,
     int health,
     int maxHealth,
     int mana,
     int maxMana,
     int spawnX,
     int spawnY,
     int hair,
     byte hairDye,
     bool[] hideVisual,
     byte difficulty,
     Microsoft.Xna.Framework.Color hairColor,
     Microsoft.Xna.Framework.Color skinColor,
     Microsoft.Xna.Framework.Color eyeColor,
     Microsoft.Xna.Framework.Color shirtColor,
     Microsoft.Xna.Framework.Color underShirtColor,
     Microsoft.Xna.Framework.Color pantsColor,
     Microsoft.Xna.Framework.Color shoeColor, 
     int anglerQuests
 )
 {
     return NewCharacter
     (
         ctx,
         mode,
         auth,
         clientUUID,
         health,
         maxHealth,
         mana,
         maxMana,
         spawnX,
         spawnY,
         hair,
         hairDye,
         DataEncoding.EncodeInteger(hideVisual),
         difficulty,
         DataEncoding.EncodeColor(hairColor),
         DataEncoding.EncodeColor(skinColor),
         DataEncoding.EncodeColor(eyeColor),
         DataEncoding.EncodeColor(shirtColor),
         DataEncoding.EncodeColor(underShirtColor),
         DataEncoding.EncodeColor(pantsColor),
         DataEncoding.EncodeColor(shoeColor),
         anglerQuests
     );
 }
        /// <summary>
        /// Checks if a player exists
        /// </summary>
        /// <returns><c>true</c>, if the player exists, <c>false</c> otherwise.</returns>
        /// <param name="name">Player name.</param>
        public static bool PlayerExists(string name)
        {
#if ENTITY_FRAMEWORK_7
            using (var ctx = new TContext())
            {
                return(ctx.Players.Any(x => x.Name == name));
            }
#elif DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                    return(ctx.Count <DbPlayer>(new { Name = name }, transaction: txn) > 0);
            }
#endif
        }
        /// <summary>
        /// Gets the players password.
        /// </summary>
        /// <returns>The players password.</returns>
        /// <param name="name">Player name.</param>
        public static string GetPlayerPasword(string name)
        {
#if ENTITY_FRAMEWORK_7
            using (var ctx = new TContext())
            {
                return(ctx.Players
                       .Where(x => x.Name == name)
                       .Select(x => x.Password)
                       .FirstOrDefault());
            }
#elif DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                    return(ctx.Where <DbPlayer>(new { Name = name }, transaction: txn)
                           .Select(x => x.Password)
                           .FirstOrDefault());
            }
#endif
        }
        public void CreateDefaultGroups(TContext ctx)
        {
            var pc = CommandParser.GetAvailableCommands(AccessLevel.PLAYER);
            var ad = CommandParser.GetAvailableCommands(AccessLevel.OP);
            var op = CommandParser.GetAvailableCommands(AccessLevel.CONSOLE); //Funny how these have now changed

            CreateGroup("Guest", true, null, 255, 255, 255, pc
                    .Where(x => !String.IsNullOrEmpty(x.Value.Node))
                    .Select(x => x.Value.Node)
                    .Distinct()
                    .ToArray(), ctx, "[Guest] ");
            CreateGroup("Admin", false, "Guest", 240, 131, 77, ad
                    .Where(x => !String.IsNullOrEmpty(x.Value.Node))
                    .Select(x => x.Value.Node)
                    .Distinct()
                    .ToArray(), ctx, "[Admin] ");
            CreateGroup("Operator", false, "Admin", 77, 166, 240, op
                    .Where(x => !String.IsNullOrEmpty(x.Value.Node))
                    .Select(x => x.Value.Node)
                    .Distinct()
                    .ToArray(), ctx, "[OP] ");
        }
        /// <summary>
        /// Removes a player from the database by name
        /// </summary>
        /// <returns><c>true</c>, if the player was deleted, <c>false</c> otherwise.</returns>
        /// <param name="name">The players name.</param>
        public static bool DeletePlayer(string name)
        {
#if DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                {
                    var res = ctx.Execute($"delete from {TableMapper.TypeToName<DbPlayer>()} where Name = @Name", new { Name = name }, transaction: txn) > 0;
                    txn.Commit();
                    return(res);
                }
            }
#else
            using (var ctx = new TContext())
            {
                var matches = ctx.Players.Where(x => x.Name == name);
                ctx.Players.RemoveRange(matches);

                ctx.SaveChanges();

                return(ctx.Players.Any(x => x.Name == name));
            }
#endif
        }
        /// <summary>
        /// Gets the player from the database by name
        /// </summary>
        /// <returns>The player instance.</returns>
        /// <param name="name">Player name.</param>
        public static DbPlayer GetPlayer(string name, IDbConnection connection = null, IDbTransaction transaction = null)
        {
#if ENTITY_FRAMEWORK_7
            using (var ctx = new TContext())
            {
                return(ctx.Players
                       .Where(x => x.Name == name)
                       .FirstOrDefault());
            }
#elif DAPPER
            if (connection == null)
            {
                using (var ctx = DatabaseFactory.CreateConnection())
                {
                    using (var txn = ctx.BeginTransaction())
                        return(ctx.FirstOrDefault <DbPlayer>(new { Name = name }, transaction: txn));
                }
            }
            else
            {
                return(connection.FirstOrDefault <DbPlayer>(new { Name = name }, transaction: transaction));
            }
#endif
        }
        private static bool SaveCharacterItem(TContext ctx, bool save, Player player, int characterId, ItemType type, Item item, int slot, SlotItem[] existing)
        {
            var netId = 0;
            var prefix = 0;
            var stack = 0;
            var favorite = false;

            if (item != null)
            {
                netId = item.netID;
                prefix = item.prefix;
                stack = item.stack;
                favorite = item.favorited;
            }

            var slotItem = existing.SingleOrDefault(x => x.Slot == slot && x.Type == type && x.NetId == netId);
            if (slotItem != null)
            {
                slotItem.Favorite = favorite;
                slotItem.Stack = stack;
                slotItem.Prefix = prefix;
            }
            else
            {
                slotItem = new SlotItem()
                {
                    CharacterId = characterId,
                    Slot = slot,
                    NetId = netId,
                    Stack = stack,
                    Prefix = prefix,
                    Favorite = favorite,
                    Type = type
                };
                ctx.Items.Add(slotItem);
            }

            return true;
        }
 public static bool SavePlayerData(TContext ctx, bool save, Player player)
        public static void LoadForAuthenticated(TContext ctx, Player player, bool createIfNone = true)
        {
            var ssc = LoadPlayerData(ctx, player, createIfNone);

            if (ssc != null)
            {
//                var loaded = String.Join(",", ssc.Inventory.Select(x => x.NetId).Where(x => x > 0).ToArray());
//                ProgramLog.Admin.Log("Loaded items: " + loaded);

                //Check to make sure the player is the same player (ie skin, clothes)
                //Add hooks for pre and post apply

                var hctx = new HookContext()
                {
                    Player = player,
                    Sender = player
                };

                var args = new TDSM.Core.Events.HookArgs.PreApplyServerSideCharacter()
                {
                    Character = ssc
                };

                TDSM.Core.Events.HookPoints.PreApplyServerSideCharacter.Invoke(ref hctx, ref args);

                args.Character.ApplyToPlayer(player);

                var args1 = new TDSM.Core.Events.HookArgs.PostApplyServerSideCharacter();
                TDSM.Core.Events.HookPoints.PostApplyServerSideCharacter.Invoke(ref hctx, ref args1);
            }
            else
            {
                ProgramLog.Log("No SSC data");
            }
        }
        public static ServerCharacter LoadPlayerData(TContext ctx, Player player, bool returnNewInfo = false)
        {
            //If using a flat based system ensure the MODE is stored
            string authName = null;
            if (Mode == CharacterMode.AUTH)
            {
                var auth = player.GetAuthenticatedAs();
                if (!String.IsNullOrEmpty(auth))
                    authName = auth;
            }
            else if (Mode == CharacterMode.UUID)
            {
                if (!String.IsNullOrEmpty(player.ClientUUId))
                    authName = player.ClientUUId + '@' + player.name;
            }

//            ProgramLog.Admin.Log("SSC is: " + Storage.IsAvailable);
//            ProgramLog.Admin.Log("Finding SSC for: " + (authName ?? "NULL"));

            if (!String.IsNullOrEmpty(authName))
            {
//                ProgramLog.Log("Loading SSC for " + authName);

                if (Storage.IsAvailable)
                {
                    var auth = player.GetAuthenticatedAs();
#if ENTITY_FRAMEWORK_6 || ENTITY_FRAMEWORK_7
                    var dbSSC = Tables.CharacterTable.GetCharacter(ctx, Mode, auth, player.ClientUUId);

//                    ProgramLog.Admin.Log("Found SCC: " + (dbSSC != null));

                    if (dbSSC != null)
                    {
                        var ssc = dbSSC.ToServerCharacter();
#elif DATA_CONNECTOR
                    var ssc = Tables.CharacterTable.GetCharacter(Mode, auth, player.ClientUUId);
                    if (ssc != null)
                    { 
#endif
                        //                        ProgramLog.Log("Loading SSC loadout");

                        //                        ProgramLog.Admin.Log("Loading SSC loadout: " + dbSSC.Id);
                        //                        ProgramLog.Admin.Log("Translated SCC: " + (ssc != null));
                        //
                        var inv = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.Inventory, ssc.Id);
                        if (null != inv) ssc.Inventory = inv.ToList();

                        var amr = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.Armor, ssc.Id);
                        if (null != amr) ssc.Armor = amr.ToList();

                        var dye = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.Dye, ssc.Id);
                        if (null != dye) ssc.Dye = dye.ToList();

                        var equipment = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.Equipment, ssc.Id);
                        if (null != equipment) ssc.Equipment = equipment.ToList();

                        var miscdye = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.MiscDyes, ssc.Id);
                        if (null != miscdye) ssc.MiscDyes = miscdye.ToList();

                        var bank = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.Bank, ssc.Id);
                        if (null != bank) ssc.Bank = bank.ToList();

                        var bank2 = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.Bank2, ssc.Id);
                        if (null != bank2) ssc.Bank2 = bank2.ToList();

                        var trash = Tables.ItemTable.GetItemsForCharacter(ctx, ItemType.Trash, ssc.Id);
#if ENTITY_FRAMEWORK_6 || ENTITY_FRAMEWORK_7
                        if (null != trash && trash.Count > 0) ssc.Trash = trash.First();
#elif DATA_CONNECTOR
                        if (null != trash && trash.Length > 0) ssc.Trash = trash.First();
#endif

                        return ssc;
                    }
                    else
                    {
                        if (returnNewInfo)
                        {
//                            ProgramLog.Log("Issuing new loadout");
                            //                        player.SetPluginData(Key_NewCharacter, true);
                            EnsureSave = true; //Save is now required
                            return new ServerCharacter(StartingOutInfo, player);
                        }
//                        else ProgramLog.Log("New loadout not specified");
                    }
                }
                else
                {
                    var dir = Path.Combine(Globals.CharacterDataPath, Mode.ToString());
                    if (!Directory.Exists(dir))
                        Directory.CreateDirectory(dir);

                    var file = Path.Combine(dir, authName + ".ssc");
                    if (System.IO.File.Exists(file))
                    {
                        var json = System.IO.File.ReadAllText(file);
                        if (json.Length > 0)
                        {
//                            ProgramLog.Log("Loading existing loadout");
                            return Newtonsoft.Json.JsonConvert.DeserializeObject<ServerCharacter>(json);
                        }
                        else
                        {
                            ProgramLog.Log("Player data was empty");
                        }
                    }

                    if (returnNewInfo)
                    {
//                        ProgramLog.Log("Issuing new loadout");
//                        player.SetPluginData(Key_NewCharacter, true);
                        EnsureSave = true; //Save is now required
                        return new ServerCharacter(StartingOutInfo, player);
                    }
                }
            }

            return null;
        }
        public static Character NewCharacter(
            TContext ctx,
            CharacterMode mode,
            string auth,
            string clientUUID,
            int health,
            int maxHealth,
            int mana,
            int maxMana,
            int spawnX,
            int spawnY,
            int hair,
            byte hairDye,
            int hideVisual,
            byte difficulty,
            uint hairColor,
            uint skinColor,
            uint eyeColor,
            uint shirtColor,
            uint underShirtColor,
            uint pantsColor,
            uint shoeColor, 
            int anglerQuests
        )
        {
            int? userId = null;
            if (mode == CharacterMode.AUTH)
            {
                var user = AuthenticatedUsers.GetUser(auth);
                userId = user.Id;
            }
            else if (mode != CharacterMode.UUID)
                return null;

            Character chr = new Character()
            {
                UserId = userId,
                UUID = clientUUID,
                Health = health,
                MaxHealth = maxHealth,
                Mana = mana,
                MaxMana = maxMana,
                SpawnX = spawnX,
                SpawnY = spawnY,
                Hair = hair,
                HairDye = hairDye,
                HideVisual = hideVisual,
                Difficulty = difficulty,
                HairColor = hairColor,
                SkinColor = skinColor,
                EyeColor = eyeColor,
                ShirtColor = shirtColor,
                UnderShirtColor = underShirtColor,
                PantsColor = pantsColor,
                ShoeColor = shoeColor,
                AnglerQuests = anglerQuests
            };
            ctx.Characters.Add(chr);

            ctx.SaveChanges();

            return chr;
        }
 static void CreateGroup(string name, bool guest, string parent, byte r, byte g, byte b, string[] nodes, TContext ctx,
                         string chatPrefix = null,
                         string chatSuffix = null)
 private static bool SaveCharacterItems(TContext ctx, bool save, Player player, int characterId, Item[] items, ItemType type)
        /// <summary>
        /// Gets the player from the database by name
        /// </summary>
        /// <returns>The player instance.</returns>
        /// <param name="name">Player name.</param>
        public static DbPlayer GetPlayer(string name, IDbConnection connection = null, IDbTransaction transaction = null)
        {
#if ENTITY_FRAMEWORK_7
            using (var ctx = new TContext())
            {
                return ctx.Players
                    .Where(x => x.Name == name)
                    .FirstOrDefault();
            }
#elif DAPPER
            if (connection == null)
            {
                using (var ctx = DatabaseFactory.CreateConnection())
                {
                    using (var txn = ctx.BeginTransaction())
                        return ctx.FirstOrDefault<DbPlayer>(new { Name = name }, transaction: txn);
                }
            }
            else return connection.FirstOrDefault<DbPlayer>(new { Name = name }, transaction: transaction);
#endif
        }
        /// <summary>
        /// Gets the players password.
        /// </summary>
        /// <returns>The players password.</returns>
        /// <param name="name">Player name.</param>
        public static string GetPlayerPasword(string name)
        {
#if ENTITY_FRAMEWORK_7
            using (var ctx = new TContext())
            {
                return ctx.Players
                    .Where(x => x.Name == name)
                    .Select(x => x.Password)
                    .FirstOrDefault();
            }
#elif DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                    return ctx.Where<DbPlayer>(new { Name = name }, transaction: txn)
                    .Select(x => x.Password)
                    .FirstOrDefault();
            }
#endif
        }
        /// <summary>
        /// Checks if a player exists
        /// </summary>
        /// <returns><c>true</c>, if the player exists, <c>false</c> otherwise.</returns>
        /// <param name="name">Player name.</param>
        public static bool PlayerExists(string name)
        {
#if ENTITY_FRAMEWORK_7
            using (var ctx = new TContext())
            {
                return ctx.Players.Any(x => x.Name == name);
            }
#elif DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                    return ctx.Count<DbPlayer>(new { Name = name }, transaction: txn) > 0;
            }
#endif
        }
        private static bool SaveCharacterItem(TContext ctx, bool save, Player player, int characterId, ItemType type, Item item, int slot)
        {
            var netId = 0;
            var prefix = 0;
            var stack = 0;
            var favorite = false;

            if (item != null)
            {
                netId = item.netID;
                prefix = item.prefix;
                stack = item.stack;
                favorite = item.favorited;
            }

            var slotItem = Tables.ItemTable.GetItem(ctx, type, slot, characterId);
            if (slotItem != null)
            {
                if (!Tables.ItemTable.UpdateItem(ctx, save, type, netId, prefix, stack, favorite, slot, characterId))
                {
                    ProgramLog.Error.Log("Failed to save {1} for player: {0}", player.name, type.ToString());
                    return false;
                }
            }
            else
            {
                slotItem = Tables.ItemTable.NewItem(ctx, save, type, netId, prefix, stack, favorite, slot, characterId);
            }

            return true;
        }
        private static bool SaveCharacterItems(TContext ctx, bool save, Player player, int characterId, Item[] items, ItemType type, SlotItem[] existing)
        {
            for (var i = 0; i < items.Length; i++)
            {
                if (!SaveCharacterItem(ctx, save, player, characterId, type, items[i], i, existing)) return false;
            }

            return true;
        }
        /// <summary>
        /// Finds a list of users matching a prefix
        /// </summary>
        /// <returns>The users by prefix.</returns>
        /// <param name="search">Search.</param>
        public static string[] FindPlayersByPrefix(string search, bool includeOp = false)
        {
#if DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                    return ctx.Query<DbPlayer>($"select * from {TableMapper.TypeToName<DbPlayer>()} where {ColumnMapper.Enclose("Name")} like @Name", new { Name = '%' + search + '%' }, transaction: txn)
                    .Select(x => includeOp && x.Operator ? x.Name + " [Op]" : x.Name)
                    .ToArray();
            }
#else
            using (var ctx = new TContext())
            {
#if ENTITY_FRAMEWORK_6
                if (OTA.Data.EF6.OTAContext.IsSQLite)
                {
                    var lowered = search.ToLower();
                    return ctx.Players
                        .Where(x => x.Name.Length >= search.Length && x.Name.Substring(0, search.Length).ToLower() == lowered)
                        .Select(x => x.Name)
                        .ToArray();
                }
                else
                {
#endif
                return ctx.Players
                     .Where(x => x.Name.StartsWith(search))
                     .Select(x => x.Name)
                     .ToArray();
#if ENTITY_FRAMEWORK_6
                }
#endif
#endif
        }
 private static bool SaveCharacterItem(TContext ctx, bool save, Player player, int characterId, ItemType type, Item item, int slot)
        void OnPlayerAuthenticated(ref HookContext ctx, ref TDSMHookArgs.PlayerAuthenticationChanged args)
        {
            if (ctx.Client.State >= 4 && CharacterManager.Mode == CharacterMode.AUTH)
            {
            #if ENTITY_FRAMEWORK_7
                using (var dbCtx = new TContext())
            #elif DAPPER
                using (var dbCtx = DatabaseFactory.CreateConnection())
            #endif
                {
                    using (var txn = dbCtx.BeginTransaction())
                    {
                        CharacterManager.LoadForAuthenticated(dbCtx, txn, ctx.Player, !Config.SSC_AllowGuestInfo);
                        txn.Commit();
                    }
                }

                if (Config.SSC_AllowGuestInfo)
                {
                    ctx.Player.SetSSCReadyForSave(true); //Since we aren't issuing out data, and accepting it, we can save it.
                }
            }
        }
 public static void LoadForAuthenticated(TContext ctx, Player player, bool createIfNone = true)
        void OnPlayerJoin(ref HookContext ctx, ref HookArgs.PlayerEnteredGame args)
        {
            //The player may randomly disconnect at any time, and if it's before the point of saving then the data may be lost.
            //So we must ensure the data is saved.
            //ServerCharacters.CharacterManager.EnsureSave = true;

            #if ENTITY_FRAMEWORK_7
            using (var dbCtx = new TContext())
            #elif DAPPER
            using (var dbCtx = DatabaseFactory.CreateConnection())
            #endif
            {
                using (var txn = dbCtx.BeginTransaction())
                {
                    if (CharacterManager.Mode == CharacterMode.UUID)
                    {
                        CharacterManager.LoadForAuthenticated(dbCtx, txn, ctx.Player, !Config.SSC_AllowGuestInfo);
                    }
                    else if (CharacterManager.Mode == CharacterMode.AUTH)
                    {
                        if (!String.IsNullOrEmpty(ctx.Player.GetAuthenticatedAs()))
                        {
                            CharacterManager.LoadForAuthenticated(dbCtx, txn, ctx.Player, !Config.SSC_AllowGuestInfo);
                        }
                        else
                        {
                            if (!Config.SSC_AllowGuestInfo)
                            {
                                CharacterManager.LoadForGuest(ctx.Player);
                            }
                        }
                    }
                    txn.Commit();
                }
            }
        }
 public void CreateDefaultGroups(TContext ctx)
        public static bool SavePlayerData(TContext ctx, bool save, Player player)
        {
            if (!player.IsAuthenticated()) return false;

            //If using a flat based system ensure the MODE is stored
            string authName = null;
            if (Mode == CharacterMode.AUTH)
            {
                var auth = player.GetAuthenticatedAs();
                if (!String.IsNullOrEmpty(auth))
                    authName = auth;
            }
            else if (Mode == CharacterMode.UUID)
            {
                if (!String.IsNullOrEmpty(player.ClientUUId))
                    authName = player.ClientUUId + '@' + player.name;
            }

            if (!String.IsNullOrEmpty(authName))
            {
                if (Storage.IsAvailable)
                {
                    var auth = player.GetAuthenticatedAs();

                    #if ENTITY_FRAMEWORK_6
                    int userId = 0;
                    if (Mode == CharacterMode.AUTH)
                    {
                        var user = AuthenticatedUsers.GetUser(auth);

                        if (user == null)
                        {
                            OTA.Logging.ProgramLog.Error.Log("No user found ");
                            return false;
                        }

                        userId = user.Id;
                    }
                    else if (Mode != CharacterMode.UUID)
                        return false;

                    //Sync the character
                    var character = ctx.GetCharacter(Mode, userId, player.ClientUUId);
                    if (null == character)
                    {
                        character = ctx.AddCharacter(userId, player);
                    }
                    else character.UpdateCharacter(userId, player);

                    //Sync items
                    var items = ctx.Items.Where(x => x.CharacterId == character.Id).ToArray();

                    if (!SaveCharacterItems(ctx, save, player, character.Id, player.inventory, ItemType.Inventory, items)) return false;
                    if (!SaveCharacterItems(ctx, save, player, character.Id, player.armor, ItemType.Armor, items)) return false;
                    if (!SaveCharacterItems(ctx, save, player, character.Id, player.dye, ItemType.Dye, items)) return false;
                    if (!SaveCharacterItems(ctx, save, player, character.Id, player.miscEquips, ItemType.Equipment, items)) return false;
                    if (!SaveCharacterItems(ctx, save, player, character.Id, player.miscDyes, ItemType.MiscDyes, items)) return false;
                    if (!SaveCharacterItem(ctx, save, player, character.Id, ItemType.Trash, player.trashItem, 0, items)) return false;


                    #elif ENTITY_FRAMEWORK_7
                    #else
                    var character = Tables.CharacterTable.GetCharacter(ctx, Mode, auth, player.ClientUUId);
                    if (character == null)
                    {
//                        if (player.ClearPluginData(Key_NewCharacter))
//                        {
                        character = Tables.CharacterTable.NewCharacter
                            (
                            ctx,
                            Mode,
                            auth,
                            player.ClientUUId,
                            player.statLife,
                            player.statLifeMax,
                            player.statMana,
                            player.statManaMax,
                            player.SpawnX,
                            player.SpawnY,
                            player.hair,
                            player.hairDye,
                            player.hideVisual,
                            player.difficulty,
                            player.hairColor,
                            player.skinColor,
                            player.eyeColor,
                            player.shirtColor,
                            player.underShirtColor,
                            player.pantsColor,
                            player.shoeColor,
                            player.anglerQuestsFinished
                        );
//                        }
//                        else
//                        {
//                            ProgramLog.Error.Log("Failed to save SSC for player: {0}", player.name);
//                            return false;
//                        }
                    }
                    else
                    {
                        character = Tables.CharacterTable.UpdateCharacter
                        (
                            ctx,
                            Mode,
                            auth,
                            player.ClientUUId,
                            player.statLife,
                            player.statLifeMax,
                            player.statMana,
                            player.statManaMax,
                            player.SpawnX,
                            player.SpawnY,
                            player.hair,
                            player.hairDye,
                            player.hideVisual,
                            player.difficulty,
                            player.hairColor,
                            player.skinColor,
                            player.eyeColor,
                            player.shirtColor,
                            player.underShirtColor,
                            player.pantsColor,
                            player.shoeColor,
                            player.anglerQuestsFinished
                        );
                    }

                    if (character != null)
                    {
                        if (!SaveCharacterItems(ctx, save, player, character.Id, player.inventory, ItemType.Inventory)) return false;
                        if (!SaveCharacterItems(ctx, save, player, character.Id, player.armor, ItemType.Armor)) return false;
                        if (!SaveCharacterItems(ctx, save, player, character.Id, player.dye, ItemType.Dye)) return false;
                        if (!SaveCharacterItems(ctx, save, player, character.Id, player.miscEquips, ItemType.Equipment)) return false;
                        if (!SaveCharacterItems(ctx, save, player, character.Id, player.miscDyes, ItemType.MiscDyes)) return false;
                        if (!SaveCharacterItem(ctx, save, player, character.Id, ItemType.Trash, player.trashItem, 0)) return false;

//                        for (var i = 0; i < player.inventory.Length; i++)
//                        {
//                            var item = player.inventory[i];
//                            var netId = 0;
//                            var prefix = 0;
//                            var stack = 0;
//                            var favorite = false;
//
//                            if (item != null)
//                            {
//                                netId = item.netID;
//                                prefix = item.prefix;
//                                stack = item.stack;
//                                favorite = item.favorited;
//                            }
//
//                            var itemId = Tables.ItemTable.GetItem(ItemType.Inventory, i, characterId);
//                            if (itemId > 0)
//                            {
//                                if (!Tables.ItemTable.UpdateItem(ItemType.Inventory, netId, prefix, stack, favorite, i, characterId))
//                                {
//                                    ProgramLog.Error.Log("Failed to save Inventory for player: {0}", player.name);
//                                    return false;
//                                }
//                            }
//                            else
//                            {
//                                itemId = Tables.ItemTable.NewItem(ItemType.Inventory, netId, prefix, stack, favorite, i, characterId);
//                            }
//                        }
//                        for (var i = 0; i < player.armor.Length; i++)
//                        {
//                            var item = player.armor[i];
//                            var netId = 0;
//                            var prefix = 0;
//                            var stack = 0;
//                            var favorite = false;
//
//                            if (item != null)
//                            {
//                                netId = item.netID;
//                                prefix = item.prefix;
//                                stack = item.stack;
//                                favorite = item.favorited;
//                            }
//
//                            var itemId = Tables.ItemTable.GetItem(ItemType.Armor, i, characterId);
//                            if (itemId > 0)
//                            {
//                                if (!Tables.ItemTable.UpdateItem(ItemType.Armor, netId, prefix, stack, favorite, i, characterId))
//                                {
//                                    ProgramLog.Error.Log("Failed to save Armor for player: {0}", player.name);
//                                    return false;
//                                }
//                            }
//                            else
//                            {
//                                itemId = Tables.ItemTable.NewItem(ItemType.Armor, netId, prefix, stack, favorite, i, characterId);
//                            }
//                        }
//                        for (var i = 0; i < player.dye.Length; i++)
//                        {
//                            var item = player.dye[i];
//                            var netId = 0;
//                            var prefix = 0;
//                            var stack = 0;
//                            var favorite = false;
//
//                            if (item != null)
//                            {
//                                netId = item.netID;
//                                prefix = item.prefix;
//                                stack = item.stack;
//                                favorite = item.favorited;
//                            }
//
//                            var itemId = Tables.ItemTable.GetItem(ItemType.Dye, i, characterId);
//                            if (itemId > 0)
//                            {
//                                if (!Tables.ItemTable.UpdateItem(ItemType.Dye, netId, prefix, stack, favorite, i, characterId))
//                                {
//                                    ProgramLog.Error.Log("Failed to save Dye for player: {0}", player.name);
//                                    return false;
//                                }
//                            }
//                            else
//                            {
//                                itemId = Tables.ItemTable.NewItem(ItemType.Dye, netId, prefix, stack, favorite, i, characterId);
//                            }
//                        }
                    }
                    #endif
                }
                else
                {
                    var dir = Path.Combine(Globals.CharacterDataPath, Mode.ToString());
                    if (!Directory.Exists(dir))
                        Directory.CreateDirectory(dir);

                    var file = Path.Combine(dir, authName + ".ssc");
                    var data = new ServerCharacter(player);

//                    if (data.Buffs != null && data.BuffTime != null)
//                    {
//                        var max = Math.Min(data.Buffs.Length, data.BuffTime.Length);
//                        for (var x = 0; x < max; x++)
//                        {
//                            if (data.Buffs[x] > 0)
//                            {
//                                var time = data.BuffTime[x] * 60;
//
//                                ProgramLog.Plugin.Log("Saving buff {0} for {1}/{2}", data.Buffs[x], time, data.BuffTime[x]);
//                            }
//                        }
//                    }

                    var json = Newtonsoft.Json.JsonConvert.SerializeObject(data);
                    System.IO.File.WriteAllText(file, json);
                    return true;
                }
            }
            return false;
        }
        public static Character UpdateCharacter(
            TContext ctx,
            CharacterMode mode,
            string auth,
            string clientUUID,
            int health,
            int maxHealth,
            int mana,
            int maxMana,
            int spawnX,
            int spawnY,
            int hair,
            byte hairDye,
            int hideVisual,
            byte difficulty,
            uint hairColor,
            uint skinColor,
            uint eyeColor,
            uint shirtColor,
            uint underShirtColor,
            uint pantsColor,
            uint shoeColor, 
            int anglerQuests
        )
        {
            int? userId = null;
            if (mode == CharacterMode.AUTH)
            {
                var user = AuthenticatedUsers.GetUser(auth);
                userId = user.Id;
            }
            else if (mode != CharacterMode.UUID)
                return null;

            Character chr;
            if (mode == CharacterMode.AUTH)
            {
                chr = ctx.Characters.Single(x => x.UserId == userId.Value);
            }
            else
            {
                chr = ctx.Characters.Single(x => x.UUID == clientUUID);
            }

            chr.Health = health;
            chr.MaxHealth = maxHealth;
            chr.Mana = mana;
            chr.MaxMana = maxMana;
            chr.SpawnX = spawnX;
            chr.SpawnY = spawnY;
            chr.Hair = hair;
            chr.HairDye = hairDye;
            chr.HideVisual = hideVisual;
            chr.Difficulty = difficulty;
            chr.HairColor = hairColor;
            chr.SkinColor = skinColor;
            chr.EyeColor = eyeColor;
            chr.ShirtColor = shirtColor;
            chr.UnderShirtColor = underShirtColor;
            chr.PantsColor = pantsColor;
            chr.ShoeColor = shoeColor;
            chr.AnglerQuests = anglerQuests;

            ctx.SaveChanges();

            return chr;
        }
        public static void SaveAll()
        {
            if ((DateTime.Now - _lastSave).TotalSeconds >= SaveInterval)
            {
                //Don't perform any unnecessary writes
                var hasPlayers = Netplay.anyClients;
                if (!hasPlayers && !_hadPlayers && !EnsureSave)
                    return;

                EnsureSave = false;
                try
                {
#if ENTITY_FRAMEWORK_7
                    using (var ctx = new TContext())
#elif DAPPER
                    using(var ctx = DatabaseFactory.CreateConnection())
#endif
                    {
                        using (var txn = ctx.BeginTransaction())
                        {
                            foreach (var ply in Terraria.Main.player)
                            {
                                if (ply != null && ply.active && ply.GetSSCReadyForSave())
                                {
                                    SavePlayerData(ctx, txn, false, ply);
                                }
                            }
                            txn.Commit();
                        }

#if ENTITY_FRAMEWORK_7
                        ctx.SaveChanges();
#endif
                    }
                }
                catch (Exception e)
                {
                    ProgramLog.Log(e);
                }

                _hadPlayers = hasPlayers;
                _lastSave = DateTime.Now;
            }
        }
        /// <summary>
        /// Removes a player from the database by name
        /// </summary>
        /// <returns><c>true</c>, if the player was deleted, <c>false</c> otherwise.</returns>
        /// <param name="name">The players name.</param>
        public static bool DeletePlayer(string name)
        {
#if DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                {
                    var res = ctx.Execute($"delete from {TableMapper.TypeToName<DbPlayer>()} where Name = @Name", new { Name = name }, transaction: txn) > 0;
                    txn.Commit();
                    return res;
                }
            }
#else
            using (var ctx = new TContext())
            {
                var matches = ctx.Players.Where(x => x.Name == name);
                ctx.Players.RemoveRange(matches);

                ctx.SaveChanges();

                return ctx.Players.Any(x => x.Name == name);
            }
#endif
        }
        public static void SaveAll()
        {
            if ((DateTime.Now - _lastSave).TotalSeconds >= SaveInterval)
            {
                //Don't perform any unnecessary writes
                var hasPlayers = Netplay.anyClients;
                if (!hasPlayers && !_hadPlayers && !EnsureSave)
                    return;

                EnsureSave = false;
                try
                {
                    using (var ctx = new TContext())
                    {
                        foreach (var ply in Terraria.Main.player)
                        {
                            if (ply != null && ply.active && ply.GetSSCReadyForSave())
                            {
                                SavePlayerData(ctx, false, ply);
                            }
                        }

                        ctx.SaveChanges();
                    }
                }
                catch (Exception e)
                {
                    ProgramLog.Log(e);
                }

                _hadPlayers = hasPlayers;
                _lastSave = DateTime.Now;
            }
        }
 void OnPlayerDisconnected(ref HookContext ctx, ref HookArgs.PlayerLeftGame args)
 {
     if (Terraria.Main.ServerSideCharacter)
     {
     #if ENTITY_FRAMEWORK_7
         using (var dbCtx = new TContext())
     #elif DAPPER
         using (var dbCtx = DatabaseFactory.CreateConnection())
     #endif
         {
             using (var txn = dbCtx.BeginTransaction())
             {
                 CharacterManager.SavePlayerData(dbCtx, txn, true, ctx.Player);
                 txn.Commit();
             }
         }
     }
     if (ctx.Player != null)
     {
         if (CommandDictionary.ContainsKey(ctx.Player.name))
         {
             CommandDictionary.Remove(ctx.Player.name);
         }
         //ProgramLog.Log("{0}", ctx.Player.name); //, args.Prefix + " " + args.ArgumentString);
     }
     #if TDSMServer
     if (RestartWhenNoPlayers && ClientConnection.All.Count - 1 == 0)
     {
     PerformRestart();
     }
     #endif
 }
        /// <summary>
        /// Creates a user.
        /// </summary>
        /// <returns><c>true</c>, if user was created, <c>false</c> otherwise.</returns>
        /// <param name="name">The players name.</param>
        /// <param name="password">Password.</param>
        /// <param name="op">If set to <c>true</c> op.</param>
        public static DbPlayer CreatePlayer(string name, string password, bool op = false)
        {
#if DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                {
                    var player = new DbPlayer(name, password)
                    {
                        Operator = op,
                        DateAdded = DateTime.UtcNow
                    };
                    player.Id = ctx.Insert(player, transaction: txn);

                    var hc = new HookContext();
                    var ha = new Events.HookArgs.PlayerRegistered()
                    {
                        Connection = ctx,
                        Transaction = txn,
                        Player = player
                    };

                    Events.HookPoints.PlayerRegistered.Invoke(ref hc, ref ha);

                    if (hc.Result == HookResult.DEFAULT)
                    {
                        txn.Commit();
                        return player;
                    }
                    else
                    {
                        txn.Rollback();
                        return null;
                    }
                }
            }
#else
            using (var ctx = new TContext())
            {
                DbPlayer player;
                ctx.Players.Add(player = new DbPlayer(name, password)
                {
                    Operator = op,
                    DateAddedUTC = DateTime.UtcNow
                });

                ctx.SaveChanges();

                return player;
            }
#endif
        }
 public static IQueryable <DbPlayer> GetUser(this TContext ctx, string name)
 {
     return(ctx.Players.Where(x => x.Name == name));
 }
        /// <summary>
        /// Updates a player in the database.
        /// </summary>
        /// <returns><c>true</c>, if user was updated, <c>false</c> otherwise.</returns>
        /// <param name="name">The players name.</param>
        /// <param name="password">Password.</param>
        /// <param name="op">If set to <c>true</c> op.</param>
        public static bool UpdatePlayer(string name, string password, bool? op = null)
        {
            if (name == null && op == null) throw new InvalidOperationException("You have not specified anything to be updated");

#if DAPPER
            using (var ctx = DatabaseFactory.CreateConnection())
            {
                using (var txn = ctx.BeginTransaction())
                {
                    var player = ctx.SingleOrDefault<DbPlayer>(new { Name = name }, transaction: txn);
                    if (player == null) throw new InvalidOperationException("Cannot update a non-existent player");

                    if (password != null) player.SetRawPassword(password);
                    if (op.HasValue) player.Operator = op.Value;

                    ctx.Update(player, transaction: txn);

                    txn.Commit();
                    return true;
                }
            }
#else
            using (var ctx = new TContext())
            {
                var player = ctx.Players.SingleOrDefault(p => p.Name == name);
                if (player == null) throw new InvalidOperationException("Cannot update a non-existent player");

                if (password != null) player.SetRawPassword(password);
                if (op.HasValue) player.Operator = op.Value;

                ctx.SaveChanges();

                return true;
            }
#endif
        }