fix: use fingerprint as player ID to prevent name collision
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -70,8 +70,8 @@ type GameSession struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type playerActionMsg struct {
|
type playerActionMsg struct {
|
||||||
PlayerName string
|
PlayerID string
|
||||||
Action PlayerAction
|
Action PlayerAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGameSession() *GameSession {
|
func NewGameSession() *GameSession {
|
||||||
@@ -209,12 +209,12 @@ func (s *GameSession) GetState() GameState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GameSession) SubmitAction(playerName string, action PlayerAction) {
|
func (s *GameSession) SubmitAction(playerID string, action PlayerAction) {
|
||||||
s.actionCh <- playerActionMsg{PlayerName: playerName, Action: action}
|
s.actionCh <- playerActionMsg{PlayerID: playerID, Action: action}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuyItem handles shop purchases
|
// BuyItem handles shop purchases
|
||||||
func (s *GameSession) BuyItem(playerName string, itemIdx int) bool {
|
func (s *GameSession) BuyItem(playerID string, itemIdx int) bool {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if s.state.Phase != PhaseShop || itemIdx < 0 || itemIdx >= len(s.state.ShopItems) {
|
if s.state.Phase != PhaseShop || itemIdx < 0 || itemIdx >= len(s.state.ShopItems) {
|
||||||
@@ -222,7 +222,7 @@ func (s *GameSession) BuyItem(playerName string, itemIdx int) bool {
|
|||||||
}
|
}
|
||||||
item := s.state.ShopItems[itemIdx]
|
item := s.state.ShopItems[itemIdx]
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if p.Name == playerName && p.Gold >= item.Price {
|
if p.Fingerprint == playerID && p.Gold >= item.Price {
|
||||||
p.Gold -= item.Price
|
p.Gold -= item.Price
|
||||||
p.Inventory = append(p.Inventory, item)
|
p.Inventory = append(p.Inventory, item)
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
func TestGetStateNoRace(t *testing.T) {
|
func TestGetStateNoRace(t *testing.T) {
|
||||||
s := NewGameSession()
|
s := NewGameSession()
|
||||||
p := entity.NewPlayer("Racer", entity.ClassWarrior)
|
p := entity.NewPlayer("Racer", entity.ClassWarrior)
|
||||||
|
p.Fingerprint = "test-fp"
|
||||||
s.AddPlayer(p)
|
s.AddPlayer(p)
|
||||||
s.StartGame()
|
s.StartGame()
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ func TestGetStateNoRace(t *testing.T) {
|
|||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
select {
|
select {
|
||||||
case s.actionCh <- playerActionMsg{PlayerName: "Racer", Action: PlayerAction{Type: ActionWait}}:
|
case s.actionCh <- playerActionMsg{PlayerID: "test-fp", Action: PlayerAction{Type: ActionWait}}:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
@@ -41,6 +42,7 @@ func TestGetStateNoRace(t *testing.T) {
|
|||||||
func TestSessionTurnTimeout(t *testing.T) {
|
func TestSessionTurnTimeout(t *testing.T) {
|
||||||
s := NewGameSession()
|
s := NewGameSession()
|
||||||
p := entity.NewPlayer("test", entity.ClassWarrior)
|
p := entity.NewPlayer("test", entity.ClassWarrior)
|
||||||
|
p.Fingerprint = "test-fp"
|
||||||
s.AddPlayer(p)
|
s.AddPlayer(p)
|
||||||
s.StartFloor()
|
s.StartFloor()
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func (s *GameSession) RunTurn() {
|
|||||||
select {
|
select {
|
||||||
case msg := <-s.actionCh:
|
case msg := <-s.actionCh:
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
s.actions[msg.PlayerName] = msg.Action
|
s.actions[msg.PlayerID] = msg.Action
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
collected++
|
collected++
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
@@ -53,8 +53,8 @@ resolve:
|
|||||||
// Default action for players who didn't submit: Wait
|
// Default action for players who didn't submit: Wait
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if !p.IsOut() {
|
if !p.IsOut() {
|
||||||
if _, ok := s.actions[p.Name]; !ok {
|
if _, ok := s.actions[p.Fingerprint]; !ok {
|
||||||
s.actions[p.Name] = PlayerAction{Type: ActionWait}
|
s.actions[p.Fingerprint] = PlayerAction{Type: ActionWait}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ func (s *GameSession) resolvePlayerActions() {
|
|||||||
if p.IsOut() {
|
if p.IsOut() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
action, ok := s.actions[p.Name]
|
action, ok := s.actions[p.Fingerprint]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
17
ui/model.go
17
ui/model.go
@@ -172,6 +172,9 @@ func (m Model) updateTitle(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
} else {
|
} else {
|
||||||
m.playerName = "Adventurer"
|
m.playerName = "Adventurer"
|
||||||
}
|
}
|
||||||
|
if m.fingerprint == "" {
|
||||||
|
m.fingerprint = fmt.Sprintf("anon-%d", time.Now().UnixNano())
|
||||||
|
}
|
||||||
m.screen = screenLobby
|
m.screen = screenLobby
|
||||||
m = m.withRefreshedLobby()
|
m = m.withRefreshedLobby()
|
||||||
} else if isQuit(key) {
|
} else if isQuit(key) {
|
||||||
@@ -349,7 +352,7 @@ func (m Model) updateGame(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case game.PhaseCombat:
|
case game.PhaseCombat:
|
||||||
isPlayerDead := false
|
isPlayerDead := false
|
||||||
for _, p := range m.gameState.Players {
|
for _, p := range m.gameState.Players {
|
||||||
if p.Name == m.playerName && p.IsDead() {
|
if p.Fingerprint == m.fingerprint && p.IsDead() {
|
||||||
isPlayerDead = true
|
isPlayerDead = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -366,15 +369,15 @@ func (m Model) updateGame(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
if m.session != nil {
|
if m.session != nil {
|
||||||
switch key.String() {
|
switch key.String() {
|
||||||
case "1":
|
case "1":
|
||||||
m.session.SubmitAction(m.playerName, game.PlayerAction{Type: game.ActionAttack, TargetIdx: m.targetCursor})
|
m.session.SubmitAction(m.fingerprint, game.PlayerAction{Type: game.ActionAttack, TargetIdx: m.targetCursor})
|
||||||
case "2":
|
case "2":
|
||||||
m.session.SubmitAction(m.playerName, game.PlayerAction{Type: game.ActionSkill, TargetIdx: m.targetCursor})
|
m.session.SubmitAction(m.fingerprint, game.PlayerAction{Type: game.ActionSkill, TargetIdx: m.targetCursor})
|
||||||
case "3":
|
case "3":
|
||||||
m.session.SubmitAction(m.playerName, game.PlayerAction{Type: game.ActionItem})
|
m.session.SubmitAction(m.fingerprint, game.PlayerAction{Type: game.ActionItem})
|
||||||
case "4":
|
case "4":
|
||||||
m.session.SubmitAction(m.playerName, game.PlayerAction{Type: game.ActionFlee})
|
m.session.SubmitAction(m.fingerprint, game.PlayerAction{Type: game.ActionFlee})
|
||||||
case "5":
|
case "5":
|
||||||
m.session.SubmitAction(m.playerName, game.PlayerAction{Type: game.ActionWait})
|
m.session.SubmitAction(m.fingerprint, game.PlayerAction{Type: game.ActionWait})
|
||||||
}
|
}
|
||||||
// After submitting, poll for turn resolution
|
// After submitting, poll for turn resolution
|
||||||
return m, m.pollState()
|
return m, m.pollState()
|
||||||
@@ -401,7 +404,7 @@ func (m Model) updateShop(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case "1", "2", "3":
|
case "1", "2", "3":
|
||||||
if m.session != nil {
|
if m.session != nil {
|
||||||
idx := int(key.String()[0] - '1')
|
idx := int(key.String()[0] - '1')
|
||||||
m.session.BuyItem(m.playerName, idx)
|
m.session.BuyItem(m.fingerprint, idx)
|
||||||
m.gameState = m.session.GetState()
|
m.gameState = m.session.GetState()
|
||||||
}
|
}
|
||||||
case "q":
|
case "q":
|
||||||
|
|||||||
Reference in New Issue
Block a user