From 48b5a00726be56b655eb95499e6ecfd63e95286b Mon Sep 17 00:00:00 2001 From: CWX Date: Thu, 23 Jan 2025 23:52:35 +0000 Subject: [PATCH] implment other controllers --- Libraries/Core/Controllers/BotController.cs | 35 +-- Libraries/Core/Controllers/GameController.cs | 47 +--- .../Core/Controllers/HandBookController.cs | 4 +- .../Core/Controllers/HealthController.cs | 74 +++++- .../Core/Controllers/HideoutController.cs | 232 +++++++++++++++++- 5 files changed, 315 insertions(+), 77 deletions(-) diff --git a/Libraries/Core/Controllers/BotController.cs b/Libraries/Core/Controllers/BotController.cs index 70a2979b..8688e392 100644 --- a/Libraries/Core/Controllers/BotController.cs +++ b/Libraries/Core/Controllers/BotController.cs @@ -132,13 +132,15 @@ public class BotController( public List Generate(string sessionId, GenerateBotsRequestData info) { - var pmcProfile = _profileHelper.GetPmcProfile(sessionId); + // var pmcProfile = _profileHelper.GetPmcProfile(sessionId); + // + // // Use this opportunity to create and cache bots for later retrieval + // var multipleBotTypesRequested = info.Conditions?.Count > 1; + // return multipleBotTypesRequested + // ? GenerateMultipleBotsAndCache(info, pmcProfile, sessionId) + // : ReturnSingleBotFromCache(sessionId, info); - // Use this opportunity to create and cache bots for later retrieval - var multipleBotTypesRequested = info.Conditions?.Count > 1; - return multipleBotTypesRequested - ? GenerateMultipleBotsAndCache(info, pmcProfile, sessionId) - : ReturnSingleBotFromCache(sessionId, info); + return new List(); } private List GenerateMultipleBotsAndCache(GenerateBotsRequestData request, PmcData? pmcProfile, string sessionId) @@ -404,27 +406,6 @@ public class BotController( }; } - public int GetBotLimit(string type) - { - throw new NotImplementedException(); - } - - - public bool IsBotPmc(string botRole) - { - throw new NotImplementedException(); - } - - public bool IsBotBoss(string botRole) - { - throw new NotImplementedException(); - } - - public bool IsBotFollower(string botRole) - { - throw new NotImplementedException(); - } - public int GetBotCap(string location) { var botCap = _botConfig.MaxBotCap[location.ToLower()]; diff --git a/Libraries/Core/Controllers/GameController.cs b/Libraries/Core/Controllers/GameController.cs index be4553e4..975498a2 100644 --- a/Libraries/Core/Controllers/GameController.cs +++ b/Libraries/Core/Controllers/GameController.cs @@ -88,27 +88,6 @@ public class GameController( if (fullProfile.ProfileInfo?.IsWiped is not null && fullProfile.ProfileInfo.IsWiped.Value) return; - - if (fullProfile.SptData.Version!.Contains("3.9.") && fullProfile.SptData.Migrations.All(m => m.Key != "39x")) - { - _inventoryHelper.ValidateInventoryUsesMongoIds(fullProfile.CharacterData?.PmcData?.Inventory?.Items ?? []); - Migrate39xProfile(fullProfile); - - // flag as migrated - fullProfile.SptData.Migrations.Add("39x", _timeUtil.GetTimeStamp()); - _logger.Info($"Migration of 3.9.x profile: {fullProfile.ProfileInfo?.Username} completed successfully"); - } - - //3.10 migrations - if (fullProfile.SptData.Version!.Contains("3.10.") && fullProfile.SptData.Migrations.All(m => m.Key != "310x")) - { - Migrate310xProfile(fullProfile); - - // Flag as migrated - fullProfile.SptData.Migrations["310x"] = _timeUtil.GetTimeStamp(); - - _logger.Success($"Migration of 3.10.x profile: {fullProfile.ProfileInfo?.Username} completed successfully"); - } fullProfile.CharacterData!.PmcData!.WishList ??= new DictionaryOrList(new Dictionary(), []); fullProfile.CharacterData.ScavData!.WishList ??= new DictionaryOrList(new Dictionary(), []); @@ -158,26 +137,6 @@ public class GameController( _seasonalEventService.GivePlayerSeasonalGifts(sessionId); } - private void Migrate39xProfile(SptProfile fullProfile) - { - throw new NotImplementedException(); - } - - private void Migrate310xProfile(SptProfile fullProfile) - { - throw new NotImplementedException(); - } - - /// - /// Handles migrating profiles from older SPT versions - /// - /// - /// Formerly migrate39xProfile in node server - private void MigrateProfile(SptProfile fullProfile) - { - throw new NotImplementedException(); - } - /// /// Handle client/game/config /// @@ -354,13 +313,13 @@ public class GameController( // Set new values, whatever is smallest energyRegenPerHour += pmcProfile.Bonuses! - .Where((bonus) => bonus.Type == BonusType.EnergyRegeneration) + .Where(bonus => bonus.Type == BonusType.EnergyRegeneration) .Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value)); hydrationRegenPerHour += pmcProfile.Bonuses! - .Where((bonus) => bonus.Type == BonusType.HydrationRegeneration) + .Where(bonus => bonus.Type == BonusType.HydrationRegeneration) .Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value)); hpRegenPerHour += pmcProfile.Bonuses! - .Where((bonus) => bonus.Type == BonusType.HealthRegeneration) + .Where(bonus => bonus.Type == BonusType.HealthRegeneration) .Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value)); // Player has energy deficit diff --git a/Libraries/Core/Controllers/HandBookController.cs b/Libraries/Core/Controllers/HandBookController.cs index ac63f9e0..e3e4a12b 100644 --- a/Libraries/Core/Controllers/HandBookController.cs +++ b/Libraries/Core/Controllers/HandBookController.cs @@ -2,12 +2,12 @@ using SptCommon.Annotations; namespace Core.Controllers; -// TODO: This seems unused, is it even needed? [Injectable] public class HandBookController { public void Load() { - // throw new NotImplementedException(); + // leaving as this is how node is RN + return; } } diff --git a/Libraries/Core/Controllers/HealthController.cs b/Libraries/Core/Controllers/HealthController.cs index de84621f..f18c24d6 100644 --- a/Libraries/Core/Controllers/HealthController.cs +++ b/Libraries/Core/Controllers/HealthController.cs @@ -12,6 +12,7 @@ using Core.Utils; using Core.Utils.Cloners; using SptCommon.Annotations; using SptCommon.Extensions; +using BodyPartHealth = Core.Models.Eft.Common.Tables.BodyPartHealth; namespace Core.Controllers; @@ -37,9 +38,78 @@ public class HealthController( public ItemEventRouterResponse OffRaidHeal( PmcData pmcData, OffraidHealRequestData request, - string sessionId) + string sessionID) { - throw new NotImplementedException(); + var output = _eventOutputHolder.GetOutput(sessionID); + + // Update medkit used (hpresource) + var healingItemToUse = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item); + if (healingItemToUse is null) { + var errorMessage = _localisationService.GetText("health-healing_item_not_found", request.Item); + _logger.Error(errorMessage); + + return _httpResponseUtil.AppendErrorToOutput(output, errorMessage); + } + + // Ensure item has a upd object + _itemHelper.AddUpdObjectToItem(healingItemToUse); + + if (healingItemToUse.Upd.MedKit is not null) { + healingItemToUse.Upd.MedKit.HpResource -= request.Count; + } else { + // Get max healing from db + var maxhp = _itemHelper.GetItem(healingItemToUse.Template).Value.Properties.MaxHpResource; + healingItemToUse.Upd.MedKit = new UpdMedKit { HpResource = maxhp - request.Count }; // Subtract amout used from max + // request.count appears to take into account healing effects removed, e.g. bleeds + // Salewa heals limb for 20 and fixes light bleed = (20+45 = 65) + } + + // Resource in medkit is spent, delete it + 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()); + if (bodyPartToHeal is null) { + _logger.Warning($"Player: {sessionID} Tried to heal a non-existent body part: {request.Part}"); + + return output; + } + + // Get inital heal amount + var amountToHealLimb = request.Count; + + // Check if healing item removes negative effects + var itemRemovesEffects = healingItemDbDetails.Value.Properties.EffectsDamage.Count > 0; + if (itemRemovesEffects && bodyPartToHeal.Effects is not null) { + // Can remove effects and limb has effects to remove + var effectsOnBodyPart = bodyPartToHeal.Effects.Keys; + foreach (var effectKey in effectsOnBodyPart) { + // Check if healing item removes the effect on limb + var matchingEffectFromHealingItem = healItemEffectDetails.GetValueOrDefault(effectKey); + if (matchingEffectFromHealingItem is null) { + // Healing item doesnt have matching effect, it doesnt 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); + bodyPartToHeal.Effects.Remove(effectKey); + } + } + + // Adjust body part hp value + 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; + } + + return output; } /// diff --git a/Libraries/Core/Controllers/HideoutController.cs b/Libraries/Core/Controllers/HideoutController.cs index dee1aa38..c8be08d3 100644 --- a/Libraries/Core/Controllers/HideoutController.cs +++ b/Libraries/Core/Controllers/HideoutController.cs @@ -2,8 +2,10 @@ using SptCommon.Annotations; using Core.Generators; using Core.Helpers; using Core.Models.Eft.Common; +using Core.Models.Eft.Common.Tables; using Core.Models.Eft.Hideout; using Core.Models.Eft.ItemEvent; +using Core.Models.Enums; using Core.Models.Spt.Config; using Core.Models.Utils; using Core.Routers; @@ -42,13 +44,239 @@ public class HideoutController( ) { protected HideoutConfig _hideoutConfig = _configServer.GetConfig(); + protected string _nameTaskConditionCountersCraftingId = "673f5d6fdd6ed700c703afdc"; - public void StartUpgrade(PmcData pmcData, HideoutUpgradeRequestData info, string sessionId, ItemEventRouterResponse output) + public void StartUpgrade(PmcData pmcData, HideoutUpgradeRequestData request, string sessionID, ItemEventRouterResponse output) + { + var items = request.Items.Select( + reqItem => + { + var item = pmcData.Inventory.Items.FirstOrDefault(invItem => invItem.Id == reqItem.Id); + return new { inventoryItem = item, requestedItem = reqItem }; + } + ) + .ToList(); + + // If it's not money, its construction / barter items + foreach (var item in items) + { + if (item.inventoryItem is null) + { + _logger.Error( + _localisationService.GetText("hideout-unable_to_find_item_in_inventory", item.requestedItem.Id) + ); + _httpResponseUtil.AppendErrorToOutput(output); + + return; + } + + if ( + _paymentHelper.IsMoneyTpl(item.inventoryItem.Template) && + item.inventoryItem.Upd is not null && + 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 + var profileHideoutArea = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == request.AreaType); + if (profileHideoutArea is null) + { + _logger.Error(_localisationService.GetText("hideout-unable_to_find_area", request.AreaType)); + _httpResponseUtil.AppendErrorToOutput(output); + + return; + } + + var hideoutDataDb = _databaseService + .GetTables() + .Hideout.Areas.FirstOrDefault(area => area.Type == request.AreaType); + if (hideoutDataDb is null) + { + _logger.Error( + _localisationService.GetText("hideout-unable_to_find_area_in_database", request.AreaType) + ); + _httpResponseUtil.AppendErrorToOutput(output); + + return; + } + + var ctime = hideoutDataDb.Stages[(profileHideoutArea.Level + 1).ToString()].ConstructionTime; + if (ctime > 0) + { + if (_profileHelper.IsDeveloperAccount(sessionID)) + { + ctime = 40; + } + + var timestamp = _timeUtil.GetTimeStamp(); + + profileHideoutArea.CompleteTime = Math.Round((double)(timestamp - ctime)); + profileHideoutArea.Constructing = true; + } + } + + public void UpgradeComplete(PmcData pmcData, HideoutUpgradeCompleteRequestData request, string sessionID, ItemEventRouterResponse output) + { + var hideout = _databaseService.GetHideout(); + var globals = _databaseService.GetGlobals(); + + var profileHideoutArea = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == request.AreaType); + if (profileHideoutArea is null) + { + _logger.Error(_localisationService.GetText("hideout-unable_to_find_area", request.AreaType)); + _httpResponseUtil.AppendErrorToOutput(output); + + return; + } + + // Upgrade profile values + profileHideoutArea.Level++; + profileHideoutArea.CompleteTime = 0; + profileHideoutArea.Constructing = false; + + var hideoutData = hideout.Areas.FirstOrDefault(area => area.Type == profileHideoutArea.Type); + if (hideoutData is null) + { + _logger.Error( + _localisationService.GetText("hideout-unable_to_find_area_in_database", request.AreaType) + ); + _httpResponseUtil.AppendErrorToOutput(output); + + return; + } + + // Apply bonuses + 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 (hideoutStage?.Container is not null) + { + AddContainerImprovementToProfile( + output, + sessionID, + pmcData, + profileHideoutArea, + 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( + pmcData, + SkillTypes.HideoutManagement, + globals.Configuration.SkillsSettings.HideoutManagement.SkillPointsPerAreaUpgrade + ); + } + + private void SetWallVisibleIfPrereqsMet(PmcData pmcData) + { + var medStation = pmcData.Hideout.Areas.FirstOrDefault((area) => area.Type == HideoutAreas.MEDSTATION); + var waterCollector = pmcData.Hideout.Areas.FirstOrDefault((area) => area.Type == HideoutAreas.WATER_COLLECTOR); + 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; + } + } + } + + private void AddContainerImprovementToProfile(ItemEventRouterResponse output, string sessionID, PmcData pmcData, BotHideoutArea profileParentHideoutArea, + HideoutArea dbHideoutArea, Stage hideoutStage) + { + // Add key/value to `hideoutAreaStashes` dictionary - used to link hideout area to inventory stash by its id + if (pmcData.Inventory.HideoutAreaStashes.GetValueOrDefault(dbHideoutArea.Type.ToString()) is null) + { + 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 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 + .GetHideout() + .Areas.FirstOrDefault(area => area.ParentArea == dbHideoutArea.Id); + if (childDbArea is not null) + { + // 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 = + pmcData.Hideout.Areas.FirstOrDefault((x) => x.Type == profileParentHideoutArea.Type).Level; + + // Add/upgrade stash item in player inventory + var childDbAreaStage = childDbArea.Stages[profileParentHideoutArea.Level.ToString()]; + AddUpdateInventoryItemToProfile(sessionID, pmcData, childDbArea, childDbAreaStage); + + // Inform client of the changes + AddContainerUpgradeToClientOutput(sessionID, childDbArea.Type, childDbArea, childDbAreaStage, output); + } + } + + private void AddMissingPresetStandItemsToProfile(string sessionId, Stage hideoutStage, PmcData pmcData, HideoutArea dbHideoutArea, ItemEventRouterResponse output) { throw new NotImplementedException(); } - public void UpgradeComplete(PmcData pmcData, HideoutUpgradeCompleteRequestData request, string sessionId, ItemEventRouterResponse output) + private void AddUpdateInventoryItemToProfile(string sessionId, PmcData pmcData, HideoutArea childDbArea, Stage childDbAreaStage) + { + throw new NotImplementedException(); + } + + private void AddContainerUpgradeToClientOutput(string sessionId, HideoutAreas? type, HideoutArea childDbArea, Stage childDbAreaStage, ItemEventRouterResponse output) { throw new NotImplementedException(); }