GameAchievements 0.2.0
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package GameAchievements --version 0.2.0
NuGet\Install-Package GameAchievements -Version 0.2.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GameAchievements" Version="0.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GameAchievements" Version="0.2.0" />
<PackageReference Include="GameAchievements" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GameAchievements --version 0.2.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: GameAchievements, 0.2.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GameAchievements@0.2.0
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GameAchievements&version=0.2.0
#tool nuget:?package=GameAchievements&version=0.2.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Achievements Library
A small, composable achievements framework with:
- Pluggable criteria (AbstractCriterion<TCondition, TContext>) and conditions (ICondition<TContext>). Convenience self-referential base: AbstractCriterion<TContext> with CriterionCondition<TContext>.
- Heterogeneous evaluators that can be nested (CompositeEvaluator) and bound to independent, lazily provided runtime contexts.
- A fluent AchievementBuilder to define achievements with readable AllOf/AnyOf groups and explicit Add or AddCustom methods for flexible context injection.
Core Types
- ICriterion: Marker for a criterion.
- ICriterion<TContext>: Runtime-evaluable criterion.
- ICondition<TContext>: Requirement data that can test a runtime TContext.
- CriterionCondition<TContext>: Convenience abstract base when condition & context share the same type.
- AbstractCriterion<TCondition, TContext>: Base when requirement type (TCondition) differs from runtime context (TContext).
- AbstractCriterion<TContext>: Convenience base for self-referential (same-type) requirement/context.
- ICriterionEvaluator: Evaluates a unit or group of criteria.
- SingleEvaluator<TCondition,TContext>: Binds a criterion to a Func<TContext> context provider.
- SingleEvaluator<TContext>: Backwards compatible self-referential wrapper.
- CompositeEvaluator: Groups evaluators with All (AND) or Any (OR) semantics; allows nesting.
- Achievement: Name, Description, and a root evaluator; IsUnlocked() evaluates the tree.
- AchievementBuilder: Fluent API to compose achievements via Add (self-referential) / AddCustom (distinct types) plus AllOf/AnyOf then Build().
Quick Start (Self-Referential Condition & Context)
Create a criterion and condition:
public sealed class KillCountCondition : CriterionCondition<KillCountCondition>
{
public int Kills { get; init; }
public int RequiredKills { get; init; }
public override bool RequirementsMet(KillCountCondition ctx) => ctx.Kills >= RequiredKills;
}
public sealed class KillCountCriterion : AbstractCriterion<KillCountCondition>
{
public KillCountCriterion(int required) => Condition = new KillCountCondition { RequiredKills = required };
protected override KillCountCondition Condition { get; }
}
Bind to live state via a context provider and build achievements:
var state = new GameState();
Func<KillCountCondition> KillsCtx = () => new KillCountCondition { Kills = state.Kills };
Func<TimePlayedCondition> TimeCtx = () => new TimePlayedCondition { MinutesPlayed = state.Minutes };
Func<ScoreCondition> ScoreCtx = () => new ScoreCondition { Score = state.Score };
// Single criterion
var firstBlood = AchievementBuilder
.CreateNew("First Blood", "Get your first kill")
.Add(">= 1 kill", new KillCountCriterion(1), KillsCtx)
.Build();
// AND (All)
var grinder = AchievementBuilder
.CreateNew("Grinder", "10 kills AND 30 minutes")
.AllOf("All of", b =>
{
b.Add(">= 10 kills", new KillCountCriterion(10), KillsCtx);
b.Add(">= 30 minutes", new TimePlayedCriterion(30), TimeCtx);
})
.Build();
// OR (Any)
var versatile = AchievementBuilder
.CreateNew("Versatile", "1000 score OR 50 kills")
.AnyOf("Either", b =>
{
b.Add("1000 score", new ScoreCriterion(1000), ScoreCtx);
b.Add("50 kills", new KillCountCriterion(50), KillsCtx);
})
.Build();
// Nested: A AND ((B OR C) AND D)
var nested = AchievementBuilder
.CreateNew("Nested Mastery", "A AND ((B OR C) AND D)")
.AllOf("Outer AND", outer =>
{
outer.Add("A: >= 5 kills", new KillCountCriterion(5), KillsCtx);
outer.AllOf("Inner AND", innerAnd =>
{
innerAnd.AnyOf("(B OR C)", innerOr =>
{
innerOr.Add("B: 1500 score", new ScoreCriterion(1500), ScoreCtx);
innerOr.Add("C: >= 10 kills", new KillCountCriterion(10), KillsCtx);
});
innerAnd.Add("D: >= 60 minutes", new TimePlayedCriterion(60), TimeCtx);
});
})
.Build();
Distinct Requirement vs Runtime Context (AddCustom)
Sometimes your stored requirement type differs from the runtime context snapshot. Example: store only a threshold but evaluate against a broader PlayerState.
public sealed class LevelRequirement : ICondition<PlayerState>
{
public int RequiredLevel { get; init; }
public bool RequirementsMet(PlayerState ctx) => ctx.Level >= RequiredLevel;
}
public sealed class LevelCriterion : AbstractCriterion<LevelRequirement, PlayerState>
{
public LevelCriterion(int minLevel) => Condition = new LevelRequirement { RequiredLevel = minLevel };
protected override LevelRequirement Condition { get; }
}
public sealed class PlayerState { public int Level { get; set; } }
var player = new PlayerState();
var levelAchievement = AchievementBuilder
.CreateNew("Novice", "Reach level 5")
.AddCustom("Level >= 5", new LevelCriterion(5), () => player)
.Build();
Static readonly achievements
public static class GameAchievements
{
public static readonly Achievement FirstBlood = AchievementBuilder
.CreateNew("First Blood", "Get your first kill")
.Add(">= 1 kill", new KillCountCriterion(1), () => new KillCountCondition { Kills = Game.State.Kills })
.Build();
}
Demo
This repo includes a Demo console app that simulates state changes and prints unlock statuses.
Run:
dotnet build
dotnet run --project Demo/Demo.csproj
Design Tips
- Keep condition objects small & immutable; they are requirement data.
- Context providers should build a fresh snapshot each evaluation (avoid mutation inside the object returned unless intentional).
- Use AddCustom when the requirement (condition) type differs from the runtime context object.
- Achievements evaluate on demand; add a tracker if you need evented unlocks or persistence.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.