Skip to content

feat: la semilla del dia, el mismo campo para todos los que jueguen hoy - #37

Closed
leocagli wants to merge 1 commit into
mainfrom
semilla-del-dia-v2
Closed

leocagli wants to merge 1 commit into
mainfrom
semilla-del-dia-v2

Conversation

@leocagli

Copy link
Copy Markdown
Collaborator

Reemplaza al #24, que quedo en conflicto cuando main avanzo con el sistema de guardado, el Coliseo y el jefe mundial. En vez de pelear con marcas de conflicto se volvieron a aplicar las ocho ediciones sobre el arbol nuevo.

La issue #3 sigue viva en main hoy: los tres new Field(...) de lib/game.js no llevan semilla, asi que cada salida a la pradera es la misma pradera.

Primero de tres. Este trae la semilla del dia; el jefe del mundo y los duelos
necesitan contratos y van aparte.

Que cambia para el que juega

Hoy el campo se sembraba con el valor por defecto en los tres lugares donde nace
un Field, asi que cada salida a la pradera era exactamente la misma pradera.
Eso es la issue #3.

Ahora la semilla sale del numero de ledger de Stellar partido en bloques de un
dia. Todos los que jueguen hoy caminan el mismo campo, con los mismos bichos
en los mismos lugares. Manana es otro.

Lo que se compara entre jugadores deja de ser oro suelto y pasa a ser cuanto
aguantaste vos en el campo de hoy.

Por que la cadena y no un servidor

La semilla tiene que cumplir tres cosas: ser igual para todos, cambiar sola, y
que no la haya elegido nadie. Las dos primeras las da cualquier servidor. La
tercera exige que vos puedas comprobarlo por tu cuenta, y por eso sirve un
contador publico que ni el dueno del juego puede mover.

Lo que NO pide

Ni billetera, ni fondos, ni transacciones. Es un GET. Alguien que nunca oyo
hablar de cripto lo juega sin enterarse.

Sin internet cae a una semilla local derivada del jugador, que igual arregla la
issue #3 para el que juega solo. La consulta no bloquea ningun cuadro y nadie la
espera.

Verificado

Dos clientes independientes, sin coordinarse:

primera consulta : {"seed":3310838056,"day":250,"sequence":4320980}
otro jugador     : {"seed":3310838056,"day":250,"sequence":4320980}
coinciden        : true

Y esa semilla llega al mundo:

campo de hoy    = 88721f6c  28 bichos   0@28,13 1@28,20 2@13,30
otro jugador    = 88721f6c  iguales:  true
otro dia        = 8f57e2ee  distinto: true
el viejo (1)    = 2bb6c4bf  distinto: true

La parte tecnica que costo

@stellar/stellar-sdk no carga en Bare: pide TextDecoder, y despues
Event, porque trae su propio cliente HTTP pensado para navegador o Node.

Lo que si funciona es @stellar/stellar-base empaquetado con
--conditions=browser. Esa bandera es la clave: hace que @noble/curves elija
su camino de WebCrypto en vez del que hace require('node:crypto'), que es el
modulo que Bare no tiene. Faltan tres globals mas y los pone lib/stellar.js.

Todo esto queda explicado en vendor/README.md, incluido por que el bundle esta
commiteado: npm run make arma binarios para seis plataformas, y quien clona
tiene que poder jugar sin pasos extra. Se regenera con npm run vendor:stellar.

Sobre los tests

Ocho nuevos, y ninguno toca la red. Un test que pida la semilla de verdad se
pone rojo cuando el RPC publico tiene un mal dia, y eso no prueba el juego sino
el clima. El RPC se reemplaza por una funcion que devuelve el ledger que
queramos, y se prueba lo que decide runa: como se mezcla la semilla, que dos
momentos del mismo dia den el mismo campo, que dias vecinos den campos bien
distintos y no casi calcados, y que si la cadena no contesta no se rompa nada.

tests   = 70/70 pass   (eran 62)
asserts = 488/488 pass
lint    = limpio

Un detalle que elegi a conciencia

Se usa el numero de ledger y no su hash. El hash del ledger que abrio el dia
seria impredecible, que suena mejor, pero para leerlo hay que pedirle al RPC un
ledger de hace 24 horas y eso cae justo en el borde de lo que el RPC conserva.
Un jugador lo conseguiria y otro no, y entonces no caminarian el mismo campo,
que era todo el punto.

Entre impredecible y que todos coincidan, coincidir gana: el mapa del dia se
comparte igual apenas el primero lo publique.

Refs #3

Reaplicado sobre el main actual. La version anterior de esta rama quedo en
conflicto cuando main avanzo con el sistema de guardado, el Coliseo y el jefe
mundial, asi que en vez de pelear con marcas de conflicto se volvieron a aplicar
las ocho ediciones sobre el arbol nuevo.

El campo se sembraba con el valor por defecto en los tres lugares donde nace un
Field, asi que cada salida a la pradera era exactamente la misma pradera. Es la
issue #3, y sigue viva en main hoy: los tres `new Field(...)` no llevan semilla.

Ahora la semilla sale del numero de ledger de Stellar partido en bloques de un
dia. Todos los que jueguen hoy caminan el mismo campo, con los mismos bichos en
los mismos lugares. Manana es otro. Verificado: dos clientes independientes
sacan seed 3310838056 para el dia 250, y esa semilla produce 28 bichos
identicos.

Por que la cadena y no un servidor: la semilla tiene que ser igual para todos,
cambiar sola, y sobre todo que no la haya elegido nadie. Las dos primeras las da
cualquier servidor. La tercera exige que el jugador pueda comprobarlo por su
cuenta, y por eso sirve un contador publico que ni el dueno del juego puede
mover.

No hace falta billetera, ni fondos, ni transacciones. Es un GET. Quien nunca oyo
hablar de cripto lo juega sin enterarse, y sin internet cae a una semilla local
derivada del jugador, que igual arregla la issue #3 para el que juega solo. La
consulta no bloquea ningun cuadro y nadie la espera.

@stellar/stellar-sdk no carga en Bare: pide TextDecoder y despues Event. Se usa
@stellar/stellar-base empaquetado con --conditions=browser, que es lo que hace
que @noble/curves deje de pedir node:crypto. Los tres globals que faltan los
pone lib/stellar.js. Todo explicado en vendor/README.md, incluido por que el
bundle esta commiteado: npm run make arma binarios para seis plataformas y quien
clona tiene que poder jugar sin pasos extra. Se regenera con npm run
vendor:stellar.

Ocho tests nuevos y ninguno toca la red: un test que pida la semilla de verdad
se pone rojo cuando el RPC publico tiene un mal dia, y eso no prueba el juego
sino el clima.

  antes    65 tests, 515 asserts
  ahora    73 tests, 530 asserts

lint limpio y git diff --check limpio.

Refs #3
Comment thread lib/game.js
Comment on lines +870 to +871
this.startChain()
this.startChain()

@gitar-bot gitar-bot Bot Aug 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: startChain() called twice in loadSlot

startChain() is invoked twice back-to-back after loading a slot, so dailySeed() fires two independent RPC requests to the public Soroban endpoint every time a game is loaded. The second call is pure waste and doubles network/timeout pressure. Remove the duplicate line so only one call remains.

Remove the duplicate startChain() call.:

this.startPresence()
this.startChain()
this.announce()

Was this helpful? React with 👍 / 👎

Comment thread lib/game.js
Comment on lines +402 to +413
startChain() {
if (!this.chain || !this.chain.available) return
this.chain
.dailySeed()
.then((d) => {
if (!d) return
this.daySeed = d.seed
this.dayNumber = d.day
this.noteLater('el campo de hoy es el dia ' + d.day + ', igual para todos')
})
.catch(() => {})
}

@gitar-bot gitar-bot Bot Aug 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: New games never fetch the daily seed

startChain() is only called from loadSlot(), not from beginNewGame(). A player who starts a fresh game therefore only ever gets the local player-derived seed and never daySeed, so the core feature of this PR — everyone who plays today walks the same field — does not apply until they save and reload. Call startChain() in beginNewGame() alongside startPresence().

Kick off the daily-seed fetch when a new game begins, as loadSlot already does.:

this.say(`bienvenido, ${this.name}. usa wasd o flechas; las puertas se abren al pisarlas.`)
this.startPresence()
this.startChain()
this.saveCurrent()
return true

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 0 resolved / 2 findings

Implements a shared daily seed derived from the Stellar ledger to synchronize field generation across players. Fixes include resolving startChain() being called twice in loadSlot and ensuring new games also fetch the daily seed.

⚠️ Bug: startChain() called twice in loadSlot

📄 lib/game.js:870-871

startChain() is invoked twice back-to-back after loading a slot, so dailySeed() fires two independent RPC requests to the public Soroban endpoint every time a game is loaded. The second call is pure waste and doubles network/timeout pressure. Remove the duplicate line so only one call remains.

Remove the duplicate startChain() call.
this.startPresence()
this.startChain()
this.announce()
⚠️ Bug: New games never fetch the daily seed

📄 lib/game.js:890-904 📄 lib/game.js:402-413

startChain() is only called from loadSlot(), not from beginNewGame(). A player who starts a fresh game therefore only ever gets the local player-derived seed and never daySeed, so the core feature of this PR — everyone who plays today walks the same field — does not apply until they save and reload. Call startChain() in beginNewGame() alongside startPresence().

Kick off the daily-seed fetch when a new game begins, as loadSlot already does.
this.say(`bienvenido, ${this.name}. usa wasd o flechas; las puertas se abren al pisarlas.`)
this.startPresence()
this.startChain()
this.saveCurrent()
return true
🤖 Prompt for agents
Code Review: Implements a shared daily seed derived from the Stellar ledger to synchronize field generation across players. Fixes include resolving startChain() being called twice in loadSlot and ensuring new games also fetch the daily seed.

1. ⚠️ Bug: startChain() called twice in loadSlot
   Files: lib/game.js:870-871

   `startChain()` is invoked twice back-to-back after loading a slot, so `dailySeed()` fires two independent RPC requests to the public Soroban endpoint every time a game is loaded. The second call is pure waste and doubles network/timeout pressure. Remove the duplicate line so only one call remains.

   Fix (Remove the duplicate startChain() call.):
   this.startPresence()
   this.startChain()
   this.announce()

2. ⚠️ Bug: New games never fetch the daily seed
   Files: lib/game.js:890-904, lib/game.js:402-413

   `startChain()` is only called from `loadSlot()`, not from `beginNewGame()`. A player who starts a fresh game therefore only ever gets the local player-derived seed and never `daySeed`, so the core feature of this PR — everyone who plays today walks the same field — does not apply until they save and reload. Call `startChain()` in `beginNewGame()` alongside `startPresence()`.

   Fix (Kick off the daily-seed fetch when a new game begins, as loadSlot already does.):
   this.say(`bienvenido, ${this.name}. usa wasd o flechas; las puertas se abren al pisarlas.`)
   this.startPresence()
   this.startChain()
   this.saveCurrent()
   return true

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 7 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

@leocagli

Copy link
Copy Markdown
Collaborator Author

Reemplazado por el PR nuevo, reconstruido sobre el main de hoy. Este entro en conflicto cuando se mergeo el #19.

@leocagli leocagli closed this Aug 25, 2026
@leocagli
leocagli deleted the semilla-del-dia-v2 branch August 25, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant