Game ideas & features

Your next feature

Validated Actions

Have the server validate game actions.

SDK developRequires a player session
Godot
Illustration of Validated Actions
Your visible result

A valid action is accepted and an invalid action is rejected.

Validate game actions3:12
Open video separately ↗

Prepare the same project

  1. Choose the same project in the dashboard as in your game configuration.

    Validated Actions →
  2. Create or reuse these test entries in the dashboard form. These are example values, not current project data.

    Key (slug)
    weekly
    Accept scores only from validated runs
    true
    Maximum score
    20000
    Minimum duration (seconds)
    0
    Stage required
    false

    In a test project, save these rules with other limits unset. The fixed quickstart bytes test the request protocol. Score 18250 should pass. Start a new run with 20001 to check rejection. Record actual game inputs in your game.

    Leaderboard →
  3. Save, reload and verify the entries before running the example. Preserve unrelated definitions.

Build this feature

You can preview the guide. Running it requires an active project key. Prepare project

SDK installed, project configuration imported and player signed in.

This SDK example uses develop. Check whether the required APIs exist in your installed SDK.

Save the GDScript, attach it to a node in the main scene and run it. Check Output.

GDScript
res://scripts/validated_actions.gd
horizOn callSetup
1# Attach this script to a node in your main scene.
2extends Node
3​
4var input_log: PackedByteArray = "quickstart".to_utf8_buffer()
5​
6​
7func _ready() -> void:
8 # Setup: initialize, connect and sign in a player.
9 var connected = await Horizon.connect_to_server()
10 if not connected:
11 print("Failed to connect to horizOn server")
12 return
13 if not Horizon.auth.isSignedIn():
14 var signed_in: bool
15 if Horizon.auth.hasCachedAnonymousToken():
16 signed_in = await Horizon.auth.restoreAnonymousSession()
17 else:
18 signed_in = await Horizon.auth.signUpAnonymous("StatisticsPlayer")
19 if not signed_in:
20 return
21​
22 # horizOn: start a run, record the input, submit the validated score.
23 # 1. Dashboard: turn on "Validated submissions only" for the board "weekly"
24​
25 # 2. Round start: single-use ticket plus server seed
26 var run: Dictionary = await Horizon.validatedActions.startRun("weekly")
27 if run.is_empty():
28 print(Horizon.validatedActions.getLastErrorCode()) # e.g. RUN_RATE_LIMITED
29 return
30 var rng := RandomNumberGenerator.new()
31 rng.seed = run["seed"]
32​
33 # Protocol test input only. Replace it with actual recorded game inputs in your game.
34​
35 # 3. Round end: score plus input log (the SDK sends its SHA-256 hash)
36 var result: Dictionary = await Horizon.validatedActions.submitValidated(18250, input_log)
37 if result.is_empty():
38 print(Horizon.validatedActions.getLastErrorCode())
39 return
40 print("Accepted score=", result.get("score"), ", rank=", result.get("rank"))
Open the complete SDK sample ↗

Test your new feature.

A valid action is accepted and an invalid action is rejected.

Choose the same project in the dashboard as in your game configuration.

Endpoints
  • POST/validated-actions/runs
  • POST/validated-actions/submit
All endpoints in the API reference
Our suggestion for your next step

Give every round a high score.

Save the score after a round and show who's ahead. Keep using your connection and player session.

Tutorial video

Validated ActionsGodot6:05
Open video separately ↗
Server-owned valuesGodot4:58
Open video separately ↗
Input logGodot5:45
Open video separately ↗