Merge branch 'general-devel' into fix-1904

This commit is contained in:
Lucas Nicodemus 2020-05-25 00:17:35 -07:00 committed by GitHub
commit e9ded60396
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 189 additions and 13 deletions

View file

@ -4,6 +4,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
## Upcoming Release
* Fix pet licenses. (@Olink)
* 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)

View file

@ -0,0 +1,138 @@
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
{
/// <summary>
/// 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.
/// </summary>
public class ResearchDatastore
{
private IDbConnection database;
/// <summary>
/// In-memory cache of what items have been sacrificed.
/// The first call to GetSacrificedItems will load this with data from the database.
/// </summary>
private Dictionary<int, int> _itemsSacrificed;
/// <summary>
/// Initializes a new instance of the <see cref="TShockAPI.DB.ResearchDatastore"/> class.
/// </summary>
/// <param name="db">A valid connection to the TShock database</param>
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)");
}
}
/// <summary>
/// This call will return the memory-cached list of items sacrificed.
/// If the cache is not initialized, it will be initialized from the database.
/// </summary>
/// <returns></returns>
public Dictionary<int, int> GetSacrificedItems()
{
if (_itemsSacrificed == null)
{
_itemsSacrificed = ReadFromDatabase();
}
return _itemsSacrificed;
}
/// <summary>
/// This function will return a Dictionary&lt;ItemId, AmountSacrificed&gt; representing
/// what the progress of research on items is for this world.
/// </summary>
/// <returns>A dictionary of ItemID keys and Amount Sacrificed values.</returns>
private Dictionary<int, int> ReadFromDatabase()
{
Dictionary<int, int> sacrificedItems = new Dictionary<int, int>();
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<Int32>("itemId");
var amount = reader.Get<Int32>("totalSacrificed");
sacrificedItems[itemId] = amount;
}
}
}
catch (Exception ex)
{
TShock.Log.Error(ex.ToString());
}
return sacrificedItems;
}
/// <summary>
/// This method will sacrifice an amount of an item for research.
/// </summary>
/// <param name="itemId">The net ItemId that is being researched.</param>
/// <param name="amount">The amount of items being sacrificed.</param>
/// <param name="player">The player who sacrificed the item for research.</param>
/// <returns>The cumulative total sacrifices for this item.</returns>
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];
}
}
}

View file

@ -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
{
@ -3135,7 +3137,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;
@ -3147,7 +3149,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;
@ -3156,7 +3158,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;
@ -3165,7 +3167,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;
@ -3174,7 +3176,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;
@ -3183,7 +3185,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;
@ -3192,7 +3194,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;
@ -3201,7 +3203,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;
@ -3210,7 +3212,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;
@ -3219,7 +3221,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;
@ -3228,7 +3230,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;
@ -3237,7 +3239,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;
@ -3247,6 +3249,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:

View file

@ -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);
}
}
}
}

View file

@ -100,6 +100,8 @@ namespace TShockAPI
public static RememberedPosManager RememberedPos;
/// <summary>CharacterDB - Static reference to the SSC character manager.</summary>
public static CharacterManager CharacterDB;
/// <summary>Contains the information about what research has been performed in Journey mode.</summary>
public static ResearchDatastore ResearchDatastore;
/// <summary>Config - Static reference to the config system, for accessing values set in users' config files.</summary>
public static ConfigFile Config { get; set; }
/// <summary>ServerSideCharacterConfig - Static reference to the server side character config, for accessing values set by users to modify SSC.</summary>
@ -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();

View file

@ -85,6 +85,7 @@
<Compile Include="CLI\FlagSet.cs" />
<Compile Include="DB\ProjectileManager.cs" />
<Compile Include="DB\RegionManager.cs" />
<Compile Include="DB\ResearchDatastore.cs" />
<Compile Include="DB\TileManager.cs" />
<Compile Include="Extensions\ExceptionExt.cs" />
<Compile Include="Hooks\AccountHooks.cs" />
@ -220,4 +221,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>