Merge tag '4.0.9'
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<!-- SPT specific -->
|
||||
<SptVersion Condition="'$(SptVersion)' == ''">4.0.8</SptVersion>
|
||||
<SptVersion Condition="'$(SptVersion)' == ''">4.0.9</SptVersion>
|
||||
<SptCommit Condition="'$(SptCommit)' == ''">a12b34</SptCommit>
|
||||
<SptBuildTime Condition="'$(SptBuildTime)' == ''">0000000000</SptBuildTime>
|
||||
<SptBuildType Condition="'$(SptBuildType)' == ''">LOCAL</SptBuildType>
|
||||
|
||||
@@ -9930,7 +9930,8 @@
|
||||
"adjustBotAppearances": true,
|
||||
"enableChristmasHideout": true,
|
||||
"enableSanta": true,
|
||||
"enableRundansEvent": true
|
||||
"enableRundansEvent": true,
|
||||
"enableKhorvodEvent": true
|
||||
},
|
||||
"startDay": "13",
|
||||
"startMonth": "12",
|
||||
@@ -9944,6 +9945,7 @@
|
||||
"settings": {
|
||||
"adjustBotAppearances": true,
|
||||
"enableChristmasHideout": true,
|
||||
"enableKhorvodEvent": true,
|
||||
"enableSanta": true
|
||||
},
|
||||
"startDay": "1",
|
||||
@@ -13997,5 +13999,23 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"khorovodEventTransitWhitelist": {
|
||||
"shoreline": [
|
||||
24
|
||||
],
|
||||
"lighthouse": [
|
||||
22
|
||||
],
|
||||
"rezervbase": [
|
||||
19
|
||||
],
|
||||
"woods": [
|
||||
41
|
||||
],
|
||||
"bigmap": [
|
||||
11
|
||||
],
|
||||
"interchange": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35191,6 +35191,7 @@
|
||||
],
|
||||
"active": false,
|
||||
"activePVE": false,
|
||||
"initialFrozenDelaySec": 60,
|
||||
"applyFrozenEverySec": 1,
|
||||
"consumables": [
|
||||
"67586bee39b1b82b0d0f9d06"
|
||||
|
||||
@@ -396,7 +396,8 @@ public class DialogueController(
|
||||
var checkTime = message.DateTime + (message.MaxStorageTime ?? 0);
|
||||
return timeNow < checkTime;
|
||||
})
|
||||
.ToList() ?? [];
|
||||
.ToList()
|
||||
?? [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -781,23 +781,23 @@ public class HideoutController(
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Validate that we have a matching production
|
||||
var productionDict = pmcData.Hideout.Production;
|
||||
// Find craft/production in player profile
|
||||
MongoId? prodId = null;
|
||||
foreach (var (productionId, production) in productionDict)
|
||||
foreach (var (productionId, productionInProfile) in pmcData.Hideout.Production)
|
||||
{
|
||||
// Skip undefined production objects
|
||||
if (production is null)
|
||||
// Skip undefined production objects caused by continious crafts
|
||||
if (productionInProfile is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (production.RecipeId != request.RecipeId)
|
||||
// Not craft we're looking for
|
||||
if (productionInProfile.RecipeId != request.RecipeId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Production or ScavCase
|
||||
// Could be Production or ScavCase
|
||||
prodId = productionId; // Set to objects key
|
||||
break;
|
||||
}
|
||||
@@ -817,7 +817,6 @@ public class HideoutController(
|
||||
|
||||
// Variables for management of skill
|
||||
var craftingExpAmount = 0;
|
||||
|
||||
var counterHoursCrafting = GetCustomSptHoursCraftingTaskConditionCounter(pmcData, recipe);
|
||||
var totalCraftingHours = counterHoursCrafting.Value;
|
||||
|
||||
@@ -886,6 +885,21 @@ public class HideoutController(
|
||||
serverLocalisationService.GetText("inventory-no_stash_space"),
|
||||
BackendErrorCodes.NotEnoughSpace
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the crafting result to the stash, marked as FiR
|
||||
var addItemsRequest = new AddItemsDirectRequest
|
||||
{
|
||||
ItemsWithModsToAdd = itemAndChildrenToSendToPlayer,
|
||||
FoundInRaid = true,
|
||||
UseSortingTable = false,
|
||||
Callback = null,
|
||||
};
|
||||
inventoryHelper.AddItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -908,24 +922,10 @@ public class HideoutController(
|
||||
}
|
||||
}
|
||||
|
||||
// Add the crafting result to the stash, marked as FiR
|
||||
var addItemsRequest = new AddItemsDirectRequest
|
||||
{
|
||||
ItemsWithModsToAdd = itemAndChildrenToSendToPlayer,
|
||||
FoundInRaid = true,
|
||||
UseSortingTable = false,
|
||||
Callback = null,
|
||||
};
|
||||
inventoryHelper.AddItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// - increment skill point for crafting
|
||||
// - delete the production in profile Hideout.Production
|
||||
// - Increment skill point for crafting
|
||||
// - Delete the production in profile Hideout.Production
|
||||
// Hideout Management skill
|
||||
// ? use a configuration variable for the value?
|
||||
// ? Use a configuration variable for the value?
|
||||
var globals = databaseService.GetGlobals();
|
||||
profileHelper.AddSkillPointsToPlayer(
|
||||
pmcData,
|
||||
|
||||
@@ -607,7 +607,7 @@ public class RepeatableQuestController(
|
||||
fullProfile.SptData.FreeRepeatableRefreshUsedCount[repeatableTypeLower] = 0;
|
||||
|
||||
// Create stupid redundant change requirements from quest data
|
||||
generatedRepeatables.ChangeRequirement = new Dictionary<MongoId, ChangeRequirement?>();
|
||||
generatedRepeatables.ChangeRequirement = [];
|
||||
foreach (var quest in generatedRepeatables.ActiveQuests)
|
||||
{
|
||||
generatedRepeatables.ChangeRequirement.TryAdd(
|
||||
@@ -707,6 +707,7 @@ public class RepeatableQuestController(
|
||||
EndTime = 0,
|
||||
FreeChanges = hasAccess ? repeatableConfig.FreeChanges : 0,
|
||||
FreeChangesAvailable = hasAccess ? repeatableConfig.FreeChangesAvailable : 0,
|
||||
ChangeRequirement = [],
|
||||
};
|
||||
|
||||
// Add base object that holds repeatable data to profile
|
||||
@@ -770,6 +771,14 @@ public class RepeatableQuestController(
|
||||
/// <returns>True if unlocked</returns>
|
||||
protected bool PlayerHasDailyScavQuestsUnlocked(PmcData pmcData)
|
||||
{
|
||||
if (pmcData.TradersInfo.TryGetValue(Traders.FENCE, out var fence))
|
||||
{
|
||||
if (fence.Unlocked is not null && !fence.Unlocked.Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return pmcData.Hideout?.Areas?.FirstOrDefault(hideoutArea => hideoutArea.Type == HideoutAreas.IntelligenceCenter)?.Level >= 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1820,9 +1820,14 @@ public class BotEquipmentModGenerator(
|
||||
scopeSlot?.All(slot =>
|
||||
slot.Properties.Filters.FirstOrDefault()
|
||||
.Filter.All(tpl =>
|
||||
itemHelper.IsOfBaseclasses(tpl, whitelistedSightTypes) || itemHelper.IsOfBaseclass(tpl, BaseClasses.MOUNT)
|
||||
itemHelper.IsItemInDb(tpl)
|
||||
&& (
|
||||
itemHelper.IsOfBaseclasses(tpl, whitelistedSightTypes)
|
||||
|| itemHelper.IsOfBaseclass(tpl, BaseClasses.MOUNT)
|
||||
)
|
||||
) ?? false
|
||||
)
|
||||
)
|
||||
?? false
|
||||
)
|
||||
// Add mod to allowed list
|
||||
{
|
||||
|
||||
@@ -716,10 +716,8 @@ public class BotWeaponGenerator(
|
||||
|
||||
// Try to get cartridges from slots array first, if none found, try Cartridges array
|
||||
var cartridges =
|
||||
magazineTemplate.Value.Properties.Slots.FirstOrDefault()?.Properties?.Filters?.FirstOrDefault()?.Filter ?? magazineTemplate
|
||||
.Value.Properties.Cartridges.FirstOrDefault()
|
||||
?.Properties?.Filters?.FirstOrDefault()
|
||||
?.Filter;
|
||||
magazineTemplate.Value.Properties.Slots.FirstOrDefault()?.Properties?.Filters?.FirstOrDefault()?.Filter
|
||||
?? magazineTemplate.Value.Properties.Cartridges.FirstOrDefault()?.Properties?.Filters?.FirstOrDefault()?.Filter;
|
||||
|
||||
return cartridges ?? [];
|
||||
}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using SPTarkov.DI.Annotations;
|
||||
|
||||
namespace SPTarkov.Server.Core.Migration.Migrations.Fixes;
|
||||
|
||||
[Injectable]
|
||||
public sealed class InvalidRepeatableQuestFix : AbstractProfileMigration
|
||||
{
|
||||
public override string FromVersion
|
||||
{
|
||||
get { return "~4.0"; }
|
||||
}
|
||||
|
||||
public override string ToVersion
|
||||
{
|
||||
get { return "~4.0"; }
|
||||
}
|
||||
|
||||
public override string MigrationName
|
||||
{
|
||||
get { return "InvalidRepeatableQuestFix"; }
|
||||
}
|
||||
|
||||
public override bool CanMigrate(JsonObject profile, IEnumerable<IProfileMigration> previouslyRanMigrations)
|
||||
{
|
||||
if (profile["characters"]?["pmc"]?["RepeatableQuests"] is JsonArray repeatables)
|
||||
{
|
||||
foreach (var node in repeatables)
|
||||
{
|
||||
if (node is not JsonObject quest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var endTimeNode = quest["endTime"];
|
||||
var endTime = endTimeNode?.GetValue<int>() ?? 0;
|
||||
|
||||
if (endTime != 0 && quest["changeRequirement"] is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override JsonObject? Migrate(JsonObject profile)
|
||||
{
|
||||
if (profile["characters"]?["pmc"]?["RepeatableQuests"] is JsonArray repeatables)
|
||||
{
|
||||
foreach (var node in repeatables)
|
||||
{
|
||||
if (node is not JsonObject quest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var endTime = quest["endTime"]?.GetValue<int>() ?? 0;
|
||||
|
||||
if (endTime != 0 && quest["changeRequirement"] is null)
|
||||
{
|
||||
quest["endTime"] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.Migrate(profile);
|
||||
}
|
||||
}
|
||||
@@ -648,6 +648,9 @@ public record RunddansSettings
|
||||
[JsonPropertyName("applyFrozenEverySec")]
|
||||
public double ApplyFrozenEverySec { get; set; }
|
||||
|
||||
[JsonPropertyName("initialFrozenDelaySec")]
|
||||
public double InitialFrozenDelaySec { get; set; }
|
||||
|
||||
[JsonPropertyName("consumables")]
|
||||
public IEnumerable<string> Consumables { get; set; }
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
public record RepeatableQuest : Quest
|
||||
{
|
||||
[JsonPropertyName("changeCost")]
|
||||
public List<ChangeCost?>? ChangeCost { get; set; }
|
||||
public required List<ChangeCost> ChangeCost { get; set; }
|
||||
|
||||
[JsonPropertyName("changeStandingCost")]
|
||||
public int? ChangeStandingCost { get; set; }
|
||||
@@ -94,7 +94,7 @@ public record PmcDataRepeatableQuest
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
[JsonPropertyName("changeRequirement")]
|
||||
public Dictionary<MongoId, ChangeRequirement?>? ChangeRequirement { get; set; }
|
||||
public required Dictionary<MongoId, ChangeRequirement> ChangeRequirement { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("freeChanges")]
|
||||
public int? FreeChanges { get; set; }
|
||||
@@ -106,10 +106,10 @@ public record PmcDataRepeatableQuest
|
||||
public record ChangeRequirement
|
||||
{
|
||||
[JsonPropertyName("changeCost")]
|
||||
public List<ChangeCost?>? ChangeCost { get; set; }
|
||||
public required List<ChangeCost> ChangeCost { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("changeStandingCost")]
|
||||
public double? ChangeStandingCost { get; set; }
|
||||
public required double ChangeStandingCost { get; set; }
|
||||
}
|
||||
|
||||
public record ChangeCost
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace SPTarkov.Server.Core.Models.Enums;
|
||||
|
||||
[Flags]
|
||||
public enum TransitionType
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
@@ -65,10 +65,10 @@ public record ArmorDurability
|
||||
public int MinLimitPercent { get; set; }
|
||||
|
||||
[JsonPropertyName("lowestMaxPercent")]
|
||||
public int LowestMaxPercent { get; set; }
|
||||
public int? LowestMaxPercent { get; set; }
|
||||
|
||||
[JsonPropertyName("highestMaxPercent")]
|
||||
public int HighestMaxPercent { get; set; }
|
||||
public int? HighestMaxPercent { get; set; }
|
||||
}
|
||||
|
||||
public record WeaponDurability
|
||||
|
||||
@@ -47,6 +47,9 @@ public record SeasonalEventConfig : BaseConfig
|
||||
[JsonPropertyName("hostilitySettingsForEvent")]
|
||||
public required Dictionary<string, Dictionary<string, List<AdditionalHostilitySettings>>> HostilitySettingsForEvent { get; set; }
|
||||
|
||||
[JsonPropertyName("khorovodEventTransitWhitelist")]
|
||||
public required Dictionary<string, List<int>> KhorovodEventTransitWhitelist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ids of containers on locations that only have Christmas loot
|
||||
/// </summary>
|
||||
@@ -143,6 +146,9 @@ public record SeasonalEventSettings
|
||||
|
||||
[JsonPropertyName("enableRundansEvent")]
|
||||
public bool? EnableRundansEvent { get; set; }
|
||||
|
||||
[JsonPropertyName("enableKhorvodEvent")]
|
||||
public bool? EnableKhorvodEvent { get; set; }
|
||||
}
|
||||
|
||||
public record ZombieSettings
|
||||
|
||||
@@ -16,12 +16,11 @@ public class ItemBaseClassService(
|
||||
ServerLocalisationService serverLocalisationService
|
||||
)
|
||||
{
|
||||
private bool _cacheGenerated;
|
||||
|
||||
/// <summary>
|
||||
/// Key = Item tpl, values = Ids of its parents
|
||||
/// </summary>
|
||||
private Dictionary<MongoId, HashSet<MongoId>> _itemBaseClassesCache = [];
|
||||
private readonly Lock _itemBaseClassesLock = new();
|
||||
private readonly HashSet<MongoId> _rootNodeIds = [];
|
||||
|
||||
/// <summary>
|
||||
@@ -36,23 +35,32 @@ public class ItemBaseClassService(
|
||||
var items = databaseService.GetItems();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (string.Equals(item.Value.Type, "Item", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var itemIdToUpdate = item.Value.Id;
|
||||
if (!_itemBaseClassesCache.ContainsKey(item.Value.Id))
|
||||
{
|
||||
_itemBaseClassesCache[item.Value.Id] = [];
|
||||
AddItemToCache(item.Key);
|
||||
}
|
||||
}
|
||||
|
||||
AddBaseItems(itemIdToUpdate, item.Value);
|
||||
public void AddItemToCache(MongoId itemTpl)
|
||||
{
|
||||
var itemDb = databaseService.GetItems();
|
||||
|
||||
if (!itemDb.TryGetValue(itemTpl, out var item))
|
||||
{
|
||||
logger.Error($"Could not add {itemTpl} to cache, it does not exist in the item database!");
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_itemBaseClassesLock)
|
||||
{
|
||||
if (string.Equals(item.Type, "Item", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_itemBaseClassesCache.TryAdd(item.Id, []);
|
||||
AddBaseItems(item.Id, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rootNodeIds.Add(item.Key);
|
||||
_rootNodeIds.Add(item.Id);
|
||||
}
|
||||
}
|
||||
|
||||
_cacheGenerated = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -79,11 +87,6 @@ public class ItemBaseClassService(
|
||||
/// <returns> true if item inherits from base class passed in </returns>
|
||||
public bool ItemHasBaseClass(MongoId itemTpl, IEnumerable<MongoId> baseClasses)
|
||||
{
|
||||
if (!_cacheGenerated)
|
||||
{
|
||||
HydrateItemBaseClassCache();
|
||||
}
|
||||
|
||||
if (itemTpl.IsEmpty)
|
||||
{
|
||||
logger.Warning("Unable to check itemTpl base class as value passed is null");
|
||||
@@ -101,14 +104,8 @@ public class ItemBaseClassService(
|
||||
var existsInCache = _itemBaseClassesCache.TryGetValue(itemTpl, out var baseClassList);
|
||||
if (!existsInCache)
|
||||
{
|
||||
// Not found
|
||||
if (logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
logger.Debug(serverLocalisationService.GetText("baseclass-item_not_found", itemTpl.ToString()));
|
||||
}
|
||||
|
||||
// Not found in cache, Hydrate again - some mods add items late in server startup lifecycle
|
||||
HydrateItemBaseClassCache();
|
||||
// Not found in cache, attempt to add first
|
||||
AddItemToCache(itemTpl);
|
||||
|
||||
existsInCache = _itemBaseClassesCache.TryGetValue(itemTpl, out baseClassList);
|
||||
}
|
||||
@@ -131,11 +128,6 @@ public class ItemBaseClassService(
|
||||
/// <returns> true if item inherits from base class passed in </returns>
|
||||
public bool ItemHasBaseClass(MongoId itemTpl, MongoId baseClasses)
|
||||
{
|
||||
if (!_cacheGenerated)
|
||||
{
|
||||
HydrateItemBaseClassCache();
|
||||
}
|
||||
|
||||
if (itemTpl.IsEmpty)
|
||||
{
|
||||
logger.Warning("Unable to check itemTpl base class as value passed is null");
|
||||
@@ -153,14 +145,8 @@ public class ItemBaseClassService(
|
||||
var existsInCache = _itemBaseClassesCache.TryGetValue(itemTpl, out var baseClassList);
|
||||
if (!existsInCache)
|
||||
{
|
||||
// Not found
|
||||
if (logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
logger.Debug(serverLocalisationService.GetText("baseclass-item_not_found", itemTpl.ToString()));
|
||||
}
|
||||
|
||||
// Not found in cache, Hydrate again - some mods add items late in server startup lifecycle
|
||||
HydrateItemBaseClassCache();
|
||||
// Not found in cache, attempt to add first
|
||||
AddItemToCache(itemTpl);
|
||||
|
||||
existsInCache = _itemBaseClassesCache.TryGetValue(itemTpl, out baseClassList);
|
||||
}
|
||||
@@ -182,11 +168,6 @@ public class ItemBaseClassService(
|
||||
/// <returns> array of base classes </returns>
|
||||
public HashSet<MongoId> GetItemBaseClasses(MongoId itemTpl)
|
||||
{
|
||||
if (!_cacheGenerated)
|
||||
{
|
||||
HydrateItemBaseClassCache();
|
||||
}
|
||||
|
||||
if (!_itemBaseClassesCache.TryGetValue(itemTpl, out var value))
|
||||
{
|
||||
return [];
|
||||
|
||||
@@ -58,6 +58,7 @@ public class LocationLifecycleService(
|
||||
protected readonly PmcConfig PMCConfig = configServer.GetConfig<PmcConfig>();
|
||||
protected readonly BotConfig BotConfig = configServer.GetConfig<BotConfig>();
|
||||
protected readonly LostOnDeathConfig LostOnDeathConfig = configServer.GetConfig<LostOnDeathConfig>();
|
||||
protected readonly SeasonalEventConfig SeasonalEventConfig = configServer.GetConfig<SeasonalEventConfig>();
|
||||
|
||||
protected const string Pmc = "pmc";
|
||||
protected const string Savage = "savage";
|
||||
@@ -93,21 +94,73 @@ public class LocationLifecycleService(
|
||||
: playerProfile.CharacterData.ScavData.Skills.Common
|
||||
);
|
||||
|
||||
var transitionType = TransitionType.NONE;
|
||||
|
||||
if (request.TransitionType is TransitionType flags)
|
||||
{
|
||||
if (flags.HasFlag(TransitionType.COMMON))
|
||||
{
|
||||
transitionType = TransitionType.COMMON;
|
||||
}
|
||||
|
||||
if (flags.HasFlag(TransitionType.EVENT))
|
||||
{
|
||||
transitionType = TransitionType.EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
// Raid is starting, adjust run times to reduce server load while player is in raid
|
||||
RagfairConfig.RunIntervalSeconds = RagfairConfig.RunIntervalValues.InRaid;
|
||||
HideoutConfig.RunIntervalSeconds = HideoutConfig.RunIntervalValues.InRaid;
|
||||
|
||||
var location = GenerateLocationAndLoot(sessionId, request.Location, !request.ShouldSkipLootGeneration ?? true);
|
||||
var isRundansActive = databaseService.GetGlobals().Configuration.RunddansSettings.Active;
|
||||
|
||||
if (transitionType == TransitionType.EVENT)
|
||||
{
|
||||
// Handle Runddans / Khorovod event
|
||||
if (isRundansActive && location.Transits is not null)
|
||||
{
|
||||
// Get whitelist for maps transits, event should have 1 only
|
||||
var matchingTransitWhitelist = SeasonalEventConfig.KhorovodEventTransitWhitelist.GetValueOrDefault(
|
||||
location.Id.ToLowerInvariant(),
|
||||
[]
|
||||
);
|
||||
|
||||
foreach (var transits in location.Transits)
|
||||
{
|
||||
if (transits.Id is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// ActivateAfterSeconds sets the timer on the generator, events is needed because it is checked again in the client
|
||||
// To enable certain stuff for the Khorovod event
|
||||
if (matchingTransitWhitelist.Contains(transits.Id.Value))
|
||||
{
|
||||
transits.ActivateAfterSeconds = 300;
|
||||
transits.Events = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable the other transits in this event, people are only allowed to transit to certain points
|
||||
transits.IsActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result = new StartLocalRaidResponseData
|
||||
{
|
||||
// PVE_OFFLINE_xxxxxxxx_27_06_2025_20_20_44
|
||||
ServerId = $"{request.Location}.{request.PlayerSide} {timeUtil.GetTimeStamp()}", // Only used for metrics in client
|
||||
ServerSettings = databaseService.GetLocationServices(), // TODO - is this per map or global?
|
||||
Profile = new ProfileInsuredItems { InsuredItems = playerProfile.CharacterData.PmcData.InsuredItems },
|
||||
LocationLoot = GenerateLocationAndLoot(sessionId, request.Location, !request.ShouldSkipLootGeneration ?? true),
|
||||
TransitionType = TransitionType.NONE,
|
||||
LocationLoot = location,
|
||||
TransitionType = transitionType,
|
||||
Transition = new Transition
|
||||
{
|
||||
TransitionType = TransitionType.NONE,
|
||||
TransitionType = transitionType,
|
||||
TransitionRaidId = new MongoId(),
|
||||
TransitionCount = 0,
|
||||
VisitedLocations = [],
|
||||
@@ -128,7 +181,7 @@ public class LocationLifecycleService(
|
||||
if (transitionData is not null)
|
||||
{
|
||||
logger.Success($"Player: {sessionId} is in transit to {request.Location}");
|
||||
result.Transition.TransitionType = TransitionType.COMMON;
|
||||
result.Transition.TransitionType = transitionType;
|
||||
result.Transition.TransitionRaidId = transitionData.TransitionRaidId;
|
||||
result.Transition.TransitionCount += 1;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class CustomItemService(
|
||||
|
||||
AddToFleaPriceDb(newItemId, newItemDetails.FleaPriceRoubles);
|
||||
|
||||
itemBaseClassService.HydrateItemBaseClassCache();
|
||||
itemBaseClassService.AddItemToCache(newItemId);
|
||||
|
||||
if (itemHelper.IsOfBaseclass(itemClone.Id, BaseClasses.WEAPON))
|
||||
{
|
||||
@@ -112,7 +112,7 @@ public class CustomItemService(
|
||||
|
||||
AddToFleaPriceDb(newItem.Id, newItemDetails.FleaPriceRoubles);
|
||||
|
||||
itemBaseClassService.HydrateItemBaseClassCache();
|
||||
itemBaseClassService.AddItemToCache(newItem.Id);
|
||||
|
||||
if (itemHelper.IsOfBaseclass(newItem.Id, BaseClasses.WEAPON))
|
||||
{
|
||||
|
||||
@@ -539,33 +539,39 @@ public class ProfileFixerService(
|
||||
foreach (var profileArea in pmcProfile.Hideout?.Areas ?? [])
|
||||
{
|
||||
var areaType = profileArea.Type;
|
||||
var level = profileArea.Level;
|
||||
var currentLevel = profileArea.Level;
|
||||
|
||||
if (level.GetValueOrDefault(0) == 0)
|
||||
if (currentLevel.GetValueOrDefault(0) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get array of hideout area upgrade levels to check for bonuses
|
||||
// Create array of hideout area upgrade levels player has installed
|
||||
// Zero indexed
|
||||
var areaLevelsToCheck = new List<string>();
|
||||
for (var index = 0; index < level + 1; index++)
|
||||
// Stage key is saved as string in db
|
||||
for (var index = 0; index < currentLevel + 1; index++)
|
||||
{
|
||||
areaLevelsToCheck.Add(index.ToString());
|
||||
areaLevelsToCheck.Add(index.ToString()); // Convert to string as hideout stage key is saved as string in db
|
||||
}
|
||||
|
||||
// Iterate over area levels, check for bonuses, add if needed
|
||||
// Get hideout area data from db
|
||||
var dbArea = dbHideoutAreas?.FirstOrDefault(area => area.Type == areaType);
|
||||
if (dbArea is null)
|
||||
if (dbArea is null || dbArea.Stages is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if profile is missing any bonuses from each area level
|
||||
foreach (var areaLevel in areaLevelsToCheck)
|
||||
{
|
||||
// Get areas level bonuses from db
|
||||
var levelBonuses = dbArea.Stages?[areaLevel].Bonuses;
|
||||
// Get areas level from db
|
||||
if (!dbArea.Stages.TryGetValue(areaLevel, out var stage))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the bonuses for this upgrade stage
|
||||
var levelBonuses = stage.Bonuses;
|
||||
if (levelBonuses is null || levelBonuses.Count == 0)
|
||||
{
|
||||
continue;
|
||||
@@ -578,8 +584,10 @@ public class ProfileFixerService(
|
||||
var profileBonus = GetBonusFromProfile(pmcProfile.Bonuses, bonus);
|
||||
if (profileBonus is null)
|
||||
{
|
||||
// no bonus, add to profile
|
||||
logger.Debug($"Profile has level {level} area {profileArea.Type} but no bonus found, adding {bonus.Type}");
|
||||
// No bonus in profile, add it
|
||||
logger.Debug(
|
||||
$"Profile has level: {currentLevel} area: {profileArea.Type} but no bonus found, adding: {bonus.Type}"
|
||||
);
|
||||
hideoutHelper.ApplyPlayerUpgradesBonus(pmcProfile, bonus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ public class App(
|
||||
logger.Debug($"OS: {Environment.OSVersion.Version} | {Environment.OSVersion.Platform}");
|
||||
logger.Debug($"Pagefile: {pageFileGb:F2} GB");
|
||||
logger.Debug($"RAM: {totalMemoryGb:F2} GB");
|
||||
if (totalMemoryGb < 30)
|
||||
{
|
||||
logger.Warning($"Detected RAM ({totalMemoryGb:F2}GB) is smaller than recommended (32GB) you may experience crashes or reduced FPS on large maps");
|
||||
}
|
||||
|
||||
logger.Debug($"Ran as admin: {Environment.IsPrivilegedProcess}");
|
||||
logger.Debug($"CPU cores: {Environment.ProcessorCount}");
|
||||
logger.Debug($"PATH: {(Environment.ProcessPath ?? "null returned").Encode(EncodeType.BASE64)}");
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"commandName": "Project",
|
||||
"hotReloadEnabled": false,
|
||||
"workingDirectory": "bin/$(Configuration)/$(TargetFramework)"
|
||||
},
|
||||
"Spt Server (Mac)": {
|
||||
"commandName": "Project",
|
||||
"hotReloadEnabled": false,
|
||||
"workingDirectory": "bin/$(Configuration)/$(TargetFramework)/osx-arm64"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64'">
|
||||
<AssemblyName>SPT.Server.Linux</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'osx-arm64'">
|
||||
<AssemblyName>SPT.Server.Mac</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Libraries\SPTarkov.Reflection\SPTarkov.Reflection.csproj" />
|
||||
<ProjectReference Include="..\Libraries\SPTarkov.Server.Core\SPTarkov.Server.Core.csproj" />
|
||||
|
||||
Reference in New Issue
Block a user