The .NET binding
C#, F# and PowerShell share one generated net8.0 assembly, Clunkyard.dll,
which calls the core's C ABI through P/Invoke. It loads under the image's
.NET 10 runtime and PowerShell's .NET 9 runtime. The API, record layouts,
enums and conformance dispatch are generated from protocol/v2/api.json.
Only loading, the run loop and exception mapping are written by hand.
Install with make install SDK=/opt/clunkyard/sdk. Reference
/opt/clunkyard/sdk/bindings/csharp/Clunkyard.dll when compiling and set
Private to false on that reference. Run with
dotnet /opt/clunkyard/sdk/bindings/csharp/host/Clunkyard.Host.dll bot.dll.
The SDK host resolves the binding from the image; the artifact holds only
its own program and other dependencies. The binding loads
libclunkyard.so.2, or the file named by CLUNKYARD_LIB.
Without Make, run node install.cjs SDK_DIRECTORY with your installed .NET SDK.
Both commands use the same installer and need no Unix shell utilities on Windows.
Build files stay in a temporary directory; only the binding and host assemblies
are installed into the selected SDK. Set CLUNKYARD_LIB to the matching native
core library, including clunkyard.dll on Windows or libclunkyard.2.dylib on
macOS. The player CLI selects that path for local matches.
Subsystems and facts are properties. Methods use PascalCase. Optional
records are null, and optional scalars are nullable value types. Controls
accept nullable fields, with named arguments for changing only one field;
fields merge within the turn. Drive.Get("throttle") reads one back.
Throw new Forfeit(code, message) to forfeit. Other exceptions are logged
with their trace and send the controls already set. Clunkyard.Play plays
lines in memory for tests.
A tiny robot
using Clunkyard;
class Bot : Robot {
public override void OnTurn(){
var target=Sensors.Nearest;
if(target==null){
Drive.Set(throttle:0.75,turn:0.25);
Scanner.Set(Me.Heading,40);
Status.Set("SEARCH",Scanner.Last.Arc);
return;
}
double power=Gun.PowerForFlightTime(target.Range,1);
var aim=Gun.Lead(target,power);
Gun.Aim(aim?.Heading??target.Bearing,aim?.Pitch??target.Elevation);
if(Gun.CanFire(power,10))Gun.Fire(power);
Drive.Set(throttle:0.5,turn:Angles.Clamp(Angles.AngleDiff(target.Bearing,Me.Heading)));
Scanner.Set(target.Bearing,10);
Status.Set("TRACK",target.Range);
}
static void Main()=>Clunkyard.Clunkyard.Run(new Bot());
}
make test SDK=... compares every API vector with the core's transcript,
including exact floating-point results and act lines. The tiny robot also
participates in the cross-language act identity check.
Names
Every entry of the robot API 2.0.0 in C# / .NET. names.md has every language side by side.
| Canonical | Form | C# / .NET |
|---|---|---|
match.mode |
property | Match.Mode |
match.ruleset |
property | Match.Ruleset |
match.control |
property | Match.Control |
match.robots |
property | Match.Robots |
match.is_3d |
property | Match.Is3d |
match.tick_rate |
property | Match.TickRate |
match.max_ticks |
property | Match.MaxTicks |
match.robot_id |
call | Match.RobotId |
clock.tick |
property | Clock.Tick |
clock.seconds |
property | Clock.Seconds |
clock.remaining_ticks |
property | Clock.RemainingTicks |
arena.size |
property | Arena.Size |
arena.gravity |
property | Arena.Gravity |
arena.terrain_kind |
property | Arena.TerrainKind |
arena.ground_height |
call | Arena.GroundHeight |
me.health |
property | Me.Health |
me.position |
property | Me.Position |
me.velocity |
property | Me.Velocity |
me.heading |
property | Me.Heading |
me.pitch |
property | Me.Pitch |
me.roll |
property | Me.Roll |
me.angular_velocity |
property | Me.AngularVelocity |
me.attitude |
property | Me.Attitude |
me.grounded |
property | Me.Grounded |
me.altitude |
property | Me.Altitude |
me.applied |
property | Me.Applied |
battery.charge |
property | Battery.Charge |
battery.capacity |
property | Battery.Capacity |
battery.regen |
property | Battery.Regen |
battery.sustainable_drive |
property | Battery.SustainableDrive |
battery.compute |
property | Battery.Compute |
battery.drive_cost |
call | Battery.DriveCost |
drive.hover_lift |
property | Drive.HoverLift |
drive.set |
control | Drive.Set |
drive.forces |
control | Drive.Forces |
drive.get |
call | Drive.Get |
gun.aim_now |
property | Gun.AimNow |
gun.cooldown_ticks |
property | Gun.CooldownTicks |
gun.spread |
property | Gun.Spread |
gun.max_power |
property | Gun.MaxPower |
gun.damage_scale |
property | Gun.DamageScale |
gun.can_fire |
call | Gun.CanFire |
gun.shot_speed |
call | Gun.ShotSpeed |
gun.shot_cost |
call | Gun.ShotCost |
gun.reload_ticks |
call | Gun.ReloadTicks |
gun.shot_damage |
call | Gun.ShotDamage |
gun.power_for_speed |
call | Gun.PowerForSpeed |
gun.power_for_flight_time |
call | Gun.PowerForFlightTime |
gun.lead |
call | Gun.Lead |
gun.lead_point |
call | Gun.LeadPoint |
gun.aim |
control | Gun.Aim |
gun.fire |
control | Gun.Fire |
gun.get |
call | Gun.Get |
scanner.last |
property | Scanner.Last |
scanner.proximity_range |
property | Scanner.ProximityRange |
scanner.reach |
call | Scanner.Reach |
scanner.arc_for_reach |
call | Scanner.ArcForReach |
scanner.set |
control | Scanner.Set |
scanner.get |
call | Scanner.Get |
sensors.contacts |
property | Sensors.Contacts |
sensors.nearest |
property | Sensors.Nearest |
sensors.cues |
property | Sensors.Cues |
sensors.contact |
call | Sensors.Contact |
sensors.position_of |
call | Sensors.PositionOf |
tracker.cue |
property | Tracker.Cue |
tracker.nearest_bearing_rate |
property | Tracker.NearestBearingRate |
tracker.velocity |
call | Tracker.Velocity |
tracker.position |
call | Tracker.Position |
tracker.last_seen |
call | Tracker.LastSeen |
tracker.configure |
call | Tracker.Configure |
nav.zone |
property | Nav.Zone |
nav.zone.margin |
call | Nav.Zone.Margin |
nav.zone.contains |
call | Nav.Zone.Contains |
nav.zone.distance_from |
call | Nav.Zone.DistanceFrom |
nav.storm |
property | Nav.Storm |
nav.storm.margin |
call | Nav.Storm.Margin |
nav.storm.contains |
call | Nav.Storm.Contains |
nav.storm.distance_from |
call | Nav.Storm.DistanceFrom |
nav.hill |
property | Nav.Hill |
nav.hill.margin |
call | Nav.Hill.Margin |
nav.hill.contains |
call | Nav.Hill.Contains |
nav.hill.distance_from |
call | Nav.Hill.DistanceFrom |
nav.pickups |
property | Nav.Pickups |
nav.nearest_pickup |
call | Nav.NearestPickup |
nav.field_distance |
call | Nav.FieldDistance |
score.me |
property | Score.Me |
score.best |
property | Score.Best |
score.armour |
property | Score.Armour |
angles.normalize |
call | Angles.Normalize |
angles.angle_diff |
call | Angles.AngleDiff |
angles.bearing_to |
call | Angles.BearingTo |
angles.elevation_to |
call | Angles.ElevationTo |
angles.direction |
call | Angles.Direction |
angles.distance |
call | Angles.Distance |
angles.clamp |
call | Angles.Clamp |
status.set |
control | Status.Set |
status.get |
call | Status.Get |
raw.number |
call | Raw.Number |
raw.text |
call | Raw.Text |
raw.has |
call | Raw.Has |
raw.flag |
call | Raw.Flag |
raw.count |
call | Raw.Count |
raw.line |
call | Raw.Line |
raw.extra |
call | Raw.Extra |
session.event |
property | Session.Event |
session.next |
call | Session.Next |
session.send |
call | Session.Send |
session.forfeit |
call | Session.Forfeit |
session.log |
call | Session.Log |
session.feed |
call | Session.Feed |
session.reply |
call | Session.Reply |