From 6eb80389910ec642106372ff5f45f19ae759047b Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sun, 24 May 2020 22:19:10 -0700 Subject: [PATCH 1/5] Refactor grammar of permission error --- TShockAPI/GetDataHandlers.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index d5e3b2c7..6c9cec8c 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -3126,7 +3126,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_timefreeze)) { - args.Player.SendErrorMessage("You have no permission to freeze the time of the server!"); + args.Player.SendErrorMessage("You don't have permission to freeze the time of the server!"); return true; } break; @@ -3138,7 +3138,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_timeset)) { - args.Player.SendErrorMessage("You have no permission to modify the time of the server!"); + args.Player.SendErrorMessage("You don't have permission to modify the time of the server!"); return true; } break; @@ -3147,7 +3147,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_godmode)) { - args.Player.SendErrorMessage("You have no permission to toggle godmode!"); + args.Player.SendErrorMessage("You don't have permission to toggle godmode!"); return true; } break; @@ -3156,7 +3156,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_windstrength)) { - args.Player.SendErrorMessage("You have no permission to modify the wind strength of the server!"); + args.Player.SendErrorMessage("You don't have permission to modify the wind strength of the server!"); return true; } break; @@ -3165,7 +3165,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_rainstrength)) { - args.Player.SendErrorMessage("You have no permission to modify the rain strength of the server!"); + args.Player.SendErrorMessage("You don't have permission to modify the rain strength of the server!"); return true; } break; @@ -3174,7 +3174,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_timespeed)) { - args.Player.SendErrorMessage("You have no permission to modify the time speed of the server!"); + args.Player.SendErrorMessage("You don't have permission to modify the time speed of the server!"); return true; } break; @@ -3183,7 +3183,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_rainfreeze)) { - args.Player.SendErrorMessage("You have no permission to freeze the rain strength of the server!"); + args.Player.SendErrorMessage("You don't have permission to freeze the rain strength of the server!"); return true; } break; @@ -3192,7 +3192,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_windfreeze)) { - args.Player.SendErrorMessage("You have no permission to freeze the wind strength of the server!"); + args.Player.SendErrorMessage("You don't have permission to freeze the wind strength of the server!"); return true; } break; @@ -3201,7 +3201,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_placementrange)) { - args.Player.SendErrorMessage("You have no permission to modify the tile placement range of your character!"); + args.Player.SendErrorMessage("You don't have permission to modify the tile placement range of your character!"); return true; } break; @@ -3210,7 +3210,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_setdifficulty)) { - args.Player.SendErrorMessage("You have no permission to modify the world dificulty of the server!"); + args.Player.SendErrorMessage("You don't have permission to modify the world dificulty of the server!"); return true; } break; @@ -3219,7 +3219,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_biomespreadfreeze)) { - args.Player.SendErrorMessage("You have no permission to freeze the biome spread of server!"); + args.Player.SendErrorMessage("You don't have permission to freeze the biome spread of server!"); return true; } break; @@ -3228,7 +3228,7 @@ namespace TShockAPI { if (!args.Player.HasPermission(Permissions.journey_setspawnrate)) { - args.Player.SendErrorMessage("You have no permission to modify the NPC spawn rate of server!"); + args.Player.SendErrorMessage("You don't have permission to modify the NPC spawn rate of server!"); return true; } break; From 56b695b80bbe06a914066138c394e4541404209d Mon Sep 17 00:00:00 2001 From: Olink Date: Mon, 25 May 2020 02:24:03 -0400 Subject: [PATCH 2/5] Add initial support for Journey mode in SSC. --- TShockAPI/DB/ResearchDatastore.cs | 123 ++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 16 ++++ TShockAPI/PlayerData.cs | 17 +++++ TShockAPI/TShock.cs | 3 + TShockAPI/TShockAPI.csproj | 3 +- 5 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 TShockAPI/DB/ResearchDatastore.cs diff --git a/TShockAPI/DB/ResearchDatastore.cs b/TShockAPI/DB/ResearchDatastore.cs new file mode 100644 index 00000000..d4fa2197 --- /dev/null +++ b/TShockAPI/DB/ResearchDatastore.cs @@ -0,0 +1,123 @@ +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) + { + System.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"; + + using (var reader = database.QueryReader(sql, Main.worldID)) + { + while (reader.Read()) + { + var itemId = reader.Get("itemId"); + var amount = reader.Get("totalSacrificed"); + sacrificedItems[itemId] = amount; + } + } + + 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 = database.Query(sql, Main.worldID, player.Account.ID, itemId, amount, DateTime.Now); + if (result == 1) + { + itemsSacrificed[itemId] += amount; + } + + return itemsSacrificed[itemId]; + } + } +} diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index d5e3b2c7..4ea4d729 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -39,6 +39,8 @@ using TShockAPI.Localization; using TShockAPI.Models; using TShockAPI.Models.PlayerUpdate; using TShockAPI.Models.Projectiles; +using Terraria.Net; +using Terraria.GameContent.NetModules; namespace TShockAPI { @@ -3238,6 +3240,20 @@ namespace TShockAPI return true; } } + } else if (moduleId == (int)NetModulesTypes.CreativeUnlocksPlayerReport) + { + var unknownField = args.Data.ReadByte(); + + if (unknownField == 0) //this is required or something??? + { + var itemId = args.Data.ReadUInt16(); + var amount = args.Data.ReadUInt16(); + + var totalSacrificed = TShock.ResearchDatastore.SacrificeItem(itemId, amount, args.Player); + + var response = NetCreativeUnlocksModule.SerializeItemSacrifice(itemId, totalSacrificed); + NetManager.Instance.Broadcast(response); + } } // As of 1.4.x.x, this is now used for more things: diff --git a/TShockAPI/PlayerData.cs b/TShockAPI/PlayerData.cs index 64a33676..6e649768 100644 --- a/TShockAPI/PlayerData.cs +++ b/TShockAPI/PlayerData.cs @@ -20,6 +20,9 @@ using Microsoft.Xna.Framework; using Terraria; using TShockAPI; using Terraria.Localization; +using Terraria.GameContent.NetModules; +using Terraria.Net; +using Terraria.ID; namespace TShockAPI { @@ -480,6 +483,20 @@ namespace TShockAPI NetMessage.SendData(76, -1, -1, NetworkText.Empty, player.Index); NetMessage.SendData(39, player.Index, -1, NetworkText.Empty, 400); + + + var sacrificedItems = TShock.ResearchDatastore.GetSacrificedItems(); + for(int i = 0; i < ItemID.Count; i++) + { + var amount = 0; + if (sacrificedItems.ContainsKey(i)) + { + amount = sacrificedItems[i]; + } + + var response = NetCreativeUnlocksModule.SerializeItemSacrifice(i, amount); + NetManager.Instance.SendToClient(response, player.TPlayer.whoAmI); + } } } } diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index c1032d43..aa1791d5 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -100,6 +100,8 @@ namespace TShockAPI public static RememberedPosManager RememberedPos; /// CharacterDB - Static reference to the SSC character manager. public static CharacterManager CharacterDB; + /// Contains the information about what research has been performed in Journey mode. + public static ResearchDatastore ResearchDatastore; /// Config - Static reference to the config system, for accessing values set in users' config files. public static ConfigFile Config { get; set; } /// ServerSideCharacterConfig - Static reference to the server side character config, for accessing values set by users to modify SSC. @@ -324,6 +326,7 @@ namespace TShockAPI TileBans = new TileManager(DB); RememberedPos = new RememberedPosManager(DB); CharacterDB = new CharacterManager(DB); + ResearchDatastore = new ResearchDatastore(DB); RestApi = new SecureRest(Netplay.ServerIP, Config.RestApiPort); RestManager = new RestManager(RestApi); RestManager.RegisterRestfulCommands(); diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 02b9e43e..c941ea0a 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -85,6 +85,7 @@ + @@ -220,4 +221,4 @@ --> - \ No newline at end of file + From 96ad7a5dd89c8d82ebb2ddbd8bbe4b72d620ca6e Mon Sep 17 00:00:00 2001 From: Olink Date: Mon, 25 May 2020 02:26:58 -0400 Subject: [PATCH 3/5] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d6864e..783a1b99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ This is the rolling changelog for TShock for Terraria. Use past tense when adding new entries; sign your name off when you add or change something. This should primarily be things like user changes, not necessarily codebase changes unless it's really relevant or large. +## Upcoming Release +* Initial support for Journey mode in SSC worlds. (@Olink) + ## TShock 4.4.0 (Pre-release 8) * Update for OTAPI 2.0.0.36 and Terraria 1.4.0.4. (@hakusaro, @Patrikkk, @DeathCradle) * Fixed /wind command. (@AxeelAnder) From df22a331323773d2db0eaec448037909a6837f23 Mon Sep 17 00:00:00 2001 From: Olink Date: Mon, 25 May 2020 03:07:54 -0400 Subject: [PATCH 4/5] Add some try/catch blocks around the sql commands. --- TShockAPI/DB/ResearchDatastore.cs | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/TShockAPI/DB/ResearchDatastore.cs b/TShockAPI/DB/ResearchDatastore.cs index d4fa2197..b861aedd 100644 --- a/TShockAPI/DB/ResearchDatastore.cs +++ b/TShockAPI/DB/ResearchDatastore.cs @@ -84,16 +84,21 @@ namespace TShockAPI.DB where WorldId = @0 group by itemId"; - using (var reader = database.QueryReader(sql, Main.worldID)) - { - while (reader.Read()) + try { + using (var reader = database.QueryReader(sql, Main.worldID)) { - var itemId = reader.Get("itemId"); - var amount = reader.Get("totalSacrificed"); - sacrificedItems[itemId] = amount; + 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; } @@ -111,7 +116,17 @@ namespace TShockAPI.DB itemsSacrificed[itemId] = 0; var sql = @"insert into Research (WorldId, PlayerId, ItemId, AmountSacrificed, TimeSacrificed) values (@0, @1, @2, @3, @4)"; - var result = database.Query(sql, Main.worldID, player.Account.ID, itemId, amount, DateTime.Now); + + 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; From 2b4faf4d9b0d87b8a5927d7cc15b39d304c79ee0 Mon Sep 17 00:00:00 2001 From: Zack Date: Mon, 25 May 2020 03:11:41 -0400 Subject: [PATCH 5/5] Update TShockAPI/DB/ResearchDatastore.cs @hakusaro raised a solid point in Discord. Co-authored-by: Lucas Nicodemus --- TShockAPI/DB/ResearchDatastore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TShockAPI/DB/ResearchDatastore.cs b/TShockAPI/DB/ResearchDatastore.cs index b861aedd..cb7d933c 100644 --- a/TShockAPI/DB/ResearchDatastore.cs +++ b/TShockAPI/DB/ResearchDatastore.cs @@ -50,7 +50,7 @@ namespace TShockAPI.DB } catch (DllNotFoundException) { - System.Console.WriteLine("Possible problem with your database - is Sqlite3.dll present?"); + Console.WriteLine("Possible problem with your database - is Sqlite3.dll present?"); throw new Exception("Could not find a database library (probably Sqlite3.dll)"); } }