milestones

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 30, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package milestones tracks subject progress toward typed criteria: events flow in, the registry routes them by Type, evaluators decide which criteria apply per subject, counters increment, and threshold crossings emit Reached records.

Common applications:

  • Games — achievement systems ("kill 100 skaven warriors").
  • Apps — gamified onboarding milestones, engagement KPIs.
  • Trading-bot — fee-tier accumulators, personal-finance goals.

The package ships an in-memory Store backend; consumers needing durability supply a Postgres-backed Store implementing the same interface.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Criterion

type Criterion struct {
	ID     CriterionID
	Type   CriterionType
	Target int64
	Params map[string]any // type-specific config consumed by Evaluator
}

Criterion is the durable definition of "track this kind of event for this subject until counter ≥ Target".

type CriterionID

type CriterionID uint32

CriterionID is a unique identifier for one criterion instance (one achievement-row, one milestone definition).

type CriterionType

type CriterionType uint16

CriterionType identifies a class of criteria evaluated together — "kill_creature", "spend_currency", "complete_quest", etc.

type Evaluator

type Evaluator interface {
	Match(c Criterion, e Event) bool
}

Evaluator decides whether an Event matches a Criterion's filter. For a "kill X creature" criterion, the evaluator checks e.Tags["creature"] against Criterion.Params["creature_id"]. The evaluator does not need to compare types — Tracker only routes events of matching Type.

type EvaluatorFunc

type EvaluatorFunc func(c Criterion, e Event) bool

EvaluatorFunc adapts a function to the Evaluator interface.

func (EvaluatorFunc) Match

func (f EvaluatorFunc) Match(c Criterion, e Event) bool

type Event

type Event struct {
	Type    CriterionType
	Subject SubjectID
	Amount  int64
	Tags    map[string]string
}

Event is a single observation that may or may not advance counters. Subject identifies who the event is for; Type routes it to matching Evaluators; Amount is the value added to any criterion that matches; Tags carry type-specific dimensions (e.g. {"creature": "skaven_warlord"}).

type InMemoryStore

type InMemoryStore struct {
	// contains filtered or unexported fields
}

InMemoryStore is a concurrent-safe Store backed by a map. Suitable for tests and ephemeral use; production consumers should supply a Postgres-backed store implementing the same interface.

func NewInMemoryStore

func NewInMemoryStore() *InMemoryStore

NewInMemoryStore returns an empty in-memory store.

func (*InMemoryStore) Get

func (s *InMemoryStore) Get(_ context.Context, subject SubjectID, criterion CriterionID) (int64, error)

Get returns the current counter for (subject, criterion).

func (*InMemoryStore) Inc

func (s *InMemoryStore) Inc(_ context.Context, subject SubjectID, criterion CriterionID, by int64) (int64, error)

Inc atomically increments and returns the new value.

type Reached

type Reached struct {
	Subject   SubjectID
	Criterion CriterionID
	Final     int64
}

Reached is fired when a criterion crosses its target. Emitted from Tracker.Record as a slice (multiple criteria may cross from one event).

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry binds CriterionTypes to Evaluators.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty registry.

func (*Registry) RegisterEvaluator

func (r *Registry) RegisterEvaluator(t CriterionType, e Evaluator)

RegisterEvaluator binds an Evaluator to a CriterionType.

type Store

type Store interface {
	// Get returns the current counter for (subject, criterion). Returns
	// 0 if no prior progress is recorded.
	Get(ctx context.Context, subject SubjectID, criterion CriterionID) (int64, error)
	// Inc atomically increments and returns the new value.
	Inc(ctx context.Context, subject SubjectID, criterion CriterionID, by int64) (int64, error)
}

Store persists per-subject counters. The default in-memory backend is safe for tests; production consumers supply a Postgres or Redis implementation.

type SubjectID

type SubjectID uint64

SubjectID is whatever the consumer treats as the bearer of progress: player, account, character, organisation — opaque to this package.

type Tracker

type Tracker struct {
	// contains filtered or unexported fields
}

Tracker is the runtime state: it knows which criteria are active per subject and routes events through the registry to advance counters.

func NewTracker

func NewTracker(reg *Registry, store Store) *Tracker

NewTracker returns a Tracker over a registry and a store.

func (*Tracker) Activate

func (t *Tracker) Activate(subject SubjectID, c Criterion)

Activate registers a criterion as in-progress for a subject. Idempotent.

func (*Tracker) Deactivate

func (t *Tracker) Deactivate(subject SubjectID, criterion CriterionID)

Deactivate stops tracking a criterion for a subject. The store's counter is preserved (consumers can re-Activate to resume).

func (*Tracker) Progress

func (t *Tracker) Progress(ctx context.Context, subject SubjectID, criterion CriterionID) (current int64, target int64, err error)

Progress returns the current counter and target for a subject's criterion (whether or not the criterion is currently activated).

func (*Tracker) Record

func (t *Tracker) Record(ctx context.Context, e Event) ([]Reached, error)

Record routes an event through every active criterion for its subject whose Type matches and whose Evaluator returns true. Returns the list of criteria that crossed their target as a result of this event.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL