aboutsummaryrefslogtreecommitdiff
path: root/internal/game/sys_safespot_state.go
blob: 1520bc7313f89157e4c694fcc81b0e9493e59730 (plain)
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
}