PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd / gnofly / arena
Files
15 (gnomod.toml)
Exported functions
21
Module
gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/v0
gno
0.9

Files (15)

  • gnomod.tomltoml
  • arena.gnogno
  • claims.gnogno
  • doc.gnogno
  • earnings.gnogno
  • errors.gnogno
  • escrow.gnogno
  • json.gnogno
  • lobby.gnogno
  • render.gnogno
  • results.gnogno
  • roles.gnogno
  • rounds.gnogno
  • spec.gnogno
  • validate.gnogno
  • render.gnogno
    1package arena23import (4	"strings"5	"time"67	"gno.land/p/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/payout/v0"8

    Functions

    • 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.

    Rendered

    RenderedRawgnoweb ↗
    )
    9
    10// Render returns the state of the arenas as markdown, for gnoweb:
    11//
    12// "" the open arenas and the last games played
    13// "arena/<id>" one arena: its rules, lobby and game, or its result
    14// "earnings" the top winners
    15//
    16// Everything printed here was validated against a narrow charset when it was
    17// written (see spec.gno and validate.gno), or is an address the chain gave
    18// the realm. The only caller-supplied value, the id of an arena page, is
    19// printed only if it is a valid id. Nothing needs markdown escaping.
    20func Render(path string) string {
    21 switch {
    22 case path == "":
    23 return renderHome()
    24 case path == "earnings":
    25 return renderEarnings()
    26 case strings.HasPrefix(path, "arena/"):
    27 id := strings.TrimPrefix(path, "arena/")
    28 if a := getArena(id); a != nil {
    29 return renderArena(id, a)
    30 }
    31 if r, ok := resultOf(id); ok {
    32 return renderResult(id, r)
    33 }
    34 }
    35 return "# gnofly arenas\n\nPage not found. Go back to the [overview](" + link("") + ").\n"
    36}
    37
    38// link returns the gnoweb URL of a Render path of this realm.
    39func link(path string) string {
    40 if path == "" {
    41 return webPath
    42 }
    43 return webPath + ":" + path
    44}
    45
    46func renderHome() string {
    47 var b strings.Builder
    48 b.WriteString("# gnofly arenas\n\n")
    49 b.WriteString("Paid games of gnofly, a multiplayer plane game, created by players at [gnofly.xyz/arena](https://gnofly.xyz/arena).\n")
    50 b.WriteString("A pilot pays the entry price to join, the realm keeps the stakes until the game is over, then credits them by the rule of its mode. Winners claim what they are owed with Claim.\n")
    51 b.WriteString("The house takes " + percent(feeBps) + " of what a settled game pays out.\n\n")
    52
    53 b.WriteString("## Open arenas\n\n")
    54 if arenas.Size() == 0 {
    55 b.WriteString("No arena has players right now.\n\n")
    56 } else {
    57 b.WriteString("| Arena | Mode | Entry | Seats | Lives | Time | Kill target | Pilots |\n|---|---|---|---|---|---|---|---|\n")
    58 arenas.Iterate("", "", func(id string, v any) bool {
    59 a := v.(*arena)
    60 pilots := itoa(int64(len(a.lobby))) + " waiting"
    61 if a.round != nil {
    62 pilots = itoa(int64(len(a.round.players))) + " playing"
    63 }
    64 b.WriteString("| [" + id[:8] + "](" + link("arena/"+id) + ") | " + a.mode + " | " + gnot(a.stake) +
    65 " | " + itoa(a.minSeats) + " to " + itoa(a.maxSeats) + " | " + itoa(a.lives) +
    66 " | " + itoa(a.seconds/60) + " min | " + targetCell(a.killTarget) + " | " + pilots + " |\n")
    67 return false
    68 })
    69 b.WriteByte('\n')
    70 }
    71
    72 b.WriteString("## Last games\n\n")
    73 if len(closed) == 0 {
    74 b.WriteString("No game is over yet.\n\n")
    75 } else {
    76 b.WriteString("| Arena | Mode | Outcome | Pilots | Pot | Fee |\n|---|---|---|---|---|---|\n")
    77 for i := len(closed) - 1; i >= 0 && i >= len(closed)-10; i-- {
    78 r, _ := resultOf(closed[i])
    79 b.WriteString("| [" + closed[i][:8] + "](" + link("arena/"+closed[i]) + ") | " + r.mode + " | " + r.outcome +
    80 " | " + itoa(r.players) + " | " + gnot(r.pot) + " | " + gnot(r.fee) + " |\n")
    81 }
    82 b.WriteByte('\n')
    83 }
    84
    85 b.WriteString("| | |\n|---|---|\n")
    86 b.WriteString("| In escrow | " + gnot(escrowed) + " |\n")
    87 b.WriteString("| Refund delay | " + itoa(refundDelay) + " s |\n\n")
    88 b.WriteString("- [Earnings](" + link("earnings") + "): " + itoa(int64(len(winners.addrs))) + " ranked pilots\n")
    89 return b.String()
    90}
    91
    92func renderArena(id string, a *arena) string {
    93 var b strings.Builder
    94 b.WriteString("# Arena " + id[:8] + "\n\n")
    95 b.WriteString("Mode `" + a.mode + "`: " + modeDoc(a.mode) + "\n\n")
    96
    97 b.WriteString("| | |\n|---|---|\n")
    98 b.WriteString("| Id | `" + id + "` |\n")
    99 b.WriteString("| Entry | " + gnot(a.stake) + " |\n")
    100 b.WriteString("| Seats | " + itoa(a.minSeats) + " to " + itoa(a.maxSeats) + " |\n")
    101 b.WriteString("| Lives | " + itoa(a.lives) + " |\n")
    102 b.WriteString("| Game time | " + itoa(a.seconds/60) + " min |\n")
    103 b.WriteString("| Kill target | " + targetCell(a.killTarget) + " |\n")
    104 b.WriteString("| Created by | " + a.creator.String() + " |\n")
    105 b.WriteString("| Takes entries until | " + clock(a.created+entryWindow) + " |\n\n")
    106
    107 if a.round == nil {
    108 b.WriteString("## Lobby\n\n")
    109 b.WriteString("Pilots who paid and wait for the game. They can leave with `Leave` until it starts.\n\n")
    110 b.WriteString("| Seat | Pilot |\n|---|---|\n")
    111 for i, player := range a.lobby {
    112 b.WriteString("| " + itoa(int64(i+1)) + " | " + player.String() + " |\n")
    113 }
    114 } else {
    115 r := a.round
    116 b.WriteString("## Game\n\n")
    117 b.WriteString("Started at " + clock(r.startedAt) + " with " + itoa(int64(len(r.players))) +
    118 " pilots and a pot of " + gnot(a.stake*int64(len(r.players))) + ".\n")
    119 b.WriteString("If the referee does not settle it, anyone can send the stakes back with `RefundRound` from " +
    120 clock(r.startedAt+a.seconds+refundDelay) + ".\n\n")
    121 b.WriteString("| Pilot |\n|---|\n")
    122 for _, player := range r.players {
    123 b.WriteString("| " + player.String() + " |\n")
    124 }
    125 }
    126 b.WriteString("\n[Earnings](" + link("earnings") + ") | [Overview](" + link("") + ")\n")
    127 return b.String()
    128}
    129
    130func renderResult(id string, r result) string {
    131 var b strings.Builder
    132 b.WriteString("# Arena " + id[:8] + "\n\n")
    133 b.WriteString("Mode `" + r.mode + "`, " + itoa(r.players) + " pilots, closed at " + clock(r.closedAt) + ": " + r.outcome + ".\n\n")
    134 b.WriteString("| | |\n|---|---|\n")
    135 b.WriteString("| Entry | " + gnot(r.stake) + " |\n")
    136 b.WriteString("| Pot | " + gnot(r.pot) + " |\n")
    137 b.WriteString("| Fee | " + gnot(r.fee) + " |\n")
    138 b.WriteString("| Paid | " + paidCell(r) + " |\n")
    139 b.WriteString("\n[Overview](" + link("") + ")\n")
    140 return b.String()
    141}
    142
    143// targetCell formats a kill target: most arenas end on the clock only.
    144func targetCell(n int64) string {
    145 if n == 0 {
    146 return "none"
    147 }
    148 return itoa(n) + " kills"
    149}
    150
    151// paidCell lists who was paid what in a round, for a table cell.
    152func paidCell(r result) string {
    153 if r.outcome != outcomeSettled {
    154 return "every stake sent back"
    155 }
    156 if len(r.payouts) == 0 {
    157 return "nobody"
    158 }
    159 parts := make([]string, len(r.payouts))
    160 for i, p := range r.payouts {
    161 parts[i] = p.Address.String() + " " + gnot(p.Amount)
    162 }
    163 return strings.Join(parts, ", ")
    164}
    165
    166func renderEarnings() string {
    167 var b strings.Builder
    168 b.WriteString("# gnofly arena earnings\n\n")
    169 b.WriteString("The top " + itoa(topSize) + " pilots by what they won above their own stakes, over every settled round.\n\n")
    170 if len(winners.addrs) == 0 {
    171 b.WriteString("Nobody won anything yet.\n")
    172 } else {
    173 b.WriteString("| Rank | Pilot | Won | Rounds |\n|---|---|---|---|\n")
    174 for i, addr := range winners.addrs {
    175 t := totalsOf(addr)
    176 b.WriteString("| " + itoa(int64(i+1)) + " | " + addr.String() +
    177 " | " + gnot(t.won) + " | " + itoa(t.rounds) + " |\n")
    178 }
    179 }
    180 b.WriteString("\n[Back to the overview](" + link("") + ")\n")
    181 return b.String()
    182}
    183
    184// modeDoc is one sentence about the payout rule of a mode.
    185func modeDoc(mode string) string {
    186 switch mode {
    187 case payout.ModeBattleRoyale:
    188 return "the pot, less the fee, goes to the last pilot flying; when the clock runs out, to the pilot still in with the most kills."
    189 case payout.ModeDeathmatch:
    190 return "the pot, less the fee, goes to the top three by kills: 60%, 30% and 10%."
    191 }
    192 return "see the payout package."
    193}
    194
    195// gnot formats an amount of ugnot in GNOT, without trailing zeros:
    196// 10000000 gives "10 GNOT", 9500000 gives "9.5 GNOT", 1 gives "0.000001 GNOT".
    197func gnot(ugnot int64) string {
    198 whole, frac := ugnot/1000000, ugnot%1000000
    199 if frac == 0 {
    200 return itoa(whole) + " GNOT"
    201 }
    202 decimals := itoa(1000000 + frac)[1:] // all six of them, zeros included
    203 end := len(decimals)
    204 for decimals[end-1] == '0' {
    205 end--
    206 }
    207 return itoa(whole) + "." + decimals[:end] + " GNOT"
    208}
    209
    210// percent formats basis points as a percentage, without trailing zeros:
    211// 500 gives "5%", 250 gives "2.5%", 1 gives "0.01%".
    212func percent(bps int64) string {
    213 whole, frac := bps/100, bps%100
    214 switch {
    215 case frac == 0:
    216 return itoa(whole) + "%"
    217 case frac%10 == 0:
    218 return itoa(whole) + "." + itoa(frac/10) + "%"
    219 case frac < 10:
    220 return itoa(whole) + ".0" + itoa(frac) + "%"
    221 }
    222 return itoa(whole) + "." + itoa(frac) + "%"
    223}
    224
    225// clock formats a block time in Unix seconds, in UTC.
    226func clock(unix int64) string {
    227 return time.Unix(unix, 0).UTC().Format("2006-01-02 15:04:05") + " UTC"
    228}
    229

    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.