Rewrite to Go: engine, plugin system, D2R plugin, API, loot filter

This commit is contained in:
Hoid 2026-02-14 09:43:39 +00:00
parent e0282a7111
commit 3b363192f2
60 changed files with 1576 additions and 3407 deletions

108
pkg/engine/safety/safety.go Normal file
View file

@ -0,0 +1,108 @@
// Package safety provides anti-detection measures: session timing,
// break scheduling, and behavioral pattern randomization.
package safety
import (
"math/rand"
"time"
)
// SessionConfig defines play session parameters.
type SessionConfig struct {
MinSessionHours float64
MaxSessionHours float64
MinBreakMinutes float64
MaxBreakMinutes float64
MaxDailyHours float64
MicroBreakMinSec int
MicroBreakMaxSec int
MicroBreakIntervalMinSec int
MicroBreakIntervalMaxSec int
}
// DefaultSessionConfig returns realistic session timing.
func DefaultSessionConfig() SessionConfig {
return SessionConfig{
MinSessionHours: 1.0,
MaxSessionHours: 4.0,
MinBreakMinutes: 10.0,
MaxBreakMinutes: 45.0,
MaxDailyHours: 12.0,
MicroBreakMinSec: 2,
MicroBreakMaxSec: 8,
MicroBreakIntervalMinSec: 120,
MicroBreakIntervalMaxSec: 300,
}
}
// SessionTimer manages play session duration and breaks.
type SessionTimer struct {
config SessionConfig
sessionStart time.Time
dailyPlaytime time.Duration
targetDuration time.Duration
nextMicroBreak time.Time
}
// NewSessionTimer creates a session timer.
func NewSessionTimer(config SessionConfig) *SessionTimer {
st := &SessionTimer{
config: config,
sessionStart: time.Now(),
}
st.targetDuration = st.rollSessionDuration()
st.nextMicroBreak = st.scheduleMicroBreak()
return st
}
// ShouldStopSession returns true if the current session should end.
func (s *SessionTimer) ShouldStopSession() bool {
elapsed := time.Since(s.sessionStart)
if elapsed >= s.targetDuration {
return true
}
if s.dailyPlaytime+elapsed >= time.Duration(s.config.MaxDailyHours*float64(time.Hour)) {
return true
}
return false
}
// ShouldMicroBreak returns the break duration if it's time, or 0.
func (s *SessionTimer) ShouldMicroBreak() time.Duration {
if time.Now().After(s.nextMicroBreak) {
duration := time.Duration(s.config.MicroBreakMinSec+rand.Intn(s.config.MicroBreakMaxSec-s.config.MicroBreakMinSec+1)) * time.Second
s.nextMicroBreak = s.scheduleMicroBreak()
return duration
}
return 0
}
// BreakDuration returns a randomized long break duration.
func (s *SessionTimer) BreakDuration() time.Duration {
minMs := int(s.config.MinBreakMinutes * 60 * 1000)
maxMs := int(s.config.MaxBreakMinutes * 60 * 1000)
return time.Duration(minMs+rand.Intn(maxMs-minMs)) * time.Millisecond
}
// StartNewSession resets for a new play session.
func (s *SessionTimer) StartNewSession() {
s.dailyPlaytime += time.Since(s.sessionStart)
s.sessionStart = time.Now()
s.targetDuration = s.rollSessionDuration()
}
// Elapsed returns time in current session.
func (s *SessionTimer) Elapsed() time.Duration {
return time.Since(s.sessionStart)
}
func (s *SessionTimer) rollSessionDuration() time.Duration {
minMs := int(s.config.MinSessionHours * 3600 * 1000)
maxMs := int(s.config.MaxSessionHours * 3600 * 1000)
return time.Duration(minMs+rand.Intn(maxMs-minMs)) * time.Millisecond
}
func (s *SessionTimer) scheduleMicroBreak() time.Time {
interval := s.config.MicroBreakIntervalMinSec + rand.Intn(s.config.MicroBreakIntervalMaxSec-s.config.MicroBreakIntervalMinSec+1)
return time.Now().Add(time.Duration(interval) * time.Second)
}