Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Core
9 changes: 9 additions & 0 deletions Source/Data/AchievementSetType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ public enum AchievementSetType
/// </remarks>
Bonus,

/// <summary>
/// A unique way to play the game.
/// </summary>
/// <remarks>
/// Allows loading the core set and potentially bonus sets.
/// Must be explicitly opted-in by the player.
/// </remarks>
Challenge,

/// <summary>
/// A unique way to play the game.
/// </summary>
Expand Down
11 changes: 11 additions & 0 deletions Source/Parser/AchievementScriptInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public AchievementScriptInterpreter()
_achievements = new Dictionary<Achievement, int>();
_leaderboards = new Dictionary<Leaderboard, int>();
_richPresence = new RichPresenceBuilder();
Sets = Array.Empty<AchievementSet>();

_minimumVersion = RATools.Data.Version.MinimumVersion;
}
Expand Down Expand Up @@ -55,6 +56,11 @@ internal void AddAchievement(Achievement achievement)
_achievements[achievement] = 0;
}

/// <summary>
/// Gets the sets generated by the script.
/// </summary>
public IEnumerable<AchievementSet> Sets { get; private set; }

/// <summary>
/// Gets the game identifier from the script.
/// </summary>
Expand Down Expand Up @@ -328,6 +334,7 @@ public bool Run(ExpressionGroupCollection expressionGroups, IScriptInterpreterCa
_achievements.Clear();
_leaderboards.Clear();
_richPresence.Clear();
var sets = new List<AchievementSet>();

foreach (var expressionGroup in expressionGroups.Groups.OfType<AssetExpressionGroup>())
{
Expand All @@ -352,7 +359,11 @@ public bool Run(ExpressionGroupCollection expressionGroups, IScriptInterpreterCa
result = false;
}
}

if (expressionGroup.GeneratedSets != null)
sets.AddRange(expressionGroup.GeneratedSets);
}
Sets = sets;

SoftwareVersion minimumVersion = scriptContext.SerializationContext.MinimumVersion.OrNewer(_minimumVersion);
uint maxAddress = 0;
Expand Down
1 change: 1 addition & 0 deletions Source/Parser/Functions/AchievementSetFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public override bool Evaluate(InterpreterScope scope, out ExpressionBase result)
case "BONUS": set.Type = AchievementSetType.Bonus; break;
case "SPECIALTY": set.Type = AchievementSetType.Specialty; break;
case "EXCLUSIVE": set.Type = AchievementSetType.Exclusive; break;
case "CHALLENGE": set.Type = AchievementSetType.Challenge; break;

case "CORE":
result = new ErrorExpression("Cannot add CORE set. Only one is allowed, and is provided by default.", type);
Expand Down
8 changes: 8 additions & 0 deletions Source/Parser/Internal/AssetExpressionGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public AssetExpressionGroup()

public RichPresenceBuilder GeneratedRichPresence { get; private set; }

public AchievementSet[] GeneratedSets { get; private set; }

protected override ExpressionGroup CreateGroup()
{
return new AssetExpressionGroup();
Expand Down Expand Up @@ -48,6 +50,12 @@ internal void CaptureGeneratedAssets(AchievementScriptContext context)
GeneratedRichPresence = context.RichPresence;
context.RichPresence = null;
}

if (context.Sets.Count > 0)
{
GeneratedSets = context.Sets.ToArray();
context.Sets.Clear();
}
}

internal override void AdjustSourceLines(int adjustment)
Expand Down
15 changes: 15 additions & 0 deletions Source/ViewModels/AssetViewModelBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@ public int Id
protected set { SetValue(IdProperty, value); }
}

public int OwnerSetId
{
get
{
if (Generated.Asset != null && Generated.Asset.OwnerSetId != 0)
return Generated.Asset.OwnerSetId;
if (Local.Asset != null && Local.Asset.OwnerSetId != 0)
return Local.Asset.OwnerSetId;
if (Published.Asset != null && Published.Asset.OwnerSetId != 0)
return Published.Asset.OwnerSetId;
return 0;
}
}

public static readonly ModelProperty PointsProperty = ModelProperty.Register(typeof(AssetViewModelBase), "Points", typeof(int), 0);
public int Points
{
Expand Down Expand Up @@ -187,6 +201,7 @@ private void UpdateModified()
{
Triggers = Local.TriggerList;
TriggerSource = "Local (Not Generated)";
CompareState = GeneratedCompareState.NotGenerated;
}
}
else if (IsModified(Local, true))
Expand Down
22 changes: 9 additions & 13 deletions Source/ViewModels/GameViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,8 @@ internal void PopulateEditorList(AchievementScriptInterpreter interpreter)
GeneratedAchievementCount = 0;
}

if (NavigationNodes == null || !NavigationNodes.Any())
{
var navigationNodes = new List<NavigationViewModelBase>();
navigationNodes.Add(new ScriptFolderNavigationViewModel());
navigationNodes.Add(new RichPresenceNavigationViewModel(null));
navigationNodes.Add(new AssetFolderNavigationViewModel("Achievements"));
navigationNodes.Add(new AssetFolderNavigationViewModel("Leaderboards"));
NavigationNodes = navigationNodes;
}

var navigation = new NavigationListViewModel(this, _publishedAssets, _localAssets, _editors);
navigation.Merge(interpreter);
NavigationNodes = navigation.Merge(interpreter);

SelectedNavigationNode = FindEditorNavigationNode(NavigationNodes, SelectedEditor);
}
Expand All @@ -258,7 +248,7 @@ internal void UpdateCompileProgress(int progress, int line)
}
}

public static readonly ModelProperty NavigationNodesProperty = ModelProperty.Register(typeof(GameViewModel), "Editors", typeof(IEnumerable<NavigationViewModelBase>), new NavigationViewModelBase[0]);
public static readonly ModelProperty NavigationNodesProperty = ModelProperty.Register(typeof(GameViewModel), "NavigationNodes", typeof(IEnumerable<NavigationViewModelBase>), new NavigationViewModelBase[0]);
public IEnumerable<NavigationViewModelBase> NavigationNodes
{
get { return (IEnumerable<NavigationViewModelBase>)GetValue(NavigationNodesProperty); }
Expand Down Expand Up @@ -539,7 +529,13 @@ public string Title
private set { SetValue(TitleProperty, value); }
}

public IEnumerable<AchievementSet> PublishedSets { get { return _publishedAssets?.Sets ?? new AchievementSet[0]; } }
public IEnumerable<AchievementSet> PublishedSets
{
get
{
return _publishedAssets?.Sets ?? new [] { new AchievementSet { OwnerGameId = GameId, Title = Title } };
}
}

public static readonly ModelProperty GeneratedAchievementCountProperty = ModelProperty.Register(typeof(MainWindowViewModel), "GeneratedAchievementCount", typeof(int), 0);
public int GeneratedAchievementCount
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using RATools.Data;

namespace RATools.ViewModels.Navigation
{
internal class AchievementSetFolderNavigationViewModel : AssetFolderNavigationViewModel
{
public AchievementSetFolderNavigationViewModel(AchievementSet achievementSet)
: base(achievementSet.Title)
{
AchievementSet = achievementSet;
}

public AchievementSet AchievementSet { get; private set; }
}
}
91 changes: 81 additions & 10 deletions Source/ViewModels/Navigation/NavigationListViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ public NavigationListViewModel(GameViewModel gameViewModel, PublishedAssets publ
private readonly List<ViewerViewModelBase> _editors;
private readonly IBackgroundWorkerService _backgroundWorkerService;

private void MergeScript()
private void MergeScript(IEnumerable<NavigationViewModelBase> navigationNodes)
{
if (_gameViewModel.Script != null)
{
if (!_editors.Contains(_gameViewModel.Script))
_editors.Add(_gameViewModel.Script);

var scriptFolder = _gameViewModel.NavigationNodes.OfType<ScriptFolderNavigationViewModel>().First();
var scriptFolder = navigationNodes.OfType<ScriptFolderNavigationViewModel>().First();
var scriptNode = scriptFolder.Children.OfType<ScriptNavigationViewModel>().FirstOrDefault();
if (scriptNode == null)
{
Expand Down Expand Up @@ -349,21 +349,45 @@ private void MergeLocal()
}
}

private void UpdateNavigationNodes()
private void UpdateNavigationNodes(IEnumerable<NavigationViewModelBase> navigationNodes)
{
MergeScript();
MergeScript(navigationNodes);

var richPresence = _editors.OfType<RichPresenceViewModel>().FirstOrDefault();
if (richPresence != null)
{
var richPresenceNode = _gameViewModel.NavigationNodes.OfType<RichPresenceNavigationViewModel>().First();
var richPresenceNode = navigationNodes.OfType<RichPresenceNavigationViewModel>().First();
richPresenceNode.Editor = richPresence;
}

var achievementsFolder = _gameViewModel.NavigationNodes.OfType<AssetFolderNavigationViewModel>().First(n => n.Label == "Achievements");
bool hasSubsets = false;
foreach (var achievementSetNode in navigationNodes.OfType<AchievementSetFolderNavigationViewModel>())
{
var achievementsFolder = achievementSetNode.Children.OfType<AssetFolderNavigationViewModel>().First(n => n.Label == "Achievements");
var leaderboardsFolder = achievementSetNode.Children.OfType<AssetFolderNavigationViewModel>().First(n => n.Label == "Leaderboards");
UpdateAchievementSetNodes(achievementsFolder, leaderboardsFolder, achievementSetNode.AchievementSet);
hasSubsets = true;
}

if (!hasSubsets)
{
var achievementsFolder = navigationNodes.OfType<AssetFolderNavigationViewModel>().First(n => n.Label == "Achievements");
var leaderboardsFolder = navigationNodes.OfType<AssetFolderNavigationViewModel>().First(n => n.Label == "Leaderboards");
UpdateAchievementSetNodes(achievementsFolder, leaderboardsFolder, null);
}
}

private void UpdateAchievementSetNodes(AssetFolderNavigationViewModel achievementsFolder, AssetFolderNavigationViewModel leaderboardsFolder, AchievementSet achievementSet)
{
var achievementNodes = achievementsFolder.Children.OfType<AchievementNavigationViewModel>().ToList();
foreach (var achievement in _editors.OfType<AchievementViewModel>())
{
if (achievementSet != null && achievement.OwnerSetId != achievementSet.Id)
{
if (achievement.OwnerSetId != 0 || achievementSet.Type != AchievementSetType.Core)
continue;
}

if (achievement.Generated.Asset == null && achievement.Local.Asset == null && achievement.Published.Asset == null)
{
// nothing keeping this node around, let it get discarded
Expand All @@ -387,7 +411,6 @@ private void UpdateNavigationNodes()
foreach (var achievementNode in achievementNodes)
achievementsFolder.Children.Remove(achievementNode);

var leaderboardsFolder = _gameViewModel.NavigationNodes.OfType<AssetFolderNavigationViewModel>().First(n => n.Label == "Leaderboards");
var leaderboardNodes = leaderboardsFolder.Children.OfType<LeaderboardNavigationViewModel>().ToList();
foreach (var leaderboard in _editors.OfType<LeaderboardViewModel>())
{
Expand Down Expand Up @@ -459,8 +482,54 @@ private static void ApplySort(ObservableCollection<NavigationViewModelBase> node
}
}

public void Merge(AchievementScriptInterpreter interpreter)
public IEnumerable<NavigationViewModelBase> Merge(AchievementScriptInterpreter interpreter)
{
var navigationNodes = _gameViewModel.NavigationNodes;

var previousSubsetCount = navigationNodes != null ? navigationNodes.OfType<AchievementSetFolderNavigationViewModel>().Count() : 0;
var sets = new List<AchievementSet>();
if (interpreter != null)
sets.AddRange(interpreter.Sets);
foreach (var set in _gameViewModel.PublishedSets)
{
if (!sets.Any(s => s.Id == set.Id))
sets.Add(set);
}
if (sets.Count == 0)
sets.Add(new AchievementSet { OwnerGameId = _gameViewModel.GameId, Title = _gameViewModel.Title });

if (sets.Count != previousSubsetCount)
{
var newNavigationNodes = new List<NavigationViewModelBase>();
if (navigationNodes != null && navigationNodes.Any())
{
newNavigationNodes.AddRange(navigationNodes.Take(2));
}
else
{
newNavigationNodes.Add(new ScriptFolderNavigationViewModel());
newNavigationNodes.Add(new RichPresenceNavigationViewModel(null));
}

if (sets.Count < 2)
{
newNavigationNodes.Add(new AssetFolderNavigationViewModel("Achievements"));
newNavigationNodes.Add(new AssetFolderNavigationViewModel("Leaderboards"));
}
else
{
foreach (var achievementSet in sets)
{
var setFolderNode = new AchievementSetFolderNavigationViewModel(achievementSet);
setFolderNode.AddChild(new AssetFolderNavigationViewModel("Achievements"));
setFolderNode.AddChild(new AssetFolderNavigationViewModel("Leaderboards"));
newNavigationNodes.Add(setFolderNode);
}
}

navigationNodes = newNavigationNodes.ToArray();
}

foreach (var editor in _editors.OfType<AssetViewModelBase>())
editor.SortOrder = 0;

Expand All @@ -480,11 +549,13 @@ public void Merge(AchievementScriptInterpreter interpreter)

_backgroundWorkerService.InvokeOnUiThread(() =>
{
UpdateNavigationNodes();
UpdateNavigationNodes(navigationNodes);

foreach (var node in _gameViewModel.NavigationNodes)
foreach (var node in navigationNodes)
ApplySort(node.Children);
});

return navigationNodes;
}
}
}
2 changes: 1 addition & 1 deletion Source/ViewModels/Navigation/NavigationViewModelBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ protected virtual string GetModificationMessage(GeneratedCompareState state)
case GeneratedCompareState.PublishedDiffers: // ◐
return "Generated asset differs from published";
case GeneratedCompareState.NotGenerated: // ◖
return "Published asset is not generated";
return "Local asset is not generated";
default:
return null;
}
Expand Down
10 changes: 5 additions & 5 deletions Source/ViewModels/ViewerViewModelBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,27 +97,27 @@ public enum GeneratedCompareState
None = 0,

/// <summary>
/// generated matches core and/or local. no icon
/// published by not generated or generated matches core and/or local. no icon
/// </summary>
Same,

/// <summary>
/// ◖ not generated (core only). half circle icon
/// ◖ not generated (local only). half circle icon
/// </summary>
NotGenerated,

/// <summary>
/// ○ generated but not stored (no core or no local). hollow circle icon
/// ○ generated but not stored (no published or no local). hollow circle icon
/// </summary>
GeneratedOnly,

/// <summary>
/// ◐ generated differs from core (local may or may not exist). half filled circle icon
/// ◐ generated differs from published (local may or may not exist). half filled circle icon
/// </summary>
PublishedDiffers,

/// <summary>
/// ● generated differs from local (core may or may not exist). fully filled circle icon
/// ● generated differs from local (published may or may not exist). fully filled circle icon
/// </summary>
LocalDiffers,
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/ViewModels/AssetViewModelBaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public void TestRefreshLocalNotGenerated()
Assert.That(vmAsset.IsTitleModified, Is.False);
Assert.That(vmAsset.IsDescriptionModified, Is.False);
Assert.That(vmAsset.BadgeName, Is.EqualTo("Badge"));
Assert.That(vmAsset.CompareState, Is.EqualTo(GeneratedCompareState.None));
Assert.That(vmAsset.CompareState, Is.EqualTo(GeneratedCompareState.NotGenerated));
Assert.That(vmAsset.ModificationMessage, Is.EqualTo("Not generated"));
Assert.That(vmAsset.IsGenerated, Is.False);
Assert.That(vmAsset.CanUpdate, Is.False);
Expand Down
Loading
Loading