diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.yml b/.github/ISSUE_TEMPLATE/1-bug-report.yml index a9c358fd..c9373da6 100644 --- a/.github/ISSUE_TEMPLATE/1-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/1-bug-report.yml @@ -12,7 +12,7 @@ body: - You must be able to replicate the issue with a fresh profile, running no mods. If you can't, we can't fix it. - If you are using a profile from an older version, please make a fresh profile and replicate the issue before submitting. - You must upload all the required log files, even if you think they are useless. - - Failure to comply with any of the above requirements will result in your issue being closed without notice. + - Failure to comply with any of the above requirements will result in your issue being closed without notice. - type: dropdown id: version attributes: @@ -59,7 +59,7 @@ body: id: log_server attributes: label: "Server Log" - description: "Upload a copy of your *entire* server log: `/user/logs/spt/spt.txt`." + description: "Upload a copy of your *entire* server log: `SPT/user/logs/spt/spt.txt`." placeholder: "Attach the log file. Do not paste the contents." validations: required: true @@ -83,7 +83,7 @@ body: id: profile attributes: label: "Player Profile" - description: "If helpful, upload a copy of your *entire* player profile: `/user/profiles/.json`." + description: "If helpful, upload a copy of your *entire* player profile: `SPT/user/profiles/.json`." placeholder: "Attach the profile file. Do not paste the contents." validations: required: false diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/bot.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/bot.json index c482fae2..7bc5ea6b 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/bot.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/bot.json @@ -2838,5 +2838,6 @@ "bossKnight" ], "resetDay": "Monday" - } + }, + "replaceScavWith": "assault" } diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/core.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/core.json index e3e38886..01bcb2d9 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/core.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/core.json @@ -190,7 +190,7 @@ "giveCommandEnabled": true }, "commandUseLimits": { - "StashRows": 29 + "StashRows": 28 }, "ids": { "commando": "6723fd51c5924c57ce0ca01e", diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/item.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/item.json index 0fdd5179..7fff618d 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/item.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/item.json @@ -584,7 +584,10 @@ "68418091b5b0c9e4c60f0e7a", "684180ee9b6d80d840042e8a", "684181208d035f60230f63f9", - "6866665cdf54e1190902df55" + "6866665cdf54e1190902df55", + "6841b6b674a3c16f5e03d653", + "679bab714e9ca6b3d80586b4", + "64d4b23dc1b37504b41ac2b6" ], "rewardItemTypeBlacklist": [ "65649eb40bf0ed77b8044453" diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/pmc.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/pmc.json index 27c89a2c..f7ccb311 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/pmc.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/pmc.json @@ -182,11 +182,9 @@ "pmcType": { "pmcbear": { "factory4_day": { - "bossTagilla": 1, "pmcBEAR": 10 }, "factory4_night": { - "bossTagilla": 1, "pmcBEAR": 10 }, "bigmap": { @@ -225,11 +223,9 @@ }, "pmcusec": { "factory4_day": { - "bossTagilla": 1, "pmcUSEC": 10 }, "factory4_night": { - "bossTagilla": 1, "pmcUSEC": 10 }, "bigmap": { diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/weather.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/weather.json index 307e03aa..c097f584 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/weather.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/weather.json @@ -37,7 +37,7 @@ "max": 0 }, "fog": { - "0.0013": 35, + "0.0013": 30, "0.0018": 6, "0.002": 4, "0.004": 3, @@ -60,12 +60,14 @@ }, "RAINY": { "clouds": { - "0.4": 5, - "1": 4 + "0.7": 2, + "0.9": 4, + "1": 4, + "1.2": 1 }, "windSpeed": { - "0": 6, - "1": 3, + "0": 3, + "1": 2, "2": 2, "3": 1, "4": 1 diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/bear.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/bear.json index 019651b4..cd46e67c 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/bear.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/bear.json @@ -2976,7 +2976,9 @@ "YukoVR", "ZenosBleed", "chrispawl89", - "hulkhan" + "hulkhan", + "LycorisOni", + "Quik" ], "generation": { "items": { diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/usec.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/usec.json index 91a9c8f4..a929c419 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/usec.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/bots/types/usec.json @@ -2967,7 +2967,9 @@ "YukoVR", "ZenosBleed", "chrispawl89", - "hulkhan" + "hulkhan", + "LycorisOni", + "Quik" ], "generation": { "items": { diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/bigmap/base.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/bigmap/base.json index c30682fb..dc999218 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/bigmap/base.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/bigmap/base.json @@ -138,7 +138,7 @@ "TriggerName": "" }, { - "BossChance": 0, + "BossChance": 18, "BossDifficult": "normal", "BossEscortAmount": "2", "BossEscortDifficult": "normal", diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/develop/base.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/develop/base.json index e12b4681..de3e8e43 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/develop/base.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/develop/base.json @@ -1,209 +1,201 @@ { + "AccessKeys": [], + "AccessKeysPvE": [], + "Area": 0, + "AveragePlayTime": 2, + "AveragePlayerLevel": 10, + "BotAssault": 0, + "BotEasy": 0, + "BotHard": 0, + "BotImpossible": 0, + "BotMarksman": 0, + "BotMax": 5, + "BotMaxPvE": 5, + "BotNormal": 0, + "BotSpawnCountStep": 3, + "BotSpawnPeriodCheck": 15, + "BotSpawnTimeOffMax": 0, + "BotSpawnTimeOffMin": 0, + "BotSpawnTimeOnMax": 0, + "BotSpawnTimeOnMin": 0, + "BotStart": 30, + "BotStartPlayer": 0, + "BotStop": 2400, + "DisabledScavExits": "", + "EnableCoop": false, "Enabled": false, + "EscapeTimeLimit": 60000, + "EscapeTimeLimitCoop": 60000, + "ForceOnlineRaidInPVE": false, + "GlobalContainerChanceModifier": 1, + "HeatmapCellSize": { + "x": 1, + "y": 2, + "z": 1 + }, + "HeatmapLayers": [ + "AllCharactersPositions", + "AllBotsPositions", + "AllRealPlayersPositions", + "RealPlayersSavagesPositions", + "RealPlayersSavagesDeads", + "RealPlayersSavagesDamages", + "RealPlayersPmcPositions", + "RealPlayersPmcDeads", + "RealPlayersPmcDamages", + "RealPlayersPmcLaydownPositions", + "RealPlayersPmcEquipmentDropPositions", + "RealPlayersPmcHealingPositions", + "BotsBossPositions", + "BotsBossDeads", + "BotsBossDamages", + "BotsSavagesPositions", + "BotsSavagesDeads", + "BotsSavagesDamages", + "AllCharactersDamageSources", + "RealPlayerDamageSources", + "BotsDamageSources", + "LootPositions" + ], + "IconX": 156, + "IconY": 551, + "IsSecret": false, "Locked": false, - "Insurance": false, - "SafeLocation": false, + "MaxBotPerZone": 0, + "MaxCoopGroup": 10, + "MaxDistToFreePoint": 900, + "MaxPlayers": 10, + "MinDistToFreePoint": 10, + "MinPlayerLvlAccessKeys": 0, + "MinPlayers": 1, "Name": "Arena", + "NewSpawn": false, + "NewSpawnForPlayers": false, + "NonWaveGroupScenario": { + "Chance": 50, + "Enabled": true, + "MaxToBeGroup": 3, + "MinToBeGroup": 2 + }, + "OcculsionCullingEnabled": true, + "OfflineNewSpawn": true, + "OfflineOldSpawn": true, + "OldSpawn": true, + "OpenZones": "", + "PlayersRequestCount": -1, + "PmcMaxPlayersInGroup": 5, + "RequiredPlayerLevelMax": 100, + "RequiredPlayerLevelMin": 0, + "Rules": "Normal", + "ScavMaxPlayersInGroup": 4, "Scene": { "path": "maps/develop_preset.bundle", "rcid": "develop.scenespreset.asset" }, - "Area": 0, - "RequiredPlayerLevel": 1, - "MinPlayers": 1, - "MaxPlayers": 10, - "exit_count": 0, - "exit_access_time": 0, - "exit_time": 0, - "IconX": 156, - "IconY": 551, + "UnixDateTime": 1600869802, + "doors": [], + "limits": [], "waves": [ { - "number": 0, - "time_min": 0, - "time_max": 10, - "slots_min": 1, - "slots_max": 2, - "BotSide": "Savage", "BotPreset": "normal", - "SpawnPoints": "BotZoneMain", - "WildSpawnType": "assault", - "isPlayers": true - }, - { - "number": 1, - "time_min": 10, - "time_max": 120, - "slots_min": 2, - "slots_max": 3, "BotSide": "Savage", - "BotPreset": "easy", + "KeepZoneOnSpawn": false, + "SpawnMode": [], "SpawnPoints": "BotZoneMain", "WildSpawnType": "assault", - "isPlayers": true - }, - { + "isPlayers": false, "number": 0, - "time_min": 120, - "time_max": 240, - "slots_min": 3, - "slots_max": 4, + "slots_max": 2, + "slots_min": 1, + "time_max": 10, + "time_min": 0 + }, + { + "BotPreset": "easy", "BotSide": "Savage", - "BotPreset": "hard", + "KeepZoneOnSpawn": false, + "SpawnMode": [], "SpawnPoints": "BotZoneMain", "WildSpawnType": "assault", - "isPlayers": true + "isPlayers": false, + "number": 1, + "slots_max": 3, + "slots_min": 2, + "time_max": 120, + "time_min": 10 + }, + { + "BotPreset": "hard", + "BotSide": "Savage", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "BotZoneMain", + "WildSpawnType": "assault", + "isPlayers": false, + "number": 0, + "slots_max": 4, + "slots_min": 3, + "time_max": 240, + "time_min": 120 + } + ], + "AirdropParameters": [ + { + "AirdropPointDeactivateDistance": 50, + "MinPlayersCountToSpawnAirdrop": 0, + "PlaneAirdropChance": 0, + "PlaneAirdropCooldownMax": 900, + "PlaneAirdropCooldownMin": 600, + "PlaneAirdropEnd": 2100, + "PlaneAirdropMax": 0, + "PlaneAirdropStartMax": 900, + "PlaneAirdropStartMin": 300, + "UnsuccessfulTryPenalty": 10 } ], - "limits": [], - "AveragePlayTime": 2, - "AveragePlayerLevel": 10, - "escape_time_limit": 60000, - "Rules": "Normal", - "IsSecret": false, - "doors": [], - "tmp_location_field_remove_me": 0, - "MinDistToExitPoint": 0, - "MaxDistToFreePoint": 900, - "MinDistToFreePoint": 10, - "MaxBotPerZone": 0, - "OpenZones": "", - "OcculsionCullingEnabled": true, - "GlobalLootChanceModifier": 0, - "OldSpawn": true, - "NewSpawn": false, - "BotMax": 5, - "BotStart": 30, - "BotStop": 2400, - "BotMaxTimePlayer": 0, - "BotSpawnTimeOnMin": 0, - "BotSpawnTimeOnMax": 0, - "BotSpawnTimeOffMin": 0, - "BotSpawnTimeOffMax": 0, - "BotMaxPlayer": 0, - "BotEasy": 0, - "BotNormal": 0, - "BotHard": 0, - "BotImpossible": 0, - "BotAssault": 0, - "BotMarksman": 0, - "DisabledScavExits": "", - "AccessKeys": [], - "UnixDateTime": 1600869802, - "users_gather_seconds": 0, - "users_spawn_seconds_n": 0, - "users_spawn_seconds_n2": 0, - "users_summon_seconds": 0, - "sav_summon_seconds": 0, - "matching_min_seconds": 0, - "MinMaxBots": [], "BotLocationModifier": { "AccuracySpeed": 1, - "Scattering": 1, - "GainSight": 1, - "MarksmanAccuratyCoef": 1, - "VisibleDistance": 1, - "DistToSleep": 100, "DistToActivate": 80, - "MagnetPower": 10 + "DistToActivatePvE": 80, + "DistToSleep": 100, + "DistToSleepPvE": 100, + "FogVisibilityDistanceCoef": 0, + "FogVisibilitySpeedCoef": 0, + "GainSight": 1, + "MagnetPower": 10, + "MarksmanAccuratyCoef": 1, + "RainVisibilityDistanceCoef": 0, + "RainVisibilitySpeedCoef": 0, + "Scattering": 1, + "VisibleDistance": 1 }, - "exits": [ - { - "Name": "UN Roadblock", - "EntryPoints": "House,Houseb", - "Chance": 100, - "MinTime": 0, - "MaxTime": 0, - "PlayersCount": 0, - "ExfiltrationTime": 10, - "PassageRequirement": "TransferItem", - "ExfiltrationType": "SharedTimer", - "RequiredSlot": "FirstPrimaryWeapon", - "Id": "5449016a4bdc2d6f028b456f", - "RequirementTip": "Сотку должен", - "Count": 100 - }, - { - "Name": "Elevator", - "EntryPoints": "House,Houseb", - "Chance": 100, - "MinTime": 0, - "MaxTime": 0, - "PlayersCount": 3, - "ExfiltrationTime": 10, - "PassageRequirement": "None", - "ExfiltrationType": "Individual", - "RequiredSlot": "FirstPrimaryWeapon", - "Id": "", - "RequirementTip": "", - "Count": 0 - }, - { - "Name": "Outskirts", - "EntryPoints": "House,Houseb", - "Chance": 100, - "MinTime": 0, - "MaxTime": 0, - "PlayersCount": 0, - "ExfiltrationTime": 10, - "PassageRequirement": "None", - "ExfiltrationType": "Individual", - "RequiredSlot": "FirstPrimaryWeapon", - "Id": "", - "RequirementTip": "", - "Count": 0 - }, - { - "Name": "Hangar Gate", - "EntryPoints": "House,Houseb", - "Chance": 100, - "MinTime": 0, - "MaxTime": 0, - "PlayersCount": 0, - "ExfiltrationTime": 10, - "PassageRequirement": "None", - "ExfiltrationType": "Individual", - "RequiredSlot": "FirstPrimaryWeapon", - "Id": "", - "RequirementTip": "", - "Count": 0 - }, - { - "Name": "Tunnel", - "EntryPoints": "House,Houseb", - "Chance": 100, - "MinTime": 0, - "MaxTime": 0, - "PlayersCount": 0, - "ExfiltrationTime": 10, - "PassageRequirement": "None", - "ExfiltrationType": "Individual", - "RequiredSlot": "FirstPrimaryWeapon", - "Id": "", - "RequirementTip": "", - "Count": 0 - }, - { - "Name": "EXFIL_Train", - "EntryPoints": "House,Houseb", - "Chance": 100, - "MinTime": 30, - "MaxTime": 60, - "PlayersCount": 0, - "ExfiltrationTime": 5, - "PassageRequirement": "Train", - "ExfiltrationType": "SharedTimer", - "RequiredSlot": "FirstPrimaryWeapon", - "Id": "0", - "RequirementTip": "TIP IS HARDCODED", - "Count": 90 - } - ], "DisabledForScav": false, - "BossLocationSpawn": [], + "MinMaxBots": [], "SpawnPointParams": [ { + "BotZoneName": "", + "Categories": [ + "Player" + ], + "ColliderParams": { + "_parent": "SpawnBoxParams", + "_props": { + "Center": { + "x": 0, + "y": 0, + "z": 0 + }, + "Size": { + "x": 2.2, + "y": 2.04, + "z": 2.14 + } + } + }, + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "03841924-ea1a-4e5c-bf27-82af7868beb1", + "Infiltration": "House", "Position": { "x": -30.359436, "y": 0.1, @@ -212,12 +204,13 @@ "Rotation": 87.10709, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "House", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -233,10 +226,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "0da5b986-424a-44d1-906a-1d7cc118413a", + "Infiltration": "Houseb", "Position": { "x": 19.715271, "y": 0.06, @@ -245,12 +238,13 @@ "Rotation": 269.253418, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "Houseb", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -266,10 +260,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "110e3c75-e58d-461c-ab61-9f6a715ca6b1", + "Infiltration": "House", "Position": { "x": -30.0410156, "y": 0.1, @@ -278,12 +272,13 @@ "Rotation": 87.10709, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "House", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -299,10 +294,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "1a40138b-6f65-4866-bad2-64162d7772de", + "Infiltration": "House", "Position": { "x": -29.2000122, "y": 0.1, @@ -311,12 +306,13 @@ "Rotation": 87.10709, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "House", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -332,10 +328,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "3feb492c-8c45-405a-8e7a-8dd903433eb0", + "Infiltration": "House", "Position": { "x": -23.7852783, "y": 0.1, @@ -344,12 +340,13 @@ "Rotation": 87.10709, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "House", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -365,10 +362,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "52d3284b-0e8f-47e8-a7d1-701bf4cd8e5b", + "Infiltration": "House", "Position": { "x": -23.4979248, "y": 0.1, @@ -377,12 +374,13 @@ "Rotation": 87.10709, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "House", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -398,10 +396,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "870629fd-e4d5-4fa1-8274-94c223ad9692", + "Infiltration": "Houseb", "Position": { "x": 12.9941406, "y": 0.06, @@ -410,12 +408,13 @@ "Rotation": 269.253418, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "Houseb", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -431,10 +430,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "93a1c6d6-1379-43e6-99c2-c346178bb3e0", + "Infiltration": "Houseb", "Position": { "x": 18.1246338, "y": 0.06, @@ -443,45 +442,13 @@ "Rotation": 269.253418, "Sides": [ "Bear" - ], - "Categories": [ - "Player" - ], - "Infiltration": "Houseb", - "DelayToCanSpawnSec": 4, - "ColliderParams": { - "_parent": "SpawnBoxParams", - "_props": { - "Center": { - "x": 0, - "y": 0, - "z": 0 - }, - "Size": { - "x": 2.2, - "y": 2.04, - "z": 2.14 - } - } - }, - "BotZoneName": "" + ] }, { - "Id": "971882ef-596f-4419-acfb-ca2bfe52d043", - "Position": { - "x": -17.92, - "y": 0, - "z": 5.55 - }, - "Rotation": 0, - "Sides": [ - "Savage" - ], + "BotZoneName": "BotZoneMain", "Categories": [ "Bot" ], - "Infiltration": "", - "DelayToCanSpawnSec": 10, "ColliderParams": { "_parent": "SpawnSphereParams", "_props": { @@ -493,10 +460,44 @@ "Radius": 4 } }, - "BotZoneName": "BotZoneMain" + "CorePointId": 0, + "DelayToCanSpawnSec": 10, + "Id": "971882ef-596f-4419-acfb-ca2bfe52d043", + "Infiltration": "", + "Position": { + "x": -17.92, + "y": 0, + "z": 5.55 + }, + "Rotation": 0, + "Sides": [ + "Savage" + ] }, { + "BotZoneName": "", + "Categories": [ + "Player" + ], + "ColliderParams": { + "_parent": "SpawnBoxParams", + "_props": { + "Center": { + "x": 0, + "y": 0, + "z": 0 + }, + "Size": { + "x": 2.2, + "y": 2.04, + "z": 2.14 + } + } + }, + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "cf24125e-1c3a-457e-a024-613a8df98b06", + "Infiltration": "Houseb", "Position": { "x": 12.47467, "y": 0.06, @@ -505,12 +506,13 @@ "Rotation": 269.253418, "Sides": [ "Bear" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ "Player" ], - "Infiltration": "Houseb", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnBoxParams", "_props": { @@ -526,10 +528,10 @@ } } }, - "BotZoneName": "" - }, - { + "CorePointId": 0, + "DelayToCanSpawnSec": 4, "Id": "d052b031-b477-465f-8913-ae108c9ca2c3", + "Infiltration": "Houseb", "Position": { "x": 19.210022, "y": 0.06, @@ -538,28 +540,135 @@ "Rotation": 269.253418, "Sides": [ "Bear" - ], - "Categories": [ - "Player" - ], - "Infiltration": "Houseb", - "DelayToCanSpawnSec": 4, - "ColliderParams": { - "_parent": "SpawnBoxParams", - "_props": { - "Center": { - "x": 0, - "y": 0, - "z": 0 - }, - "Size": { - "x": 2.2, - "y": 2.04, - "z": 2.14 - } - } - }, - "BotZoneName": "" + ] + } + ], + "exits": [ + { + "Chance": 100, + "ChancePVE": 100, + "Count": 100, + "CountPVE": 100, + "EntryPoints": "House,Houseb", + "ExfiltrationTime": 10, + "ExfiltrationTimePVE": 10, + "ExfiltrationType": "SharedTimer", + "Id": "5449016a4bdc2d6f028b456f", + "MaxTime": 0, + "MaxTimePVE": 0, + "MinTime": 0, + "MinTimePVE": 0, + "Name": "UN Roadblock", + "PassageRequirement": "TransferItem", + "PlayersCount": 0, + "PlayersCountPVE": 0, + "RequiredSlot": "FirstPrimaryWeapon", + "RequirementTip": "Сотку должен" + }, + { + "Chance": 100, + "ChancePVE": 100, + "Count": 0, + "CountPVE": 0, + "EntryPoints": "House,Houseb", + "ExfiltrationTime": 10, + "ExfiltrationTimePVE": 10, + "ExfiltrationType": "Individual", + "Id": "", + "MaxTime": 0, + "MaxTimePVE": 0, + "MinTime": 0, + "MinTimePVE": 0, + "Name": "Elevator", + "PassageRequirement": "None", + "PlayersCount": 3, + "PlayersCountPVE": 3, + "RequiredSlot": "FirstPrimaryWeapon", + "RequirementTip": "" + }, + { + "Chance": 100, + "ChancePVE": 100, + "Count": 0, + "CountPVE": 0, + "EntryPoints": "House,Houseb", + "ExfiltrationTime": 10, + "ExfiltrationTimePVE": 10, + "ExfiltrationType": "Individual", + "Id": "", + "MaxTime": 0, + "MaxTimePVE": 0, + "MinTime": 0, + "MinTimePVE": 0, + "Name": "Outskirts", + "PassageRequirement": "None", + "PlayersCount": 0, + "PlayersCountPVE": 0, + "RequiredSlot": "FirstPrimaryWeapon", + "RequirementTip": "" + }, + { + "Chance": 100, + "ChancePVE": 100, + "Count": 0, + "CountPVE": 0, + "EntryPoints": "House,Houseb", + "ExfiltrationTime": 10, + "ExfiltrationTimePVE": 10, + "ExfiltrationType": "Individual", + "Id": "", + "MaxTime": 0, + "MaxTimePVE": 0, + "MinTime": 0, + "MinTimePVE": 0, + "Name": "Hangar Gate", + "PassageRequirement": "None", + "PlayersCount": 0, + "PlayersCountPVE": 0, + "RequiredSlot": "FirstPrimaryWeapon", + "RequirementTip": "" + }, + { + "Chance": 100, + "ChancePVE": 100, + "Count": 0, + "CountPVE": 0, + "EntryPoints": "House,Houseb", + "ExfiltrationTime": 10, + "ExfiltrationTimePVE": 10, + "ExfiltrationType": "Individual", + "Id": "", + "MaxTime": 0, + "MaxTimePVE": 0, + "MinTime": 0, + "MinTimePVE": 0, + "Name": "Tunnel", + "PassageRequirement": "None", + "PlayersCount": 0, + "PlayersCountPVE": 0, + "RequiredSlot": "FirstPrimaryWeapon", + "RequirementTip": "" + }, + { + "Chance": 100, + "ChancePVE": 100, + "Count": 90, + "CountPVE": 90, + "EntryPoints": "House,Houseb", + "ExfiltrationTime": 5, + "ExfiltrationTimePVE": 5, + "ExfiltrationType": "SharedTimer", + "Id": "0", + "MaxTime": 60, + "MaxTimePVE": 60, + "MinTime": 30, + "MinTimePVE": 30, + "Name": "EXFIL_Train", + "PassageRequirement": "Train", + "PlayersCount": 0, + "PlayersCountPVE": 0, + "RequiredSlot": "FirstPrimaryWeapon", + "RequirementTip": "TIP IS HARDCODED" } ], "maxItemCountInLocation": [], @@ -570,23 +679,12 @@ { "id": "5805f617245977100b2c1f41", "pic": { - "path": "CONTENT/banners/tglabs.jpg", - "rcid": "" - } - }, - { - "id": "5807be8924597742c603fa19", - "pic": { - "path": "CONTENT/banners/banner_tarkov.jpg", - "rcid": "" - } - }, - { - "id": "5c1b857086f77465f465faa4", - "pic": { - "path": "CONTENT/banners/banner_scavraider.jpg", - "rcid": "" + "file": "67e404d9bec96f5d8e097331.jpg", + "path": "banners/67e404d9bec96f5d8e097331.jpg", + "rcid": "", + "type": "banners" } } - ] + ], + "BossLocationSpawn": [] } diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/hideout/base.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/hideout/base.json index fcc30edb..00bf121c 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/hideout/base.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/hideout/base.json @@ -1,81 +1,139 @@ { - "Enabled": false, + "AccessKeys": [], + "AccessKeysPvE": [], + "Area": 0, + "AveragePlayTime": 1000000, + "AveragePlayerLevel": 10, + "BotAssault": 0, + "BotEasy": 0, + "BotHard": 0, + "BotImpossible": 0, + "BotMarksman": 0, + "BotMax": 0, + "BotMaxPvE": 0, + "BotNormal": 0, + "BotSpawnCountStep": 3, + "BotSpawnPeriodCheck": 15, + "BotSpawnTimeOffMax": 0, + "BotSpawnTimeOffMin": 0, + "BotSpawnTimeOnMax": 0, + "BotSpawnTimeOnMin": 0, + "BotStart": 0, + "BotStartPlayer": 0, + "BotStop": 0, + "DisabledScavExits": "", "EnableCoop": true, + "Enabled": false, + "EscapeTimeLimit": 99999, + "EscapeTimeLimitCoop": 99999, + "ForceOnlineRaidInPVE": false, + "GlobalContainerChanceModifier": 1, + "HeatmapCellSize": { + "x": 1, + "y": 2, + "z": 1 + }, + "HeatmapLayers": [ + "AllCharactersPositions", + "AllBotsPositions", + "AllRealPlayersPositions", + "RealPlayersSavagesPositions", + "RealPlayersSavagesDeads", + "RealPlayersSavagesDamages", + "RealPlayersPmcPositions", + "RealPlayersPmcDeads", + "RealPlayersPmcDamages", + "RealPlayersPmcLaydownPositions", + "RealPlayersPmcEquipmentDropPositions", + "RealPlayersPmcHealingPositions", + "BotsBossPositions", + "BotsBossDeads", + "BotsBossDamages", + "BotsSavagesPositions", + "BotsSavagesDeads", + "BotsSavagesDamages", + "AllCharactersDamageSources", + "RealPlayerDamageSources", + "BotsDamageSources", + "LootPositions" + ], + "IconX": 0, + "IconY": 0, + "IsSecret": false, "Locked": true, + "MaxBotPerZone": 0, + "MaxCoopGroup": 10, + "MaxDistToFreePoint": 900, + "MaxPlayers": 10, + "MinDistToFreePoint": 10, + "MinPlayerLvlAccessKeys": 0, + "MinPlayers": 1, "Name": "Hideout", + "NewSpawn": false, + "NewSpawnForPlayers": false, + "NonWaveGroupScenario": { + "Chance": 50, + "Enabled": true, + "MaxToBeGroup": 3, + "MinToBeGroup": 2 + }, + "OcculsionCullingEnabled": false, + "OfflineNewSpawn": true, + "OfflineOldSpawn": true, + "OldSpawn": true, + "OpenZones": "", + "PlayersRequestCount": -1, + "PmcMaxPlayersInGroup": 5, + "RequiredPlayerLevelMax": 100, + "RequiredPlayerLevelMin": 1, + "Rules": "Normal", + "ScavMaxPlayersInGroup": 4, "Scene": { "path": "maps/bunker_preset.bundle", "rcid": "bunker.ScenesPreset.asset" }, - "Area": 0, - "RequiredPlayerLevelMin": 1, - "RequiredPlayerLevelMax": 100, - "PmcMaxPlayersInGroup": 5, - "ScavMaxPlayersInGroup": 4, - "MinPlayers": 1, - "MaxPlayers": 10, - "MaxCoopGroup": 10, - "IconX": 0, - "IconY": 0, - "waves": [], - "limits": [], - "AveragePlayTime": 1000000, - "AveragePlayerLevel": 10, - "EscapeTimeLimit": 99999, - "EscapeTimeLimitCoop": 99999, - "Rules": "Normal", - "IsSecret": false, - "doors": [], - "MaxDistToFreePoint": 900, - "MinDistToFreePoint": 10, - "MaxBotPerZone": 0, - "OpenZones": "", - "OcculsionCullingEnabled": false, - "OldSpawn": true, - "OfflineOldSpawn": true, - "NewSpawn": false, - "OfflineNewSpawn": true, - "BotMax": 0, - "BotStart": 0, - "BotStartPlayer": 0, - "BotStop": 0, - "BotSpawnTimeOnMin": 0, - "BotSpawnTimeOnMax": 0, - "BotSpawnTimeOffMin": 0, - "BotSpawnTimeOffMax": 0, - "BotEasy": 0, - "BotNormal": 0, - "BotHard": 0, - "BotImpossible": 0, - "BotAssault": 0, - "BotMarksman": 0, - "DisabledScavExits": "", - "MinPlayerLvlAccessKeys": 0, - "AccessKeys": [], "UnixDateTime": 1689772567, - "PlayersRequestCount": -1, - "NonWaveGroupScenario": { - "MinToBeGroup": 2, - "MaxToBeGroup": 3, - "Chance": 50, - "Enabled": false - }, - "BotSpawnCountStep": 3, - "BotSpawnPeriodCheck": 15, - "GlobalContainerChanceModifier": 1, - "MinMaxBots": [], + "doors": [], + "limits": [], + "waves": [], "BotLocationModifier": { "AccuracySpeed": 1, - "Scattering": 1, + "DistToActivatePvE": 0, + "DistToSleepPvE": 0, + "FogVisibilityDistanceCoef": 0, + "FogVisibilitySpeedCoef": 0, "GainSight": 1, "MarksmanAccuratyCoef": 1, - "VisibleDistance": 0 + "RainVisibilityDistanceCoef": 0, + "RainVisibilitySpeedCoef": 0, + "Scattering": 1, + "VisibleDistance": 0, + "DistToActivate": 0, + "DistToSleep": 0 }, - "exits": [], "DisabledForScav": false, + "MinMaxBots": [], "SpawnPointParams": [ { + "BotZoneName": "", + "Categories": [ + "Player", + "Bot" + ], + "ColliderParams": { + "_parent": "SpawnSphereParams", + "_props": { + "Center": { + "x": 0, + "y": 0, + "z": 0 + }, + "Radius": 10 + } + }, + "DelayToCanSpawnSec": 0.5, "Id": "f656a561-6524-49e2-90c0-1cbbece183ce", + "Infiltration": "", "Position": { "x": -5.8, "y": 0.1, @@ -84,13 +142,13 @@ "Rotation": 45.0000038, "Sides": [ "Usec" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ - "Player", - "Bot" + "Player" ], - "Infiltration": "", - "DelayToCanSpawnSec": 0.5, "ColliderParams": { "_parent": "SpawnSphereParams", "_props": { @@ -102,10 +160,9 @@ "Radius": 10 } }, - "BotZoneName": "" - }, - { + "DelayToCanSpawnSec": 4, "Id": "f92541a9-08ab-4c9e-957a-d802e143b705", + "Infiltration": "Hideout", "Position": { "x": -5.8, "y": 0.1, @@ -114,12 +171,14 @@ "Rotation": 45.0000038, "Sides": [ "All" - ], + ] + }, + { + "BotZoneName": "", "Categories": [ - "Player" + "Player", + "Bot" ], - "Infiltration": "Hideout", - "DelayToCanSpawnSec": 4, "ColliderParams": { "_parent": "SpawnSphereParams", "_props": { @@ -131,10 +190,9 @@ "Radius": 10 } }, - "BotZoneName": "" - }, - { + "DelayToCanSpawnSec": 0.5, "Id": "faf351a1-e5f5-4642-8ece-267508fdfea6", + "Infiltration": "", "Position": { "x": -5.8, "y": 0.1, @@ -143,27 +201,10 @@ "Rotation": 45.0000038, "Sides": [ "Bear" - ], - "Categories": [ - "Player", - "Bot" - ], - "Infiltration": "", - "DelayToCanSpawnSec": 0.5, - "ColliderParams": { - "_parent": "SpawnSphereParams", - "_props": { - "Center": { - "x": 0, - "y": 0, - "z": 0 - }, - "Radius": 10 - } - }, - "BotZoneName": "" + ] } ], + "exits": [], "maxItemCountInLocation": [ { "TemplateId": "604b47caa16c2359315ad047", @@ -177,15 +218,19 @@ { "id": "5805f617245977100b2c1f41", "pic": { - "path": "CONTENT/banners/tglabs.jpg", - "rcid": "" + "file": "67e404d9bec96f5d8e097331.jpg", + "path": "banners/67e404d9bec96f5d8e097331.jpg", + "rcid": "", + "type": "banners" } }, { "id": "5807be8924597742c603fa19", "pic": { - "path": "CONTENT/banners/banner_tarkov.jpg", - "rcid": "" + "file": "67e4046dbec96f5d8e09732a.jpg", + "path": "banners/67e4046dbec96f5d8e09732a.jpg", + "rcid": "", + "type": "banners" } } ], diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/privatearea/base.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/privatearea/base.json index f7b34005..3b243fe4 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/privatearea/base.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/privatearea/base.json @@ -1,106 +1,149 @@ { + "AccessKeys": [], + "AccessKeysPvE": [], + "Area": 0, + "AveragePlayTime": 100, + "AveragePlayerLevel": 10, + "BotAssault": 0, + "BotEasy": 0, + "BotHard": 0, + "BotImpossible": 0, + "BotMarksman": 0, + "BotMax": 0, + "BotMaxPvE": 0, + "BotNormal": 0, + "BotSpawnCountStep": 3, + "BotSpawnPeriodCheck": 15, + "BotSpawnTimeOffMax": 0, + "BotSpawnTimeOffMin": 0, + "BotSpawnTimeOnMax": 0, + "BotSpawnTimeOnMin": 0, + "BotStart": 0, + "BotStartPlayer": 0, + "BotStop": 0, + "DisabledScavExits": "", + "EnableCoop": true, "Enabled": false, + "EscapeTimeLimit": 0, + "EscapeTimeLimitCoop": 0, + "ForceOnlineRaidInPVE": false, + "GlobalContainerChanceModifier": 1, + "HeatmapCellSize": { + "x": 1, + "y": 2, + "z": 1 + }, + "HeatmapLayers": [ + "AllCharactersPositions", + "AllBotsPositions", + "AllRealPlayersPositions", + "RealPlayersSavagesPositions", + "RealPlayersSavagesDeads", + "RealPlayersSavagesDamages", + "RealPlayersPmcPositions", + "RealPlayersPmcDeads", + "RealPlayersPmcDamages", + "RealPlayersPmcLaydownPositions", + "RealPlayersPmcEquipmentDropPositions", + "RealPlayersPmcHealingPositions", + "BotsBossPositions", + "BotsBossDeads", + "BotsBossDamages", + "BotsSavagesPositions", + "BotsSavagesDeads", + "BotsSavagesDamages", + "AllCharactersDamageSources", + "RealPlayerDamageSources", + "BotsDamageSources", + "LootPositions" + ], + "IconX": 224, + "IconY": 646, + "IsSecret": true, "Locked": true, - "Insurance": true, - "SafeLocation": false, + "MaxBotPerZone": 0, + "MaxCoopGroup": 9, + "MaxDistToFreePoint": 900, + "MaxPlayers": 9, + "MinDistToFreePoint": 10, + "MinPlayerLvlAccessKeys": 0, + "MinPlayers": 6, "Name": "Private Sector", - "Description": "Private residential sector, built up with cottages of the upper-class citizens of Tarkov. In the first weeks of emerging chaos it served as a refugee staging camp, but has become a known scavenger haunt afterwards.", + "NewSpawn": false, + "NewSpawnForPlayers": false, + "NonWaveGroupScenario": { + "Chance": 50, + "Enabled": true, + "MaxToBeGroup": 3, + "MinToBeGroup": 2 + }, + "OcculsionCullingEnabled": false, + "OfflineNewSpawn": true, + "OfflineOldSpawn": true, + "OldSpawn": true, + "OpenZones": "", + "PlayersRequestCount": -1, + "PmcMaxPlayersInGroup": 5, + "RequiredPlayerLevelMax": 100, + "RequiredPlayerLevelMin": 0, + "Rules": "Normal", + "ScavMaxPlayersInGroup": 4, "Scene": { "path": "", "rcid": "" }, - "Area": 0, - "RequiredPlayerLevel": 0, - "MinPlayers": 6, - "MaxPlayers": 9, - "exit_count": 1, - "exit_access_time": 10, - "exit_time": 2, - "Preview": { - "path": "", - "rcid": "" - }, - "IconX": 224, - "IconY": 646, - "filter_ex": [], + "UnixDateTime": 0, + "doors": [], + "limits": [], "waves": [ { - "number": 0, - "time_min": 1, - "time_max": 2, - "slots_min": 3, - "slots_max": 6, - "SpawnPoints": "", - "BotSide": "Savage", "BotPreset": "normal", + "BotSide": "Savage", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", + "WildSpawnType": "assault", "isPlayers": false, - "WildSpawnType": "assault" + "number": 0, + "slots_max": 6, + "slots_min": 3, + "time_max": 2, + "time_min": 1 }, { - "number": 1, - "time_min": 10, - "time_max": 12, - "slots_min": 3, - "slots_max": 5, - "SpawnPoints": "", - "BotSide": "Usec", "BotPreset": "hard", + "BotSide": "Usec", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", + "WildSpawnType": "assault", "isPlayers": false, - "WildSpawnType": "assault" + "number": 1, + "slots_max": 5, + "slots_min": 3, + "time_max": 12, + "time_min": 10 } ], - "limits": [], - "AveragePlayTime": 100, - "AveragePlayerLevel": 10, - "escape_time_limit": 0, - "Rules": "Normal", - "IsSecret": true, - "doors": [], - "tmp_location_field_remove_me": 0, - "MinDistToExitPoint": 30, - "MaxDistToFreePoint": 900, - "MinDistToFreePoint": 10, - "MaxBotPerZone": 0, - "OpenZones": "", - "OcculsionCullingEnabled": false, - "GlobalLootChanceModifier": 1, - "OldSpawn": true, - "NewSpawn": false, - "BotMax": 0, - "BotStart": 0, - "BotStop": 0, - "BotMaxTimePlayer": 0, - "BotSpawnTimeOnMin": 0, - "BotSpawnTimeOnMax": 0, - "BotSpawnTimeOffMin": 0, - "BotSpawnTimeOffMax": 0, - "BotMaxPlayer": 0, - "BotEasy": 0, - "BotNormal": 0, - "BotHard": 0, - "BotImpossible": 0, - "BotAssault": 0, - "BotMarksman": 0, - "DisabledScavExits": "", - "AccessKeys": [], - "UnixDateTime": 0, - "users_gather_seconds": 120, - "users_spawn_seconds_n": 60, - "users_spawn_seconds_n2": 90, - "users_summon_seconds": 0, - "sav_summon_seconds": 60, - "matching_min_seconds": 120, - "MinMaxBots": [], "BotLocationModifier": { "AccuracySpeed": 0, - "Scattering": 0, + "DistToActivatePvE": 0, + "DistToSleepPvE": 0, + "FogVisibilityDistanceCoef": 0, + "FogVisibilitySpeedCoef": 0, "GainSight": 0, "MarksmanAccuratyCoef": 0, - "VisibleDistance": 0 + "RainVisibilityDistanceCoef": 0, + "RainVisibilitySpeedCoef": 0, + "Scattering": 0, + "VisibleDistance": 0, + "DistToActivate": 0, + "DistToSleep": 0 }, - "exits": [], "DisabledForScav": false, + "MinMaxBots": [], "SpawnPointParams": [], + "exits": [], "maxItemCountInLocation": [], "Id": "Private Area", "_Id": "5704e64ad2720bb55b8b456e", @@ -109,15 +152,19 @@ { "id": "5803a58524597710ca36fcb2", "pic": { - "path": "CONTENT/banners/banner_terragroup.jpg", - "rcid": "" + "file": "67e404d9bec96f5d8e097331.jpg", + "path": "banners/67e404d9bec96f5d8e097331.jpg", + "rcid": "", + "type": "banners" } }, { "id": "5c1b857086f77465f465faa4", "pic": { - "path": "CONTENT/banners/banner_scavraider.jpg", - "rcid": "" + "file": "67e404c5bec96f5d8e09732f.jpg", + "path": "banners/67e404c5bec96f5d8e09732f.jpg", + "rcid": "", + "type": "banners" } } ], diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/suburbs/base.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/suburbs/base.json index 7b9dae9d..2cd9bb44 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/suburbs/base.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/suburbs/base.json @@ -1,101 +1,149 @@ { + "AccessKeys": [], + "AccessKeysPvE": [], + "Area": 0, + "AveragePlayTime": 100, + "AveragePlayerLevel": 10, + "BotAssault": 0, + "BotEasy": 0, + "BotHard": 0, + "BotImpossible": 0, + "BotMarksman": 0, + "BotMax": 0, + "BotMaxPvE": 0, + "BotNormal": 0, + "BotSpawnCountStep": 3, + "BotSpawnPeriodCheck": 15, + "BotSpawnTimeOffMax": 0, + "BotSpawnTimeOffMin": 0, + "BotSpawnTimeOnMax": 0, + "BotSpawnTimeOnMin": 0, + "BotStart": 0, + "BotStartPlayer": 0, + "BotStop": 0, + "DisabledScavExits": "", + "EnableCoop": true, "Enabled": false, + "EscapeTimeLimit": 0, + "EscapeTimeLimitCoop": 0, + "ForceOnlineRaidInPVE": false, + "GlobalContainerChanceModifier": 1, + "HeatmapCellSize": { + "x": 1, + "y": 2, + "z": 1 + }, + "HeatmapLayers": [ + "AllCharactersPositions", + "AllBotsPositions", + "AllRealPlayersPositions", + "RealPlayersSavagesPositions", + "RealPlayersSavagesDeads", + "RealPlayersSavagesDamages", + "RealPlayersPmcPositions", + "RealPlayersPmcDeads", + "RealPlayersPmcDamages", + "RealPlayersPmcLaydownPositions", + "RealPlayersPmcEquipmentDropPositions", + "RealPlayersPmcHealingPositions", + "BotsBossPositions", + "BotsBossDeads", + "BotsBossDamages", + "BotsSavagesPositions", + "BotsSavagesDeads", + "BotsSavagesDamages", + "AllCharactersDamageSources", + "RealPlayerDamageSources", + "BotsDamageSources", + "LootPositions" + ], + "IconX": 480, + "IconY": 577, + "IsSecret": false, "Locked": true, - "Insurance": false, - "SafeLocation": false, + "MaxBotPerZone": 0, + "MaxCoopGroup": 9, + "MaxDistToFreePoint": 900, + "MaxPlayers": 9, + "MinDistToFreePoint": 10, + "MinPlayerLvlAccessKeys": 0, + "MinPlayers": 6, "Name": "Suburbs", + "NewSpawn": false, + "NewSpawnForPlayers": false, + "NonWaveGroupScenario": { + "Chance": 50, + "Enabled": true, + "MaxToBeGroup": 3, + "MinToBeGroup": 2 + }, + "OcculsionCullingEnabled": false, + "OfflineNewSpawn": true, + "OfflineOldSpawn": true, + "OldSpawn": true, + "OpenZones": "", + "PlayersRequestCount": -1, + "PmcMaxPlayersInGroup": 5, + "RequiredPlayerLevelMax": 100, + "RequiredPlayerLevelMin": 0, + "Rules": "Normal", + "ScavMaxPlayersInGroup": 4, "Scene": { "path": "", "rcid": "" }, - "Area": 0, - "RequiredPlayerLevel": 0, - "MinPlayers": 6, - "MaxPlayers": 9, - "exit_count": 0, - "exit_access_time": 0, - "exit_time": 0, - "IconX": 480, - "IconY": 577, + "UnixDateTime": 0, + "doors": [], + "limits": [], "waves": [ { - "number": 0, - "time_min": 1, - "time_max": 2, - "slots_min": 3, - "slots_max": 6, - "SpawnPoints": "", - "BotSide": "Savage", "BotPreset": "normal", + "BotSide": "Savage", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", + "WildSpawnType": "assault", "isPlayers": false, - "WildSpawnType": "assault" + "number": 0, + "slots_max": 6, + "slots_min": 3, + "time_max": 2, + "time_min": 1 }, { - "number": 1, - "time_min": 10, - "time_max": 12, - "slots_min": 3, - "slots_max": 5, - "SpawnPoints": "", - "BotSide": "Usec", "BotPreset": "easy", + "BotSide": "Usec", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", + "WildSpawnType": "assault", "isPlayers": false, - "WildSpawnType": "assault" + "number": 1, + "slots_max": 5, + "slots_min": 3, + "time_max": 12, + "time_min": 10 } ], - "limits": [], - "AveragePlayTime": 100, - "AveragePlayerLevel": 10, - "escape_time_limit": 0, - "Rules": "Normal", - "IsSecret": false, - "doors": [], - "tmp_location_field_remove_me": 0, - "MinDistToExitPoint": 0, - "MaxDistToFreePoint": 900, - "MinDistToFreePoint": 10, - "MaxBotPerZone": 0, - "OpenZones": "", - "OcculsionCullingEnabled": false, - "GlobalLootChanceModifier": 0, - "OldSpawn": true, - "NewSpawn": false, - "BotMax": 0, - "BotStart": 0, - "BotStop": 0, - "BotMaxTimePlayer": 0, - "BotSpawnTimeOnMin": 0, - "BotSpawnTimeOnMax": 0, - "BotSpawnTimeOffMin": 0, - "BotSpawnTimeOffMax": 0, - "BotMaxPlayer": 0, - "BotEasy": 0, - "BotNormal": 0, - "BotHard": 0, - "BotImpossible": 0, - "BotAssault": 0, - "BotMarksman": 0, - "DisabledScavExits": "", - "AccessKeys": [], - "UnixDateTime": 0, - "users_gather_seconds": 0, - "users_spawn_seconds_n": 0, - "users_spawn_seconds_n2": 0, - "users_summon_seconds": 0, - "sav_summon_seconds": 0, - "matching_min_seconds": 0, - "MinMaxBots": [], "BotLocationModifier": { "AccuracySpeed": 0, - "Scattering": 0, + "DistToActivatePvE": 0, + "DistToSleepPvE": 0, + "FogVisibilityDistanceCoef": 0, + "FogVisibilitySpeedCoef": 0, "GainSight": 0, "MarksmanAccuratyCoef": 0, - "VisibleDistance": 0 + "RainVisibilityDistanceCoef": 0, + "RainVisibilitySpeedCoef": 0, + "Scattering": 0, + "VisibleDistance": 0, + "DistToActivate": 0, + "DistToSleep": 0 }, - "exits": [], "DisabledForScav": false, - "BossLocationSpawn": [], + "MinMaxBots": [], "SpawnPointParams": [], + "exits": [], "maxItemCountInLocation": [], "Id": "Suburbs", "_Id": "5714dc342459777137212e0b", @@ -104,16 +152,21 @@ { "id": "5807be8924597742c603fa19", "pic": { - "path": "CONTENT/banners/banner_tarkov.jpg", - "rcid": "" + "file": "67e4046dbec96f5d8e09732a.jpg", + "path": "banners/67e4046dbec96f5d8e09732a.jpg", + "rcid": "", + "type": "banners" } }, { "id": "5c1b857086f77465f465faa4", "pic": { - "path": "CONTENT/banners/banner_scavraider.jpg", - "rcid": "" + "file": "67e404c5bec96f5d8e09732f.jpg", + "path": "banners/67e404c5bec96f5d8e09732f.jpg", + "rcid": "", + "type": "banners" } } - ] + ], + "BossLocationSpawn": [] } diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/terminal/base.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/terminal/base.json index c63c81c1..bb9ad53c 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/terminal/base.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/terminal/base.json @@ -1,104 +1,161 @@ { + "AccessKeys": [], + "AccessKeysPvE": [], + "Area": 0, + "AveragePlayTime": 100, + "AveragePlayerLevel": 10, + "BotAssault": 0, + "BotEasy": 0, + "BotHard": 0, + "BotImpossible": 0, + "BotMarksman": 0, + "BotMax": 0, + "BotMaxPvE": 0, + "BotNormal": 0, + "BotSpawnCountStep": 3, + "BotSpawnPeriodCheck": 15, + "BotSpawnTimeOffMax": 0, + "BotSpawnTimeOffMin": 0, + "BotSpawnTimeOnMax": 0, + "BotSpawnTimeOnMin": 0, + "BotStart": 0, + "BotStartPlayer": 0, + "BotStop": 0, + "DisabledScavExits": "", + "EnableCoop": true, "Enabled": true, + "EscapeTimeLimit": 0, + "EscapeTimeLimitCoop": 0, + "ForceOnlineRaidInPVE": false, + "GlobalContainerChanceModifier": 1, + "HeatmapCellSize": { + "x": 1, + "y": 2, + "z": 1 + }, + "HeatmapLayers": [ + "AllCharactersPositions", + "AllBotsPositions", + "AllRealPlayersPositions", + "RealPlayersSavagesPositions", + "RealPlayersSavagesDeads", + "RealPlayersSavagesDamages", + "RealPlayersPmcPositions", + "RealPlayersPmcDeads", + "RealPlayersPmcDamages", + "RealPlayersPmcLaydownPositions", + "RealPlayersPmcEquipmentDropPositions", + "RealPlayersPmcHealingPositions", + "BotsBossPositions", + "BotsBossDeads", + "BotsBossDamages", + "BotsSavagesPositions", + "BotsSavagesDeads", + "BotsSavagesDamages", + "AllCharactersDamageSources", + "RealPlayerDamageSources", + "BotsDamageSources", + "LootPositions" + ], + "IconX": 280, + "IconY": 160, + "IsSecret": false, "Locked": true, - "Insurance": false, - "SafeLocation": false, + "MaxBotPerZone": 0, + "MaxCoopGroup": 9, + "MaxDistToFreePoint": 900, + "MaxPlayers": 9, + "MinDistToFreePoint": 10, + "MinPlayerLvlAccessKeys": 0, + "MinPlayers": 6, "Name": "Terminal", + "NewSpawn": false, + "NewSpawnForPlayers": false, + "NonWaveGroupScenario": { + "Chance": 50, + "Enabled": true, + "MaxToBeGroup": 3, + "MinToBeGroup": 2 + }, + "OcculsionCullingEnabled": false, + "OfflineNewSpawn": true, + "OfflineOldSpawn": true, + "OldSpawn": true, + "OpenZones": "", + "PlayersRequestCount": -1, + "PmcMaxPlayersInGroup": 5, + "RequiredPlayerLevelMax": 100, + "RequiredPlayerLevelMin": 0, + "Rules": "Normal", + "ScavMaxPlayersInGroup": 4, "Scene": { "path": "", "rcid": "" }, - "Area": 0, - "RequiredPlayerLevel": 0, - "MinPlayers": 6, - "MaxPlayers": 9, - "exit_count": 0, - "exit_access_time": 0, - "exit_time": 0, - "IconX": 280, - "IconY": 160, + "UnixDateTime": 0, + "doors": [], + "limits": [], "waves": [ { - "number": 0, - "time_min": 1, - "time_max": 2, - "slots_min": 3, - "slots_max": 6, - "SpawnPoints": "", - "BotSide": "Savage", "BotPreset": "easy", + "BotSide": "Savage", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", + "WildSpawnType": "assault", "isPlayers": false, - "WildSpawnType": "assault" + "number": 0, + "slots_max": 6, + "slots_min": 3, + "time_max": 2, + "time_min": 1 }, { - "number": 1, - "time_min": 10, - "time_max": 12, - "slots_min": 3, - "slots_max": 5, - "SpawnPoints": "", - "BotSide": "Savage", "BotPreset": "easy", + "BotSide": "Savage", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", + "WildSpawnType": "assault", "isPlayers": false, - "WildSpawnType": "assault" + "number": 1, + "slots_max": 5, + "slots_min": 3, + "time_max": 12, + "time_min": 10 } ], - "limits": [], - "AveragePlayTime": 100, - "AveragePlayerLevel": 10, - "escape_time_limit": 0, - "Rules": "Normal", - "IsSecret": false, - "doors": [], - "tmp_location_field_remove_me": 0, - "MinDistToExitPoint": 0, - "MaxDistToFreePoint": 900, - "MinDistToFreePoint": 10, - "MaxBotPerZone": 0, - "OpenZones": "", - "OcculsionCullingEnabled": false, - "GlobalLootChanceModifier": 0, - "OldSpawn": true, - "NewSpawn": false, - "BotMax": 0, - "BotStart": 0, - "BotStop": 0, - "BotMaxTimePlayer": 0, - "BotSpawnTimeOnMin": 0, - "BotSpawnTimeOnMax": 0, - "BotSpawnTimeOffMin": 0, - "BotSpawnTimeOffMax": 0, - "BotMaxPlayer": 0, - "BotEasy": 0, - "BotNormal": 0, - "BotHard": 0, - "BotImpossible": 0, - "BotAssault": 0, - "BotMarksman": 0, - "DisabledScavExits": "", - "AccessKeys": [], - "UnixDateTime": 0, - "users_gather_seconds": 0, - "users_spawn_seconds_n": 0, - "users_spawn_seconds_n2": 0, - "users_summon_seconds": 0, - "sav_summon_seconds": 0, - "matching_min_seconds": 0, - "MinMaxBots": [], "BotLocationModifier": { "AccuracySpeed": 0, - "Scattering": 0, + "DistToActivatePvE": 0, + "DistToSleepPvE": 0, + "FogVisibilityDistanceCoef": 0, + "FogVisibilitySpeedCoef": 0, "GainSight": 0, + "LockSpawnCheckRadius": 150, + "LockSpawnCheckRadiusPvE": 150, + "LockSpawnStartTime": 10, + "LockSpawnStartTimePvE": 10, + "LockSpawnStepTime": 50, + "LockSpawnStepTimePvE": 50, "MarksmanAccuratyCoef": 0, - "VisibleDistance": 0 + "NonWaveSpawnBotsLimitPerPlayer": 10, + "NonWaveSpawnBotsLimitPerPlayerPvE": 15, + "RainVisibilityDistanceCoef": 0, + "RainVisibilitySpeedCoef": 0, + "Scattering": 0, + "VisibleDistance": 0, + "DistToActivate": 0, + "DistToSleep": 0 }, - "exits": [], "DisabledForScav": false, - "BossLocationSpawn": [], + "MinMaxBots": [], "SpawnPointParams": [], + "exits": [], "maxItemCountInLocation": [], "Id": "Terminal", "_Id": "5704e5a4d2720bb45b8b4567", "Loot": [], - "Banners": [] + "Banners": [], + "BossLocationSpawn": [] } diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/town/base.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/town/base.json index cda252da..dbd0ffc1 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/town/base.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locations/town/base.json @@ -1,101 +1,149 @@ { + "AccessKeys": [], + "AccessKeysPvE": [], + "Area": 0, + "AveragePlayTime": 100, + "AveragePlayerLevel": 10, + "BotAssault": 0, + "BotEasy": 0, + "BotHard": 0, + "BotImpossible": 0, + "BotMarksman": 0, + "BotMax": 0, + "BotMaxPvE": 0, + "BotNormal": 0, + "BotSpawnCountStep": 3, + "BotSpawnPeriodCheck": 15, + "BotSpawnTimeOffMax": 0, + "BotSpawnTimeOffMin": 0, + "BotSpawnTimeOnMax": 0, + "BotSpawnTimeOnMin": 0, + "BotStart": 0, + "BotStartPlayer": 0, + "BotStop": 0, + "DisabledScavExits": "", + "EnableCoop": true, "Enabled": false, + "EscapeTimeLimit": 0, + "EscapeTimeLimitCoop": 0, + "ForceOnlineRaidInPVE": false, + "GlobalContainerChanceModifier": 1, + "HeatmapCellSize": { + "x": 1, + "y": 2, + "z": 1 + }, + "HeatmapLayers": [ + "AllCharactersPositions", + "AllBotsPositions", + "AllRealPlayersPositions", + "RealPlayersSavagesPositions", + "RealPlayersSavagesDeads", + "RealPlayersSavagesDamages", + "RealPlayersPmcPositions", + "RealPlayersPmcDeads", + "RealPlayersPmcDamages", + "RealPlayersPmcLaydownPositions", + "RealPlayersPmcEquipmentDropPositions", + "RealPlayersPmcHealingPositions", + "BotsBossPositions", + "BotsBossDeads", + "BotsBossDamages", + "BotsSavagesPositions", + "BotsSavagesDeads", + "BotsSavagesDamages", + "AllCharactersDamageSources", + "RealPlayerDamageSources", + "BotsDamageSources", + "LootPositions" + ], + "IconX": 72, + "IconY": 413, + "IsSecret": false, "Locked": true, - "Insurance": false, - "SafeLocation": false, + "MaxBotPerZone": 0, + "MaxCoopGroup": 9, + "MaxDistToFreePoint": 900, + "MaxPlayers": 9, + "MinDistToFreePoint": 10, + "MinPlayerLvlAccessKeys": 0, + "MinPlayers": 6, "Name": "Town", + "NewSpawn": false, + "NewSpawnForPlayers": false, + "NonWaveGroupScenario": { + "Chance": 50, + "Enabled": true, + "MaxToBeGroup": 3, + "MinToBeGroup": 2 + }, + "OcculsionCullingEnabled": false, + "OfflineNewSpawn": true, + "OfflineOldSpawn": true, + "OldSpawn": true, + "OpenZones": "", + "PlayersRequestCount": -1, + "PmcMaxPlayersInGroup": 5, + "RequiredPlayerLevelMax": 100, + "RequiredPlayerLevelMin": 0, + "Rules": "Normal", + "ScavMaxPlayersInGroup": 4, "Scene": { "path": "", "rcid": "" }, - "Area": 0, - "RequiredPlayerLevel": 0, - "MinPlayers": 6, - "MaxPlayers": 9, - "exit_count": 0, - "exit_access_time": 0, - "exit_time": 0, - "IconX": 72, - "IconY": 413, + "UnixDateTime": 0, + "doors": [], + "limits": [], "waves": [ { - "number": 0, - "time_min": 1, - "time_max": 2, - "slots_min": 3, - "slots_max": 6, - "SpawnPoints": "", - "BotSide": "Usec", "BotPreset": "hard", + "BotSide": "Usec", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", "WildSpawnType": "assault", - "isPlayers": false + "isPlayers": false, + "number": 0, + "slots_max": 6, + "slots_min": 3, + "time_max": 2, + "time_min": 1 }, { - "number": 1, - "time_min": 10, - "time_max": 12, - "slots_min": 3, - "slots_max": 5, - "SpawnPoints": "", - "BotSide": "Savage", "BotPreset": "normal", + "BotSide": "Savage", + "KeepZoneOnSpawn": false, + "SpawnMode": [], + "SpawnPoints": "", "WildSpawnType": "assault", - "isPlayers": false + "isPlayers": false, + "number": 1, + "slots_max": 5, + "slots_min": 3, + "time_max": 12, + "time_min": 10 } ], - "limits": [], - "AveragePlayTime": 100, - "AveragePlayerLevel": 10, - "escape_time_limit": 0, - "Rules": "Normal", - "IsSecret": false, - "doors": [], - "tmp_location_field_remove_me": 0, - "MinDistToExitPoint": 0, - "MaxDistToFreePoint": 900, - "MinDistToFreePoint": 10, - "MaxBotPerZone": 0, - "OpenZones": "", - "OcculsionCullingEnabled": false, - "GlobalLootChanceModifier": 0, - "OldSpawn": true, - "NewSpawn": false, - "BotMax": 0, - "BotStart": 0, - "BotStop": 0, - "BotMaxTimePlayer": 0, - "BotSpawnTimeOnMin": 0, - "BotSpawnTimeOnMax": 0, - "BotSpawnTimeOffMin": 0, - "BotSpawnTimeOffMax": 0, - "BotMaxPlayer": 0, - "BotEasy": 0, - "BotNormal": 0, - "BotHard": 0, - "BotImpossible": 0, - "BotAssault": 0, - "BotMarksman": 0, - "DisabledScavExits": "", - "AccessKeys": [], - "UnixDateTime": 0, - "users_gather_seconds": 0, - "users_spawn_seconds_n": 0, - "users_spawn_seconds_n2": 0, - "users_summon_seconds": 0, - "sav_summon_seconds": 0, - "matching_min_seconds": 0, - "MinMaxBots": [], "BotLocationModifier": { "AccuracySpeed": 0, - "Scattering": 0, + "DistToActivatePvE": 0, + "DistToSleepPvE": 0, + "FogVisibilityDistanceCoef": 0, + "FogVisibilitySpeedCoef": 0, "GainSight": 0, "MarksmanAccuratyCoef": 0, - "VisibleDistance": 0 + "RainVisibilityDistanceCoef": 0, + "RainVisibilitySpeedCoef": 0, + "Scattering": 0, + "VisibleDistance": 0, + "DistToActivate": 0, + "DistToSleep": 0 }, - "exits": [], "DisabledForScav": false, - "BossLocationSpawn": [], + "MinMaxBots": [], "SpawnPointParams": [], + "exits": [], "maxItemCountInLocation": [], "Id": "Town", "_Id": "5704e47ed2720bb35b8b4568", @@ -104,16 +152,21 @@ { "id": "5464e0454bdc2d06708b4567", "pic": { - "path": "CONTENT/banners/banner_bear.jpg", - "rcid": "" + "file": "67e4045225a1aca9270117e7.jpg", + "path": "banners/67e4045225a1aca9270117e7.jpg", + "rcid": "", + "type": "banners" } }, { "id": "5c1b857086f77465f465faa4", "pic": { - "path": "CONTENT/banners/banner_scavraider.jpg", - "rcid": "" + "file": "67e404c5bec96f5d8e09732f.jpg", + "path": "banners/67e404c5bec96f5d8e09732f.jpg", + "rcid": "", + "type": "banners" } } - ] + ], + "BossLocationSpawn": [] } diff --git a/Libraries/SPTarkov.Server.Assets/SPTarkov.Server.Assets.csproj b/Libraries/SPTarkov.Server.Assets/SPTarkov.Server.Assets.csproj index 52b5cd89..005fe28a 100644 --- a/Libraries/SPTarkov.Server.Assets/SPTarkov.Server.Assets.csproj +++ b/Libraries/SPTarkov.Server.Assets/SPTarkov.Server.Assets.csproj @@ -17,7 +17,15 @@ - + + Always + True + True + None + true + contentFiles\any\any\SPT_Data\ + + Always True True @@ -26,8 +34,11 @@ contentFiles\any\any\SPT_Data\ - - + + + + + diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs index 6a4dd183..62733df3 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs @@ -842,7 +842,7 @@ public class InsuranceController( ) ) { - logger.Warning( + logger.Debug( $"Unable to add item id: {itemId.ToString()} to client/insurance/items/list/cost response, already exists" ); } diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs index 8207a1d7..2bab4785 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs @@ -509,7 +509,7 @@ public class InventoryController( return presetHelper.GetBaseItemTpl(request.ItemId); } - if (request.FromOwner.Id == Traders.FENCE) + if (Traders.FENCE.Equals(request.FromOwner.Id)) // Get tpl from fence assorts { return fenceService.GetRawFenceAssorts().Items.FirstOrDefault(x => x.Id == request.ItemId)?.Template; @@ -519,10 +519,7 @@ public class InventoryController( // Not fence // get tpl from trader assort { - return databaseService - .GetTrader(request.FromOwner.Id.Value) - .Assort.Items.FirstOrDefault(item => item.Id == request.ItemId) - ?.Template; + return databaseService.GetTrader(request.FromOwner.Id).Assort.Items.FirstOrDefault(item => item.Id == request.ItemId)?.Template; } if (request.FromOwner.Type == "RagFair") @@ -536,7 +533,7 @@ public class InventoryController( // Try alternate way of getting offer if first approach fails var offer = - ragfairOfferService.GetOfferByOfferId(request.ItemId) ?? ragfairOfferService.GetOfferByOfferId(request.FromOwner.Id.Value); + ragfairOfferService.GetOfferByOfferId(request.ItemId) ?? ragfairOfferService.GetOfferByOfferId(request.FromOwner.Id); // Try find examine item inside offer items array var matchingItem = offer.Items.FirstOrDefault(offerItem => offerItem.Id == request.ItemId); @@ -555,6 +552,12 @@ public class InventoryController( return request.ItemId; } + // Hideout upgrade + if (request.FromOwner.Type == "HideoutUpgrade") + { + return request.ItemId; + } + if (request.FromOwner.Type == "Mail") { // when inspecting an item in mail rewards, we are given on the message its in and its mongoId, not the Template, so we have to go find it ourselves diff --git a/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs b/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs index a607935b..c9f79f4b 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs @@ -343,7 +343,7 @@ public class RagfairController( var offers = ragfairOfferService.GetOffersOfType(getPriceRequest.TemplateId); // Offers exist for item, get averages of what's listed - if (offers.Any()) + if (offers != null && offers.Any()) { // These get calculated while iterating through the list below var minMax = new MinMax(int.MaxValue, 0); @@ -858,7 +858,7 @@ public class RagfairController( if (logger.IsLogEnabled(LogLevel.Debug)) { - logger.Debug($"Offer tax to charge: {tax}, pulled from client: {storedClientTaxValue.Count is not null}"); + logger.Debug($"Offer tax to charge: {tax}, pulled from client: {storedClientTaxValue?.Count is not null}"); } // Cleanup of cache now we've used the tax value from it diff --git a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/ICommandoCommand.cs b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/ICommandoCommand.cs new file mode 100644 index 00000000..8e25bfbe --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/ICommandoCommand.cs @@ -0,0 +1,5 @@ +using SPTarkov.Server.Core.Helpers.Dialog.Commando; + +namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando; + +public interface ICommandoCommand : IChatCommand { } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommandoCommands.cs b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommandoCommands.cs index 0e69643b..4527d81d 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommandoCommands.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommandoCommands.cs @@ -1,5 +1,6 @@ using SPTarkov.DI.Annotations; using SPTarkov.Server.Core.Helpers.Dialog.Commando.SptCommands; +using SPTarkov.Server.Core.Helpers.Dialogue.Commando; using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Eft.Dialog; using SPTarkov.Server.Core.Models.Eft.Profile; @@ -10,7 +11,7 @@ using SPTarkov.Server.Core.Services; namespace SPTarkov.Server.Core.Helpers.Dialog.Commando; [Injectable] -public class SptCommandoCommands : IChatCommand +public class SptCommandoCommands : ICommandoCommand { protected readonly ServerLocalisationService _serverLocalisationService; protected readonly IDictionary _sptCommands; diff --git a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/CommandoDialogChatBot.cs b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/CommandoDialogChatBot.cs index 95f20310..e57fa993 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/CommandoDialogChatBot.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/CommandoDialogChatBot.cs @@ -1,5 +1,6 @@ using SPTarkov.DI.Annotations; using SPTarkov.Server.Core.Helpers.Dialog.Commando; +using SPTarkov.Server.Core.Helpers.Dialogue.Commando; using SPTarkov.Server.Core.Models.Eft.Profile; using SPTarkov.Server.Core.Models.Enums; using SPTarkov.Server.Core.Models.Spt.Config; @@ -15,7 +16,7 @@ public class CommandoDialogChatBot( MailSendService mailSendService, ServerLocalisationService localisationService, ConfigServer configServer, - IEnumerable chatCommands + IEnumerable chatCommands ) : AbstractDialogChatBot(logger, mailSendService, localisationService, chatCommands) { protected readonly CoreConfig CoreConfig = configServer.GetConfig(); diff --git a/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs index cc1083a2..688328df 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs @@ -860,7 +860,7 @@ public class InventoryHelper( else if (string.Equals(request.FromOwner.Type, "mail", StringComparison.OrdinalIgnoreCase)) { // Split requests don't use 'use' but 'splitItem' property - fromInventoryItems = dialogueHelper.GetMessageItemContents(request.FromOwner.Id.Value, sessionId, itemId); + fromInventoryItems = dialogueHelper.GetMessageItemContents(request.FromOwner.Id, sessionId, itemId); fromType = "mail"; } } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs index 332d2233..550be953 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs @@ -28,7 +28,6 @@ public class PrestigeHelper( var indexOfPrestigeObtained = Math.Clamp((prestige.PrestigeLevel ?? 1) - 1, 0, prestigeLevels.Count - 1); // Levels are 1 to 4, Index is 0 to 3 // Skill copy - var skillProgressCopyAmount = (float)(1 - prestigeLevels[indexOfPrestigeObtained].TransferConfigs.SkillConfig.TransferMultiplier); var masteringProgressCopyAmount = (float)( 1 - prestigeLevels[indexOfPrestigeObtained].TransferConfigs.MasteringConfig.TransferMultiplier @@ -90,6 +89,9 @@ public class PrestigeHelper( AddPrestigeRewardsToProfile(sessionId!.Value, newProfile, prestigeRewards); + // Copy profile stats + CopyStats(newProfile, oldProfile); + // Flag profile as having achieved this prestige level if (newProfile.CharacterData?.PmcData?.Prestige?.TryAdd(currentPrestigeData!.Id, timeUtil.GetTimeStamp()) is false) { @@ -126,6 +128,36 @@ public class PrestigeHelper( newProfile.CharacterData!.PmcData!.Info!.PrestigeLevel = prestige.PrestigeLevel; } + /// + /// Copy over profile stats from old profile to new + /// Remove some stats once copied over + /// + /// Profile to add stats to + /// Profile to copy stats from + protected void CopyStats(SptProfile newProfile, SptProfile oldProfile) + { + var newPmcStats = newProfile.CharacterData.PmcData.Stats; + var oldPmcStats = oldProfile.CharacterData.PmcData.Stats; + + newPmcStats.Eft = oldPmcStats.Eft; + + // Reset some PMC stats that should not be copied over + newPmcStats.Eft.CarriedQuestItems = []; + newPmcStats.Eft.FoundInRaidItems = []; + newPmcStats.Eft.LastSessionDate = 0; + + // TODO: find evidence scav stats are copied over in live + //var newScavStats = newProfile.CharacterData.ScavData.Stats; + //var oldScavStats = oldProfile.CharacterData.ScavData.Stats; + + //newPmcStats.Eft = oldScavStats.Eft; + + //// Reset some Scav stats that should not be copied over + //newScavStats.Eft.CarriedQuestItems = []; + //newScavStats.Eft.FoundInRaidItems = []; + //newScavStats.Eft.LastSessionDate = 0; + } + private void AddPrestigeRewardsToProfile(MongoId sessionId, SptProfile newProfile, IEnumerable rewards) { var itemsToSend = new List(); diff --git a/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs index 6ff44f61..1e98865c 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs @@ -1245,7 +1245,7 @@ public class QuestHelper( } /// - /// Create a clone of the given quest Collection with the rewards updated to reflect the given game version + /// Remove rewards from quests that do not fulfil the gameversion requirement /// /// List of quests to check /// Game version of the profile @@ -1255,15 +1255,15 @@ public class QuestHelper( foreach (var quest in quests) { // Remove any reward that doesn't pass the game edition check - var propsAsDict = quest.Rewards; - foreach (var rewardType in propsAsDict) + foreach (var rewardType in quest.Rewards) { if (rewardType.Value is null) { continue; } - propsAsDict[rewardType.Key] = propsAsDict[rewardType.Key] + quest.Rewards[rewardType.Key] = quest + .Rewards[rewardType.Key] .Where(reward => rewardHelper.RewardIsForGameEdition(reward, gameVersion)) .ToList(); } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs index d7e5559d..65d80fa7 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs @@ -14,6 +14,7 @@ using SPTarkov.Server.Core.Routers; using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; +using SPTarkov.Server.Core.Utils.Cloners; namespace SPTarkov.Server.Core.Helpers; @@ -38,7 +39,8 @@ public class RagfairOfferHelper( RagfairRequiredItemsService ragfairRequiredItemsService, ProfileHelper profileHelper, EventOutputHolder eventOutputHolder, - ConfigServer configServer + ConfigServer configServer, + ICloner cloner ) { protected const string GoodSoldTemplate = "5bdabfb886f7743e152e867e 0"; // Your {soldItem} {itemCount} items were bought by {buyerNickname}. @@ -63,8 +65,10 @@ public class RagfairOfferHelper( var playerIsFleaBanned = pmcData.PlayerIsFleaBanned(timeUtil.GetTimeStamp()); var tieredFlea = RagfairConfig.TieredFlea; var tieredFleaLimitTypes = tieredFlea.UnlocksType; - return ragfairOfferService - .GetOffers() + + // Clone offers if tiered flea is enabled as we perform modification of offer data prior to return + var offers = tieredFlea.Enabled ? cloner.Clone(ragfairOfferService.GetOffers()) : ragfairOfferService.GetOffers(); + return offers .Where(offer => { var offerRootItem = offer.Items.FirstOrDefault(); @@ -128,6 +132,7 @@ public class RagfairOfferHelper( { // Lock the offer if player's level is below the ammo's unlock requirement offer.Locked = true; + offer.User.Nickname = $"Unlock level: {unlockLevel}"; return; } @@ -140,6 +145,7 @@ public class RagfairOfferHelper( { // Lock the offer if player's level is below the item's specific requirement offer.Locked = true; + offer.User.Nickname = $"Unlock level: {itemLevelRequirement}"; return; } @@ -152,14 +158,22 @@ public class RagfairOfferHelper( } // Check if the item belongs to any restricted type and if player level is insufficient - if ( - tieredFleaLimitTypes - .Where(tieredItemType => itemHelper.IsOfBaseclass(offerItemTpl, tieredItemType)) - .Any(tieredItemType => playerLevel < tieredFlea.UnlocksType[tieredItemType]) - ) + var matchingTypes = tieredFleaLimitTypes.Where(tieredItemType => itemHelper.IsOfBaseclass(offerItemTpl, tieredItemType)); + if (!matchingTypes.Any()) + { + return; + } + + //Get all matches + var levelRequirements = tieredFlea.UnlocksType.Where(x => matchingTypes.Contains(x.Key)).Select(x => x.Value); + + // Get highest requirement + var highestRequirement = levelRequirements.Max(); + if (playerLevel < highestRequirement) { // Players level is below matching types requirement, flag as locked offer.Locked = true; + offer.User.Nickname = $"Unlock level: {levelRequirements.Max()}"; } } @@ -182,7 +196,7 @@ public class RagfairOfferHelper( var result = new List(); foreach ( var offer in offerIDsForItem - .Select(ragfairOfferService.GetOfferByOfferId) + .Select(tieredFlea.Enabled ? cloner.Clone(ragfairOfferService.GetOfferByOfferId) : ragfairOfferService.GetOfferByOfferId) // Clone offer when tiered flea enabled as we may modify offer data .Where(offer => PassesSearchFilterCriteria(searchRequest, offer, offer.Items.FirstOrDefault(), pmcData)) ) { @@ -220,7 +234,10 @@ public class RagfairOfferHelper( foreach (var desiredItemTpl in searchRequest.BuildItems) { - var matchingOffers = ragfairOfferService.GetOffersOfType(desiredItemTpl.Key); + // Clone offers when tiered flea enabled as we may modify the offer + var matchingOffers = tieredFlea.Enabled + ? cloner.Clone(ragfairOfferService.GetOffersOfType(desiredItemTpl.Key)) + : ragfairOfferService.GetOffersOfType(desiredItemTpl.Key); if (matchingOffers is null) // No offers found for this item, skip { diff --git a/Libraries/SPTarkov.Server.Core/Helpers/RagfairSortHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/RagfairSortHelper.cs index 2eb47f74..0c52e5cc 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RagfairSortHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RagfairSortHelper.cs @@ -33,7 +33,8 @@ public class RagfairSortHelper(LocaleService localeService) break; case RagfairSort.OFFER_TITLE: - offers.Sort(SortOffersByName); + var locale = localeService.GetLocaleDb(); + offers.Sort((offer, ragfairOffer) => SortOffersByName(offer, ragfairOffer, locale)); break; case RagfairSort.PRICE: @@ -75,14 +76,12 @@ public class RagfairSortHelper(LocaleService localeService) return ratingA.CompareTo(ratingB); } - protected int SortOffersByName(RagfairOffer a, RagfairOffer b) + protected int SortOffersByName(RagfairOffer a, RagfairOffer b, Dictionary locale) { - var locale = localeService.GetLocaleDb(); - - var tplA = a.Items[0].Template; - var tplB = b.Items[0].Template; - var nameA = locale.GetValueOrDefault($"{tplA} Name", tplA); - var nameB = locale.GetValueOrDefault($"{tplB} Name", tplB); + var tplA = a.Items.First().Template; + var tplB = b.Items.First().Template; + var nameA = locale.GetValueOrDefault($"{tplA} Name", tplA.ToString()); + var nameB = locale.GetValueOrDefault($"{tplB} Name", tplB.ToString()); return string.CompareOrdinal(nameA, nameB); } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/LocationBase.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/LocationBase.cs index 8e974e0f..56d6689e 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/LocationBase.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/LocationBase.cs @@ -586,7 +586,7 @@ public record BotLocationModifier public double? AccuracySpeed { get; set; } [JsonPropertyName("AdditionalHostilitySettings")] - public IEnumerable AdditionalHostilitySettings { get; set; } + public IEnumerable? AdditionalHostilitySettings { get; set; } [JsonPropertyName("DistToActivate")] public double? DistanceToActivate { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Request/BaseInteractionRequestData.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Request/BaseInteractionRequestData.cs index 31b6a5c2..52984bd1 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Request/BaseInteractionRequestData.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Request/BaseInteractionRequestData.cs @@ -18,7 +18,7 @@ public record BaseInteractionRequestData public record OwnerInfo { [JsonPropertyName("id")] - public MongoId? Id { get; set; } + public string? Id { get; set; } [JsonPropertyName("type")] public string? Type { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs index ec9efa64..dd601592 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs @@ -425,6 +425,7 @@ public record MasterySkill public record CommonSkill { + [JsonConverter(typeof(SafeDoubleConverter))] public double PointsEarnedDuringSession { get; set; } public long LastAccess { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/BotConfig.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/BotConfig.cs index 690111d9..fb11db48 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/BotConfig.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/BotConfig.cs @@ -131,6 +131,12 @@ public record BotConfig : BaseConfig /// [JsonPropertyName("weeklyBoss")] public required WeeklyBossSettings WeeklyBoss { get; set; } + + /// + /// Replace all scavs across all maps with the provided WildSpawnType + /// + [JsonPropertyName("replaceScavWith")] + public required WildSpawnType ReplaceScavWith { get; set; } } public record WeeklyBossSettings diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Mod/AbstractModMetadata.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Mod/AbstractModMetadata.cs index 17d0c435..b711730e 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Spt/Mod/AbstractModMetadata.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Mod/AbstractModMetadata.cs @@ -1,4 +1,6 @@ -using Range = SemanticVersioning.Range; +using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Utils.Json.Converters; +using Range = SemanticVersioning.Range; using Version = SemanticVersioning.Version; namespace SPTarkov.Server.Core.Models.Spt.Mod; @@ -40,6 +42,7 @@ public abstract record AbstractModMetadata ///
/// Version = new Version("1.0.0.0"); is not /// + [JsonConverter(typeof(ToStringJsonConverter))] public abstract Version Version { get; init; } /// @@ -49,6 +52,7 @@ public abstract record AbstractModMetadata ///
/// Version = new Version("4.0.0.0"); is not ///
+ [JsonConverter(typeof(ToStringJsonConverter))] public abstract Range SptVersion { get; init; } /// diff --git a/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs b/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs index 5edb94c2..bc296251 100644 --- a/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs @@ -210,7 +210,7 @@ public class LocationLifecycleService( foreach (var botId in PMCConfig.HostilitySettings) { var configHostilityChanges = PMCConfig.HostilitySettings[botId.Key]; - var locationBotHostilityDetails = location.BotLocationModifier.AdditionalHostilitySettings.FirstOrDefault(botSettings => + var locationBotHostilityDetails = location.BotLocationModifier.AdditionalHostilitySettings?.FirstOrDefault(botSettings => string.Equals(botSettings.BotRole, botId.Key, StringComparison.OrdinalIgnoreCase) ); diff --git a/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs b/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs index 6c1bc4c5..0540ca96 100644 --- a/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs @@ -252,9 +252,15 @@ public class CustomItemService( { lazyLoad.AddTransformer(localeData => { - localeData.Add($"{newItemId} Name", newLocaleDetails.Name); - localeData.Add($"{newItemId} ShortName", newLocaleDetails.ShortName); - localeData.Add($"{newItemId} Description", newLocaleDetails.Description); + if (!localeData.TryAdd($"{newItemId} Name", newLocaleDetails.Name)) + { + logger.Error($"Error adding locale `{newItemId} Name` to {shortNameKey.Key}, duplicate key"); + } + else + { + localeData.TryAdd($"{newItemId} ShortName", newLocaleDetails.ShortName); + localeData.TryAdd($"{newItemId} Description", newLocaleDetails.Description); + } return localeData; }); diff --git a/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs b/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs index 71e2c04f..528c5d29 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs @@ -131,6 +131,30 @@ public class PostDbLoadService( var chosenBoss = GetWeeklyBoss(BotConfig.WeeklyBoss.BossPool, BotConfig.WeeklyBoss.ResetDay); FlagMapAsGuaranteedBoss(chosenBoss); } + + if (BotConfig.ReplaceScavWith != WildSpawnType.assault) + { + ReplaceScavWavesWithRole(BotConfig.ReplaceScavWith); + } + } + + protected void ReplaceScavWavesWithRole(WildSpawnType newScavRole) + { + foreach (var location in databaseService.GetLocations().GetDictionary().Values) + { + if (location.Base?.Waves is null) + { + continue; + } + + foreach (var wave in location.Base.Waves) + { + if (wave.WildSpawnType == WildSpawnType.assault) + { + wave.WildSpawnType = newScavRole; + } + } + } } /// diff --git a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs index 49a309c5..2fc9bcbb 100644 --- a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs @@ -198,7 +198,7 @@ public class ProfileFixerService( if (customizationDb.ContainsKey(pmcProfile.Customization.Feet.Value)) { var defaultFeet = playerIsUsec - ? customizationDbArray.FirstOrDefault(x => x.Name == "DefaultUsecFeet") + ? customizationDbArray.FirstOrDefault(x => x.Name == "DefaulUsecFeet") : customizationDbArray.FirstOrDefault(x => x.Name == "DefaultBearFeet"); pmcProfile.Customization.Feet = defaultFeet.Id; } diff --git a/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs b/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs index 8d526488..6347176b 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs @@ -49,6 +49,11 @@ public class RagfairOfferService( return ragfairOfferHolder.GetOfferById(offerId); } + /// + /// Get offers for a desired item tpl + /// + /// Id of item to get offers for + /// IEnumerable public IEnumerable? GetOffersOfType(MongoId templateId) { return ragfairOfferHolder.GetOffersByTemplate(templateId); diff --git a/Libraries/SPTarkov.Server.Core/Services/RaidTimeAdjustmentService.cs b/Libraries/SPTarkov.Server.Core/Services/RaidTimeAdjustmentService.cs index e5287444..d27be8da 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RaidTimeAdjustmentService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RaidTimeAdjustmentService.cs @@ -1,4 +1,5 @@ using SPTarkov.DI.Annotations; +using SPTarkov.Server.Core.Constants; using SPTarkov.Server.Core.Helpers; using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Eft.Common; @@ -157,6 +158,21 @@ public class RaidTimeAdjustmentService( wave.TimeMax -= (int)Math.Max(startSeconds, 0); } + // Now additionally move all PMCs back so they spawn starting at the beginning of the raid + var pmcSpawns = mapBase.BossLocationSpawn.Where(boss => boss.BossName is Sides.PmcUsec or Sides.PmcBear); + var firstPmcSpawn = pmcSpawns.OrderBy(boss => boss.Time).FirstOrDefault(); + if (firstPmcSpawn != null) + { + var pmcStartSeconds = firstPmcSpawn.Time.GetValueOrDefault(1); + foreach (var spawn in pmcSpawns) + { + // Sanity check, the client won't spawn a time of 0 + spawn.Time = (double)Math.Max(spawn.Time.GetValueOrDefault(1) - pmcStartSeconds, 1); + } + + logger.Debug($"Offset PMC spawns by {pmcStartSeconds} seconds"); + } + logger.Debug( $"Removed: {originalPmcWaveCount - mapBase.BossLocationSpawn.Count} boss waves from map due to simulated raid start time of {raidAdjustments.SimulatedRaidStartSeconds / 60} minutes" ); diff --git a/Libraries/SPTarkov.Server.Core/Services/SeasonalEventService.cs b/Libraries/SPTarkov.Server.Core/Services/SeasonalEventService.cs index 408c9fe4..a408a21c 100644 --- a/Libraries/SPTarkov.Server.Core/Services/SeasonalEventService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/SeasonalEventService.cs @@ -615,7 +615,7 @@ public class SeasonalEventService( foreach (var settings in newHostilitySettings) { - var matchingBaseSettings = locationBase.Base.BotLocationModifier.AdditionalHostilitySettings.FirstOrDefault(x => + var matchingBaseSettings = locationBase.Base.BotLocationModifier?.AdditionalHostilitySettings?.FirstOrDefault(x => x.BotRole == settings.BotRole ); if (matchingBaseSettings is null) diff --git a/Libraries/SPTarkov.Server.Core/Utils/App.cs b/Libraries/SPTarkov.Server.Core/Utils/App.cs index c7ad8938..4c8bd14f 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/App.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/App.cs @@ -32,7 +32,15 @@ public class App( if (logger.IsLogEnabled(LogLevel.Debug)) { + var totalMemoryBytes = GC.GetGCMemoryInfo().TotalAvailableMemoryBytes; + + // Convert bytes to GB + var totalMemoryGb = totalMemoryBytes / (1024.0 * 1024.0 * 1024.0); + var pageFileGb = Environment.SystemPageSize / (1024.0 * 1024.0 * 1024.0); + logger.Debug($"OS: {Environment.OSVersion.Version} | {Environment.OSVersion.Platform}"); + logger.Debug($"Pagefile: {pageFileGb:F2} GB"); + logger.Debug($"RAM: {totalMemoryGb:F2} GB"); logger.Debug($"Ran as admin: {Environment.IsPrivilegedProcess}"); logger.Debug($"CPU cores: {Environment.ProcessorCount}"); logger.Debug($"PATH: {(Environment.ProcessPath ?? "null returned").Encode(EncodeType.BASE64)}"); diff --git a/Libraries/SPTarkov.Server.Core/Utils/Collections/ProbabilityObjectArray.cs b/Libraries/SPTarkov.Server.Core/Utils/Collections/ProbabilityObjectArray.cs index 670de92c..3ef05bfe 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/Collections/ProbabilityObjectArray.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/Collections/ProbabilityObjectArray.cs @@ -159,7 +159,13 @@ public class ProbabilityObjectArray : List> for (var i = 0; i < itemCountToDraw; i++) { var rand = Random.Shared.NextDouble(); - var randomIndex = cumulativeProbabilities.FindIndex(probability => probability > rand); + var randomIndex = cumulativeProbabilities.FindIndex(probability => probability >= rand); + + if (randomIndex == -1) + { + continue; + } + results.Add(this[randomIndex].Key); } diff --git a/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs b/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs index b3f3e4ab..8a961dbb 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/FileUtil.cs @@ -1,3 +1,4 @@ +using System.Text; using SPTarkov.DI.Annotations; namespace SPTarkov.Server.Core.Utils; @@ -101,27 +102,52 @@ public class FileUtil public async Task WriteFileAsync(string filePath, string fileContent) { - if (!DirectoryExists(Path.GetDirectoryName(filePath))) - { - CreateDirectory(Path.GetDirectoryName(filePath)); - } - - if (!FileExists(filePath)) - { - CreateFile(filePath); - } - - await File.WriteAllTextAsync(filePath, fileContent); + var bytes = Encoding.UTF8.GetBytes(fileContent); + await WriteFileAsync(filePath, bytes); } + /// + /// Writes a file atomically by first writing to a temporary file, then replacing the original. + /// This prevents corruption if the write operation fails or is interrupted. + /// public async Task WriteFileAsync(string filePath, byte[] fileContent) { - if (!FileExists(filePath)) + var directoryPath = Path.GetDirectoryName(filePath); + + if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath)) { - CreateFile(filePath); + Directory.CreateDirectory(directoryPath); } - await File.WriteAllBytesAsync(filePath, fileContent); + var tempFilePath = filePath + ".bak"; + + try + { + await using ( + var fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true) + ) + { + await fs.WriteAsync(fileContent); + + // We flush here so we can be sure it's immediately committed to disk + await fs.FlushAsync(); + } + + // Overwrite over the old file + File.Move(tempFilePath, filePath, overwrite: true); + } + catch + { + if (File.Exists(tempFilePath)) + { + try + { + File.Delete(tempFilePath); + } + catch { } + } + throw; + } } private void CreateFile(string filePath) diff --git a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/SafeDoubleConverter.cs b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/SafeDoubleConverter.cs new file mode 100644 index 00000000..5a5ca511 --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/SafeDoubleConverter.cs @@ -0,0 +1,49 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace SPTarkov.Server.Core.Utils.Json.Converters; + +public class SafeDoubleConverter : JsonConverter +{ + public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + switch (reader.TokenType) + { + case JsonTokenType.Number: + try + { + return reader.GetDouble(); + } + catch (FormatException) + { + try + { + var decimalValue = reader.GetDecimal(); + return decimalValue > 0 ? double.MaxValue : 0; + } + catch + { + return double.MaxValue; + } + } + + case JsonTokenType.String: + if (double.TryParse(reader.GetString(), out var stringParsed)) + { + return stringParsed; + } + return 0; + + case JsonTokenType.Null: + return 0; + + default: + return 0; + } + } + + public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options) + { + writer.WriteNumberValue(value); + } +} diff --git a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/ToStringJsonConverter.cs b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/ToStringJsonConverter.cs new file mode 100644 index 00000000..11069f08 --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/ToStringJsonConverter.cs @@ -0,0 +1,42 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace SPTarkov.Server.Core.Utils.Json.Converters; + +internal class ToStringJsonConverter : JsonConverter +{ + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return default; + } + + if (reader.TokenType == JsonTokenType.String) + { + var value = reader.GetString(); + try + { + return (T?)Activator.CreateInstance(typeToConvert, value); + } + catch (Exception ex) + { + throw new JsonException($"Unable to convert \"{value}\" to {typeof(T).Name}.", ex); + } + } + + throw new JsonException($"Expected string to deserialize {typeof(T).Name} but got {reader.TokenType}."); + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteNullValue(); + } + else + { + writer.WriteStringValue(value.ToString()); + } + } +} diff --git a/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs b/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs index c866bc75..c5434228 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs @@ -20,7 +20,9 @@ public class JsonUtil ReadCommentHandling = JsonCommentHandling.Skip, WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, +#if DEBUG UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, +#endif Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, }; diff --git a/Libraries/SPTarkov.Server.Web/SPTWeb.cs b/Libraries/SPTarkov.Server.Web/SPTWeb.cs index c4c11bc3..d1dff139 100644 --- a/Libraries/SPTarkov.Server.Web/SPTWeb.cs +++ b/Libraries/SPTarkov.Server.Web/SPTWeb.cs @@ -17,7 +17,6 @@ public static class SPTWeb builder.WebHost.UseStaticWebAssets(); builder.Services.AddMudServices(); - builder.Services.AddRazorComponents().AddInteractiveServerComponents(); var mvcBuilder = builder.Services.AddControllers(); @@ -25,6 +24,8 @@ public static class SPTWeb { mvcBuilder.AddApplicationPart(assembly); } + + builder.Services.AddRazorComponents().AddInteractiveServerComponents(); } public static void UseSptBlazor(this WebApplication app) @@ -33,6 +34,7 @@ public static class SPTWeb app.UseAntiforgery(); app.UseStaticFiles(); + app.MapControllers(); var razorBuilder = app.MapRazorComponents().AddInteractiveServerRenderMode(); @@ -67,7 +69,5 @@ public static class SPTWeb ); } } - - app.MapControllers(); } } diff --git a/SPTarkov.Server/Program.cs b/SPTarkov.Server/Program.cs index 443debc0..c8c94860 100644 --- a/SPTarkov.Server/Program.cs +++ b/SPTarkov.Server/Program.cs @@ -32,6 +32,14 @@ public static class Program { await StartServer(args); } + catch (SocketException) + { + Console.WriteLine("========================================================================================================="); + Console.WriteLine("You have multiple servers running or another process using port 6969"); + Console.WriteLine("========================================================================================================="); + Console.WriteLine("Press any key to exit..."); + Console.ReadLine(); + } catch (Exception e) { Console.WriteLine("========================================================================================================="); @@ -226,7 +234,9 @@ public static class Program private static void SetConsoleOutputMode() { - if (!OperatingSystem.IsWindows()) + var disableFlag = Environment.GetEnvironmentVariable("DISABLE_VIRTUAL_TERMINAL"); + + if (!OperatingSystem.IsWindows() || disableFlag == "1" || string.Equals(disableFlag, "true", StringComparison.OrdinalIgnoreCase)) { return; }