Initial Commit
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
using System.Net.Http.Json;
|
||||
using Model.Notes;
|
||||
|
||||
namespace Services.Development;
|
||||
|
||||
public class NoteService : INoteService
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
private bool isLoaded;
|
||||
|
||||
public NoteService(HttpClient httpClient)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public List<NoteContentModel> NoteContentModelsByPageOrder { get; set; } = new();
|
||||
|
||||
public List<NoteContentModel> NoteContentModels { get; set; } = default!;
|
||||
public List<NoteConnectionModel> NoteConnectionModels { get; set; } = null!;
|
||||
public List<NoteSectionModel> NoteSectionModels { get; set; } = null!;
|
||||
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public bool IsLoaded()
|
||||
{
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public async Task Load()
|
||||
{
|
||||
if (isLoaded) return;
|
||||
|
||||
NoteContentModels =
|
||||
(await httpClient.GetFromJsonAsync<NoteContentModel[]>("generated/NoteContentModels.json") ??
|
||||
Array.Empty<NoteContentModel>()).ToList();
|
||||
NoteConnectionModels =
|
||||
(await httpClient.GetFromJsonAsync<NoteConnectionModel[]>("generated/NoteConnectionModels.json") ??
|
||||
Array.Empty<NoteConnectionModel>()).ToList();
|
||||
NoteSectionModels =
|
||||
(await httpClient.GetFromJsonAsync<NoteSectionModel[]>("generated/NoteSectionModels.json") ??
|
||||
Array.Empty<NoteSectionModel>()).ToList();
|
||||
|
||||
isLoaded = true;
|
||||
|
||||
SortSQL();
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
|
||||
private event Action OnChange = default!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
|
||||
private NoteContentModel? ContentById(int id)
|
||||
{
|
||||
foreach (var data in NoteContentModels!)
|
||||
if (data.Id == id)
|
||||
return data;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SortSQL()
|
||||
{
|
||||
foreach (var connection in NoteConnectionModels)
|
||||
{
|
||||
ContentById(connection.ParentId)!.NoteContentModels.Add(ContentById(connection.ChildId));
|
||||
ContentById(connection.ChildId)!.Parent = ContentById(connection.ParentId);
|
||||
}
|
||||
|
||||
foreach (var content in NoteContentModels)
|
||||
if (content.NoteSectionModelId != null)
|
||||
foreach (var section in NoteSectionModels)
|
||||
if (section.Id == content.NoteSectionModelId)
|
||||
section.NoteContentModels.Add(content);
|
||||
|
||||
ByPageOrder();
|
||||
}
|
||||
|
||||
private void ByPageOrder()
|
||||
{
|
||||
NoteContentModelsByPageOrder = new List<NoteContentModel>();
|
||||
|
||||
var order = 1;
|
||||
foreach (var note in NoteContentModels)
|
||||
{
|
||||
if (note.Parent != null) continue;
|
||||
|
||||
note.PageOrder = order++;
|
||||
NoteContentModelsByPageOrder.Add(note);
|
||||
|
||||
void GetAllChildren(NoteContentModel docs)
|
||||
{
|
||||
foreach (var doc in docs.NoteContentModels)
|
||||
{
|
||||
doc.PageOrder = order++;
|
||||
NoteContentModelsByPageOrder.Add(doc);
|
||||
|
||||
if (doc.NoteContentModels.Count > 0) GetAllChildren(doc);
|
||||
}
|
||||
}
|
||||
|
||||
GetAllChildren(note);
|
||||
}
|
||||
|
||||
NoteContentModelsByPageOrder =
|
||||
NoteContentModelsByPageOrder.OrderBy(noteContent => noteContent.PageOrder).ToList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
using Model.BuildOrders;
|
||||
using Model.Economy;
|
||||
using Model.Entity;
|
||||
using Model.Feedback;
|
||||
using Model.MemoryTester;
|
||||
using Model.Notes;
|
||||
using Model.Website;
|
||||
using Model.Website.Enums;
|
||||
using Services.Immortal;
|
||||
using Services.Website;
|
||||
|
||||
namespace Services;
|
||||
|
||||
public interface IToastService
|
||||
{
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
void AddToast(ToastModel toast);
|
||||
void RemoveToast(ToastModel toast);
|
||||
bool HasToasts();
|
||||
List<ToastModel> GetToasts();
|
||||
void AgeToasts();
|
||||
void ClearAllToasts();
|
||||
}
|
||||
|
||||
public interface IDataCollectionService
|
||||
{
|
||||
public void SendEvent<T>(string eventName, T eventData);
|
||||
}
|
||||
|
||||
public interface IStorageService
|
||||
{
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
T GetValue<T>(string forKey);
|
||||
void SetValue<T>(string key, T value);
|
||||
|
||||
Task Load();
|
||||
}
|
||||
|
||||
public interface IPermissionService
|
||||
{
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
|
||||
public bool GetIsStorageEnabled();
|
||||
public bool GetIsDataCollectionEnabled();
|
||||
|
||||
public void SetIsStorageEnabled(bool isEnabled);
|
||||
public void SetIsDataCollectionEnabled(bool isEnabled);
|
||||
}
|
||||
|
||||
public interface ISearchService
|
||||
{
|
||||
public List<SearchPointModel> SearchPoints { get; set; }
|
||||
|
||||
public Dictionary<string, List<SearchPointModel>> Searches { get; set; }
|
||||
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
|
||||
public void Search(string entityId);
|
||||
|
||||
public Task Load();
|
||||
|
||||
public bool IsLoaded();
|
||||
void Show();
|
||||
void Hide();
|
||||
}
|
||||
|
||||
public interface IMyDialogService
|
||||
{
|
||||
public bool IsVisible { get; set; }
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
public void Show(DialogContents dialogContents);
|
||||
public DialogContents GetDialogContents();
|
||||
public void Hide();
|
||||
}
|
||||
|
||||
public interface IEconomyComparisonService
|
||||
{
|
||||
public List<BuildToCompareModel> BuildsToCompare { get; set; }
|
||||
public void ChangeNumberOfTownHalls(int forPlayer, int toCount);
|
||||
public void ChangeTownHallTiming(int forPlayer, int forTownHall, int toTiming);
|
||||
public int GetTownHallCount(int forPlayer);
|
||||
public int GetTownHallBuildTime(int forPlayer, int forTownHall);
|
||||
|
||||
public List<int> GetTownHallBuildTimes(int forPlayer);
|
||||
public void ChangeFaction(int forPlayer, string toFaction);
|
||||
public string GetFaction(int forPlayer);
|
||||
|
||||
public void ChangeColor(int forPlayer, string toColor);
|
||||
public string GetColor(int forPlayer);
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
}
|
||||
|
||||
public interface IEntityDialogService
|
||||
{
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
|
||||
public void AddDialog(string entityId);
|
||||
public void CloseDialog();
|
||||
|
||||
public void BackDialog();
|
||||
|
||||
public string? GetEntityId();
|
||||
|
||||
public bool HasDialog();
|
||||
public bool HasHistory();
|
||||
}
|
||||
|
||||
|
||||
public interface INoteService
|
||||
{
|
||||
public List<NoteContentModel> NoteContentModels { get; set; }
|
||||
public List<NoteConnectionModel> NoteConnectionModels { get; set; }
|
||||
public List<NoteSectionModel> NoteSectionModels { get; set; }
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
public void Update();
|
||||
public Task Load();
|
||||
public bool IsLoaded();
|
||||
}
|
||||
|
||||
public interface INavigationService
|
||||
{
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
|
||||
public void ChangeNavigationSectionId(int newState);
|
||||
public int GetNavigationSectionId();
|
||||
public void ChangeNavigationState(string newState);
|
||||
public string GetNavigationState();
|
||||
|
||||
public void Back();
|
||||
public void SelectSection(int webSectionType);
|
||||
public void SelectPage(int pageType, Type webPageType);
|
||||
|
||||
public NavSelectionType GetNavSelectionType();
|
||||
public int GetWebPageId();
|
||||
public int GetWebSectionId();
|
||||
public Type GetRenderType();
|
||||
}
|
||||
|
||||
public interface IBuildComparisonService
|
||||
{
|
||||
public void SetBuilds(BuildToCompareModel buildToCompareModel);
|
||||
public BuildToCompareModel Get();
|
||||
public string BuildOrderAsYaml();
|
||||
public string AsJson();
|
||||
public bool LoadJson(string data);
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
}
|
||||
|
||||
public interface ITimingService
|
||||
{
|
||||
public int BuildingInputDelay { get; set; }
|
||||
public int WaitTime { get; set; }
|
||||
public int WaitTo { get; set; }
|
||||
public int GetAttackTime();
|
||||
public void SetAttackTime(int timing);
|
||||
public int GetTravelTime();
|
||||
public void SetTravelTime(int timing);
|
||||
public void Subscribe(Action? action);
|
||||
public void Unsubscribe(Action? action);
|
||||
}
|
||||
|
||||
public interface IEconomyService
|
||||
{
|
||||
public List<EconomyModel> GetOverTime();
|
||||
public EconomyModel GetEconomy(int atInterval);
|
||||
public void Calculate(IBuildOrderService buildOrder, ITimingService timing, int fromInterval);
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
}
|
||||
|
||||
public interface IEntityFilterService
|
||||
{
|
||||
public delegate void EntityFilterAction(EntityFilterEvent entityFilterEvent);
|
||||
|
||||
public string GetFactionType();
|
||||
public string GetImmortalType();
|
||||
public string GetEntityType();
|
||||
public string GetSearchText();
|
||||
|
||||
public List<string> GetFactionChoices();
|
||||
public List<string> GetImmortalChoices();
|
||||
public List<string> GetEntityChoices();
|
||||
|
||||
|
||||
public bool SelectFactionType(string factionType);
|
||||
public bool SelectImmortalType(string immortalType);
|
||||
public bool SelectEntityType(string entityType);
|
||||
public bool EnterSearchText(string searchText);
|
||||
|
||||
|
||||
public void Subscribe(EntityFilterAction action);
|
||||
public void Unsubscribe(EntityFilterAction action);
|
||||
}
|
||||
|
||||
public interface IEntityService
|
||||
{
|
||||
public List<EntityModel> GetEntities();
|
||||
}
|
||||
|
||||
public interface IEntityDisplayService
|
||||
{
|
||||
public List<string> DefaultChoices();
|
||||
|
||||
public string GetDisplayType();
|
||||
public void SetDisplayType(string displayType);
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
}
|
||||
|
||||
public interface IImmortalSelectionService
|
||||
{
|
||||
public string GetFaction();
|
||||
public string GetImmortal();
|
||||
public bool SelectFaction(string faction);
|
||||
public bool SelectImmortal(string immortal);
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
}
|
||||
|
||||
public interface IKeyService
|
||||
{
|
||||
public List<string> GetAllPressedKeys();
|
||||
public string? GetHotkey();
|
||||
public string GetHotkeyGroup();
|
||||
public bool IsHoldingSpace();
|
||||
public bool AddPressedKey(string key);
|
||||
public bool RemovePressedKey(string key);
|
||||
public void Subscribe(Action? action);
|
||||
public void Unsubscribe(Action? action);
|
||||
}
|
||||
|
||||
public interface IMemoryTesterService
|
||||
{
|
||||
public delegate void MemoryAction(MemoryTesterEvent memoryEvent);
|
||||
|
||||
public List<MemoryEntityModel> GetEntities();
|
||||
public List<MemoryQuestionModel> GetQuestions();
|
||||
|
||||
void GenerateQuiz();
|
||||
|
||||
public void Update(MemoryQuestionModel question);
|
||||
|
||||
public void Verify();
|
||||
|
||||
public void Subscribe(MemoryAction memoryAction);
|
||||
public void Unsubscribe(MemoryAction memoryAction);
|
||||
}
|
||||
|
||||
public interface IBuildOrderService
|
||||
{
|
||||
public Dictionary<int, List<EntityModel>> StartedOrders { get; }
|
||||
public Dictionary<int, List<EntityModel>> CompletedOrders { get; }
|
||||
public Dictionary<int, List<EntityModel>> DepletedOrders { get; }
|
||||
public Dictionary<string, int> UniqueCompletedTimes { get; }
|
||||
|
||||
public Dictionary<int, int> SupplyCountTimes { get; }
|
||||
|
||||
|
||||
public bool Add(EntityModel entity, IEconomyService withEconomy);
|
||||
public void Add(EntityModel entity, int atInterval);
|
||||
public bool AddWait(int forInterval);
|
||||
public bool AddWaitTo(int interval);
|
||||
|
||||
|
||||
public void SetName(string name);
|
||||
public string GetName();
|
||||
|
||||
public void SetNotes(string notes);
|
||||
public string GetNotes();
|
||||
|
||||
public void DeprecatedSetColor(string color);
|
||||
public string GetColor();
|
||||
|
||||
public int? WillMeetRequirements(EntityModel entity);
|
||||
public int? WillMeetSupply(EntityModel entity);
|
||||
public Dictionary<int, List<EntityModel>> GetOrders();
|
||||
public List<EntityModel> GetCompletedBefore(int interval);
|
||||
public List<EntityModel> GetUndepletedHarvestPointsCompletedBefore(int interval);
|
||||
|
||||
public void RemoveLast();
|
||||
public void Reset();
|
||||
|
||||
public int GetLastRequestInterval();
|
||||
public string BuildOrderAsYaml();
|
||||
public string AsJson();
|
||||
public void Subscribe(Action action);
|
||||
public void Unsubscribe(Action action);
|
||||
}
|
||||
@@ -0,0 +1,497 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Model.BuildOrders;
|
||||
using Model.Entity;
|
||||
using Model.Entity.Data;
|
||||
using Model.Feedback;
|
||||
using Model.Types;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class BuildOrderService : IBuildOrderService
|
||||
{
|
||||
private readonly BuildOrderModel _buildOrder = new();
|
||||
|
||||
private readonly ITimingService _timingService;
|
||||
|
||||
private readonly IToastService _toastService;
|
||||
|
||||
private int _lastInterval;
|
||||
|
||||
public BuildOrderService(IToastService toastService, ITimingService timingService)
|
||||
{
|
||||
_toastService = toastService;
|
||||
_timingService = timingService;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public Dictionary<int, List<EntityModel>> StartedOrders => _buildOrder.StartedOrders;
|
||||
public Dictionary<int, List<EntityModel>> CompletedOrders => _buildOrder.CompletedOrders;
|
||||
public Dictionary<int, List<EntityModel>> DepletedOrders => _buildOrder.DepletedOrders;
|
||||
public Dictionary<string, int> UniqueCompletedTimes => _buildOrder.UniqueCompletedTimes;
|
||||
public Dictionary<int, int> SupplyCountTimes => _buildOrder.SupplyCountTimes;
|
||||
|
||||
public int GetLastRequestInterval()
|
||||
{
|
||||
return _lastInterval;
|
||||
}
|
||||
|
||||
public Dictionary<int, List<EntityModel>> GetOrders()
|
||||
{
|
||||
return _buildOrder.StartedOrders;
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
|
||||
public void Add(EntityModel entity, int atInterval)
|
||||
{
|
||||
if (!_buildOrder.StartedOrders.ContainsKey(atInterval))
|
||||
_buildOrder.StartedOrders.Add(atInterval, []);
|
||||
|
||||
var production = entity.Production();
|
||||
|
||||
var completedTime = atInterval;
|
||||
if (production != null) completedTime += production.BuildTime;
|
||||
|
||||
if (!_buildOrder.CompletedOrders.ContainsKey(completedTime))
|
||||
_buildOrder.CompletedOrders.Add(completedTime, []);
|
||||
|
||||
_buildOrder.StartedOrders[atInterval].Add(entity.Clone());
|
||||
_buildOrder.CompletedOrders[completedTime].Add(entity.Clone());
|
||||
|
||||
_buildOrder.UniqueCompletedTimes.TryAdd(entity.DataType, atInterval);
|
||||
|
||||
if (!_buildOrder.UniqueCompletedCount.TryAdd(entity.DataType, 1))
|
||||
_buildOrder.UniqueCompletedCount[entity.DataType]++;
|
||||
|
||||
if (!_buildOrder.UniqueCompleted.ContainsKey(entity.DataType))
|
||||
_buildOrder.UniqueCompleted.Add(entity.DataType, []);
|
||||
|
||||
if (entity.Production()?.ProducedBy != null)
|
||||
_buildOrder.TrainingCapacityUsed.Add(new TrainingCapacityUsedModel
|
||||
{
|
||||
StartingUsageTime = atInterval,
|
||||
StopUsageTime = completedTime,
|
||||
UsedSlots = entity.Supply() != null ? entity.Supply()!.Takes : 1,
|
||||
UsedBuilding = entity.Production()!.ProducedBy
|
||||
});
|
||||
|
||||
_buildOrder.UniqueCompleted[entity.DataType].Add(entity);
|
||||
|
||||
if (entity.Supply() != null && entity.Supply()!.Takes > 0)
|
||||
_buildOrder.CurrentSupplyUsed += entity.Supply()!.Takes;
|
||||
if (entity.Supply() != null && entity.Supply()!.Grants > 0)
|
||||
_buildOrder.SupplyCountTimes.Add(_buildOrder.SupplyCountTimes.Last().Key + entity.Supply()!.Grants,
|
||||
completedTime);
|
||||
|
||||
if (atInterval > _lastInterval) _lastInterval = atInterval;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public bool AddWait(int forInterval)
|
||||
{
|
||||
if (forInterval < 0)
|
||||
{
|
||||
_toastService.AddToast(new ToastModel
|
||||
{ SeverityType = SeverityType.Error, Title = "Wait", Message = "This should never happen." });
|
||||
return false;
|
||||
}
|
||||
|
||||
_lastInterval += forInterval;
|
||||
|
||||
if (!_buildOrder.StartedOrders.ContainsKey(_lastInterval))
|
||||
_buildOrder.StartedOrders.Add(_lastInterval, []);
|
||||
|
||||
if (!_buildOrder.CompletedOrders.ContainsKey(_lastInterval))
|
||||
_buildOrder.CompletedOrders.Add(_lastInterval, []);
|
||||
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddWaitTo(int interval)
|
||||
{
|
||||
if (interval <= _lastInterval)
|
||||
{
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
SeverityType = SeverityType.Error, Title = "Logic Error",
|
||||
Message = "You cannot wait to a time that has already elapsed."
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
_lastInterval = interval;
|
||||
|
||||
if (!_buildOrder.StartedOrders.ContainsKey(_lastInterval))
|
||||
_buildOrder.StartedOrders.Add(_lastInterval, []);
|
||||
|
||||
if (!_buildOrder.CompletedOrders.ContainsKey(_lastInterval))
|
||||
_buildOrder.CompletedOrders.Add(_lastInterval, []);
|
||||
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
public int? WillMeetRequirements(EntityModel entity)
|
||||
{
|
||||
var requirements = entity.Requirements();
|
||||
|
||||
if (requirements.Count == 0) return 0;
|
||||
|
||||
var metTime = 0;
|
||||
foreach (var requiredEntity in requirements)
|
||||
if (_buildOrder.UniqueCompletedTimes.TryGetValue(requiredEntity.Id, out var completedTime))
|
||||
{
|
||||
if (completedTime > metTime) metTime = completedTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return metTime;
|
||||
}
|
||||
|
||||
public int? WillMeetSupply(EntityModel entity)
|
||||
{
|
||||
var supply = entity.Supply();
|
||||
|
||||
if (supply == null || supply.Takes.Equals(0)) return 0;
|
||||
|
||||
foreach (var supplyAtTime in
|
||||
_buildOrder.SupplyCountTimes
|
||||
.Where(supplyAtTime => supply.Takes + _buildOrder.CurrentSupplyUsed <= supplyAtTime.Key))
|
||||
return supplyAtTime.Value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public bool Add(EntityModel entity, IEconomyService withEconomy)
|
||||
{
|
||||
var atInterval = _lastInterval;
|
||||
|
||||
if (!HandleSupply(entity, ref atInterval)) return false;
|
||||
if (!HandleRequirements(entity, ref atInterval)) return false;
|
||||
if (!HandleEconomy(entity, withEconomy, ref atInterval)) return false;
|
||||
if (!HandleTrainingQueue(entity, ref atInterval)) return false;
|
||||
|
||||
Add(entity, atInterval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveLast()
|
||||
{
|
||||
if (_buildOrder.StartedOrders.Keys.Count <= 1) return;
|
||||
|
||||
if (_buildOrder.StartedOrders.Count == 0)
|
||||
{
|
||||
_buildOrder.StartedOrders.Remove(_buildOrder.StartedOrders.Last().Key);
|
||||
_buildOrder.CompletedOrders.Remove(_buildOrder.CompletedOrders.Last().Key);
|
||||
|
||||
_lastInterval = _buildOrder.StartedOrders.Last().Key;
|
||||
return;
|
||||
}
|
||||
|
||||
var lastStarted = _buildOrder.StartedOrders.Keys.Last();
|
||||
var lastCompleted = _buildOrder.CompletedOrders.Keys.Last();
|
||||
|
||||
EntityModel entityRemoved = default!;
|
||||
|
||||
if (_buildOrder.StartedOrders[lastStarted].Count > 0)
|
||||
{
|
||||
entityRemoved = _buildOrder.StartedOrders[lastStarted].Last();
|
||||
_buildOrder.StartedOrders[lastStarted].Remove(_buildOrder.StartedOrders[lastStarted].Last());
|
||||
_buildOrder.CompletedOrders[lastCompleted].Remove(_buildOrder.CompletedOrders[lastCompleted].Last());
|
||||
}
|
||||
|
||||
if (_buildOrder.StartedOrders[lastStarted].Count == 0) _buildOrder.StartedOrders.Remove(lastStarted);
|
||||
if (_buildOrder.CompletedOrders[lastCompleted].Count == 0)
|
||||
_buildOrder.CompletedOrders.Remove(lastCompleted);
|
||||
|
||||
if (_buildOrder.StartedOrders.Keys.Count > 0)
|
||||
_lastInterval = _buildOrder.StartedOrders.Keys.Last();
|
||||
else
|
||||
_lastInterval = 0;
|
||||
|
||||
if (entityRemoved.Supply()?.Grants > 0)
|
||||
SupplyCountTimes.Remove(SupplyCountTimes.Last().Key);
|
||||
|
||||
if (entityRemoved.Supply()?.Takes > 0)
|
||||
_buildOrder.CurrentSupplyUsed -= entityRemoved.Supply()!.Takes;
|
||||
|
||||
_buildOrder.UniqueCompletedCount[entityRemoved!.DataType]--;
|
||||
if (_buildOrder.UniqueCompletedCount[entityRemoved!.DataType] == 0)
|
||||
UniqueCompletedTimes.Remove(entityRemoved.DataType);
|
||||
|
||||
_buildOrder.UniqueCompleted[entityRemoved.DataType]
|
||||
.Remove(_buildOrder.UniqueCompleted[entityRemoved.DataType].Last());
|
||||
|
||||
if (entityRemoved.Production() != null
|
||||
&& entityRemoved.Production()!.ProducedBy != null
|
||||
&& entityRemoved.Supply() != null
|
||||
&& entityRemoved.Supply()!.Takes > 0)
|
||||
_buildOrder.TrainingCapacityUsed.Remove(_buildOrder.TrainingCapacityUsed.Last());
|
||||
|
||||
if (entityRemoved.Info().Descriptive == DescriptiveType.Worker)
|
||||
{
|
||||
RemoveLast();
|
||||
return;
|
||||
}
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
|
||||
public string AsJson()
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
return JsonSerializer.Serialize(_buildOrder, options);
|
||||
}
|
||||
|
||||
public string BuildOrderAsYaml()
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
var serializer = new Serializer();
|
||||
stringBuilder.AppendLine(serializer.Serialize(_buildOrder));
|
||||
var buildOrderText = stringBuilder.ToString();
|
||||
return buildOrderText;
|
||||
}
|
||||
|
||||
|
||||
public List<EntityModel> GetCompletedBefore(int interval)
|
||||
{
|
||||
return (from ordersAtTime in _buildOrder.StartedOrders
|
||||
from orders in ordersAtTime.Value
|
||||
where ordersAtTime.Key + (orders.Production() == null ? 0 : orders.Production().BuildTime) <= interval
|
||||
select orders).ToList();
|
||||
}
|
||||
|
||||
public List<EntityModel> GetUndepletedHarvestPointsCompletedBefore(int interval)
|
||||
{
|
||||
return (from ordersAtTime in _buildOrder.StartedOrders
|
||||
from orders in ordersAtTime.Value
|
||||
where ordersAtTime.Key + (orders.Production() == null
|
||||
? 0
|
||||
: orders.Production().BuildTime) <= interval
|
||||
&& !orders.Harvest().IsDepleted(
|
||||
interval,
|
||||
ordersAtTime.Key + (orders.Production() == null
|
||||
? 0
|
||||
: orders.Production().BuildTime))
|
||||
where orders.Harvest() != null
|
||||
select orders).ToList();
|
||||
}
|
||||
|
||||
|
||||
public void SetName(string name)
|
||||
{
|
||||
_buildOrder.Name = name;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
return _buildOrder.Name;
|
||||
}
|
||||
|
||||
public void SetNotes(string notes)
|
||||
{
|
||||
_buildOrder.Notes = notes;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public string GetNotes()
|
||||
{
|
||||
return _buildOrder.Notes;
|
||||
}
|
||||
|
||||
public void DeprecatedSetColor(string color)
|
||||
{
|
||||
}
|
||||
|
||||
public string GetColor()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_lastInterval = 0;
|
||||
_buildOrder.Initialize(DataType.FACTION_Aru);
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public int? WillMeetTrainingQueue(EntityModel entity)
|
||||
{
|
||||
var supply = entity.Supply();
|
||||
var production = entity.Production();
|
||||
|
||||
var checkedInterval = _lastInterval;
|
||||
|
||||
if (supply == null || production == null || supply.Takes.Equals(0)) return 1;
|
||||
|
||||
var producedBy = production.ProducedBy;
|
||||
if (producedBy == null) return 1;
|
||||
|
||||
var uniqueCompleted = _buildOrder.UniqueCompleted[producedBy];
|
||||
|
||||
var shortestIncrement = int.MaxValue;
|
||||
var didDelay = false;
|
||||
|
||||
var trainingSlots = uniqueCompleted.Sum(productionEntity => productionEntity.Supply()!.Grants);
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
var usedSlots = 0;
|
||||
foreach (var used in
|
||||
_buildOrder.TrainingCapacityUsed
|
||||
.Where(used =>
|
||||
checkedInterval >= used.StartingUsageTime && checkedInterval < used.StopUsageTime))
|
||||
{
|
||||
usedSlots += used.UsedSlots;
|
||||
var duration = used.StopUsageTime - used.StartingUsageTime;
|
||||
if (duration < shortestIncrement) shortestIncrement = duration;
|
||||
}
|
||||
|
||||
if (usedSlots + supply.Takes <= trainingSlots)
|
||||
{
|
||||
if (didDelay)
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Waited", SeverityType = SeverityType.Information,
|
||||
Message = $"Had to wait {checkedInterval - _lastInterval}s for Training Queue."
|
||||
});
|
||||
|
||||
return checkedInterval;
|
||||
}
|
||||
|
||||
checkedInterval += shortestIncrement;
|
||||
didDelay = true;
|
||||
|
||||
if (shortestIncrement == int.MaxValue) return null;
|
||||
}
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private bool HandleEconomy(EntityModel entity, IEconomyService withEconomy, ref int atInterval)
|
||||
{
|
||||
var production = entity.Production();
|
||||
|
||||
if (production == null) return true;
|
||||
|
||||
for (var interval = atInterval; interval < withEconomy.GetOverTime().Count; interval++)
|
||||
{
|
||||
var economyAtSecond = withEconomy.GetOverTime()[interval];
|
||||
if (!(economyAtSecond.Alloy >= production.Alloy)
|
||||
|| !(economyAtSecond.Ether >= production.Ether)
|
||||
|| !(economyAtSecond.Pyre >= production.Pyre)) continue;
|
||||
|
||||
atInterval = interval;
|
||||
|
||||
if (entity.EntityType != EntityType.Army) atInterval += _timingService.BuildingInputDelay;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (withEconomy.GetOverTime().Last().Ether < production.Ether)
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Not Enough Ether", Message = "Build more ether extractors!",
|
||||
SeverityType = SeverityType.Error
|
||||
});
|
||||
|
||||
if (withEconomy.GetOverTime().Last().Alloy < production.Alloy)
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Not Enough Alloy", Message = "Build more bases!",
|
||||
SeverityType = SeverityType.Error
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool HandleSupply(EntityModel entity, ref int atInterval)
|
||||
{
|
||||
var minSupplyInterval = WillMeetSupply(entity);
|
||||
if (minSupplyInterval == null)
|
||||
{
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Supply Cap Reached", Message = "Build more supply!",
|
||||
SeverityType = SeverityType.Error
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (minSupplyInterval > atInterval) atInterval = (int)minSupplyInterval;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleTrainingQueue(EntityModel entity, ref int atInterval)
|
||||
{
|
||||
var minTrainingQueueInterval = WillMeetTrainingQueue(entity);
|
||||
if (minTrainingQueueInterval == null)
|
||||
{
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Invalid", Message = "Invalid Training Queue error",
|
||||
SeverityType = SeverityType.Error
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (minTrainingQueueInterval > atInterval) atInterval = (int)minTrainingQueueInterval;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private bool HandleRequirements(EntityModel entity, ref int atInterval)
|
||||
{
|
||||
var minRequirementInterval = WillMeetRequirements(entity);
|
||||
if (minRequirementInterval == null)
|
||||
{
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Missing Requirements", Message = "You don't have what's needed for this unit.",
|
||||
SeverityType = SeverityType.Error
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (minRequirementInterval > atInterval) atInterval = (int)minRequirementInterval;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Model.BuildOrders;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class DeprecatedBuildComparisionService : IBuildComparisonService
|
||||
{
|
||||
private BuildToCompareModel buildToCompare = new();
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public void SetBuilds(BuildToCompareModel buildToCompareModel)
|
||||
{
|
||||
buildToCompare = buildToCompareModel;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public BuildToCompareModel Get()
|
||||
{
|
||||
return buildToCompare;
|
||||
}
|
||||
|
||||
public string AsJson()
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
return JsonSerializer.Serialize(buildToCompare, options);
|
||||
}
|
||||
|
||||
public bool LoadJson(string data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
buildToCompare = JsonSerializer.Deserialize<BuildToCompareModel>(data, options)!;
|
||||
|
||||
// Must Hydrate because not loaded with Parts
|
||||
HydratedLoadedJson();
|
||||
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string BuildOrderAsYaml()
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
var serializer = new Serializer();
|
||||
stringBuilder.AppendLine(serializer.Serialize(buildToCompare));
|
||||
var buildOrderText = stringBuilder.ToString();
|
||||
return buildOrderText;
|
||||
}
|
||||
|
||||
private event Action OnChange = default!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
|
||||
|
||||
public void HydratedLoadedJson()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
using Model.BuildOrders;
|
||||
using Model.Economy;
|
||||
using Model.Entity;
|
||||
using Model.Entity.Data;
|
||||
using Model.Types;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class EconomyComparisionService : IEconomyComparisonService
|
||||
{
|
||||
private readonly int IntervalMax = 1024;
|
||||
|
||||
public EconomyComparisionService()
|
||||
{
|
||||
BuildsToCompare = new List<BuildToCompareModel>
|
||||
{
|
||||
new() { NumberOfTownHallExpansions = 0, Faction = DataType.FACTION_Aru, ChartColor = "green" },
|
||||
new() { NumberOfTownHallExpansions = 0, Faction = DataType.FACTION_Aru, ChartColor = "red" }
|
||||
};
|
||||
|
||||
BuildsToCompare[0].EconomyOverTimeModel = CalculateEconomy(BuildsToCompare[0]);
|
||||
BuildsToCompare[1].EconomyOverTimeModel = CalculateEconomy(BuildsToCompare[1]);
|
||||
}
|
||||
|
||||
public List<BuildToCompareModel> BuildsToCompare { get; set; }
|
||||
|
||||
|
||||
public void ChangeNumberOfTownHalls(int forPlayer, int toCount)
|
||||
{
|
||||
if (BuildsToCompare[forPlayer].NumberOfTownHallExpansions == toCount) return;
|
||||
|
||||
BuildsToCompare[forPlayer].NumberOfTownHallExpansions = toCount;
|
||||
|
||||
CalculateBuildOrder(BuildsToCompare[forPlayer]);
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void ChangeTownHallTiming(int forPlayer, int forTownHall, int toTiming)
|
||||
{
|
||||
if (BuildsToCompare[forPlayer].TimeToBuildTownHall[forTownHall] == toTiming) return;
|
||||
|
||||
BuildsToCompare[forPlayer].TimeToBuildTownHall[forTownHall] = toTiming;
|
||||
|
||||
CalculateBuildOrder(BuildsToCompare[forPlayer]);
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public int GetTownHallCount(int forPlayer)
|
||||
{
|
||||
return BuildsToCompare[forPlayer].NumberOfTownHallExpansions;
|
||||
}
|
||||
|
||||
public int GetTownHallBuildTime(int forPlayer, int forTownHall)
|
||||
{
|
||||
return BuildsToCompare[forPlayer].TimeToBuildTownHall[forTownHall];
|
||||
}
|
||||
|
||||
public List<int> GetTownHallBuildTimes(int forPlayer)
|
||||
{
|
||||
return BuildsToCompare[forPlayer].TimeToBuildTownHall;
|
||||
}
|
||||
|
||||
public void ChangeFaction(int forPlayer, string toFaction)
|
||||
{
|
||||
if (BuildsToCompare[forPlayer].Faction.Equals(toFaction)) return;
|
||||
|
||||
BuildsToCompare[forPlayer].Faction = toFaction;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public string GetFaction(int forPlayer)
|
||||
{
|
||||
return BuildsToCompare[forPlayer].Faction;
|
||||
}
|
||||
|
||||
public void ChangeColor(int forPlayer, string toColor)
|
||||
{
|
||||
if (BuildsToCompare[forPlayer].ChartColor.Equals(toColor)) return;
|
||||
|
||||
BuildsToCompare[forPlayer].ChartColor = toColor;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public string GetColor(int forPlayer)
|
||||
{
|
||||
return BuildsToCompare[forPlayer].ChartColor;
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
|
||||
private void CalculateBuildOrder(BuildToCompareModel buildToCompare)
|
||||
{
|
||||
buildToCompare.BuildOrderModel = new BuildOrderModel(buildToCompare.Faction);
|
||||
|
||||
foreach (var time in buildToCompare.TimeToBuildTownHall)
|
||||
{
|
||||
var townHall = buildToCompare.GetTownHallEntity;
|
||||
var townHallMining2 = buildToCompare.GetTownHallMining2Entity;
|
||||
|
||||
Add(townHall, buildToCompare, time);
|
||||
Add(townHallMining2, buildToCompare, time + townHall.Production()!.BuildTime);
|
||||
}
|
||||
|
||||
CalculateEconomy(buildToCompare);
|
||||
}
|
||||
|
||||
public void Add(EntityModel entityModel, BuildToCompareModel buildToCompare, int atInterval)
|
||||
{
|
||||
var buildOrder = buildToCompare.BuildOrderModel;
|
||||
|
||||
|
||||
if (!buildOrder.StartedOrders.ContainsKey(atInterval))
|
||||
buildOrder.StartedOrders.Add(atInterval, new List<EntityModel>());
|
||||
|
||||
var production = entityModel.Production();
|
||||
|
||||
var completedTime = atInterval;
|
||||
if (production != null) completedTime += production.BuildTime;
|
||||
|
||||
if (!buildOrder.CompletedOrders.ContainsKey(completedTime))
|
||||
buildOrder.CompletedOrders.Add(completedTime, new List<EntityModel>());
|
||||
|
||||
buildOrder.StartedOrders[atInterval].Add(entityModel.Clone());
|
||||
buildOrder.CompletedOrders[completedTime].Add(entityModel.Clone());
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
private List<EconomyModel> CalculateEconomy(BuildToCompareModel buildToCompare, int fromInterval = 0)
|
||||
{
|
||||
// We don't consider things mining at zero seconds
|
||||
if (fromInterval == 0) fromInterval = 1;
|
||||
|
||||
var buildOrder = buildToCompare.BuildOrderModel;
|
||||
|
||||
List<EconomyModel> buildEconomyOverTime = buildToCompare.EconomyOverTimeModel;
|
||||
|
||||
while (buildEconomyOverTime.Count < IntervalMax)
|
||||
buildEconomyOverTime.Add(new EconomyModel { Interval = buildEconomyOverTime.Count - 1 });
|
||||
|
||||
for (var interval = fromInterval; interval < IntervalMax; interval++)
|
||||
{
|
||||
buildEconomyOverTime[interval] = new EconomyModel();
|
||||
var economyAtSecond = buildEconomyOverTime[interval];
|
||||
if (interval > 0)
|
||||
{
|
||||
economyAtSecond.Alloy = buildEconomyOverTime[interval - 1].Alloy;
|
||||
economyAtSecond.Ether = buildEconomyOverTime[interval - 1].Ether;
|
||||
economyAtSecond.Pyre = buildEconomyOverTime[interval - 1].Pyre;
|
||||
economyAtSecond.WorkerCount = buildEconomyOverTime[interval - 1].WorkerCount;
|
||||
economyAtSecond.BusyWorkerCount = buildEconomyOverTime[interval - 1].BusyWorkerCount;
|
||||
economyAtSecond.CreatingWorkerCount = buildEconomyOverTime[interval - 1].CreatingWorkerCount;
|
||||
economyAtSecond.HarvestPoints = buildEconomyOverTime[interval - 1].HarvestPoints.ToList();
|
||||
economyAtSecond.CreatingWorkerDelays = buildEconomyOverTime[interval - 1].CreatingWorkerDelays.ToList();
|
||||
}
|
||||
|
||||
economyAtSecond.Interval = interval;
|
||||
|
||||
// Add funds
|
||||
float freeWorkers = economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount;
|
||||
var workersNeeded = 0;
|
||||
|
||||
economyAtSecond.HarvestPoints =
|
||||
(from harvester in buildOrder.GetHarvestersCompletedBefore(interval)
|
||||
select harvester).ToList();
|
||||
|
||||
// Add funds
|
||||
economyAtSecond.Pyre += 1;
|
||||
|
||||
// Add funds
|
||||
foreach (var entity in economyAtSecond.HarvestPoints)
|
||||
{
|
||||
var harvester = entity.Harvest();
|
||||
if (harvester.RequiresWorker)
|
||||
if (harvester.Resource == ResourceType.Alloy)
|
||||
{
|
||||
var usedWorkers = Math.Min(harvester.Slots, freeWorkers);
|
||||
economyAtSecond.Alloy += harvester.HarvestedPerInterval * usedWorkers;
|
||||
freeWorkers -= usedWorkers;
|
||||
|
||||
if (usedWorkers < harvester.Slots) workersNeeded += 1;
|
||||
}
|
||||
|
||||
if (harvester.RequiresWorker == false)
|
||||
{
|
||||
if (harvester.Resource == ResourceType.Ether)
|
||||
economyAtSecond.Ether += harvester.HarvestedPerInterval * harvester.Slots;
|
||||
|
||||
if (harvester.Resource == ResourceType.Alloy)
|
||||
economyAtSecond.Alloy += harvester.HarvestedPerInterval * harvester.Slots;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new worker
|
||||
if (economyAtSecond.CreatingWorkerCount > 0)
|
||||
for (var i = 0; i < economyAtSecond.CreatingWorkerDelays.Count; i++)
|
||||
if (economyAtSecond.CreatingWorkerDelays[i] > 0)
|
||||
{
|
||||
if (economyAtSecond.Alloy > 2.5f)
|
||||
{
|
||||
economyAtSecond.Alloy -= 2.5f;
|
||||
economyAtSecond.CreatingWorkerDelays[i]--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
economyAtSecond.CreatingWorkerCount -= 1;
|
||||
economyAtSecond.WorkerCount += 1;
|
||||
economyAtSecond.CreatingWorkerDelays.Remove(i);
|
||||
i--;
|
||||
}
|
||||
|
||||
if (workersNeeded > economyAtSecond.CreatingWorkerCount)
|
||||
{
|
||||
economyAtSecond.CreatingWorkerCount += 1;
|
||||
economyAtSecond.CreatingWorkerDelays.Add(50);
|
||||
}
|
||||
|
||||
// Remove Funds from Build Order
|
||||
|
||||
if (buildOrder.StartedOrders.TryGetValue(interval, out var ordersAtTime))
|
||||
foreach (var order in ordersAtTime)
|
||||
{
|
||||
var foundEntity = EntityModel.GetDictionary()[order.DataType];
|
||||
var production = foundEntity.Production();
|
||||
|
||||
if (production != null)
|
||||
{
|
||||
economyAtSecond.Alloy -= production.Alloy;
|
||||
economyAtSecond.Ether -= production.Ether;
|
||||
economyAtSecond.Pyre -= production.Pyre;
|
||||
var finishedAt = interval + production.BuildTime;
|
||||
|
||||
if (production.RequiresWorker) economyAtSecond.BusyWorkerCount += 1;
|
||||
|
||||
if (production.ConsumesWorker) economyAtSecond.WorkerCount -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle new entities
|
||||
if (buildOrder.CompletedOrders.TryGetValue(interval, out var completedAtInterval))
|
||||
foreach (var newEntity in completedAtInterval)
|
||||
{
|
||||
var harvest = newEntity;
|
||||
if (harvest != null) economyAtSecond.HarvestPoints.Add(harvest);
|
||||
|
||||
var production = newEntity.Production();
|
||||
if (production != null && production.RequiresWorker) economyAtSecond.BusyWorkerCount -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return buildEconomyOverTime;
|
||||
}
|
||||
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
using Model.Economy;
|
||||
using Model.Entity;
|
||||
using Model.Entity.Parts;
|
||||
using Model.Types;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class EconomyService : IEconomyService
|
||||
{
|
||||
private List<EconomyModel>? buildEconomyOverTime;
|
||||
|
||||
public List<EconomyModel> GetOverTime()
|
||||
{
|
||||
return buildEconomyOverTime;
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public void Calculate(IBuildOrderService buildOrder, ITimingService timing, int fromInterval)
|
||||
{
|
||||
// We don't consider things mining at zero seconds
|
||||
if (fromInterval == 0) fromInterval = 1;
|
||||
|
||||
if (buildEconomyOverTime == null)
|
||||
{
|
||||
buildEconomyOverTime = [];
|
||||
for (var interval = 0; interval < timing.GetAttackTime(); interval++)
|
||||
buildEconomyOverTime.Add(new EconomyModel { Interval = interval });
|
||||
}
|
||||
|
||||
if (buildEconomyOverTime.Count > timing.GetAttackTime())
|
||||
buildEconomyOverTime.RemoveRange(timing.GetAttackTime(),
|
||||
buildEconomyOverTime.Count - timing.GetAttackTime());
|
||||
|
||||
while (buildEconomyOverTime.Count < timing.GetAttackTime())
|
||||
buildEconomyOverTime.Add(new EconomyModel { Interval = buildEconomyOverTime.Count - 1 });
|
||||
|
||||
for (var interval = fromInterval; interval < timing.GetAttackTime(); interval++)
|
||||
{
|
||||
buildEconomyOverTime[interval] = new EconomyModel();
|
||||
|
||||
var economyAtSecond = buildEconomyOverTime[interval];
|
||||
|
||||
CarryOverEconomyFromPreviousInterval(interval, economyAtSecond);
|
||||
|
||||
SetupCurrentInterval(buildOrder, economyAtSecond, interval);
|
||||
AddPassivePyreGain(interval, economyAtSecond);
|
||||
float freeWorkers = economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount;
|
||||
var workersNeeded = AddFundsFromHarvestPoints(economyAtSecond, freeWorkers);
|
||||
workersNeeded -= CalculateCreatingWorkerCosts(economyAtSecond);
|
||||
MakeNeededNewWorkersRequests(workersNeeded, economyAtSecond);
|
||||
SubtractFundsOnRequestedOrders(buildOrder, interval, economyAtSecond);
|
||||
HandledAddingNewHarvestPointsAndWorkersToEconomy(buildOrder, interval, economyAtSecond);
|
||||
}
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
|
||||
public EconomyModel GetEconomy(int atInterval)
|
||||
{
|
||||
return atInterval >= buildEconomyOverTime.Count
|
||||
? buildEconomyOverTime.Last()
|
||||
: buildEconomyOverTime[atInterval];
|
||||
}
|
||||
|
||||
private static void SetupCurrentInterval(
|
||||
IBuildOrderService buildOrder,
|
||||
EconomyModel economyAtSecond,
|
||||
int interval)
|
||||
{
|
||||
economyAtSecond.Interval = interval;
|
||||
economyAtSecond.HarvestPoints =
|
||||
(from harvester
|
||||
in buildOrder
|
||||
.GetUndepletedHarvestPointsCompletedBefore(interval +
|
||||
1) // One second into the future for completed harvest points
|
||||
select harvester).ToList();
|
||||
}
|
||||
|
||||
private static void HandledAddingNewHarvestPointsAndWorkersToEconomy(IBuildOrderService buildOrder, int interval,
|
||||
EconomyModel economyAtSecond)
|
||||
{
|
||||
if (!buildOrder.CompletedOrders.TryGetValue(interval, out var completedAtInterval)) return;
|
||||
|
||||
foreach (var newEntity in completedAtInterval)
|
||||
{
|
||||
var entity = newEntity.Clone();
|
||||
//entity.Harvest().StartedAt = interval;
|
||||
economyAtSecond.HarvestPoints.Add(entity);
|
||||
|
||||
var production = newEntity.Production();
|
||||
if (production is { RequiresWorker: true }) economyAtSecond.BusyWorkerCount -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SubtractFundsOnRequestedOrders(IBuildOrderService buildOrder, int interval,
|
||||
EconomyModel economyAtSecond)
|
||||
{
|
||||
if (!buildOrder.StartedOrders.TryGetValue(interval, out var ordersAtTime)) return;
|
||||
|
||||
foreach (var production in
|
||||
ordersAtTime.Select(order => EntityModel.GetDictionary()[order.DataType])
|
||||
.Select(foundEntity => foundEntity.Production())
|
||||
.OfType<EntityProductionModel>())
|
||||
{
|
||||
economyAtSecond.Alloy -= production.Alloy;
|
||||
economyAtSecond.Ether -= production.Ether;
|
||||
economyAtSecond.Pyre -= production.Pyre;
|
||||
|
||||
if (production.RequiresWorker) economyAtSecond.BusyWorkerCount += 1;
|
||||
if (production.ConsumesWorker) economyAtSecond.WorkerCount -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void MakeNeededNewWorkersRequests(int workersNeeded, EconomyModel economyAtSecond)
|
||||
{
|
||||
if (workersNeeded <= economyAtSecond.CreatingWorkerCount) return;
|
||||
|
||||
economyAtSecond.CreatingWorkerCount += 1;
|
||||
economyAtSecond.CreatingWorkerDelays.Add(20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of workers created
|
||||
*/
|
||||
private static int CalculateCreatingWorkerCosts(EconomyModel economyAtSecond)
|
||||
{
|
||||
var createdWorkers = 0;
|
||||
|
||||
if (economyAtSecond.CreatingWorkerCount <= 0) return createdWorkers;
|
||||
|
||||
for (var i = 0; i < economyAtSecond.CreatingWorkerDelays.Count; i++)
|
||||
if (economyAtSecond.CreatingWorkerDelays[i] > 0)
|
||||
{
|
||||
if (!(economyAtSecond.Alloy > 2.5f)) continue;
|
||||
|
||||
economyAtSecond.Alloy -= 2.5f;
|
||||
economyAtSecond.CreatingWorkerDelays[i]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
economyAtSecond.CreatingWorkerCount -= 1;
|
||||
economyAtSecond.WorkerCount += 1;
|
||||
createdWorkers++;
|
||||
economyAtSecond.CreatingWorkerDelays.Remove(i);
|
||||
i--;
|
||||
}
|
||||
|
||||
return createdWorkers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns needed workers to maximize harvest points
|
||||
*/
|
||||
private static int AddFundsFromHarvestPoints(EconomyModel economyAtSecond, float freeWorkers)
|
||||
{
|
||||
var workersNeeded = 0;
|
||||
|
||||
|
||||
foreach (var harvesterPoint in
|
||||
economyAtSecond.HarvestPoints.Select(entity => entity.Harvest()))
|
||||
//if (harvesterPoint.IsDepleted(economyAtSecond.Interval))
|
||||
// continue;
|
||||
switch (harvesterPoint.RequiresWorker)
|
||||
{
|
||||
case true:
|
||||
{
|
||||
if (harvesterPoint.Resource == ResourceType.Alloy)
|
||||
{
|
||||
var usedWorkers = Math.Min(harvesterPoint.Slots, freeWorkers);
|
||||
|
||||
economyAtSecond.Alloy += harvesterPoint.HarvestedPerInterval * usedWorkers;
|
||||
economyAtSecond.AlloyIncome += harvesterPoint.HarvestedPerInterval * usedWorkers;
|
||||
|
||||
freeWorkers -= usedWorkers;
|
||||
|
||||
if (usedWorkers < harvesterPoint.Slots) workersNeeded += 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case false:
|
||||
{
|
||||
switch (harvesterPoint.Resource)
|
||||
{
|
||||
case ResourceType.Ether:
|
||||
economyAtSecond.Ether += harvesterPoint.HarvestedPerInterval * harvesterPoint.Slots;
|
||||
economyAtSecond.EtherIncome += harvesterPoint.HarvestedPerInterval * harvesterPoint.Slots;
|
||||
break;
|
||||
case ResourceType.Alloy:
|
||||
economyAtSecond.Alloy += harvesterPoint.HarvestedPerInterval * harvesterPoint.Slots;
|
||||
economyAtSecond.AlloyIncome += harvesterPoint.HarvestedPerInterval * harvesterPoint.Slots;
|
||||
break;
|
||||
case ResourceType.Pyre:
|
||||
break; // Pyre Miner?
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return workersNeeded;
|
||||
}
|
||||
|
||||
private static void AddPassivePyreGain(int interval, EconomyModel economyAtSecond)
|
||||
{
|
||||
if (interval % 3 == 0) economyAtSecond.Pyre += 1;
|
||||
}
|
||||
|
||||
private void CarryOverEconomyFromPreviousInterval(int interval, EconomyModel economyAtSecond)
|
||||
{
|
||||
if (interval <= 0) return;
|
||||
|
||||
economyAtSecond.Alloy = buildEconomyOverTime[interval - 1].Alloy;
|
||||
economyAtSecond.Ether = buildEconomyOverTime[interval - 1].Ether;
|
||||
economyAtSecond.Pyre = buildEconomyOverTime[interval - 1].Pyre;
|
||||
economyAtSecond.WorkerCount = buildEconomyOverTime[interval - 1].WorkerCount;
|
||||
economyAtSecond.BusyWorkerCount = buildEconomyOverTime[interval - 1].BusyWorkerCount;
|
||||
economyAtSecond.CreatingWorkerCount = buildEconomyOverTime[interval - 1].CreatingWorkerCount;
|
||||
economyAtSecond.HarvestPoints = buildEconomyOverTime[interval - 1].HarvestPoints.ToList();
|
||||
economyAtSecond.CreatingWorkerDelays = buildEconomyOverTime[interval - 1].CreatingWorkerDelays.ToList();
|
||||
}
|
||||
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using Services.Website;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class EntityViewType
|
||||
{
|
||||
public static string Detailed = "Detailed";
|
||||
public static string Plain = "Plain";
|
||||
}
|
||||
|
||||
public class EntityDisplayService : IEntityDisplayService
|
||||
{
|
||||
private string _displayType;
|
||||
|
||||
public EntityDisplayService(IStorageService storageService)
|
||||
{
|
||||
_displayType = storageService.GetValue<bool>(StorageKeys.IsPlainView)
|
||||
? EntityViewType.Plain
|
||||
: EntityViewType.Detailed;
|
||||
}
|
||||
|
||||
|
||||
public List<string> DefaultChoices()
|
||||
{
|
||||
return new List<string> { EntityViewType.Detailed, EntityViewType.Plain };
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public string GetDisplayType()
|
||||
{
|
||||
return _displayType;
|
||||
}
|
||||
|
||||
public void SetDisplayType(string displayType)
|
||||
{
|
||||
_displayType = displayType;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
using Model.Entity.Data;
|
||||
using static Services.IEntityFilterService;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public enum EntityFilterEvent
|
||||
{
|
||||
OnRefreshFaction,
|
||||
OnRefreshImmortal,
|
||||
OnRefreshEntity,
|
||||
OnRefreshSearch
|
||||
}
|
||||
|
||||
public class EntityFilterService : IEntityFilterService
|
||||
{
|
||||
private readonly List<string> _entityChoices = new();
|
||||
|
||||
private readonly List<string> _factionChoices = new()
|
||||
{ DataType.Any, DataType.FACTION_QRath, DataType.FACTION_Aru };
|
||||
|
||||
private readonly List<string> _immortalChoices = new();
|
||||
private string _entityType = EntityType.Army;
|
||||
private string _searchText = "";
|
||||
private string _selectedFaction = DataType.Any;
|
||||
private string _selectedImmortal = DataType.Any;
|
||||
|
||||
public EntityFilterService()
|
||||
{
|
||||
RefreshImmortalChoices();
|
||||
RefreshEntityChoices();
|
||||
}
|
||||
|
||||
public void Subscribe(EntityFilterAction action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(EntityFilterAction action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public string GetEntityType()
|
||||
{
|
||||
return _entityType;
|
||||
}
|
||||
|
||||
public string GetFactionType()
|
||||
{
|
||||
return _selectedFaction;
|
||||
}
|
||||
|
||||
public string GetImmortalType()
|
||||
{
|
||||
return _selectedImmortal;
|
||||
}
|
||||
|
||||
|
||||
public bool SelectFactionType(string factionType)
|
||||
{
|
||||
if (_selectedFaction == factionType)
|
||||
{
|
||||
_selectedFaction = DataType.None;
|
||||
_selectedImmortal = DataType.None;
|
||||
|
||||
RefreshImmortalChoices();
|
||||
RefreshEntityChoices();
|
||||
|
||||
NotifyDataChanged(EntityFilterEvent.OnRefreshFaction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_selectedFaction = factionType;
|
||||
_selectedImmortal = DataType.Any;
|
||||
|
||||
RefreshImmortalChoices();
|
||||
RefreshEntityChoices();
|
||||
|
||||
NotifyDataChanged(EntityFilterEvent.OnRefreshFaction);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SelectImmortalType(string immortalType)
|
||||
{
|
||||
if (_selectedImmortal == immortalType)
|
||||
{
|
||||
_selectedImmortal = DataType.None;
|
||||
NotifyDataChanged(EntityFilterEvent.OnRefreshImmortal);
|
||||
return true;
|
||||
}
|
||||
|
||||
_selectedImmortal = immortalType;
|
||||
NotifyDataChanged(EntityFilterEvent.OnRefreshImmortal);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SelectEntityType(string entityType)
|
||||
{
|
||||
if (_entityType == entityType) return false;
|
||||
_entityType = entityType;
|
||||
NotifyDataChanged(EntityFilterEvent.OnRefreshEntity);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool EnterSearchText(string searchText)
|
||||
{
|
||||
if (_searchText.Equals(searchText))
|
||||
return false;
|
||||
_searchText = searchText;
|
||||
NotifyDataChanged(EntityFilterEvent.OnRefreshSearch);
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<string> GetFactionChoices()
|
||||
{
|
||||
return _factionChoices;
|
||||
}
|
||||
|
||||
public List<string> GetImmortalChoices()
|
||||
{
|
||||
return _immortalChoices;
|
||||
}
|
||||
|
||||
public List<string> GetEntityChoices()
|
||||
{
|
||||
return _entityChoices;
|
||||
}
|
||||
|
||||
public string GetSearchText()
|
||||
{
|
||||
return _searchText;
|
||||
}
|
||||
|
||||
private event EntityFilterAction OnChange = null!;
|
||||
|
||||
private void RefreshImmortalChoices()
|
||||
{
|
||||
_immortalChoices.Clear();
|
||||
|
||||
//TODO Consider getting these values from the database
|
||||
/*if (_selectedFaction == FactionType.QRath || _selectedFaction == FactionType.Any) {
|
||||
_immortalChoices.Add(ImmortalType.Orzum);
|
||||
_immortalChoices.Add(ImmortalType.Ajari);
|
||||
}
|
||||
|
||||
if (_selectedFaction == FactionType.Aru || _selectedFaction == FactionType.Any) {
|
||||
_immortalChoices.Add(ImmortalType.Mala);
|
||||
_immortalChoices.Add(ImmortalType.Xol);
|
||||
}*/
|
||||
|
||||
if (_selectedFaction == DataType.FACTION_QRath || _selectedFaction == DataType.Any)
|
||||
{
|
||||
_immortalChoices.Add(DataType.IMMORTAL_Orzum);
|
||||
_immortalChoices.Add(DataType.IMMORTAL_Ajari);
|
||||
}
|
||||
|
||||
if (_selectedFaction == DataType.FACTION_Aru || _selectedFaction == DataType.Any)
|
||||
{
|
||||
_immortalChoices.Add(DataType.IMMORTAL_Atzlan);
|
||||
_immortalChoices.Add(DataType.IMMORTAL_Mala);
|
||||
_immortalChoices.Add(DataType.IMMORTAL_Xol);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshEntityChoices()
|
||||
{
|
||||
_entityChoices.Clear();
|
||||
|
||||
if (_selectedFaction == DataType.FACTION_QRath || _selectedFaction == DataType.FACTION_Aru ||
|
||||
_selectedFaction == DataType.Any)
|
||||
{
|
||||
_entityChoices.Add(EntityType.Army);
|
||||
_entityChoices.Add(EntityType.Immortal);
|
||||
_entityChoices.Add(EntityType.Passive);
|
||||
_entityChoices.Add(EntityType.Building);
|
||||
_entityChoices.Add(EntityType.Tech);
|
||||
_entityChoices.Add(EntityType.Ability);
|
||||
_entityChoices.Add(EntityType.Pyre_Spell);
|
||||
_entityChoices.Add(EntityType.Worker);
|
||||
}
|
||||
|
||||
if (_selectedFaction == DataType.Any) _entityChoices.Add(EntityType.Any);
|
||||
}
|
||||
|
||||
|
||||
private void NotifyDataChanged(EntityFilterEvent entityFilterEvent)
|
||||
{
|
||||
OnChange?.Invoke(entityFilterEvent);
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Model.Entity;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class EntityService : IEntityService
|
||||
{
|
||||
public List<EntityModel> GetEntities()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Model.Entity.Data;
|
||||
using Services.Website;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class ImmortalSelectionService : IImmortalSelectionService, IDisposable
|
||||
{
|
||||
private readonly IStorageService _storageService;
|
||||
private string _selectedFaction = DataType.FACTION_QRath;
|
||||
private string _selectedImmortal = DataType.IMMORTAL_Orzum;
|
||||
|
||||
public ImmortalSelectionService(IStorageService storageService)
|
||||
{
|
||||
_storageService = storageService;
|
||||
|
||||
_storageService.Subscribe(RefreshDefaults);
|
||||
|
||||
RefreshDefaults();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_storageService.Unsubscribe(RefreshDefaults);
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public string GetFaction()
|
||||
{
|
||||
return _selectedFaction;
|
||||
}
|
||||
|
||||
public string GetImmortal()
|
||||
{
|
||||
return _selectedImmortal;
|
||||
}
|
||||
|
||||
public bool SelectFaction(string faction)
|
||||
{
|
||||
if (_selectedFaction == faction) return false;
|
||||
_selectedFaction = faction;
|
||||
|
||||
if (_selectedFaction == DataType.FACTION_QRath) _selectedImmortal = DataType.IMMORTAL_Orzum;
|
||||
|
||||
if (_selectedFaction == DataType.FACTION_Aru) _selectedImmortal = DataType.IMMORTAL_Mala;
|
||||
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SelectImmortal(string immortal)
|
||||
{
|
||||
if (_selectedImmortal == immortal) return false;
|
||||
_selectedImmortal = immortal;
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RefreshDefaults()
|
||||
{
|
||||
var foundFaction = _storageService.GetValue<string?>(StorageKeys.SelectedFaction);
|
||||
var foundImmortal = _storageService.GetValue<string?>(StorageKeys.SelectedImmortal);
|
||||
|
||||
if (foundFaction != null) _selectedFaction = foundFaction;
|
||||
|
||||
if (foundImmortal != null) _selectedImmortal = foundImmortal;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using Model.Hotkeys;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class KeyService : IKeyService
|
||||
{
|
||||
private static readonly List<string> PressedKeys = new();
|
||||
private string? _hotkey;
|
||||
private string _hotkeyGroup = "C";
|
||||
private bool _isHoldingSpace;
|
||||
|
||||
|
||||
public void Subscribe(Action? action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action? action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public bool AddPressedKey(string key)
|
||||
{
|
||||
_hotkey = null;
|
||||
|
||||
if (PressedKeys.Count > 0) return false;
|
||||
var pressedKey = key.ToUpper();
|
||||
|
||||
if (pressedKey.Equals(" ") || pressedKey.Equals("SPACE"))
|
||||
{
|
||||
if (!_isHoldingSpace)
|
||||
{
|
||||
_isHoldingSpace = true;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PressedKeys.Contains(pressedKey))
|
||||
{
|
||||
if (HotkeyModel.KeyGroups.Contains(pressedKey)) _hotkeyGroup = pressedKey;
|
||||
|
||||
if (HotkeyModel.HotKeys.Contains(pressedKey)) _hotkey = pressedKey;
|
||||
|
||||
PressedKeys.Add(pressedKey);
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<string> GetAllPressedKeys()
|
||||
{
|
||||
return PressedKeys;
|
||||
}
|
||||
|
||||
public bool RemovePressedKey(string key)
|
||||
{
|
||||
_hotkey = null;
|
||||
|
||||
var pressedKey = key.ToUpper();
|
||||
if (pressedKey.Equals(" ") || pressedKey.Equals("SPACE"))
|
||||
{
|
||||
if (_isHoldingSpace || true)
|
||||
{
|
||||
_isHoldingSpace = false;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PressedKeys.Contains(pressedKey))
|
||||
{
|
||||
PressedKeys.Remove(pressedKey);
|
||||
NotifyDataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsHoldingSpace()
|
||||
{
|
||||
return _isHoldingSpace;
|
||||
}
|
||||
|
||||
public string? GetHotkey()
|
||||
{
|
||||
return _hotkey;
|
||||
}
|
||||
|
||||
public string GetHotkeyGroup()
|
||||
{
|
||||
return _hotkeyGroup;
|
||||
}
|
||||
|
||||
private event Action? OnChange;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using Model.Entity;
|
||||
using Model.Entity.Data;
|
||||
using Model.MemoryTester;
|
||||
using static Services.IMemoryTesterService;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public enum MemoryTesterEvent
|
||||
{
|
||||
OnVerify,
|
||||
OnRefresh
|
||||
}
|
||||
|
||||
public class MemoryTesterService : IMemoryTesterService
|
||||
{
|
||||
private readonly List<MemoryEntityModel> memoryEntities = MemoryEntityModel.TestData;
|
||||
private readonly List<MemoryQuestionModel> memoryQuestions = MemoryQuestionModel.TestData;
|
||||
|
||||
|
||||
private readonly Random random = new();
|
||||
|
||||
|
||||
public void Subscribe(MemoryAction action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(MemoryAction action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public void GenerateQuiz()
|
||||
{
|
||||
memoryEntities.Clear();
|
||||
memoryQuestions.Clear();
|
||||
|
||||
//TODO redo this
|
||||
var units = (from entity in EntityModel.GetListOnlyHotkey()
|
||||
where entity.EntityType == EntityType.Army
|
||||
where entity.Weapons().Count > 0
|
||||
select entity).OrderBy(entity => random.Next()).Take(4).ToList();
|
||||
|
||||
var entityIndex = 0;
|
||||
var questionIndex = 0;
|
||||
|
||||
foreach (var unit in units)
|
||||
{
|
||||
memoryEntities.Add(new MemoryEntityModel
|
||||
{
|
||||
Id = ++entityIndex,
|
||||
Name = unit.Info().Name
|
||||
});
|
||||
|
||||
var weaponIndex = 0;
|
||||
foreach (var weapon in unit.Weapons())
|
||||
{
|
||||
weaponIndex++;
|
||||
|
||||
memoryQuestions.Add(new MemoryQuestionModel
|
||||
{
|
||||
Id = ++questionIndex,
|
||||
MemoryEntityModelId = entityIndex,
|
||||
Name = $"Range (Weapon {weaponIndex})",
|
||||
Answer = weapon.Range,
|
||||
IsRevealed = entityIndex == 1 || entityIndex == 3
|
||||
});
|
||||
}
|
||||
|
||||
memoryQuestions.Add(new MemoryQuestionModel
|
||||
{
|
||||
Id = ++questionIndex,
|
||||
MemoryEntityModelId = entityIndex,
|
||||
Name = "Speed",
|
||||
Answer = (int)unit.Movement().Speed,
|
||||
IsRevealed = entityIndex == 1 || entityIndex == 2
|
||||
});
|
||||
}
|
||||
|
||||
NotifyDataChanged(MemoryTesterEvent.OnRefresh);
|
||||
}
|
||||
|
||||
public List<MemoryEntityModel> GetEntities()
|
||||
{
|
||||
return memoryEntities;
|
||||
}
|
||||
|
||||
public List<MemoryQuestionModel> GetQuestions()
|
||||
{
|
||||
return memoryQuestions;
|
||||
}
|
||||
|
||||
public void Update(MemoryQuestionModel memoryQuestion)
|
||||
{
|
||||
memoryQuestions[memoryQuestion.Id - 1].Guess = memoryQuestion.Guess;
|
||||
}
|
||||
|
||||
public void Verify()
|
||||
{
|
||||
NotifyDataChanged(MemoryTesterEvent.OnVerify);
|
||||
}
|
||||
|
||||
|
||||
private event MemoryAction OnChange = null!;
|
||||
|
||||
|
||||
//public delegate void MemoryAction(MemoryTesterActions memoryAction);
|
||||
|
||||
private void NotifyDataChanged(MemoryTesterEvent memoryAction)
|
||||
{
|
||||
OnChange?.Invoke(memoryAction);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using Services.Website;
|
||||
|
||||
namespace Services.Immortal;
|
||||
|
||||
public class TimingService : ITimingService, IDisposable
|
||||
{
|
||||
private readonly IStorageService _storageService;
|
||||
private int attackTime = 1500;
|
||||
private int travelTime = 30;
|
||||
|
||||
public TimingService(IStorageService storageService)
|
||||
{
|
||||
_storageService = storageService;
|
||||
|
||||
_storageService.Subscribe(RefreshDefaults);
|
||||
|
||||
RefreshDefaults();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_storageService.Unsubscribe(RefreshDefaults);
|
||||
}
|
||||
|
||||
public void Subscribe(Action? action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action? action)
|
||||
{
|
||||
OnChange -= action;
|
||||
}
|
||||
|
||||
public int BuildingInputDelay { get; set; } = 2;
|
||||
public int WaitTime { get; set; } = 30;
|
||||
public int WaitTo { get; set; } = 60;
|
||||
|
||||
public int GetAttackTime()
|
||||
{
|
||||
return attackTime;
|
||||
}
|
||||
|
||||
public void SetAttackTime(int timing)
|
||||
{
|
||||
if (attackTime != timing)
|
||||
{
|
||||
attackTime = timing;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int GetTravelTime()
|
||||
{
|
||||
return travelTime;
|
||||
}
|
||||
|
||||
public void SetTravelTime(int timing)
|
||||
{
|
||||
if (travelTime != timing)
|
||||
{
|
||||
travelTime = timing;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshDefaults()
|
||||
{
|
||||
//TODO Timing has changed in Storage
|
||||
//TODO Timing has changed in itself
|
||||
|
||||
var foundAttackTime = _storageService.GetValue<int?>(StorageKeys.AttackTime);
|
||||
var foundTravelTime = _storageService.GetValue<int?>(StorageKeys.TravelTime);
|
||||
|
||||
var foundBuildInputDefault = _storageService.GetValue<int?>(StorageKeys.BuildInputDelay);
|
||||
|
||||
var foundWaitTime = _storageService.GetValue<int?>(StorageKeys.WaitTime);
|
||||
var foundWaitTo = _storageService.GetValue<int?>(StorageKeys.WaitTo);
|
||||
|
||||
if (foundAttackTime != null) attackTime = (int)foundAttackTime;
|
||||
if (foundTravelTime != null) travelTime = (int)foundTravelTime;
|
||||
|
||||
if (foundBuildInputDefault != null) BuildingInputDelay = (int)foundBuildInputDefault;
|
||||
if (foundWaitTime != null) WaitTime = (int)foundWaitTime;
|
||||
if (foundWaitTo != null) WaitTo = (int)foundWaitTo;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
private event Action? OnChange;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DefineConstants>TRACE;NO_SQL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DefineConstants>TRACE;NO_SQL;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blazor-Analytics" Version="3.11.0"/>
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0-preview.1"/>
|
||||
<PackageReference Include="Microsoft.JSInterop" Version="8.0.14"/>
|
||||
<PackageReference Include="YamlDotNet" Version="11.2.1"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Model\Model.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,45 @@
|
||||
using Blazor.Analytics;
|
||||
|
||||
namespace Services.Website;
|
||||
|
||||
public class DataCollectionKeys
|
||||
{
|
||||
// Inputs people are using in the build calculator
|
||||
public static string BuildCalcInput = "buildcalc-input";
|
||||
public static string PageInitialized = "page-initialized";
|
||||
public static string FirstPage = "first-page";
|
||||
}
|
||||
|
||||
public class DataCollectionService : IDataCollectionService, IDisposable
|
||||
{
|
||||
private readonly IAnalytics _globalTracking;
|
||||
private readonly IStorageService _storageService;
|
||||
|
||||
private bool _isEnabled;
|
||||
|
||||
public DataCollectionService(IAnalytics globalTracking,
|
||||
IStorageService storageService)
|
||||
{
|
||||
_globalTracking = globalTracking;
|
||||
_storageService = storageService;
|
||||
|
||||
_storageService.Subscribe(Refresh);
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void SendEvent<T>(string eventName, T eventData)
|
||||
{
|
||||
if (_isEnabled) _globalTracking.TrackEvent(eventName, eventData);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_storageService.Unsubscribe(Refresh);
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
_isEnabled = _storageService.GetValue<bool>(StorageKeys.EnabledDataCollection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
namespace Services.Website;
|
||||
|
||||
//TODO Move to a database folder, with EntityService, EntityFilterService
|
||||
public class EntityDialogService : IEntityDialogService
|
||||
{
|
||||
private readonly List<string> history = new();
|
||||
private string? entityId;
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void AddDialog(string id)
|
||||
{
|
||||
entityId = id;
|
||||
history.Add(id);
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void CloseDialog()
|
||||
{
|
||||
entityId = null;
|
||||
history.Clear();
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void BackDialog()
|
||||
{
|
||||
if (history.Count > 1)
|
||||
{
|
||||
history.RemoveAt(history.Count - 1);
|
||||
|
||||
if (history.Count == 0)
|
||||
{
|
||||
entityId = null;
|
||||
NotifyDataChanged();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
entityId = history.Last();
|
||||
NotifyDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool HasDialog()
|
||||
{
|
||||
return entityId != null;
|
||||
}
|
||||
|
||||
public bool HasHistory()
|
||||
{
|
||||
return history.Count > 1;
|
||||
}
|
||||
|
||||
public string? GetEntityId()
|
||||
{
|
||||
return entityId;
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Services.Website;
|
||||
|
||||
public class DialogContents
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string ConfirmButtonLabel { get; set; }
|
||||
public EventCallback<EventArgs> OnConfirm { get; set; }
|
||||
public EventCallback<EventArgs> OnCancel { get; set; }
|
||||
}
|
||||
|
||||
public class MyDialogService : IMyDialogService
|
||||
{
|
||||
private DialogContents _dialogContents;
|
||||
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Show(DialogContents dialogContents)
|
||||
{
|
||||
_dialogContents = dialogContents;
|
||||
IsVisible = true;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public DialogContents GetDialogContents()
|
||||
{
|
||||
return _dialogContents;
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
IsVisible = false;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using Model.Website.Enums;
|
||||
|
||||
namespace Services.Website;
|
||||
|
||||
public class NavigationService : INavigationService
|
||||
{
|
||||
private int navigationStateId = -1;
|
||||
private string navigationStateType = NavigationStateType.Default;
|
||||
|
||||
private NavSelectionType navSelectionType = NavSelectionType.None;
|
||||
|
||||
|
||||
private Type renderType = null!;
|
||||
private int webPageType;
|
||||
private int webSectionType;
|
||||
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void ChangeNavigationSectionId(int newState)
|
||||
{
|
||||
navigationStateId = newState;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public int GetNavigationSectionId()
|
||||
{
|
||||
return navigationStateId;
|
||||
}
|
||||
|
||||
public void ChangeNavigationState(string newState)
|
||||
{
|
||||
if (newState.Equals(navigationStateType))
|
||||
return;
|
||||
|
||||
navigationStateType = newState;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public string GetNavigationState()
|
||||
{
|
||||
return navigationStateType;
|
||||
}
|
||||
|
||||
public void SelectPage(int pageType, Type page)
|
||||
{
|
||||
if (renderType != page)
|
||||
{
|
||||
renderType = page;
|
||||
webPageType = pageType;
|
||||
navSelectionType = NavSelectionType.Page;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SelectSection(int section)
|
||||
{
|
||||
if (section == webSectionType) return;
|
||||
webSectionType = section;
|
||||
navSelectionType = NavSelectionType.Section;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void Back()
|
||||
{
|
||||
if (navSelectionType == NavSelectionType.Page)
|
||||
{
|
||||
navSelectionType = NavSelectionType.Section;
|
||||
webPageType = 0;
|
||||
NotifyDataChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (navSelectionType == NavSelectionType.Section)
|
||||
{
|
||||
navSelectionType = NavSelectionType.None;
|
||||
webSectionType = 0;
|
||||
webPageType = 0;
|
||||
NotifyDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public NavSelectionType GetNavSelectionType()
|
||||
{
|
||||
return navSelectionType;
|
||||
}
|
||||
|
||||
public int GetWebPageId()
|
||||
{
|
||||
return webPageType;
|
||||
}
|
||||
|
||||
public int GetWebSectionId()
|
||||
{
|
||||
return webSectionType;
|
||||
}
|
||||
|
||||
public Type GetRenderType()
|
||||
{
|
||||
return renderType;
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Services.Website;
|
||||
|
||||
public class PermissionService : IPermissionService, IDisposable
|
||||
{
|
||||
private readonly IStorageService _storageService;
|
||||
private IJSRuntime _jsRuntime;
|
||||
private IToastService _toastService;
|
||||
private bool isLoaded;
|
||||
private bool isStorageEnabled = false;
|
||||
|
||||
public PermissionService(IJSRuntime jsRuntime, IToastService toastService, IStorageService storageService)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
_toastService = toastService;
|
||||
_storageService = storageService;
|
||||
|
||||
_storageService.Subscribe(NotifyDataChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_storageService.Unsubscribe(NotifyDataChanged);
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public bool GetIsStorageEnabled()
|
||||
{
|
||||
return _storageService.GetValue<bool>(StorageKeys.EnabledStorage);
|
||||
}
|
||||
|
||||
public bool GetIsDataCollectionEnabled()
|
||||
{
|
||||
return _storageService.GetValue<bool>(StorageKeys.EnabledDataCollection);
|
||||
}
|
||||
|
||||
public void SetIsStorageEnabled(bool isEnabled)
|
||||
{
|
||||
_storageService.SetValue(StorageKeys.EnabledStorage, isEnabled);
|
||||
}
|
||||
|
||||
public void SetIsDataCollectionEnabled(bool isEnabled)
|
||||
{
|
||||
_storageService.SetValue(StorageKeys.EnabledDataCollection, isEnabled);
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using Model.Entity.Data;
|
||||
using Model.Website;
|
||||
using Model.Website.Data;
|
||||
|
||||
namespace Services.Website;
|
||||
|
||||
public class SearchService : ISearchService
|
||||
{
|
||||
private readonly INoteService noteService;
|
||||
|
||||
private bool isLoaded;
|
||||
|
||||
public SearchService(INoteService noteService)
|
||||
{
|
||||
this.noteService = noteService;
|
||||
}
|
||||
|
||||
public List<SearchPointModel> SearchPoints { get; set; } = new();
|
||||
|
||||
public Dictionary<string, List<SearchPointModel>> Searches { get; set; } = new();
|
||||
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Search(string entityId)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task Load()
|
||||
{
|
||||
await noteService.Load();
|
||||
|
||||
|
||||
Searches.Add("Pages", new List<SearchPointModel>());
|
||||
Searches.Add("Notes", new List<SearchPointModel>());
|
||||
Searches.Add("Entities", new List<SearchPointModel>());
|
||||
|
||||
foreach (var webPage in WebsiteData.GetPages())
|
||||
{
|
||||
SearchPoints.Add(new SearchPointModel
|
||||
{
|
||||
Title = webPage.Name,
|
||||
PointType = "WebPage",
|
||||
Summary = $"{webPage.Description}",
|
||||
Href = webPage.Href
|
||||
});
|
||||
|
||||
Searches["Pages"].Add(SearchPoints.Last());
|
||||
}
|
||||
|
||||
foreach (var note in noteService.NoteContentModels)
|
||||
{
|
||||
SearchPoints.Add(new SearchPointModel
|
||||
{
|
||||
Title = note.Name,
|
||||
PointType = "Note",
|
||||
Href = note.GetNoteLink(),
|
||||
Summary = note.Description
|
||||
});
|
||||
|
||||
Searches["Notes"].Add(SearchPoints.Last());
|
||||
}
|
||||
|
||||
|
||||
foreach (var entity in EntityData.Get().Values)
|
||||
{
|
||||
var summary =
|
||||
entity.Info().Description.Length > 35
|
||||
? entity.Info().Description.Substring(0, 30).Trim() + "..."
|
||||
: entity.Info().Description.Length > 0
|
||||
? entity.Info().Description
|
||||
: "";
|
||||
|
||||
SearchPoints.Add(new SearchPointModel
|
||||
{
|
||||
Title = entity.Info().Name,
|
||||
Tags = $"{entity.EntityType},{entity.Descriptive}",
|
||||
PointType = "Entity",
|
||||
Summary = $"{entity.EntityType}, {summary}",
|
||||
Href = $"database/{entity.Info().Name.ToLower()}"
|
||||
});
|
||||
|
||||
Searches["Entities"].Add(SearchPoints.Last());
|
||||
}
|
||||
|
||||
isLoaded = true;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public bool IsLoaded()
|
||||
{
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
IsVisible = true;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
IsVisible = false;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using Blazored.LocalStorage;
|
||||
using Model.Feedback;
|
||||
|
||||
namespace Services.Website;
|
||||
|
||||
public class StorageKeys
|
||||
{
|
||||
public static string EnabledStorage = "StorageEnabled";
|
||||
public static string EnabledDataCollection = "StorageDataCollection";
|
||||
public static string IsPlainView { get; set; } = "IsPlainView";
|
||||
public static string IsDynamicFormatting { get; set; } = "IsDynamicFormatting";
|
||||
public static string AttackTime { get; set; } = "AttackTime";
|
||||
public static string TravelTime { get; set; } = "TravelTime";
|
||||
public static string SelectedFaction { get; set; } = "SelectedFaction";
|
||||
public static string SelectedImmortal { get; set; } = "SelectedImmortal";
|
||||
public static string BuildInputDelay { get; set; } = "BuildInputDelay";
|
||||
public static string WaitTime { get; set; } = "WaitTime";
|
||||
|
||||
public static string WaitTo { get; set; } = "WaitTo";
|
||||
}
|
||||
|
||||
public class StorageService : IStorageService
|
||||
{
|
||||
private readonly ISyncLocalStorageService _localStorageService;
|
||||
private readonly IToastService _toastService;
|
||||
private bool isLoaded;
|
||||
|
||||
|
||||
public StorageService(IToastService toastService,
|
||||
ISyncLocalStorageService localStorageService)
|
||||
{
|
||||
_toastService = toastService;
|
||||
_localStorageService = localStorageService;
|
||||
}
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public T GetValue<T>(string forKey)
|
||||
{
|
||||
return _localStorageService.GetItem<T>(forKey);
|
||||
}
|
||||
|
||||
public void SetValue<T>(string key, T value)
|
||||
{
|
||||
if (key.Equals(StorageKeys.EnabledStorage) && value.Equals(true))
|
||||
{
|
||||
_localStorageService.SetItem(key, value);
|
||||
NotifyDataChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.Equals(StorageKeys.EnabledStorage))
|
||||
{
|
||||
_localStorageService.Clear();
|
||||
NotifyDataChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
var isEnabled = GetValue<bool>(StorageKeys.EnabledStorage);
|
||||
if (!isEnabled)
|
||||
{
|
||||
_toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Permission Error",
|
||||
SeverityType = SeverityType.Error,
|
||||
Message = "Storage must be enabled before Storage can be used."
|
||||
});
|
||||
NotifyDataChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
_localStorageService.SetItem(key, value);
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public Task Load()
|
||||
{
|
||||
if (!isLoaded) return Task.CompletedTask;
|
||||
|
||||
|
||||
isLoaded = true;
|
||||
|
||||
NotifyDataChanged();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Model.Feedback;
|
||||
|
||||
namespace Services.Website;
|
||||
|
||||
public class ToastService : IToastService
|
||||
{
|
||||
private readonly List<ToastModel> toasts = new();
|
||||
|
||||
public void Subscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void Unsubscribe(Action action)
|
||||
{
|
||||
OnChange += action;
|
||||
}
|
||||
|
||||
public void AddToast(ToastModel toast)
|
||||
{
|
||||
toasts.Insert(0, toast);
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void RemoveToast(ToastModel toast)
|
||||
{
|
||||
toasts.Remove(toast);
|
||||
}
|
||||
|
||||
public bool HasToasts()
|
||||
{
|
||||
return toasts.Count > 0;
|
||||
}
|
||||
|
||||
public List<ToastModel> GetToasts()
|
||||
{
|
||||
return toasts;
|
||||
}
|
||||
|
||||
public void AgeToasts()
|
||||
{
|
||||
foreach (var toast in toasts) toast.Age++;
|
||||
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
public void ClearAllToasts()
|
||||
{
|
||||
toasts.Clear();
|
||||
NotifyDataChanged();
|
||||
}
|
||||
|
||||
private event Action OnChange = null!;
|
||||
|
||||
private void NotifyDataChanged()
|
||||
{
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user