feat(scum): add bounded vehicle spawn adapter
This commit is contained in:
@@ -42,6 +42,28 @@ type ue4SSPlayerNotification struct {
|
||||
protectedAuditCommand string
|
||||
}
|
||||
|
||||
// UE4SSVehicleSpawnPort is a Companion-local, platform-authorized transport
|
||||
// for one fixed template. It accepts no raw command text, socket, credential,
|
||||
// or host path. Implementations remain in this Companion package so the
|
||||
// protected audit template cannot cross a general transport boundary.
|
||||
type UE4SSVehicleSpawnPort interface {
|
||||
SpawnVehicle(context.Context, ue4SSVehicleSpawn) (UE4SSVehicleSpawnReceipt, error)
|
||||
}
|
||||
type UE4SSVehicleSpawnOutcome string
|
||||
|
||||
const (
|
||||
UE4SSVehicleSpawnAccepted UE4SSVehicleSpawnOutcome = "accepted"
|
||||
UE4SSVehicleSpawnRejected UE4SSVehicleSpawnOutcome = "rejected"
|
||||
UE4SSVehicleSpawnUnknown UE4SSVehicleSpawnOutcome = "unknown"
|
||||
)
|
||||
|
||||
type UE4SSVehicleSpawnReceipt struct{ Outcome UE4SSVehicleSpawnOutcome }
|
||||
type ue4SSVehicleSpawn struct {
|
||||
ServerID string
|
||||
VehicleCode string
|
||||
protectedAuditCommand string
|
||||
}
|
||||
|
||||
type VersionedAdapter struct {
|
||||
BoundServerID string
|
||||
ServerVersion string
|
||||
@@ -49,6 +71,7 @@ type VersionedAdapter struct {
|
||||
UE4SSReferenceRevision string
|
||||
Config AuthorizedConfigPort
|
||||
Notification UE4SSNotificationPort
|
||||
VehicleSpawn UE4SSVehicleSpawnPort
|
||||
DiagnosticsState map[string]string
|
||||
}
|
||||
|
||||
@@ -103,7 +126,7 @@ func (VersionedAdapter) DeliverReward(context.Context, map[string]any) (map[stri
|
||||
return nil, fmt.Errorf("reward adapter is unsupported")
|
||||
}
|
||||
func (adapter VersionedAdapter) NotifyPlayer(ctx context.Context, payload map[string]any) (map[string]any, error) {
|
||||
if !adapter.supportsUE4SSNotification() || adapter.Notification == nil {
|
||||
if !adapter.supportsPinnedUE4SS() || adapter.Notification == nil {
|
||||
return nil, fmt.Errorf("notification adapter is unsupported")
|
||||
}
|
||||
playerID, playerOK := payload["playerId"].(string)
|
||||
@@ -121,12 +144,33 @@ func (adapter VersionedAdapter) NotifyPlayer(ctx context.Context, payload map[st
|
||||
}
|
||||
return map[string]any{"accepted": true, "message": "notification accepted for online recipient"}, nil
|
||||
}
|
||||
func (adapter VersionedAdapter) SpawnVehicle(ctx context.Context, payload map[string]any) (map[string]any, error) {
|
||||
if !adapter.supportsPinnedUE4SS() || adapter.VehicleSpawn == nil {
|
||||
return nil, fmt.Errorf("vehicle spawn adapter is unsupported")
|
||||
}
|
||||
vehicleCode, ok := payload["vehicleCode"].(string)
|
||||
spawn, err := newUE4SSVehicleSpawn(adapter.BoundServerID, vehicleCode)
|
||||
if !ok || err != nil {
|
||||
return nil, fmt.Errorf("vehicle spawn payload is invalid")
|
||||
}
|
||||
receipt, err := adapter.VehicleSpawn.SpawnVehicle(ctx, spawn)
|
||||
if err != nil || receipt.Outcome == UE4SSVehicleSpawnUnknown {
|
||||
return map[string]any{"outcome": "unknown"}, nil
|
||||
}
|
||||
if receipt.Outcome == UE4SSVehicleSpawnRejected {
|
||||
return map[string]any{"outcome": "failed"}, nil
|
||||
}
|
||||
if receipt.Outcome != UE4SSVehicleSpawnAccepted {
|
||||
return map[string]any{"outcome": "unknown"}, nil
|
||||
}
|
||||
return map[string]any{"outcome": "succeeded"}, nil
|
||||
}
|
||||
|
||||
func (adapter VersionedAdapter) supportsUE4SSNotification() bool {
|
||||
func (adapter VersionedAdapter) supportsPinnedUE4SS() bool {
|
||||
// The pinned source reflects SendChatLineToPlayer at runtime and fails
|
||||
// closed on a schema change, so no unverified SCUM-version mapping is
|
||||
// embedded here. The dispatcher still requires a discovered server version.
|
||||
return adapter.BoundServerID != "" && adapter.UE4SSBuild == UE4SSReferenceBuild && adapter.UE4SSReferenceRevision == UE4SSReferenceRevision
|
||||
return adapter.BoundServerID != "" && supportedAdapterVersion(adapter.ServerVersion) && adapter.UE4SSBuild == UE4SSReferenceBuild && adapter.UE4SSReferenceRevision == UE4SSReferenceRevision
|
||||
}
|
||||
func newUE4SSPlayerNotification(serverID, playerID, message string) (ue4SSPlayerNotification, error) {
|
||||
if strings.TrimSpace(serverID) == "" || !steamID64(playerID) || !validNotificationMessage(message) {
|
||||
@@ -134,6 +178,12 @@ func newUE4SSPlayerNotification(serverID, playerID, message string) (ue4SSPlayer
|
||||
}
|
||||
return ue4SSPlayerNotification{ServerID: serverID, RecipientSteamID: playerID, Message: message, chatType: fixedNotificationType, protectedAuditCommand: "SendChat 4 \"" + escapeUE4SSChatMessage(message) + "\" " + playerID}, nil
|
||||
}
|
||||
func newUE4SSVehicleSpawn(serverID, vehicleCode string) (ue4SSVehicleSpawn, error) {
|
||||
if strings.TrimSpace(serverID) == "" || !supportedVehicleSpawnCode(vehicleCode) {
|
||||
return ue4SSVehicleSpawn{}, fmt.Errorf("invalid typed UE4SS vehicle spawn")
|
||||
}
|
||||
return ue4SSVehicleSpawn{ServerID: serverID, VehicleCode: vehicleCode, protectedAuditCommand: "#spawnvehicle " + vehicleCode}, nil
|
||||
}
|
||||
func steamID64(value string) bool {
|
||||
if len(value) != 17 {
|
||||
return false
|
||||
@@ -161,6 +211,9 @@ func escapeUE4SSChatMessage(value string) string {
|
||||
}
|
||||
|
||||
func supportedAdapterVersion(version string) bool { return version == "0.9.700.90357" }
|
||||
func supportedVehicleSpawnCode(value string) bool {
|
||||
return map[string]bool{"BPC_Laika_C": true, "BPC_WolfsWagen_C": true}[value]
|
||||
}
|
||||
func supportedConfigKey(key string) bool {
|
||||
return map[string]bool{"ServerName": true, "GamePort": true, "QueryPort": true, "MaxPlayers": true, "WelcomeMessage": true}[key]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user