init commit

This commit is contained in:
Jose Luis Montañes Ojados
2026-01-14 21:33:21 +01:00
commit dbab788e6b
27 changed files with 4001 additions and 0 deletions

158
internal/state/helpers.go Normal file
View File

@@ -0,0 +1,158 @@
package state
import (
"customServer/internal/protocol"
)
// Constants
const (
MockUserID = 8381763
MockUserName = "CustomPlayer"
)
// Helpers to generate mock bytes using Protocol Codecs
// We use manual encoding to ensure exact byte match with original monolithic server for safety
func GetMockPlayerBytes() []byte {
player := make([]byte, 0)
// field 1 (Name), string
player = append(player, 0x0a)
player = append(player, protocol.EncodeVarint(uint64(len(MockUserName)))...)
player = append(player, MockUserName...)
// field 2 (Id), varint
player = append(player, 0x10)
player = append(player, protocol.EncodeVarint(uint64(MockUserID))...)
// field 5 (Karma), varint
player = append(player, 0x28)
player = append(player, protocol.EncodeVarint(52)...)
// field 7 (RankScore), fixed64 (WireType 1) - double
player = append(player, 0x39) // (7 << 3) | 1 = 57 = 0x39
player = append(player, protocol.EncodeDouble(1500.0)...)
// field 9 (WWWId), varint
player = append(player, 0x48)
player = append(player, protocol.EncodeVarint(uint64(MockUserID))...)
// field 11 (nbGames), varint
player = append(player, 0x58)
player = append(player, protocol.EncodeVarint(2)...)
// field 12 (Banned), varint
player = append(player, 0x60)
player = append(player, protocol.EncodeVarint(0)...) // False
// field 14 (Avatar), message
avatarMsg := make([]byte, 0)
avatarUrl := "https://uploads.asmodee.net/builtin/avatar-neutral.jpg"
// Avatar.Image (Field 3), String
avatarMsg = append(avatarMsg, 0x1a)
avatarMsg = append(avatarMsg, protocol.EncodeVarint(uint64(len(avatarUrl)))...)
avatarMsg = append(avatarMsg, avatarUrl...)
player = append(player, 0x72) // Field 14, WireType 2
player = append(player, protocol.EncodeVarint(uint64(len(avatarMsg)))...)
player = append(player, avatarMsg...)
// field 15 (Language), varint
player = append(player, 0x78)
player = append(player, protocol.EncodeVarint(1)...)
// field 16 (Tz), string
player = append(player, 0x82, 0x01) // Field 16 (128 + 2), WireType 2
player = append(player, protocol.EncodeVarint(uint64(len("UTC")))...)
player = append(player, "UTC"...)
return player
}
func GetMockSmallPlayerBytes() []byte {
player := make([]byte, 0)
// field 1 (WWWId), int32
player = append(player, 0x08)
player = append(player, protocol.EncodeVarint(uint64(MockUserID))...)
// field 2 (Name), string
player = append(player, 0x12)
player = append(player, protocol.EncodeVarint(uint64(len(MockUserName)))...)
player = append(player, MockUserName...)
// field 3 (Karma), int32
player = append(player, 0x18)
player = append(player, protocol.EncodeVarint(52)...)
// field 4 (RankScore), double
player = append(player, 0x21) // (4 << 3) | 1 = 33 = 0x21
player = append(player, protocol.EncodeDouble(1500.0)...)
return player
}
func GetMockIronHumanPlayerBytes() []byte {
// IronHumanPlayer
// Field 1: PlayerId (int32)
// Field 2: House (Enum) -> Stark (0)
data := make([]byte, 0)
// PlayerId
data = append(data, 0x08)
data = append(data, protocol.EncodeVarint(uint64(MockUserID))...)
// House (0 is default, we skip it)
return data
}
func GetMockIronGameConfigurationBytes() []byte {
// IronGameConfiguration
// Field 1: TotalPlayers (int32) -> 6
// Field 7: HumanPlayers (repeated IronHumanPlayer)
// Field 8: CreatedBy (int64)
data := make([]byte, 0)
// TotalPlayers = 6
data = append(data, 0x08)
data = append(data, protocol.EncodeVarint(6)...)
// HumanPlayers
hpBytes := GetMockIronHumanPlayerBytes()
data = append(data, 0x3a) // Field 7, WireType 2
data = append(data, protocol.EncodeVarint(uint64(len(hpBytes)))...)
data = append(data, hpBytes...)
// CreatedBy
data = append(data, 0x40) // Field 8, WireType 0
data = append(data, protocol.EncodeVarint(uint64(MockUserID))...)
return data
}
func GetMockIronGameStateBytes() []byte {
// IronGameState
// Field 1: GameId (int64)
// Field 2: Version (int32)
// Field 7: Configuration (IronGameConfiguration)
// Field 9: AllianceStateVersion (int32)
data := make([]byte, 0)
// GameId
data = append(data, 0x08)
data = append(data, protocol.EncodeVarint(4016461897007108096)...)
// Version
data = append(data, 0x10)
data = append(data, protocol.EncodeVarint(1)...)
// Configuration
configBytes := GetMockIronGameConfigurationBytes()
data = append(data, 0x3a) // Field 7, WireType 2
data = append(data, protocol.EncodeVarint(uint64(len(configBytes)))...)
data = append(data, configBytes...)
// AllianceStateVersion
data = append(data, 0x48)
data = append(data, protocol.EncodeVarint(1)...)
return data
}

64
internal/state/manager.go Normal file
View File

@@ -0,0 +1,64 @@
package state
import (
_ "embed"
"encoding/base64"
"fmt"
"sync"
)
// Global Game State Manager
type GameManager struct {
mu sync.Mutex
hasActiveGame bool
activeGameID int64
activeGameData []byte
}
var GlobalManager *GameManager
func init() {
GlobalManager = &GameManager{
hasActiveGame: false,
activeGameID: 0,
}
// Pre-decode the embedded game data
data, err := base64.StdEncoding.DecodeString(MockGameDataBase64)
if err != nil {
fmt.Printf("Error decoding mock game data: %v\n", err)
} else {
GlobalManager.activeGameData = data
}
}
func (m *GameManager) HasActiveGame() bool {
m.mu.Lock()
defer m.mu.Unlock()
return m.hasActiveGame
}
func (m *GameManager) GetActiveGameID() int64 {
m.mu.Lock()
defer m.mu.Unlock()
return m.activeGameID
}
func (m *GameManager) GetActiveGameData() []byte {
m.mu.Lock()
defer m.mu.Unlock()
return m.activeGameData
}
func (m *GameManager) CreateGame(id int64) {
m.mu.Lock()
defer m.mu.Unlock()
m.hasActiveGame = true
m.activeGameID = id
m.activeGameData = GetMockIronGameStateBytes()
}
// Embeds
//go:embed mock_gamedata.b64
var MockGameDataBase64 string

View File

@@ -0,0 +1 @@
CICggOjD6dXeNxAKGAMiVnsibmFtZSI6InN3dCIsInZhbHVlIjp7InNsbiI6eyJlaWQiOjE5MiwidHJzIjpbeyJlbHQiOls2NTNdLCJuYW1lIjoiZWx0ciJ9XX0sImN0ciI6MX19IlZ7Im5hbWUiOiJzd3QiLCJ2YWx1ZSI6eyJzbG4iOnsiZWlkIjo2NTMsInRycyI6W3siZWx0IjpbNTUxXSwibmFtZSI6ImVsdHIifV19LCJjdHIiOjF9fSJWeyJuYW1lIjoic3d0IiwidmFsdWUiOnsic2xuIjp7ImVpZCI6MjAyLCJ0cnMiOlt7ImVsdCI6WzYzOV0sIm5hbWUiOiJlbHRyIn1dfSwiY3RyIjoxfX0iVnsibmFtZSI6InN3dCIsInZhbHVlIjp7InNsbiI6eyJlaWQiOjYzOSwidHJzIjpbeyJlbHQiOls1NTFdLCJuYW1lIjoiZWx0ciJ9XX0sImN0ciI6MX19IlZ7Im5hbWUiOiJzd3QiLCJ2YWx1ZSI6eyJzbG4iOnsiZWlkIjoyMDIsInRycyI6W3siZWx0IjpbNjM5XSwibmFtZSI6ImVsdHIifV19LCJjdHIiOjF9fSJWeyJuYW1lIjoic3d0IiwidmFsdWUiOnsic2xuIjp7ImVpZCI6MTkyLCJ0cnMiOlt7ImVsdCI6WzY2MV0sIm5hbWUiOiJlbHRyIn1dfSwiY3RyIjoxfX0iVnsibmFtZSI6InN3dCIsInZhbHVlIjp7InNsbiI6eyJlaWQiOjE5MCwidHJzIjpbeyJlbHQiOls2NjNdLCJuYW1lIjoiZWx0ciJ9XX0sImN0ciI6MX19IlZ7Im5hbWUiOiJzd3QiLCJ2YWx1ZSI6eyJzbG4iOnsiZWlkIjo2NjMsInRycyI6W3siZWx0IjpbNTUxXSwibmFtZSI6ImVsdHIifV19LCJjdHIiOjF9fSJWeyJuYW1lIjoic3d0IiwidmFsdWUiOnsic2xuIjp7ImVpZCI6MTkwLCJ0cnMiOlt7ImVsdCI6WzY0NV0sIm5hbWUiOiJlbHRyIn1dfSwiY3RyIjoxfX0iIHsibmFtZSI6InN3dCIsInZhbHVlIjp7InNsbiI6eyJlaWQiOjE5MiwidHJzIjpbeyJlbHQiOltdLCJuYW1lIjoiZWx0ciJ9XX0sImN0ciI6NTd9fSJXeyJuYW1lIjoic3d0IiwidmFsdWUiOnsic2xuIjp7ImVpZCI6MTc1LCJ0cnMiOlt7ImVsdCI6WzE2N10sIm5hbWUiOiJlbHRyIn1dfSwiY3RyIjo2MX19IlR7Im5hbWUiOiJzd3QiLCJ2YWx1ZSI6eyJzbG4iOnsiZWlkIjoxNjksInRycyI6W3siZWx0IjpbXSwibmFtZSI6ImVsdHIifV19LCJjdHIiOjYzfX0iV3sibmFtZSI6InN3dCIsInZhbHVlIjp7InNsbiI6eyJlaWQiOjI1MCwidHJzIjpbeyJlbHQiOlsxNTZdLCJuYW1lIjoiZWx0ciJ9XX0sImN0ciI6NzJ9fSIgeyJuYW1lIjoibXMiLCJ2YWx1ZSI6eyJjdHIiOjc1fX0iL3sibmFtZSI6ImdjYyIsInZhbHVlIjp7InNlbGVjdGlvbiI6MCwiY3RyIjo4MX19Ild7Im5hbWUiOiJzd3QiLCJ2YWx1ZSI6eyJzbG4iOnsiZWlkIjoyNTAsInRycyI6W3siZWx0IjpbMTUyXSwibmFtZSI6ImVsdHIifV19LCJjdHIiOjg4fX0iL3sibmFtZSI6ImdjYyIsInZhbHVlIjp7InNlbGVjdGlvbiI6MywiY3RyIjo5N319Ilh7Im5hbWUiOiJzd3QiLCJ2YWx1ZSI6eyJzbG4iOnsiZWlkIjo1NDMsInRycyI6W3siZWx0IjpbMTkyXSwibmFtZSI6ImVsdHIifV19LCJjdHIiOjExMX19IjB7Im5hbWUiOiJnY2MiLCJ2YWx1ZSI6eyJzZWxlY3Rpb24iOjQsImN0ciI6MTE4fX0iMHsibmFtZSI6ImdjYyIsInZhbHVlIjp7InNlbGVjdGlvbiI6MCwiY3RyIjoxMjJ9fToWOgIIAToECAIQBToECAMQAToECAQQBA==

View File