feat: implement character stat mapping to created char
All checks were successful
Build, Package and Push Images / preprocess (push) Successful in 1s
Build, Package and Push Images / build (push) Successful in 25s
Build, Package and Push Images / sonarqube (push) Has been skipped
Build, Package and Push Images / sbom-scan (push) Successful in 33s
Build, Package and Push Images / container-build (push) Successful in 1m19s
Build, Package and Push Images / container-sbom-scan (push) Successful in 31s
All checks were successful
Build, Package and Push Images / preprocess (push) Successful in 1s
Build, Package and Push Images / build (push) Successful in 25s
Build, Package and Push Images / sonarqube (push) Has been skipped
Build, Package and Push Images / sbom-scan (push) Successful in 33s
Build, Package and Push Images / container-build (push) Successful in 1m19s
Build, Package and Push Images / container-sbom-scan (push) Successful in 31s
This commit is contained in:
parent
55276354db
commit
1f4f3cff51
11 changed files with 185 additions and 34 deletions
|
@ -14,11 +14,14 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
{
|
{
|
||||||
private readonly WonderkingContext _wonderkingContext;
|
private readonly WonderkingContext _wonderkingContext;
|
||||||
private readonly ItemObjectPoolService _itemObjectPoolService;
|
private readonly ItemObjectPoolService _itemObjectPoolService;
|
||||||
|
private readonly CharacterStatsMappingConfiguration _characterStatsMapping;
|
||||||
|
|
||||||
public CharacterCreationHandler(WonderkingContext wonderkingContext, ItemObjectPoolService itemObjectPoolService)
|
public CharacterCreationHandler(WonderkingContext wonderkingContext, ItemObjectPoolService itemObjectPoolService,
|
||||||
|
CharacterStatsMappingConfiguration characterStatsMappingConfiguration)
|
||||||
{
|
{
|
||||||
_wonderkingContext = wonderkingContext;
|
_wonderkingContext = wonderkingContext;
|
||||||
_itemObjectPoolService = itemObjectPoolService;
|
_itemObjectPoolService = itemObjectPoolService;
|
||||||
|
_characterStatsMapping = characterStatsMappingConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(CharacterCreationPacket packet, TcpSession session)
|
public async Task HandleAsync(CharacterCreationPacket packet, TcpSession session)
|
||||||
|
@ -26,14 +29,38 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
var authSession = session as AuthSession;
|
var authSession = session as AuthSession;
|
||||||
var account =
|
var account =
|
||||||
_wonderkingContext.Accounts.FirstOrDefault(a => authSession != null && a.Id == authSession.AccountId);
|
_wonderkingContext.Accounts.FirstOrDefault(a => authSession != null && a.Id == authSession.AccountId);
|
||||||
var items = new List<InventoryItem>
|
var mappedDefaultItems = _characterStatsMapping.DefaultCharacterMapping.Items
|
||||||
|
.Select(i => _itemObjectPoolService.GetBaseInventoryItem(i.Id, i.Quantity)).ToArray();
|
||||||
|
|
||||||
|
var firstJobConfig = packet.FirstJob switch
|
||||||
{
|
{
|
||||||
_itemObjectPoolService.GetBaseInventoryItem(25),
|
1 => _characterStatsMapping.Swordsman,
|
||||||
_itemObjectPoolService.GetBaseInventoryItem(764),
|
2 => _characterStatsMapping.Mage,
|
||||||
_itemObjectPoolService.GetBaseInventoryItem(766),
|
3 => _characterStatsMapping.Thief,
|
||||||
_itemObjectPoolService.GetBaseInventoryItem(763),
|
4 => _characterStatsMapping.Scout,
|
||||||
_itemObjectPoolService.GetBaseInventoryItem(767)
|
_ => _characterStatsMapping.Swordsman
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var mappedJobItems = firstJobConfig.Items
|
||||||
|
.Select(i => _itemObjectPoolService.GetBaseInventoryItem(i.Id, i.Quantity)).ToArray();
|
||||||
|
InventoryItem[] items =
|
||||||
|
[
|
||||||
|
.. mappedDefaultItems,
|
||||||
|
.. mappedJobItems,
|
||||||
|
_itemObjectPoolService.GetBaseInventoryItem((ushort)((packet.FirstJob - 1) * 6 +
|
||||||
|
((byte)packet.Gender - 1) * 3 +
|
||||||
|
packet.Hair + 1)),
|
||||||
|
_itemObjectPoolService.GetBaseInventoryItem((ushort)((packet.FirstJob - 1) * 6 +
|
||||||
|
((byte)packet.Gender - 1) * 3 +
|
||||||
|
packet.Eyes + 25)),
|
||||||
|
_itemObjectPoolService.GetBaseInventoryItem((ushort)(((byte)packet.Gender - 1) * 3 +
|
||||||
|
packet.Shirt + 49)),
|
||||||
|
_itemObjectPoolService.GetBaseInventoryItem((ushort)(((byte)packet.Gender - 1) * 3 +
|
||||||
|
packet.Pants + 58)),
|
||||||
|
];
|
||||||
|
|
||||||
|
var calculateCurrentMana = CalculateCurrentMana(1, firstJobConfig);
|
||||||
|
var calculateCurrentHealth = CalculateCurrentHealth(1, firstJobConfig);
|
||||||
account?.Characters.Add(new Character
|
account?.Characters.Add(new Character
|
||||||
{
|
{
|
||||||
Account = account,
|
Account = account,
|
||||||
|
@ -42,22 +69,14 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
LastXCoordinate = 113,
|
LastXCoordinate = 113,
|
||||||
LastYCoordinate = 0,
|
LastYCoordinate = 0,
|
||||||
PvPLevel = PvPLevel.None,
|
PvPLevel = PvPLevel.None,
|
||||||
Gender = Gender.None,
|
Gender = packet.Gender,
|
||||||
Experience = 0,
|
Experience = 0,
|
||||||
Level = 1,
|
Level = 1,
|
||||||
InventoryItems = items,
|
InventoryItems = items,
|
||||||
BaseStats = new BaseStats
|
BaseStats = firstJobConfig.BaseStats,
|
||||||
{
|
|
||||||
Strength = 5,
|
|
||||||
Dexterity = 5,
|
|
||||||
Intelligence = 5,
|
|
||||||
Vitality = 5,
|
|
||||||
Luck = 5,
|
|
||||||
Wisdom = 5
|
|
||||||
},
|
|
||||||
JobData = new JobData { FirstJob = packet.FirstJob, SecondJob = 0, ThirdJob = 0, FourthJob = 0 },
|
JobData = new JobData { FirstJob = packet.FirstJob, SecondJob = 0, ThirdJob = 0, FourthJob = 0 },
|
||||||
Health = 250,
|
Health = calculateCurrentHealth,
|
||||||
Mana = 250,
|
Mana = calculateCurrentMana
|
||||||
});
|
});
|
||||||
await _wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
await _wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
||||||
|
|
||||||
|
@ -93,4 +112,16 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
isDuplicate = false,
|
isDuplicate = false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int CalculateCurrentHealth(ushort level, JobSpecificMapping firstJobConfig)
|
||||||
|
{
|
||||||
|
return (int)((level - 1) * firstJobConfig.DynamicStats.HealthPerLevel +
|
||||||
|
firstJobConfig.BaseStats.Vitality * firstJobConfig.DynamicStats.HealthPerVitality);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CalculateCurrentMana(ushort level, JobSpecificMapping firstJobConfig)
|
||||||
|
{
|
||||||
|
return (int)((level - 1) * firstJobConfig.DynamicStats.ManaPerLevel +
|
||||||
|
firstJobConfig.BaseStats.Wisdom * firstJobConfig.DynamicStats.ManaPerWisdom);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -24,7 +24,8 @@ public class CharacterDeletionHandler : IPacketHandler<CharacterDeletePacket>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var character = await _wonderkingContext.Characters.FirstOrDefaultAsync(x => x.Name == packet.Name)
|
var character = await _wonderkingContext.Characters.FirstOrDefaultAsync(x => x.Name == packet.Name &&
|
||||||
|
x.Account.Id == authSession.AccountId)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
if (character == null)
|
if (character == null)
|
||||||
{
|
{
|
||||||
|
|
10
Server/PacketHandlers/CharacterMappingItemEntry.cs
Normal file
10
Server/PacketHandlers/CharacterMappingItemEntry.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Server.PacketHandlers;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public struct CharacterMappingItemEntry
|
||||||
|
{
|
||||||
|
public required ushort Id { get; set; }
|
||||||
|
public required ushort Quantity { get; set; }
|
||||||
|
}
|
15
Server/PacketHandlers/CharacterStatsMappingConfiguration.cs
Normal file
15
Server/PacketHandlers/CharacterStatsMappingConfiguration.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Server.PacketHandlers;
|
||||||
|
|
||||||
|
public class CharacterStatsMappingConfiguration
|
||||||
|
{
|
||||||
|
[JsonPropertyName("default")] public DefaultCharacterMapping DefaultCharacterMapping { get; set; }
|
||||||
|
[JsonPropertyName("1")] public JobSpecificMapping Swordsman { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("2")] public JobSpecificMapping Mage { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("3")] public JobSpecificMapping Thief { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("4")] public JobSpecificMapping Scout { get; set; }
|
||||||
|
}
|
8
Server/PacketHandlers/DefaultCharacterMapping.cs
Normal file
8
Server/PacketHandlers/DefaultCharacterMapping.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Server.PacketHandlers;
|
||||||
|
|
||||||
|
public class DefaultCharacterMapping
|
||||||
|
{
|
||||||
|
[JsonPropertyName("items")] public List<Item> Items { get; set; }
|
||||||
|
}
|
47
Server/PacketHandlers/DynamicStats.cs
Normal file
47
Server/PacketHandlers/DynamicStats.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Server.PacketHandlers;
|
||||||
|
|
||||||
|
public class DynamicStats
|
||||||
|
{
|
||||||
|
[JsonPropertyName("healthPerLevel")] public int HealthPerLevel { get; set; }
|
||||||
|
[JsonPropertyName("manaPerLevel")] public int ManaPerLevel { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("meleeDamagePerStrength")]
|
||||||
|
public double MeleeDamagePerStrength { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("rangedDamagePerDexterity")]
|
||||||
|
public double RangedDamagePerDexterity { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("hitRatingPerDexterity")]
|
||||||
|
public double HitRatingPerDexterity { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("magicPowerPerIntelligence")]
|
||||||
|
public double MagicPowerPerIntelligence { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("meleeDamagePerLuck")]
|
||||||
|
public double MeleeDamagePerLuck { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("rangedDamagePerLuck")]
|
||||||
|
public double RangedDamagePerLuck { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("evasionPerLuck")] public double EvasionPerLuck { get; set; }
|
||||||
|
[JsonPropertyName("criticalPerLuck")] public double CriticalPerLuck { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("healthPerVitality")]
|
||||||
|
public double HealthPerVitality { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("physicalDefensePerVitality")]
|
||||||
|
public double PhysicalDefensePerVitality { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("manaPerWisdom")] public double ManaPerWisdom { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("elementalDefensePerWisdom")]
|
||||||
|
public double ElementalDefensePerWisdom { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("elementalPowerPerMagicPower")]
|
||||||
|
public double ElementalPowerPerMagicPower { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("elementalDefensePerMagicPower")]
|
||||||
|
public double ElementalDefensePerMagicPower { get; set; }
|
||||||
|
}
|
11
Server/PacketHandlers/Item.cs
Normal file
11
Server/PacketHandlers/Item.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Server.PacketHandlers;
|
||||||
|
|
||||||
|
public class Item
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public ushort Id { get; set; }
|
||||||
|
[JsonPropertyName("quantity")]
|
||||||
|
public ushort Quantity { get; set; }
|
||||||
|
}
|
14
Server/PacketHandlers/JobSpecificMapping.cs
Normal file
14
Server/PacketHandlers/JobSpecificMapping.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
|
namespace Server.PacketHandlers;
|
||||||
|
|
||||||
|
public class JobSpecificMapping
|
||||||
|
{
|
||||||
|
[JsonPropertyName("items")]
|
||||||
|
public ICollection<Item> Items { get; set; }
|
||||||
|
[JsonPropertyName("baseStats")]
|
||||||
|
public BaseStats BaseStats { get; set; }
|
||||||
|
[JsonPropertyName("dynamicStats")]
|
||||||
|
public DynamicStats DynamicStats { get; set; }
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -7,15 +8,21 @@ using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Server.DB;
|
using Server.DB;
|
||||||
|
using Server.PacketHandlers;
|
||||||
using Server.Services;
|
using Server.Services;
|
||||||
|
|
||||||
var builder = Host.CreateApplicationBuilder();
|
var builder = Host.CreateApplicationBuilder();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
builder.Environment.EnvironmentName = "Development";
|
builder.Environment.EnvironmentName = "Development";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
builder.Configuration.AddJsonFile("settings.json", true, true)
|
builder.Configuration.AddJsonFile("settings.json", true, true)
|
||||||
.AddJsonFile($"settings.{builder.Environment.EnvironmentName}.json", true)
|
.AddJsonFile($"settings.{builder.Environment.EnvironmentName}.json", true)
|
||||||
.AddEnvironmentVariables().Build();
|
.AddEnvironmentVariables().Build();
|
||||||
|
builder.Services.AddSingleton<CharacterStatsMappingConfiguration>(
|
||||||
|
JsonSerializer.Deserialize<CharacterStatsMappingConfiguration>(
|
||||||
|
File.ReadAllText("config/character-stats.mapping.json")) ?? throw new InvalidOperationException());
|
||||||
|
|
||||||
builder.Services.AddLogging();
|
builder.Services.AddLogging();
|
||||||
var loggerFactory = LoggerFactory.Create(loggingBuilder =>
|
var loggerFactory = LoggerFactory.Create(loggingBuilder =>
|
||||||
{
|
{
|
||||||
|
@ -23,6 +30,7 @@ var loggerFactory = LoggerFactory.Create(loggingBuilder =>
|
||||||
loggingBuilder.AddFile("logs/Server-{Date}.json.log", LogLevel.Trace, isJson: true);
|
loggingBuilder.AddFile("logs/Server-{Date}.json.log", LogLevel.Trace, isJson: true);
|
||||||
loggingBuilder.AddConsole();
|
loggingBuilder.AddConsole();
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddDbContextPool<WonderkingContext>(o =>
|
builder.Services.AddDbContextPool<WonderkingContext>(o =>
|
||||||
{
|
{
|
||||||
using var configuration = builder.Configuration;
|
using var configuration = builder.Configuration;
|
||||||
|
@ -30,6 +38,7 @@ builder.Services.AddDbContextPool<WonderkingContext>(o =>
|
||||||
$"Host={configuration["DB:Host"]};Username={configuration["DB:Username"]};Password={configuration["DB:Password"]};Database={configuration["DB:Database"]};Port={configuration["DB:Port"]}")
|
$"Host={configuration["DB:Host"]};Username={configuration["DB:Username"]};Password={configuration["DB:Password"]};Database={configuration["DB:Database"]};Port={configuration["DB:Port"]}")
|
||||||
.EnableSensitiveDataLogging().UseLazyLoadingProxies().UseLoggerFactory(loggerFactory);
|
.EnableSensitiveDataLogging().UseLazyLoadingProxies().UseLoggerFactory(loggerFactory);
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddSingleton<ILoggerFactory>(loggerFactory);
|
builder.Services.AddSingleton<ILoggerFactory>(loggerFactory);
|
||||||
builder.Services.AddSingleton<PacketDistributorService>();
|
builder.Services.AddSingleton<PacketDistributorService>();
|
||||||
builder.Services.AddSingleton<ItemObjectPoolService>();
|
builder.Services.AddSingleton<ItemObjectPoolService>();
|
||||||
|
|
|
@ -22,17 +22,22 @@ public class PacketDistributorService : IHostedService
|
||||||
{
|
{
|
||||||
private readonly ConcurrentQueue<RawPacket> _concurrentQueue;
|
private readonly ConcurrentQueue<RawPacket> _concurrentQueue;
|
||||||
|
|
||||||
private readonly
|
private ImmutableDictionary<OperationCode,
|
||||||
ImmutableDictionary<OperationCode,
|
Func<byte[], IPacket>> _deserializationMap;
|
||||||
Func<byte[], IPacket>> _deserializationMap;
|
|
||||||
|
|
||||||
private readonly ILogger<PacketDistributorService> _logger;
|
private readonly ILogger<PacketDistributorService> _logger;
|
||||||
private readonly ConcurrentDictionary<OperationCode, object> _packetHandlersInstantiation;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private ConcurrentDictionary<OperationCode, object> _packetHandlersInstantiation;
|
||||||
|
|
||||||
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
|
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
this._concurrentQueue = new ConcurrentQueue<RawPacket>();
|
this._concurrentQueue = new ConcurrentQueue<RawPacket>();
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
var tempDeserializationMap =
|
var tempDeserializationMap =
|
||||||
new Dictionary<OperationCode, Func<byte[], IPacket>>();
|
new Dictionary<OperationCode, Func<byte[], IPacket>>();
|
||||||
|
|
||||||
|
@ -43,7 +48,7 @@ public class PacketDistributorService : IHostedService
|
||||||
packetHandlers.ForEach(x =>
|
packetHandlers.ForEach(x =>
|
||||||
{
|
{
|
||||||
var packetHandler =
|
var packetHandler =
|
||||||
ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider,
|
ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider,
|
||||||
x.Value);
|
x.Value);
|
||||||
this._packetHandlersInstantiation.TryAdd(x.Key, packetHandler);
|
this._packetHandlersInstantiation.TryAdd(x.Key, packetHandler);
|
||||||
});
|
});
|
||||||
|
@ -60,15 +65,14 @@ public class PacketDistributorService : IHostedService
|
||||||
|
|
||||||
Return(packetVariable);
|
Return(packetVariable);
|
||||||
}).Compile();
|
}).Compile();
|
||||||
logger.PacketCreationFunctionCreated(packetsType.Key);
|
_logger.PacketCreationFunctionCreated(packetsType.Key);
|
||||||
tempDeserializationMap.Add(packetsType.Key, lambda);
|
tempDeserializationMap.Add(packetsType.Key, lambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._deserializationMap = tempDeserializationMap.ToImmutableDictionary();
|
this._deserializationMap = tempDeserializationMap.ToImmutableDictionary();
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||||
|
|
||||||
private Dictionary<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
|
private Dictionary<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -7,10 +8,10 @@ namespace Wonderking.Packets.Outgoing.Data;
|
||||||
[Owned]
|
[Owned]
|
||||||
public class BaseStats
|
public class BaseStats
|
||||||
{
|
{
|
||||||
public required short Strength { get; set; }
|
[JsonPropertyName("strength")] public required short Strength { get; set; }
|
||||||
public required short Dexterity { get; set; }
|
[JsonPropertyName("dexterity")] public required short Dexterity { get; set; }
|
||||||
public required short Intelligence { get; set; }
|
[JsonPropertyName("intelligence")] public required short Intelligence { get; set; }
|
||||||
public required short Vitality { get; set; }
|
[JsonPropertyName("vitality")] public required short Vitality { get; set; }
|
||||||
public required short Luck { get; set; }
|
[JsonPropertyName("luck")] public required short Luck { get; set; }
|
||||||
public required short Wisdom { get; set; }
|
[JsonPropertyName("wisdom")] public required short Wisdom { get; set; }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue