more progress (#45)

* ignore nulls in json

* Implement ProfileActivityService

* add temp beta release

* implement customizationController

* comment out logging

* implement gameStart
This commit is contained in:
CWX
2025-01-12 20:41:00 +00:00
committed by GitHub
parent 42ed7683c9
commit 5e7b4e3538
10 changed files with 167 additions and 78 deletions
+12
View File
@@ -55,6 +55,18 @@ public class ClientLogCallbacks
public string ReleaseNotes()
{
var data = _configServer.GetConfig<CoreConfig>(ConfigTypes.CORE).Release;
data.BetaDisclaimerText = "BetaDisclaimerText";
data.BetaDisclaimerAcceptText = "BetaDisclaimerAcceptText";
data.ServerModsLoadedText = "ServerModsLoadedText";
data.ClientModsLoadedText = "clientModsLoadedText";
data.ClientModsLoadedDebugText = "clientModsLoadedDebugText";
data.ClientModsLoadedDebugText = "clientModsLoadedDebugText";
data.IllegalPluginsExceptionText = "IllegalPluginsExceptionText";
data.ReleaseSummaryText = "ReleaseSummaryText";
data.IsBeta = false;
data.IsModdable = true;
data.IsModded = false;
// data.betaDisclaimerText = ProgramStatics.MODS
// ? this.localisationService.getText("release-beta-disclaimer-mods-enabled")
+49 -49
View File
@@ -57,10 +57,10 @@ public class CustomizationController
{
var pmcData = _profileHelper.GetPmcProfile(sessionId);
var clothing = _databaseService.GetCustomization();
var suits = _databaseService.GetTrader(traderId).Suits;
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();
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));
@@ -83,21 +83,21 @@ public class CustomizationController
{
var output = _eventOutputHolder.GetOutput(sessionId);
var traderOffer = GetTraderClothingOffer(sessionId, buyClothingRequest.Offer);
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;
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,
ItemId = suitDetails?.Id,
ItemName = suitDetails?.Name,
}));
}
@@ -111,7 +111,7 @@ public class CustomizationController
private Suit GetTraderClothingOffer(string sessionId, string? offerId)
{
var foundSuit = GetAllTraderSuits(sessionId).FirstOrDefault(s => s.Id == 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));
@@ -143,61 +143,61 @@ public class CustomizationController
/// <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);
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)
if (paymentItemDetails?.Del != null)
{
output.ProfileChanges[sessionId].Items.DeletedItems.Add(new Product
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
Id = inventoryItem?.Id,
Template = inventoryItem?.Template,
ParentId = inventoryItem?.ParentId,
SlotId = inventoryItem?.SlotId,
Location = (ItemLocation)inventoryItem?.Location,
Upd = inventoryItem?.Upd
});
pmcData.Inventory.Items.Remove(inventoryItem);
pmcData?.Inventory?.Items?.Remove(inventoryItem);
}
if (inventoryItem.Upd == null)
if (inventoryItem?.Upd == null)
inventoryItem.Upd = new() { StackObjectsCount = 1 };
if (inventoryItem.Upd.StackObjectsCount == null)
if (inventoryItem?.Upd?.StackObjectsCount == null)
inventoryItem.Upd.StackObjectsCount = 1;
if (inventoryItem.Upd.StackObjectsCount == paymentItemDetails.Count)
if (inventoryItem?.Upd?.StackObjectsCount == paymentItemDetails?.Count)
{
output.ProfileChanges[sessionId].Items.DeletedItems.Add(new Product
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
Id = inventoryItem?.Id,
Template = inventoryItem?.Template,
ParentId = inventoryItem?.ParentId,
SlotId = inventoryItem?.SlotId,
Location = (ItemLocation)inventoryItem?.Location,
Upd = inventoryItem?.Upd
});
pmcData.Inventory.Items.Remove(inventoryItem);
pmcData?.Inventory?.Items?.Remove(inventoryItem);
return;
}
if (inventoryItem.Upd.StackObjectsCount > paymentItemDetails.Count)
if (inventoryItem.Upd.StackObjectsCount > paymentItemDetails?.Count)
{
inventoryItem.Upd.StackObjectsCount -= paymentItemDetails.Count;
output.ProfileChanges[sessionId].Items.ChangedItems.Add(new Product
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
Id = inventoryItem?.Id,
Template = inventoryItem?.Template,
ParentId = inventoryItem?.ParentId,
SlotId = inventoryItem?.SlotId,
Location = (ItemLocation)inventoryItem?.Location,
Upd = inventoryItem?.Upd
});
}
}
@@ -291,7 +291,7 @@ public class CustomizationController
throw new Exception($"Unknown game edition given from profile {profile}");
}
var prestigeLevel = profile.CharacterData.PmcData.Info.PrestigeLevel;
var prestigeLevel = profile?.CharacterData?.PmcData?.Info?.PrestigeLevel;
if (prestigeLevel != null)
{
if (prestigeLevel >= 1)
@@ -324,10 +324,10 @@ public class CustomizationController
/// <returns></returns>
private string GetGameEdition(SptProfile profile)
{
var edition = profile.CharacterData.PmcData.Info.GameVersion;
var edition = profile?.CharacterData?.PmcData?.Info?.GameVersion;
if (edition == null)
{
var launcherEdition = profile.ProfileInfo.Edition;
var launcherEdition = profile?.ProfileInfo?.Edition;
switch (launcherEdition.ToLower())
{
case "edge of darkness":
@@ -351,18 +351,18 @@ public class CustomizationController
/// <returns></returns>
public ItemEventRouterResponse SetClothing(string sessionId, CustomizationSetRequest request, PmcData pmcData)
{
foreach (var customisation in request.Customizations)
foreach (var customisation in request?.Customizations)
{
switch (customisation.Id)
{
case "dogTag":
pmcData.Customization.DogTag = customisation.Id;
pmcData.Customization.DogTag = customisation?.Id;
break;
case "suite":
ApplyClothingItemToProfile(customisation, pmcData);
break;
default:
_logger.Error($"Unhandled customisation type: {customisation.Type}");
_logger.Error($"Unhandled customisation type: {customisation?.Type}");
break;
}
}
@@ -377,24 +377,24 @@ public class CustomizationController
/// <param name="pmcData">Profile to update</param>
private void ApplyClothingItemToProfile(CustomizationSetOption customisation, PmcData pmcData)
{
var dbSuit = _databaseService.GetCustomization()[customisation.Id];
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}");
_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;
pmcData.Customization.Body = dbSuit?.Properties?.Body;
pmcData.Customization.Hands = dbSuit?.Properties?.Hands;
return;
}
if (dbSuit.Parent == "5cd944ca1388ce03a44dc2a4")
{
pmcData.Customization.Feet = dbSuit.Properties.Feet;
pmcData.Customization.Feet = dbSuit?.Properties?.Feet;
}
}
}
+53 -18
View File
@@ -20,7 +20,9 @@ public class GameController
private readonly ILogger _logger;
private readonly ConfigServer _configServer;
private readonly DatabaseService _databaseService;
private readonly TimeUtil _timeUtil;
// private readonly PreSptModLoader _preSptModLoader;
private readonly HttpServerHelper _httpServerHelper;
private readonly InventoryHelper _inventoryHelper;
@@ -39,7 +41,7 @@ public class GameController
private readonly ProfileActivityService _profileActivityService;
private readonly ApplicationContext _applicationContext;
private readonly ICloner _cloner;
private readonly CoreConfig _coreConfig;
private readonly HttpConfig _httpConfig;
private readonly RagfairConfig _ragfairConfig;
@@ -68,7 +70,7 @@ public class GameController
ProfileActivityService profileActivityService,
ApplicationContext applicationContext,
ICloner cloner
)
)
{
_logger = logger;
_configServer = configServer;
@@ -98,7 +100,7 @@ public class GameController
_hideoutConfig = configServer.GetConfig<HideoutConfig>(ConfigTypes.HIDEOUT);
_botConfig = configServer.GetConfig<BotConfig>(ConfigTypes.BOT);
}
/// <summary>
/// Handle client/game/start
/// </summary>
@@ -110,9 +112,9 @@ public class GameController
{
// Store client start time in app context
_applicationContext.AddValue(ContextVariableType.CLIENT_START_TIMESTAMP, $"{sessionId}_{startTimeStampMs}");
_profileActivityService.SetActivityTimestamp(sessionId);
// repeatableQuests are stored by in profile.Quests due to the responses of the client (e.g. Quests in
// offraidData). Since we don't want to clutter the Quests list, we need to remove all completed (failed or
// successful) repeatable quests. We also have to remove the Counters from the repeatableQuests
@@ -124,7 +126,7 @@ public class GameController
if (fullProfile.SptData.Migrations == null)
fullProfile.SptData.Migrations = new();
if (fullProfile.FriendProfileIds == null)
fullProfile.FriendProfileIds = new();
@@ -132,12 +134,12 @@ public class GameController
{
_inventoryHelper.ValidateInventoryUsesMongoIds(fullProfile.CharacterData.PmcData.Inventory.Items);
Migrate39xProfile(fullProfile);
// flag as migrated
fullProfile.SptData.Migrations.Add("39x", _timeUtil.GetTimeStamp());
_logger.Success($"Migration of 3.9.x profile: {fullProfile.ProfileInfo.Username} completed successfully");
}
// with our method of converting type from array for this prop, we *might* not need this?
// if (Array.isArray(fullProfile.characters.pmc.WishList)) {
// fullProfile.characters.pmc.WishList = {};
@@ -146,17 +148,17 @@ public class GameController
// if (Array.isArray(fullProfile.characters.scav.WishList)) {
// fullProfile.characters.scav.WishList = {};
// }
if (fullProfile.DialogueRecords != null)
_profileFixerService.CheckForAndFixDialogueAttachments(fullProfile);
_logger.Debug($"Started game with session {sessionId} {fullProfile.ProfileInfo.Username}");
var pmcProfile = fullProfile.CharacterData.PmcData;
if (_coreConfig.Fixes.FixProfileBreakingInventoryItemIssues)
_profileFixerService.FixProfileBreakingInventoryItemIssues(pmcProfile);
if (pmcProfile.Health != null)
UpdateProfileHealthValues(pmcProfile);
@@ -165,7 +167,7 @@ public class GameController
SendPraporGiftsToNewProfiles(pmcProfile);
_profileFixerService.CheckForOrphanedModdedItems(sessionId, fullProfile);
}
_profileFixerService.CheckForAndRemoveInvalidTraders(fullProfile);
_profileFixerService.CheckForAndFixPmcProfileIssues(pmcProfile);
@@ -175,7 +177,7 @@ public class GameController
_hideoutHelper.SetHideoutImprovementsToCompleted(pmcProfile);
_hideoutHelper.UnlockHideoutWallInProfile(pmcProfile);
}
LogProfileDetails(fullProfile);
SaveActiveModsToProfile(fullProfile);
@@ -184,10 +186,10 @@ public class GameController
AddPlayerToPmcNames(pmcProfile);
CheckForAndRemoveUndefinedDialogues(fullProfile);
}
if (pmcProfile.Skills.Common != null)
WarnOnActiveBotReloadSkill(pmcProfile);
_seasonalEventService.GivePlayerSeasonalGifts(sessionId);
}
}
@@ -214,7 +216,41 @@ public class GameController
/// <returns></returns>
public GameConfigResponse GetGameConfig(string sessionId)
{
throw new NotImplementedException();
var profile = _profileHelper.GetPmcProfile(sessionId);
var gameTime = profile?.Stats?.Eft?.OverallCounters?.Items.FirstOrDefault(c =>
c.Key.Contains("LifeTime") &&
c.Key.Contains("Pmc")).Value ?? 0D;
var config = new GameConfigResponse
{
Languages = _databaseService.GetLocales().Languages,
IsNdaFree = false,
IsReportAvailable = false,
IsTwitchEventMember = false,
Language = "en",
Aid = profile.Aid,
Taxonomy = 6,
ActiveProfileId = sessionId,
Backend = new()
{
Lobby = _httpServerHelper.GetBackendUrl(),
Trading = _httpServerHelper.GetBackendUrl(),
Messaging = _httpServerHelper.GetBackendUrl(),
Main = _httpServerHelper.GetBackendUrl(),
RagFair = _httpServerHelper.GetBackendUrl()
},
UseProtobuf = false,
UtcTime = _timeUtil.GetTimeStamp(),
TotalInGame = gameTime,
SessionMode = "pve",
PurchasedGames = new()
{
IsEftPurchased = true,
IsArenaPurchased = false
}
};
return config;
}
/// <summary>
@@ -257,7 +293,6 @@ public class GameController
/// </summary>
/// <param name="sessionId"></param>
/// <returns></returns>
public CurrentGroupResponse GetCurrentGroup(string sessionId)
{
return new CurrentGroupResponse
@@ -265,7 +300,7 @@ public class GameController
Squad = []
};
}
/// <summary>
/// Handle client/checkVersion
+12 -1
View File
@@ -1,12 +1,23 @@
using Core.Annotations;
using Core.Models.Eft.Common;
using Core.Models.Eft.Common.Tables;
using Core.Services;
namespace Core.Controllers;
[Injectable]
public class PrestigeController
{
private DatabaseService _databaseService;
public PrestigeController
(
DatabaseService databaseService
)
{
_databaseService = databaseService;
}
/// <summary>
/// Handle /client/prestige/list
/// </summary>
@@ -17,7 +28,7 @@ public class PrestigeController
string sessionId,
EmptyRequestData info)
{
throw new NotImplementedException();
return _databaseService.GetTemplates().Prestige;
}
/// <summary>
+2 -1
View File
@@ -35,7 +35,8 @@ public class TraderController
/// <returns>Return a list of all traders</returns>
public List<TraderBase> GetAllTraders(string sessionId)
{
throw new NotImplementedException();
var traders = new List<TraderBase>();
}
/// <summary>
+3 -3
View File
@@ -5,7 +5,7 @@ namespace Core.Models.Eft.Game;
public class GameConfigResponse
{
[JsonPropertyName("aid")]
public int? Aid { get; set; }
public double? Aid { get; set; }
[JsonPropertyName("lang")]
public string? Language { get; set; }
@@ -33,7 +33,7 @@ public class GameConfigResponse
/** Total in game time */
[JsonPropertyName("totalInGame")]
public int? TotalInGame { get; set; }
public double? TotalInGame { get; set; }
[JsonPropertyName("reportAvailable")]
public bool? IsReportAvailable { get; set; }
@@ -73,4 +73,4 @@ public class Backend
[JsonPropertyName("RagFair")]
public string? RagFair { get; set; }
}
}
+2 -2
View File
@@ -120,7 +120,7 @@ public class SptHttpListener : IHttpListener
if (IsDebugRequest(req)) {
// Send only raw response without transformation
SendJson(resp, output, sessionID);
Console.WriteLine($"Response: {output}");
// Console.WriteLine($"Response: {output}");
// TODO: this.logRequest(req, output);
return;
}
@@ -133,7 +133,7 @@ public class SptHttpListener : IHttpListener
// No serializer can handle the request (majority of requests dont), zlib the output and send response back
SendZlibJson(resp, output, sessionID);
}
Console.WriteLine($"Response: {output}");
// Console.WriteLine($"Response: {output}");
// TODO: this.LogRequest(req, output);
}
+1 -1
View File
@@ -7,7 +7,7 @@ public class PostDbLoadService
{
public void PerformPostDbLoadActions()
{
throw new NotImplementedException();
// throw new NotImplementedException();
}
protected void AdjustMinReserveRaiderSpawnChance()
+32 -3
View File
@@ -1,10 +1,19 @@
using Core.Annotations;
using Core.Utils;
namespace Core.Services;
[Injectable(InjectionType.Singleton)]
public class ProfileActivityService
{
private TimeUtil _timeUtil;
private Dictionary<string, long> profileActivityTimestamps = new();
public ProfileActivityService(TimeUtil timeUtil)
{
_timeUtil = timeUtil;
}
/**
* Was the requested profile active in the last requested minutes
* @param sessionId Profile to check
@@ -13,7 +22,13 @@ public class ProfileActivityService
*/
public bool ActiveWithinLastMinutes(string sessionId, int minutes)
{
throw new NotImplementedException();
var currentTimestamp = _timeUtil.GetTimeStamp();
var storedActivityTimestamp = profileActivityTimestamps[sessionId];
if (storedActivityTimestamp != null)
return false;
return currentTimestamp - storedActivityTimestamp < minutes * 60;
}
/**
@@ -23,7 +38,21 @@ public class ProfileActivityService
*/
public List<string> GetActiveProfileIdsWithinMinutes(int minutes)
{
throw new NotImplementedException();
var currentTimestamp = _timeUtil.GetTimeStamp();
var result = new List<string>();
foreach (var activity in profileActivityTimestamps ?? new())
{
var lastActivityTimestamp = activity.Value;
if (lastActivityTimestamp == null)
continue;
// Profile was active in last x minutes, add to return list
if (currentTimestamp - lastActivityTimestamp < minutes * 60)
result.Add(activity.Key);
}
return result;
}
/**
@@ -32,6 +61,6 @@ public class ProfileActivityService
*/
public void SetActivityTimestamp(string sessionId)
{
throw new NotImplementedException();
profileActivityTimestamps[sessionId] = _timeUtil.GetTimeStamp();
}
}
+1
View File
@@ -13,6 +13,7 @@ public class JsonUtil
private static readonly JsonSerializerOptions jsonSerializerOptionsNoIndent = new()
{
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
Converters =
{