diff --git a/ModExamples/13AddTraderWithAssortJson/AddTraderHelper.cs b/ModExamples/13AddTraderWithAssortJson/AddTraderHelper.cs new file mode 100644 index 00000000..c0cc3b36 --- /dev/null +++ b/ModExamples/13AddTraderWithAssortJson/AddTraderHelper.cs @@ -0,0 +1,84 @@ +using Core.Models.Common; +using Core.Models.Eft.Common.Tables; +using Core.Models.Spt.Config; +using Core.Models.Spt.Server; +using Core.Utils; + +namespace _13AddTraderWithAssortJson +{ + public class AddTraderHelper + { + /** + * Add record to trader config to set the refresh time of trader in seconds (default is 60 minutes) + * @param traderConfig trader config to add our trader to + * @param baseJson json file for trader (db/base.json) + * @param refreshTimeSecondsMin How many seconds between trader stock refresh min time + * @param refreshTimeSecondsMax How many seconds between trader stock refresh max time + */ + public void SetTraderUpdateTime(TraderConfig traderConfig, dynamic baseJson, int refreshTimeSecondsMin, int refreshTimeSecondsMax) + { + // Add refresh time in seconds to config + var traderRefreshRecord = new UpdateTime + { + TraderId = baseJson.id, + Seconds = new MinMax(refreshTimeSecondsMin, refreshTimeSecondsMax) + }; + + + traderConfig.UpdateTime.Add(traderRefreshRecord); + } + + /** + * Add our new trader to the database + * @param traderDetailsToAdd trader details + * @param tables database + * @param jsonUtil json utility class + */ + public void AddTraderToDb(dynamic traderDetailsToAdd, DatabaseTables tables, JsonUtil jsonUtil, object assortJson) + { + // Create trader data ready to add to database + var traderDataToAdd = new Trader + { + Assort = + jsonUtil.Deserialize( + jsonUtil.Serialize(assortJson)), // Deserialise/serialise creates a copy of the json + Base = + jsonUtil.Deserialize( + jsonUtil.Serialize(traderDetailsToAdd)), // Deserialise/serialise creates a copy of the json + QuestAssort = new Dictionary> // questassort is empty as trader has no assorts unlocked by quests + { + { "Started", new Dictionary() }, + { "Success", new Dictionary() }, + { "Fail", new Dictionary() } + } + }; + + // Add trader to trader table, key is the traders id + tables.Traders.Add(traderDetailsToAdd._id, traderDataToAdd); + } + + /** + * Add traders name/location/description to the locale table + * @param baseJson json file for trader (db/base.json) + * @param tables database tables + * @param fullName Complete name of trader + * @param firstName First name of trader + * @param nickName Nickname of trader + * @param location Location of trader (e.g. "Here in the cat shop") + * @param description Description of trader + */ + public void AddTraderToLocales(dynamic baseJson, DatabaseTables tables, string fullName, string firstName, string nickName, string location, string description) + { + // For each language, add locale for the new trader + var locales = tables.Locales.Global; + + foreach (var (key, value) in locales) { + value.Value[$"{baseJson._id} FullName"] = fullName; + value.Value[$"{baseJson._id} FirstName"] = firstName; + value.Value[$"{baseJson._id} Nickname"] = nickName; + value.Value[$"{baseJson._id} Location"] = location; + value.Value[$"{baseJson._id} Description"] = description; + } + } + } +} diff --git a/ModExamples/13AddTraderWithAssortJson/AddTraderWithAssortJson.cs b/ModExamples/13AddTraderWithAssortJson/AddTraderWithAssortJson.cs new file mode 100644 index 00000000..d3065790 --- /dev/null +++ b/ModExamples/13AddTraderWithAssortJson/AddTraderWithAssortJson.cs @@ -0,0 +1,86 @@ +using Core.Models.Eft.Common.Tables; +using Core.Models.External; +using Core.Models.Spt.Config; +using Core.Models.Utils; +using Core.Routers; +using Core.Servers; +using Core.Services; +using Core.Utils; + +namespace _13AddTraderWithAssortJson +{ + public class AddTraderWithAssortJson : IPostDBLoadMod + { + private readonly ISptLogger _logger; + private readonly JsonUtil _jsonUtil; + private readonly FileUtil _fileUtil; + private readonly DatabaseService _databaseService; + private readonly ImageRouter _imageRouter; + private readonly ConfigServer _configServer; + private readonly TraderConfig _traderConfig; + private readonly RagfairConfig _ragfairConfig; + + public AddTraderWithAssortJson( + ISptLogger logger, + JsonUtil jsonUtil, + FileUtil fileUtil, + DatabaseService databaseService, + ImageRouter imageRouter, + ConfigServer configServer) + { + _logger = logger; + _jsonUtil = jsonUtil; + _fileUtil = fileUtil; + _databaseService = databaseService; + _imageRouter = imageRouter; + _configServer = configServer; + + _traderConfig = _configServer.GetConfig(); + _ragfairConfig = _configServer.GetConfig(); + } + + public void PostDBLoad() + { + var traderImagePath = "./db/cat.jpg"; + + var baseJson = _fileUtil.ReadFile("./db/base.json"); + var traderBase = _jsonUtil.Deserialize(baseJson); + + var assortJson = _fileUtil.ReadFile("./db/assort.json"); + var assort = _jsonUtil.Deserialize(assortJson); + + // Create helper class and use it to register our traders image/icon + set its stock refresh time + var addTraderHelper = new AddTraderHelper(); + _imageRouter.AddRoute(traderBase.Avatar.Replace(".jpg", ""), System.IO.Path.GetFullPath(traderImagePath)); + addTraderHelper.SetTraderUpdateTime(_traderConfig, traderBase, 3600, 4000); + + // Add trader to flea market + _ragfairConfig.Traders[traderBase.Id] = true; + + // Add new trader to the trader dictionary in DatabaseServer - this is where the assort json is loaded + /* + * The assortJSON includes the following: + * Milk available for roubles at LL1 + * Milk available for item barter at LL1 + * Helmet w/ soft armour available for roubles at LL1 + * Helmet w/ soft armour available for item barter at LL1 + * + * It is *REQUIRED* to use MongoIDs for IDs in the assort + */ + addTraderHelper.AddTraderToDb( + baseJson, + _databaseService.GetTables(), + _jsonUtil, + assortJson); + + addTraderHelper.AddTraderToLocales( + baseJson, + _databaseService.GetTables(), + traderBase.Name, + "Cat", + traderBase.Nickname, + traderBase.Location, + "This is the cat shop. Meow."); + } + } +} diff --git a/ModExamples/13AddTraderWithAssortJson/Class1.cs b/ModExamples/13AddTraderWithAssortJson/Class1.cs deleted file mode 100644 index 73cff41d..00000000 --- a/ModExamples/13AddTraderWithAssortJson/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace _13AddTraderWithAssortJson -{ - public class Class1 - { - - } -} diff --git a/ModExamples/13AddTraderWithAssortJson/data/assort.json b/ModExamples/13AddTraderWithAssortJson/data/assort.json new file mode 100644 index 00000000..d7321ed0 --- /dev/null +++ b/ModExamples/13AddTraderWithAssortJson/data/assort.json @@ -0,0 +1,132 @@ +{ + "items": [ + { + "_name": "milk", + "_id": "6751d7d0ac6207409b0823a0", + "_tpl": "575146b724597720a27126d5", + "parentId": "hideout", + "slotId": "hideout", + "upd": { + "UnlimitedCount": false, + "StackObjectsCount": 200, + "BuyRestrictionMax": 10, + "BuyRestrictionCurrent": 0 + } + }, + { + "_name": "milk barter", + "_id": "6751d7d0ac6207409b0823a1", + "_tpl": "575146b724597720a27126d5", + "parentId": "hideout", + "slotId": "hideout", + "upd": { + "UnlimitedCount": false, + "StackObjectsCount": 200, + "BuyRestrictionMax": 10, + "BuyRestrictionCurrent": 0 + } + }, + { + "_name": "helmet", + "_id": "6751d7d0ac6207409b0823a2", + "_tpl": "5b40e3f35acfc40016388218", + "parentId": "hideout", + "slotId": "hideout", + "upd": { + "UnlimitedCount": false, + "StackObjectsCount": 200, + "BuyRestrictionMax": 10, + "BuyRestrictionCurrent": 0 + } + }, + { + "_name": "HELMET_SOFT_ARMOUR_TOP", + "_id": "6751d7d0ac6207409b0823a3", + "_tpl": "657f95bff92cd718b701550c", + "parentId": "HELMET_ID", + "slotId": "Helmet_top" + }, + { + "_name": "HELMET_SOFT_ARMOUR_BACK_ID", + "_id": "6751d7d0ac6207409b0823a4", + "_tpl": "657f9605f4c82973640b2358", + "parentId": "HELMET_ID", + "slotId": "Helmet_back" + }, + { + "_name": "HELMET_ID_BARTER", + "_id": "6751d7d0ac6207409b0823a5", + "_tpl": "5b40e3f35acfc40016388218", + "parentId": "hideout", + "slotId": "hideout", + "upd": { + "UnlimitedCount": false, + "StackObjectsCount": 200, + "BuyRestrictionMax": 10, + "BuyRestrictionCurrent": 0 + } + }, + { + "_name": "HELMET_SOFT_ARMOUR_TOP_ID_BARTER", + "_id": "6751d7d0ac6207409b0823a5", + "_tpl": "657f95bff92cd718b701550c", + "parentId": "HELMET_ID_BARTER", + "slotId": "Helmet_top" + }, + { + "_name": "HELMET_SOFT_ARMOUR_BACK_ID_BARTER", + "_id": "6751d7d0ac6207409b0823a6", + "_tpl": "657f9605f4c82973640b2358", + "parentId": "HELMET_ID_BARTER", + "slotId": "Helmet_back" + } + ], + "barter_scheme": { + "6751d7d0ac6207409b0823a0": [ + [ + { + "count": 2000, + "_tpl": "5449016a4bdc2d6f028b456f" + } + ] + ], + "6751d7d0ac6207409b0823a1": [ + [ + { + "count": 3, + "_tpl": "59faff1d86f7746c51718c9c" + }, + { + "count": 1, + "_tpl": "544fb45d4bdc2dee738b4568" + } + ] + ], + "6751d7d0ac6207409b0823a2": [ + [ + { + "count": 2000, + "_tpl": "5449016a4bdc2d6f028b456f" + } + ] + ], + "6751d7d0ac6207409b0823a5": [ + [ + { + "count": 3, + "_tpl": "59faff1d86f7746c51718c9c" + }, + { + "count": 1, + "_tpl": "544fb45d4bdc2dee738b4568" + } + ] + ] + }, + "loyal_level_items": { + "6751d7d0ac6207409b0823a0": 1, + "6751d7d0ac6207409b0823a1": 1, + "6751d7d0ac6207409b0823a2": 1, + "6751d7d0ac6207409b0823a5": 1 + } +} diff --git a/ModExamples/13AddTraderWithAssortJson/package.json b/ModExamples/13AddTraderWithAssortJson/package.json new file mode 100644 index 00000000..5adc350e --- /dev/null +++ b/ModExamples/13AddTraderWithAssortJson/package.json @@ -0,0 +1,13 @@ +{ + "Name": "1313AddTraderWithAssortJson", + "Version": "1.0.0", + "SptVersion": "~4.0", + "LoadBefore": [], + "LoadAfter": [], + "IncompatibileMods": [], + "Url": "https://github.com/sp-tarkov/server-csharp/tree/develop/ExampleMods/Mods", + "IsBundleMod": false, + "Author": "SPT", + "Contributors": [], + "Licence": "MIT" +} diff --git a/ModExamples/ModExamples.sln b/ModExamples/ModExamples.sln index 6bab9086..b4f6f8a4 100644 --- a/ModExamples/ModExamples.sln +++ b/ModExamples/ModExamples.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.12.35527.113 d17.12 +VisualStudioVersion = 17.12.35527.113 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "1Logging", "1Logging\1Logging.csproj", "{98270ED7-04C7-4F90-91B1-820C672CE123}" EndProject @@ -91,9 +91,6 @@ Global {636D5797-E37F-425A-B8DB-E3FBE4573F71}.Debug|Any CPU.Build.0 = Debug|Any CPU {636D5797-E37F-425A-B8DB-E3FBE4573F71}.Release|Any CPU.ActiveCfg = Release|Any CPU {636D5797-E37F-425A-B8DB-E3FBE4573F71}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE {B4DDC0E8-99D1-405E-9E01-823523FE642B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B4DDC0E8-99D1-405E-9E01-823523FE642B}.Debug|Any CPU.Build.0 = Debug|Any CPU {B4DDC0E8-99D1-405E-9E01-823523FE642B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -103,4 +100,7 @@ Global {15F2B434-439E-498E-9B85-B7BBC2F4AFA4}.Release|Any CPU.ActiveCfg = Release|Any CPU {15F2B434-439E-498E-9B85-B7BBC2F4AFA4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection EndGlobal