init commit
This commit is contained in:
72
internal/handlers/auth.go
Normal file
72
internal/handlers/auth.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"customServer/internal/protocol"
|
||||
"customServer/internal/state"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func HandleAsyncAuthRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling AsyncAuthRequest")
|
||||
|
||||
// Session Message
|
||||
sessionData := make([]byte, 0)
|
||||
// field 1 (Id), Varint (WireType 0)
|
||||
sessionData = append(sessionData, 0x08)
|
||||
sessionData = append(sessionData, protocol.EncodeVarint(uint64(time.Now().UnixNano()))...)
|
||||
|
||||
// Player Message
|
||||
player := state.GetMockPlayerBytes()
|
||||
|
||||
// AsyncConnectedRequest
|
||||
asyncConnected := make([]byte, 0)
|
||||
// field 1 (Session), message
|
||||
asyncConnected = append(asyncConnected, 0x0a)
|
||||
asyncConnected = append(asyncConnected, protocol.EncodeVarint(uint64(len(sessionData)))...)
|
||||
asyncConnected = append(asyncConnected, sessionData...)
|
||||
|
||||
// field 2 (Player), message
|
||||
asyncConnected = append(asyncConnected, 0x12)
|
||||
asyncConnected = append(asyncConnected, protocol.EncodeVarint(uint64(len(player)))...)
|
||||
asyncConnected = append(asyncConnected, player...)
|
||||
|
||||
return asyncConnected, 406
|
||||
}
|
||||
|
||||
func HandlePingRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling PingRequest")
|
||||
// The client sends a PingRequest with a timestamp (field 1).
|
||||
// We should respond with a PingRequest (777) containing the same timestamp.
|
||||
|
||||
// Extract timestamp if possible, otherwise just send back a default one
|
||||
// For simplicity, we just echo back what we got if it's small, or send a new one.
|
||||
return requestData, 777
|
||||
}
|
||||
|
||||
func HandleAsyncDisconnectRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling AsyncDisconnectRequest")
|
||||
return []byte{}, 401
|
||||
}
|
||||
|
||||
func HandleAskServerStatisticsRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling AskServerStatisticsRequest")
|
||||
// Return ServerStatisticsRequest (409)
|
||||
// Fields: 1:HostedGames, 2:Players, 3:ConnectedPlayers (all int32)
|
||||
stats := make([]byte, 0)
|
||||
|
||||
// Field 1: HostedGames (Varint)
|
||||
stats = append(stats, 0x08)
|
||||
stats = append(stats, protocol.EncodeVarint(1)...)
|
||||
|
||||
// Field 2: Players (Varint)
|
||||
stats = append(stats, 0x10)
|
||||
stats = append(stats, protocol.EncodeVarint(1)...)
|
||||
|
||||
// Field 3: ConnectedPlayers (Varint)
|
||||
stats = append(stats, 0x18)
|
||||
stats = append(stats, protocol.EncodeVarint(1)...)
|
||||
|
||||
return stats, 409
|
||||
}
|
||||
66
internal/handlers/dispatcher.go
Normal file
66
internal/handlers/dispatcher.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"customServer/internal/protocol"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Dispatcher Function
|
||||
// Note: We might pass dependencies here if we want to avoid globals,
|
||||
// but for this refactor we'll stick to dispatching to handler functions.
|
||||
|
||||
func Dispatch(conn net.Conn, packetID int64, requestNumber int32, requestData []byte) ([]byte, int) {
|
||||
fmt.Printf("[Dispatcher] Dispatching Request %d (PacketID: %d)\n", requestNumber, packetID)
|
||||
|
||||
switch requestNumber {
|
||||
// Auth
|
||||
case 400:
|
||||
return HandleAsyncAuthRequest(conn, requestData)
|
||||
case 401:
|
||||
return HandleAsyncDisconnectRequest(conn, requestData)
|
||||
case 408:
|
||||
return HandleAskServerStatisticsRequest(conn, requestData)
|
||||
|
||||
// System / Buddies
|
||||
case 515:
|
||||
return HandleAsyncBuddyListRequest(conn, requestData)
|
||||
case 560:
|
||||
return HandleAsyncIgnoreListRequest(conn, requestData)
|
||||
|
||||
// Lobby
|
||||
case 600:
|
||||
return HandleEnterLobbyRequest(conn, requestData)
|
||||
case 604:
|
||||
return HandleLobbyPlayerListRequest(conn, requestData)
|
||||
case 607:
|
||||
return HandleLobbyCreateGameRequest(conn, requestData)
|
||||
case 609:
|
||||
return HandleLobbyGameListRequest(conn, requestData)
|
||||
case 610:
|
||||
return HandleLobbyJoinGameRequest(conn, requestData)
|
||||
case 622:
|
||||
return HandleObservableGameListRequest(conn, requestData)
|
||||
|
||||
// Game
|
||||
case 511:
|
||||
return HandleWhatsNewPussycatRequest(conn, requestData)
|
||||
case 608:
|
||||
// Note: 608 is LobbyGameCreatedRequest (OUT), 607 is IN.
|
||||
// If client sends 608, it's weird.
|
||||
return nil, 0
|
||||
|
||||
// System / Ping
|
||||
case 777:
|
||||
return HandlePingRequest(conn, requestData)
|
||||
|
||||
default:
|
||||
fmt.Printf("[Dispatcher] Unknown Request %d\n", requestNumber)
|
||||
return nil, 0
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to encode varint for handlers that need it locally
|
||||
func encodeVarint(v uint64) []byte {
|
||||
return protocol.EncodeVarint(v)
|
||||
}
|
||||
79
internal/handlers/game.go
Normal file
79
internal/handlers/game.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"customServer/internal/protocol"
|
||||
"customServer/internal/state"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func HandleWhatsNewPussycatRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling WhatsNewPussycatRequest")
|
||||
|
||||
mgr := state.GlobalManager
|
||||
if mgr.HasActiveGame() {
|
||||
activeGameID := mgr.GetActiveGameID()
|
||||
fmt.Printf("[TCP] StatusReport: Reporting Active Game %d\n", activeGameID)
|
||||
|
||||
// StatusReport Message (Inner)
|
||||
innerReport := make([]byte, 0)
|
||||
|
||||
// Field 1: GameId (int64)
|
||||
innerReport = append(innerReport, 0x08)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(uint64(activeGameID))...)
|
||||
|
||||
// Field 2: Status (Enum) = 1 (IN_PROGRESS)
|
||||
innerReport = append(innerReport, 0x10)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(uint64(protocol.GameStatus_IN_PROGRESS))...)
|
||||
|
||||
// Field 3: Data (Bytes) - Dynamic IronGameState
|
||||
dataBytes := state.GetMockIronGameStateBytes()
|
||||
innerReport = append(innerReport, 0x1a)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(uint64(len(dataBytes)))...)
|
||||
innerReport = append(innerReport, dataBytes...)
|
||||
|
||||
// Field 4: TurnId (int32) = 4
|
||||
innerReport = append(innerReport, 0x20)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(4)...)
|
||||
|
||||
// Field 5: NextPlayerIds (Repeated Int32)
|
||||
nextPlayers := []uint64{uint64(state.MockUserID)}
|
||||
npBytes := make([]byte, 0)
|
||||
for _, pid := range nextPlayers {
|
||||
npBytes = append(npBytes, protocol.EncodeVarint(pid)...)
|
||||
}
|
||||
innerReport = append(innerReport, 0x2a)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(uint64(len(npBytes)))...)
|
||||
innerReport = append(innerReport, npBytes...)
|
||||
|
||||
// Field 6: Players (Repeated Player)
|
||||
mockPlayer := state.GetMockPlayerBytes()
|
||||
innerReport = append(innerReport, 0x32)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(uint64(len(mockPlayer)))...)
|
||||
innerReport = append(innerReport, mockPlayer...)
|
||||
|
||||
// Field 14: Configuration (GameConfiguration)
|
||||
fallbackConfig := getFallbackConfigBytes()
|
||||
innerReport = append(innerReport, 0x72)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(uint64(len(fallbackConfig)))...)
|
||||
innerReport = append(innerReport, fallbackConfig...)
|
||||
|
||||
// Field 16: ActivePlayer (Int32)
|
||||
innerReport = append(innerReport, 0x80, 0x01)
|
||||
innerReport = append(innerReport, protocol.EncodeVarint(uint64(state.MockUserID))...)
|
||||
|
||||
// Wrap in GameStatusReportRequest (Field 1: repeated StatusReport)
|
||||
responsePayload := make([]byte, 0)
|
||||
responsePayload = append(responsePayload, 0x0a)
|
||||
responsePayload = append(responsePayload, protocol.EncodeVarint(uint64(len(innerReport)))...)
|
||||
responsePayload = append(responsePayload, innerReport...)
|
||||
|
||||
return responsePayload, 512
|
||||
} else {
|
||||
fmt.Println("[TCP] StatusReport: Reporting Idle/Lobby State (Dynamic)")
|
||||
|
||||
// Idle Status (Empty reports list)
|
||||
responsePayload := make([]byte, 0)
|
||||
return responsePayload, 512
|
||||
}
|
||||
}
|
||||
208
internal/handlers/lobby.go
Normal file
208
internal/handlers/lobby.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"customServer/internal/protocol"
|
||||
"customServer/internal/state"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func HandleEnterLobbyRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling EnterLobbyRequest")
|
||||
|
||||
// Pre-push the game list so it's there when the client transitions
|
||||
gameList := getMockGameListBytes()
|
||||
conn.Write(protocol.WrapPacket(609, gameList, 999))
|
||||
|
||||
return []byte{}, 601
|
||||
}
|
||||
|
||||
func HandleLobbyPlayerListRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling LobbyPlayerListRequest")
|
||||
mockSmallPlayer := state.GetMockSmallPlayerBytes()
|
||||
|
||||
// PlayerList Message
|
||||
playerList := make([]byte, 0)
|
||||
playerList = append(playerList, 0x0a)
|
||||
playerList = append(playerList, protocol.EncodeVarint(uint64(len(mockSmallPlayer)))...)
|
||||
playerList = append(playerList, mockSmallPlayer...)
|
||||
|
||||
// Deflate
|
||||
compressed := protocol.ZlibCompress(playerList)
|
||||
|
||||
responsePayload := make([]byte, 0)
|
||||
responsePayload = append(responsePayload, 0x0a) // Field 1: playerList (ByteString)
|
||||
responsePayload = append(responsePayload, protocol.EncodeVarint(uint64(len(compressed)))...)
|
||||
responsePayload = append(responsePayload, compressed...)
|
||||
|
||||
return responsePayload, 604
|
||||
}
|
||||
|
||||
func HandleLobbyGameListRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling LobbyGameListRequest")
|
||||
return getMockGameListBytes(), 609
|
||||
}
|
||||
|
||||
func HandleObservableGameListRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling ObservableGameListRequest")
|
||||
return getMockGameListBytes(), 622
|
||||
}
|
||||
|
||||
func HandleLobbyCreateGameRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling LobbyCreateGameRequest")
|
||||
|
||||
// 1. Scan the request data for Field 607 (LobbyCreateGameRequest)
|
||||
// Actually, the dispatcher already gives us the requestData which IS the payload of the request number?
|
||||
// In the original main.go, the Switch handled requestNumber.
|
||||
// For 607, it manually scanned payloadBytes again.
|
||||
|
||||
var configBytes []byte
|
||||
msgReader := bytes.NewReader(requestData)
|
||||
for {
|
||||
tag, err := protocol.ReadVarint(msgReader)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
fieldNum := tag >> 3
|
||||
wireType := tag & 0x7
|
||||
|
||||
if fieldNum == 607 && wireType == 2 {
|
||||
length, _ := protocol.ReadVarint(msgReader)
|
||||
createGameReqBytes := make([]byte, length)
|
||||
msgReader.Read(createGameReqBytes)
|
||||
|
||||
// Extract Configuration (Field 1) from LobbyCreateGameRequest
|
||||
reqReader := bytes.NewReader(createGameReqBytes)
|
||||
for {
|
||||
rtag, rerr := protocol.ReadVarint(reqReader)
|
||||
if rerr != nil {
|
||||
break
|
||||
}
|
||||
rfieldNum := rtag >> 3
|
||||
rwireType := rtag & 0x7
|
||||
if rfieldNum == 1 && rwireType == 2 {
|
||||
rlength, _ := protocol.ReadVarint(reqReader)
|
||||
configBytes = make([]byte, rlength)
|
||||
reqReader.Read(configBytes)
|
||||
break
|
||||
} else {
|
||||
protocol.SkipField(reqReader, rwireType)
|
||||
}
|
||||
}
|
||||
break
|
||||
} else {
|
||||
protocol.SkipField(msgReader, wireType)
|
||||
}
|
||||
}
|
||||
|
||||
// Update State
|
||||
newGameID := int64(4016461897007108096)
|
||||
state.GlobalManager.CreateGame(newGameID)
|
||||
|
||||
// Construct Response (LobbyGameCreatedRequest 608)
|
||||
gameDetails := getMockGameDetailsBytes(newGameID, configBytes, [][]byte{state.GetMockPlayerBytes()})
|
||||
|
||||
// Push updated game list
|
||||
gameList := getMockGameListBytes()
|
||||
conn.Write(protocol.WrapPacket(609, gameList, 1000))
|
||||
|
||||
responsePayload := make([]byte, 0)
|
||||
responsePayload = append(responsePayload, 0x0a)
|
||||
responsePayload = append(responsePayload, protocol.EncodeVarint(uint64(len(gameDetails)))...)
|
||||
responsePayload = append(responsePayload, gameDetails...)
|
||||
|
||||
return responsePayload, 608
|
||||
}
|
||||
|
||||
func HandleLobbyJoinGameRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling LobbyJoinGameRequest")
|
||||
state.GlobalManager.CreateGame(4016461897007108096)
|
||||
|
||||
// Construct LobbyNewPlayerRequest (611)
|
||||
gameDetails := getMockGameDetailsBytes(4016461897007108096, nil, [][]byte{state.GetMockPlayerBytes()})
|
||||
|
||||
// LobbyNewPlayerRequest Message
|
||||
newPlayerReq := make([]byte, 0)
|
||||
// Field 1: GameDetails
|
||||
newPlayerReq = append(newPlayerReq, 0x0a)
|
||||
newPlayerReq = append(newPlayerReq, protocol.EncodeVarint(uint64(len(gameDetails)))...)
|
||||
newPlayerReq = append(newPlayerReq, gameDetails...)
|
||||
|
||||
// Field 2: JoiningPlayer
|
||||
newPlayerReq = append(newPlayerReq, 0x10)
|
||||
newPlayerReq = append(newPlayerReq, protocol.EncodeVarint(uint64(state.MockUserID))...)
|
||||
|
||||
return newPlayerReq, 611
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
func getMockGameDetailsBytes(gameID int64, configBytes []byte, players [][]byte) []byte {
|
||||
gameDetails := make([]byte, 0)
|
||||
gameDetails = append(gameDetails, 0x08)
|
||||
gameDetails = append(gameDetails, protocol.EncodeVarint(uint64(gameID))...)
|
||||
|
||||
for _, p := range players {
|
||||
gameDetails = append(gameDetails, 0x12)
|
||||
gameDetails = append(gameDetails, protocol.EncodeVarint(uint64(len(p)))...)
|
||||
gameDetails = append(gameDetails, p...)
|
||||
}
|
||||
|
||||
if len(configBytes) > 0 {
|
||||
// Field 3: Configuration (From request)
|
||||
gameDetails = append(gameDetails, 0x1a)
|
||||
gameDetails = append(gameDetails, protocol.EncodeVarint(uint64(len(configBytes)))...)
|
||||
gameDetails = append(gameDetails, configBytes...)
|
||||
} else {
|
||||
// Field 3: Configuration (Fallback)
|
||||
fallbackConfig := getFallbackConfigBytes()
|
||||
gameDetails = append(gameDetails, 0x1a)
|
||||
gameDetails = append(gameDetails, protocol.EncodeVarint(uint64(len(fallbackConfig)))...)
|
||||
gameDetails = append(gameDetails, fallbackConfig...)
|
||||
}
|
||||
|
||||
return gameDetails
|
||||
}
|
||||
|
||||
func getMockGameListBytes() []byte {
|
||||
// For the lobby list, show a game with NO players so anyone can join
|
||||
gameData := getMockGameDetailsBytes(4016461897007108096, nil, [][]byte{})
|
||||
|
||||
// GameList Message
|
||||
gameList := make([]byte, 0)
|
||||
gameList = append(gameList, 0x0a)
|
||||
gameList = append(gameList, protocol.EncodeVarint(uint64(len(gameData)))...)
|
||||
gameList = append(gameList, gameData...)
|
||||
|
||||
// Deflate
|
||||
compressed := protocol.ZlibCompress(gameList)
|
||||
|
||||
responsePayload := make([]byte, 0)
|
||||
responsePayload = append(responsePayload, 0x0a) // Field 1: gameList (ByteString)
|
||||
responsePayload = append(responsePayload, protocol.EncodeVarint(uint64(len(compressed)))...)
|
||||
responsePayload = append(responsePayload, compressed...)
|
||||
return responsePayload
|
||||
}
|
||||
|
||||
func getFallbackConfigBytes() []byte {
|
||||
fallbackConfig := make([]byte, 0)
|
||||
name := "Fallback Game"
|
||||
fallbackConfig = append(fallbackConfig, 0x0a)
|
||||
fallbackConfig = append(fallbackConfig, protocol.EncodeVarint(uint64(len(name)))...)
|
||||
fallbackConfig = append(fallbackConfig, name...)
|
||||
fallbackConfig = append(fallbackConfig, 0x10, 0x00, 0x18, 0x01, 0x20, 0x00)
|
||||
fallbackConfig = append(fallbackConfig, 0x28)
|
||||
fallbackConfig = append(fallbackConfig, protocol.EncodeVarint(1)...)
|
||||
fallbackConfig = append(fallbackConfig, 0x30)
|
||||
fallbackConfig = append(fallbackConfig, protocol.EncodeVarint(6)...)
|
||||
fallbackConfig = append(fallbackConfig, 0x48, 0x00, 0x50, 0x2d)
|
||||
|
||||
// Field 11: Data (IronGameConfiguration)
|
||||
ironData := state.GetMockIronGameConfigurationBytes()
|
||||
fallbackConfig = append(fallbackConfig, 0x5a) // (11 << 3) | 2 = 88 | 2 = 90 = 0x5a
|
||||
fallbackConfig = append(fallbackConfig, protocol.EncodeVarint(uint64(len(ironData)))...)
|
||||
fallbackConfig = append(fallbackConfig, ironData...)
|
||||
|
||||
return fallbackConfig
|
||||
}
|
||||
20
internal/handlers/system.go
Normal file
20
internal/handlers/system.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func HandleAsyncBuddyListRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling AsyncBuddyListRequest")
|
||||
// Return AsyncBuddyListContentRequest (516)
|
||||
// Field 2: Buddies (AsyncBuddyList)
|
||||
return []byte{0x12, 0x00}, 516
|
||||
}
|
||||
|
||||
func HandleAsyncIgnoreListRequest(conn net.Conn, requestData []byte) ([]byte, int) {
|
||||
fmt.Println("[TCP] Handling AsyncIgnoreListRequest")
|
||||
// Return AsyncIgnoreListContentRequest (516)
|
||||
// Field 2: Ignores (AsyncBuddyList)
|
||||
return []byte{0x12, 0x00}, 561
|
||||
}
|
||||
Reference in New Issue
Block a user