Converting Tests back to C# but still with Playwright
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
@inject IJSRuntime jsRuntime
|
||||
|
||||
@inject IBuildOrderService buildOrder
|
||||
@inject ITimingService timingService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<div class="armyView">
|
||||
|
||||
<FormLayoutComponent>
|
||||
<div style="display: flex; gap: 24px;">
|
||||
<FormDisplayComponent Label="Army Completed At">
|
||||
<Display>@lastInterval | T @Interval.ToTime(lastInterval)</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Army Attacking At">
|
||||
<Display>@(lastInterval + timingService.GetTravelTime()) |
|
||||
T @Interval.ToTime(lastInterval + timingService.GetTravelTime())</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
<FormDisplayComponent Label="Army units built">
|
||||
<Display>
|
||||
<div class="armyCardsContainer">
|
||||
@foreach (var unit in armyCount)
|
||||
{
|
||||
<div class="armyCard">
|
||||
<div class="armyCountPosition">
|
||||
<div class="armyCount">@unit.Value.ToString()x</div>
|
||||
</div>
|
||||
<div>@unit.Key</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Display>
|
||||
</FormDisplayComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.armyView {
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.armyCardsContainer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.armyCard {
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.armyCountPosition {
|
||||
height: 0;
|
||||
top: -20px;
|
||||
left: -16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.armyCount {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private int lastInterval;
|
||||
|
||||
readonly Dictionary<string, int> armyCount = new();
|
||||
|
||||
List<EntityModel> army = new();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
buildOrder.Subscribe(OnBuildOrderChanged);
|
||||
timingService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
buildOrder.Unsubscribe(OnBuildOrderChanged);
|
||||
timingService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "ArmyComponent");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "ArmyComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnBuildOrderChanged()
|
||||
{
|
||||
var armyCountWas = 0;
|
||||
foreach (var army in armyCount)
|
||||
{
|
||||
armyCountWas += army.Value;
|
||||
}
|
||||
|
||||
armyCount.Clear();
|
||||
|
||||
lastInterval = 0;
|
||||
|
||||
var entitiesOverTime = buildOrder.GetOrders();
|
||||
|
||||
foreach (var entitiesAtTime in entitiesOverTime)
|
||||
{
|
||||
foreach (var entity in entitiesAtTime.Value)
|
||||
{
|
||||
if (entity.EntityType == EntityType.Army)
|
||||
{
|
||||
if (!armyCount.TryAdd(entity.Info().Name, 1))
|
||||
{
|
||||
armyCount[entity.Info().Name]++;
|
||||
}
|
||||
|
||||
if (entity.Production() != null && entity.Production().BuildTime + entitiesAtTime.Key > lastInterval)
|
||||
{
|
||||
lastInterval = entity.Production().BuildTime + entitiesAtTime.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO Better
|
||||
var armyCountIs = 0;
|
||||
foreach (var army in armyCount)
|
||||
{
|
||||
armyCountIs += army.Value;
|
||||
}
|
||||
|
||||
|
||||
if (armyCountWas != armyCountIs)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
|
||||
@inject IEconomyService economyService
|
||||
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<div class="bankContainer">
|
||||
<FormDisplayComponent Label="Time">
|
||||
<Display>@(BuildOrderService.GetLastRequestInterval() + 1) |
|
||||
T @Interval.ToTime(BuildOrderService.GetLastRequestInterval() + 1)</Display>
|
||||
</FormDisplayComponent>
|
||||
<div class="bankRow">
|
||||
<FormDisplayComponent Label="Alloy">
|
||||
<Display>@_economy.Alloy +@_economy.AlloyIncome</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Ether">
|
||||
<Display>@Math.Round(_economy.Ether) +@Math.Round(_economy.EtherIncome)</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
<div class="bankRow">
|
||||
<FormDisplayComponent Label="Pyre">
|
||||
<Display>@_economy.Pyre</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Supply">
|
||||
<Display>@_supplyTaken / @_supplyGranted (@(_supplyGranted / 16)@(_extraBuildings > 0 ? "+" + _extraBuildings : ""))</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="workerText">Workers</div>
|
||||
<div class="bankRow">
|
||||
<FormDisplayComponent Label="Current">
|
||||
<Display>@_economy.WorkerCount</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Busy">
|
||||
<Display>@_economy.BusyWorkerCount</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Creating">
|
||||
<Display>@_economy.CreatingWorkerCount</Display>
|
||||
</FormDisplayComponent>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.bankContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.workerText {
|
||||
margin-bottom: -2px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.bankRow {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject] IBuildOrderService BuildOrderService { get; set; } = default!;
|
||||
|
||||
[Inject] IEconomyService EconomyService { get; set; } = default!;
|
||||
|
||||
EconomyModel _economy = new();
|
||||
int _supplyGranted;
|
||||
int _supplyTaken;
|
||||
int _extraBuildings;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
BuildOrderService.Subscribe(OnBuildOrderChanged);
|
||||
|
||||
|
||||
_economy = EconomyService.GetEconomy(BuildOrderService.GetLastRequestInterval() + 1);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "BankComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "BankComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
BuildOrderService.Unsubscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
void OnBuildOrderChanged()
|
||||
{
|
||||
_economy = EconomyService.GetEconomy(BuildOrderService.GetLastRequestInterval() + 1);
|
||||
|
||||
var ordersOverTime = BuildOrderService.GetOrders();
|
||||
|
||||
_supplyTaken = (from ordersAtInterval in ordersOverTime
|
||||
from order in ordersAtInterval.Value
|
||||
where order.Supply() != null
|
||||
where order.Supply().Takes > 0
|
||||
select order.Supply().Takes).Sum();
|
||||
|
||||
_supplyGranted = (from ordersAtInterval in ordersOverTime
|
||||
from order in ordersAtInterval.Value
|
||||
where order.Supply() != null
|
||||
where order.Supply().Grants > 0
|
||||
select order.Supply().Grants).Sum();
|
||||
|
||||
_extraBuildings = 0;
|
||||
if (_supplyGranted > 160)
|
||||
{
|
||||
_extraBuildings = (_supplyGranted - 160) / 16;
|
||||
_supplyGranted = 160;
|
||||
}
|
||||
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
@inject IEconomyService EconomyService
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject ITimingService TimingService
|
||||
@inject IJSRuntime JsRuntime;
|
||||
@implements IDisposable
|
||||
|
||||
@if (lastRequestedRefreshIndex != requestedRefreshIndex)
|
||||
{
|
||||
<LoadingComponent/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="chartsContainer">
|
||||
@foreach (var chart in charts)
|
||||
{
|
||||
var takenPixels = new Dictionary<int, bool>();
|
||||
|
||||
<div style="width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
|
||||
<div
|
||||
style="position: relative; border: 2px solid gray; border-radius:2px; width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
|
||||
@foreach (var point in chart.Points)
|
||||
{
|
||||
var x = int.Parse(point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax));
|
||||
if (takenPixels.ContainsKey(x)) continue;
|
||||
|
||||
takenPixels.Add(x, true);
|
||||
|
||||
<div style="position: absolute;
|
||||
bottom:@point.GetValue(chart.HighestValuePoint, chart.ValueDisplayMax)px;
|
||||
left:@point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax)px;
|
||||
width: 0px;
|
||||
height: 0px;">
|
||||
<div
|
||||
style="width:1px; height: 1px; border-top-right-radius:10px; border-top-left-radius:10px; border: 2px solid @chart.ChartColor; background-color:@chart.ChartColor">
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.chartsContainer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormDisplayComponent Label="Highest Alloy">
|
||||
<Display>@highestAlloyPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Highest Ether">
|
||||
<Display>@highestEtherPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
<DevOnlyComponent>
|
||||
<FormDisplayComponent Label="Highest Pyre">
|
||||
<Display>@highestEtherPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
</DevOnlyComponent>
|
||||
<FormDisplayComponent Label="Highest Army">
|
||||
<Display>@highestArmyPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
</FormLayoutComponent>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
private readonly int width = 250;
|
||||
|
||||
List<int> valueList = new();
|
||||
|
||||
readonly List<ChartModel> charts = new();
|
||||
|
||||
|
||||
float highestAlloyPoint;
|
||||
float highestEtherPoint;
|
||||
float highestPyrePoint;
|
||||
float highestArmyPoint;
|
||||
|
||||
private Timer ageTimer = null!;
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
BuildOrderService.Subscribe(OnBuilderOrderChanged);
|
||||
TimingService.Subscribe(OnBuilderOrderChanged);
|
||||
|
||||
ageTimer = new Timer(1000);
|
||||
ageTimer.Elapsed += OnAge!;
|
||||
ageTimer.Enabled = true;
|
||||
|
||||
|
||||
GenerateChart();
|
||||
}
|
||||
|
||||
|
||||
int lastRequestedRefreshIndex;
|
||||
|
||||
void OnAge(object? sender, ElapsedEventArgs elapsedEventArgs)
|
||||
{
|
||||
if (requestedRefreshIndex > 0)
|
||||
{
|
||||
if (requestedRefreshIndex == lastRequestedRefreshIndex)
|
||||
{
|
||||
GenerateChart();
|
||||
requestedRefreshIndex = 0;
|
||||
lastRequestedRefreshIndex = 0;
|
||||
}
|
||||
|
||||
lastRequestedRefreshIndex = requestedRefreshIndex;
|
||||
}
|
||||
|
||||
ageTimer.Enabled = true;
|
||||
}
|
||||
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
BuildOrderService.Unsubscribe(OnBuilderOrderChanged);
|
||||
TimingService.Unsubscribe(OnBuilderOrderChanged);
|
||||
}
|
||||
|
||||
|
||||
int requestedRefreshIndex;
|
||||
|
||||
void OnBuilderOrderChanged()
|
||||
{
|
||||
requestedRefreshIndex++;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "ChartComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "ChartComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
void GenerateChart()
|
||||
{
|
||||
var economyOverTime = EconomyService.GetOverTime();
|
||||
|
||||
charts.Clear();
|
||||
|
||||
var alloyChart = new ChartModel
|
||||
{
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "Cyan"
|
||||
};
|
||||
var etherChart = new ChartModel
|
||||
{
|
||||
Offset = width,
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "LightGreen"
|
||||
};
|
||||
|
||||
var pyreChart = new ChartModel
|
||||
{
|
||||
Offset = width * 2,
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "Red"
|
||||
};
|
||||
|
||||
var armyChart = new ChartModel
|
||||
{
|
||||
Offset = width * 3,
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "White"
|
||||
};
|
||||
|
||||
highestAlloyPoint = 0;
|
||||
highestEtherPoint = 0;
|
||||
highestPyrePoint = 0;
|
||||
highestArmyPoint = 0;
|
||||
|
||||
for (var interval = 0; interval < economyOverTime.Count(); interval++)
|
||||
{
|
||||
var army = from unit in BuildOrderService.GetCompletedBefore(interval)
|
||||
where unit.EntityType == EntityType.Army
|
||||
select unit;
|
||||
|
||||
var armyValue = 0;
|
||||
foreach (var unit in army)
|
||||
{
|
||||
armyValue += unit.Production().Alloy + unit.Production().Ether;
|
||||
}
|
||||
|
||||
|
||||
highestArmyPoint = Math.Max(highestArmyPoint, armyValue);
|
||||
|
||||
armyChart.Points.Add(new PointModel { Interval = interval, Value = armyValue });
|
||||
}
|
||||
|
||||
|
||||
for (var interval = 0; interval < economyOverTime.Count(); interval++)
|
||||
{
|
||||
var alloyPoint = new PointModel { Interval = interval };
|
||||
var etherPoint = new PointModel { Interval = interval };
|
||||
var pyrePoint = new PointModel { Interval = interval };
|
||||
|
||||
var economyAtSecond = economyOverTime[interval];
|
||||
|
||||
var alloyWorkerHarvesters = from harvester in economyAtSecond.HarvestPoints
|
||||
where harvester.Harvest() != null
|
||||
where harvester.Harvest().RequiresWorker
|
||||
where harvester.Harvest().Resource == ResourceType.Alloy
|
||||
select harvester;
|
||||
|
||||
var alloyAutomaticHarvesters = from harvester in economyAtSecond.HarvestPoints
|
||||
where harvester.Harvest() != null
|
||||
where !harvester.Harvest().RequiresWorker
|
||||
where harvester.Harvest().Resource == ResourceType.Alloy
|
||||
select harvester;
|
||||
|
||||
var etherAutomaticHarvesters = from harvester in economyAtSecond.HarvestPoints
|
||||
where harvester.Harvest() != null
|
||||
where !harvester.Harvest().RequiresWorker
|
||||
where harvester.Harvest().Resource == ResourceType.Ether
|
||||
select harvester;
|
||||
|
||||
float autoAlloy = 0;
|
||||
float workerSlots = 0;
|
||||
float workerAlloy = 0;
|
||||
float autoEther = 0;
|
||||
|
||||
float economySpending = 0;
|
||||
|
||||
foreach (var alloyAutoHarvester in alloyAutomaticHarvesters)
|
||||
{
|
||||
autoAlloy += alloyAutoHarvester.Harvest().Slots * alloyAutoHarvester.Harvest().HarvestedPerInterval;
|
||||
var production = alloyAutoHarvester.Production();
|
||||
if (production != null)
|
||||
{
|
||||
economySpending += production.Alloy;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var alloyWorkerHarvester in alloyWorkerHarvesters)
|
||||
{
|
||||
workerSlots += alloyWorkerHarvester.Harvest().Slots;
|
||||
var production = alloyWorkerHarvester.Production();
|
||||
if (production != null)
|
||||
{
|
||||
economySpending += production.Alloy;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var etherWorkerHarvester in etherAutomaticHarvesters)
|
||||
{
|
||||
autoEther += etherWorkerHarvester.Harvest().Slots * etherWorkerHarvester.Harvest().HarvestedPerInterval;
|
||||
var production = etherWorkerHarvester.Production();
|
||||
if (production != null)
|
||||
{
|
||||
economySpending += production.Alloy;
|
||||
}
|
||||
}
|
||||
|
||||
economySpending += (economyAtSecond.WorkerCount - 6) * 50;
|
||||
|
||||
workerAlloy = Math.Min(economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount, workerSlots);
|
||||
|
||||
|
||||
alloyPoint.TempValue = workerAlloy + autoAlloy;
|
||||
etherPoint.Value = autoEther;
|
||||
|
||||
|
||||
if (interval > 0)
|
||||
{
|
||||
alloyPoint.TempValue += alloyChart.Points.Last().TempValue;
|
||||
etherPoint.Value += etherChart.Points.Last().Value;
|
||||
pyrePoint.Value = pyreChart.Points.Last().Value + 1;
|
||||
}
|
||||
|
||||
alloyPoint.Value = alloyPoint.TempValue - economySpending;
|
||||
|
||||
highestAlloyPoint = Math.Max(highestAlloyPoint, alloyPoint.Value);
|
||||
highestEtherPoint = Math.Max(highestEtherPoint, etherPoint.Value);
|
||||
|
||||
alloyChart.Points.Add(alloyPoint);
|
||||
etherChart.Points.Add(etherPoint);
|
||||
pyreChart.Points.Add(pyrePoint);
|
||||
}
|
||||
|
||||
alloyChart.HighestValuePoint = (int)Math.Max(highestAlloyPoint, 5000.0f);
|
||||
etherChart.HighestValuePoint = (int)Math.Max(highestEtherPoint, 2000.0f);
|
||||
pyreChart.HighestValuePoint = (int)Math.Max(highestPyrePoint, 2000.0f);
|
||||
|
||||
alloyChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
etherChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
pyreChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
|
||||
armyChart.HighestValuePoint = (int)Math.Max(highestArmyPoint, 2000.0f);
|
||||
armyChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
|
||||
|
||||
charts.Add(alloyChart);
|
||||
charts.Add(etherChart);
|
||||
|
||||
|
||||
//TODO WIP
|
||||
//charts.Add(pyreChart);
|
||||
|
||||
charts.Add(armyChart);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
|
||||
@inject IBuildOrderService buildOrderService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
/**
|
||||
* // TODO: Make this more elegant, and useful. Also, it currently doesn't clear properly
|
||||
* <FormTextAreaComponent Label="JSON Data"
|
||||
* Rows="14"
|
||||
* Value="@buildOrderService.AsJson()">
|
||||
* </FormTextAreaComponent>
|
||||
*/
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
buildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
buildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "BuildOrderComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "BuildOrderComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
@inject IImmortalSelectionService FilterService
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<div style="@GetBorderStyle()">
|
||||
@ChildContent
|
||||
</div>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
string GetBorderStyle()
|
||||
{
|
||||
var faction = FilterService.GetFaction();
|
||||
var color = faction == DataType.FACTION_Aru ? "var(--faction-aru)" : "var(--faction-qrath)";
|
||||
return $"border-top: 4px solid {color}; padding-top: 14px; margin-top: -12px;";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
@inject IImmortalSelectionService FilterService
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<div style="@GetBorderStyle()">
|
||||
@ChildContent
|
||||
</div>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
string GetBorderStyle()
|
||||
{
|
||||
var immortal = FilterService.GetImmortal();
|
||||
var color = "#666666";
|
||||
if (immortal == DataType.IMMORTAL_Orzum) color = "var(--immortal-orzum)";
|
||||
else if (immortal == DataType.IMMORTAL_Ajari) color = "var(--immortal-ajari)";
|
||||
else if (immortal == DataType.IMMORTAL_Atzlan) color = "var(--immortal-atzlan)";
|
||||
else if (immortal == DataType.IMMORTAL_Mala) color = "var(--immortal-mala)";
|
||||
else if (immortal == DataType.IMMORTAL_Xol) color = "var(--immortal-xol)";
|
||||
return $"border-top: 4px solid {color}; padding-top: 14px; margin-top: -12px;";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject IKeyService KeyService
|
||||
@inject IImmortalSelectionService FilterService
|
||||
@inject IStorageService StorageService
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@using Services.Website
|
||||
@implements IDisposable
|
||||
|
||||
@if (_entity != null)
|
||||
{
|
||||
<div class="entityClickView">
|
||||
<CascadingValue Value="_entity">
|
||||
<CascadingValue Value="@_viewType">
|
||||
<EntityViewComponent></EntityViewComponent>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
</div>
|
||||
}
|
||||
<style>
|
||||
.entityClickView {
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
height: 550px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private EntityModel? _entity;
|
||||
private string _viewType = EntityViewType.Detailed;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
KeyService.Subscribe(HandleClick);
|
||||
StorageService.Subscribe(RefreshDefaults);
|
||||
BuildOrderService.Subscribe(OnBuildOrderServiceChanged);
|
||||
|
||||
RefreshDefaults();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
KeyService.Unsubscribe(HandleClick);
|
||||
StorageService.Unsubscribe(RefreshDefaults);
|
||||
BuildOrderService.Unsubscribe(OnBuildOrderServiceChanged);
|
||||
}
|
||||
|
||||
|
||||
void OnBuildOrderServiceChanged()
|
||||
{
|
||||
if (BuildOrderService.GetLastRequestInterval() == 0)
|
||||
{
|
||||
_entity = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshDefaults()
|
||||
{
|
||||
_viewType = StorageService.GetValue<bool>(StorageKeys.IsPlainView) ? EntityViewType.Plain : EntityViewType.Detailed;
|
||||
}
|
||||
|
||||
private void HandleClick()
|
||||
{
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFaction();
|
||||
var immortal = FilterService.GetImmortal();
|
||||
|
||||
var foundEntity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
|
||||
|
||||
if (foundEntity != null && _entity != foundEntity)
|
||||
{
|
||||
_entity = foundEntity;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
@inject IJSRuntime JsRuntime;
|
||||
@inject IImmortalSelectionService FilterService
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormSelectComponent OnChange="@OnFactionChanged">
|
||||
<FormLabelComponent>Faction</FormLabelComponent>
|
||||
<ChildContent>
|
||||
<option value="@DataType.FACTION_Aru"
|
||||
selected="@(FilterService.GetFaction().Equals(DataType.FACTION_Aru))">
|
||||
Aru
|
||||
</option>
|
||||
<option value="@DataType.FACTION_QRath"
|
||||
selected="@(FilterService.GetFaction().Equals(DataType.FACTION_QRath))">
|
||||
Q'Rath
|
||||
</option>
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
|
||||
<FormSelectComponent OnChange="@OnImmortalChanged">
|
||||
<FormLabelComponent>Immortal</FormLabelComponent>
|
||||
<ChildContent>
|
||||
@if (FilterService.GetFaction() == DataType.FACTION_QRath)
|
||||
{
|
||||
<option value="@DataType.IMMORTAL_Orzum"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Orzum))">
|
||||
Orzum
|
||||
</option>
|
||||
<option value="@DataType.IMMORTAL_Ajari"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Ajari))">
|
||||
Ajari
|
||||
</option>
|
||||
}
|
||||
@if (FilterService.GetFaction() == DataType.FACTION_Aru)
|
||||
{
|
||||
<option value="@DataType.IMMORTAL_Atzlan"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Atzlan))">
|
||||
Atzlan
|
||||
</option>
|
||||
<option value="@DataType.IMMORTAL_Mala"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Mala))">
|
||||
Mala
|
||||
</option>
|
||||
<option value="@DataType.IMMORTAL_Xol"
|
||||
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Xol))">
|
||||
Xol
|
||||
</option>
|
||||
}
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
void OnFactionChanged(ChangeEventArgs e)
|
||||
{
|
||||
FilterService.SelectFaction(e.Value!.ToString()!);
|
||||
}
|
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e)
|
||||
{
|
||||
FilterService.SelectImmortal(e.Value!.ToString()!);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "FilterComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "FilterComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
@inject IEconomyService economyService
|
||||
@inject IBuildOrderService buildOrderService
|
||||
@inject ITimingService timingService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<div class="highlightsContainer">
|
||||
<div>
|
||||
<div>Requested</div>
|
||||
|
||||
@foreach (var ordersAtTime in buildOrderService.StartedOrders.Reverse())
|
||||
{
|
||||
foreach (var order in ordersAtTime.Value)
|
||||
{
|
||||
<div>
|
||||
@ordersAtTime.Key | T @Interval.ToTime(ordersAtTime.Key)
|
||||
</div>
|
||||
<div>
|
||||
@order.Info().Name
|
||||
</div>
|
||||
<br/>
|
||||
}
|
||||
}
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div>Finished</div>
|
||||
|
||||
@foreach (var ordersAtTime in buildOrderService.CompletedOrders.Reverse())
|
||||
{
|
||||
foreach (var order in ordersAtTime.Value)
|
||||
{
|
||||
<div>
|
||||
|
||||
@ordersAtTime.Key | T @Interval.ToTime(ordersAtTime.Key)
|
||||
</div>
|
||||
<div>
|
||||
@order.Info().Name
|
||||
</div>
|
||||
<br/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.highlightsContainer {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 400px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
economyService.Subscribe(StateHasChanged);
|
||||
buildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
economyService.Unsubscribe(StateHasChanged);
|
||||
buildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "HighlightsComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "HighlightsComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
@inject IJSRuntime JsRuntime;
|
||||
@using Services.Website
|
||||
@implements IDisposable
|
||||
@inject IKeyService KeyService
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject IImmortalSelectionService FilterService
|
||||
|
||||
@inject IEconomyService EconomyService
|
||||
@inject ITimingService TimingService
|
||||
@inject IToastService ToastService
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
|
||||
|
||||
<InputPanelComponent>
|
||||
<div class="keyContainer">
|
||||
@foreach (var hotkey in hotkeys)
|
||||
{
|
||||
if (hotkey.IsHidden)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var color = (hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace()) || KeyService.GetAllPressedKeys().Contains(hotkey.KeyText)
|
||||
? hotkey.GetColor()
|
||||
: hotkey.GetColor();
|
||||
|
||||
var x = hotkey.PositionX * Size;
|
||||
var y = hotkey.PositionY * Size + (hotkey.PositionY == 0 ? 5 : -50);
|
||||
|
||||
var width = Size * hotkey.Width;
|
||||
var height = hotkey.PositionY == 0 ? 50 : Size;
|
||||
|
||||
var borderRadius = hotkey.PositionY == 0 ? 12 : 0;
|
||||
|
||||
var border = "1px solid black";
|
||||
if (hotkey.KeyText.Equals(key))
|
||||
{
|
||||
border = "5px solid black";
|
||||
}
|
||||
|
||||
if (hotkey.KeyText.Equals(controlGroup))
|
||||
{
|
||||
color = "#257525";
|
||||
}
|
||||
|
||||
if (hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace())
|
||||
{
|
||||
border = "5px solid green";
|
||||
}
|
||||
|
||||
var keyText = hotkey.KeyText.Equals("CAPSLOCK") ? "Caps"
|
||||
: hotkey.KeyText.Equals("CONTROL") ? "Ctrl"
|
||||
: hotkey.KeyText.Equals("SHIFT") ? "Shift"
|
||||
: hotkey.KeyText.Equals("X") ? "X"
|
||||
: hotkey.KeyText.Equals("SPACE") ? "Space" : hotkey.KeyText;
|
||||
|
||||
|
||||
var controlStyle = $"background-color:{color}; " +
|
||||
$"width: {width}px; " +
|
||||
"border-top: 1px solid black; " +
|
||||
"border-left: 1px solid black; " +
|
||||
"border-right: 1px solid black; " +
|
||||
$"border-top-left-radius: {borderRadius}px; " +
|
||||
$"border-top-right-radius: {borderRadius}px; " +
|
||||
"overflow: hidden; " +
|
||||
"text-align: center;";
|
||||
|
||||
var keyStyle = $"background-color:{color}; " +
|
||||
$"border: {border}; " +
|
||||
$"width: {width}px; " +
|
||||
$"height: {height}px; " +
|
||||
"overflow: hidden; " +
|
||||
"padding: 4px;";
|
||||
|
||||
var usedStyle = hotkey.PositionY == 0 ? controlStyle : keyStyle;
|
||||
|
||||
<div style="position:relative;
|
||||
cursor:pointer;
|
||||
top:@y.ToString()px;
|
||||
left:@x.ToString()px;
|
||||
width: 0px;
|
||||
height: 0px;">
|
||||
|
||||
<div @onclick="e => ButtonClicked(e, hotkey)" style="@usedStyle">
|
||||
@keyText
|
||||
@foreach (var entity in data.Values)
|
||||
{
|
||||
if (InvalidKey(entity, hotkey) || InvalidKeyGroup(entity, hotkey) || InvalidHoldSpace(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InvalidFaction(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InvalidVanguard(entity) || InvalidNonVanguard(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isVanguard = entity.VanguardAdded() != null;
|
||||
var style = isVanguard ? "font-weight: bold;" : "";
|
||||
|
||||
if (BuildOrderService.WillMeetRequirements(entity) == null)
|
||||
{
|
||||
style += "color:gray; font-style: italic;";
|
||||
}
|
||||
|
||||
|
||||
<div style="@style">@entity.Info()?.Name</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</InputPanelComponent>
|
||||
|
||||
<style>
|
||||
.keyContainer {
|
||||
width: 400px;
|
||||
max-width: 95vw;
|
||||
height: 350px;
|
||||
outline: 3px solid black;
|
||||
border-radius: 8px;
|
||||
background-color: #282A30;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.keyContainer {
|
||||
transform: scale(0.85) translateX(-20px);
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public int Size { get; set; } = 100;
|
||||
|
||||
readonly Dictionary<string, EntityModel> data = EntityModel.GetDictionary();
|
||||
readonly List<HotkeyModel> hotkeys = HotkeyModel.GetAll();
|
||||
|
||||
private string controlGroup = "C";
|
||||
private string key = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
KeyService.Subscribe(OnKeyPressed);
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
BuildOrderService.Subscribe(OnBuilderOrderChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
KeyService.Unsubscribe(OnKeyPressed);
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
BuildOrderService.Unsubscribe(OnBuilderOrderChanged);
|
||||
}
|
||||
|
||||
int completedTimeCount;
|
||||
|
||||
void OnBuilderOrderChanged()
|
||||
{
|
||||
if (BuildOrderService.UniqueCompletedTimes.Count != completedTimeCount)
|
||||
{
|
||||
completedTimeCount = BuildOrderService.UniqueCompletedTimes.Count;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "HotKeyViewerComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "HotKeyViewerComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidFaction(EntityModel entity)
|
||||
{
|
||||
if (entity.Faction() != null && entity.Faction()?.Faction != FilterService.GetFaction() && FilterService.GetFaction() != DataType.Any)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidVanguard(EntityModel entity)
|
||||
{
|
||||
if (entity.VanguardAdded() != null
|
||||
&& entity.VanguardAdded()?.ImmortalId != FilterService.GetImmortal()
|
||||
&& FilterService.GetImmortal() != DataType.Any)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidNonVanguard(EntityModel entity)
|
||||
{
|
||||
if (entity.Replaceds().Count > 0)
|
||||
{
|
||||
foreach (var replaced in entity.Replaceds())
|
||||
{
|
||||
if (FilterService.GetImmortal() == replaced.ImmortalId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InvalidKey(EntityModel entity, HotkeyModel key)
|
||||
{
|
||||
if (entity.Hotkey()?.Hotkey == key.KeyText)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidKeyGroup(EntityModel entity, HotkeyModel key)
|
||||
{
|
||||
if (entity.Hotkey()?.HotkeyGroup == controlGroup)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidKey(EntityModel entity)
|
||||
{
|
||||
if (entity.Hotkey()?.Hotkey == key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidKeyGroup(EntityModel entity)
|
||||
{
|
||||
if (entity.Hotkey()?.HotkeyGroup == controlGroup)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidHoldSpace(EntityModel entity)
|
||||
{
|
||||
if (entity.Hotkey()?.HoldSpace == KeyService.IsHoldingSpace())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnKeyPressed()
|
||||
{
|
||||
var controlGroupWas = controlGroup;
|
||||
var keyWas = key;
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("Z"))
|
||||
{
|
||||
controlGroup = "Z";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("X"))
|
||||
{
|
||||
controlGroup = "X";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("C"))
|
||||
{
|
||||
controlGroup = "C";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("D"))
|
||||
{
|
||||
controlGroup = "D";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("V"))
|
||||
{
|
||||
controlGroup = "V";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("ALT"))
|
||||
{
|
||||
controlGroup = "ALT";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("SHIFT"))
|
||||
{
|
||||
controlGroup = "SHIFT";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("CONTROL"))
|
||||
{
|
||||
controlGroup = "CONTROL";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Count > 0)
|
||||
{
|
||||
key = KeyService.GetAllPressedKeys().First();
|
||||
}
|
||||
|
||||
if (controlGroupWas != controlGroup || keyWas != key)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void HandleClick()
|
||||
{
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
|
||||
if (hotkey is "`")
|
||||
HandleCancelEntity();
|
||||
|
||||
if (EntityFromKey(hotkey, out var entity))
|
||||
return;
|
||||
|
||||
if (BuildOrderService.Add(entity!, EconomyService))
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
|
||||
private void HandleCancelEntity()
|
||||
{
|
||||
BuildOrderService.RemoveLast();
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
|
||||
private bool EntityFromKey(string? hotkey, out EntityModel? entity)
|
||||
{
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFaction();
|
||||
var immortal = FilterService.GetImmortal();
|
||||
|
||||
entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
|
||||
|
||||
return entity == null;
|
||||
}
|
||||
|
||||
private void ButtonClicked(MouseEventArgs mouseEventArgs, HotkeyModel hotkey)
|
||||
{
|
||||
DataCollectionService.SendEvent(
|
||||
DataCollectionKeys.BuildCalcInput,
|
||||
new Dictionary<string, string> { { "key", hotkey.KeyText.ToLower() }, { "input-source", "mouse" } }
|
||||
);
|
||||
|
||||
|
||||
if (hotkey.KeyText.Equals(HotKeyType.SPACE.ToString()))
|
||||
{
|
||||
if (KeyService.IsHoldingSpace())
|
||||
{
|
||||
KeyService.RemovePressedKey(hotkey.KeyText);
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyService.AddPressedKey(hotkey.KeyText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyService.AddPressedKey(hotkey.KeyText);
|
||||
KeyService.RemovePressedKey(hotkey.KeyText);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
@using Services.Website
|
||||
@inject IKeyService KeyService
|
||||
|
||||
@inject IDataCollectionService DataCollectionService
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
|
||||
<div tabindex="0"
|
||||
style="margin: auto;"
|
||||
@onkeydown="HandleKeyDown"
|
||||
@onkeyup="HandleKeyUp"
|
||||
@onkeydown:preventDefault="true"
|
||||
@onkeydown:stopPropagation="true">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; } = default!;
|
||||
|
||||
private void HandleKeyDown(KeyboardEventArgs e)
|
||||
{
|
||||
DataCollectionService.SendEvent(
|
||||
DataCollectionKeys.BuildCalcInput,
|
||||
new Dictionary<string, string> { { "key", e.Key.ToLower() }, { "input-source", "keyboard" } }
|
||||
);
|
||||
|
||||
KeyService.AddPressedKey(e.Key);
|
||||
}
|
||||
|
||||
private void HandleKeyUp(KeyboardEventArgs e)
|
||||
{
|
||||
KeyService.RemovePressedKey(e.Key);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "InputPanelComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "InputPanelComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
@inject IJSRuntime JsRuntime;
|
||||
|
||||
@inject IBuildOrderService BuildOrderService
|
||||
@inject IEconomyService EconomyService
|
||||
@inject IToastService ToastService
|
||||
@inject ITimingService TimingService
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="600"
|
||||
Min="0"
|
||||
Value="BuildDelay"
|
||||
OnChange="@OnBuildingInputDelayChanged">
|
||||
<FormLabelComponent>Building Input Delay</FormLabelComponent>
|
||||
<FormInfoComponent>Add a input delay to constructing buildings for simulating worker movement and player
|
||||
micro.
|
||||
</FormInfoComponent>
|
||||
</FormNumberComponent>
|
||||
<div class="optionRow">
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="600"
|
||||
Min="1"
|
||||
Value="WaitTime"
|
||||
OnChange="@OnWaitTimeChanged">
|
||||
<FormLabelComponent>Wait Time</FormLabelComponent>
|
||||
</FormNumberComponent>
|
||||
<ButtonComponent OnClick="OnWaitClicked">Add Wait</ButtonComponent>
|
||||
</FormLayoutComponent>
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="2048"
|
||||
Min="1"
|
||||
Value="WaitTo"
|
||||
OnChange="@OnWaitToChanged">
|
||||
<FormLabelComponent>Wait To</FormLabelComponent>
|
||||
</FormNumberComponent>
|
||||
<ButtonComponent OnClick="OnWaitToClicked">Add Wait</ButtonComponent>
|
||||
</FormLayoutComponent>
|
||||
</div>
|
||||
</FormLayoutComponent>
|
||||
|
||||
<style>
|
||||
.optionRow {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private int BuildDelay { get; set; } = 2;
|
||||
private int WaitTime { get; set; } = 30;
|
||||
private int WaitTo { get; set; } = 30;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
TimingService.Subscribe(RefreshDefaults);
|
||||
|
||||
RefreshDefaults();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
TimingService.Unsubscribe(RefreshDefaults);
|
||||
}
|
||||
|
||||
void RefreshDefaults()
|
||||
{
|
||||
BuildDelay = TimingService.BuildingInputDelay;
|
||||
WaitTime = TimingService.WaitTime;
|
||||
WaitTo = TimingService.WaitTo;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnBuildingInputDelayChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
TimingService.BuildingInputDelay = int.Parse(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
void OnWaitTimeChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
TimingService.WaitTime = (int)changeEventArgs.Value!;
|
||||
WaitTime = (int)changeEventArgs.Value!;
|
||||
}
|
||||
|
||||
void OnWaitToChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
TimingService.WaitTo = (int)changeEventArgs.Value!;
|
||||
WaitTo = (int)changeEventArgs.Value!;
|
||||
}
|
||||
|
||||
private void OnWaitClicked()
|
||||
{
|
||||
if (BuildOrderService.AddWait(WaitTime))
|
||||
{
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWaitToClicked()
|
||||
{
|
||||
if (BuildOrderService.AddWaitTo(WaitTo))
|
||||
{
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.time", "TimingComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
JsRuntime.InvokeVoidAsync("console.timeEnd", "TimingComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
@inject IJSRuntime jsRuntime
|
||||
@inject IEconomyService economyService
|
||||
@inject IBuildOrderService buildOrderService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<Virtualize Items="@economyService.GetOverTime()" Context="economyAtSecond" ItemSize="400" OverscanCount="4">
|
||||
<div style="display: grid; gap: 8px; grid-template-columns: 1fr 1fr;">
|
||||
<div>
|
||||
<div>
|
||||
@economyAtSecond.Interval
|
||||
</div>
|
||||
<div>
|
||||
T @Interval.ToTime(economyAtSecond.Interval) | A @economyAtSecond.Alloy | E @economyAtSecond.Ether
|
||||
</div>
|
||||
<div>
|
||||
Worker Count: @(economyAtSecond.WorkerCount)
|
||||
</div>
|
||||
<div>
|
||||
Free Worker Count: @(economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount)
|
||||
</div>
|
||||
<div>
|
||||
Busy Worker Count: @economyAtSecond.BusyWorkerCount
|
||||
</div>
|
||||
<div>
|
||||
Creating Worker Count: @economyAtSecond.CreatingWorkerCount
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@if (buildOrderService.StartedOrders.TryGetValue(economyAtSecond.Interval, out var ordersAtTime))
|
||||
{
|
||||
@foreach (var order in ordersAtTime)
|
||||
{
|
||||
<div>
|
||||
Requested: @order.Info().Name
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@if (buildOrderService.CompletedOrders.TryGetValue(economyAtSecond.Interval, out var ordersCompletedAtTime))
|
||||
{
|
||||
@foreach (var order in ordersCompletedAtTime)
|
||||
{
|
||||
<div>
|
||||
New: @order.Info().Name
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Virtualize>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
economyService.Subscribe(StateHasChanged);
|
||||
buildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
economyService.Unsubscribe(StateHasChanged);
|
||||
buildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "TimelineComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "TimelineComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
@inject IJSRuntime jsRuntime;
|
||||
|
||||
@inject IBuildOrderService buildOrderService
|
||||
@inject IEconomyService economyService
|
||||
@inject IToastService toastService
|
||||
@inject ITimingService timingService
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Max="2048"
|
||||
Min="0"
|
||||
Value="@timingService.GetAttackTime()"
|
||||
OnChange="@OnAttackTimeChanged">
|
||||
<FormLabelComponent>Attack Time</FormLabelComponent>
|
||||
<FormInfoComponent>
|
||||
<i>  T @Interval.ToTime(timingService.GetAttackTime())</i>
|
||||
</FormInfoComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
<FormNumberComponent Max="2048"
|
||||
Min="0"
|
||||
Value="@timingService.GetTravelTime()"
|
||||
OnChange="@OnTravelTimeChanged">
|
||||
<FormLabelComponent>Travel Time</FormLabelComponent>
|
||||
<FormInfoComponent>
|
||||
<i>  T @Interval.ToTime(timingService.GetTravelTime())</i>
|
||||
</FormInfoComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
timingService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
timingService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void OnAttackTimeChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
timingService.SetAttackTime(int.Parse(changeEventArgs.Value!.ToString()!));
|
||||
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
|
||||
toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Attack Time",
|
||||
Message = "Attack Time has changed.",
|
||||
SeverityType = SeverityType.Success
|
||||
});
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnTravelTimeChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
timingService.SetTravelTime(int.Parse(changeEventArgs.Value!.ToString()!));
|
||||
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
|
||||
toastService.AddToast(new ToastModel
|
||||
{
|
||||
Title = "Travel Time",
|
||||
Message = "Travel Time has changed.",
|
||||
SeverityType = SeverityType.Success
|
||||
});
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnNameChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
buildOrderService.SetName(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
void OnColorChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
buildOrderService.DeprecatedSetColor(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
|
||||
void OnNotesChanged(ChangeEventArgs changeEventArgs)
|
||||
{
|
||||
buildOrderService.SetNotes(changeEventArgs.Value!.ToString()!);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender()
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.time", "TimingComponent");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
#if DEBUG
|
||||
jsRuntime.InvokeVoidAsync("console.timeEnd", "TimingComponent");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
@inject IImmortalSelectionService FilterService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is this tool?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
This is a calculator to determine build timings. Mostly so someone can quickly try out a few build
|
||||
orders to see if they somewhat make sense.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
How does it work?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
The tool calculates every second of game time. So if you attempt to build a <b>Legion Hall</b> as
|
||||
your first action, the tool will scan every second, until you get to one where the request can be
|
||||
made. In this case, that is interval 58.
|
||||
<br/>
|
||||
<br/>
|
||||
If you then build 2 <b>Apostle of Bindings</b> a <b>Soul Foundry</b> and a 3 <b>Absolvers</b> you
|
||||
should see yourself roughly floating 500 alloy, with barely having any ether. Which means you could
|
||||
of gotten an <b>Acropolis</b> and a <b>Zentari</b> without hurting your build.
|
||||
<br/>
|
||||
<br/>
|
||||
Try building <b>Apostle of Bindings</b> before the <b>Legion Hall</b> and see how that changes the
|
||||
timing of your 3 <b>Absolvers</b>. (Spoiler:
|
||||
<SpoilerTextComponent> your <b>Absolvers</b> will be built much faster, and you won't be floating so
|
||||
much alloy.
|
||||
</SpoilerTextComponent>
|
||||
)
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is CONTROL key for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Economy and tech related upgrades for townhalls.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is SHIFT key for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Misc building related upgrades. (Omnivores)
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is 2 key for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
It will be for Pyre camps. Currently not implemented.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user