using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using Terraria; using Terraria.ID; namespace TShockAPI.DB { /// /// This class is used as the data interface for Journey mode research. /// This information is maintained such that SSC characters will be properly set up with /// the world's current research. /// public class ResearchDatastore { private IDbConnection database; /// /// In-memory cache of what items have been sacrificed. /// The first call to GetSacrificedItems will load this with data from the database. /// private Dictionary _itemsSacrificed; /// /// Initializes a new instance of the class. /// /// A valid connection to the TShock database public ResearchDatastore(IDbConnection db) { database = db; var table = new SqlTable("Research", new SqlColumn("WorldId", MySqlDbType.Int32), new SqlColumn("PlayerId", MySqlDbType.Int32), new SqlColumn("ItemId", MySqlDbType.Int32), new SqlColumn("AmountSacrificed", MySqlDbType.Int32), new SqlColumn("TimeSacrificed", MySqlDbType.DateTime) ); var creator = new SqlTableCreator(db, db.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder)new SqliteQueryCreator() : new MysqlQueryCreator()); try { creator.EnsureTableStructure(table); } catch (DllNotFoundException) { Console.WriteLine("Possible problem with your database - is Sqlite3.dll present?"); throw new Exception("Could not find a database library (probably Sqlite3.dll)"); } } /// /// This call will return the memory-cached list of items sacrificed. /// If the cache is not initialized, it will be initialized from the database. /// /// public Dictionary GetSacrificedItems() { if (_itemsSacrificed == null) { _itemsSacrificed = ReadFromDatabase(); } return _itemsSacrificed; } /// /// This function will return a Dictionary<ItemId, AmountSacrificed> representing /// what the progress of research on items is for this world. /// /// A dictionary of ItemID keys and Amount Sacrificed values. private Dictionary ReadFromDatabase() { Dictionary sacrificedItems = new Dictionary(); var sql = @"select itemId, sum(AmountSacrificed) totalSacrificed from Research where WorldId = @0 group by itemId"; try { using (var reader = database.QueryReader(sql, Main.worldID)) { while (reader.Read()) { var itemId = reader.Get("itemId"); var amount = reader.Get("totalSacrificed"); sacrificedItems[itemId] = amount; } } } catch (Exception ex) { TShock.Log.Error(ex.ToString()); } return sacrificedItems; } /// /// This method will sacrifice an amount of an item for research. /// /// The net ItemId that is being researched. /// The amount of items being sacrificed. /// The player who sacrificed the item for research. /// The cumulative total sacrifices for this item. public int SacrificeItem(int itemId, int amount, TSPlayer player) { var itemsSacrificed = GetSacrificedItems(); if (!(itemsSacrificed.ContainsKey(itemId))) itemsSacrificed[itemId] = 0; var sql = @"insert into Research (WorldId, PlayerId, ItemId, AmountSacrificed, TimeSacrificed) values (@0, @1, @2, @3, @4)"; var result = 0; try { result = database.Query(sql, Main.worldID, player.Account.ID, itemId, amount, DateTime.Now); } catch (Exception ex) { TShock.Log.Error(ex.ToString()); } if (result == 1) { itemsSacrificed[itemId] += amount; } return itemsSacrificed[itemId]; } } }