feat: add combat and deleveling AI
This commit is contained in:
19
Client/Infrastructure/AI/IO/JsonConfigDeserializer.cs
Normal file
19
Client/Infrastructure/AI/IO/JsonConfigDeserializer.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Client.Domain.AI;
|
||||
using Client.Domain.AI.IO;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Client.Infrastructure.AI.IO
|
||||
{
|
||||
public class JsonConfigDeserializer : ConfigDeserializerInterface
|
||||
{
|
||||
public Config? Deserialize(string data)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<Config>(data);
|
||||
}
|
||||
}
|
||||
}
|
20
Client/Infrastructure/AI/IO/JsonConfigSerializer.cs
Normal file
20
Client/Infrastructure/AI/IO/JsonConfigSerializer.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Client.Domain.AI;
|
||||
using Client.Domain.AI.IO;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Client.Infrastructure.AI.IO
|
||||
{
|
||||
public class JsonConfigSerializer : ConfigSerializerInterface
|
||||
{
|
||||
public string Serialize(Config config)
|
||||
{
|
||||
return JsonConvert.SerializeObject(config, Formatting.Indented, new JsonSerializerSettings() { Culture = CultureInfo.InvariantCulture, ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
|
||||
}
|
||||
}
|
||||
}
|
@@ -26,6 +26,8 @@ namespace Client.Infrastructure.Factories
|
||||
{
|
||||
case ItemTypeEnum.Etc:
|
||||
return JsonConvert.DeserializeObject<EtcItem>(data, settings);
|
||||
case ItemTypeEnum.Weapon:
|
||||
return JsonConvert.DeserializeObject<WeaponItem>(data, settings);
|
||||
default:
|
||||
return JsonConvert.DeserializeObject<EtcItem>(data, settings); //fixme temporary
|
||||
}
|
||||
|
54
Client/Infrastructure/Helpers/ConfigurationItemInfoHelper.cs
Normal file
54
Client/Infrastructure/Helpers/ConfigurationItemInfoHelper.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Client.Domain.Helpers;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Client.Infrastructure.Helpers
|
||||
{
|
||||
public class ConfigurationItemInfoHelper : ItemInfoHelperInterface
|
||||
{
|
||||
|
||||
public List<ItemInfo> GetAllItems()
|
||||
{
|
||||
LoadItems();
|
||||
return itemsInfo;
|
||||
}
|
||||
|
||||
public ConfigurationItemInfoHelper(IConfiguration configuration)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
private void LoadItems()
|
||||
{
|
||||
if (itemsInfo.Count == 0)
|
||||
{
|
||||
var items = configuration.GetRequiredSection("itemInfo").GetChildren();
|
||||
foreach (var item in items)
|
||||
{
|
||||
var id = uint.Parse(item.Key);
|
||||
|
||||
var isShot = false;
|
||||
if (item != null)
|
||||
{
|
||||
bool.TryParse(item.GetSection("isShot").Value, out isShot);
|
||||
}
|
||||
|
||||
itemsInfo.Add(new ItemInfo
|
||||
{
|
||||
Id = id,
|
||||
Name = string.Format("{0} [{1}]", item?.GetRequiredSection("name").Value ?? "", id),
|
||||
IsShot = isShot
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IConfiguration configuration;
|
||||
private List<ItemInfo> itemsInfo = new List<ItemInfo>();
|
||||
}
|
||||
}
|
@@ -6,7 +6,6 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using static Client.Infrastructure.Helpers.ConfigurationExperienceHelper;
|
||||
|
||||
namespace Client.Infrastructure.Helpers
|
||||
{
|
||||
@@ -14,12 +13,30 @@ namespace Client.Infrastructure.Helpers
|
||||
{
|
||||
public uint GetLevel(uint id)
|
||||
{
|
||||
return GetNpcInfo(id).level;
|
||||
LoadNpc();
|
||||
|
||||
if (npcInfo.ContainsKey(id))
|
||||
{
|
||||
return npcInfo[id].Level;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint GetAggroRadius(uint id)
|
||||
{
|
||||
return GetNpcInfo(id).aggroRadius;
|
||||
LoadNpc();
|
||||
|
||||
if (npcInfo.ContainsKey(id))
|
||||
{
|
||||
return npcInfo[id].AggroRadius;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<NpcInfo> GetAllNpc()
|
||||
{
|
||||
LoadNpc();
|
||||
return npcInfo.Select(x => x.Value).ToList();
|
||||
}
|
||||
|
||||
public ConfigurationNpcInfoHelper(IConfiguration configuration)
|
||||
@@ -27,36 +44,37 @@ namespace Client.Infrastructure.Helpers
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
private NpcInfo GetNpcInfo(uint id)
|
||||
private void LoadNpc()
|
||||
{
|
||||
if (!npcInfo.ContainsKey(id))
|
||||
if (npcInfo.Count == 0)
|
||||
{
|
||||
var item = configuration.GetRequiredSection("npcInfo").GetChildren()
|
||||
.Where(x => x.Key == id.ToString())
|
||||
.FirstOrDefault();
|
||||
uint level = 0;
|
||||
uint aggroRadius = 0;
|
||||
if (item != null)
|
||||
var items = configuration.GetRequiredSection("npcInfo").GetChildren();
|
||||
foreach (var item in items)
|
||||
{
|
||||
uint.TryParse(item.GetRequiredSection("level").Value, out level);
|
||||
uint.TryParse(item.GetRequiredSection("aggroRadius").Value, out aggroRadius);
|
||||
var id = uint.Parse(item.Key);
|
||||
|
||||
uint level = 0;
|
||||
uint aggroRadius = 0;
|
||||
bool isGuard = false;
|
||||
if (item != null)
|
||||
{
|
||||
uint.TryParse(item.GetRequiredSection("level").Value, out level);
|
||||
uint.TryParse(item.GetRequiredSection("aggroRadius").Value, out aggroRadius);
|
||||
bool.TryParse(item.GetRequiredSection("isGuard").Value, out isGuard);
|
||||
}
|
||||
npcInfo[id] = new NpcInfo
|
||||
{
|
||||
Id = id,
|
||||
Level = level,
|
||||
AggroRadius = aggroRadius,
|
||||
Name = string.Format("{0} [{1}]", item?.GetRequiredSection("name").Value ?? "", id),
|
||||
IsGuard = isGuard
|
||||
};
|
||||
}
|
||||
npcInfo[id] = new NpcInfo
|
||||
{
|
||||
level = level,
|
||||
aggroRadius = aggroRadius
|
||||
};
|
||||
}
|
||||
return npcInfo[id];
|
||||
}
|
||||
|
||||
private readonly IConfiguration configuration;
|
||||
private Dictionary<uint, NpcInfo> npcInfo = new Dictionary<uint, NpcInfo>();
|
||||
|
||||
private class NpcInfo
|
||||
{
|
||||
public uint level { get; set; }
|
||||
public uint aggroRadius { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
53
Client/Infrastructure/Helpers/ConfigurationSkillnfoHelper.cs
Normal file
53
Client/Infrastructure/Helpers/ConfigurationSkillnfoHelper.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Client.Domain.Helpers;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Client.Infrastructure.Helpers
|
||||
{
|
||||
public class ConfigurationSkillInfoHelper : SkillInfoHelperInterface
|
||||
{
|
||||
|
||||
public Dictionary<uint, SkillInfo> GetAllSkills()
|
||||
{
|
||||
LoadSkills();
|
||||
return skillsInfo;
|
||||
}
|
||||
|
||||
public ConfigurationSkillInfoHelper(IConfiguration configuration)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
private void LoadSkills()
|
||||
{
|
||||
if (skillsInfo.Count == 0)
|
||||
{
|
||||
var items = configuration.GetRequiredSection("skillInfo").GetChildren();
|
||||
foreach (var item in items)
|
||||
{
|
||||
var id = uint.Parse(item.Key);
|
||||
|
||||
var isActive = false;
|
||||
if (item != null)
|
||||
{
|
||||
bool.TryParse(item.GetRequiredSection("IsActive").Value, out isActive);
|
||||
}
|
||||
skillsInfo[id]=(new SkillInfo
|
||||
{
|
||||
Id = id,
|
||||
Name = string.Format("{0} [{1}]", item?.GetRequiredSection("name").Value ?? "", id),
|
||||
IsActive = isActive
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IConfiguration configuration;
|
||||
private Dictionary<uint, SkillInfo> skillsInfo = new Dictionary<uint, SkillInfo>();
|
||||
}
|
||||
}
|
@@ -28,7 +28,19 @@ namespace Client.Infrastructure.Service
|
||||
private CancellationTokenSource? cancellationTokenSource;
|
||||
|
||||
public ObservableCollection<PathSegment> Path { get; private set; } = new ObservableCollection<PathSegment>();
|
||||
public bool IsBusy { get; private set; } = false;
|
||||
public bool IsLocked { get; private set; } = false;
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
IsLocked = false;
|
||||
if (cancellationTokenSource != null)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource.Dispose();
|
||||
cancellationTokenSource = null;
|
||||
Path.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task MoveUntilReachedAsync(Vector3 location)
|
||||
{
|
||||
@@ -41,7 +53,7 @@ namespace Client.Infrastructure.Service
|
||||
|
||||
public async Task<bool> MoveAsync(Vector3 location)
|
||||
{
|
||||
IsBusy = true;
|
||||
IsLocked = true;
|
||||
|
||||
if (cancellationTokenSource != null)
|
||||
{
|
||||
@@ -55,11 +67,9 @@ namespace Client.Infrastructure.Service
|
||||
{
|
||||
return await Task.Run(async () =>
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
Debug.WriteLine("Find path start");
|
||||
Debug.WriteLine("Find path started");
|
||||
FindPath(location);
|
||||
Debug.WriteLine("Find path finish");
|
||||
Debug.WriteLine("Find path finished");
|
||||
|
||||
|
||||
foreach (var node in Path.ToList())
|
||||
@@ -69,19 +79,21 @@ namespace Client.Infrastructure.Service
|
||||
var reached = await WaitForNodeReaching(cancellationToken, node);
|
||||
if (!reached)
|
||||
{
|
||||
IsBusy = false;
|
||||
IsLocked = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Path.Remove(node);
|
||||
}
|
||||
|
||||
IsBusy = false;
|
||||
IsLocked = false;
|
||||
return true;
|
||||
}, cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
IsBusy = false;
|
||||
Debug.WriteLine("Path cancelled");
|
||||
IsLocked = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -118,13 +130,8 @@ namespace Client.Infrastructure.Service
|
||||
var hero = worldHandler.Hero;
|
||||
|
||||
var start = DateTime.Now;
|
||||
while (hero != null && !hero.Transform.Position.ApproximatelyEquals(node.To, nodeDistanceTolerance))
|
||||
while (!token.IsCancellationRequested && hero != null && !hero.Transform.Position.ApproximatelyEquals(node.To, nodeDistanceTolerance))
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
if (hero.Transform.Velocity.Equals(Vector3.Zero))
|
||||
{
|
||||
var elapsedSeconds = (DateTime.Now - start).TotalSeconds;
|
||||
@@ -138,7 +145,9 @@ namespace Client.Infrastructure.Service
|
||||
return false;
|
||||
}
|
||||
}
|
||||
await Task.Delay(25);
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
await Task.Delay(25, token);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -44,9 +44,9 @@ namespace Client.Infrastructure.Transports
|
||||
Debug.WriteLine("Connected to main pipe\n");
|
||||
}
|
||||
}
|
||||
public async Task StartReceiveAsync()
|
||||
public async Task ReceiveAsync()
|
||||
{
|
||||
while (IsConnected())
|
||||
if (IsConnected())
|
||||
{
|
||||
byte[] buffer = new byte[16384 * 2];
|
||||
int readBytes = await mainPipe!.ReadAsync(buffer, 0, buffer.Length);
|
||||
|
Reference in New Issue
Block a user