const EventImported, EventNotImported
EventImported is a v1 record copied in; EventNotImported one left on v1, a shot of it finer than v2 takes (validShot): its ghost would not replay here.
Package golf is the game realm: it keeps the holes, the players' rounds, the records and the rankings. Every hole is ...
Package golf is the game realm: it keeps the holes, the players' rounds, the records and the rankings. Every hole is data (a GG1 string, p/…/course), never code: golf decodes it and plays it with p/…/physics. The owner publishes the course's holes into slots of a cup ("garden/7"), each publish a new version ("garden/7/v2"); once the owner opens publishing, anyone can publish a community hole ("<address>/<slug>/v1", PublishMine), playable and recorded but outside the course and its ranking.
Reads take a version's id or its alias ("garden/7", "<address>/<slug>"), its current version. Writes take the exact id only, as HoleState or Holes gave it: a round cannot be replayed on a version it was not played on.
Who can change what (in full on the hub page): the owner holds one power, the course itself: its holes (Publish), what the lists show (Hide), and whether anyone can publish (SetPublishing).
EventImported is a v1 record copied in; EventNotImported one left on v1, a shot of it finer than v2 takes (validShot): its ghost would not replay here.
1const (
2 EventHolePublished = "HolePublished" // hole, slot, sha, by, official ("true"/"false")
3 EventHoleRetired = "HoleRetired" // hole, next
4 EventShot = "Shot" // hole, player, strokes, mode, shot ("angle,power,tick" as recorded)
5 EventHoled = "Holed" // hole, player, strokes, mode, shots (the round's)
6 EventCopyNotRanked = "CopyNotRanked" // hole, player, mode: a record sent again, kept, not ranked
7 EventRoundReset = "RoundReset" // hole, player
8 EventOwnershipOffered = "OwnershipOffered" // owner, to
9 EventOwnershipOfferCancelled = "OwnershipOfferCancelled" // owner
10 EventOwnershipTransfer = "OwnershipTransfer" // from, to
11 EventOwnershipRenounced = "OwnershipRenounced" // from
12 EventPlayURLSet = "PlayURLSet" // url
13 EventSuccessorSet = "SuccessorSet" // successor
14 EventHoleHidden = "HoleHidden" // slot, hidden ("true"/"false")
15 EventPublishingSet = "PublishingSet" // open ("true"/"false")
16)The events golf emits, and their attributes. A hole is always "hole", a player "player".
PeriodSeconds is how long one weather lasts.
Accept takes the role a Transfer offered the caller.
BestOf is a player's best finished round on a hole in a mode, 0 if none.
Bests is the best finished round on one hole, in a mode, of each of the given players (comma-separated addresses, named or not): a board of friends, where no stranger and no bot can push anyone off.
Claim ranks the caller's bests kept while they had no name: on the boards of the course's current holes, in both modes, and in the course ranking. It returns how many bests it seated, and refuses a caller with no gno.land name. It reads the course's holes only, so it costs the same for everyone.
Community is a page of every community hole, every version of each, by id: all that Holes leaves out. It is paged like Records.
CourseLeaderboard is a page of a mode's course ranking, paged like HoleLeaderboard. holes is the course's current holes, players how many the ranking holds.
Current is the id of the version an alias ("garden/7", "<address>/<slug>") plays now, "" if the alias has none.
Drain takes up to n players (1 to 400) of archived holes out of the course standings, sooner than the finishes would, and returns how many archived holes still have players in them. Anyone can call it. A standing it empties is kept at 0 holes (setRow): nothing is refunded to the caller.
Extras is what a timed hole adds at one stroke of a round (0 is the first), to draw over HoleState's field. Empty for other holes.
Ghost is a player's best round on a hole in a mode, named or not, with its height (the first to a score ranks first), period and shots, or null: what a duel races. It replays in its own weather (SimulateRoundIn for the first stroke, then SimulateFrom from each rest).
Hide takes a community hole ("<address>/<slug>", every version) off the lists (the hub, Holes, the 3D game), for a scam or abuse in its name or note; hide=false puts it back. Only the owner can. Its data, rounds and page stay, Community still has it, and a new version stays hidden. A hole already as asked is left alone, with no event.
HoleData is a version's GG1, in hex, as it was published (an alias gives its current version's): what a later version of the rules or an auditor reads back.
HoleLeaderboard is a page of a hole's board in a mode: named players' bests, fewest strokes then first there, from rank offset+1 (clamped to 0..players), at most limit rows (1..100). players is the named players, finished anyone who finished; next is the next offset, 0 at the end. A name deleted since is skipped, so a page may hold fewer rows. A page reads its own rows only.
HoleRank is a player's place on a hole's board in a mode, with their best, as Rank: 0 if unnamed or no finish there.
HoleState is the hole as JSON for a client: geometry, skins (names the client looks up), weather and wear, all it needs to draw the hole and aim. hole is a version's id or an alias; "hole" in the answer is always the version's id, the one to write with, with its "slot" and "v", and an archived one's "next".
A shot's path (Round, Simulate*) is the flight the chain computed: replay it, never re-simulate. Points far apart are a tunnel: do not interpolate.
Holes lists at most maxListed holes for a client's menu, as listed orders them: the course's current holes, its latest archived versions, then community holes, newest first, perAuthor an address, none hidden (the rest are in Community). official marks the course's holes, the only ones in a cup and the course ranking; next is the version that replaced a hole, slot its alias, play the 3D client's link, successor the realm that took the course over ("" if none). It decodes nothing.
ImportHole copies v1's current version of a course slot, by its id ("garden/7/v3"): its data, provenance (by, height, note), plays and wear. Only the owner can, into a slot v2 has nothing in yet.
ImportRecord copies a player's v1 best on an imported hole in a mode (v1's Ghost: strokes, height, period, shots) and seats it as a finish would, onto the hole imported from v1 (the same data: its sha is v1's). Only the owner can, as the migration's script runs it: v1 plays on, with no near-copy rule, so a round played there later is not one to rank here. Idempotent: a record already as good stays; a better v1 one takes its place. A record with a shot finer than 0.01 (never one the game sends) stays on v1. It answers whether it copied anything.
Launch plays one shot of the caller's round on hole (an exact id): angle in degrees (0 = right, 90 = down), power in (0, 10]. It is how gnoweb plays, with no aim preview, so its rounds are pro rounds. It answers with where the ball stopped, or the score if holed; PlayRoundAt commits many shots.
Leaderboard is a mode's course-wide top ten ("assisted" or "pro"): named players' bests on the current course holes, summed; most holes, then the best score against par (strokes - par), then the first there. Its cost does not grow with players.
Period is the weather period of the chain's current block time.
PlayRound is PlayRoundAt in the current period, for a caller with none to give (a form, a script); a round under way keeps its own. Prefer PlayRoundAt: a commit included after the weather turned is then played in the weather its shots were chosen in.
PlayRoundAt replays shots into the caller's assisted round on hole (an exact id), continuing it, in the weather of period: the current one or the one before, and a round under way keeps its own. The client sends decisions, never outcomes: the chain replays them.
shots is "angle,power[,tick];…" (MsgCall carries no slice), at most 12, fewer on a heavy hole: a commit past the work budget is refused with the number of shots that fit, and the rest goes in the next commit.
PlayRoundPro is PlayRoundAt for a round played in pro mode: the aim preview cut short. It counts on the pro records and rankings only.
Players is a page of every course standing in a mode, named or not: its holes, strokes and par (all the ranking's key reads) and the height of the finish that last improved it (the tie-break), paged like Records.
Publish puts a course hole's data into its slot as its next version and returns the new id ("garden/7/v2"). Only the owner can. hexData is the hole as course.Encode wrote it, in hex. slot must be the data's own world and order ("garden/7", order 1 to 999), so a mis-edited file cannot replace the wrong hole; the course holds at most 9999 slots (maxCourse). Data identical to the current version's is refused. The version it replaces is archived: its records stay, its bests leave the course standings. note (at most 140 characters, cleaned) says why.
PublishMine publishes a community hole of the caller's own and returns its id: "<caller>/<slug>/v1", then v2 and on. Anyone can while publishing is open (SetPublishing); only the same address adds versions. slug is 1 to 32 of a-z, 0-9 and "-". The data is checked as Publish checks it, its world and order aside; its name and note carry no web address. It is playable and recorded, in no cup and not in the course ranking; a new version of a hidden hole stays hidden. The publisher pays the storage deposit (about half a GNOT a version), and nothing published can be deleted.
Publishing is whether PublishMine is open.
Rank is a player's place in a mode's course ranking, with their standing: "rank" 1 is the top, out of "of"; 0 if unnamed or no current course hole finished. A name deleted since keeps its place until its next change, so a rank may be that many too low.
Records is a page of every player's best on a hole in a mode, named or not, with the height that ranks it before a later tie: all a successor needs to carry the boards over in their order. The paged reads (Records, Players, Community) walk everything by key: after is the last key of the page before ("" for the first), limit is clamped to 1..100, next is the after of the next page ("" at the end).
Render is the game as text: gnoweb draws the board and submits the shot.
Paths: "" the hub; "<world>" a cup's holes; "<address>" the holes an address published; "<hole>" a hole's page, "<hole>/<address>" the same with that player's ball, "<hole>/data" a version's provenance and data. <hole> is a version's id or an alias. A query string ("?…") is ignored.
Renounce gives the role up for good: no owner, no offer, and none possible.
Reset abandons the caller's round under way on hole (an exact id), freeing its storage: the next stroke starts a new one from the tee. A finished round is not kept (its best is), so a new one needs no Reset. With no round under way it does nothing, and says nothing.
Round is one player's round under way on a hole with its last stroke's path, or null if they have none: never started, holed (its best is kept: Ghost) or Reset. It costs one stroke of gas.
SetPlayURL moves the link every page gives to the 3D client. Only the owner can. url is https://, at most 100 of letters, digits and "-._~/:%", with no query or fragment: a hole's link adds "?cup=…&hole=…" to it.
SetPublishing opens community publishing (PublishMine) or closes it again. Only the owner can. Closing stops new holes and versions only: every hole published stays playable and listed. Setting it as it is does nothing.
SetSuccessor names the realm that takes this course over, once and for good: a pkgpath under gno.land/r/, not golf itself, with no "", "." or ".." segment. Only the owner can. It moves and blocks nothing: the pages and Holes say where the course went, and play goes on here. golf does not check the realm exists: check the path before sending.
1func SimulateCommit(hole string, ballX, ballY float64, stroke int, shots string, period int64) stringSimulateCommit previews the next PlayRoundAt (or PlayRoundPro) commit, read-only: shots from the exact ball ("rest") at stroke number stroke (0 is the first) in period's weather. It refuses what that commit would (too much work, too many strokes, a weather over), so a client checks every commit before it signs any. JSON as SimulateRound; strokes counts after the commit.
1func SimulateFrom(hole string, ballX, ballY float64, shot string, stroke int, period int64) stringSimulateFrom previews one shot, read-only: from an exact ball (a "rest" answered before), shot "angle,power,tick", its stroke number (0 is the first; timed and pulse holes change with it) and any period not ahead. It is what PlayRoundAt would play, for one shot's gas. As a vm/qeval query it needs no transaction or wallet: a client animates a shot the instant it is released.
SimulateRound replays a shot list from the tee, read-only, and returns its last shot and stroke count: what PlayRound would record, refusals included. Continue from an exact "rest" (SimulateFrom): rounded points are for drawing.
SimulateRoundAt is SimulateRound in a period's weather, the current one or the one before, as a round's first stroke: it agrees with PlayRoundAt.
SimulateRoundIn is SimulateRound in any period gone by, to check a recorded round as the chain played it. Weather still to come is refused.
Standings is each given player's course-wide standing in a mode: how many of the course's current holes they finished, in how many strokes, and those holes' pars summed.
Successor is the realm that took this course over, "" if none.
Transfer offers the role to another address, which takes it with Accept. Offering it to the owner themselves cancels an offer.
Versions is every version of an alias, oldest first (the newest pageMax if there are more): its id, number, the height it was published at, by whom, its data's sha256, its note, and the version that took its place. slot is the alias, "" (and no versions) for one that has none.
Weather is a hole's weather in a period, as JSON: the zones a client draws and the chain plays under. Its "gas" is what a commit there spends before its first shot (decoding and forecast), counted against the commit's budget: a client adds it to its shots' estimate. A future period panics.