public static async Task <Gotchi> GetGotchiAsync(this SQLiteDatabase database, ICreator creator)
        {
            GotchiUserInfo userData = await database.GetUserInfoAsync(creator);

            // Get this user's primary Gotchi.

            Gotchi gotchi = await database.GetGotchiAsync(userData.PrimaryGotchiId);

            // If this user's primary gotchi doesn't exist (either it was never set or no longer exists), pick a primary gotchi from their current gotchis.

            if (gotchi is null)
            {
                IEnumerable <Gotchi> gotchis = await database.GetGotchisAsync(userData.UserId);

                if (gotchis.Count() > 0)
                {
                    gotchi = gotchis.First();

                    userData.PrimaryGotchiId = gotchi.Id;

                    await database.UpdateUserInfoAsync(userData);
                }
            }

            return(gotchi);
        }
        private async Task DoAutoFeederAsync(ulong userId, SQLiteDatabase database, IEnumerable <Gotchi> userGotchis)
        {
            // Auto-feeder

            if ((await database.GetItemFromInventoryAsync(userId, GotchiItemId.AutoFeeder)).Count > 0)
            {
                GotchiUserInfo userInfo = await database.GetUserInfoAsync(userId);

                const int costPerFeeding = 5;

                if (userInfo != null && userInfo.G >= costPerFeeding)
                {
                    int gotchisFed = userGotchis.Where(g => g.IsHungry).Count();

                    if (gotchisFed > 0)
                    {
                        await database.FeedGotchisAsync(Global.GotchiContext, userId);

                        userInfo.G = Math.Max(0, userInfo.G - (costPerFeeding * gotchisFed));

                        await database.UpdateUserInfoAsync(userInfo);
                    }
                }
            }
        }
        public static async Task UpdateUserInfoAsync(this SQLiteDatabase database, GotchiUserInfo userInfo)
        {
            using (SQLiteCommand cmd = new SQLiteCommand("INSERT OR REPLACE INTO GotchiUser(user_id, g, gotchi_limit, primary_gotchi_id) VALUES ($user_id, $g, $gotchi_limit, $primary_gotchi_id)")) {
                cmd.Parameters.AddWithValue("$user_id", userInfo.UserId);
                cmd.Parameters.AddWithValue("$g", userInfo.G);
                cmd.Parameters.AddWithValue("$gotchi_limit", userInfo.GotchiLimit);
                cmd.Parameters.AddWithValue("$primary_gotchi_id", userInfo.PrimaryGotchiId);

                await database.ExecuteNonQueryAsync(cmd);
            }
        }
        // Public members

        public static async Task AddGotchiAsync(this SQLiteDatabase database, ICreator user, ISpecies species)
        {
            // Generate a unique name for the user's gotchi, but duplicate names are allowed if necessary (e.g. all generated names exhausted).

            IEnumerable <Gotchi> existingGotchis = await database.GetGotchisAsync(user);

            IGotchiNameGenerator nameGenerator = new GotchiNameGenerator();

            string    name = nameGenerator.GetName(user, species);
            const int maxNamingAttempts = 10;

            for (int i = 0; i < maxNamingAttempts && existingGotchis.Any(gotchi => gotchi.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); ++i)
            {
                name = nameGenerator.GetName(user, species);
            }

            // Add the Gotchi to the database.

            long ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

            using (SQLiteCommand cmd = new SQLiteCommand("INSERT INTO Gotchi(species_id, name, owner_id, fed_ts, born_ts, died_ts, evolved_ts) VALUES($species_id, $name, $owner_id, $fed_ts, $born_ts, $died_ts, $evolved_ts)")) {
                cmd.Parameters.AddWithValue("$species_id", species.Id);
                cmd.Parameters.AddWithValue("$owner_id", user.UserId);
                cmd.Parameters.AddWithValue("$name", name.ToLower());
                cmd.Parameters.AddWithValue("$fed_ts", ts - 60 * 60); // subtract an hour to keep it from eating immediately after creation
                cmd.Parameters.AddWithValue("$born_ts", ts);
                cmd.Parameters.AddWithValue("$died_ts", 0);
                cmd.Parameters.AddWithValue("$evolved_ts", ts);

                await database.ExecuteNonQueryAsync(cmd);
            }

            // Set this gotchi as the user's primary Gotchi.

            GotchiUserInfo user_data = await database.GetUserInfoAsync(user);

            using (SQLiteCommand cmd = new SQLiteCommand("SELECT id FROM Gotchi WHERE owner_id = $owner_id AND born_ts = $born_ts")) {
                cmd.Parameters.AddWithValue("$owner_id", user.UserId);
                cmd.Parameters.AddWithValue("$born_ts", ts);

                user_data.PrimaryGotchiId = await database.GetScalarAsync <long>(cmd);
            }

            await database.UpdateUserInfoAsync(user_data);
        }