shuffle v01.config to split out state and meta

master
Bel LaPointe 2023-03-27 10:54:02 -06:00
parent ecb719a97a
commit f647a03467
6 changed files with 130 additions and 116 deletions

View File

@ -22,13 +22,22 @@ type (
} }
configUser struct { configUser struct {
Player int Meta configUserMeta
Message string State configUserState
Alias string }
configUserMeta struct {
LastTSMS int64 LastTSMS int64
LastLag int64 LastLag int64
} }
configUserState struct {
Player int
Message string
Alias string
Vote string
}
configPlayer struct { configPlayer struct {
Transformation transformation Transformation transformation
} }

View File

@ -78,7 +78,7 @@ func (v01 *V01) getUserFeedback(w http.ResponseWriter, r *http.Request) {
if !ok { if !ok {
user = v01.cfg.Users["broadcast"] user = v01.cfg.Users["broadcast"]
} }
w.Write([]byte(user.Message)) w.Write([]byte(user.State.Message))
} }
func (v01 *V01) servePutBroadcast(w http.ResponseWriter, r *http.Request) { func (v01 *V01) servePutBroadcast(w http.ResponseWriter, r *http.Request) {
@ -88,7 +88,7 @@ func (v01 *V01) servePutBroadcast(w http.ResponseWriter, r *http.Request) {
func (v01 *V01) servePutBroadcastValue(v string) { func (v01 *V01) servePutBroadcastValue(v string) {
u := v01.cfg.Users["broadcast"] u := v01.cfg.Users["broadcast"]
u.Message = v u.State.Message = v
v01.cfg.Users["broadcast"] = u v01.cfg.Users["broadcast"] = u
} }
@ -178,10 +178,10 @@ func (v01 *V01) serveGMStatus(w http.ResponseWriter, r *http.Request) {
}{} }{}
for k, v := range v01.cfg.Users { for k, v := range v01.cfg.Users {
v2 := users[k] v2 := users[k]
v2.Lag = time.Duration(v.LastLag) * time.Millisecond v2.Lag = time.Duration(v.Meta.LastLag) * time.Millisecond
v2.Player = v.Player v2.Player = v.State.Player
if v.LastTSMS > 0 { if v.Meta.LastTSMS > 0 {
v2.IdleFor = time.Since(time.Unix(0, v.LastTSMS*int64(time.Millisecond))) v2.IdleFor = time.Since(time.Unix(0, v.Meta.LastTSMS*int64(time.Millisecond)))
} }
users[k] = v2 users[k] = v2
} }
@ -194,8 +194,8 @@ func (v01 *V01) serveGMStatus(w http.ResponseWriter, r *http.Request) {
func (v01 *V01) serveGMSomeoneSaidAlias(w http.ResponseWriter, r *http.Request) { func (v01 *V01) serveGMSomeoneSaidAlias(w http.ResponseWriter, r *http.Request) {
v01.cfg.Quiet = true v01.cfg.Quiet = true
for k, v := range v01.cfg.Users { for k, v := range v01.cfg.Users {
v.Message = v.Alias v.State.Message = v.State.Alias
v.Alias = "" v.State.Alias = ""
v01.cfg.Users[k] = v v01.cfg.Users[k] = v
} }
v01.servePutBroadcastValue(fmt.Sprintf("<<SOMEONE SAID %q>>", strings.ToUpper(r.URL.Query().Get("message")))) v01.servePutBroadcastValue(fmt.Sprintf("<<SOMEONE SAID %q>>", strings.ToUpper(r.URL.Query().Get("message"))))
@ -207,7 +207,7 @@ func (v01 *V01) serveGMFillNonPlayerAliases(w http.ResponseWriter, r *http.Reque
yaml.Unmarshal(b, &pool) yaml.Unmarshal(b, &pool)
n := 0 n := 0
for _, v := range v01.cfg.Users { for _, v := range v01.cfg.Users {
if v.Player == 0 { if v.State.Player == 0 {
n += 1 n += 1
} }
} }
@ -225,8 +225,8 @@ func (v01 *V01) serveGMFillNonPlayerAliases(w http.ResponseWriter, r *http.Reque
} }
i := 0 i := 0
for k, v := range v01.cfg.Users { for k, v := range v01.cfg.Users {
if v.Player == 0 { if v.State.Player == 0 {
v.Alias = pool[i] v.State.Alias = pool[i]
v01.cfg.Users[k] = v v01.cfg.Users[k] = v
i += 1 i += 1
} }
@ -235,12 +235,18 @@ func (v01 *V01) serveGMFillNonPlayerAliases(w http.ResponseWriter, r *http.Reque
func (v01 *V01) serveGMElect(w http.ResponseWriter, r *http.Request) { func (v01 *V01) serveGMElect(w http.ResponseWriter, r *http.Request) {
alias := r.URL.Query().Get("alias") alias := r.URL.Query().Get("alias")
aliasWinner := ""
votes := map[string]int{} votes := map[string]int{}
for _, v := range v01.cfg.Users { for k, v := range v01.cfg.Users {
if v2 := strings.Split(v.Message, "//"); len(v2) > 1 { votes[v.State.Vote] = votes[v.State.Vote] + 1 // todo into state.gm
votes[v2[1]] = votes[v2[1]] + 1 if v.State.Message == alias { // todo lowkey aliases pls // todo into state.gm
aliasWinner = k
} }
} }
if aliasWinner == "" {
http.Error(w, "who is "+alias+"?", http.StatusBadRequest)
return
}
threshold := 0.1 + float64(len(votes))/2.0 threshold := 0.1 + float64(len(votes))/2.0
winner := "" winner := ""
for k, v := range votes { for k, v := range votes {
@ -250,7 +256,7 @@ func (v01 *V01) serveGMElect(w http.ResponseWriter, r *http.Request) {
} }
if winner == "" { if winner == "" {
v01.serveGMShuffle(r) v01.serveGMShuffle(r)
} else if _, err := v01.serveGMSwap(winner, alias); err != nil { } else if _, err := v01.serveGMSwap(winner, aliasWinner); err != nil {
v01.serveGMShuffle(r) v01.serveGMShuffle(r)
} }
yaml.NewEncoder(w).Encode(votes) yaml.NewEncoder(w).Encode(votes)
@ -261,7 +267,7 @@ func (v01 *V01) serveGMVote(w http.ResponseWriter, r *http.Request) {
case http.MethodGet: case http.MethodGet:
counts := map[string]string{} counts := map[string]string{}
for k, v := range v01.cfg.Users { for k, v := range v01.cfg.Users {
if strings.Contains(v.Message, "//") { if v.State.Vote != "" {
counts[k] = "voted" counts[k] = "voted"
} else { } else {
counts[k] = "voting" counts[k] = "voting"
@ -276,7 +282,7 @@ func (v01 *V01) serveGMVote(w http.ResponseWriter, r *http.Request) {
http.Error(w, "bad voter/candidate", http.StatusBadRequest) http.Error(w, "bad voter/candidate", http.StatusBadRequest)
return return
} }
v.Message = strings.Split(v.Message, "//")[0] + "//" + candidate v.State.Vote = candidate
v01.cfg.Users[voter] = v v01.cfg.Users[voter] = v
} }
} }
@ -300,10 +306,10 @@ func (v01 *V01) serveGMShuffle(r *http.Request) {
i := 0 i := 0
msg := []string{} msg := []string{}
for k, v := range v01.cfg.Users { for k, v := range v01.cfg.Users {
v.Player = pool[i] v.State.Player = pool[i]
v01.cfg.Users[k] = v v01.cfg.Users[k] = v
if pool[i] > 0 { if pool[i] > 0 {
msg = append(msg, fmt.Sprintf("%s is now player %v", k, v.Player)) msg = append(msg, fmt.Sprintf("%s is now player %v", k, v.State.Player))
} }
i += 1 i += 1
} }
@ -311,29 +317,21 @@ func (v01 *V01) serveGMShuffle(r *http.Request) {
v01.cfg.Quiet = false v01.cfg.Quiet = false
} }
func (v01 *V01) serveGMSwap(nameA, nameB string) (int, error) { func (v01 *V01) serveGMSwap(userA, userB string) (int, error) {
getUserNameFor := func(like string) string {
for k, v := range v01.cfg.Users {
if k == like || v.Alias == like || (strings.Contains(v.Message, "//") && strings.Split(v.Message, "//")[0] == like) {
return k
}
}
return ""
}
userA := getUserNameFor(nameA)
userB := getUserNameFor(nameB)
if userA == "" || userB == "" {
return http.StatusBadRequest, errors.New("who dat?")
}
if userA == userB { if userA == userB {
return http.StatusConflict, errors.New("/spiderman-pointing") return http.StatusConflict, errors.New("/spiderman-pointing")
} }
_, okA := v01.cfg.Users[userA]
_, okB := v01.cfg.Users[userB]
if !okA || !okB {
return http.StatusBadRequest, errors.New("who dat?")
}
a := v01.cfg.Users[userA] a := v01.cfg.Users[userA]
b := v01.cfg.Users[userB] b := v01.cfg.Users[userB]
a.Player, b.Player = b.Player, a.Player a.State.Player, b.State.Player = b.State.Player, a.State.Player
v01.cfg.Users[userA] = a v01.cfg.Users[userA] = a
v01.cfg.Users[userB] = b v01.cfg.Users[userB] = b
v01.cfg.Quiet = false v01.cfg.Quiet = false
v01.servePutBroadcastValue(fmt.Sprintf(`%s is now player %v and %s is now player %v`, userA, a.Player, userB, b.Player)) v01.servePutBroadcastValue(fmt.Sprintf(`%s is now player %v and %s is now player %v`, userA, a.State.Player, userB, b.State.Player))
return http.StatusOK, nil return http.StatusOK, nil
} }

View File

@ -27,19 +27,19 @@ func TestPatchConfig(t *testing.T) {
"replace entire doc": { "replace entire doc": {
was: config{ was: config{
Feedback: configFeedback{Addr: "a", TTSURL: "a"}, Feedback: configFeedback{Addr: "a", TTSURL: "a"},
Users: map[string]configUser{"a": configUser{Player: 1, Message: "a"}}, Users: map[string]configUser{"a": configUser{State: configUserState{Player: 1, Message: "a"}}},
Players: []configPlayer{configPlayer{Transformation: transformation{"a": "a"}}}, Players: []configPlayer{configPlayer{Transformation: transformation{"a": "a"}}},
Quiet: true, Quiet: true,
}, },
patch: `[{"op": "replace", "path": "", "value": { patch: `[{"op": "replace", "path": "", "value": {
"Feedback": {"Addr": "b", "TTSURL": "b"}, "Feedback": {"Addr": "b", "TTSURL": "b"},
"Users": {"b": {"Player": 2, "Message": "b"}}, "Users": {"b": {"State":{"Player": 2, "Message": "b"}}},
"Players": [{"Transformation": {"b": "b"}}], "Players": [{"Transformation": {"b": "b"}}],
"Quiet": false "Quiet": false
}}]`, }}]`,
want: config{ want: config{
Feedback: configFeedback{Addr: "b", TTSURL: "b"}, Feedback: configFeedback{Addr: "b", TTSURL: "b"},
Users: map[string]configUser{"b": configUser{Player: 2, Message: "b"}}, Users: map[string]configUser{"b": configUser{State: configUserState{Player: 2, Message: "b"}}},
Players: []configPlayer{configPlayer{Transformation: transformation{"b": "b"}}}, Players: []configPlayer{configPlayer{Transformation: transformation{"b": "b"}}},
Quiet: false, Quiet: false,
}, },
@ -130,9 +130,11 @@ func TestServeGM(t *testing.T) {
} }
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{ "bel": configUser{
Player: 3, State: configUserState{Player: 3},
LastTSMS: time.Now().Add(-1*time.Minute).UnixNano() / int64(time.Millisecond), Meta: configUserMeta{
LastLag: int64(time.Second / time.Millisecond), LastTSMS: time.Now().Add(-1*time.Minute).UnixNano() / int64(time.Millisecond),
LastLag: int64(time.Second / time.Millisecond),
},
}, },
"zach": configUser{}, "zach": configUser{},
"chase": configUser{}, "chase": configUser{},
@ -175,24 +177,24 @@ func TestServeGM(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Quiet = false v01.cfg.Quiet = false
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{ "bel": configUser{State: configUserState{
Alias: "driver", Alias: "driver",
Message: "if someone else says 'driver', then you get to play", Message: "if someone else says 'driver', then you get to play",
}, }},
"broadcast": configUser{ "broadcast": configUser{State: configUserState{
Message: ":)", Message: ":)",
}, }},
} }
do(v01, "/gm/rpc/broadcastSomeoneSaidAlias", "") do(v01, "/gm/rpc/broadcastSomeoneSaidAlias", "")
if !v01.cfg.Quiet { if !v01.cfg.Quiet {
t.Error(v01.cfg.Quiet) t.Error(v01.cfg.Quiet)
} }
if v := v01.cfg.Users["bel"]; v.Alias != "" { if v := v01.cfg.Users["bel"]; v.State.Alias != "" {
t.Error(v.Alias) t.Error(v.State.Alias)
} else if v.Message != "driver" { } else if v.State.Message != "driver" {
t.Error(v.Message) t.Error(v.State.Message)
} }
if bc := v01.cfg.Users["broadcast"]; bc.Message == ":)" { if bc := v01.cfg.Users["broadcast"]; bc.State.Message == ":)" {
t.Error(bc) t.Error(bc)
} }
}) })
@ -210,7 +212,7 @@ func TestServeGM(t *testing.T) {
t.Run("not enough", func(t *testing.T) { t.Run("not enough", func(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"zach": configUser{Player: 0}, "zach": configUser{State: configUserState{Player: 0}},
} }
resp := do(v01, "/gm/rpc/fillNonPlayerAliases", "[]") resp := do(v01, "/gm/rpc/fillNonPlayerAliases", "[]")
if resp.Code != http.StatusBadRequest { if resp.Code != http.StatusBadRequest {
@ -221,19 +223,19 @@ func TestServeGM(t *testing.T) {
t.Run("happy", func(t *testing.T) { t.Run("happy", func(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{Player: 1}, "bel": configUser{State: configUserState{Player: 1}},
"zach": configUser{Player: 0}, "zach": configUser{State: configUserState{Player: 0}},
} }
do(v01, "/gm/rpc/fillNonPlayerAliases", "[qt]") do(v01, "/gm/rpc/fillNonPlayerAliases", "[qt]")
if v := v01.cfg.Users["bel"]; v.Alias != "" { if v := v01.cfg.Users["bel"]; v.State.Alias != "" {
t.Error(v.Alias) t.Error(v.State.Alias)
} else if v.Player != 1 { } else if v.State.Player != 1 {
t.Error(v.Player) t.Error(v.State.Player)
} }
if v := v01.cfg.Users["zach"]; v.Alias != "qt" { if v := v01.cfg.Users["zach"]; v.State.Alias != "qt" {
t.Error(v.Alias) t.Error(v.State.Alias)
} else if v.Player != 0 { } else if v.State.Player != 0 {
t.Error(v.Player) t.Error(v.State.Player)
} }
}) })
}) })
@ -248,8 +250,8 @@ func TestServeGM(t *testing.T) {
if resp.Code != http.StatusBadRequest { if resp.Code != http.StatusBadRequest {
t.Error(resp) t.Error(resp)
} }
if v01.cfg.Users["bel"].Message != "" { if v01.cfg.Users["bel"].State.Message != "" {
t.Error(v01.cfg.Users["bel"].Message) t.Error(v01.cfg.Users["bel"].State.Message)
} }
}) })
@ -257,8 +259,8 @@ func TestServeGM(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Users = map[string]configUser{"bel": {}, "zach": {}} v01.cfg.Users = map[string]configUser{"bel": {}, "zach": {}}
do(v01, "/gm/rpc/vote?user=bel&payload=zach", "") do(v01, "/gm/rpc/vote?user=bel&payload=zach", "")
if v01.cfg.Users["bel"].Message != "//zach" { if v01.cfg.Users["bel"].State.Vote != "zach" {
t.Error(v01.cfg.Users["bel"].Message) t.Error(v01.cfg.Users["bel"].State.Vote)
} }
}) })
@ -281,7 +283,7 @@ func TestServeGM(t *testing.T) {
t.Run("get mid vote", func(t *testing.T) { t.Run("get mid vote", func(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Users = map[string]configUser{"bel": {Message: "driver//zach"}} v01.cfg.Users = map[string]configUser{"bel": {State: configUserState{Vote: "zach", Message: "driver"}}}
resp := do(v01, "/gm/rpc/vote", "", "GET") resp := do(v01, "/gm/rpc/vote", "", "GET")
var result result var result result
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil { if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
@ -317,14 +319,14 @@ func TestServeGM(t *testing.T) {
t.Run("happy", func(t *testing.T) { t.Run("happy", func(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{Message: "driver//zach", Player: 1}, "bel": configUser{State: configUserState{Vote: "zach", Message: "driver", Player: 1}},
"zach": configUser{Message: "pizza//bel"}, "zach": configUser{State: configUserState{Vote: "bel", Message: "pizza"}},
"bill": configUser{Message: "//bel", Player: 2}, "bill": configUser{State: configUserState{Vote: "bel", Message: "", Player: 2}},
} }
resp := do(v01, "/gm/rpc/elect?alias=pizza", "") resp := do(v01, "/gm/rpc/elect?alias=pizza", "")
var result result var result result
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil { if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
t.Error(err) t.Errorf("%s => %v", resp.Body.Bytes(), err)
} }
if len(result) != 2 { if len(result) != 2 {
t.Error(result) t.Error(result)
@ -333,13 +335,13 @@ func TestServeGM(t *testing.T) {
} else if result["zach"] != 1 { } else if result["zach"] != 1 {
t.Error(result) t.Error(result)
} }
if v01.cfg.Users["bel"].Player != 0 { if v01.cfg.Users["bel"].State.Player != 0 {
t.Error(v01.cfg.Users["bel"].Player) t.Error(v01.cfg.Users["bel"].State.Player)
} else if v01.cfg.Users["zach"].Player != 1 { } else if v01.cfg.Users["zach"].State.Player != 1 {
t.Error(v01.cfg.Users["zach"].Player) t.Error(v01.cfg.Users["zach"].State.Player)
} }
if v01.cfg.Users["broadcast"].Message != `bel is now player 0 and zach is now player 1` { if v01.cfg.Users["broadcast"].State.Message != `bel is now player 0 and zach is now player 1` {
t.Error(v01.cfg.Users["broadcast"].Message) t.Error(v01.cfg.Users["broadcast"].State.Message)
} }
}) })
@ -347,9 +349,9 @@ func TestServeGM(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Players = []configPlayer{{}} v01.cfg.Players = []configPlayer{{}}
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{Message: "driver//zach", Player: 1}, "bel": configUser{State: configUserState{Vote: "zach", Message: "driver", Player: 1}},
"zach": configUser{Message: "//bel"}, "zach": configUser{State: configUserState{Vote: "bel", Message: ""}},
"bill": configUser{Message: "//bel"}, "bill": configUser{State: configUserState{Vote: "bel", Message: ""}},
} }
resp := do(v01, "/gm/rpc/elect?alias=driver", "") resp := do(v01, "/gm/rpc/elect?alias=driver", "")
var result result var result result
@ -363,12 +365,12 @@ func TestServeGM(t *testing.T) {
} else if result["zach"] != 1 { } else if result["zach"] != 1 {
t.Error(result) t.Error(result)
} }
if !strings.HasSuffix(v01.cfg.Users["broadcast"].Message, `is now player 1`) || strings.Contains(v01.cfg.Users["broadcast"].Message, ",") { if !strings.HasSuffix(v01.cfg.Users["broadcast"].State.Message, `is now player 1`) || strings.Contains(v01.cfg.Users["broadcast"].State.Message, ",") {
t.Error(v01.cfg.Users["broadcast"].Message) t.Error(v01.cfg.Users["broadcast"].State.Message)
} }
assignments := map[int]int{} assignments := map[int]int{}
for _, v := range v01.cfg.Users { for _, v := range v01.cfg.Users {
assignments[v.Player] = assignments[v.Player] + 1 assignments[v.State.Player] = assignments[v.State.Player] + 1
} }
if len(assignments) != 2 { if len(assignments) != 2 {
t.Error(assignments) t.Error(assignments)
@ -383,8 +385,8 @@ func TestServeGM(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Players = []configPlayer{{}} v01.cfg.Players = []configPlayer{{}}
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{Message: "driver//zach", Player: 1}, "bel": configUser{State: configUserState{Vote: "zach", Message: "driver", Player: 1}},
"zach": configUser{Message: "pizza//bel"}, "zach": configUser{State: configUserState{Vote: "bel", Message: "pizza"}},
} }
resp := do(v01, "/gm/rpc/elect?alias=pizza", "") resp := do(v01, "/gm/rpc/elect?alias=pizza", "")
var result result var result result
@ -398,12 +400,12 @@ func TestServeGM(t *testing.T) {
} else if result["zach"] != 1 { } else if result["zach"] != 1 {
t.Error(result) t.Error(result)
} }
if !strings.HasSuffix(v01.cfg.Users["broadcast"].Message, `is now player 1`) || strings.Contains(v01.cfg.Users["broadcast"].Message, ",") { if !strings.HasSuffix(v01.cfg.Users["broadcast"].State.Message, `is now player 1`) || strings.Contains(v01.cfg.Users["broadcast"].State.Message, ",") {
t.Error(v01.cfg.Users["broadcast"].Message) t.Error(v01.cfg.Users["broadcast"].State.Message)
} }
assignments := map[int]int{} assignments := map[int]int{}
for _, v := range v01.cfg.Users { for _, v := range v01.cfg.Users {
assignments[v.Player] = assignments[v.Player] + 1 assignments[v.State.Player] = assignments[v.State.Player] + 1
} }
if len(assignments) != 2 { if len(assignments) != 2 {
t.Error(assignments) t.Error(assignments)
@ -421,8 +423,8 @@ func TestServeGM(t *testing.T) {
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
v01.cfg.Quiet = true v01.cfg.Quiet = true
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{Player: 1}, "bel": configUser{State: configUserState{Player: 1}},
"zach": configUser{Player: 2}, "zach": configUser{State: configUserState{Player: 2}},
} }
v01.cfg.Players = []configPlayer{{}, {}} v01.cfg.Players = []configPlayer{{}, {}}
do(v01, "/gm/rpc/shuffle", "") do(v01, "/gm/rpc/shuffle", "")
@ -433,9 +435,9 @@ func TestServeGM(t *testing.T) {
t.Error(v01.cfg.Users) t.Error(v01.cfg.Users)
} else if len(v01.cfg.Players) != 2 { } else if len(v01.cfg.Players) != 2 {
t.Error(v01.cfg.Users) t.Error(v01.cfg.Users)
} else if bp := v01.cfg.Users["bel"].Player; bp != 1 && bp != 2 { } else if bp := v01.cfg.Users["bel"].State.Player; bp != 1 && bp != 2 {
t.Error(bp) t.Error(bp)
} else if zp := v01.cfg.Users["zach"].Player; zp != 1 && zp != 2 { } else if zp := v01.cfg.Users["zach"].State.Player; zp != 1 && zp != 2 {
t.Error(zp) t.Error(zp)
} else if bp == zp { } else if bp == zp {
t.Error(bp, zp) t.Error(bp, zp)
@ -468,7 +470,7 @@ func TestServeGM(t *testing.T) {
for i := 0; i < c.users; i++ { for i := 0; i < c.users; i++ {
v01.cfg.Users[strconv.Itoa(i)] = configUser{} v01.cfg.Users[strconv.Itoa(i)] = configUser{}
if i < c.usersAssigned { if i < c.usersAssigned {
v01.cfg.Users[strconv.Itoa(i)] = configUser{Player: i} v01.cfg.Users[strconv.Itoa(i)] = configUser{State: configUserState{Player: i}}
} }
} }
v01.cfg.Players = make([]configPlayer, c.players) v01.cfg.Players = make([]configPlayer, c.players)
@ -490,8 +492,8 @@ func TestServeGM(t *testing.T) {
} }
assignments := map[int]int{} assignments := map[int]int{}
for _, v := range v01.cfg.Users { for _, v := range v01.cfg.Users {
if v.Player > 0 { if v.State.Player > 0 {
assignments[v.Player] = assignments[v.Player] + 1 assignments[v.State.Player] = assignments[v.State.Player] + 1
} }
} }
lesser := c.users lesser := c.users
@ -515,7 +517,7 @@ func TestServeGM(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Quiet = true v01.cfg.Quiet = true
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{Player: 1}, "bel": configUser{State: configUserState{Player: 1}},
} }
resp := do(v01, "/gm/rpc/swap?a=bel&b=bel", "") resp := do(v01, "/gm/rpc/swap?a=bel&b=bel", "")
if resp.Code != http.StatusConflict { if resp.Code != http.StatusConflict {
@ -542,8 +544,8 @@ func TestServeGM(t *testing.T) {
v01 := NewV01(ctx, nil) v01 := NewV01(ctx, nil)
v01.cfg.Quiet = true v01.cfg.Quiet = true
v01.cfg.Users = map[string]configUser{ v01.cfg.Users = map[string]configUser{
"bel": configUser{Player: 1}, "bel": configUser{State: configUserState{Player: 1}},
"zach": configUser{Player: 2}, "zach": configUser{State: configUserState{Player: 2}},
} }
resp := do(v01, "/gm/rpc/swap?a=bel&b=zach", "") resp := do(v01, "/gm/rpc/swap?a=bel&b=zach", "")
if resp.Code != http.StatusOK { if resp.Code != http.StatusOK {
@ -552,9 +554,9 @@ func TestServeGM(t *testing.T) {
if v01.cfg.Quiet { if v01.cfg.Quiet {
t.Error(v01.cfg.Quiet) t.Error(v01.cfg.Quiet)
} }
if v01.cfg.Users["bel"].Player != 2 { if v01.cfg.Users["bel"].State.Player != 2 {
t.Error(v01.cfg.Users["bel"]) t.Error(v01.cfg.Users["bel"])
} else if v01.cfg.Users["zach"].Player != 1 { } else if v01.cfg.Users["zach"].State.Player != 1 {
t.Error(v01.cfg.Users["zach"]) t.Error(v01.cfg.Users["zach"])
} }
}) })

View File

@ -3,11 +3,13 @@ feedback:
ttsurl: http://localhost:15002 ttsurl: http://localhost:15002
users: users:
bel: bel:
player: 0 state:
message: "hi" player: 0
alias: driver message: "hi"
tsms: 1 alias: driver
lastlag: 2 meta:
tsms: 1
lastlag: 2
players: players:
- buttons: - buttons:
up: "w" up: "w"

View File

@ -79,10 +79,10 @@ func (v01 *V01) telemetry(msg message) {
v01.cfg.Users = map[string]configUser{} v01.cfg.Users = map[string]configUser{}
} }
u := v01.cfg.Users[msg.U] u := v01.cfg.Users[msg.U]
u.LastLag = time.Now().UnixNano()/int64(time.Millisecond) - msg.T u.Meta.LastLag = time.Now().UnixNano()/int64(time.Millisecond) - msg.T
u.LastTSMS = msg.T u.Meta.LastTSMS = msg.T
if FlagDebug { if FlagDebug {
log.Printf("%s|%dms", msg.U, u.LastLag) log.Printf("%s|%dms", msg.U, u.Meta.LastLag)
} }
v01.cfg.Users[msg.U] = u v01.cfg.Users[msg.U] = u
} }
@ -92,12 +92,12 @@ func (v01 *V01) transform(msg message) message {
return msg return msg
} }
user := v01.cfg.Users[msg.U] user := v01.cfg.Users[msg.U]
if user.Player < 1 { if user.State.Player < 1 {
msg.Y = "" msg.Y = ""
msg.N = "" msg.N = ""
return msg return msg
} }
player := v01.cfg.Players[user.Player-1] player := v01.cfg.Players[user.State.Player-1]
msg.Y = player.Transformation.pipe(msg.Y) msg.Y = player.Transformation.pipe(msg.Y)
msg.N = player.Transformation.pipe(msg.N) msg.N = player.Transformation.pipe(msg.N)
return msg return msg

View File

@ -44,7 +44,8 @@ func TestV01WithCfg(t *testing.T) {
os.WriteFile(p, []byte(` os.WriteFile(p, []byte(`
users: users:
bel: bel:
player: 2 state:
player: 2
players: players:
- transformation: - transformation:
w: t w: t
@ -87,10 +88,12 @@ func TestV01Feedback(t *testing.T) {
ttsurl: http://localhost:15002 ttsurl: http://localhost:15002
users: users:
bel: bel:
player: 2 state:
message: to bel player: 2
message: to bel
broadcast: broadcast:
message: to everyone state:
message: to everyone
players: players:
- transformation: - transformation:
w: t w: t