Add game clock commands, command completions and Cyrene login tooling
This commit is contained in:
1 parent
1fa9504176
commit
67a819a4d3
21 files changed
+1194
-7
No files matched your search
@@ -2,6 +2,9 @@ package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -27,6 +30,21 @@ type RuntimeConfig struct {
|
||||
SDKPort uint16 `json:"sdk_port"`
|
||||
PublicGameHost string `json:"public_game_host"`
|
||||
PublicSDKURL string `json:"public_sdk_url"`
|
||||
LuaOverlay LuaOverlayConfig `json:"lua_overlay"`
|
||||
GameClock GameClockConfig `json:"game_clock"`
|
||||
}
|
||||
|
||||
type GameClockConfig struct {
|
||||
StateFile string `json:"state_file"`
|
||||
}
|
||||
|
||||
// Optional Client Lua update mirror. Machine-specific directories must be
|
||||
// supplied by the local config or environment; empty means disabled.
|
||||
type LuaOverlayConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
StageDir string `json:"stage_dir"`
|
||||
HotfixDir string `json:"hotfix_dir"`
|
||||
StreamingDir string `json:"streaming_dir"`
|
||||
}
|
||||
|
||||
// The schedule interval is an explicit operator policy shared by SDK, gateway,
|
||||
@@ -65,12 +83,31 @@ func LoadRuntimeConfig() (RuntimeConfig, error) {
|
||||
"GAC_ACCOUNT_NAME": &cfg.AccountName,
|
||||
"GAC_CLIENT_VERSION": &cfg.ClientVersion, "GAC_GAME_HOST": &cfg.GameHost,
|
||||
"GAC_SDK_HOST": &cfg.SDKHost, "GAC_PUBLIC_GAME_HOST": &cfg.PublicGameHost,
|
||||
"GAC_PUBLIC_SDK_URL": &cfg.PublicSDKURL,
|
||||
"GAC_PUBLIC_SDK_URL": &cfg.PublicSDKURL,
|
||||
"GAC_LUA_OVERLAY_STAGE_DIR": &cfg.LuaOverlay.StageDir,
|
||||
"GAC_LUA_OVERLAY_HOTFIX_DIR": &cfg.LuaOverlay.HotfixDir,
|
||||
"GAC_LUA_OVERLAY_STREAMING_DIR": &cfg.LuaOverlay.StreamingDir,
|
||||
"GAC_GAME_CLOCK_STATE_FILE": &cfg.GameClock.StateFile,
|
||||
} {
|
||||
if value, ok := os.LookupEnv(name); ok {
|
||||
*dest = value
|
||||
}
|
||||
}
|
||||
if value, ok := os.LookupEnv("GAC_LUA_OVERLAY_ENABLED"); ok {
|
||||
enabled, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("GAC_LUA_OVERLAY_ENABLED must be a boolean")
|
||||
}
|
||||
cfg.LuaOverlay.Enabled = enabled
|
||||
}
|
||||
if cfg.GameClock.StateFile != "" {
|
||||
if strings.TrimSpace(cfg.GameClock.StateFile) == "" {
|
||||
return cfg, fmt.Errorf("game_clock.state_file must be a file path")
|
||||
}
|
||||
if info, err := os.Stat(cfg.GameClock.StateFile); err == nil && info.IsDir() {
|
||||
return cfg, fmt.Errorf("game_clock.state_file must not be a directory")
|
||||
}
|
||||
}
|
||||
for name, dest := range map[string]*uint16{"GAC_GAME_PORT": &cfg.GamePort, "GAC_SDK_PORT": &cfg.SDKPort} {
|
||||
if value, ok := os.LookupEnv(name); ok {
|
||||
n, err := strconv.ParseUint(value, 10, 16)
|
||||
@@ -119,6 +156,31 @@ func LoadRuntimeConfig() (RuntimeConfig, error) {
|
||||
if cfg.PlayerUID == 0 {
|
||||
return cfg, fmt.Errorf("runtime config requires a nonzero player_uid")
|
||||
}
|
||||
if cfg.LuaOverlay.Enabled {
|
||||
for name, directory := range map[string]string{"stage_dir": cfg.LuaOverlay.StageDir, "hotfix_dir": cfg.LuaOverlay.HotfixDir, "streaming_dir": cfg.LuaOverlay.StreamingDir} {
|
||||
if strings.TrimSpace(directory) == "" {
|
||||
return cfg, fmt.Errorf("lua_overlay.%s is required when enabled", name)
|
||||
}
|
||||
info, err := os.Stat(directory)
|
||||
if err != nil || !info.IsDir() {
|
||||
return cfg, fmt.Errorf("lua_overlay.%s must be an existing directory", name)
|
||||
}
|
||||
}
|
||||
selector, err := os.ReadFile(filepath.Join(cfg.LuaOverlay.StageDir, "M_LuaV.bytes"))
|
||||
if err != nil || len(selector) != 66 || string(selector[:4]) != "SRMI" {
|
||||
return cfg, fmt.Errorf("lua_overlay stage selector is invalid")
|
||||
}
|
||||
var indexDigest [16]byte
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 4; j++ {
|
||||
indexDigest[i*4+j] = selector[28+i*4+3-j]
|
||||
}
|
||||
}
|
||||
index, err := os.ReadFile(filepath.Join(cfg.LuaOverlay.StageDir, "LuaV_"+hex.EncodeToString(indexDigest[:])+".bytes"))
|
||||
if err != nil || len(index) != int(binary.LittleEndian.Uint32(selector[44:48])) || md5.Sum(index) != indexDigest {
|
||||
return cfg, fmt.Errorf("lua_overlay staged index is missing or invalid")
|
||||
}
|
||||
}
|
||||
if cfg.GamePort == 0 || cfg.SDKPort == 0 || strings.TrimSpace(cfg.ClientVersion) == "" {
|
||||
return cfg, fmt.Errorf("runtime config requires client_version, game_port and sdk_port")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user