gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/v0⧉ Realm Open in gnoweb ↗
Kind Realm (renderable)
Name v0
Namespace g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd / gnofly / arena
Exported functions 21
Module gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/v0
gno 0.9 json.gno gno
⧉
1 package arena 2 3 import "strings" 4 5 // The JSON documents are built by hand. That is safe because every string 6 // that reaches them was validated against a JSON-safe charset when it was 7 // written: ids are hex, modes and nonces [a-z0-9-], tickets hex, addresses ArenaJSON (id string) string
ArenasJSON () string
CancelRound (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, id string)
Claim (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}) int64
Claimable (addr string) int64
ClaimsJSON (addr string) string
EarningsJSON () string
Enter (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, spec string, ticket string) string
Escrowed () int64
ExpireLobby (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, id string)
Leave (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, id string)
PlayerJSON (addr string) string
RefundDelay () int64
RefundRound (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, id string)
Render (path string) string
ResultJSON (id string) string
ResultsJSON () string
SetRefundDelay (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, seconds int64)
SettleRound (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, id string, deaths string)
StartRound (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, id string) int64
Version () int64
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
8
// bech32. The one string that is not under the realm's control, an address
9 // typed into a query, goes through quote.
10 //
11 // Ordering is deterministic everywhere: arenas follow their id (the tree
12 // iterates in key order), a lobby and a round the order of entry, results
13 // are newest first and earnings best first.
14
15 // ArenasJSON returns every arena someone paid into and whose game is not
16 // over, as a JSON array sorted by id:
17 //
18 // [
19 // { "id": "3f2a...", "mode": "deathmatch", "stake": 10000000,
20 // "minSeats": 2, "maxSeats": 8, "lives": 3, "seconds": 900, "killTarget": 5,
21 // "creator": "g1...", "created": 1790950000, "nonce": "k3x9",
22 // "lobby": [ { "address": "g1...", "ticket": "9f86d0...00a08" } ],
23 // "round": { "startedAt": 1790950300, "players": [ "g1...", "g1..." ] } }
24 // ]
25 //
26 // The output has no whitespace. "round" is null until the game starts.
27 // The fields from "mode" to "nonce" are the arena's spec: the game server
28 // rebuilds the spec string, and so the id, from them.
29 func ArenasJSON() string {
30 var b strings.Builder
31 b.WriteByte( '[' )
32 first := true
33 arenas.Iterate( "" , "" , func (id string , v any ) bool {
34 if !first {
35 b.WriteByte( ',' )
36 }
37 first = false
38 writeArena(&b, id, v.(*arena))
39 return false
40 })
41 b.WriteByte( ']' )
42 return b.String()
43 }
44
45 // ArenaJSON returns one arena in the shape of ArenasJSON, or null.
46 func ArenaJSON(id string ) string {
47 a := getArena(id)
48 if a == nil {
49 return "null"
50 }
51 var b strings.Builder
52 writeArena(&b, id, a)
53 return b.String()
54 }
55
56 func writeArena(b *strings.Builder, id string , a *arena) {
57 b.WriteString( `{"id":"` + id + `","mode":"` + a.mode + `"` )
58 for _, f := range [] struct {
59 k string
60 v int64
61 }{{ "stake" , a.stake}, { "minSeats" , a.minSeats}, { "maxSeats" , a.maxSeats}, { "lives" , a.lives},
62 { "seconds" , a.seconds}, { "killTarget" , a.killTarget}} {
63 b.WriteString( `,"` + f.k + `":` + itoa(f.v))
64 }
65 b.WriteString( `,"creator":"` + a.creator.String() + `","created":` + itoa(a.created) + `,"nonce":"` + a.nonce + `"` )
66 b.WriteString( `,"lobby":[` )
67 for i, p := range a.lobby {
68 if i > 0 {
69 b.WriteByte( ',' )
70 }
71 b.WriteString( `{"address":"` + p.String() + `","ticket":"` + a.tickets[i] + `"}` )
72 }
73 b.WriteString( `],"round":` )
74 if a.round == nil {
75 b.WriteString( "null}" )
76 return
77 }
78 b.WriteString( `{"startedAt":` + itoa(a.round.startedAt) + `,"players":[` )
79 for i, p := range a.round.players {
80 if i > 0 {
81 b.WriteByte( ',' )
82 }
83 b.WriteString( `"` + p.String() + `"` )
84 }
85 b.WriteString( "]}}" )
86 }
87
88 // ResultsJSON returns the last closed games, newest first, at most 50:
89 //
90 // [ { "id": "3f2a...", "mode": "deathmatch", "stake": 10000000,
91 // "outcome": "settled", "players": 2, "pot": 20000000, "fee": 500000,
92 // "closedAt": 1790951000,
93 // "payouts": [ { "address": "g1...", "amount": 19500000 } ] } ]
94 func ResultsJSON() string {
95 var b strings.Builder
96 b.WriteByte( '[' )
97 for i := len(closed) - 1 ; i >= 0 ; i-- {
98 if i < len(closed)- 1 {
99 b.WriteByte( ',' )
100 }
101 r, _ := resultOf(closed[i])
102 writeResult(&b, closed[i], r)
103 }
104 b.WriteByte( ']' )
105 return b.String()
106 }
107
108 // ResultJSON returns the result of one closed game in the shape of
109 // ResultsJSON, or null when the realm does not have it (still running, or
110 // too old).
111 func ResultJSON(id string ) string {
112 r, ok := resultOf(id)
113 if !ok {
114 return "null"
115 }
116 var b strings.Builder
117 writeResult(&b, id, r)
118 return b.String()
119 }
120
121 func writeResult(b *strings.Builder, id string , r result) {
122 b.WriteString( `{"id":"` + id + `","mode":"` + r.mode + `","stake":` + itoa(r.stake) +
123 `,"outcome":"` + r.outcome + `","players":` + itoa(r.players) + `,"pot":` + itoa(r.pot) +
124 `,"fee":` + itoa(r.fee) + `,"closedAt":` + itoa(r.closedAt) + `,"payouts":[` )
125 for i, p := range r.payouts {
126 if i > 0 {
127 b.WriteByte( ',' )
128 }
129 b.WriteString( `{"address":"` + p.Address.String() + `","amount":` + itoa(p.Amount) + `}` )
130 }
131 b.WriteString( "]}" )
132 }
133
134 // EarningsJSON returns the top winners as a JSON array, best first, at most
135 // 10 entries:
136 //
137 // [ { "address": "g1...", "won": 19000000, "rounds": 3 } ]
138 //
139 // The output has no whitespace. "won" adds up, round after round, what the
140 // player was paid above their own stake, never less than zero for a round.
141 // "rounds" is how many settled rounds they played. With equal winnings, the
142 // player who got there first stays ahead.
143 func EarningsJSON() string {
144 var b strings.Builder
145 b.WriteByte( '[' )
146 for i, addr := range winners.addrs {
147 if i > 0 {
148 b.WriteByte( ',' )
149 }
150 writeTotals(&b, `"` +addr.String()+ `"` , totalsOf(addr))
151 }
152 b.WriteByte( ']' )
153 return b.String()
154 }
155
156 // PlayerJSON returns one player's totals as a JSON object:
157 //
158 // { "address": "g1...", "won": 19000000, "rounds": 3 }
159 //
160 // The output has no whitespace. An unknown address returns the same shape
161 // with zero won and zero rounds.
162 func PlayerJSON(addr address) string {
163 var b strings.Builder
164 writeTotals(&b, quote(addr.String()), totalsOf(addr))
165 return b.String()
166 }
167
168 // writeTotals writes the totals of a player. quoted is the player's address
169 // as a JSON string literal, quotes included.
170 func writeTotals(b *strings.Builder, quoted string , t totals) {
171 b.WriteString( `{"address":` )
172 b.WriteString(quoted)
173 b.WriteString( `,"won":` )
174 b.WriteString(itoa(t.won))
175 b.WriteString( `,"rounds":` )
176 b.WriteString(itoa(t.rounds))
177 b.WriteByte( '}' )
178 }
179
180 // quote returns s as a JSON string literal, quotes included. It is for the
181 // strings the realm did not validate. Quotes and backslashes are escaped and
182 // anything outside printable ASCII is replaced by "?", so the result is
183 // valid JSON whatever s holds.
184 func quote(s string ) string {
185 var b strings.Builder
186 b.WriteByte( '"' )
187 for i := 0 ; i < len(s); i++ {
188 c := s[i]
189 switch {
190 case c == '"' || c == '\\' :
191 b.WriteByte( '\\' )
192 b.WriteByte(c)
193 case c < 0x20 || c > 0x7e :
194 b.WriteByte( '?' )
195 default :
196 b.WriteByte(c)
197 }
198 }
199 b.WriteByte( '"' )
200 return b.String()
201 }
202
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.