1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
package game
import "sync"
// SafespotState tracks a player's active safespot (cover) in a room.
type SafespotState struct {
Active bool
ObjectDefID string
ObjectIndex int
RoomID int
HideCountdown int
}
// SafespotManager owns the per-player safespot state map and its mutex.
// Callers receive value copies via Get/Peek so they cannot mutate state
// outside the lock — this avoids the lock-copy-pointer-unlock anti-pattern.
type SafespotManager struct {
mu sync.Mutex
states map[string]*SafespotState
}
func NewSafespotManager() *SafespotManager {
return &SafespotManager{states: make(map[string]*SafespotState)}
}
// Get returns a value copy of the player's safespot state.
func (m *SafespotManager) Get(name string) (SafespotState, bool) {
m.mu.Lock()
defer m.mu.Unlock()
ss, ok := m.states[name]
if !ok {
return SafespotState{}, false
}
return *ss, true
}
// Has reports whether any safespot state exists for the player.
func (m *SafespotManager) Has(name string) bool {
m.mu.Lock()
defer m.mu.Unlock()
_, ok := m.states[name]
return ok
}
// IsActive reports whether the player has an active, fully-hidden safespot
// (hide countdown complete).
func (m *SafespotManager) IsActive(name string) bool {
m.mu.Lock()
defer m.mu.Unlock()
ss, ok := m.states[name]
return ok && ss.Active && ss.HideCountdown <= 0
}
// Set stores a safespot state for the player.
func (m *SafespotManager) Set(name string, ss SafespotState) {
m.mu.Lock()
defer m.mu.Unlock()
m.states[name] = &ss
}
// Delete removes the player's safespot state. Returns true if a state existed.
func (m *SafespotManager) Delete(name string) bool {
m.mu.Lock()
defer m.mu.Unlock()
_, ok := m.states[name]
delete(m.states, name)
return ok
}
// DecrementHideCountdown decrements the hide countdown for a player who is
// transitioning from hiding to hidden. Returns (newCountdown, ok). A return of
// ok=true with newCountdown > 0 means the player is still counting down;
// newCountdown == 0 means the safespot just activated.
func (m *SafespotManager) DecrementHideCountdown(name string) (int, bool) {
m.mu.Lock()
defer m.mu.Unlock()
ss, ok := m.states[name]
if !ok || !ss.Active {
return 0, false
}
if ss.HideCountdown > 0 {
ss.HideCountdown--
}
return ss.HideCountdown, true
}
|