Files
SPT-Server-Build/Core/Controllers/CustomizationController.cs
T
2025-01-12 18:41:33 +00:00

401 lines
14 KiB
C#

using Core.Annotations;
using Core.Helpers;
using Core.Models.Eft.Common;
using Core.Models.Eft.Common.Tables;
using Core.Models.Eft.Customization;
using Core.Models.Eft.Hideout;
using Core.Models.Eft.ItemEvent;
using Core.Models.Eft.Profile;
using Core.Models.Enums;
using Core.Routers;
using Core.Servers;
using Core.Services;
using Core.Utils.Cloners;
using ILogger = Core.Models.Utils.ILogger;
using Product = Core.Models.Eft.ItemEvent.Product;
namespace Core.Controllers;
[Injectable]
public class CustomizationController
{
protected ILogger _logger;
protected EventOutputHolder _eventOutputHolder;
protected DatabaseService _databaseService;
protected SaveServer _saveServer;
protected LocalisationService _localisationService;
protected ProfileHelper _profileHelper;
protected ICloner _cloner;
public CustomizationController
(
ILogger logger,
EventOutputHolder eventOutputHolder,
DatabaseService databaseService,
SaveServer saveServer,
LocalisationService localisationService,
ProfileHelper profileHelper,
ICloner cloner
)
{
_logger = logger;
_eventOutputHolder = eventOutputHolder;
_databaseService = databaseService;
_saveServer = saveServer;
_localisationService = localisationService;
_profileHelper = profileHelper;
_cloner = cloner;
}
/// <summary>
/// Get purchasable clothing items from trader that match players side (usec/bear)
/// </summary>
/// <param name="traderId">trader to look up clothing for</param>
/// <param name="sessionId">Session id</param>
/// <returns>Suit array</returns>
public List<Suit> GetTraderSuits(string traderId, string sessionId)
{
var pmcData = _profileHelper.GetPmcProfile(sessionId);
var clothing = _databaseService.GetCustomization();
var suits = _databaseService.GetTrader(traderId).Suits;
var matchingSuits = suits.Where(s => clothing.ContainsKey(s.SuiteId)).ToList();
matchingSuits = matchingSuits?.Where(s => clothing[s.SuiteId].Properties.Side.Contains(pmcData.Info.Side)).ToList();
if (matchingSuits == null)
throw new Exception(_localisationService.GetText("customisation-unable_to_get_trader_suits", traderId));
return matchingSuits;
}
/// <summary>
/// Handle CustomizationBuy event
/// Purchase/unlock a clothing item from a trader
/// </summary>
/// <param name="pmcData">Player profile</param>
/// <param name="buyClothingRequest">Request object</param>
/// <param name="sessionId">Session id</param>
/// <returns>ItemEventRouterResponse</returns>
public ItemEventRouterResponse BuyClothing(
PmcData pmcData,
BuyClothingRequestData buyClothingRequest,
string sessionId)
{
var output = _eventOutputHolder.GetOutput(sessionId);
var traderOffer = GetTraderClothingOffer(sessionId, buyClothingRequest.Offer);
if (traderOffer == null)
{
_logger.Error(_localisationService.GetText("customisation-unable_to_find_suit_by_id", buyClothingRequest.Offer));
return output;
}
var suitId = traderOffer.SuiteId;
if (OutfitAlreadyPurchased(suitId, sessionId))
{
var suitDetails = _databaseService.GetCustomization()[suitId];
_logger.Error(_localisationService.GetText("customisation-item_already_purchased", new
{
ItemId = suitDetails.Id,
ItemName = suitDetails.Name,
}));
}
return output;
}
private bool OutfitAlreadyPurchased(object suitId, string sessionId)
{
return _saveServer.GetProfile(sessionId).Suits.Contains(suitId);
}
private Suit GetTraderClothingOffer(string sessionId, string? offerId)
{
var foundSuit = GetAllTraderSuits(sessionId).FirstOrDefault(s => s.Id == offerId);
if (foundSuit == null)
throw new Exception(_localisationService.GetText("customisation-unable_to_find_suit_with_id", offerId));
return foundSuit;
}
/// <summary>
/// Update output object and player profile with purchase details
/// </summary>
/// <param name="sessionId">Session id</param>
/// <param name="pmcData">Player profile</param>
/// <param name="itemsToPayForClothingWith">Clothing purchased</param>
/// <param name="output">Client response</param>
private void PayForClothingItems(string sessionId, PmcData pmcData, List<PaymentItemForClothing> itemsToPayForClothingWith,
ItemEventRouterResponse output)
{
foreach (var inventoryItemToProcess in itemsToPayForClothingWith)
{
PayForClothingItem(sessionId, pmcData, inventoryItemToProcess, output);
}
}
/// <summary>
/// Update output object and player profile with purchase details for single piece of clothing
/// </summary>
/// <param name="sessionId">Session id</param>
/// <param name="pmcData">Player profile</param>
/// <param name="paymentItemDetails">Payment details</param>
/// <param name="output">Client response</param>
private void PayForClothingItem(string sessionId, PmcData pmcData, PaymentItemForClothing paymentItemDetails, ItemEventRouterResponse output)
{
var inventoryItem = pmcData.Inventory.Items.FirstOrDefault(x => x.Id == paymentItemDetails.Id);
if (inventoryItem == null)
{
_logger.Error(_localisationService.GetText("customisation-unable_to_find_clothing_item_in_inventory", paymentItemDetails.Id));
return;
}
if (paymentItemDetails.Del != null)
{
output.ProfileChanges[sessionId].Items.DeletedItems.Add(new Product
{
Id = inventoryItem.Id,
Template = inventoryItem.Template,
ParentId = inventoryItem.ParentId,
SlotId = inventoryItem.SlotId,
Location = (ItemLocation)inventoryItem.Location,
Upd = inventoryItem.Upd
});
pmcData.Inventory.Items.Remove(inventoryItem);
}
if (inventoryItem.Upd == null)
inventoryItem.Upd = new() { StackObjectsCount = 1 };
if (inventoryItem.Upd.StackObjectsCount == null)
inventoryItem.Upd.StackObjectsCount = 1;
if (inventoryItem.Upd.StackObjectsCount == paymentItemDetails.Count)
{
output.ProfileChanges[sessionId].Items.DeletedItems.Add(new Product
{
Id = inventoryItem.Id,
Template = inventoryItem.Template,
ParentId = inventoryItem.ParentId,
SlotId = inventoryItem.SlotId,
Location = (ItemLocation)inventoryItem.Location,
Upd = inventoryItem.Upd
});
pmcData.Inventory.Items.Remove(inventoryItem);
return;
}
if (inventoryItem.Upd.StackObjectsCount > paymentItemDetails.Count)
{
inventoryItem.Upd.StackObjectsCount -= paymentItemDetails.Count;
output.ProfileChanges[sessionId].Items.ChangedItems.Add(new Product
{
Id = inventoryItem.Id,
Template = inventoryItem.Template,
ParentId = inventoryItem.ParentId,
SlotId = inventoryItem.SlotId,
Location = (ItemLocation)inventoryItem.Location,
Upd = inventoryItem.Upd
});
}
}
/// <summary>
///
/// </summary>
/// <param name="sessionId"></param>
/// <returns></returns>
private List<Suit> GetAllTraderSuits(string sessionId)
{
var traders = _databaseService.GetTraders();
var result = new List<Suit>();
foreach (var trader in traders)
{
if (trader.Value.Base.CustomizationSeller.Value)
result.AddRange(GetTraderSuits(trader.Key, sessionId));
}
return result;
}
/// <summary>
/// Handle client/hideout/customization/offer/list
/// </summary>
/// <param name="sessionId"></param>
/// <param name="info"></param>
/// <returns></returns>
public HideoutCustomisation GetHideoutCustomisation(string sessionId, EmptyRequestData info)
{
return _databaseService.GetHideout().Customisation;
}
/// <summary>
/// Handle client/customization/storage
/// </summary>
/// <param name="sessionId"></param>
/// <param name="info"></param>
/// <returns></returns>
public List<CustomisationStorage> GetCustomisationStorage(
string sessionId,
EmptyRequestData info)
{
var customisationResultsClone = _cloner.Clone(_databaseService.GetTemplates().CustomisationStorage);
var profile = _profileHelper.GetFullProfile(sessionId);
switch (GetGameEdition(profile))
{
case GameEditions.EDGE_OF_DARKNESS:
customisationResultsClone.Add(new ()
{
Id = "6746fd09bafff85008048838",
Source = "default",
Type = "dogTag"
});
customisationResultsClone.Add(new ()
{
Id = "67471938bafff850080488b7",
Source = "default",
Type = "dogTag"
});
break;
case GameEditions.UNHEARD:
customisationResultsClone.Add(new ()
{
Id = "6746fd09bafff85008048838",
Source = "default",
Type = "dogTag"
});
customisationResultsClone.Add(new ()
{
Id = "67471938bafff850080488b7",
Source = "default",
Type = "dogTag"
});
customisationResultsClone.Add(new ()
{
Id = "67471928d17d6431550563b5",
Source = "default",
Type = "dogTag"
});
customisationResultsClone.Add(new ()
{
Id = "6747193f170146228c0d2226",
Source = "default",
Type = "dogTag"
});
break;
default:
throw new Exception($"Unknown game edition given from profile {profile}");
}
var prestigeLevel = profile.CharacterData.PmcData.Info.PrestigeLevel;
if (prestigeLevel != null)
{
if (prestigeLevel >= 1)
{
customisationResultsClone.Add(new ()
{
Id = "674dbf593bee1152d407f005",
Source = "default",
Type = "dogTag"
});
}
if (prestigeLevel >= 2)
{
customisationResultsClone.Add(new ()
{
Id = "675dcfea7ae1a8792107ca99",
Source = "default",
Type = "dogTag"
});
}
}
return customisationResultsClone;
}
/// <summary>
///
/// </summary>
/// <param name="profile"></param>
/// <returns></returns>
private string GetGameEdition(SptProfile profile)
{
var edition = profile.CharacterData.PmcData.Info.GameVersion;
if (edition == null)
{
var launcherEdition = profile.ProfileInfo.Edition;
switch (launcherEdition.ToLower())
{
case "edge of darkness":
return GameEditions.EDGE_OF_DARKNESS;
case "unheard":
return GameEditions.UNHEARD;
default:
return GameEditions.STANDARD;
}
}
return edition;
}
/// <summary>
/// Handle CustomizationSet event
/// </summary>
/// <param name="sessionId"></param>
/// <param name="request"></param>
/// <param name="pmcData"></param>
/// <returns></returns>
public ItemEventRouterResponse SetClothing(string sessionId, CustomizationSetRequest request, PmcData pmcData)
{
foreach (var customisation in request.Customizations)
{
switch (customisation.Id)
{
case "dogTag":
pmcData.Customization.DogTag = customisation.Id;
break;
case "suite":
ApplyClothingItemToProfile(customisation, pmcData);
break;
default:
_logger.Error($"Unhandled customisation type: {customisation.Type}");
break;
}
}
return _eventOutputHolder.GetOutput(sessionId);
}
/// <summary>
/// Applies a purchased suit to the players doll
/// </summary>
/// <param name="customization">Suit to apply to profile</param>
/// <param name="pmcData">Profile to update</param>
private void ApplyClothingItemToProfile(CustomizationSetOption customisation, PmcData pmcData)
{
var dbSuit = _databaseService.GetCustomization()[customisation.Id];
if (dbSuit == null)
{
_logger.Error($"Unable to find suit customisation id: {customisation.Id}, cannot apply clothing to player profile: {pmcData.Id}");
return;
}
if (dbSuit.Parent == "5cd944d01388ce000a659df9")
{
pmcData.Customization.Body = dbSuit.Properties.Body;
pmcData.Customization.Hands = dbSuit.Properties.Hands;
return;
}
if (dbSuit.Parent == "5cd944ca1388ce03a44dc2a4")
{
pmcData.Customization.Feet = dbSuit.Properties.Feet;
}
}
}