Integrate builds with Focus view (#164)

* Integrate builds with Focus view
Detect when GameData is invalid
Detect when reading memory is faulty
Show current character data in Focus View
Closes #161
Closes #162
Closes #163

* Increment version

* Bugfix version comparison script
This commit is contained in:
2023-03-04 17:21:08 +01:00
committed by GitHub
parent 8a91ded610
commit 159928f24b
15 changed files with 318 additions and 27 deletions
+1 -1
View File
@@ -13,7 +13,7 @@
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9.8.9</Version>
<Version>0.9.8.10</Version>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
</PropertyGroup>
+1
View File
@@ -5,6 +5,7 @@ namespace Daybreak.Models;
public sealed class GameData
{
public bool Valid { get; init; }
public MainPlayerInformation? MainPlayer { get; init; }
public List<PlayerInformation>? Party { get; init; }
public UserInformation? User { get; init; }
@@ -7,6 +7,7 @@ public class PlayerInformation
public Profession? PrimaryProfession { get; init; }
public Profession? SecondaryProfession { get; init; }
public List<Profession>? UnlockedProfession { get; init; }
public Build? CurrentBuild { get; init; }
public float CurrentHealth { get; init; }
public float MaxHealth { get; init; }
public float CurrentEnergy { get; init; }
@@ -0,0 +1,11 @@
namespace Daybreak.Models.Guildwars;
public sealed class SkillMetadata
{
public Skill? Skill { get; init; }
public uint Adrenaline1 { get; init; }
public uint Adrenaline2 { get; init; }
public uint Recharge { get; init; }
public uint Id { get; init; }
public uint Event { get; init; }
}
@@ -1,4 +1,6 @@
namespace Daybreak.Models.Guildwars;
using System.Collections.Generic;
namespace Daybreak.Models.Guildwars;
public class WorldPlayerInformation : PlayerInformation
{
@@ -0,0 +1,10 @@
namespace Daybreak.Models.Interop;
public readonly struct AttributeContext
{
public readonly uint Id;
public readonly uint BaseLevel;
public readonly uint ActualLevel;
public readonly uint DecrementPoints;
public readonly uint IncrementPoints;
}
+7 -1
View File
@@ -12,6 +12,9 @@ public readonly struct GameContext
///Array of type <see cref="MapEntityContext"/>.
public readonly GuildwarsArray MapEntities;
[FieldOffset(0x0030)]
public readonly GuildwarsArray PartyAttributes;
[FieldOffset(0x04AC)]
public readonly uint QuestId;
@@ -21,10 +24,13 @@ public readonly struct GameContext
[FieldOffset(0x0608)]
public readonly uint HardModeUnlocked;
[FieldOffset(0x640)]
[FieldOffset(0x0640)]
///Array of type <see cref="ProfessionsContext"/>
public readonly GuildwarsArray Professions;
[FieldOffset(0x0674)]
public readonly GuildwarsArray Skillbars;
[FieldOffset(0x06C4)]
public readonly uint Experience;
@@ -0,0 +1,11 @@
using System.Runtime.InteropServices;
namespace Daybreak.Models.Interop;
public readonly struct PartyAttributesContext
{
public readonly uint AgentId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x36)]
public readonly AttributeContext[] Attributes;
}
+17
View File
@@ -0,0 +1,17 @@
using System.Runtime.InteropServices;
namespace Daybreak.Models.Interop;
[StructLayout(LayoutKind.Sequential)]
public readonly struct SkillContext
{
public readonly uint Adrenaline1;
public readonly uint Adrenaline2;
public readonly uint Recharge;
public readonly uint Id;
public readonly uint Event;
}
@@ -0,0 +1,23 @@
using System.Runtime.InteropServices;
namespace Daybreak.Models.Interop;
[StructLayout(LayoutKind.Explicit)]
public readonly struct SkillbarContext
{
[FieldOffset(0x0000)]
public readonly uint AgentId;
[FieldOffset(0x0004)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x08)]
public readonly SkillContext[] Skills;
[FieldOffset(0x00A4)]
public readonly uint Disabled;
[FieldOffset(0x00B0)]
public readonly uint Casting;
[FieldOffset(0x00B8)]
public readonly uint H00B8;
}
@@ -1,17 +1,19 @@
using Daybreak.Models;
using Daybreak.Models.Builds;
using Daybreak.Models.Guildwars;
using Daybreak.Models.Interop;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Core.Extensions;
using System.Diagnostics;
using System.Extensions;
using System.Linq;
using System.Logging;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Documents;
namespace Daybreak.Services.Scanner;
@@ -26,6 +28,8 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
private IntPtr entityArrayPointer;
private volatile CancellationTokenSource? cancellationTokenSource;
public bool Faulty { get; private set; }
public bool Running => this.cancellationTokenSource is not null && this.cancellationTokenSource.IsCancellationRequested is false;
public GameData? GameData { get; private set; }
@@ -121,9 +125,12 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
try
{
this.ReadGameMemory(cancellationToken);
this.Faulty = false;
}
catch(Exception e)
{
this.GameData = null;
this.Faulty = true;
this.logger.LogError(e, "Exception encountered when reading game memory");
}
}
@@ -157,13 +164,16 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
var professions = this.memoryScanner.ReadArray<ProfessionsContext>(gameContext.Professions);
var players = this.memoryScanner.ReadArray<PlayerContext>(gameContext.Players);
var quests = this.memoryScanner.ReadArray<QuestContext>(gameContext.QuestLog);
var skills = this.memoryScanner.ReadArray<SkillbarContext>(gameContext.Skillbars);
var partyAttributes = this.memoryScanner.ReadArray<PartyAttributesContext>(gameContext.PartyAttributes);
var playerEntityId = this.memoryScanner.ReadPtrChain<int>(this.GetPlayerIdPointer(), 0x0, 0x0);
// The following lines would retrieve all entities, including item entities.
//var entityArray = this.memoryScanner.ReadPtrChain<GuildwarsArray>(this.GetEntityArrayPointer(), 0x0, 0x0);
//var entities = this.memoryScanner.ReadArray<EntityContext>(entityArray);
this.GameData = this.AggregateGameData(gameContext, instanceContext, mapEntities, players, professions, quests, userContext, playerEntityId);
this.GameData = this.AggregateGameData(gameContext, instanceContext, mapEntities, players, professions, quests, userContext, skills, partyAttributes, playerEntityId);
}
private IntPtr GetPlayerIdPointer()
@@ -185,7 +195,7 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
return this.entityArrayPointer;
}
private GameData AggregateGameData(
GameContext gameContext,
InstanceContext instanceContext,
@@ -194,6 +204,8 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
ProfessionsContext[] professions,
QuestContext[] quests,
UserContext userContext,
SkillbarContext[] skills,
PartyAttributesContext[] partyAttributes,
int mainPlayerEntityId)
{
var email = ParseAndCleanWCharArray(userContext.PlayerEmailBytes);
@@ -201,14 +213,14 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
_ = Map.TryParse((int)userContext.MapId, out var currentMap);
var partyMembers = professions
.Where(p => p.AgentId != mainPlayerEntityId)
.Select(p => GetPlayerInformation((int)p.AgentId, instanceContext, entities, professions))
.Select(p => GetPlayerInformation((int)p.AgentId, instanceContext, entities, professions, skills, partyAttributes))
.ToList();
var mainPlayer = GetMainPlayerInformation(mainPlayerEntityId, name, gameContext, instanceContext, entities, professions, quests);
var mainPlayer = GetMainPlayerInformation(mainPlayerEntityId, name, gameContext, instanceContext, entities, professions, quests, skills, partyAttributes);
var worldPlayers = players
.Where(p => p.AgentId != mainPlayerEntityId)
.Select(p => GetWorldPlayerInformation(p, this.memoryScanner.ReadWString(p.NamePointer, 0x40), instanceContext, entities, professions))
.Select(p => GetWorldPlayerInformation(p, this.memoryScanner.ReadWString(p.NamePointer, 0x40), instanceContext, entities, professions, skills, partyAttributes))
.ToList();
@@ -245,7 +257,8 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
MainPlayer = mainPlayer,
Session = sessionInformation,
User = userInformation,
WorldPlayers = worldPlayers
WorldPlayers = worldPlayers,
Valid = entities.Length > 0 || players.Length > 0 || professions.Length > 0 || quests.Length > 0 || skills.Length > 0 || partyAttributes.Length > 0
};
}
@@ -256,9 +269,11 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
InstanceContext instanceContext,
MapEntityContext[] entities,
ProfessionsContext[] professions,
QuestContext[] quests)
QuestContext[] quests,
SkillbarContext[] skillbars,
PartyAttributesContext[] partyAttributes)
{
var playerInformation = GetPlayerInformation(mainPlayerId, instanceContext, entities, professions);
var playerInformation = GetPlayerInformation(mainPlayerId, instanceContext, entities, professions, skillbars, partyAttributes);
_ = Quest.TryParse((int)gameContext.QuestId, out var quest);
var questLog = quests
.Select(q =>
@@ -288,7 +303,8 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
Name = name,
Experience = gameContext.Experience,
Level = gameContext.Level,
Morale = gameContext.Morale
Morale = gameContext.Morale,
CurrentBuild = playerInformation.CurrentBuild
};
}
@@ -297,9 +313,11 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
string name,
InstanceContext instanceContext,
MapEntityContext[] entities,
ProfessionsContext[] professions)
ProfessionsContext[] professions,
SkillbarContext[] skillbars,
PartyAttributesContext[] partyAttributes)
{
var playerInformation = GetPlayerInformation(playerContext.AgentId, instanceContext, entities, professions);
var playerInformation = GetPlayerInformation(playerContext.AgentId, instanceContext, entities, professions, skillbars, partyAttributes);
return new WorldPlayerInformation
{
PrimaryProfession = playerInformation.PrimaryProfession,
@@ -312,6 +330,7 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
EnergyRegen = playerInformation.EnergyRegen,
HealthRegen = playerInformation.HealthRegen,
Name = name,
CurrentBuild = playerInformation.CurrentBuild
};
}
@@ -319,7 +338,9 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
int playerId,
InstanceContext instanceContext,
MapEntityContext[] entities,
ProfessionsContext[] professions)
ProfessionsContext[] professions,
SkillbarContext[] skillbars,
PartyAttributesContext[] partyAttributes)
{
var entityContext = entities.Skip(playerId).FirstOrDefault();
var professionContext = professions.Where(p => p.AgentId == playerId).FirstOrDefault();
@@ -331,6 +352,44 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
.Where(p => p is not null && p != Profession.None)
.OrderBy(p => p.Id)
.ToList();
var maybeSkillbarContext = skillbars.Select(s => (SkillbarContext?) s).FirstOrDefault(s => s?.AgentId == playerId);
var maybePartyAttributesContext = partyAttributes.Select(p => (PartyAttributesContext?) p).FirstOrDefault(p => p?.AgentId == playerId);
Build? build = null;
if (maybeSkillbarContext is SkillbarContext skillbarContext &&
maybePartyAttributesContext is PartyAttributesContext attributesContext &&
primaryProfession is not null &&
secondaryProfession is not null)
{
var attributes = new List<Models.Guildwars.Attribute> { primaryProfession.PrimaryAttribute! }
.Concat(primaryProfession.Attributes)
.Concat(secondaryProfession.Attributes)
.Select(a => new AttributeEntry { Attribute = a })
.ToList();
foreach(var attribute in attributesContext.Attributes)
{
if (attribute.Id < 0 || attribute.Id > 44)
{
continue;
}
var maybeAttributeEntry = attributes.FirstOrDefault(a => a.Attribute!.Id == attribute.Id);
if (maybeAttributeEntry is not AttributeEntry attributeEntry)
{
continue;
}
attributeEntry.Points = (int)attribute.BaseLevel;
}
build = new Build
{
Primary = primaryProfession,
Secondary = secondaryProfession,
Attributes = attributes,
Skills = skillbarContext.Skills.Select(s => Skill.Parse((int)s.Id)).ToList()
};
}
(var currentHp, var currentEnergy) = ApplyEnergyAndHealthRegen(instanceContext, entityContext);
return new PlayerInformation
{
@@ -342,7 +401,8 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
MaxHealth = entityContext.MaxHealth,
MaxEnergy = entityContext.MaxEnergy,
HealthRegen = entityContext.HealthRegen,
EnergyRegen = entityContext.EnergyRegen
EnergyRegen = entityContext.EnergyRegen,
CurrentBuild = build
};
}
@@ -377,5 +437,6 @@ public sealed class GuildwarsMemoryReader : IGuildwarsMemoryReader, IDisposable
this.cancellationTokenSource?.Cancel();
this.cancellationTokenSource?.Dispose();
this.cancellationTokenSource = null;
this.Faulty = false;
}
}
@@ -5,6 +5,7 @@ namespace Daybreak.Services.Scanner;
public interface IGuildwarsMemoryReader
{
bool Faulty { get; }
bool Running { get; }
GameData? GameData { get; }
Process? TargetProcess { get; }
+84 -5
View File
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Daybreak.Views"
xmlns:controls="clr-namespace:Daybreak.Controls"
xmlns:converters="clr-namespace:Daybreak.Converters"
xmlns:templates="clr-namespace:Daybreak.Controls.Templates"
mc:Ignorable="d"
Foreground="White"
@@ -14,6 +15,7 @@
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
<converters:BooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" TriggerValue="True" ></converters:BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
@@ -32,7 +34,8 @@
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="2"
Grid.RowSpan="2">
Grid.RowSpan="2"
Visibility="{Binding ElementName=_this, Path=GameData.Valid, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
@@ -238,19 +241,90 @@
</Grid>
<Grid
Grid.Row="1"
Grid.Column="1">
Grid.Column="1"
Visibility="{Binding ElementName=_this, Path=GameData.Valid, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel
Background="#F0212121"
Grid.Row="0"
Margin="0, 0, 5, 0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
FontSize="18"
Margin="10"
Text="Current Character"
HorizontalAlignment="Left"></TextBlock>
<TextBlock
Grid.Column="1"
FontSize="18"
Margin="10"
Text="{Binding ElementName=_this, Path=GameData.MainPlayer.Name, Mode=OneWay}"
HorizontalAlignment="Center"></TextBlock>
<controls:OpaqueButton
Grid.Column="2"
Text="Edit Build"
Highlight="White"
HighlightOpacity="0.6"
Margin="10"
HorizontalAlignment="Stretch"
TextHorizontalAlignment="Center"
Cursor="Hand"
FontSize="18"
MouseLeftButtonDown="EditBuild_MouseLeftButtonDown"></controls:OpaqueButton>
<controls:OpaqueButton
Grid.Column="3"
Text="Meta Builds"
Highlight="White"
HighlightOpacity="0.6"
Margin="10"
HorizontalAlignment="Stretch"
TextHorizontalAlignment="Right"
Cursor="Hand"
FontSize="18"
MouseLeftButtonDown="MetaBuilds_MouseLeftButtonDown"></controls:OpaqueButton>
</Grid>
<Rectangle
Height="1"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Rectangle>
<controls:OpaqueButton
Text="{Binding ElementName=_this, Path=GameData.MainPlayer.PrimaryProfession.Name, Mode=OneWay}"
Highlight="White"
HighlightOpacity="0.6"
HorizontalAlignment="Stretch"
TextHorizontalAlignment="Left"
Cursor="Hand"
FontSize="20"
MouseLeftButtonDown="PrimaryProfession_MouseLeftButtonDown"></controls:OpaqueButton>
<controls:OpaqueButton
Text="{Binding ElementName=_this, Path=GameData.MainPlayer.SecondaryProfession.Name, Mode=OneWay}"
Highlight="White"
HighlightOpacity="0.6"
HorizontalAlignment="Stretch"
TextHorizontalAlignment="Left"
Cursor="Hand"
FontSize="20"
MouseLeftButtonDown="SecondaryProfession_MouseLeftButtonDown"></controls:OpaqueButton>
</StackPanel>
<StackPanel
Background="#F0212121"
Grid.Row="2"
Margin="0, 0, 5, 0">
<TextBlock
FontSize="18"
Margin="10"
@@ -270,7 +344,7 @@
</StackPanel>
<StackPanel
Background="#F0212121"
Grid.Row="2"
Grid.Row="4"
Margin="0, 0, 5, 0">
<TextBlock
FontSize="18"
@@ -291,7 +365,7 @@
</StackPanel>
<TextBlock
Background="#F0212121"
Grid.Row="4"
Grid.Row="6"
FontSize="18"
Margin="0, 0, 5, 0"
Padding="10"
@@ -300,7 +374,7 @@
Background="#F0212121"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
Grid.Row="5"
Grid.Row="7"
Margin="0, 0, 5, 0">
<templates:QuestLogTemplate
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
@@ -321,5 +395,10 @@
Address="{Binding ElementName=_this, Path=BrowserAddress, Mode=TwoWay}"
MaximizeClicked="Browser_MaximizeClicked"
PreventDispose="True"></controls:ChromiumBrowserWrapper>
<controls:CircularLoadingWidget Grid.ColumnSpan="4"
Grid.RowSpan="3"
Width="100"
Height="100"
Visibility="{Binding ElementName=_this, Path=GameData.Valid, Mode=OneWay, Converter={StaticResource InverseBooleanToVisibilityConverter}}"></controls:CircularLoadingWidget>
</Grid>
</UserControl>
+43 -1
View File
@@ -1,7 +1,9 @@
using Daybreak.Configuration;
using Daybreak.Models;
using Daybreak.Models.Builds;
using Daybreak.Models.Guildwars;
using Daybreak.Services.ApplicationLauncher;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Experience;
using Daybreak.Services.Navigation;
using Daybreak.Services.Scanner;
@@ -15,6 +17,7 @@ using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media.Animation;
namespace Daybreak.Views;
@@ -23,8 +26,12 @@ namespace Daybreak.Views;
/// </summary>
public partial class FocusView : UserControl
{
private const string InfoNamePlaceholder = "[NAME]";
private const string WikiBaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
private const string BuildsAddress = $"https://gwpvx.fandom.com/wiki/Category:Builds_by_category";
private const double BarsTotalSize = 116; // Size of the bars on one side of the screen.
private readonly IBuildTemplateManager buildTemplateManager;
private readonly IApplicationLauncher applicationLauncher;
private readonly IGuildwarsMemoryReader guildwarsMemoryReader;
private readonly IExperienceCalculator experienceCalculator;
@@ -74,6 +81,7 @@ public partial class FocusView : UserControl
private bool browserMaximized = false;
public FocusView(
IBuildTemplateManager buildTemplateManager,
IApplicationLauncher applicationLauncher,
IGuildwarsMemoryReader guildwarsMemoryReader,
IExperienceCalculator experienceCalculator,
@@ -81,6 +89,7 @@ public partial class FocusView : UserControl
ILiveUpdateableOptions<ApplicationConfiguration> liveUpdateableOptions,
ILogger<FocusView> logger)
{
this.buildTemplateManager = buildTemplateManager.ThrowIfNull();
this.applicationLauncher = applicationLauncher.ThrowIfNull();
this.guildwarsMemoryReader = guildwarsMemoryReader.ThrowIfNull();
this.experienceCalculator = experienceCalculator.ThrowIfNull();
@@ -126,7 +135,8 @@ public partial class FocusView : UserControl
this.viewManager.ShowView<LauncherView>();
}
if (this.guildwarsMemoryReader.Running is false)
if (this.guildwarsMemoryReader.Running is false ||
this.guildwarsMemoryReader.Faulty)
{
this.guildwarsMemoryReader.Initialize(this.applicationLauncher.RunningGuildwarsProcess!);
}
@@ -134,6 +144,7 @@ public partial class FocusView : UserControl
this.Dispatcher.Invoke(() =>
{
this.GameData = this.guildwarsMemoryReader.GameData;
this.Browser.Visibility = this.GameData?.Valid is true ? Visibility.Visible : Visibility.Collapsed;
if (this.GameData?.MainPlayer is null ||
this.GameData?.User is null ||
this.GameData?.Session is null)
@@ -491,6 +502,37 @@ public partial class FocusView : UserControl
}
}
private void MetaBuilds_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.BrowserAddress = BuildsAddress;
}
private void PrimaryProfession_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.GameData.MainPlayer?.PrimaryProfession?.Name is string professionName)
{
this.BrowserAddress = WikiBaseAddress.Replace(InfoNamePlaceholder, professionName);
}
}
private void SecondaryProfession_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.GameData.MainPlayer?.SecondaryProfession?.Name is string professionName)
{
this.BrowserAddress = WikiBaseAddress.Replace(InfoNamePlaceholder, professionName);
}
}
private void EditBuild_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (this.GameData.MainPlayer?.CurrentBuild is Build build)
{
var buildEntry = this.buildTemplateManager.CreateBuild();
buildEntry.Build = build;
this.viewManager.ShowView<BuildTemplateView>(buildEntry);
}
}
private void Browser_MaximizeClicked(object sender, EventArgs e)
{
this.browserMaximized = !this.browserMaximized;
+30 -4
View File
@@ -13,10 +13,36 @@ if ($lastVersion.StartsWith("v")){
$lastVersion = $lastVersion.Substring(1)
}
$isNewer = $currentVersion.CompareTo($lastVersion) -eq 1
if ($isNewer -eq $false){
throw "Version is not incremented. Current version " + $currentVersion + ". Last version " + $lastVersion
$currentVersionTokens = $currentVersion.Split('.')
$lastVersionTokens = $lastVersion.Split('.')
if ($currentVersionTokens.Length -eq $lastVersionTokens.Length)
{
for($i = 0 ; $i -lt $currentVersionTokens.Length; $i++)
{
$currentVersionToken = [int]$currentVersionTokens[$i]
$lastVersionToken = [int]$lastVersionTokens[$i]
if ($currentVersionToken -lt $lastVersionToken){
throw "Version is not incremented. Current version " + $currentVersion + ". Last version " + $lastVersion
}
}
if ($currentVersionToken -le $lastVersionToken){
throw "Version is not incremented. Current version " + $currentVersion + ". Last version " + $lastVersion
}
Write-Host "Version has been incremented"
}
else{
elseif ($currentVersionTokens.Length -gt $lastVersionTokens.Length){
if ($currentVersionTokens[$lastVersionTokens.Length - 1] -lt $lastVersionTokens[$lastVersionTokens.Length - 1]){
throw "Version is not incremented. Current version " + $currentVersion + ". Last version " + $lastVersion
}
Write-Host "Version has been incremented"
}
elseif ($currentVersionTokens.Length -lt $lastVersionTokens.Length){
if ($currentVersionTokens[$currentVersionTokens.Length - 1] -le $lastVersionTokens[$currentVersionTokens.Length - 1]){
throw "Version is not incremented. Current version " + $currentVersion + ". Last version " + $lastVersion
}
Write-Host "Version has been incremented"
}