go-susapp/packetprocessor.go

204 lines
8.1 KiB
Go

package main
import (
"encoding/hex"
"fmt"
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/gamedata"
"codehub.onpointcoding.net/sean/go-susapp/innernetobjects"
"codehub.onpointcoding.net/sean/go-susapp/packets"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/util"
)
type PacketProcessor struct {
sus *SusApp
gameDataProcessor *GameDataProcessor
normalPacketTagMap map[byte]func(net *protocol.PacketHandler, h *protocol.Hazel)
reliablePacketTagMap map[byte]func(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel)
}
func NewPacketProcessor(sus *SusApp) *PacketProcessor {
proc := &PacketProcessor{sus: sus, gameDataProcessor: NewGameDataProcessor(sus)}
proc.normalPacketTagMap = map[byte]func(net *protocol.PacketHandler, h *protocol.Hazel){
0x05: proc.captureUnreliableGameDataAll,
0x06: proc.captureUnreliableGameDataTo,
}
proc.reliablePacketTagMap = map[byte]func(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel){
0x00: proc.captureCreateGame,
0x01: proc.emptyCapture,
0x02: proc.captureStartGame,
0x04: proc.captureRemovePlayer,
0x05: proc.captureGameDataAll,
0x06: proc.captureGameDataTo,
0x07: proc.captureJoinedGame,
0x0a: proc.captureAlterGame,
0x0d: proc.captureRedirect,
}
return proc
}
func (proc *PacketProcessor) receiveNormalPacket(net *protocol.PacketHandler, h []*protocol.Hazel) {
for i := 0; i < len(h); i++ {
v, ok := proc.normalPacketTagMap[h[i].GetTag()]
if ok {
v(net, h[i])
} else {
fmt.Printf("Unable to parse normal packet with tag of %x\n", h[i].GetTag())
fmt.Printf("Packet %v\n", hex.EncodeToString(h[i].GetUnderlyingPacket().Dump()))
}
}
}
func (proc *PacketProcessor) receiveReliablePacket(net *protocol.PacketHandler, nonce uint16, h []*protocol.Hazel) {
for i := 0; i < len(h); i++ {
v, ok := proc.reliablePacketTagMap[h[i].GetTag()]
if ok {
v(net, nonce, h[i])
net.SendAcknowledgementPacket(nonce, 0xff)
} else {
fmt.Printf("Unable to parse packets with tag of %x\n", h[i].GetTag())
fmt.Printf("Packet: %v\n", hex.EncodeToString(h[i].GetUnderlyingPacket().Dump()))
}
}
}
func (proc *PacketProcessor) emptyCapture(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
}
func (proc *PacketProcessor) captureCreateGame(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.HostGameS2C{}
a.Read(h.GetUnderlyingPacket())
proc.sus.state.TypedGameID = util.CodeFromGameID(a.GameID)
var z protocol.HazelPayload = &packets.JoinGameC2S{GameID: a.GameID}
proc.sus.networkHandler.SendReliablePacket(proc.sus.networkHandler.GetNonce(), []*protocol.Hazel{
protocol.NewHazelFromPayload(&z),
})
}
func (proc *PacketProcessor) captureStartGame(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.StartGameH2G{}
a.Read(h.GetUnderlyingPacket())
if a.GameID == proc.sus.state.CurrentGame.GameID {
proc.sus.state.Screen = enum.SCREEN_INGAME
proc.sus.state.LoadCollisionForMap(proc.sus.state.CurrentGame.GameOptions.Maps)
var d1 packets.GameDataSubpacket = &gamedata.ReadyC2H{ReadyClientID: proc.sus.state.CurrentGame.ClientID}
var d2 protocol.HazelPayload = packets.NewGameDataToSingleSubpacket(proc.sus.state.CurrentGame.GameID, proc.sus.state.CurrentGame.HostClientID, &d1)
net.SendReliablePacket(proc.sus.networkHandler.GetNonce(), []*protocol.Hazel{protocol.NewHazelFromPayload(&d2)})
}
}
func (proc *PacketProcessor) captureGameDataAll(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.GameDataAll{}
a.Read(h.GetUnderlyingPacket())
proc.gameDataProcessor.receiveGameDataSubpacket(net, a.GameID, a.Subpackets)
}
func (proc *PacketProcessor) captureGameDataTo(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.GameDataTo{}
a.Read(h.GetUnderlyingPacket())
if a.TargetClientID == proc.sus.state.CurrentGame.ClientID {
proc.gameDataProcessor.receiveGameDataSubpacket(net, a.GameID, a.Subpackets)
}
}
func (proc *PacketProcessor) captureUnreliableGameDataAll(net *protocol.PacketHandler, h *protocol.Hazel) {
a := &packets.GameDataAll{}
a.Read(h.GetUnderlyingPacket())
proc.gameDataProcessor.receiveGameDataSubpacket(net, a.GameID, a.Subpackets)
}
func (proc *PacketProcessor) captureUnreliableGameDataTo(net *protocol.PacketHandler, h *protocol.Hazel) {
a := &packets.GameDataTo{}
a.Read(h.GetUnderlyingPacket())
if a.TargetClientID == proc.sus.state.CurrentGame.ClientID {
proc.gameDataProcessor.receiveGameDataSubpacket(net, a.GameID, a.Subpackets)
}
}
func (proc *PacketProcessor) captureJoinedGame(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.JoinedGameH2C{}
a.Read(h.GetUnderlyingPacket())
fmt.Printf("Joined game: %v\n", a.GameID)
fmt.Printf("Client id: %v\n", a.JoinedClientID)
fmt.Printf("Host client id: %v\n", a.HostClientID)
proc.sus.state.CurrentGame = &CurrentGameData{
GameID: a.GameID,
ClientID: a.JoinedClientID,
HostClientID: a.HostClientID,
GamePrivacy: 0,
GameOptions: protocol.NewDefaultGameOptionsData(),
NetObjects: map[uint32]*innernetobjects.InnerNetObject{},
PlayerNetObjects: &PlayerNetObjectMaps{},
}
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerClientID = map[uint32]*PlayerObject{}
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID = map[uint32]*PlayerObject{}
proc.sus.state.CurrentGame.OtherClientIDs = a.OtherClientIDs
proc.sus.state.Screen = enum.SCREEN_LOBBY
proc.sus.state.LoadCollision("lobby")
// Send platform
var b1 packets.GameDataSubpacket = &gamedata.ClientInfoC2S{
ClientID: proc.sus.state.CurrentGame.ClientID,
PlatformID: enum.PLATFORM_LinuxPlayer,
}
var b2 protocol.HazelPayload = packets.NewGameDataSingleSubpacket(proc.sus.state.CurrentGame.GameID, &b1)
net.SendReliablePacket(net.GetNonce(), []*protocol.Hazel{protocol.NewHazelFromPayload(&b2)})
// Send scene change
var c1 packets.GameDataSubpacket = &gamedata.SceneChangeC2H{
ClientID: proc.sus.state.CurrentGame.ClientID,
SceneName: "OnlineGame",
}
var c2 protocol.HazelPayload = packets.NewGameDataSingleSubpacket(proc.sus.state.CurrentGame.GameID, &c1)
net.SendReliablePacket(net.GetNonce(), []*protocol.Hazel{protocol.NewHazelFromPayload(&c2)})
}
func (proc *PacketProcessor) captureAlterGame(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.AlterGameH2G{}
a.Read(h.GetUnderlyingPacket())
fmt.Printf("Alter game: %v\n", a.GameID)
fmt.Printf("Tag ID: %v\n", a.TagID)
fmt.Printf("Tag value: %v\n", a.TagValue)
if a.GameID == proc.sus.state.CurrentGame.GameID && a.TagID == 1 {
proc.sus.state.CurrentGame.GamePrivacy = a.TagValue
}
}
func (proc *PacketProcessor) captureRedirect(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.RedirectS2C{}
a.Read(h.GetUnderlyingPacket())
fmt.Printf("Redirect: %v:%v", a.IPAddress.String(), a.Port)
if proc.sus.networkHandler != nil {
proc.sus.networkHandler.SendNormalDisconnectPacket()
proc.sus.networkHandler.Close()
proc.sus.networkHandler = nil
}
proc.sus.setupPacketHandler(&a.IPAddress, int(a.Port), func(ph *protocol.PacketHandler) {
fmt.Println("Sending first packet to new server")
ph.SendHelloPacket(ph.GetNonce(), 0, proc.sus.state.Version, proc.sus.state.Settings.PlayerName, 0, proc.sus.state.Settings.Language, proc.sus.state.Settings.QuickChatMode)
y, _ := util.CodeToGameID(proc.sus.state.TypedGameID)
var z protocol.HazelPayload = &packets.JoinGameC2S{GameID: y}
ph.SendReliablePacket(ph.GetNonce(), []*protocol.Hazel{
protocol.NewHazelFromPayload(&z),
})
})
}
func (proc *PacketProcessor) captureRemovePlayer(net *protocol.PacketHandler, nonce uint16, h *protocol.Hazel) {
a := &packets.RemovePlayerS2G{}
a.Read(h.GetUnderlyingPacket())
if proc.sus.state.CurrentGame != nil {
if a.GameID == proc.sus.state.CurrentGame.GameID && a.HostClientID == proc.sus.state.CurrentGame.ClientID {
fmt.Println("Host player disconnected and left me in charge")
fmt.Println("I can't host a game so I'm disconnecting too")
net.SendNormalDisconnectPacket()
}
}
}