The SCUM 用户管理 list stayed empty because the typed scum_user and scum_vehicle tables had no producer: the run ingest endpoint is signed-run only, and the previously registered plugin templates asked for a Run database capability the endpoint never advertises. The plugin now declares bounded, read-only SQLite projections for players and vehicles (sql/scum-db-v57/*.sql with query schemas), and the platform dispatches those templates as durable remote.run.db.sqlite.query jobs on run heartbeat and page open, then projects the returned rows into the typed SCUM tables through the same shared ingest path used by signed run facts.
319 lines
7.2 KiB
Go
319 lines
7.2 KiB
Go
package domain
|
|
|
|
import "time"
|
|
|
|
const (
|
|
SCUMUserOfflineAfter = 15 * time.Minute
|
|
SCUMWelcomeMessageDelay = time.Minute
|
|
SCUMDefaultListLimit = 500
|
|
SCUMDefaultTrajectoryLimit = 500
|
|
SCUMFactBatchLimit = 1000
|
|
)
|
|
|
|
type SCUMPosition struct {
|
|
X float64
|
|
Y float64
|
|
Z float64
|
|
}
|
|
|
|
type SCUMUser struct {
|
|
ID string
|
|
ServerInstanceID string
|
|
SteamID string
|
|
DisplayName string
|
|
SquadID int64
|
|
RegisteredAt time.Time
|
|
LastLoginAt time.Time
|
|
LastActivityAt time.Time
|
|
LastLoginIP string
|
|
Online bool
|
|
X *float64
|
|
Y *float64
|
|
Z *float64
|
|
BankBalance *int64
|
|
GoldBars *int64
|
|
RiddenVehicleID string
|
|
GameVehicleID string
|
|
LastLoginAge time.Duration
|
|
WelcomeQueuedAt time.Time
|
|
WelcomeLastError string
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
type SCUMUserFilter struct {
|
|
ServerInstanceID string
|
|
SteamID string
|
|
Online *bool
|
|
ChangedAfter time.Time
|
|
// StaleBefore matches users whose latest activity is older than the given
|
|
// instant. It backs the offline convergence query for stale online users.
|
|
StaleBefore time.Time
|
|
Limit int
|
|
}
|
|
|
|
type SCUMUserTrajectory struct {
|
|
ID string
|
|
ServerInstanceID string
|
|
SCUMUserID string
|
|
SteamID string
|
|
DisplayName string
|
|
X float64
|
|
Y float64
|
|
Z float64
|
|
RiddenVehicleID string
|
|
GameVehicleID string
|
|
ObservedAt time.Time
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type SCUMUserTrajectoryFilter struct {
|
|
ServerInstanceID string
|
|
SCUMUserID string
|
|
SteamID string
|
|
After time.Time
|
|
Limit int
|
|
}
|
|
|
|
type SCUMVehicle struct {
|
|
ID string
|
|
ServerInstanceID string
|
|
GameVehicleID string
|
|
VehicleClass string
|
|
DisplayName string
|
|
Exists bool
|
|
Locked bool
|
|
X *float64
|
|
Y *float64
|
|
Z *float64
|
|
LastObservedAt time.Time
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
type SCUMVehicleFilter struct {
|
|
ServerInstanceID string
|
|
GameVehicleID string
|
|
Exists *bool
|
|
ChangedAfter time.Time
|
|
Limit int
|
|
}
|
|
|
|
type SCUMVehicleTrajectory struct {
|
|
ID string
|
|
ServerInstanceID string
|
|
SCUMVehicleID string
|
|
GameVehicleID string
|
|
VehicleClass string
|
|
X float64
|
|
Y float64
|
|
Z float64
|
|
ObservedAt time.Time
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type SCUMVehicleTrajectoryFilter struct {
|
|
ServerInstanceID string
|
|
SCUMVehicleID string
|
|
GameVehicleID string
|
|
After time.Time
|
|
Limit int
|
|
}
|
|
|
|
type SCUMVehicleLock struct {
|
|
ID string
|
|
ServerInstanceID string
|
|
SCUMVehicleID string
|
|
GameVehicleID string
|
|
SCUMUserID string
|
|
SteamID string
|
|
LockedAt time.Time
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type SCUMVehicleLockFilter struct {
|
|
ServerInstanceID string
|
|
SCUMVehicleID string
|
|
GameVehicleID string
|
|
SCUMUserID string
|
|
SteamID string
|
|
After time.Time
|
|
Limit int
|
|
}
|
|
|
|
type SCUMSurface struct {
|
|
Users []SCUMUser
|
|
Vehicles []SCUMVehicle
|
|
UserTrajectories []SCUMUserTrajectory
|
|
VehicleTrajectories []SCUMVehicleTrajectory
|
|
VehicleLocks []SCUMVehicleLock
|
|
}
|
|
|
|
type SCUMFactIngest struct {
|
|
RunEndpointID string
|
|
SessionToken string
|
|
ServerInstanceID string
|
|
Users []SCUMUserFact
|
|
Vehicles []SCUMVehicleFact
|
|
}
|
|
|
|
type SCUMUserFact struct {
|
|
SteamID string
|
|
DisplayName string
|
|
SquadID *int64
|
|
LoginIP string
|
|
Online bool
|
|
Login bool
|
|
ObservedAt time.Time
|
|
LoginObservedAt time.Time
|
|
Position *SCUMPosition
|
|
BankBalance *int64
|
|
GoldBars *int64
|
|
RiddenGameVehicleID string
|
|
}
|
|
|
|
type SCUMVehicleFact struct {
|
|
GameVehicleID string
|
|
VehicleClass string
|
|
DisplayName string
|
|
Exists *bool
|
|
Locked *bool
|
|
LockedBySteamID string
|
|
LockedAt time.Time
|
|
ObservedAt time.Time
|
|
Position *SCUMPosition
|
|
}
|
|
|
|
type SCUMFactIngestResult struct {
|
|
Accepted bool
|
|
AcceptedUserCount int
|
|
AcceptedVehicleCount int
|
|
WelcomeQueuedCount int
|
|
ServerTime time.Time
|
|
}
|
|
|
|
func CopySCUMUser(value SCUMUser) SCUMUser {
|
|
value.X = copyFloatPtr(value.X)
|
|
value.Y = copyFloatPtr(value.Y)
|
|
value.Z = copyFloatPtr(value.Z)
|
|
value.BankBalance = copyInt64Ptr(value.BankBalance)
|
|
value.GoldBars = copyInt64Ptr(value.GoldBars)
|
|
return value
|
|
}
|
|
|
|
func CopySCUMUsers(values []SCUMUser) []SCUMUser {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
out := make([]SCUMUser, len(values))
|
|
for i, value := range values {
|
|
out[i] = CopySCUMUser(value)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func CopySCUMUserTrajectory(value SCUMUserTrajectory) SCUMUserTrajectory { return value }
|
|
func CopySCUMUserTrajectories(values []SCUMUserTrajectory) []SCUMUserTrajectory {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
out := make([]SCUMUserTrajectory, len(values))
|
|
copy(out, values)
|
|
return out
|
|
}
|
|
|
|
func CopySCUMVehicle(value SCUMVehicle) SCUMVehicle {
|
|
value.X = copyFloatPtr(value.X)
|
|
value.Y = copyFloatPtr(value.Y)
|
|
value.Z = copyFloatPtr(value.Z)
|
|
return value
|
|
}
|
|
|
|
func CopySCUMVehicles(values []SCUMVehicle) []SCUMVehicle {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
out := make([]SCUMVehicle, len(values))
|
|
for i, value := range values {
|
|
out[i] = CopySCUMVehicle(value)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func CopySCUMVehicleTrajectory(value SCUMVehicleTrajectory) SCUMVehicleTrajectory { return value }
|
|
func CopySCUMVehicleTrajectories(values []SCUMVehicleTrajectory) []SCUMVehicleTrajectory {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
out := make([]SCUMVehicleTrajectory, len(values))
|
|
copy(out, values)
|
|
return out
|
|
}
|
|
|
|
func CopySCUMVehicleLock(value SCUMVehicleLock) SCUMVehicleLock { return value }
|
|
func CopySCUMVehicleLocks(values []SCUMVehicleLock) []SCUMVehicleLock {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
out := make([]SCUMVehicleLock, len(values))
|
|
copy(out, values)
|
|
return out
|
|
}
|
|
|
|
func CopySCUMFactIngest(value SCUMFactIngest) SCUMFactIngest {
|
|
value.Users = CopySCUMUserFacts(value.Users)
|
|
value.Vehicles = CopySCUMVehicleFacts(value.Vehicles)
|
|
return value
|
|
}
|
|
|
|
func CopySCUMUserFacts(values []SCUMUserFact) []SCUMUserFact {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
out := make([]SCUMUserFact, len(values))
|
|
for i, value := range values {
|
|
out[i] = value
|
|
out[i].SquadID = copyInt64Ptr(value.SquadID)
|
|
out[i].BankBalance = copyInt64Ptr(value.BankBalance)
|
|
out[i].GoldBars = copyInt64Ptr(value.GoldBars)
|
|
if value.Position != nil {
|
|
position := *value.Position
|
|
out[i].Position = &position
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func CopySCUMVehicleFacts(values []SCUMVehicleFact) []SCUMVehicleFact {
|
|
if values == nil {
|
|
return nil
|
|
}
|
|
out := make([]SCUMVehicleFact, len(values))
|
|
for i, value := range values {
|
|
out[i] = value
|
|
out[i].Exists = copyBoolPtr(value.Exists)
|
|
out[i].Locked = copyBoolPtr(value.Locked)
|
|
if value.Position != nil {
|
|
position := *value.Position
|
|
out[i].Position = &position
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func copyInt64Ptr(value *int64) *int64 {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
copy := *value
|
|
return ©
|
|
}
|
|
|
|
func copyBoolPtr(value *bool) *bool {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
copy := *value
|
|
return ©
|
|
}
|