summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorewy <ewy0@protonmail.com>2026-09-22 15:05:51 +0200
committerewy <ewy0@protonmail.com>2026-09-22 15:05:51 +0200
commit3eacf89dded0121d2a50fb01dec5d8ccbfbbe4ee (patch)
treebce32fd935807c2d5a0daaee76d9a75bdc27f99c
parent83b2f2e9922f46fe46fd5330e6b38c66d1483ade (diff)
naive auth
-rw-r--r--.pik/serve.sh2
-rw-r--r--data/cirno/cirno.go5
-rw-r--r--data/dummy/cards.go10
-rw-r--r--engine/card.go20
-rw-r--r--engine/game.go45
-rw-r--r--engine/player.go16
-rw-r--r--engine/stack.go6
-rw-r--r--server/api/game.go60
-rw-r--r--server/server.go3
9 files changed, 141 insertions, 26 deletions
diff --git a/.pik/serve.sh b/.pik/serve.sh
new file mode 100644
index 0000000..3b47db1
--- /dev/null
+++ b/.pik/serve.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+go run -tags server .
diff --git a/data/cirno/cirno.go b/data/cirno/cirno.go
index d0d89c3..612697a 100644
--- a/data/cirno/cirno.go
+++ b/data/cirno/cirno.go
@@ -1,11 +1,12 @@
package cirno
import (
+ "sakura/data/dummy"
"sakura/engine"
)
var Cirno = &engine.Character{
Name: "Cirno",
- Cards: nil,
- Ultimates: nil,
+ Cards: dummy.Dummy.Cards,
+ Ultimates: dummy.Dummy.Ultimates,
}
diff --git a/data/dummy/cards.go b/data/dummy/cards.go
index 7fde0c8..10c438f 100644
--- a/data/dummy/cards.go
+++ b/data/dummy/cards.go
@@ -13,9 +13,11 @@ var Cards = []engine.IsCard{
Text: "Attack a little",
Flavor: "",
},
- MinDistance: card.NoMinimumRange,
- MaxDistance: card.NoMaximumRange,
- AuraDamage: 1,
- LifeDamage: 1,
+ Range: &card.Range{
+ MinimumRange: card.NoMinimumRange,
+ MaximumRange: card.NoMaximumRange,
+ },
+ AuraDamage: 1,
+ LifeDamage: 1,
},
}
diff --git a/engine/card.go b/engine/card.go
index 3eb6a8f..fce1af0 100644
--- a/engine/card.go
+++ b/engine/card.go
@@ -1,5 +1,7 @@
package engine
+import "slices"
+
type Card struct {
Name string
AllOut bool
@@ -19,3 +21,21 @@ type IsCard interface {
Base() *Card
CanPlay(g *Game) bool
}
+
+type CardInstance struct {
+ *Card
+ Visible bool
+}
+
+var secretCardStruct = &Card{
+ Name: "?",
+}
+
+var SecretCard = &CardInstance{
+ Card: secretCardStruct,
+ Visible: false,
+}
+
+func Secrets(size int) Stack {
+ return slices.Repeat([]IsCard{SecretCard}, size)
+}
diff --git a/engine/game.go b/engine/game.go
index 8365869..0735958 100644
--- a/engine/game.go
+++ b/engine/game.go
@@ -5,22 +5,24 @@ import (
)
type Turn struct {
- Player *Player
+ Player *Player `json:"-"`
+ PlayerSlot string `json:"Player"`
ActionTaken bool
- Actions []Action
+ Actions []Action
}
type Game struct {
Shadow *pool.Pool
Distance *pool.Pool
- Yin *Player
- Yang *Player
+ Yin *Player `json:"PlayerYin"`
+ Yang *Player `json:"PlayerYang"`
Stack []IsCard
Actions []Action
- CurrentPlayer *Player
+ CurrentPlayer *Player `json:"-"`
+ CurrentPlayerSlot string `json:"CurrentPlayer"`
History []Turn
}
@@ -59,18 +61,45 @@ func (g *Game) Winner() *Player {
func (g *Game) NextTurn() {
current := g.CurrentPlayer.Opponent(g)
g.CurrentPlayer = current
+ playerRef := "UNKNOWN"
+ switch current {
+ case g.Yin:
+ playerRef = "YIN"
+ case g.Yang:
+ playerRef = "YANG"
+ }
g.History = append(g.History, Turn{
- Player: current,
+ Player: current,
ActionTaken: false,
+ PlayerSlot: playerRef,
})
- g.Actions = Interactions(ShuffleDeckAction(g),DrawCardAction(g)),
+ g.CurrentPlayerSlot = playerRef
+ g.Actions = Interactions(ShuffleDeckAction(g), DrawCardAction(g))
}
func (g *Game) CurrentTurn() Turn {
- return g.History[len(g.History) - 1]
+ return g.History[len(g.History)-1]
}
func (g *Game) ActionToHistory(a Action) {
thisTurn := g.History[len(g.History)-1]
thisTurn.Actions = append(thisTurn.Actions, a)
}
+
+func (g *Game) Present(p *Player) Game {
+ localGame := *g
+ switch p {
+ case g.Yin:
+ localGame.Yang.Hide()
+ case g.Yang:
+ localGame.Yin.Hide()
+ }
+ var acs []Action
+ for _, a := range g.Actions {
+ if a.Actor(g) == p {
+ acs = append(acs, a)
+ }
+ }
+ localGame.Actions = acs
+ return localGame
+}
diff --git a/engine/player.go b/engine/player.go
index eb7ac49..a4f7c35 100644
--- a/engine/player.go
+++ b/engine/player.go
@@ -13,7 +13,15 @@ type Player struct {
Hand Stack
MasterDeck Stack
DrawPile Stack
- Ultimates []*Card
+ Ultimates []IsCard
+ Character *Character
+ Cookie string
+}
+
+func (p *Player) SetCharacter(c *Character) {
+ p.Character = c
+ p.MasterDeck = c.Cards
+ p.Ultimates = c.Ultimates
}
func (p *Player) Opponent(g *Game) *Player {
@@ -41,3 +49,9 @@ func NewPlayer(g *Game) *Player {
p.propagate(g)
return p
}
+
+func (p *Player) Hide() {
+ p.MasterDeck = p.MasterDeck.Hidden()
+ p.Hand = p.Hand.Hidden()
+ p.DrawPile = p.DrawPile.Hidden()
+}
diff --git a/engine/stack.go b/engine/stack.go
index 8bcff6f..dd10dd6 100644
--- a/engine/stack.go
+++ b/engine/stack.go
@@ -1,6 +1,6 @@
package engine
-type Stack []*Card
+type Stack []IsCard
func (s Stack) Contains(predicate func(c IsCard) bool) bool {
for _, c := range s {
@@ -30,3 +30,7 @@ func (s Stack) Pop() IsCard {
return c
}
}
+
+func (s Stack) Hidden() Stack {
+ return Secrets(len(s))
+}
diff --git a/server/api/game.go b/server/api/game.go
index 636ff66..d830d71 100644
--- a/server/api/game.go
+++ b/server/api/game.go
@@ -2,6 +2,7 @@ package api
import (
"net/http"
+ "sakura/data/cirno"
"sakura/engine"
"slices"
"uuid"
@@ -20,7 +21,11 @@ var connections = make(map[uuid.UUID][]*Conn)
func GameCreate(w http.ResponseWriter, r *http.Request) {
id := uuid.NewV7()
- games[id] = engine.NewGame()
+ g := engine.NewGame()
+ games[id] = g
+ g.Yin.SetCharacter(cirno.Cirno)
+ g.Yang.SetCharacter(cirno.Cirno)
+
w.Write([]byte(id.String()))
}
@@ -36,7 +41,10 @@ func GameConnect(w http.ResponseWriter, r *http.Request) {
http.Error(w, "game not found", http.StatusNotFound)
return
}
- wsConn, err := upgrader.Upgrade(w, r, nil)
+ p, c := Bind(game, w, r)
+ wsConn, err := upgrader.Upgrade(w, r, http.Header{
+ "Set-Cookie": []string{c.String()},
+ })
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -53,12 +61,47 @@ func GameConnect(w http.ResponseWriter, r *http.Request) {
})
return nil
})
- err = wsConn.WriteJSON(game)
+ go PumpRead(uid, game, p, wsConn)
+}
+
+func Bind(g *engine.Game, w http.ResponseWriter, r *http.Request) (*engine.Player, *http.Cookie) {
+ cookie, err := r.Cookie("User")
+ newUser := false
+
+ var id string
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ newUser = true
+ uid := uuid.NewV7()
+ id = uid.String()
+ cookie = &http.Cookie{
+ Name: "User",
+ Value: id,
+ Quoted: true,
+ Secure: true,
+ HttpOnly: false,
+ Path: "/",
+ SameSite: http.SameSiteStrictMode,
+ }
+ http.SetCookie(w, cookie)
+ } else {
+ id = cookie.Value
}
- go PumpRead(uid, game, wsConn)
+
+ switch {
+ case newUser && g.Yin.Cookie == "":
+ g.Yin.Cookie = id
+ return g.Yin, cookie
+ case newUser && g.Yang.Cookie == "":
+ g.Yang.Cookie = id
+ return g.Yang, cookie
+ case g.Yang.Cookie == id:
+ return g.Yang, cookie
+ case g.Yin.Cookie == id:
+ return g.Yin, cookie
+ default:
+ return nil, cookie
+ }
+
}
func Update(id uuid.UUID, g *engine.Game) {
@@ -67,9 +110,11 @@ func Update(id uuid.UUID, g *engine.Game) {
}
}
-func PumpRead(id uuid.UUID, g *engine.Game, conn *websocket.Conn) {
+func PumpRead(id uuid.UUID, g *engine.Game, p *engine.Player, conn *websocket.Conn) {
var interaction engine.InteractionID
for {
+ strippedGame := g.Present(p)
+ Update(id, &strippedGame)
err := conn.ReadJSON(&interaction)
if err != nil {
break
@@ -80,6 +125,5 @@ func PumpRead(id uuid.UUID, g *engine.Game, conn *websocket.Conn) {
}
a.Then(g)
g.ActionToHistory(a)
- Update(id, g)
}
}
diff --git a/server/server.go b/server/server.go
index af8393d..f6773cb 100644
--- a/server/server.go
+++ b/server/server.go
@@ -21,11 +21,10 @@ func Start() {
fmt.Println("Server started")
addr := net.JoinHostPort(*cfg.Host, strconv.Itoa(*cfg.Port))
fmt.Printf("Listening on %s\n", addr)
- var err error
+ sub, err := fs.Sub(web, "web")
if err != nil {
panic(err)
}
- sub, err := fs.Sub(web, "web")
http.Handle("/", http.FileServer(http.FS(sub)))
http.HandleFunc(cfg.CreateMethod+" "+cfg.CreatePath, api.GameCreate)
http.HandleFunc(cfg.ConnectMethod+" "+cfg.ConnectPath, api.GameConnect)