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){ 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) 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, OtherClientIDs: make([]uint32, len(a.OtherClientIDs)), 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{} for j := 0; j < len(a.OtherClientIDs); j++ { proc.sus.state.CurrentGame.OtherClientIDs[j] = a.OtherClientIDs[j] } proc.sus.state.Screen = enum.SCREEN_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 a.GameID == proc.sus.state.CurrentGame.GameID && a.HostClientID == proc.sus.state.CurrentGame.ClientID { fmt.Println("Host player disconnect and left me in charge") fmt.Println("I can't host a game so I'm disconnecting too") net.SendNormalDisconnectPacket() } }