This is just Jetbrains formatting and code syntax styling

This commit is contained in:
CWX
2025-02-05 06:56:51 +00:00
parent ce78a2231e
commit f648f42721
382 changed files with 6348 additions and 10422 deletions
@@ -23,11 +23,10 @@ public class AchievementController(
var stats = new Dictionary<string, int>();
foreach (var achievement in achievements)
{
if (achievement.Id != null) stats.Add(achievement.Id, 0);
}
if (achievement.Id != null)
stats.Add(achievement.Id, 0);
return new()
return new CompletedAchievementsResponse
{
Elements = stats
};
+25 -69
View File
@@ -52,10 +52,7 @@ public class BotController(
.First(p => p.Name.ToLower() == (typeInLower == "assaultgroup" ? "assault" : typeInLower))
.GetValue(_botConfig.PresetBatch);
if (value != null)
{
return value;
}
if (value != null) return value;
_logger.Warning(_localisationService.GetText("bot-bot_preset_count_value_missing", type));
return 30;
@@ -70,18 +67,12 @@ public class BotController(
{
var difficulty = diffLevel.ToLower();
if (!(raidConfig != null || ignoreRaidSettings))
{
_logger.Error(_localisationService.GetText("bot-missing_application_context", "RAID_CONFIGURATION"));
}
if (!(raidConfig != null || ignoreRaidSettings)) _logger.Error(_localisationService.GetText("bot-missing_application_context", "RAID_CONFIGURATION"));
// Check value chosen in pre-raid difficulty dropdown
// If value is not 'asonline', change requested difficulty to be what was chosen in dropdown
var botDifficultyDropDownValue = raidConfig?.WavesSettings?.BotDifficulty?.ToString().ToLower() ?? "asonline";
if (botDifficultyDropDownValue != "asonline")
{
difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue);
}
if (botDifficultyDropDownValue != "asonline") difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue);
var botDb = _databaseService.GetBots();
return _botDifficultyHelper.GetBotDifficultySettings(type, difficulty, botDb);
@@ -96,10 +87,7 @@ public class BotController(
var botTypes = Enum.GetValues<WildSpawnType>().Select(item => item.ToString()).ToList();
foreach (var botType in botTypes)
{
if (botTypesDb is null)
{
continue;
}
if (botTypesDb is null) continue;
// If bot is usec/bear, swap to different name
var botTypeLower = _botHelper.IsBotPmc(botType)
@@ -113,10 +101,7 @@ public class BotController(
{
// No bot of this type found, copy details from assault
result[botTypeLower] = result["assault"];
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Unable to find bot: {botTypeLower} in db, copying 'assault'");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Unable to find bot: {botTypeLower} in db, copying 'assault'");
continue;
}
@@ -131,10 +116,7 @@ public class BotController(
foreach (var (difficultyName, _) in botDetails.BotDifficulty)
{
// Bot doesn't exist in result, add
if (!result.ContainsKey(botNameKey))
{
result.TryAdd(botNameKey, new Dictionary<string, DifficultyCategories>());
}
if (!result.ContainsKey(botNameKey)) result.TryAdd(botNameKey, new Dictionary<string, DifficultyCategories>());
// Store all difficulty values in dict keyed by difficulty type e.g. easy/normal/impossible
result[botNameKey].Add(difficultyName, GetBotDifficulty(botNameKey, difficultyName, null, true));
@@ -147,7 +129,7 @@ public class BotController(
public List<BotBase> Generate(string sessionId, GenerateBotsRequestData info)
{
var pmcProfile = _profileHelper.GetPmcProfile(sessionId);
// Use this opportunity to create and cache bots for later retrieval
var multipleBotTypesRequested = info.Conditions?.Count > 1;
return multipleBotTypesRequested
@@ -166,7 +148,6 @@ public class BotController(
var tasks = new List<Task>();
// Map conditions to promises for bot generation
foreach (var condition in request.Conditions ?? [])
{
tasks.Add(
Task.Factory.StartNew(
() =>
@@ -185,14 +166,10 @@ public class BotController(
}
)
);
}
Task.WaitAll(tasks.ToArray());
stopwatch.Stop();
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache");
return [];
}
@@ -220,24 +197,17 @@ public class BotController(
if (botCacheCount >= botGenerationDetails.BotCountToGenerate)
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Cache already has sufficient {cacheKey} bots: {botCacheCount}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Cache already has sufficient {cacheKey} bots: {botCacheCount}");
return;
}
// We're below desired count, add bots to cache
var botsToGenerate = botGenerationDetails.BotCountToGenerate - botCacheCount;
var progressWriter = new ProgressWriter(botGenerationDetails.BotCountToGenerate.GetValueOrDefault(30));
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Generating {botsToGenerate} bots for cacheKey: {cacheKey}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Generating {botsToGenerate} bots for cacheKey: {cacheKey}");
for (var i = 0; i < botsToGenerate; i++)
{
try
{
var detailsClone = _cloner.Clone(botGenerationDetails);
@@ -248,15 +218,12 @@ public class BotController(
{
_logger.Error($"Failed to generate bot: {botGenerationDetails.Role} #{i + 1}: {e.Message}");
}
}
if(_logger.IsLogEnabled(LogLevel.Debug))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
_logger.Debug(
$"Generated {botGenerationDetails.BotCountToGenerate} {botGenerationDetails.Role}" +
$"({botGenerationDetails.EventRole ?? botGenerationDetails.Role ?? ""}) {botGenerationDetails.BotDifficulty}bots"
);
}
}
private List<BotBase> ReturnSingleBotFromCache(string sessionId, GenerateBotsRequestData request)
@@ -271,7 +238,7 @@ public class BotController(
{
Role = requestedBot?.Role,
Limit = 5,
Difficulty = requestedBot?.Difficulty,
Difficulty = requestedBot?.Difficulty
};
var botGenerationDetails = GetBotGenerationDetailsForWave(
condition,
@@ -321,13 +288,9 @@ public class BotController(
{
var bossConvertPercent = bossConvertMinMax.GetByJsonProp<MinMax>(requestedBot?.Role?.ToLower() ?? string.Empty);
if (bossConvertPercent is not null)
{
// Roll a percentage check if we should convert scav to boss
if (_randomUtil.GetChance100(_randomUtil.GetDouble(bossConvertPercent.Min!.Value, bossConvertPercent.Max!.Value)))
{
UpdateBotGenerationDetailsToRandomBoss(botGenerationDetails, bossesToConvertToWeights);
}
}
}
// Create a compound key to store bots in cache against
@@ -341,14 +304,12 @@ public class BotController(
{
// No bot in cache, generate new and store in cache
GenerateSingleBotAndStoreInCache(botGenerationDetails, sessionId, cacheKey);
if(_logger.IsLogEnabled(LogLevel.Debug))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
_logger.Debug(
$"Generated {botGenerationDetails.BotCountToGenerate} " +
$"{botGenerationDetails.Role} ({botGenerationDetails.EventRole ?? ""}) {botGenerationDetails.BotDifficulty} bots"
);
}
}
var desiredBot = _botGenerationCacheService.GetBot(cacheKey);
@@ -400,10 +361,7 @@ public class BotController(
.GetLatestValue(ContextVariableType.RAID_CONFIGURATION)
?.GetValue<GetRaidConfigurationRequestData>();
if (raidSettings is null)
{
_logger.Warning(_localisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext"));
}
if (raidSettings is null) _logger.Warning(_localisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext"));
return raidSettings;
}
@@ -432,9 +390,9 @@ public class BotController(
BotRelativeLevelDeltaMin = _pmcConfig.BotRelativeLevelDeltaMin,
BotCountToGenerate = botCountToGenerate,
BotDifficulty = condition.Difficulty,
LocationSpecificPmcLevelOverride = this.GetPmcLevelRangeForMap(raidSettings?.Location), // Min/max levels for PMCs to generate within
LocationSpecificPmcLevelOverride = GetPmcLevelRangeForMap(raidSettings?.Location), // Min/max levels for PMCs to generate within
IsPlayerScav = false,
AllPmcsHaveSameNameAsPlayer = allPmcsHaveSameNameAsPlayer,
AllPmcsHaveSameNameAsPlayer = allPmcsHaveSameNameAsPlayer
};
}
@@ -442,11 +400,9 @@ public class BotController(
{
var botCap = _botConfig.MaxBotCap.FirstOrDefault(x => x.Key.ToLower() == location.ToLower());
if (location == "default")
{
_logger.Warning(
_localisationService.GetText("bot-no_bot_cap_found_for_location", location.ToLower())
);
}
return botCap.Value;
}
@@ -457,7 +413,7 @@ public class BotController(
{
PmcType = _pmcConfig.PmcType,
Assault = _botConfig.AssaultBrainType,
PlayerScav = _botConfig.PlayerScavBrainType,
PlayerScav = _botConfig.PlayerScavBrainType
};
}
}
@@ -465,11 +421,11 @@ public class BotController(
public record AiBotBrainTypes
{
[JsonPropertyName("pmc")]
public Dictionary<string,Dictionary<string,Dictionary<string,double>>> PmcType { get; set; }
public Dictionary<string, Dictionary<string, Dictionary<string, double>>> PmcType { get; set; }
[JsonPropertyName("assault")]
public Dictionary<string,Dictionary<string,int>> Assault { get; set; }
public Dictionary<string, Dictionary<string, int>> Assault { get; set; }
[JsonPropertyName("playerScav")]
public Dictionary<string,Dictionary<string,int>> PlayerScav { get; set; }
public Dictionary<string, Dictionary<string, int>> PlayerScav { get; set; }
}
+6 -13
View File
@@ -36,9 +36,7 @@ public class BuildController(
const string secureContainerSlotId = "SecuredContainer";
var profile = _profileHelper.GetFullProfile(sessionID);
if (profile is not null && profile.UserBuildData is null)
{
profile.UserBuildData = new UserBuilds { EquipmentBuilds = [], WeaponBuilds = [], MagazineBuilds = [] };
}
// Ensure the secure container in the default presets match what the player has equipped
var defaultEquipmentPresetsClone = _cloner.Clone(
@@ -52,18 +50,13 @@ public class BuildController(
x => x.SlotId == secureContainerSlotId
);
if (playerSecureContainer is not null && playerSecureContainer.Template != firstDefaultItemsSecureContainer?.Template)
{
// Default equipment presets' secure container tpl doesn't match players secure container tpl
foreach (var defaultPreset in defaultEquipmentPresetsClone ?? [])
{
// Find presets secure container
var secureContainer = defaultPreset.Items?.FirstOrDefault(item => item.SlotId == secureContainerSlotId);
if (secureContainer is not null)
{
secureContainer.Template = playerSecureContainer.Template;
}
if (secureContainer is not null) secureContainer.Template = playerSecureContainer.Template;
}
}
// Clone player build data from profile and append the above defaults onto end
var userBuildsClone = _cloner.Clone(profile?.UserBuildData);
@@ -87,7 +80,7 @@ public class BuildController(
body.Root = body.Items.FirstOrDefault().Id;
// Create new object ready to save into profile userbuilds.weaponBuilds
WeaponBuild newBuild = new WeaponBuild { Id = body.Id, Name = body.Name, Root = body.Root, Items = body.Items };
var newBuild = new WeaponBuild { Id = body.Id, Name = body.Name, Root = body.Root, Items = body.Items };
var profile = _profileHelper.GetFullProfile(sessionId);
@@ -124,13 +117,13 @@ public class BuildController(
// Root ID and the base item ID need to match.
request.Items = _itemHelper.ReplaceIDs(request.Items, pmcData);
EquipmentBuild newBuild = new EquipmentBuild
var newBuild = new EquipmentBuild
{
Id = request.Id,
Name = request.Name,
BuildType = EquipmentBuildType.Custom,
Root = request.Items[0].Id,
Items = request.Items,
Items = request.Items
};
var existingBuild = existingSavedEquipmentBuilds.FirstOrDefault(
@@ -167,14 +160,14 @@ public class BuildController(
/// <param name="request"></param>
public void CreateMagazineTemplate(string sessionId, SetMagazineRequest request)
{
MagazineBuild result = new MagazineBuild
var result = new MagazineBuild
{
Id = request.Id,
Name = request.Name,
Caliber = request.Caliber,
TopCount = request.TopCount,
BottomCount = request.BottomCount,
Items = request.Items,
Items = request.Items
};
var profile = _profileHelper.GetFullProfile(sessionId);
@@ -8,9 +8,8 @@ namespace Core.Controllers;
[Injectable]
public class ClientLogController(
ISptLogger<ClientLogController> _logger
)
)
{
/// <summary>
/// Handle /singleplayer/log
/// </summary>
@@ -55,10 +55,7 @@ public class CustomizationController(
)
.ToList();
if (matchingSuits == null)
{
throw new Exception(_localisationService.GetText("customisation-unable_to_get_trader_suits", traderId));
}
if (matchingSuits == null) throw new Exception(_localisationService.GetText("customisation-unable_to_get_trader_suits", traderId));
return matchingSuits;
}
@@ -104,7 +101,7 @@ public class CustomizationController(
return output;
}
// Charge player for buying item
PayForClothingItems(sessionId, pmcData, buyClothingRequest.Items, output);
@@ -127,20 +124,14 @@ public class CustomizationController(
{
var suits = _saveServer.GetProfile(sessionId).Suits;
if (suits is null || suits.Count == 0)
{
return false;
}
if (suits is null || suits.Count == 0) return false;
return suits.Contains(suitId);
}
private Suit? GetTraderClothingOffer(string sessionId, string? offerId)
{
var foundSuit = GetAllTraderSuits(sessionId).FirstOrDefault(s => s.Id == offerId);
if (foundSuit is null)
{
_logger.Error(_localisationService.GetText("customisation-unable_to_find_suit_with_id", offerId));
}
if (foundSuit is null) _logger.Error(_localisationService.GetText("customisation-unable_to_find_suit_with_id", offerId));
return foundSuit;
}
@@ -156,11 +147,8 @@ public class CustomizationController(
List<PaymentItemForClothing>? itemsToPayForClothingWith,
ItemEventRouterResponse output)
{
if (itemsToPayForClothingWith is null || itemsToPayForClothingWith.Count == 0)
{
return;
}
if (itemsToPayForClothingWith is null || itemsToPayForClothingWith.Count == 0) return;
foreach (var inventoryItemToProcess in itemsToPayForClothingWith)
{
var options = new ProcessBuyTradeRequestData
@@ -189,9 +177,7 @@ public class CustomizationController(
foreach (var trader in traders)
if (trader.Value.Base?.CustomizationSeller is not null && trader.Value.Base.CustomizationSeller.Value)
{
result.AddRange(GetTraderSuits(trader.Key, sessionId));
}
return result;
}
@@ -220,10 +206,7 @@ public class CustomizationController(
var customisationResultsClone = _cloner.Clone(_databaseService.GetTemplates().CustomisationStorage);
var profile = _profileHelper.GetFullProfile(sessionId);
if (profile is null)
{
return customisationResultsClone!;
}
if (profile is null) return customisationResultsClone!;
customisationResultsClone!.AddRange(profile.CustomisationUnlocks ?? []);
@@ -240,7 +223,6 @@ public class CustomizationController(
public ItemEventRouterResponse SetCustomisation(string sessionId, CustomizationSetRequest request, PmcData pmcData)
{
foreach (var customisation in request.Customizations)
{
switch (customisation.Type)
{
case "dogTag":
@@ -253,7 +235,6 @@ public class CustomizationController(
_logger.Error($"Unhandled customisation type: {customisation.Type}");
break;
}
}
return _eventOutputHolder.GetOutput(sessionId);
}
@@ -285,9 +266,6 @@ public class CustomizationController(
}
// Feet
if (dbSuit.Parent == _lowerParentClothingId)
{
pmcData.Customization.Feet = dbSuit.Properties.Feet;
}
if (dbSuit.Parent == _lowerParentClothingId) pmcData.Customization.Feet = dbSuit.Properties.Feet;
}
}
@@ -37,9 +37,7 @@ public class DialogueController(
public void RegisterChatBot(IDialogueChatBot chatBot) // TODO: this is in with the helper types
{
if (_dialogueChatBots.Any(cb => cb.GetChatBot().Id == chatBot.GetChatBot().Id))
{
_logger.Error(_localisationService.GetText("dialog-chatbot_id_already_exists", chatBot.GetChatBot().Id));
}
_dialogueChatBots.Add(chatBot);
}
@@ -51,10 +49,7 @@ public class DialogueController(
public void Update()
{
var profiles = _saveServer.GetProfiles();
foreach (var kvp in profiles)
{
RemoveExpiredItemsFromMessages(kvp.Key);
}
foreach (var kvp in profiles) RemoveExpiredItemsFromMessages(kvp.Key);
}
/// <summary>
@@ -70,23 +65,19 @@ public class DialogueController(
// Add any friends the user has after the chatbots
var profile = _profileHelper.GetFullProfile(sessionId);
if (profile?.FriendProfileIds is not null)
{
foreach (var friendId in profile.FriendProfileIds)
{
var friendProfile = _profileHelper.GetChatRoomMemberFromSessionId(friendId);
if (friendProfile is not null)
{
friends.Add(
new UserDialogInfo
{
Id = friendProfile.Id,
Aid = friendProfile.Aid,
Info = friendProfile.Info,
Info = friendProfile.Info
}
);
}
}
}
return new GetFriendListDataResponse
{
@@ -105,10 +96,7 @@ public class DialogueController(
foreach (var bot in _dialogueChatBots)
{
var botData = bot.GetChatBot();
if (chatBotConfig.EnabledBots.ContainsKey(botData.Id!))
{
activeBots.Add(botData);
}
if (chatBotConfig.EnabledBots.ContainsKey(botData.Id!)) activeBots.Add(botData);
}
return activeBots;
@@ -124,10 +112,7 @@ public class DialogueController(
public List<DialogueInfo> GenerateDialogueList(string sessionId)
{
var data = new List<DialogueInfo>();
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId))
{
data.Add(GetDialogueInfo(dialogueId.Key, sessionId));
}
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId)) data.Add(GetDialogueInfo(dialogueId.Key, sessionId));
return data;
}
@@ -153,7 +138,7 @@ public class DialogueController(
New = dialogue?.New,
AttachmentsNew = dialogue?.AttachmentsNew,
Pinned = dialogue?.Pinned,
Users = GetDialogueUsers(dialogue, dialogue?.Type, sessionId),
Users = GetDialogueUsers(dialogue, dialogue?.Type, sessionId)
};
return result;
@@ -177,7 +162,6 @@ public class DialogueController(
if (messageType == MessageType.USER_MESSAGE &&
dialog?.Users is not null &&
dialog.Users.All(userDialog => userDialog.Id != profile.CharacterData?.PmcData?.SessionId))
{
dialog.Users.Add(
new UserDialogInfo
{
@@ -189,11 +173,10 @@ public class DialogueController(
Nickname = profile.CharacterData?.PmcData?.Info?.Nickname,
Side = profile.CharacterData?.PmcData?.Info?.Side,
MemberCategory = profile.CharacterData?.PmcData?.Info?.MemberCategory,
SelectedMemberCategory = profile.CharacterData?.PmcData?.Info?.SelectedMemberCategory,
},
SelectedMemberCategory = profile.CharacterData?.PmcData?.Info?.SelectedMemberCategory
}
}
);
}
return dialog?.Users!;
}
@@ -225,7 +208,7 @@ public class DialogueController(
{
Messages = dialogue.Messages,
Profiles = GetProfilesForMail(fullProfile, dialogue.Users),
HasMessagesWithRewards = MessagesHaveUncollectedRewards(dialogue.Messages!),
HasMessagesWithRewards = MessagesHaveUncollectedRewards(dialogue.Messages!)
};
}
@@ -249,22 +232,16 @@ public class DialogueController(
Pinned = false,
Messages = [],
New = 0,
Type = request.Type,
Type = request.Type
};
if (request.Type != MessageType.USER_MESSAGE)
{
return profile.DialogueRecords[request.DialogId!];
}
if (request.Type != MessageType.USER_MESSAGE) return profile.DialogueRecords[request.DialogId!];
var dialogue = profile.DialogueRecords[request.DialogId!];
dialogue.Users = [];
var chatBot = _dialogueChatBots.FirstOrDefault(cb => cb.GetChatBot().Id == request.DialogId);
if (chatBot is null)
{
return profile.DialogueRecords[request.DialogId!];
}
if (chatBot is null) return profile.DialogueRecords[request.DialogId!];
dialogue.Users ??= [];
dialogue.Users.Add(chatBot.GetChatBot());
@@ -282,17 +259,12 @@ public class DialogueController(
{
List<UserDialogInfo> result = [];
if (userDialogs is null)
{
// Nothing to add
return result;
}
result.AddRange(userDialogs);
if (result.Any(userDialog => userDialog.Id == fullProfile.ProfileInfo?.ProfileId))
{
return result;
}
if (result.Any(userDialog => userDialog.Id == fullProfile.ProfileInfo?.ProfileId)) return result;
// Player doesn't exist, add them in before returning
var pmcProfile = fullProfile.CharacterData?.PmcData;
@@ -307,7 +279,7 @@ public class DialogueController(
Side = pmcProfile?.Info?.Side,
Level = pmcProfile?.Info?.Level,
MemberCategory = pmcProfile?.Info?.MemberCategory,
SelectedMemberCategory = pmcProfile?.Info?.SelectedMemberCategory,
SelectedMemberCategory = pmcProfile?.Info?.SelectedMemberCategory
}
}
);
@@ -328,12 +300,8 @@ public class DialogueController(
var newAttachmentCount = 0;
var activeMessages = GetActiveMessagesFromDialog(sessionId, dialogueId);
foreach (var message in activeMessages)
{
if (message.HasRewards.GetValueOrDefault(false) && !message.RewardCollected.GetValueOrDefault(false))
{
newAttachmentCount++;
}
}
return newAttachmentCount;
}
@@ -382,7 +350,7 @@ public class DialogueController(
new
{
sessionId,
dialogueId,
dialogueId
}
)
);
@@ -410,7 +378,7 @@ public class DialogueController(
new
{
sessionId,
dialogueId,
dialogueId
}
)
);
@@ -437,7 +405,7 @@ public class DialogueController(
"dialogue-unable_to_find_dialogs_in_profile",
new
{
sessionId,
sessionId
}
)
);
@@ -498,11 +466,13 @@ public class DialogueController(
{
_mailSendService.SendPlayerMessageToNpc(sessionId, request.DialogId!, request.Text!);
return (_dialogueChatBots.FirstOrDefault(cb =>
cb.GetChatBot().Id == request.DialogId)
?.HandleMessage(sessionId, request)
?? request.DialogId)
?? string.Empty;
return (_dialogueChatBots.FirstOrDefault(
cb =>
cb.GetChatBot().Id == request.DialogId
)
?.HandleMessage(sessionId, request) ??
request.DialogId) ??
string.Empty;
}
/// <summary>
@@ -521,10 +491,7 @@ public class DialogueController(
/// <param name="sessionId">Session id</param>
private void RemoveExpiredItemsFromMessages(string sessionId)
{
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId))
{
RemoveExpiredItemsFromMessage(sessionId, dialogueId.Key);
}
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId)) RemoveExpiredItemsFromMessage(sessionId, dialogueId.Key);
}
/// <summary>
@@ -535,18 +502,11 @@ public class DialogueController(
private void RemoveExpiredItemsFromMessage(string sessionId, string dialogueId)
{
var dialogs = _dialogueHelper.GetDialogsForProfile(sessionId);
if (!dialogs.TryGetValue(dialogueId, out var dialog))
{
return;
}
if (!dialogs.TryGetValue(dialogueId, out var dialog)) return;
foreach (var message in dialog.Messages ?? [])
{
if (MessageHasExpired(message))
{
message.Items = new MessageItems();
}
}
}
/**
@@ -564,30 +524,25 @@ public class DialogueController(
// To avoid needing to jump between profiles, auto-accept all friend requests
var friendProfile = _profileHelper.GetFullProfile(request.To);
if (friendProfile?.CharacterData?.PmcData is null)
{
return new FriendRequestSendResponse
{
Status = BackendErrorCodes.PlayerProfileNotFound,
RequestId = "", // Unused in an error state
RetryAfter = 600,
RetryAfter = 600
};
}
// Only add the profile to the friends list if it doesn't already exist
var profile = _saveServer.GetProfile(sessionID);
if (!profile.FriendProfileIds.Contains(request.To))
{
profile.FriendProfileIds.Add(request.To);
}
if (!profile.FriendProfileIds.Contains(request.To)) profile.FriendProfileIds.Add(request.To);
// We need to delay this so that the friend request gets properly added to the clientside list before we accept it
_ = new Timer(
_ =>
{
WsFriendsListAccept notification = new WsFriendsListAccept
var notification = new WsFriendsListAccept
{
EventType = NotificationEventType.friendListRequestAccept,
Profile = _profileHelper.GetChatRoomMemberFromPmcProfile(friendProfile.CharacterData.PmcData),
Profile = _profileHelper.GetChatRoomMemberFromPmcProfile(friendProfile.CharacterData.PmcData)
};
_notificationSendHelper.SendMessage(sessionID, notification);
},
@@ -608,9 +563,6 @@ public class DialogueController(
{
var profile = _saveServer.GetProfile(sessionID);
var friendIndex = profile.FriendProfileIds.IndexOf(request.FriendId);
if (friendIndex != -1)
{
profile.FriendProfileIds.RemoveAt(friendIndex);
}
if (friendIndex != -1) profile.FriendProfileIds.RemoveAt(friendIndex);
}
}
+39 -98
View File
@@ -44,12 +44,12 @@ public class GameController(
ICloner _cloner
)
{
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected CoreConfig _coreConfig = _configServer.GetConfig<CoreConfig>();
protected double _deviation = 0.0001;
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
protected HttpConfig _httpConfig = _configServer.GetConfig<HttpConfig>();
protected RagfairConfig _ragfairConfig = _configServer.GetConfig<RagfairConfig>();
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected double _deviation = 0.0001;
/// <summary>
/// Handle client/game/start
@@ -82,40 +82,25 @@ public class GameController(
_logger.Error($"{nameof(fullProfile)} is null on GameController.GameStart");
return;
}
fullProfile.SptData ??= new Spt { Version = "Replace_me" };
fullProfile.SptData.Migrations ??= new Dictionary<string, long>();
fullProfile.FriendProfileIds ??= [];
if (fullProfile.ProfileInfo?.IsWiped is not null && fullProfile.ProfileInfo.IsWiped.Value)
{
return;
}
if (fullProfile.ProfileInfo?.IsWiped is not null && fullProfile.ProfileInfo.IsWiped.Value) return;
fullProfile.CharacterData!.PmcData!.WishList ??= new DictionaryOrList<string, int>(new Dictionary<string, int>(), []);
fullProfile.CharacterData.ScavData!.WishList ??= new DictionaryOrList<string, int>(new Dictionary<string, int>(), []);
if (fullProfile.DialogueRecords is not null)
{
_profileFixerService.CheckForAndFixDialogueAttachments(fullProfile);
}
if (fullProfile.DialogueRecords is not null) _profileFixerService.CheckForAndFixDialogueAttachments(fullProfile);
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Started game with session {sessionId} {fullProfile.ProfileInfo?.Username}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Started game with session {sessionId} {fullProfile.ProfileInfo?.Username}");
var pmcProfile = fullProfile.CharacterData.PmcData;
if (_coreConfig.Fixes.FixProfileBreakingInventoryItemIssues)
{
_profileFixerService.FixProfileBreakingInventoryItemIssues(pmcProfile);
}
if (_coreConfig.Fixes.FixProfileBreakingInventoryItemIssues) _profileFixerService.FixProfileBreakingInventoryItemIssues(pmcProfile);
if (pmcProfile.Health is not null)
{
UpdateProfileHealthValues(pmcProfile);
}
if (pmcProfile.Health is not null) UpdateProfileHealthValues(pmcProfile);
if (pmcProfile.Inventory is not null)
{
@@ -143,10 +128,7 @@ public class GameController(
CheckForAndRemoveUndefinedDialogues(fullProfile);
}
if (pmcProfile.Skills?.Common is not null)
{
WarnOnActiveBotReloadSkill(pmcProfile);
}
if (pmcProfile.Skills?.Common is not null) WarnOnActiveBotReloadSkill(pmcProfile);
_seasonalEventService.GivePlayerSeasonalGifts(sessionId);
}
@@ -160,8 +142,9 @@ public class GameController(
{
var profile = _profileHelper.GetPmcProfile(sessionId);
var gameTime = profile?.Stats?.Eft?.OverallCounters?.Items?
.FirstOrDefault(c => c.Key!.Contains("LifeTime")
&& c.Key.Contains("Pmc"))?.Value ?? 0D;
.FirstOrDefault(c => c.Key!.Contains("LifeTime") && c.Key.Contains("Pmc"))
?.Value ??
0D;
var config = new GameConfigResponse
{
@@ -173,7 +156,7 @@ public class GameController(
Aid = profile?.Aid,
Taxonomy = 6,
ActiveProfileId = sessionId,
Backend = new()
Backend = new Backend
{
Lobby = _httpServerHelper.GetBackendUrl(),
Trading = _httpServerHelper.GetBackendUrl(),
@@ -185,7 +168,7 @@ public class GameController(
UtcTime = _timeUtil.GetTimeStamp(),
TotalInGame = gameTime,
SessionMode = "pve",
PurchasedGames = new()
PurchasedGames = new PurchasedGames
{
IsEftPurchased = true,
IsArenaPurchased = false
@@ -205,7 +188,7 @@ public class GameController(
string sessionId,
GameModeRequestData requestData)
{
return new()
return new GameModeResponse
{
GameMode = "pve",
BackendUrl = _httpServerHelper.GetBackendUrl()
@@ -291,7 +274,7 @@ public class GameController(
/// <returns></returns>
public SurveyResponseData GetSurvey(string sessionId)
{
return this._coreConfig.Survey;
return _coreConfig.Survey;
}
/// <summary>
@@ -301,10 +284,7 @@ public class GameController(
private void WarnOnActiveBotReloadSkill(PmcData pmcProfile)
{
var botReloadSkill = _profileHelper.GetSkillFromProfile(pmcProfile, SkillTypes.BotReload);
if (botReloadSkill?.Progress > 0)
{
_logger.Warning(_localisationService.GetText("server_start_player_active_botreload_skill"));
}
if (botReloadSkill?.Progress > 0) _logger.Warning(_localisationService.GetText("server_start_player_active_botreload_skill"));
}
/// <summary>
@@ -323,40 +303,35 @@ public class GameController(
// Base values
double energyRegenPerHour = 60;
double hydrationRegenPerHour = 60;
double hpRegenPerHour = 456.6;
var hpRegenPerHour = 456.6;
// Set new values, whatever is smallest
energyRegenPerHour += pmcProfile.Bonuses!
.Where(bonus => bonus.Type == BonusType.EnergyRegeneration)
.Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value));
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
hydrationRegenPerHour += pmcProfile.Bonuses!
.Where(bonus => bonus.Type == BonusType.HydrationRegeneration)
.Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value));
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
hpRegenPerHour += pmcProfile.Bonuses!
.Where(bonus => bonus.Type == BonusType.HealthRegeneration)
.Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value));
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
// Player has energy deficit
if (Math.Abs((pmcProfile.Health?.Energy?.Current - pmcProfile.Health?.Energy?.Maximum) ?? 1) <= _deviation)
if (Math.Abs(pmcProfile.Health?.Energy?.Current - pmcProfile.Health?.Energy?.Maximum ?? 1) <= _deviation)
{
// Set new value, whatever is smallest
pmcProfile.Health!.Energy!.Current += Math.Round(energyRegenPerHour * (diffSeconds!.Value / 3600));
if (pmcProfile.Health.Energy.Current > pmcProfile.Health.Energy.Maximum)
{
pmcProfile.Health.Energy.Current = pmcProfile.Health.Energy.Maximum;
}
if (pmcProfile.Health.Energy.Current > pmcProfile.Health.Energy.Maximum) pmcProfile.Health.Energy.Current = pmcProfile.Health.Energy.Maximum;
}
// Player has hydration deficit
if (Math.Abs((pmcProfile.Health?.Hydration?.Current - pmcProfile.Health?.Hydration?.Maximum) ?? 1) <= _deviation)
if (Math.Abs(pmcProfile.Health?.Hydration?.Current - pmcProfile.Health?.Hydration?.Maximum ?? 1) <= _deviation)
{
pmcProfile.Health!.Hydration!.Current += Math.Round(hydrationRegenPerHour * (diffSeconds!.Value / 3600));
if (pmcProfile.Health.Hydration.Current > pmcProfile.Health.Hydration.Maximum)
{
pmcProfile.Health.Hydration.Current = pmcProfile.Health.Hydration.Maximum;
}
}
// Check all body parts
@@ -364,21 +339,12 @@ public class GameController(
.Select(bodyPartKvP => bodyPartKvP.Value))
{
// Check part hp
if (bodyPart.Health!.Current < bodyPart.Health.Maximum)
{
bodyPart.Health.Current += Math.Round(hpRegenPerHour * (diffSeconds!.Value / 3600));
}
if (bodyPart.Health!.Current < bodyPart.Health.Maximum) bodyPart.Health.Current += Math.Round(hpRegenPerHour * (diffSeconds!.Value / 3600));
if (bodyPart.Health.Current > bodyPart.Health.Maximum)
{
bodyPart.Health.Current = bodyPart.Health.Maximum;
}
if (bodyPart.Health.Current > bodyPart.Health.Maximum) bodyPart.Health.Current = bodyPart.Health.Maximum;
if (bodyPart.Effects is null || bodyPart.Effects.Count == 0)
{
continue;
}
if (bodyPart.Effects is null || bodyPart.Effects.Count == 0) continue;
// Look for effects
foreach (var effectKvP in bodyPart.Effects)
@@ -387,10 +353,7 @@ public class GameController(
if (effectKvP.Value.Time < 1)
{
// More than 30 mins has passed
if (diffSeconds > 1800)
{
bodyPart.Effects.Remove(effectKvP.Key);
}
if (diffSeconds > 1800) bodyPart.Effects.Remove(effectKvP.Key);
continue;
}
@@ -398,10 +361,8 @@ public class GameController(
// Decrement effect time value by difference between current time and time health was last updated
effectKvP.Value.Time -= diffSeconds;
if (effectKvP.Value.Time < 1)
{
// Effect time was sub 1, set floor it can be
effectKvP.Value.Time = 1;
}
}
}
@@ -421,16 +382,10 @@ public class GameController(
var currentTimeStamp = _timeUtil.GetTimeStamp();
// One day post-profile creation
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds)
{
_giftService.SendPraporStartingGift(pmcProfile.SessionId!, 1);
}
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds) _giftService.SendPraporStartingGift(pmcProfile.SessionId!, 1);
// Two day post-profile creation
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2)
{
_giftService.SendPraporStartingGift(pmcProfile.SessionId!, 2);
}
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2) _giftService.SendPraporStartingGift(pmcProfile.SessionId!, 2);
}
/**
@@ -438,7 +393,7 @@ public class GameController(
* @param pmcProfile Player profile
*/
protected void SendMechanicGiftsToNewProfile(PmcData pmcProfile)
{
{
_giftService.SendGiftWithSilentReceivedCheck("MechanicGiftDay1", pmcProfile.SessionId, 1);
}
@@ -495,27 +450,16 @@ public class GameController(
var bots = _databaseService.GetBots().Types;
// Official names can only be 15 chars in length
if (playerName.Length > _botConfig.BotNameLengthLimit)
{
return;
}
if (playerName.Length > _botConfig.BotNameLengthLimit) return;
// Skip if player name exists already
if (bots!.TryGetValue("bear", out var bearBot))
{
if (bearBot is not null && bearBot.FirstNames!.Any(x => x == playerName))
{
bearBot.FirstNames!.Add(playerName);
}
}
if (bots.TryGetValue("bear", out var usecBot))
{
if (usecBot is not null && usecBot.FirstNames!.Any(x => x == playerName))
{
usecBot.FirstNames!.Add(playerName);
}
}
}
}
@@ -525,10 +469,7 @@ public class GameController(
/// <param name="fullProfile">Profile to check for dialog in</param>
private void CheckForAndRemoveUndefinedDialogues(SptProfile fullProfile)
{
if (fullProfile.DialogueRecords!.TryGetValue("undefined", out var _))
{
fullProfile.DialogueRecords.Remove("undefined");
}
if (fullProfile.DialogueRecords!.TryGetValue("undefined", out _)) fullProfile.DialogueRecords.Remove("undefined");
}
/// <summary>
@@ -540,7 +481,7 @@ public class GameController(
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Profile made with: {fullProfile.SptData?.Version}");
_logger.Debug($"Server version: {(ProgramStatics.SPT_VERSION()) ?? _coreConfig.SptVersion} {ProgramStatics.COMMIT()}");
_logger.Debug($"Server version: {ProgramStatics.SPT_VERSION() ?? _coreConfig.SptVersion} {ProgramStatics.COMMIT()}");
_logger.Debug($"Debug enabled: {ProgramStatics.DEBUG()}");
_logger.Debug($"Mods enabled: {ProgramStatics.MODS()}");
}
+8 -43
View File
@@ -69,15 +69,12 @@ public class HealthController(
}
// Resource in medkit is spent, delete it
if (healingItemToUse.Upd.MedKit.HpResource <= 0)
{
_inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
}
if (healingItemToUse.Upd.MedKit.HpResource <= 0) _inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
var healingItemDbDetails = _itemHelper.GetItem(healingItemToUse.Template);
var healItemEffectDetails = healingItemDbDetails.Value.Properties.EffectsDamage;
BodyPartHealth bodyPartToHeal = pmcData.Health.BodyParts.GetValueOrDefault(request.Part.ToString());
var bodyPartToHeal = pmcData.Health.BodyParts.GetValueOrDefault(request.Part.ToString());
if (bodyPartToHeal is null)
{
_logger.Warning($"Player: {sessionID} Tried to heal a non-existent body part: {request.Part}");
@@ -98,10 +95,8 @@ public class HealthController(
{
// Check if healing item removes the effect on limb
if (!healItemEffectDetails.TryGetValue(Enum.Parse<DamageEffectType>(effectKey), out var matchingEffectFromHealingItem))
{
// Healing item doesn't have matching effect, it doesn't remove the effect
continue;
}
// Adjust limb heal amount based on if its fixing an effect (request.count is TOTAL cost of hp resource on heal item, NOT amount to heal limb)
amountToHealLimb -= (int)(matchingEffectFromHealingItem.Cost ?? 0);
@@ -113,10 +108,7 @@ public class HealthController(
bodyPartToHeal.Health.Current += amountToHealLimb;
// Ensure we've not healed beyond the limbs max hp
if (bodyPartToHeal.Health.Current > bodyPartToHeal.Health.Maximum)
{
bodyPartToHeal.Health.Current = bodyPartToHeal.Health.Maximum;
}
if (bodyPartToHeal.Health.Current > bodyPartToHeal.Health.Maximum) bodyPartToHeal.Health.Current = bodyPartToHeal.Health.Maximum;
return output;
}
@@ -139,13 +131,11 @@ public class HealthController(
var itemToConsume = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
if (itemToConsume is null)
{
// Item not found, very bad
return _httpResponseUtil.AppendErrorToOutput(
output,
_localisationService.GetText("health-unable_to_find_item_to_consume", request.Item)
);
}
var consumedItemMaxResource = _itemHelper.GetItem(itemToConsume.Template).Value.Properties.MaxResource;
if (consumedItemMaxResource > 1)
@@ -154,22 +144,15 @@ public class HealthController(
_itemHelper.AddUpdObjectToItem(itemToConsume);
if (itemToConsume.Upd.FoodDrink is null)
{
itemToConsume.Upd.FoodDrink = new UpdFoodDrink { HpPercent = consumedItemMaxResource - request.Count };
}
else
{
itemToConsume.Upd.FoodDrink.HpPercent -= request.Count;
}
resourceLeft = itemToConsume.Upd.FoodDrink.HpPercent.Value;
}
// Remove item from inventory if resource has dropped below threshold
if (consumedItemMaxResource == 1 || resourceLeft < 1)
{
_inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
}
if (consumedItemMaxResource == 1 || resourceLeft < 1) _inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
// Check what effect eating item has and handle
var foodItemDbDetails = _itemHelper.GetItem(itemToConsume.Template).Value;
@@ -198,14 +181,10 @@ public class HealthController(
OffraidEatRequestData request)
{
if (foodIsSingleUse)
{
// Apply whole value from passed in parameter
bodyValue.Current += consumptionDetails.Value;
}
else
{
bodyValue.Current += request.Count;
}
// Ensure current never goes over max
if (bodyValue.Current > bodyValue.Maximum)
@@ -216,10 +195,7 @@ public class HealthController(
}
// Same as above but for the lower bound
if (bodyValue.Current < 0)
{
bodyValue.Current = 0;
}
if (bodyValue.Current < 0) bodyValue.Current = 0;
}
/// <summary>
@@ -248,10 +224,7 @@ public class HealthController(
};
_paymentService.PayMoney(pmcData, payMoneyRequest, sessionID, output);
if (output.Warnings.Count > 0)
{
return output;
}
if (output.Warnings.Count > 0) return output;
foreach (var bodyPartKvP in healthTreatmentRequest.Difference.BodyParts.GetAllPropsAsDict())
{
@@ -261,25 +234,17 @@ public class HealthController(
// Bodypart healing is chosen when part request hp is above 0
if (partRequest.Health > 0)
{
// Heal bodypart
profilePart.Health.Current = profilePart.Health.Maximum;
}
// Check for effects to remove
if (partRequest.Effects?.Count > 0)
{
// Found some, loop over them and remove from pmc profile
foreach (var effect in partRequest.Effects)
{
pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Remove(effect);
}
foreach (var effect in partRequest.Effects) pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Remove(effect);
// Remove empty effect object
if (pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Count == 0)
{
pmcData.Health.BodyParts[bodyPartKvP.Key].Effects = null;
}
if (pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Count == 0) pmcData.Health.BodyParts[bodyPartKvP.Key].Effects = null;
}
}
+41 -139
View File
@@ -46,7 +46,6 @@ public class HideoutController(
ConfigServer _configServer
)
{
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
public const string NameTaskConditionCountersCraftingId = "673f5d6fdd6ed700c703afdc";
protected List<HideoutAreas> _hideoutAreas =
@@ -54,9 +53,11 @@ public class HideoutController(
HideoutAreas.AIR_FILTERING,
HideoutAreas.WATER_COLLECTOR,
HideoutAreas.GENERATOR,
HideoutAreas.BITCOIN_FARM,
HideoutAreas.BITCOIN_FARM
];
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
public void StartUpgrade(PmcData pmcData, HideoutUpgradeRequestData request, string sessionID, ItemEventRouterResponse output)
{
var items = request.Items.Select(
@@ -87,13 +88,9 @@ public class HideoutController(
item.inventoryItem.Upd.StackObjectsCount is not null &&
item.inventoryItem.Upd.StackObjectsCount > item.requestedItem.Count
)
{
item.inventoryItem.Upd.StackObjectsCount -= item.requestedItem.Count;
}
else
{
_inventoryHelper.RemoveItem(pmcData, item.inventoryItem.Id, sessionID, output);
}
}
// Construction time management
@@ -122,10 +119,7 @@ public class HideoutController(
var ctime = hideoutDataDb.Stages[(profileHideoutArea.Level + 1).ToString()].ConstructionTime;
if (ctime > 0)
{
if (_profileHelper.IsDeveloperAccount(sessionID))
{
ctime = 40;
}
if (_profileHelper.IsDeveloperAccount(sessionID)) ctime = 40;
var timestamp = _timeUtil.GetTimeStamp();
@@ -168,16 +162,11 @@ public class HideoutController(
var hideoutStage = hideoutData.Stages[profileHideoutArea.Level.ToString()];
var bonuses = hideoutStage.Bonuses;
if (bonuses?.Count > 0)
{
foreach (var bonus in bonuses)
{
_hideoutHelper.ApplyPlayerUpgradesBonuses(pmcData, bonus);
}
}
// Upgrade includes a container improvement/addition
if (!string.IsNullOrEmpty(hideoutStage?.Container))
{
AddContainerImprovementToProfile(
output,
sessionID,
@@ -186,22 +175,17 @@ public class HideoutController(
hideoutData,
hideoutStage
);
}
// Upgrading water collector / med station
if (
profileHideoutArea.Type == HideoutAreas.WATER_COLLECTOR ||
profileHideoutArea.Type == HideoutAreas.MEDSTATION
)
{
SetWallVisibleIfPrereqsMet(pmcData);
}
// Cleanup temporary buffs/debuffs from wall if complete
if (profileHideoutArea.Type == HideoutAreas.EMERGENCY_WALL && profileHideoutArea.Level == 6)
{
_hideoutHelper.RemoveHideoutWallBuffsAndDebuffs(hideoutData, pmcData);
}
// Add Skill Points Per Area Upgrade
_profileHelper.AddSkillPointsToPlayer(
@@ -218,10 +202,7 @@ public class HideoutController(
if (medStation?.Level >= 1 && waterCollector?.Level >= 1)
{
var wall = pmcData.Hideout.Areas.FirstOrDefault((area) => area.Type == HideoutAreas.EMERGENCY_WALL);
if (wall?.Level == 0)
{
wall.Level = 3;
}
if (wall?.Level == 0) wall.Level = 3;
}
}
@@ -230,27 +211,21 @@ public class HideoutController(
{
// Add key/value to `hideoutAreaStashes` dictionary - used to link hideout area to inventory stash by its id
if (!pmcData.Inventory.HideoutAreaStashes.ContainsKey(dbHideoutArea.Type.ToString()))
{
pmcData.Inventory.HideoutAreaStashes[dbHideoutArea.Type.ToString()] = dbHideoutArea.Id;
}
// Add/upgrade stash item in player inventory
AddUpdateInventoryItemToProfile(sessionID, pmcData, dbHideoutArea, hideoutStage);
// Edge case, add/update `stand1/stand2/stand3` children
if (dbHideoutArea.Type == HideoutAreas.EQUIPMENT_PRESETS_STAND)
{
// Can have multiple 'standx' children depending on upgrade level
AddMissingPresetStandItemsToProfile(sessionID, hideoutStage, pmcData, dbHideoutArea, output);
}
// Dont inform client when upgraded area is hall of fame or equipment stand, BSG doesn't inform client this specifc upgrade has occurred
// will break client if sent
List<HideoutAreas> check = [HideoutAreas.PLACE_OF_FAME];
if (!check.Contains(dbHideoutArea.Type ?? HideoutAreas.NOTSET))
{
AddContainerUpgradeToClientOutput(sessionID, dbHideoutArea.Type, dbHideoutArea, hideoutStage, output);
}
// Some hideout areas (Gun stand) have child areas linked to it
var childDbArea = _databaseService
@@ -260,9 +235,7 @@ public class HideoutController(
{
// Add key/value to `hideoutAreaStashes` dictionary - used to link hideout area to inventory stash by its id
if (pmcData.Inventory.HideoutAreaStashes.GetValueOrDefault(childDbArea.Type.ToString()) is null)
{
pmcData.Inventory.HideoutAreaStashes[childDbArea.Type.ToString()] = childDbArea.Id;
}
// Set child area level to same as parent area
pmcData.Hideout.Areas.FirstOrDefault((hideoutArea) => hideoutArea.Type == childDbArea.Type).Level =
@@ -297,15 +270,13 @@ public class HideoutController(
ItemEventRouterResponse output)
{
if (output.ProfileChanges[sessionID].ChangedHideoutStashes is null)
{
output.ProfileChanges[sessionID].ChangedHideoutStashes = new Dictionary<string, HideoutStashItem>();
}
// Inform client of changes
output.ProfileChanges[sessionID].ChangedHideoutStashes[areaType.ToString()] = new HideoutStashItem
{
Id = hideoutDbData.Id,
Template = hideoutStage.Container,
Template = hideoutStage.Container
};
}
@@ -370,7 +341,7 @@ public class HideoutController(
Id = item.inventoryItem.Id,
Template = item.inventoryItem.Template,
Upd = item.inventoryItem.Upd
},
}
];
_inventoryHelper.RemoveItem(pmcData, item.inventoryItem.Id, sessionID, output);
@@ -445,15 +416,13 @@ public class HideoutController(
ItemWithModsToAdd = [itemToReturn.ConvertToItem()],
FoundInRaid = itemToReturn.Upd?.SpawnedInSession,
Callback = null,
UseSortingTable = false,
UseSortingTable = false
};
_inventoryHelper.AddItemToStash(sessionID, request, pmcData, output);
if (output.Warnings?.Count > 0)
{
// Adding to stash failed, drop out - don't remove item from hideout area slot
return output;
}
// Remove items from slot, locationIndex remains
var hideoutSlotIndex = hideoutArea.Slots.FindIndex((slot) => slot.LocationIndex == slotIndexToRemove);
@@ -510,18 +479,12 @@ public class HideoutController(
// Handle tools not having a `count`, but always only requiring 1
var requiredCount = requirement.Count ?? 1;
if (requiredCount <= 0)
{
continue;
}
if (requiredCount <= 0) continue;
_inventoryHelper.RemoveItemByCount(pmcData, itemToDelete.Id, requiredCount, sessionID, output);
// Tools don't have a count
if (requirement.Type != "Tool")
{
requirement.Count -= (int)itemToDelete.Count;
}
if (requirement.Type != "Tool") requirement.Count -= (int)itemToDelete.Count;
}
return output;
@@ -546,13 +509,9 @@ public class HideoutController(
}
if (inventoryItem.Upd?.StackObjectsCount is not null && inventoryItem.Upd.StackObjectsCount > requestedItem.Count)
{
inventoryItem.Upd.StackObjectsCount -= requestedItem.Count;
}
else
{
_inventoryHelper.RemoveItem(pmcData, requestedItem.Id, sessionID, output);
}
}
var recipe = _databaseService.GetHideout().Production?.ScavRecipes?.FirstOrDefault(r => r.Id == body.RecipeId);
@@ -592,10 +551,7 @@ public class HideoutController(
private double? GetScavCaseTime(PmcData pmcData, double? productionTime)
{
var fenceLevel = _fenceService.GetFenceInfo(pmcData);
if (fenceLevel is null)
{
return productionTime;
}
if (fenceLevel is null) return productionTime;
return productionTime * fenceLevel.ScavCaseTimeModifier;
}
@@ -661,10 +617,7 @@ public class HideoutController(
foreach (var production in productionDict)
{
// Skip undefined production objects
if (production.Value is null)
{
continue;
}
if (production.Value is null) continue;
// Production or ScavCase
if (production.Value.RecipeId == request.RecipeId)
@@ -723,11 +676,11 @@ public class HideoutController(
if (rewardIsStackable ?? false)
{
// Create root item
Item rewardToAdd = new Item
var rewardToAdd = new Item
{
Id = _hashUtil.Generate(),
Template = recipe.EndProduct,
Upd = new Upd { StackObjectsCount = recipe.Count },
Upd = new Upd { StackObjectsCount = recipe.Count }
};
// Split item into separate items with acceptable stack sizes
@@ -739,50 +692,39 @@ public class HideoutController(
// Not stackable, may have to send send multiple of reward
// Add the first reward item to array when not a preset (first preset added above earlier)
if (!rewardIsPreset)
{
itemAndChildrenToSendToPlayer.Add([new Item { Id = _hashUtil.Generate(), Template = recipe.EndProduct }]);
}
if (!rewardIsPreset) itemAndChildrenToSendToPlayer.Add([new Item { Id = _hashUtil.Generate(), Template = recipe.EndProduct }]);
// Add multiple of item if recipe requests it
// Start index at one so we ignore first item in array
var countOfItemsToReward = recipe.Count;
for (var index = 1; index < countOfItemsToReward; index++)
{
List<Item> itemAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(itemAndChildrenToSendToPlayer.FirstOrDefault()));
var itemAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(itemAndChildrenToSendToPlayer.FirstOrDefault()));
itemAndChildrenToSendToPlayer.AddRange([itemAndMods]);
}
}
// Recipe has an `isEncoded` requirement for reward(s), Add `RecodableComponent` property
if (recipe.IsEncoded ?? false)
{
foreach (var reward in itemAndChildrenToSendToPlayer)
{
_itemHelper.AddUpdObjectToItem(reward.FirstOrDefault());
reward.FirstOrDefault().Upd.RecodableComponent = new UpdRecodableComponent { IsEncoded = true };
}
}
// Build an array of the tools that need to be returned to the player
List<List<Item>> toolsToSendToPlayer = [];
var hideoutProduction = pmcData.Hideout.Production[prodId];
if (hideoutProduction.SptRequiredTools?.Count > 0)
{
foreach (var tool in hideoutProduction.SptRequiredTools)
{
toolsToSendToPlayer.Add([tool]);
}
}
// Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times
var area = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == recipe.AreaType);
if (area is not null && request.RecipeId != area.LastRecipe)
{
// 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module
craftingExpAmount += _hideoutConfig.ExpCraftAmount; // Default is 10
}
// Update variable with time spent crafting item(s)
// 1 point per 8 hours of crafting
@@ -814,34 +756,28 @@ public class HideoutController(
foreach (var toolItem in toolsToSendToPlayer)
{
// Note: FIR state will be based on the first item's SpawnedInSession property per item group
AddItemsDirectRequest addToolsRequest = new AddItemsDirectRequest
var addToolsRequest = new AddItemsDirectRequest
{
ItemsWithModsToAdd = [toolItem],
FoundInRaid = toolItem[0].Upd?.SpawnedInSession ?? false,
UseSortingTable = false,
Callback = null,
Callback = null
};
_inventoryHelper.AddItemsToStash(sessionID, addToolsRequest, pmcData, output);
if (output.Warnings?.Count > 0)
{
return;
}
if (output.Warnings?.Count > 0) return;
}
// Add the crafting result to the stash, marked as FiR
AddItemsDirectRequest addItemsRequest = new AddItemsDirectRequest
var addItemsRequest = new AddItemsDirectRequest
{
ItemsWithModsToAdd = itemAndChildrenToSendToPlayer,
FoundInRaid = true,
UseSortingTable = false,
Callback = null,
Callback = null
};
_inventoryHelper.AddItemsToStash(sessionID, addItemsRequest, pmcData, output);
if (output.Warnings?.Count > 0)
{
return;
}
if (output.Warnings?.Count > 0) return;
// - increment skill point for crafting
// - delete the production in profile Hideout.Production
@@ -861,10 +797,7 @@ public class HideoutController(
_profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Crafting, craftingExpAmount);
var intellectAmountToGive = 0.5 * Math.Round((double)(craftingExpAmount / 15));
if (intellectAmountToGive > 0)
{
_profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Intellect, intellectAmountToGive);
}
if (intellectAmountToGive > 0) _profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Intellect, intellectAmountToGive);
}
area.LastRecipe = request.RecipeId;
@@ -879,36 +812,29 @@ public class HideoutController(
// Continious recipies need the craft time refreshed as it gets created once on initial craft and stays the same regardless of what
// production.json is set to
if (recipe.Continuous ?? false)
{
pmcData.Hideout.Production[prodId].ProductionTime = _hideoutHelper.GetAdjustedCraftTimeWithSkills(
pmcData,
recipe.Id,
true
);
}
// Flag normal (non continious) crafts as complete
if (!recipe.Continuous ?? false)
{
pmcData.Hideout.Production[prodId].InProgress = false;
}
if (!recipe.Continuous ?? false) pmcData.Hideout.Production[prodId].InProgress = false;
}
private TaskConditionCounter GetHoursCraftingTaskConditionCounter(PmcData pmcData, HideoutProduction recipe)
{
if (!pmcData.TaskConditionCounters.TryGetValue(HideoutController.NameTaskConditionCountersCraftingId, out var _))
{
if (!pmcData.TaskConditionCounters.TryGetValue(NameTaskConditionCountersCraftingId, out _))
// Doesn't exist, create
pmcData.TaskConditionCounters[HideoutController.NameTaskConditionCountersCraftingId] = new TaskConditionCounter
pmcData.TaskConditionCounters[NameTaskConditionCountersCraftingId] = new TaskConditionCounter
{
Id = recipe.Id,
Type = HideoutController.NameTaskConditionCountersCraftingId,
Type = NameTaskConditionCountersCraftingId,
SourceId = "CounterCrafting",
Value = 0,
Value = 0
};
}
return pmcData.TaskConditionCounters[HideoutController.NameTaskConditionCountersCraftingId];
return pmcData.TaskConditionCounters[NameTaskConditionCountersCraftingId];
}
private void HandleScavCase(string sessionID, PmcData pmcData, HideoutTakeProductionRequestData request, ItemEventRouterResponse output)
@@ -916,14 +842,12 @@ public class HideoutController(
var ongoingProductions = pmcData.Hideout.Production;
string? prodId = null;
foreach (var production in ongoingProductions)
{
// Production or ScavCase
if ((production.Value).RecipeId == request.RecipeId)
if (production.Value.RecipeId == request.RecipeId)
{
prodId = production.Key; // Set to objects key
break;
}
}
if (prodId == null)
{
@@ -942,19 +866,16 @@ public class HideoutController(
// Create rewards for scav case
var scavCaseRewards = _scavCaseRewardGenerator.Generate(request.RecipeId);
AddItemsDirectRequest addItemsRequest = new AddItemsDirectRequest
var addItemsRequest = new AddItemsDirectRequest
{
ItemsWithModsToAdd = scavCaseRewards,
FoundInRaid = true,
Callback = null,
UseSortingTable = false,
UseSortingTable = false
};
_inventoryHelper.AddItemsToStash(sessionID, addItemsRequest, pmcData, output);
if (output.Warnings?.Count > 0)
{
return;
}
if (output.Warnings?.Count > 0) return;
// Remove the old production from output object before its sent to client
output.ProfileChanges[sessionID].Production.Remove(request.RecipeId);
@@ -981,7 +902,6 @@ public class HideoutController(
var qteDb = _databaseService.GetHideout().Qte;
var relevantQte = qteDb.FirstOrDefault(qte => qte.Id == request.Id);
foreach (var outcome in request.Results)
{
if (outcome)
{
// Success
@@ -994,17 +914,10 @@ public class HideoutController(
pmcData.Health.Energy.Current += relevantQte.Results[QteEffectType.singleFailEffect].Energy;
pmcData.Health.Hydration.Current += relevantQte.Results[QteEffectType.singleFailEffect].Hydration;
}
}
if (pmcData.Health.Energy.Current < 1)
{
pmcData.Health.Energy.Current = 1;
}
if (pmcData.Health.Energy.Current < 1) pmcData.Health.Energy.Current = 1;
if (pmcData.Health.Hydration.Current < 1)
{
pmcData.Health.Hydration.Current = 1;
}
if (pmcData.Health.Hydration.Current < 1) pmcData.Health.Hydration.Current = 1;
HandleMusclePain(pmcData, relevantQte.Results[QteEffectType.finishEffect]);
}
@@ -1021,7 +934,7 @@ public class HideoutController(
pmcData.Health.BodyParts["Chest"].Effects ??= new Dictionary<string, BodyPartEffectProperties>();
pmcData.Health.BodyParts["Chest"].Effects["MildMusclePain"] = new BodyPartEffectProperties
{
Time = finishEffect.RewardEffects.FirstOrDefault().Time, // TODO - remove hard coded access, get value properly
Time = finishEffect.RewardEffects.FirstOrDefault().Time // TODO - remove hard coded access, get value properly
};
return;
@@ -1034,7 +947,7 @@ public class HideoutController(
pmcData.Health.BodyParts["Chest"].Effects["SevereMusclePain"] = new BodyPartEffectProperties
{
Time = finishEffect.RewardEffects.FirstOrDefault().Time,
Time = finishEffect.RewardEffects.FirstOrDefault().Time
};
}
}
@@ -1086,13 +999,9 @@ public class HideoutController(
item.inventoryItem.Upd.StackObjectsCount is not null &&
item.inventoryItem.Upd.StackObjectsCount > item.requestedItem.Count
)
{
item.inventoryItem.Upd.StackObjectsCount -= item.requestedItem.Count;
}
else
{
_inventoryHelper.RemoveItem(pmcData, item.inventoryItem.Id, sessionId, output);
}
}
var profileHideoutArea = pmcData.Hideout.Areas.FirstOrDefault(x => x.Type == request.AreaType);
@@ -1115,17 +1024,14 @@ public class HideoutController(
var improvements = hideoutDbData.Stages[profileHideoutArea.Level.ToString()].Improvements;
var timestamp = _timeUtil.GetTimeStamp();
if (output.ProfileChanges[sessionId].Improvements is null)
{
output.ProfileChanges[sessionId].Improvements = new Dictionary<string, HideoutImprovement>();
}
if (output.ProfileChanges[sessionId].Improvements is null) output.ProfileChanges[sessionId].Improvements = new Dictionary<string, HideoutImprovement>();
foreach (var improvement in improvements)
{
var improvementDetails = new HideoutImprovement
{
Completed = false,
ImproveCompleteTimestamp = (long)(timestamp + improvement.ImprovementTime),
ImproveCompleteTimestamp = (long)(timestamp + improvement.ImprovementTime)
};
output.ProfileChanges[sessionId].Improvements[improvement.Id] = improvementDetails;
@@ -1232,7 +1138,7 @@ public class HideoutController(
Id = standId,
Template = ItemTpl.INVENTORY_DEFAULT,
ParentId = equipmentPresetHideoutArea.Id,
SlotId = mannequinSlot.Name,
SlotId = mannequinSlot.Name
};
pmcData.Inventory.Items.Add(mannequinToAdd);
@@ -1245,7 +1151,7 @@ public class HideoutController(
)
.Template, // Same pocket tpl as players profile (unheard get bigger, matching pockets etc)
ParentId = standId,
SlotId = "Pockets",
SlotId = "Pockets"
};
pmcData.Inventory.Items.Add(mannequinPocketItemToAdd);
output.ProfileChanges[sessionId].Items.NewItems.Add(mannequinToAdd);
@@ -1290,16 +1196,12 @@ public class HideoutController(
public void Update()
{
foreach (var sessionID in _saveServer.GetProfiles())
{
if (sessionID.Value.CharacterData.PmcData.Hideout is not null &&
_profileActivityService.ActiveWithinLastMinutes(
sessionID.Key,
_hideoutConfig.UpdateProfileHideoutWhenActiveWithinMinutes
)
)
{
_hideoutHelper.UpdatePlayerHideout(sessionID.Key);
}
}
}
}
@@ -16,8 +16,8 @@ public class InRaidController(
ConfigServer _configServer
)
{
protected InRaidConfig _inRaidConfig = _configServer.GetConfig<InRaidConfig>();
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected InRaidConfig _inRaidConfig = _configServer.GetConfig<InRaidConfig>();
/// <summary>
/// Save locationId to active profiles in-raid object AND app context
@@ -43,9 +43,7 @@ public class InRaidController(
// If equipment match overwrite existing data from update to date raid data for scavenger screen to work correctly.
// otherwise Scav inventory will be overwritten and break scav regeneration, breaking profile.
if (serverScavProfile.Inventory.Equipment == offRaidProfileData.Inventory.Equipment)
{
serverScavProfile.Inventory.Items = offRaidProfileData.Inventory.Items;
}
}
/// <summary>
+28 -111
View File
@@ -86,12 +86,8 @@ public class InsuranceController(
var profileInsuranceDetails = _saveServer.GetProfile(sessionId).InsuranceList;
if (profileInsuranceDetails.Count > 0)
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
_logger.Debug($"Found {profileInsuranceDetails.Count} insurance packages in profile {sessionId}");
}
}
return profileInsuranceDetails.Where(insured => insuranceTime >= insured.ScheduledTime).ToList();
}
@@ -105,12 +101,10 @@ public class InsuranceController(
*/
protected void ProcessInsuredItems(List<Insurance> insuranceDetails, string sessionId)
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
_logger.Debug(
$"Processing {insuranceDetails.Count} insurance packages, which includes a total of: {CountAllInsuranceItems(insuranceDetails)} items, in profile: {sessionId}"
);
}
// Iterate over each of the insurance packages.
foreach (var insured in insuranceDetails)
@@ -170,10 +164,7 @@ public class InsuranceController(
)
.ToList();
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Removed processed insurance package. Remaining packages: {profile.InsuranceList.Count}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Removed processed insurance package. Remaining packages: {profile.InsuranceList.Count}");
}
/**
@@ -198,10 +189,7 @@ public class InsuranceController(
);
// Process all items that are not attached, attachments; those are handled separately, by value.
if (hasRegularItems)
{
ProcessRegularItems(insured, toDelete, parentAttachmentsMap);
}
if (hasRegularItems) ProcessRegularItems(insured, toDelete, parentAttachmentsMap);
// Process attached, attachments, by value, only if there are any.
if (parentAttachmentsMap.Count > 0)
@@ -215,12 +203,8 @@ public class InsuranceController(
// Log the number of items marked for deletion, if any
if (!toDelete.Any())
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
_logger.Debug($"Marked {toDelete.Count} items for deletion from insurance.");
}
}
return toDelete;
}
@@ -253,7 +237,7 @@ public class InsuranceController(
{
insuredItemId = insuredItem.Id,
insuredItemTpl = insuredItem.Template,
parentId = insuredItem.ParentId,
parentId = insuredItem.ParentId
}
)
);
@@ -273,7 +257,7 @@ public class InsuranceController(
new
{
insuredItemId = insuredItem.Id,
insuredItemTpl = insuredItem.Template,
insuredItemTpl = insuredItem.Template
}
)
);
@@ -293,7 +277,7 @@ public class InsuranceController(
{
insuredItemId = insuredItem.Id,
insuredItemTpl = insuredItem.Template,
parentId = insuredItem.ParentId,
parentId = insuredItem.ParentId
}
)
);
@@ -304,10 +288,7 @@ public class InsuranceController(
// Update (or add to) the main-parent to attachments map.
if (mainParentToAttachmentsMap.ContainsKey(mainParent.Id))
{
if (mainParentToAttachmentsMap.TryGetValue(mainParent.Id, out var parent))
{
parent.Add(insuredItem);
}
if (mainParentToAttachmentsMap.TryGetValue(mainParent.Id, out var parent)) parent.Add(insuredItem);
}
else
{
@@ -344,24 +325,14 @@ public class InsuranceController(
// attachment on the main-parent. For example, if the attachment is a stock, we need to check to see if
// it's moddable in the upper receiver (attachment/parent), which is attached to the gun (main-parent).
if (attachment.ParentId is not null)
{
if (itemsMap.TryGetValue(attachment.ParentId, out var directParentItem))
{
attachmentParentItem = directParentItem;
}
}
if (_itemHelper.IsRaidModdable(attachment, attachmentParentItem) ?? false)
{
moddableAttachments.Add(attachment);
}
if (_itemHelper.IsRaidModdable(attachment, attachmentParentItem) ?? false) moddableAttachments.Add(attachment);
}
// If any moddable attachments remain, add them to the updated map.
if (moddableAttachments.Count > 0)
{
updatedMap.TryAdd(map.Key, moddableAttachments);
}
if (moddableAttachments.Count > 0) updatedMap.TryAdd(map.Key, moddableAttachments);
}
return updatedMap;
@@ -382,10 +353,7 @@ public class InsuranceController(
foreach (var insuredItem in insured.Items)
{
// Skip if the item is an attachment. These are handled separately.
if (_itemHelper.IsAttachmentAttached(insuredItem))
{
continue;
}
if (_itemHelper.IsAttachmentAttached(insuredItem)) continue;
// Roll for item deletion
var itemRoll = RollForDelete(insured.TraderId, insuredItem);
@@ -401,10 +369,7 @@ public class InsuranceController(
insured.Items,
insuredItem.Id
);
foreach (var item in itemAndChildren)
{
toDelete.Add(item.Id);
}
foreach (var item in itemAndChildren) toDelete.Add(item.Id);
// Remove the parent (and its children) from the parentAttachmentsMap.
parentAttachmentsMap.Remove(insuredItem.Id);
@@ -433,18 +398,12 @@ public class InsuranceController(
{
// Skip processing if parentId is already marked for deletion, as all attachments for that parent will
// already be marked for deletion as well.
if (toDelete.Contains(parentObj.Key))
{
continue;
}
if (toDelete.Contains(parentObj.Key)) continue;
// Log the parent item's name.
itemsMap.TryGetValue(parentObj.Key, out var parentItem);
var parentName = _itemHelper.GetItemName(parentItem.Template);
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Processing attachments of parent {parentName}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Processing attachments of parent {parentName}");
// Process the attachments for this individual parent item.
ProcessAttachmentByParent(parentObj.Value, insuredTraderId, toDelete);
@@ -473,25 +432,17 @@ public class InsuranceController(
// Create prob array and add all attachments with rouble price as the weight
var attachmentsProbabilityArray = new ProbabilityObjectArray<string, double?>(_mathUtil, _cloner);
foreach (var attachmentTpl in weightedAttachmentByPrice)
{
attachmentsProbabilityArray.Add(
new ProbabilityObject<string, double?>(attachmentTpl.Key, attachmentTpl.Value, null)
);
}
// Draw x attachments from weighted array to remove from parent, remove from pool after being picked
var attachmentIdsToRemove = attachmentsProbabilityArray.Draw((int)countOfAttachmentsToRemove, false);
foreach (var attachmentId in attachmentIdsToRemove)
{
toDelete.Add(attachmentId);
}
foreach (var attachmentId in attachmentIdsToRemove) toDelete.Add(attachmentId);
LogAttachmentsBeingRemoved(attachmentIdsToRemove, attachments, weightedAttachmentByPrice);
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Number of attachments to be deleted: {attachmentIdsToRemove.Count}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Number of attachments to be deleted: {attachmentIdsToRemove.Count}");
}
private void LogAttachmentsBeingRemoved(List<string> attachmentIdsToRemove, List<Item> attachments, Dictionary<string, double> attachmentPrices)
@@ -500,12 +451,10 @@ public class InsuranceController(
foreach (var attachmentId in attachmentIdsToRemove)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
$"Attachment {index} Id: {attachmentId} Tpl: {attachments.FirstOrDefault((x) => x.Id == attachmentId)?.Template} - " +
$"Price: {attachmentPrices[attachmentId]}"
);
}
index++;
}
}
@@ -518,10 +467,7 @@ public class InsuranceController(
foreach (var attachment in attachments)
{
var price = _ragfairPriceService.GetDynamicItemPrice(attachment.Template, Money.ROUBLES);
if (price is not null)
{
result[attachment.Id] = Math.Round(price ?? 0);
}
if (price is not null) result[attachment.Id] = Math.Round(price ?? 0);
}
_weightedRandomHelper.ReduceWeightValues(result);
@@ -533,10 +479,7 @@ public class InsuranceController(
{
var removeCount = 0;
if (_randomUtil.GetChance100(_insuranceConfig.ChanceNoAttachmentsTakenPercent))
{
return removeCount;
}
if (_randomUtil.GetChance100(_insuranceConfig.ChanceNoAttachmentsTakenPercent)) return removeCount;
// Get attachments count above or equal to price set in config
return weightedAttachmentByPrice
@@ -564,19 +507,13 @@ public class InsuranceController(
// Map is labs + insurance is disabled in base.json
if (IsMapLabsAndInsuranceDisabled(insurance))
{
// Trader has labs-specific messages
// Wipe out returnable items
HandleLabsInsurance(traderDialogMessages, insurance);
}
else if (insurance.Items?.Count == 0)
{
// Not labs and no items to return
if (traderDialogMessages.TryGetValue("insuranceFailed", out var insuranceFailedTemplates))
{
insurance.MessageTemplateId = _randomUtil.GetArrayValue(insuranceFailedTemplates);
}
}
// Send the insurance message
_mailSendService.SendLocalisedNpcMessageToPlayer(
@@ -592,9 +529,8 @@ public class InsuranceController(
private bool IsMapLabsAndInsuranceDisabled(Insurance insurance, string labsId = "laboratory")
{
return (insurance.SystemData?.Location?.ToLower() == labsId
&& !(_databaseService.GetLocation(labsId)?.Base?.Insurance.GetValueOrDefault(false) ?? false)
);
return insurance.SystemData?.Location?.ToLower() == labsId &&
!(_databaseService.GetLocation(labsId)?.Base?.Insurance.GetValueOrDefault(false) ?? false);
}
/**
@@ -618,10 +554,7 @@ public class InsuranceController(
private bool? RollForDelete(string traderId, Item? insuredItem = null)
{
var trader = _traderHelper.GetTraderById(traderId);
if (trader is null)
{
return null;
}
if (trader is null) return null;
const int maxRoll = 9999;
const int conversionFactor = 100;
@@ -633,10 +566,8 @@ public class InsuranceController(
// Log the roll with as much detail as possible.
var itemName = insuredItem is not null ? $"{_itemHelper.GetItemName(insuredItem.Template)}" : "";
var status = roll ? "Delete" : "Keep";
if(_logger.IsLogEnabled(LogLevel.Debug))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
_logger.Debug($"Rolling {itemName} with {trader} - Return {traderReturnChance}% - Roll: {returnChance} - Status: {status}");
}
return roll;
}
@@ -661,7 +592,6 @@ public class InsuranceController(
// Get price of all items being insured, add to 'itemsToPay'
foreach (var key in body.Items)
{
itemsToPay.Add(
new IdWithCount
{
@@ -673,7 +603,6 @@ public class InsuranceController(
)
}
);
}
var options = new ProcessBuyTradeRequestData
{
@@ -688,10 +617,7 @@ public class InsuranceController(
// pay for the item insurance
_paymentService.PayMoney(pmcData, options, sessionId, output);
if (output.Warnings?.Count > 0)
{
return output;
}
if (output.Warnings?.Count > 0) return output;
// add items to InsuredItems list once money has been paid
pmcData.InsuredItems ??= [];
@@ -699,10 +625,7 @@ public class InsuranceController(
{
pmcData.InsuredItems.Add(new InsuredItem { TId = body.TransactionId, ItemId = inventoryItemsHash[key].Id });
// If Item is Helmet or Body Armour -> Handle insurance of soft inserts
if (_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(inventoryItemsHash[key].Template))
{
InsureSoftInserts(inventoryItemsHash[key], pmcData, body);
}
if (_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(inventoryItemsHash[key].Template)) InsureSoftInserts(inventoryItemsHash[key], pmcData, body);
}
_profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Charisma, itemsToInsureCount * 0.01);
@@ -726,11 +649,8 @@ public class InsuranceController(
foreach (var softInsertSlot in softInsertSlots)
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"SoftInsertSlots: {softInsertSlot.SlotId}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"SoftInsertSlots: {softInsertSlot.SlotId}");
pmcData.InsuredItems.Add(new InsuredItem { TId = body.TransactionId, ItemId = softInsertSlot.Id });
}
}
@@ -761,10 +681,7 @@ public class InsuranceController(
// Ensure hash has item in it
if (!inventoryItemsHash.ContainsKey(itemId))
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Item with id: {itemId} missing from player inventory, skipping");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Item with id: {itemId} missing from player inventory, skipping");
continue;
}
@@ -83,9 +83,7 @@ public class InventoryController(
// Item is moving into or out of place of fame dog tag slot
if (moveRequest.To?.Container != null &&
(moveRequest.To.Container.StartsWith("dogtag") || originalLocationSlotId.StartsWith("dogtag")))
{
_hideoutHelper.ApplyPlaceOfFameDogtagBonus(pmcData);
}
}
else
{
@@ -155,7 +153,7 @@ public class InventoryController(
_logger.Success($"Set trader {mailEvent.Entity}: Standing to: {mailEvent.Value}");
break;
case ProfileChangeEventType.ProfileLevel:
pmcData.Info.Experience = (int) mailEvent.Value.Value;
pmcData.Info.Experience = (int)mailEvent.Value.Value;
// Will calculate level below
_traderHelper.ValidateTraderStandingsAndPlayerLevelForProfile(sessionId);
_logger.Success($"Set profile xp to: {mailEvent.Value}");
@@ -347,23 +345,16 @@ public class InventoryController(
inventoryItem.ParentId = change.ParentId;
inventoryItem.SlotId = change.SlotId;
if (change.Location is not null)
{
inventoryItem.Location = change.Location;
}
else
{
inventoryItem.Location = null;
}
}
}
public ItemEventRouterResponse ReadEncyclopedia(PmcData pmcData, InventoryReadEncyclopediaRequestData body,
string sessionId)
{
foreach (var id in body.Ids)
{
pmcData.Encyclopedia[id] = true;
}
foreach (var id in body.Ids) pmcData.Encyclopedia[id] = true;
return _eventOutputHolder.GetOutput(sessionId);
}
@@ -373,7 +364,6 @@ public class InventoryController(
{
string? itemId = null;
if (request.FromOwner is not null)
{
try
{
itemId = GetExaminedItemTpl(request, sessionId);
@@ -382,25 +372,17 @@ public class InventoryController(
{
_logger.Error(_localisationService.GetText("inventory-examine_item_does_not_exist", request.Item));
}
}
if (itemId is null)
{
// item template
if (_databaseService.GetItems().ContainsKey(request.Item))
{
itemId = request.Item;
}
}
if (itemId is null)
{
// Player inventory
var target = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
if (target is not null)
{
itemId = target.Template;
}
if (target is not null) itemId = target.Template;
}
if (itemId is not null)
@@ -415,29 +397,22 @@ public class InventoryController(
if (_presetHelper.IsPreset(request.Item)) return _presetHelper.GetBaseItemTpl(request.Item);
if (request.FromOwner.Id == Traders.FENCE)
{
// Get tpl from fence assorts
return _fenceService.GetRawFenceAssorts().Items.FirstOrDefault(x => x.Id == request.Item)?.Template;
}
if (request.FromOwner.Type == "Trader")
{
// Not fence
// get tpl from trader assort
return _databaseService
.GetTrader(request.FromOwner.Id)
.Assort.Items.FirstOrDefault(item => item.Id == request.Item)
?.Template;
}
if (request.FromOwner.Type == "RagFair")
{
// Try to get tplId from items.json first
var item = _itemHelper.GetItem(request.Item);
if (item.Key)
{
return item.Value.Id;
}
if (item.Key) return item.Value.Id;
// Try alternate way of getting offer if first approach fails
var offer = _ragfairOfferService.GetOfferByOfferId(request.Item) ??
@@ -445,20 +420,14 @@ public class InventoryController(
// Try find examine item inside offer items array
var matchingItem = offer.Items.FirstOrDefault(offerItem => offerItem.Id == request.Item);
if (matchingItem is not null)
{
return matchingItem.Template;
}
if (matchingItem is not null) return matchingItem.Template;
// Unable to find item in database or ragfair
_logger.Warning(_localisationService.GetText("inventory-unable_to_find_item", request.Item));
}
// get hideout item
if (request.FromOwner.Type == "HideoutProduction")
{
return request.Item;
}
if (request.FromOwner.Type == "HideoutProduction") return request.Item;
if (request.FromOwner.Type == "Mail")
{
@@ -472,10 +441,7 @@ public class InventoryController(
// get the Id given and get the Template ID from that
var item = message.Items.Data.FirstOrDefault(item => item.Id == request.Item);
if (item is not null)
{
return item.Template;
}
if (item is not null) return item.Template;
}
_logger.Error($"Unable to get item with id: {request.Item}");
@@ -559,10 +525,7 @@ public class InventoryController(
var playerData = pmcData;
// We may be folding data on scav profile, get that profile instead
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id)
{
playerData = _profileHelper.GetScavProfile(sessionId);
}
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id) playerData = _profileHelper.GetScavProfile(sessionId);
var itemToFold = playerData.Inventory.Items.FirstOrDefault(item => item?.Id == request.Item);
if (itemToFold is null)
@@ -592,10 +555,7 @@ public class InventoryController(
{
// During post-raid scav transfer, the swap may be in the scav inventory
var playerData = pmcData;
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id)
{
playerData = _profileHelper.GetScavProfile(sessionId);
}
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id) playerData = _profileHelper.GetScavProfile(sessionId);
var itemOne = playerData.Inventory.Items.FirstOrDefault(x => x.Id == request.Item);
if (itemOne is null)
@@ -631,24 +591,16 @@ public class InventoryController(
// Request object has location data, add it in, otherwise remove existing location from object
if (request.To.Location is not null)
{
itemOne.Location = request.To.Location;
}
else
{
itemOne.Location = null;
}
itemTwo.ParentId = request.To2.Id;
itemTwo.SlotId = request.To2.Container;
if (request.To2.Location is not null)
{
itemTwo.Location = request.To2.Location;
}
else
{
itemTwo.Location = null;
}
// Client already informed of inventory locations, nothing for us to do
return _eventOutputHolder.GetOutput(sessionId);
@@ -696,15 +648,11 @@ public class InventoryController(
var sourceStackCount = sourceItem.Upd.StackObjectsCount;
if (sourceStackCount > request.Count)
{
// Source items stack count greater than new desired count
sourceItem.Upd.StackObjectsCount = sourceStackCount - request.Count;
}
else
{
// Moving a full stack onto a smaller stack
sourceItem.Upd.StackObjectsCount = sourceStackCount - 1;
}
destinationItem.Upd ??= new Upd { StackObjectsCount = 1 };
@@ -743,27 +691,19 @@ public class InventoryController(
}
if (destinationItem.Upd?.StackObjectsCount is null)
{
// No stackcount on destination, add one
destinationItem.Upd = new Upd { StackObjectsCount = 1 };
}
if (sourceItem.Upd is null)
{
sourceItem.Upd = new Upd { StackObjectsCount = 1 };
}
else if (sourceItem.Upd.StackObjectsCount is null)
{
// Items pulled out of raid can have no stack count if the stack should be 1
sourceItem.Upd.StackObjectsCount = 1;
}
// Remove FiR status from destination stack when source stack has no FiR but destination does
if (!sourceItem.Upd.SpawnedInSession.GetValueOrDefault(false) &&
destinationItem.Upd.SpawnedInSession.GetValueOrDefault(false))
{
destinationItem.Upd.SpawnedInSession = false;
}
destinationItem.Upd.StackObjectsCount +=
sourceItem.Upd.StackObjectsCount; // Add source stackcount to destination
@@ -45,7 +45,7 @@ public class LauncherController(
BackendUrl = _httpServerHelper.GetBackendUrl(),
Name = _coreConfig.ServerName,
Editions = profiles,
ProfileDescriptions = GetProfileDescriptions(),
ProfileDescriptions = GetProfileDescriptions()
};
}
@@ -83,10 +83,7 @@ public class LauncherController(
foreach (var kvp in _saveServer.GetProfiles())
{
var account = _saveServer.GetProfile(kvp.Key).ProfileInfo;
if (info?.Username == account?.Username)
{
return kvp.Key;
}
if (info?.Username == account?.Username) return kvp.Key;
}
return null;
@@ -95,12 +92,8 @@ public class LauncherController(
public string Register(RegisterData info)
{
foreach (var kvp in _saveServer.GetProfiles())
{
if (info.Username == _saveServer.GetProfile(kvp.Key).ProfileInfo?.Username)
{
return "";
}
}
return CreateAccount(info);
}
@@ -117,7 +110,7 @@ public class LauncherController(
Username = info.Username,
Password = info.Password,
IsWiped = true,
Edition = info.Edition,
Edition = info.Edition
};
_saveServer.CreateProfile(newProfileDetails);
@@ -146,10 +139,7 @@ public class LauncherController(
{
var sessionID = Login(info);
if (!string.IsNullOrEmpty(sessionID))
{
_saveServer.GetProfile(sessionID).ProfileInfo!.Username = info.Change;
}
if (!string.IsNullOrEmpty(sessionID)) _saveServer.GetProfile(sessionID).ProfileInfo!.Username = info.Change;
return sessionID;
}
@@ -158,10 +148,7 @@ public class LauncherController(
{
var sessionID = Login(info);
if (!string.IsNullOrEmpty(sessionID))
{
_saveServer.GetProfile(sessionID).ProfileInfo!.Password = info.Change;
}
if (!string.IsNullOrEmpty(sessionID)) _saveServer.GetProfile(sessionID).ProfileInfo!.Password = info.Change;
return sessionID;
}
@@ -173,10 +160,7 @@ public class LauncherController(
*/
public string? Wipe(RegisterData info)
{
if (!_coreConfig.AllowProfileWipe)
{
return null;
}
if (!_coreConfig.AllowProfileWipe) return null;
var sessionID = Login(info);
@@ -58,7 +58,7 @@ public class LauncherV2Controller(
var casterPropertyValue = propertyValue as ProfileSides;
result[templatesProperty.GetJsonName()] = _localisationService.GetText(casterPropertyValue?.DescriptionLocaleKey!);
}
return result;
}
@@ -82,12 +82,8 @@ public class LauncherV2Controller(
public bool Register(RegisterData info)
{
foreach (var session in _saveServer.GetProfiles())
{
if (info.Username == _saveServer.GetProfile(session.Key).ProfileInfo!.Username)
{
return false;
}
}
CreateAccount(info);
return true;
@@ -104,7 +100,7 @@ public class LauncherV2Controller(
if (sessionId is null)
return false;
_saveServer.GetProfile(sessionId).ProfileInfo!.Password = info.Password;
return true;
}
@@ -117,7 +113,7 @@ public class LauncherV2Controller(
public bool Remove(LoginRequestData info)
{
var sessionId = GetSessionId(info);
return sessionId is not null && _saveServer.RemoveProfile(sessionId);
}
@@ -169,22 +165,22 @@ public class LauncherV2Controller(
IsWiped = true,
Edition = info.Edition
};
_saveServer.CreateProfile(newProfileDetails);
_saveServer.LoadProfile(profileId);
_saveServer.SaveProfile(profileId);
return profileId;
}
protected string GenerateProfileId()
{
var timestamp = _timeUtil.GetTimeStamp();
return FormatID(timestamp, timestamp * _randomUtil.GetInt(1, 1000000));
}
protected string FormatID(long timeStamp, long counter)
{
var timeStampStr = Convert.ToString(timeStamp, 16).PadLeft(8, '0');
@@ -196,13 +192,8 @@ public class LauncherV2Controller(
protected string? GetSessionId(LoginRequestData info)
{
foreach (var profile in _saveServer.GetProfiles())
{
if (info.Username == profile.Value.ProfileInfo!.Username
&& info.Password == profile.Value.ProfileInfo.Password)
{
if (info.Username == profile.Value.ProfileInfo!.Username && info.Password == profile.Value.ProfileInfo.Password)
return profile.Key;
}
}
return null;
}
@@ -18,7 +18,6 @@ public class LocationController(
ICloner _cloner
)
{
/// <summary>
/// Handle client/locations
/// Get all maps base location properties without loot data
@@ -38,10 +37,7 @@ public class LocationController(
var mapBase = kvp.Value.Base;
if (mapBase == null)
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Map: {kvp} has no base json file, skipping generation");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Map: {kvp} has no base json file, skipping generation");
continue;
}
@@ -65,10 +61,7 @@ public class LocationController(
/// <returns></returns>
public GetAirdropLootResponse? GetAirDropLoot(GetAirdropLootRequest? request)
{
if (request?.ContainerId is not null)
{
return _airdropService.GenerateCustomAirdropLoot(request);
}
if (request?.ContainerId is not null) return _airdropService.GenerateCustomAirdropLoot(request);
return _airdropService.GenerateAirdropLoot();
}
@@ -50,7 +50,7 @@ public class MatchController(
/// <returns></returns>
public ProfileStatusResponse JoinMatch(MatchGroupStartGameRequest info, string sessionId)
{
ProfileStatusResponse output = new ProfileStatusResponse
var output = new ProfileStatusResponse
{
MaxPveCountExceeded = false,
// get list of players joining into the match
@@ -105,11 +105,9 @@ public class MatchController(
// Set pmcs to difficulty set in pre-raid screen if override in bot config isnt enabled
if (!_pmcConfig.UseDifficultyOverride)
{
_pmcConfig.Difficulty = ConvertDifficultyDropdownIntoBotDifficulty(
request.WavesSettings.BotDifficulty.ToString()
);
}
}
/// <summary>
@@ -120,10 +118,7 @@ public class MatchController(
private string ConvertDifficultyDropdownIntoBotDifficulty(string botDifficulty)
{
// Edge case medium - must be altered
if (botDifficulty.ToLower() == "medium")
{
return "normal";
}
if (botDifficulty.ToLower() == "medium") return "normal";
return botDifficulty;
}
+4 -4
View File
@@ -23,9 +23,9 @@ public class NoteController(
NoteActionData body,
string sessionId)
{
Note newNote = new Note { Time = body.Note.Time, Text = body.Note.Text };
var newNote = new Note { Time = body.Note.Time, Text = body.Note.Text };
pmcData.Notes.DataNotes.Add(newNote);
return _eventOutputHolder.GetOutput(sessionId);
}
@@ -41,10 +41,10 @@ public class NoteController(
NoteActionData body,
string sessionId)
{
Note noteToEdit = pmcData.Notes.DataNotes[body.Index!.Value];
var noteToEdit = pmcData.Notes.DataNotes[body.Index!.Value];
noteToEdit.Time = body.Note.Time;
noteToEdit.Text = body.Note.Text;
return _eventOutputHolder.GetOutput(sessionId);
}
@@ -11,7 +11,7 @@ namespace Core.Controllers;
public class NotifierController(
HttpServerHelper _httpServerHelper,
NotifierHelper _notifierHelper
)
)
{
/// <summary>
/// Resolve an array of session notifications.
@@ -59,9 +59,9 @@ public class NotifierController(
// _notificationService.UpdateMessageOnQueue(sessionID, []);
// resolve(messages);
//};
//};
// immediately check
// immediately check
// checkNotifications();
//});
}
@@ -55,25 +55,25 @@ public class PrestigeController(
ObtainPrestigeRequestList request)
{
// Going to prestige 1
// transfer
// 5% of skills should be transfered over
// 5% of mastering should be transfered over
// earned achievements should be transfered over
// profile stats should be transfered over
// prestige progress should be transfered over
// reset
// trader standing
// task progress
// character level
// stash
// hideout progress
// going to prestige 2
// most likely the same, but wait for dump of new beginnings quest
// Clone existing profile, create a new one
var prePrestigeProfileClone = _cloner.Clone(_profileHelper.GetFullProfile(sessionId));
var prePrestigePmc = prePrestigeProfileClone.CharacterData.PmcData;
@@ -87,7 +87,7 @@ public class PrestigeController(
(customisation) => customisation.Value.Name == prePrestigePmc.Info.Voice
)
.Value.Id,
SptForcePrestigeLevel = prePrestigeProfileClone.CharacterData.PmcData.Info.PrestigeLevel.GetValueOrDefault(0) + 1, // Current + 1
SptForcePrestigeLevel = prePrestigeProfileClone.CharacterData.PmcData.Info.PrestigeLevel.GetValueOrDefault(0) + 1 // Current + 1
};
// Reset profile
@@ -104,15 +104,11 @@ public class PrestigeController(
skillToCopy.Progress = skillToCopy.Progress.Value * 0.05;
var existingSkill = newProfile.CharacterData.PmcData.Skills.Common.FirstOrDefault((skill) => skill.Id == skillToCopy.Id);
if (existingSkill is not null)
{
existingSkill.Progress = skillToCopy.Progress;
}
else
{
newProfile.CharacterData.PmcData.Skills.Common.Add(skillToCopy);
}
}
// Copy mastering to new profile
var masteringSkillsToCopy = prePrestigePmc.Skills.Mastering;
foreach (var skillToCopy in masteringSkillsToCopy)
@@ -123,35 +119,29 @@ public class PrestigeController(
(skill) => skill.Id == skillToCopy.Id
);
if (existingSkill is not null)
{
existingSkill.Progress = skillToCopy.Progress;
}
else
{
newProfile.CharacterData.PmcData.Skills.Mastering.Add(skillToCopy);
}
}
// Add existing completed achievements and new one for prestige
newProfile.CharacterData.PmcData.Achievements = prePrestigeProfileClone.CharacterData.PmcData.Achievements; // this *should* only contain completed ones
// Add "Prestigious" achievement
if (!newProfile.CharacterData.PmcData.Achievements.ContainsKey("676091c0f457869a94017a23"))
{
newProfile.CharacterData.PmcData.Achievements.Add("676091c0f457869a94017a23", _timeUtil.GetTimeStamp());
}
// TODO: is there one for second prestige
// Add existing Stats to profile
newProfile.CharacterData.PmcData.Stats = prePrestigePmc.Stats;
// Assumes Prestige data is in descending order
var indexOfPrestigeObtained = (int)Math.Min(createRequest.SptForcePrestigeLevel.Value - 1, 1); // Index starts at 0
var currentPrestigeData = _databaseService.GetTemplates().Prestige.Elements[indexOfPrestigeObtained];
var prestigeRewards = _databaseService.GetTemplates()
.Prestige.Elements.Slice(0, indexOfPrestigeObtained + 1)
.SelectMany((prestige) => prestige.Rewards);
AddPrestigeRewardsToProfile(sessionId, newProfile, prestigeRewards);
// Flag profile as having achieved this prestige level
@@ -159,7 +149,6 @@ public class PrestigeController(
newProfile.CharacterData.PmcData.Info.PrestigeLevel++;
if (request is not null)
{
// Copy transferred items
foreach (var transferRequest in request)
{
@@ -169,7 +158,7 @@ public class PrestigeController(
ItemWithModsToAdd = [item],
FoundInRaid = item.Upd?.SpawnedInSession,
UseSortingTable = false,
Callback = null,
Callback = null
};
_inventoryHelper.AddItemToStash(
sessionId,
@@ -178,40 +167,39 @@ public class PrestigeController(
_eventOutputHolder.GetOutput(sessionId)
);
}
}
// Force save of above changes to disk
_saveServer.SaveProfile(sessionId);
}
private void AddPrestigeRewardsToProfile(string sessionId, SptProfile newProfile, IEnumerable<Reward> rewards)
{
foreach (var reward in rewards) {
switch (reward.Type) {
case RewardType.CustomizationDirect: {
foreach (var reward in rewards)
switch (reward.Type)
{
case RewardType.CustomizationDirect:
{
_profileHelper.AddHideoutCustomisationUnlock(newProfile, reward, CustomisationSource.PRESTIGE);
break;
}
case RewardType.Skill:
if (Enum.TryParse(reward.Target, out SkillTypes result))
{
_profileHelper.AddSkillPointsToPlayer(
newProfile.CharacterData.PmcData,
result,
((JsonElement)reward.Value).ToObject<double>()
);
}
else
{
_logger.Error($"Unable to parse reward Target to Enum: {reward.Target}");
}
break;
case RewardType.Item: {
AddItemDirectRequest addItemRequest = new AddItemDirectRequest {
case RewardType.Item:
{
var addItemRequest = new AddItemDirectRequest
{
ItemWithModsToAdd = reward.Items,
FoundInRaid = reward.Items.FirstOrDefault()?.Upd?.SpawnedInSession,
UseSortingTable = false,
Callback = null,
Callback = null
};
_inventoryHelper.AddItemToStash(
sessionId,
@@ -229,6 +217,5 @@ public class PrestigeController(
_logger.Error($"Unhandled prestige reward type: {reward.Type}");
break;
}
}
}
}
+20 -43
View File
@@ -51,19 +51,15 @@ public class ProfileController(
public MiniProfile GetMiniProfile(string sessionID)
{
var profile = _saveServer.GetProfile(sessionID);
if (profile?.CharacterData == null)
{
throw new Exception($"Unable to find character data for id: {sessionID}. Profile may be corrupt");
}
if (profile?.CharacterData == null) throw new Exception($"Unable to find character data for id: {sessionID}. Profile may be corrupt");
var pmc = profile.CharacterData.PmcData;
var maxLvl = _profileHelper.GetMaxLevel();
// Player hasn't completed profile creation process, send defaults
var currlvl = pmc?.Info?.Level.GetValueOrDefault(1);
var xpToNextLevel = _profileHelper.GetExperience(((currlvl ?? 1) + 1));
var xpToNextLevel = _profileHelper.GetExperience((currlvl ?? 1) + 1);
if (pmc?.Info?.Level == null)
{
return new MiniProfile
{
Username = profile.ProfileInfo?.Username ?? "",
@@ -77,9 +73,8 @@ public class ProfileController(
MaxLevel = maxLvl,
Edition = profile.ProfileInfo?.Edition ?? "",
ProfileId = profile.ProfileInfo?.ProfileId ?? "",
SptData = _profileHelper.GetDefaultSptDataObject(),
SptData = _profileHelper.GetDefaultSptDataObject()
};
}
return new MiniProfile
{
@@ -87,14 +82,14 @@ public class ProfileController(
Nickname = pmc.Info.Nickname,
HasPassword = profile.ProfileInfo.Password != "",
Side = pmc.Info.Side,
CurrentLevel = (int)(pmc.Info.Level),
CurrentExperience = (pmc.Info.Experience ?? 0),
CurrentLevel = (int)pmc.Info.Level,
CurrentExperience = pmc.Info.Experience ?? 0,
PreviousExperience = currlvl == 0 ? 0 : _profileHelper.GetExperience((int)currlvl),
NextLevel = xpToNextLevel,
MaxLevel = maxLvl,
Edition = profile.ProfileInfo?.Edition ?? "",
ProfileId = profile.ProfileInfo?.ProfileId ?? "",
SptData = profile.SptData,
SptData = profile.SptData
};
}
@@ -133,15 +128,9 @@ public class ProfileController(
*/
public string ValidateNickname(ValidateNicknameRequestData info, string sessionID)
{
if (info.Nickname.Length < 3)
{
return "tooshort";
}
if (info.Nickname.Length < 3) return "tooshort";
if (_profileHelper.IsNicknameTaken(info, sessionID))
{
return "taken";
}
if (_profileHelper.IsNicknameTaken(info, sessionID)) return "taken";
return "OK";
}
@@ -188,10 +177,7 @@ public class ProfileController(
{
var pmcProfile = profile?.CharacterData?.PmcData;
if (!pmcProfile?.Info?.LowerNickname?.Contains(info.Nickname.ToLower()) ?? false)
{
continue;
}
if (!pmcProfile?.Info?.LowerNickname?.Contains(info.Nickname.ToLower()) ?? false) continue;
result.Add(_profileHelper.GetChatRoomMemberFromPmcProfile(pmcProfile));
}
@@ -210,8 +196,8 @@ public class ProfileController(
MaxPveCountExceeded = false,
Profiles =
[
new() { ProfileId = account.ScavengerId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 },
new() { ProfileId = account.ProfileId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 },
new ProfileStatusData { ProfileId = account.ScavengerId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 },
new ProfileStatusData { ProfileId = account.ProfileId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 }
]
};
@@ -261,7 +247,7 @@ public class ProfileController(
MemberCategory = profileToViewPmc.Info.MemberCategory as int?,
BannedState = profileToViewPmc.Info.BannedState,
BannedUntil = profileToViewPmc.Info.BannedUntil,
RegistrationDate = profileToViewPmc.Info.RegistrationDate,
RegistrationDate = profileToViewPmc.Info.RegistrationDate
},
Customization =
{
@@ -269,13 +255,13 @@ public class ProfileController(
Body = profileToViewPmc.Customization.Body,
Feet = profileToViewPmc.Customization.Feet,
Hands = profileToViewPmc.Customization.Hands,
Dogtag = profileToViewPmc.Customization.DogTag,
Dogtag = profileToViewPmc.Customization.DogTag
},
Skills = profileToViewPmc.Skills,
Equipment =
{
Id = profileToViewPmc.Inventory.Equipment,
Items = profileToViewPmc.Inventory.Items,
Items = profileToViewPmc.Inventory.Items
},
Achievements = profileToViewPmc.Achievements,
FavoriteItems = _profileHelper.GetOtherProfileFavorites(profileToViewPmc),
@@ -284,15 +270,15 @@ public class ProfileController(
Eft =
{
TotalInGameTime = profileToViewPmc.Stats.Eft.TotalInGameTime,
OverAllCounters = profileToViewPmc.Stats.Eft.OverallCounters,
},
OverAllCounters = profileToViewPmc.Stats.Eft.OverallCounters
}
},
ScavStats =
{
Eft =
{
TotalInGameTime = profileToViewScav.Stats.Eft.TotalInGameTime,
OverAllCounters = profileToViewScav.Stats.Eft.OverallCounters,
OverAllCounters = profileToViewScav.Stats.Eft.OverallCounters
}
},
Hideout = profileToViewPmc.Hideout,
@@ -308,20 +294,11 @@ public class ProfileController(
public bool SetChosenProfileIcon(string sessionId, GetProfileSettingsRequest request)
{
var profileToUpdate = _profileHelper.GetPmcProfile(sessionId);
if (profileToUpdate == null)
{
return false;
}
if (profileToUpdate == null) return false;
if (request.MemberCategory != null)
{
profileToUpdate.Info.SelectedMemberCategory = request.MemberCategory as MemberCategory?;
}
if (request.MemberCategory != null) profileToUpdate.Info.SelectedMemberCategory = request.MemberCategory as MemberCategory?;
if (request.SquadInviteRestriction != null)
{
profileToUpdate.Info.SquadInviteRestriction = request.SquadInviteRestriction;
}
if (request.SquadInviteRestriction != null) profileToUpdate.Info.SquadInviteRestriction = request.SquadInviteRestriction;
return true;
}
+10 -33
View File
@@ -107,10 +107,7 @@ public class QuestController(
acceptedQuest.QuestId,
sessionID
);
if (newlyAccessibleQuests.Count > 0)
{
acceptQuestResponse.ProfileChanges[sessionID].Quests.AddRange(newlyAccessibleQuests);
}
if (newlyAccessibleQuests.Count > 0) acceptQuestResponse.ProfileChanges[sessionID].Quests.AddRange(newlyAccessibleQuests);
return acceptQuestResponse;
}
@@ -120,11 +117,9 @@ public class QuestController(
foreach (var condition in questConditions)
{
if (pmcData.TaskConditionCounters.TryGetValue(condition.Id, out var counter))
{
_logger.Error(
$"Unable to add new task condition counter: {condition.ConditionType} for qeust: {questId} to profile: {pmcData.SessionId} as it already exists:"
);
}
switch (condition.ConditionType)
{
@@ -134,7 +129,7 @@ public class QuestController(
Id = condition.Id,
SourceId = questId,
Type = condition.ConditionType,
Value = 0,
Value = 0
};
break;
}
@@ -186,10 +181,7 @@ public class QuestController(
var matchingQuest = repeatableQuest.ActiveQuests.FirstOrDefault(x => x.Id == acceptedQuest.QuestId);
if (matchingQuest is not null)
{
if(_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Accepted repeatable quest {acceptedQuest.QuestId} from {repeatableQuest.Name}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Accepted repeatable quest {acceptedQuest.QuestId} from {repeatableQuest.Name}");
matchingQuest.SptRepatableGroupName = repeatableQuest.Name;
return matchingQuest;
@@ -217,7 +209,6 @@ public class QuestController(
// Decrement number of items handed in
QuestCondition? handoverRequirements = null;
foreach (var condition in quest.Conditions.AvailableForFinish)
{
if (condition.Id == handoverQuestRequest.ConditionId && handoverQuestTypes.Contains(condition.ConditionType))
{
handedInCount = int.Parse(condition.Value.ToString());
@@ -249,19 +240,14 @@ public class QuestController(
break;
}
}
}
if (isItemHandoverQuest && handedInCount == 0)
{
return ShowRepeatableQuestInvalidConditionError(handoverQuestRequest, output);
}
if (isItemHandoverQuest && handedInCount == 0) return ShowRepeatableQuestInvalidConditionError(handoverQuestRequest, output);
var totalItemCountToRemove = 0d;
foreach (var itemHandover in handoverQuestRequest.Items)
{
var matchingItemInProfile = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == itemHandover.Id);
if (!(matchingItemInProfile is not null && handoverRequirements.Target.List.Contains(matchingItemInProfile.Template)))
{
// Item handed in by player doesnt match what was requested
return ShowQuestItemHandoverMatchError(
handoverQuestRequest,
@@ -269,7 +255,6 @@ public class QuestController(
handoverRequirements,
output
);
}
// Remove the right quantity of given items
var itemCountToRemove = Math.Min(itemHandover.Count ?? 0, handedInCount - totalItemCountToRemove);
@@ -284,10 +269,7 @@ public class QuestController(
sessionID,
output
);
if (totalItemCountToRemove == handedInCount)
{
break;
}
if (totalItemCountToRemove == handedInCount) break;
}
else
{
@@ -306,13 +288,12 @@ public class QuestController(
// Important: loop backward when removing items from the array we're looping on
while (index-- > 0)
{
if (toRemove.Contains(pmcData.Inventory.Items[index].Id))
{
var removedItem = _cloner.Clone(pmcData.Inventory.Items[index]);
pmcData.Inventory.Items.RemoveAt(index);
// Remove the item
// Remove the item
// If the removed item has a numeric `location` property, re-calculate all the child
// element `location` properties of the parent so they are sequential, while retaining order
if (removedItem.Location.GetType() == typeof(int))
@@ -324,15 +305,11 @@ public class QuestController(
childItems.RemoveAt(0); // Remove the parent
// Sort by the current `location` and update
childItems.Sort((a, b) => (((int)a.Location) > ((int)b.Location) ? 1 : -1));
childItems.Sort((a, b) => (int)a.Location > (int)b.Location ? 1 : -1);
for (int i = 0; i < childItems.Count; i++)
{
childItems[i].Location = i;
}
for (var i = 0; i < childItems.Count; i++) childItems[i].Location = i;
}
}
}
}
}
@@ -370,7 +347,7 @@ public class QuestController(
{
questId = handoverQuestRequest.QuestId,
handedInTpl = itemHandedOver?.Template ?? "UNKNOWN",
requiredTpl = handoverRequirements.Target.List.FirstOrDefault(),
requiredTpl = handoverRequirements.Target.List.FirstOrDefault()
}
);
_logger.Error(errorMessage);
@@ -392,7 +369,7 @@ public class QuestController(
Id = conditionId,
SourceId = questId,
Type = "HandoverItem",
Value = counterValue,
Value = counterValue
};
}
+77 -166
View File
@@ -25,32 +25,32 @@ namespace Core.Controllers;
[Injectable]
public class RagfairController
{
private readonly ISptLogger<RagfairController> _logger;
private readonly TimeUtil _timeUtil;
private readonly JsonUtil _jsonUtil;
private readonly HttpResponseUtil _httpResponseUtil;
private readonly EventOutputHolder _eventOutputHolder;
private readonly RagfairServer _ragfairServer;
private readonly ItemHelper _itemHelper;
private readonly InventoryHelper _inventoryHelper;
private readonly RagfairSellHelper _ragfairSellHelper;
private readonly HandbookHelper _handbookHelper;
private readonly ProfileHelper _profileHelper;
private readonly PaymentHelper _paymentHelper;
private readonly RagfairHelper _ragfairHelper;
private readonly RagfairSortHelper _ragfairSortHelper;
private readonly RagfairOfferHelper _ragfairOfferHelper;
private readonly TraderHelper _traderHelper;
private readonly DatabaseService _databaseService;
private readonly LocalisationService _localisationService;
private readonly RagfairTaxService _ragfairTaxService;
private readonly RagfairOfferService _ragfairOfferService;
private readonly PaymentService _paymentService;
private readonly RagfairPriceService _ragfairPriceService;
private readonly RagfairOfferGenerator _ragfairOfferGenerator;
private readonly ConfigServer _configServer;
private readonly DatabaseService _databaseService;
private readonly EventOutputHolder _eventOutputHolder;
private readonly HandbookHelper _handbookHelper;
private readonly HttpResponseUtil _httpResponseUtil;
private readonly InventoryHelper _inventoryHelper;
private readonly ItemHelper _itemHelper;
private readonly JsonUtil _jsonUtil;
private readonly LocalisationService _localisationService;
private readonly ISptLogger<RagfairController> _logger;
private readonly PaymentHelper _paymentHelper;
private readonly PaymentService _paymentService;
private readonly ProfileHelper _profileHelper;
private readonly RagfairConfig _ragfairConfig;
private readonly RagfairHelper _ragfairHelper;
private readonly RagfairOfferGenerator _ragfairOfferGenerator;
private readonly RagfairOfferHelper _ragfairOfferHelper;
private readonly RagfairOfferService _ragfairOfferService;
private readonly RagfairPriceService _ragfairPriceService;
private readonly RagfairSellHelper _ragfairSellHelper;
private readonly RagfairServer _ragfairServer;
private readonly RagfairSortHelper _ragfairSortHelper;
private readonly RagfairTaxService _ragfairTaxService;
private readonly TimeUtil _timeUtil;
private readonly TraderHelper _traderHelper;
public RagfairController(
ISptLogger<RagfairController> logger,
@@ -119,9 +119,7 @@ public class RagfairController
if (
pmcProfile.RagfairInfo is not null && pmcProfile.Info.Level >= _databaseService.GetGlobals().Configuration.RagFair.MinUserLevel
)
{
_ragfairOfferHelper.ProcessOffersOnProfile(sessionId);
}
}
}
@@ -142,16 +140,14 @@ public class RagfairController
{
Offers = [],
OffersCount = searchRequest.Limit,
SelectedCategory = searchRequest.HandbookId,
SelectedCategory = searchRequest.HandbookId
};
result.Offers = GetOffersForSearchType(searchRequest, itemsToAdd, traderAssorts, profile.CharacterData.PmcData);
// Client requested a category refresh
if (searchRequest.UpdateOfferCount.GetValueOrDefault(false))
{
result.Categories = GetSpecificCategories(profile.CharacterData.PmcData, searchRequest, result.Offers);
}
AddIndexValueToOffers(result.Offers);
@@ -167,10 +163,7 @@ public class RagfairController
{
// For the items, check the barter schemes. The method getDisplayableAssorts sets a flag sptQuestLocked
// to true if the quest is not completed yet
if (_ragfairOfferHelper.TraderOfferItemQuestLocked(traderOffer, traderAssorts))
{
traderOffer.Locked = true;
}
if (_ragfairOfferHelper.TraderOfferItemQuestLocked(traderOffer, traderAssorts)) traderOffer.Locked = true;
// Update offers BuyRestrictionCurrent/BuyRestrictionMax values
SetTraderOfferPurchaseLimits(traderOffer, profile);
@@ -208,7 +201,7 @@ public class RagfairController
new
{
offerId = offer.Items.First().Id,
traderId = offer.User.Id,
traderId = offer.User.Id
}
)
);
@@ -263,10 +256,7 @@ public class RagfairController
{
var counter = 0;
foreach (var offer in offers)
{
offer.InternalId = ++counter;
}
foreach (var offer in offers) offer.InternalId = ++counter;
}
/**
@@ -293,10 +283,7 @@ public class RagfairController
else
{
_logger.Error(_localisationService.GetText("ragfair-unable_to_get_categories"));
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(_jsonUtil.Serialize(searchRequest));
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug(_jsonUtil.Serialize(searchRequest));
return new Dictionary<string, int>();
}
@@ -335,15 +322,9 @@ public class RagfairController
PmcData pmcProfile)
{
// Searching for items in preset menu
if (searchRequest.BuildCount > 0)
{
return _ragfairOfferHelper.GetOffersForBuild(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
}
if (searchRequest.BuildCount > 0) return _ragfairOfferHelper.GetOffersForBuild(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
if (searchRequest.NeededSearchId?.Length > 0)
{
return _ragfairOfferHelper.GetOffersThatRequireItem(searchRequest, pmcProfile);
}
if (searchRequest.NeededSearchId?.Length > 0) return _ragfairOfferHelper.GetOffersThatRequireItem(searchRequest, pmcProfile);
// Searching for general items
return _ragfairOfferHelper.GetValidOffers(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
@@ -375,10 +356,7 @@ public class RagfairController
// No offers listed, get price from live ragfair price list prices.json
// No flea price, get handbook price
var fleaPrices = _databaseService.GetPrices();
if (!fleaPrices.TryGetValue(getPriceRequest.TemplateId, out var tplPrice))
{
tplPrice = _handbookHelper.GetTemplatePrice(getPriceRequest.TemplateId);
}
if (!fleaPrices.TryGetValue(getPriceRequest.TemplateId, out var tplPrice)) tplPrice = _handbookHelper.GetTemplatePrice(getPriceRequest.TemplateId);
return new GetItemPriceResult { Avg = tplPrice, Min = tplPrice, Max = tplPrice };
}
@@ -391,40 +369,26 @@ public class RagfairController
foreach (var offer in offers)
{
// Exclude barter items, they tend to have outrageous equivalent prices
if (offer.Requirements.Any(req => !_paymentHelper.IsMoneyTpl(req.Template)))
{
continue;
}
if (offer.Requirements.Any(req => !_paymentHelper.IsMoneyTpl(req.Template))) continue;
if (ignoreTraderOffers && _ragfairOfferHelper.OfferIsFromTrader(offer))
{
continue;
}
if (ignoreTraderOffers && _ragfairOfferHelper.OfferIsFromTrader(offer)) continue;
// Figure out how many items the requirementsCost is applying to, and what the per-item price is
var offerItemCount = offer.SellInOnePiece.GetValueOrDefault(false)
? (offer.Items.First().Upd?.StackObjectsCount ?? 1)
? offer.Items.First().Upd?.StackObjectsCount ?? 1
: 1;
var perItemPrice = offer.RequirementsCost / offerItemCount;
// Handle min/max calculations based on the per-item price
if (perItemPrice < minMax.Min)
{
minMax.Min = perItemPrice;
}
else if (perItemPrice > minMax.Max)
{
minMax.Max = perItemPrice;
}
else if (perItemPrice > minMax.Max) minMax.Max = perItemPrice;
sum += perItemPrice.Value;
totalOfferCount++;
}
if (totalOfferCount == 0)
{
return -1d;
}
if (totalOfferCount == 0) return -1d;
return sum / totalOfferCount;
}
@@ -442,16 +406,11 @@ public class RagfairController
var fullProfile = _profileHelper.GetFullProfile(sessionID);
var validationMessage = "";
if (!IsValidPlayerOfferRequest(offerRequest, validationMessage))
{
return _httpResponseUtil.AppendErrorToOutput(output, validationMessage);
}
if (!IsValidPlayerOfferRequest(offerRequest, validationMessage)) return _httpResponseUtil.AppendErrorToOutput(output, validationMessage);
var typeOfOffer = GetOfferType(offerRequest);
if (typeOfOffer == FleaOfferType.UNKNOWN)
{
return _httpResponseUtil.AppendErrorToOutput(output, $"Unknown offer type: {typeOfOffer}, cannot list item on flea");
}
switch (typeOfOffer)
{
@@ -504,21 +463,12 @@ public class RagfairController
if (!sellInOncePiece)
{
if (offerRequest.Items.Count == 1)
{
return FleaOfferType.SINGLE;
}
if (offerRequest.Items.Count == 1) return FleaOfferType.SINGLE;
if (offerRequest.Items.Count > 1)
{
return FleaOfferType.MULTI;
}
if (offerRequest.Items.Count > 1) return FleaOfferType.MULTI;
}
if (sellInOncePiece)
{
return FleaOfferType.PACK;
}
if (sellInOncePiece) return FleaOfferType.PACK;
return FleaOfferType.UNKNOWN;
}
@@ -542,14 +492,12 @@ public class RagfairController
// Get first item and its children and use as template
var firstListingAndChidren = _itemHelper.FindAndReturnChildrenAsItems(
pmcData.Inventory.Items,
offerRequest.Items[0]);
offerRequest.Items[0]
);
// Find items to be listed on flea (+ children) from player inventory
var result = GetItemsToListOnFleaFromInventory(pmcData, offerRequest.Items);
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage))
{
_httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
}
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage)) _httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
// Total count of items summed using their stack counts
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(result.Items);
@@ -557,7 +505,7 @@ public class RagfairController
// When listing identical items on flea, condense separate items into one stack with a merged stack count
// e.g. 2 ammo items, stackObjectCount = 3 for each, will result in 1 stack of 6
firstListingAndChidren[0].Upd ??= new Upd{ };
firstListingAndChidren[0].Upd ??= new Upd { };
firstListingAndChidren[0].Upd.StackObjectsCount = stackCountTotal;
@@ -568,14 +516,11 @@ public class RagfairController
var newRootOfferItem = offer.Items[0];
// Average offer price for single item (or whole weapon)
var averages = GetItemMinAvgMaxFleaPriceValues(new GetMarketPriceRequestData{ TemplateId = offer.Items[0].Template });
var averages = GetItemMinAvgMaxFleaPriceValues(new GetMarketPriceRequestData { TemplateId = offer.Items[0].Template });
var averageOfferPrice = averages.Avg;
// Check for and apply item price modifer if it exists in config
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out var itemPriceModifer))
{
averageOfferPrice *= itemPriceModifer;
}
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out var itemPriceModifer)) averageOfferPrice *= itemPriceModifer;
// Get average of item+children quality
var qualityMultiplier = _itemHelper.GetItemQualityModifierForItems(offer.Items, true);
@@ -590,7 +535,8 @@ public class RagfairController
var sellChancePercent = _ragfairSellHelper.CalculateSellChance(
averageOfferPrice.Value,
playerListedPriceInRub,
qualityMultiplier);
qualityMultiplier
);
// Create array of sell times for items listed
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int)stackCountTotal);
@@ -605,11 +551,9 @@ public class RagfairController
playerListedPriceInRub,
(int)stackCountTotal,
offerRequest,
output);
if (taxFeeChargeFailed)
{
return output;
}
output
);
if (taxFeeChargeFailed) return output;
}
// Add offer to players profile + add to client response
@@ -617,9 +561,7 @@ public class RagfairController
output.ProfileChanges[sessionID].RagFairOffers.Add(offer);
// Remove items from inventory after creating offer
foreach (var itemToRemove in offerRequest.Items) {
_inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
}
foreach (var itemToRemove in offerRequest.Items) _inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
return output;
}
@@ -643,14 +585,12 @@ public class RagfairController
// Get first item and its children and use as template
var firstListingAndChidren = _itemHelper.FindAndReturnChildrenAsItems(
pmcData.Inventory.Items,
offerRequest.Items[0]);
offerRequest.Items[0]
);
// Find items to be listed on flea (+ children) from player inventory
var result = GetItemsToListOnFleaFromInventory(pmcData, offerRequest.Items);
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage))
{
_httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
}
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage)) _httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
// Total count of items summed using their stack counts
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(result.Items);
@@ -668,14 +608,11 @@ public class RagfairController
var newRootOfferItem = offer.Items[0];
// Single price for an item
var averages = GetItemMinAvgMaxFleaPriceValues( new GetMarketPriceRequestData{ TemplateId = firstListingAndChidren[0].Template });
var averages = GetItemMinAvgMaxFleaPriceValues(new GetMarketPriceRequestData { TemplateId = firstListingAndChidren[0].Template });
var singleItemPrice = averages.Avg;
// Check for and apply item price modifer if it exists in config
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out double itemPriceModifer))
{
singleItemPrice *= itemPriceModifer;
}
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out var itemPriceModifer)) singleItemPrice *= itemPriceModifer;
// Get average of item+children quality
var qualityMultiplier = _itemHelper.GetItemQualityModifierForItems(offer.Items, true);
@@ -690,7 +627,8 @@ public class RagfairController
var sellChancePercent = _ragfairSellHelper.CalculateSellChance(
singleItemPrice.Value * stackCountTotal,
playerListedPriceInRub,
qualityMultiplier);
qualityMultiplier
);
// Create array of sell times for items listed + sell all at once as its a pack
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int)stackCountTotal, true);
@@ -705,11 +643,9 @@ public class RagfairController
playerListedPriceInRub,
(int)stackCountTotal,
offerRequest,
output);
if (taxFeeChargeFailed)
{
return output;
}
output
);
if (taxFeeChargeFailed) return output;
}
// Add offer to players profile + add to client response
@@ -717,9 +653,7 @@ public class RagfairController
output.ProfileChanges[sessionID].RagFairOffers.Add(offer);
// Remove items from inventory after creating offer
foreach (var itemToRemove in offerRequest.Items) {
_inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
}
foreach (var itemToRemove in offerRequest.Items) _inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
return output;
}
@@ -741,10 +675,7 @@ public class RagfairController
// Find items to be listed on flea from player inventory
var result = GetItemsToListOnFleaFromInventory(pmcData, offerRequest.Items);
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage))
{
_httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
}
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage)) _httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
// Total count of items summed using their stack counts
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(result.Items);
@@ -767,10 +698,8 @@ public class RagfairController
var averageOfferPriceSingleItem = averages.Avg;
// Check for and apply item price modifer if it exists in config
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(rootItem.Template, out double itemPriceModifer))
{
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(rootItem.Template, out var itemPriceModifer))
averageOfferPriceSingleItem *= itemPriceModifer;
}
// Multiply single item price by quality
averageOfferPriceSingleItem *= qualityMultiplier;
@@ -795,10 +724,7 @@ public class RagfairController
offerRequest,
output
);
if (taxFeeChargeFailed)
{
return output;
}
if (taxFeeChargeFailed) return output;
}
// Add offer to players profile + add to client response
@@ -806,10 +732,7 @@ public class RagfairController
output.ProfileChanges[sessionID].RagFairOffers.Add(offer);
// Remove items from inventory after creating offer
foreach (var itemToRemove in offerRequest.Items)
{
_inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
}
foreach (var itemToRemove in offerRequest.Items) _inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
return output;
}
@@ -846,10 +769,7 @@ public class RagfairController
offerRequest.SellInOnePiece.GetValueOrDefault(false)
);
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Offer tax to charge: {tax}, pulled from client: {storedClientTaxValue.Count is not null}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _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
_ragfairTaxService.ClearStoredOfferTaxById(offerRequest.Items.First());
@@ -892,7 +812,7 @@ public class RagfairController
{
Template = item.Template,
Count = item.Count,
OnlyFunctional = item.OnlyFunctional,
OnlyFunctional = item.OnlyFunctional
}
);
@@ -919,13 +839,9 @@ public class RagfairController
var requestedItemTpl = item.Template;
if (_paymentHelper.IsMoneyTpl(requestedItemTpl))
{
requirementsPriceInRub += _handbookHelper.InRUB(item.Count.Value, requestedItemTpl);
}
else
{
requirementsPriceInRub += _itemHelper.GetDynamicItemPrice(requestedItemTpl).Value * item.Count.Value;
}
}
return requirementsPriceInRub;
@@ -963,12 +879,6 @@ public class RagfairController
return new GetItemsToListOnFleaFromInventoryResult { Items = itemsToReturn, ErrorMessage = errorMessage };
}
public record GetItemsToListOnFleaFromInventoryResult
{
public List<List<Item>>? Items { get; set; }
public string? ErrorMessage { get; set; }
}
public ItemEventRouterResponse RemoveOffer(RemoveOfferRequestData removeRequest, string sessionId)
{
var output = _eventOutputHolder.GetOutput(sessionId);
@@ -1050,10 +960,7 @@ public class RagfairController
{
var count = 1;
var sellInOncePiece = playerOffer.SellInOnePiece.GetValueOrDefault(false);
if (!sellInOncePiece)
{
count = (int)playerOffer.Items.Sum(offerItem => offerItem.Upd?.StackObjectsCount ?? 0);
}
if (!sellInOncePiece) count = (int)playerOffer.Items.Sum(offerItem => offerItem.Upd?.StackObjectsCount ?? 0);
var tax = _ragfairTaxService.CalculateTax(
playerOffer.Items.First(),
@@ -1066,12 +973,10 @@ public class RagfairController
var request = CreateBuyTradeRequestObject(CurrencyType.RUB, tax);
_paymentService.PayMoney(pmcData, request, sessionId, output);
if (output.Warnings.Count > 0)
{
return _httpResponseUtil.AppendErrorToOutput(
output,
_localisationService.GetText("ragfair-unable_to_pay_commission_fee")
);
}
}
// Add extra time to offer
@@ -1096,7 +1001,7 @@ public class RagfairController
Type = "",
ItemId = "",
Count = 0,
SchemeId = 0,
SchemeId = 0
};
}
@@ -1117,4 +1022,10 @@ public class RagfairController
return offerToReturn;
}
public record GetItemsToListOnFleaFromInventoryResult
{
public List<List<Item>>? Items { get; set; }
public string? ErrorMessage { get; set; }
}
}
@@ -11,7 +11,7 @@ namespace Core.Controllers;
public class RepairController(
EventOutputHolder _eventOutputHolder,
RepairService _repairService
)
)
{
/// <summary>
/// Handle TraderRepair event
@@ -29,7 +29,8 @@ public class RepairController(
var output = _eventOutputHolder.GetOutput(sessionID);
// find the item to repair
foreach (var repairItem in body.RepairItems) {
foreach (var repairItem in body.RepairItems)
{
var repairDetails = _repairService.RepairItemByTrader(sessionID, pmcData, repairItem, body.TId);
_repairService.PayForRepair(
@@ -38,12 +39,10 @@ public class RepairController(
repairItem.Id,
repairDetails.RepairCost.Value,
body.TId,
output);
output
);
if (output.Warnings?.Count > 0)
{
return output;
}
if (output.Warnings?.Count > 0) return output;
// Add repaired item to output object
output.ProfileChanges[sessionID].Items.ChangedItems.Add(repairDetails.RepairedItem);
@@ -89,10 +89,7 @@ public class RepeatableQuestController(
);
// If the configuration dictates to replace with the same quest type, adjust the available quest types
if (repeatableConfig?.KeepDailyQuestTypeOnReplacement is not null)
{
repeatableConfig.Types = [questToReplace.Type.ToString()];
}
if (repeatableConfig?.KeepDailyQuestTypeOnReplacement is not null) repeatableConfig.Types = [questToReplace.Type.ToString()];
// Generate meta-data for what type/levelrange of quests can be generated for player
var allowedQuestTypes = GenerateQuestPool(repeatableConfig, pmcData.Info.Level);
@@ -117,11 +114,9 @@ public class RepeatableQuestController(
repeatablesOfTypeInProfile.ActiveQuests.Add(newRepeatableQuest);
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
$"Removing: {repeatableConfig.Name} quest: {questToReplace.Id} from trader: {questToReplace.TraderId} as its been replaced"
);
}
RemoveQuestFromProfile(fullProfile, questToReplace.Id);
@@ -153,10 +148,7 @@ public class RepeatableQuestController(
// Not free, Charge player + appy charisma bonus to cost of replacement
cost.Count = (int)Math.Truncate(cost.Count.Value * (1 - Math.Truncate(charismaBonus / 100) * 0.001));
_paymentService.AddPaymentToOutput(pmcData, cost.TemplateId, cost.Count.Value, sessionID, output);
if (output.Warnings.Count > 0)
{
return output;
}
if (output.Warnings.Count > 0) return output;
}
}
@@ -227,16 +219,12 @@ public class RepeatableQuestController(
string replacedQuestId)
{
if (repeatablesOfTypeInProfile.ActiveQuests.Count == 1)
{
// Only one repeatable quest being replaced (e.g. scav_daily), remove everything ready for new quest requirement to be added
// Will assist in cleanup of existing profiles data
repeatablesOfTypeInProfile.ChangeRequirement.Clear();
}
else
{
// Multiple active quests of this type (e.g. daily or weekly) are active, just remove the single replaced quest
repeatablesOfTypeInProfile.ChangeRequirement.Remove(replacedQuestId);
}
}
private RepeatableQuest? AttemptToGenerateRepeatableQuest(string sessionId, PmcData pmcData,
@@ -256,18 +244,13 @@ public class RepeatableQuestController(
);
if (newRepeatableQuest is not null)
{
// Successfully generated a quest, exit loop
break;
}
attempts++;
}
if (attempts > maxAttempts)
{
_logger.Error("We were stuck in repeatable quest generation. This should never happen. Please report");
}
if (attempts > maxAttempts) _logger.Error("We were stuck in repeatable quest generation. This should never happen. Please report");
return newRepeatableQuest;
}
@@ -279,12 +262,10 @@ public class RepeatableQuestController(
// Find quest we're replacing in scav profile quests array and remove it
if (fullProfile.CharacterData.ScavData is not null)
{
_questHelper.FindAndRemoveQuestFromArrayIfExists(
questToReplaceId,
fullProfile.CharacterData.ScavData.Quests
);
}
}
/**
@@ -301,10 +282,8 @@ public class RepeatableQuestController(
var questToReplace =
repeatablesInProfile.ActiveQuests.FirstOrDefault(repeatable => repeatable.Id == questId);
if (questToReplace is null)
{
// Not found, skip to next repeatable sub-type
continue;
}
return new GetRepeatableByIdResult { Quest = questToReplace, RepeatableType = repeatablesInProfile };
}
@@ -328,20 +307,15 @@ public class RepeatableQuestController(
var canAccessRepeatables = CanProfileAccessRepeatableQuests(repeatableConfig, pmcData);
if (!canAccessRepeatables)
{
// Don't send any repeatables, even existing ones
continue;
}
// Existing repeatables are still valid, add to return data and move to next sub-type
if (currentTime < generatedRepeatables.EndTime - 1)
{
returnData.Add(generatedRepeatables);
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"[Quest Check] {repeatableTypeLower} quests are still valid.");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"[Quest Check] {repeatableTypeLower} quests are still valid.");
continue;
}
@@ -351,10 +325,7 @@ public class RepeatableQuestController(
// Set endtime to be now + new duration
generatedRepeatables.EndTime = currentTime + repeatableConfig.ResetTime;
generatedRepeatables.InactiveQuests = [];
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Generating new {repeatableTypeLower}");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Generating new {repeatableTypeLower}");
// Put old quests to inactive (this is required since only then the client makes them fail due to non-completion)
// Also need to push them to the "inactiveQuests" list since we need to remove them from offraidData.profile.Quests
@@ -391,10 +362,7 @@ public class RepeatableQuestController(
}
// check if there are no more quest types available
if (questTypePool.Types.Count == 0)
{
break;
}
if (questTypePool.Types.Count == 0) break;
quest.Side = repeatableConfig.Side;
generatedRepeatables.ActiveQuests.Add(quest);
@@ -473,18 +441,12 @@ public class RepeatableQuestController(
private bool CanProfileAccessRepeatableQuests(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
{
// PMC and daily quests not unlocked yet
if (repeatableConfig.Side == "Pmc" && !PlayerHasDailyPmcQuestsUnlocked(pmcData, repeatableConfig))
{
return false;
}
if (repeatableConfig.Side == "Pmc" && !PlayerHasDailyPmcQuestsUnlocked(pmcData, repeatableConfig)) return false;
// Scav and daily quests not unlocked yet
if (repeatableConfig.Side == "Scav" && !PlayerHasDailyScavQuestsUnlocked(pmcData))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug("Daily scav quests still locked, Intel center not built");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug("Daily scav quests still locked, Intel center not built");
return false;
}
@@ -521,21 +483,16 @@ public class RepeatableQuestController(
foreach (var activeQuest in generatedRepeatables.ActiveQuests)
{
var questStatusInProfile = pmcData.Quests.FirstOrDefault(quest => quest.QId == activeQuest.Id);
if (questStatusInProfile is null)
{
continue;
}
if (questStatusInProfile is null) continue;
// Keep finished quests in list so player can hand in
if (questStatusInProfile.Status == QuestStatusEnum.AvailableForFinish)
{
questsToKeep.Add(activeQuest);
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug( // TODO: this shouldnt happen, doesnt on live
$"Keeping repeatable quest: {activeQuest.Id} in activeQuests since it is available to hand in"
);
}
continue;
}
@@ -632,17 +589,10 @@ public class RepeatableQuestController(
{
var locationNames = new List<string>();
foreach (var locationName in value)
{
if (IsPmcLevelAllowedOnLocation(locationName, pmcLevel))
{
locationNames.Add(locationName);
}
}
if (locationNames.Count > 0)
{
allowedLocation[location] = locationNames;
}
if (locationNames.Count > 0) allowedLocation[location] = locationNames;
}
return allowedLocation;
@@ -657,16 +607,10 @@ public class RepeatableQuestController(
protected bool IsPmcLevelAllowedOnLocation(string location, int pmcLevel)
{
// All PMC levels are allowed for 'any' location requirement
if (location == ELocationName.any.ToString())
{
return true;
}
if (location == ELocationName.any.ToString()) return true;
var locationBase = _databaseService.GetLocation(location.ToLower())?.Base;
if (locationBase is null)
{
return true;
}
if (locationBase is null) return true;
return pmcLevel <= locationBase.RequiredPlayerLevelMax && pmcLevel >= locationBase.RequiredPlayerLevelMin;
}
@@ -680,14 +624,10 @@ public class RepeatableQuestController(
private int GetQuestCount(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
{
var questCount = repeatableConfig.NumQuests.GetValueOrDefault(0);
if (questCount == 0)
{
_logger.Warning($"Repeatable {repeatableConfig.Name} quests have a count of 0");
}
if (questCount == 0) _logger.Warning($"Repeatable {repeatableConfig.Name} quests have a count of 0");
// Add elite bonus to daily quests
if (repeatableConfig.Name.ToLower() == "daily" && _profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, pmcData))
{
// Elite charisma skill gives extra daily quest(s)
questCount += _databaseService
.GetGlobals()
@@ -698,7 +638,6 @@ public class RepeatableQuestController(
.EliteBonusSettings
.RepeatableQuestExtraCount
.GetValueOrDefault(0);
}
return questCount;
}
+14 -39
View File
@@ -58,7 +58,7 @@ public class TradeController(
if (request.Type == "buy_from_trader")
{
var foundInRaid = _traderConfig.PurchasesAreFoundInRaid;
ProcessBuyTradeRequestData buyData = (ProcessBuyTradeRequestData)request;
var buyData = (ProcessBuyTradeRequestData)request;
_tradeHelper.buyItem(pmcData, buyData, sessionID, foundInRaid, output);
return output;
@@ -67,7 +67,7 @@ public class TradeController(
// Selling
if (request.Type == "sell_to_trader")
{
ProcessSellTradeRequestData sellData = (ProcessSellTradeRequestData)request;
var sellData = (ProcessSellTradeRequestData)request;
_tradeHelper.sellItem(pmcData, pmcData, sellData, sessionID, output);
return output;
@@ -97,13 +97,11 @@ public class TradeController(
{
var fleaOffer = _ragfairServer.GetOffer(offer.Id);
if (fleaOffer is null)
{
return _httpResponseUtil.AppendErrorToOutput(
output,
$"Offer with ID {offer.Id} not found",
BackendErrorCodes.OfferNotFound
);
}
if (offer.Count == 0)
{
@@ -115,19 +113,12 @@ public class TradeController(
}
if (_ragfairOfferHelper.OfferIsFromTrader(fleaOffer))
{
BuyTraderItemFromRagfair(sessionID, pmcData, fleaOffer, offer, output);
}
else
{
BuyPmcItemFromRagfair(sessionID, pmcData, fleaOffer, offer, output);
}
// Exit loop early if problem found
if (output.Warnings?.Count > 0)
{
return output;
}
if (output.Warnings?.Count > 0) return output;
}
return output;
@@ -152,17 +143,14 @@ public class TradeController(
if (PlayerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData))
{
var errorMessage = $"Unable to buy item: {fleaOffer.Items[0].Template} from trader: {fleaOffer.User.Id} as loyalty level too low, skipping";
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(errorMessage);
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug(errorMessage);
_httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.RagfairUnavailable);
return;
}
ProcessBuyTradeRequestData buyData = new ProcessBuyTradeRequestData
var buyData = new ProcessBuyTradeRequestData
{
Action = "TradingConfirm",
Type = "buy_from_ragfair",
@@ -170,7 +158,7 @@ public class TradeController(
ItemId = fleaOffer.Root,
Count = requestOffer.Count,
SchemeId = 0,
SchemeItems = requestOffer.Items,
SchemeItems = requestOffer.Items
};
_tradeHelper.buyItem(pmcData, buyData, sessionId, _traderConfig.PurchasesAreFoundInRaid, output);
@@ -191,7 +179,7 @@ public class TradeController(
OfferRequest requestOffer,
ItemEventRouterResponse output)
{
ProcessBuyTradeRequestData buyData = new ProcessBuyTradeRequestData
var buyData = new ProcessBuyTradeRequestData
{
Action = "TradingConfirm",
Type = "buy_from_ragfair",
@@ -199,15 +187,12 @@ public class TradeController(
ItemId = fleaOffer.Id, // Store ragfair offerId in buyRequestData.item_id
Count = requestOffer.Count,
SchemeId = 0,
SchemeItems = requestOffer.Items,
SchemeItems = requestOffer.Items
};
// buyItem() must occur prior to removing the offer stack, otherwise item inside offer doesn't exist for confirmTrading() to use
_tradeHelper.buyItem(pmcData, buyData, sessionId, _ragfairConfig.Dynamic.PurchasesAreFoundInRaid, output);
if (output.Warnings?.Count > 0)
{
return;
}
if (output.Warnings?.Count > 0) return;
// resolve when a profile buy another profile's offer
var offerOwnerId = fleaOffer.User?.Id;
@@ -237,17 +222,12 @@ public class TradeController(
string? offerOwnerId)
{
// No ownerid, not player offer
if (offerOwnerId is null)
{
return false;
}
if (offerOwnerId is null) return false;
var offerCreatorProfile = _profileHelper.GetPmcProfile(offerOwnerId);
if (offerCreatorProfile is null || offerCreatorProfile.RagfairInfo.Offers?.Count == 0)
{
// No profile or no offers
return false;
}
// Does offer id exist in profile
return offerCreatorProfile.RagfairInfo.Offers.Any(offer => offer.Id == offerId);
@@ -296,17 +276,14 @@ public class TradeController(
int roublesToSend,
string trader)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Selling scav items to fence for {roublesToSend} roubles");
}
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Selling scav items to fence for {roublesToSend} roubles");
// Create single currency item with all currency on it
Item rootCurrencyReward = new Item
var rootCurrencyReward = new Item
{
Id = _hashUtil.Generate(),
Template = Money.ROUBLES,
Upd = new Upd { StackObjectsCount = roublesToSend },
Upd = new Upd { StackObjectsCount = roublesToSend }
};
// Ensure money is properly split to follow its max stack size limit
@@ -317,7 +294,7 @@ public class TradeController(
sessionId,
_traderHelper.GetTraderById(trader).ToString(),
MessageType.MESSAGE_WITH_ITEMS,
_randomUtil.GetArrayValue((_databaseService.GetTrader(trader).Dialogue.TryGetValue("SoldItems", out var items)) ? items : new List<string>()),
_randomUtil.GetArrayValue(_databaseService.GetTrader(trader).Dialogue.TryGetValue("SoldItems", out var items) ? items : new List<string>()),
curencyReward.SelectMany(x => x).ToList(),
_timeUtil.GetHoursAsSeconds(72)
);
@@ -344,10 +321,8 @@ public class TradeController(
{
var itemDetails = _itemHelper.GetItem(itemToSell.Template);
if (!(itemDetails.Key && _itemHelper.IsOfBaseclasses(itemDetails.Value.Id, traderDetails.ItemsBuy.Category)))
{
// Skip if tpl isn't item OR item doesn't fulfil match traders buy categories
continue;
}
// Get price of item multiplied by how many are in stack
totalPrice += (int)((handbookPrices[itemToSell.Template] ?? 0) * (itemToSell.Upd?.StackObjectsCount ?? 1));
+6 -15
View File
@@ -59,17 +59,13 @@ public class TraderController(
// Adjust price by traderPriceMultipler config property
if (_traderConfig.TraderPriceMultipler != 1)
{
foreach (var kvp in trader.Value?.Assort?.BarterScheme)
{
var barterSchemeItem = kvp.Value[0][0];
if (barterSchemeItem != null && _paymentHelper.IsMoneyTpl(barterSchemeItem?.Template))
{
barterSchemeItem.Count += Math.Round((barterSchemeItem?.Count * _traderConfig?.TraderPriceMultipler) ?? 0D, 2);
}
barterSchemeItem.Count += Math.Round(barterSchemeItem?.Count * _traderConfig?.TraderPriceMultipler ?? 0D, 2);
}
}
// Create dict of pristine trader assorts on server start
if (_traderAssortService.GetPristineTraderAssort(trader.Key) == null)
@@ -81,7 +77,8 @@ public class TraderController(
_traderPurchasePersisterService.RemoveStalePurchasesFromProfiles(trader.Key);
// Set to next hour on clock or current time + 60 mins
trader.Value.Base.NextResupply = traderResetStartsWithServer ? (int)_traderHelper.GetNextUpdateTimestamp(trader.Value.Base.Id) : (int)nextHourTimestamp;
trader.Value.Base.NextResupply =
traderResetStartsWithServer ? (int)_traderHelper.GetNextUpdateTimestamp(trader.Value.Base.Id) : (int)nextHourTimestamp;
}
}
@@ -101,10 +98,7 @@ public class TraderController(
continue;
case Traders.FENCE:
{
if (_fenceService.NeedsPartialRefresh())
{
_fenceService.GenerateFenceAssorts();
}
if (_fenceService.NeedsPartialRefresh()) _fenceService.GenerateFenceAssorts();
continue;
}
}
@@ -135,10 +129,7 @@ public class TraderController(
{
traders.Add(_traderHelper.GetTrader(traderId, sessionId));
if (pmcData?.Info != null)
{
_traderHelper.LevelUp(traderId, pmcData);
}
if (pmcData?.Info != null) _traderHelper.LevelUp(traderId, pmcData);
}
traders.Sort(SortByTraderId);
@@ -186,7 +177,7 @@ public class TraderController(
{
var handbookPrices = _ragfairPriceService.GetAllStaticPrices();
return new()
return new GetItemPricesResponse
{
SupplyNextTime = _traderHelper.GetNextUpdateTimestamp(traderId),
Prices = handbookPrices,
@@ -23,10 +23,7 @@ public class WishlistController(
AddToWishlistRequest request,
string sessionId)
{
foreach (var item in request.Items)
{
pmcData.WishList.Dictionary.Add(item.Key, item.Value);
}
foreach (var item in request.Items) pmcData.WishList.Dictionary.Add(item.Key, item.Value);
return _eventOutputHolder.GetOutput(sessionId);
}
@@ -43,10 +40,7 @@ public class WishlistController(
RemoveFromWishlistRequest request,
string sessionId)
{
foreach (var itemId in request.Items)
{
pmcData.WishList.Dictionary.Remove(itemId);
}
foreach (var itemId in request.Items) pmcData.WishList.Dictionary.Remove(itemId);
return _eventOutputHolder.GetOutput(sessionId);
}