Add AdjustSkillExpForLowLevels to AddSkillPointsToPlayer (#738)
* Add AdjustSkillExpForLowLevels to AddSkillPointsToPlayer * remove unused AdjustSkillExpForLowLevels * format unit tests * fix suggestions * Revert "remove unused AdjustSkillExpForLowLevels" This reverts commit 43e0ab654378ca7ba1140648b1624730d637073b. * mark as obsolete * fix log message --------- Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
This commit is contained in:
@@ -494,30 +494,103 @@ public class ProfileHelper(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// already max level, no need to do any further calculations
|
||||||
|
if (profileSkill.Progress >= 5100)
|
||||||
|
{
|
||||||
|
if (logger.IsLogEnabled(LogLevel.Debug))
|
||||||
|
{
|
||||||
|
logger.Debug($"Player already has max level in skill: {skill}, not adding points");
|
||||||
|
}
|
||||||
|
|
||||||
|
profileSkill.LastAccess = timeUtil.GetTimeStamp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (useSkillProgressRateMultiplier)
|
if (useSkillProgressRateMultiplier)
|
||||||
{
|
{
|
||||||
var skillProgressRate = databaseService.GetGlobals().Configuration.SkillsSettings.SkillProgressRate;
|
var skillProgressRate = databaseService.GetGlobals().Configuration.SkillsSettings.SkillProgressRate;
|
||||||
pointsToAddToSkill *= skillProgressRate;
|
pointsToAddToSkill *= skillProgressRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InventoryConfig.SkillGainMultipliers.TryGetValue(skill.ToString(), out _))
|
if (InventoryConfig.SkillGainMultipliers.TryGetValue(skill.ToString(), out var multiplier))
|
||||||
{
|
{
|
||||||
pointsToAddToSkill *= InventoryConfig.SkillGainMultipliers[skill.ToString()];
|
pointsToAddToSkill *= multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
profileSkill.Progress += pointsToAddToSkill;
|
var adjustedSkillProgress = AdjustSkillExpForLowLevels(profileSkill.Progress, pointsToAddToSkill);
|
||||||
|
profileSkill.Progress += adjustedSkillProgress;
|
||||||
profileSkill.Progress = Math.Min(profileSkill.Progress, 5100); // Prevent skill from ever going above level 51 (5100)
|
profileSkill.Progress = Math.Min(profileSkill.Progress, 5100); // Prevent skill from ever going above level 51 (5100)
|
||||||
|
|
||||||
profileSkill.PointsEarnedDuringSession += pointsToAddToSkill;
|
profileSkill.PointsEarnedDuringSession += adjustedSkillProgress;
|
||||||
|
|
||||||
if (logger.IsLogEnabled(LogLevel.Debug))
|
if (logger.IsLogEnabled(LogLevel.Debug))
|
||||||
{
|
{
|
||||||
logger.Debug($"Added: {pointsToAddToSkill} points to skill: {skill}, new progress value is: {profileSkill.Progress}");
|
logger.Debug($"Added: {adjustedSkillProgress} points to skill: {skill}, new progress value is: {profileSkill.Progress}");
|
||||||
}
|
}
|
||||||
|
|
||||||
profileSkill.LastAccess = timeUtil.GetTimeStamp();
|
profileSkill.LastAccess = timeUtil.GetTimeStamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method calculates the adjusted skill progression for lower levels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentProgress">Current internal progress value of the skill, used to determine current level</param>
|
||||||
|
/// <param name="visualProgressAmount">The amount of visual progress to add</param>
|
||||||
|
/// <returns>Scaled skill progress according to level</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// It expects to be passed on a value as expected per the visual progress on the UI.
|
||||||
|
/// It will return scaled internal progress according to the current skill level, to match Tarkovs skill progression curve.
|
||||||
|
/// So passing on "0.4" will always yield +0.4 progress on the UI for the player.
|
||||||
|
/// </remarks>
|
||||||
|
public double AdjustSkillExpForLowLevels(double currentProgress, double visualProgressAmount)
|
||||||
|
{
|
||||||
|
var level = Math.Floor(currentProgress / 100d);
|
||||||
|
|
||||||
|
if (level >= 9)
|
||||||
|
{
|
||||||
|
return visualProgressAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
double internalAdded = 0;
|
||||||
|
|
||||||
|
// See "CalculateExpOnFirstLevels" in client for original logic
|
||||||
|
// loop until all visual progress has been used up
|
||||||
|
while (visualProgressAmount > 0)
|
||||||
|
{
|
||||||
|
// scale to apply for levels 1-10, decreasing as level goes higher
|
||||||
|
var uiMax = 10d * (level + 1d);
|
||||||
|
var factor = 100d / uiMax;
|
||||||
|
|
||||||
|
// remaining internal points in this level
|
||||||
|
var inLevel = currentProgress % 100d;
|
||||||
|
var internalRemaining = 100d - inLevel;
|
||||||
|
|
||||||
|
if (logger.IsLogEnabled(LogLevel.Debug))
|
||||||
|
{
|
||||||
|
logger.Debug($"currentLevelRemainingProgress: {internalRemaining}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// visual needed to fill the rest of this internal level
|
||||||
|
var visualToLevelUp = internalRemaining / factor;
|
||||||
|
|
||||||
|
var spendVisual = Math.Min(visualProgressAmount, visualToLevelUp);
|
||||||
|
var addInternal = spendVisual * factor;
|
||||||
|
|
||||||
|
if (logger.IsLogEnabled(LogLevel.Debug))
|
||||||
|
{
|
||||||
|
logger.Debug($"Progress To Add Adjusted For Level: {addInternal}");
|
||||||
|
}
|
||||||
|
|
||||||
|
internalAdded += addInternal;
|
||||||
|
currentProgress += addInternal;
|
||||||
|
visualProgressAmount -= spendVisual;
|
||||||
|
|
||||||
|
level = Math.Floor(currentProgress / 100d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalAdded;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the provided session id for a developer account
|
/// Is the provided session id for a developer account
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ public class QuestHelper(
|
|||||||
/// <param name="profileSkill">the skill experience is being added to</param>
|
/// <param name="profileSkill">the skill experience is being added to</param>
|
||||||
/// <param name="progressAmount">the amount of experience being added to the skill</param>
|
/// <param name="progressAmount">the amount of experience being added to the skill</param>
|
||||||
/// <returns>the adjusted skill progress gain</returns>
|
/// <returns>the adjusted skill progress gain</returns>
|
||||||
|
[Obsolete("Will be removed in 4.1: Use ProfileHelper.AdjustSkillExpForLowLevels instead.")]
|
||||||
public int AdjustSkillExpForLowLevels(CommonSkill profileSkill, int progressAmount)
|
public int AdjustSkillExpForLowLevels(CommonSkill profileSkill, int progressAmount)
|
||||||
{
|
{
|
||||||
// TODO: what used this? can't find any uses in node
|
// TODO: what used this? can't find any uses in node
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using SPTarkov.Server.Core.Helpers;
|
||||||
|
using SPTarkov.Server.Core.Servers;
|
||||||
|
using SPTarkov.Server.Core.Services;
|
||||||
|
using SPTarkov.Server.Core.Utils;
|
||||||
|
using UnitTests.Mock;
|
||||||
|
|
||||||
|
namespace UnitTests.Tests.Services;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class ProfileHelperTests
|
||||||
|
{
|
||||||
|
private ProfileHelper _sut;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_sut = new ProfileHelper(
|
||||||
|
new MockLogger<ProfileHelper>(),
|
||||||
|
new SPTarkov.Server.Core.Utils.Cloners.FastCloner(),
|
||||||
|
DI.GetInstance().GetService<SaveServer>(),
|
||||||
|
DI.GetInstance().GetService<DatabaseService>(),
|
||||||
|
DI.GetInstance().GetService<Watermark>(),
|
||||||
|
DI.GetInstance().GetService<TimeUtil>(),
|
||||||
|
DI.GetInstance().GetService<ServerLocalisationService>(),
|
||||||
|
DI.GetInstance().GetService<ConfigServer>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCaseSource(nameof(GetAdjustSkillExpForLowLevelsTestData))]
|
||||||
|
public void AdjustSkillExpForLowLevels(double startingProgress, double addedProgress, double expectedAdjustedProgress)
|
||||||
|
{
|
||||||
|
var result = _sut.AdjustSkillExpForLowLevels(startingProgress, addedProgress);
|
||||||
|
Assert.AreEqual(expectedAdjustedProgress, result, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<double[]> GetAdjustSkillExpForLowLevelsTestData()
|
||||||
|
{
|
||||||
|
// tests for levels 1-10 with +1.0 progress added
|
||||||
|
yield return [0000, 01.0, 10.000]; // 1, 10.0 XP on UI, +1 => 1.0/ 10.0 = 10.000/100 internal
|
||||||
|
yield return [0100, 01.0, 05.000]; // 2, 20.0 XP on UI, +1 => 1.0/ 20.0 = 5.000/100 internal
|
||||||
|
yield return [0200, 01.0, 03.333]; // 3, 30.0 XP on UI, +1 => 1.0/ 30.0 = 3.333/100 internal
|
||||||
|
yield return [0300, 01.0, 02.500]; // 4, 40.0 XP on UI, +1 => 1.0/ 40.0 = 2.500/100 internal
|
||||||
|
yield return [0400, 01.0, 02.000]; // 5, 50.0 XP on UI, +1 => 1.0/ 50.0 = 2.000/100 internal
|
||||||
|
yield return [0500, 01.0, 01.667]; // 6, 60.0 XP on UI, +1 => 1.0/ 60.0 = 1.667/100 internal
|
||||||
|
yield return [0600, 01.0, 01.428]; // 7, 70.0 XP on UI, +1 => 1.0/ 70.0 = 1.428/100 internal
|
||||||
|
yield return [0700, 01.0, 01.250]; // 8, 80.0 XP on UI, +1 => 1.0/ 80.0 = 1.250/100 internal
|
||||||
|
yield return [0800, 01.0, 01.111]; // 9, 90.0 XP on UI, +1 => 1.0/ 90.0 = 1.111/100 internal
|
||||||
|
yield return [0900, 01.0, 01.000]; // 10, 100.0 XP on UI, +1 => 1.0/100.0 = 1.000/100 internal => no scaling
|
||||||
|
yield return [1000, 01.0, 01.000]; // 11, 100.0 XP on UI, +1 => 1.0/100.0 = 1.000/100 internal => no scaling
|
||||||
|
// level boundary tests for partial progress with +4.0 progress added
|
||||||
|
yield return [0098, 04.0, 21.000]; // 1-> 2, 98 = 9.8/ 10, +4.0 = 9.8-> 10 (+2, -0.2), remaining +3.8 (3.8/ 20) = 19.000/100 => 21.000 total
|
||||||
|
yield return [0198, 04.0, 14.000]; // 2-> 3, 198 = 19.6/ 20, +4.0 = 19.6-> 20 (+2, -0.4), remaining +3.6 (3.6/ 30) = 12.000/100 => 14.000 total
|
||||||
|
yield return [0298, 04.0, 10.500]; // 3-> 4, 298 = 29.4/ 30, +4.0 = 29.4-> 30 (+2, -0.6), remaining +3.4 (3.4/ 40) = 8.500/100 => 10.500 total
|
||||||
|
yield return [0398, 04.0, 08.400]; // 4-> 5, 398 = 39.2/ 40, +4.0 = 39.2-> 40 (+2, -0.8), remaining +3.2 (3.2/ 50) = 6.400/100 => 8.400 total
|
||||||
|
yield return [0498, 04.0, 07.000]; // 5-> 6, 498 = 49.0/ 50, +4.0 = 49.0-> 50 (+2, -1.0), remaining +3.0 (3.0/ 60) = 5.000/100 => 7.000 total
|
||||||
|
yield return [0598, 04.0, 06.000]; // 6-> 7, 598 = 58.8/ 60, +4.0 = 58.8-> 60 (+2, -1.2), remaining +2.8 (2.8/ 70) = 4.000/100 => 6.000 total
|
||||||
|
yield return [0698, 04.0, 05.250]; // 7-> 8, 698 = 68.6/ 70, +4.0 = 68.6-> 70 (+2, -1.4), remaining +2.6 (2.6/ 80) = 3.250/100 => 5.250 total
|
||||||
|
yield return [0798, 04.0, 04.667]; // 8-> 9, 798 = 78.4/ 80, +4.0 = 78.4-> 80 (+2, -1.6), remaining +2.4 (2.4/ 90) = 2.667/100 => 4.667 total
|
||||||
|
yield return [0898, 04.0, 04.200]; // 9->10, 898 = 88.2/ 90, +4.0 = 88.2-> 90 (+2, -1.8), remaining +2.2 (2.2/100) = 2.200/100 => 4.200 total
|
||||||
|
yield return [0998, 04.0, 04.000]; // 10->11, 998 = 98.0/100, +4.0 = 98.0->100 (+2, -2.0), remaining +2.0 (2.0/100) = 2.000/100 => 4.000 total
|
||||||
|
yield return [1098, 04.0, 04.000]; // 11->12, 1098 = 98.0/100, +4.0 = 98.0->100 (+2, -2.0), remaining +2.0 (2.0/100) = 2.000/100 => 4.000 total
|
||||||
|
// test multi level boundary jumps
|
||||||
|
yield return [050, 30.0, 166.667]; // 1-> 3, 50 = 5.0/ 10, +3.0 = 5.0-> 10 (+50, -5.0), remaining +25: 0.0->20 (+100, -20), remaining +5 (5.0/30) = 16.667/100 => 166.667 total
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user