From b39cacef6d953cf0a50062a7ace1cc9d176744bb Mon Sep 17 00:00:00 2001 From: MrMelon Date: Sat, 25 Jun 2022 11:59:37 +0100 Subject: [PATCH] Final commit --- gamedataprocessor.go | 4 +- go.mod | 2 + packetprocessor.go | 19 +++-- renderer.go | 3 +- src/enum/hat.go | 119 ---------------------------- src/enum/pet.go | 16 ---- src/enum/platform.go | 31 +++----- src/enum/playeroutfittype.go | 8 ++ src/enum/roletypes.go | 10 +++ src/enum/rpccall.go | 20 ++++- src/enum/skin.go | 23 ------ src/gamedata/02_rpc.go | 103 ++++++++++++++---------- src/gamedata/21_setactivepodtype.go | 16 ++++ src/gamedata/go.mod | 2 + src/packets/01_joingameC2S.go | 5 +- src/protocol/gameoptionsdata.go | 46 ++++++++++- src/protocol/go.mod | 4 +- src/protocol/go.sum | 2 + src/protocol/packet.go | 2 +- src/protocol/playerdata.go | 72 +++++++++-------- src/protocol/playeroutfit.go | 67 ++++++++++++++++ src/protocol/roleoptionsdata.go | 66 +++++++++++++++ src/protocol/taskinfo.go | 15 ++++ state.go | 6 +- sus.go | 10 ++- 25 files changed, 394 insertions(+), 277 deletions(-) delete mode 100644 src/enum/hat.go delete mode 100644 src/enum/pet.go create mode 100644 src/enum/playeroutfittype.go create mode 100644 src/enum/roletypes.go delete mode 100644 src/enum/skin.go create mode 100644 src/gamedata/21_setactivepodtype.go create mode 100644 src/protocol/go.sum create mode 100644 src/protocol/playeroutfit.go create mode 100644 src/protocol/roleoptionsdata.go create mode 100644 src/protocol/taskinfo.go diff --git a/gamedataprocessor.go b/gamedataprocessor.go index e4b7ffe..f673b58 100644 --- a/gamedataprocessor.go +++ b/gamedataprocessor.go @@ -126,14 +126,14 @@ func (proc *GameDataProcessor) captureGameSpawn(net *protocol.PacketHandler, Gam // Send RPC CheckName proc.sus.state.CurrentGame.CheckNameNonce = net.GetNonce() var d1 gamedata.RpcSub = &gamedata.RpcCheckName{Name: proc.sus.state.Settings.PlayerName} - var d2 packets.GameDataSubpacket = gamedata.NewRpcFromRpcSub(proc.sus.state.CurrentGame.ClientPlayerNetID, &d1) + var d2 packets.GameDataSubpacket = gamedata.NewRpcFromRpcSub(proc.sus.state.CurrentGame.ClientPlayerNetID, d1) var d3 protocol.HazelPayload = packets.NewGameDataToSingleSubpacket(proc.sus.state.CurrentGame.GameID, proc.sus.state.CurrentGame.HostClientID, &d2) net.SendReliablePacket(proc.sus.state.CurrentGame.CheckNameNonce, []*protocol.Hazel{protocol.NewHazelFromPayload(&d3)}) // Send RPC CheckColor proc.sus.state.CurrentGame.CheckColorNonce = net.GetNonce() var e1 gamedata.RpcSub = &gamedata.RpcCheckColor{Color: proc.sus.state.Settings.PlayerColor} - var e2 packets.GameDataSubpacket = gamedata.NewRpcFromRpcSub(proc.sus.state.CurrentGame.ClientPlayerNetID, &e1) + var e2 packets.GameDataSubpacket = gamedata.NewRpcFromRpcSub(proc.sus.state.CurrentGame.ClientPlayerNetID, e1) var e3 protocol.HazelPayload = packets.NewGameDataToSingleSubpacket(proc.sus.state.CurrentGame.GameID, proc.sus.state.CurrentGame.HostClientID, &e2) net.SendReliablePacket(proc.sus.state.CurrentGame.CheckColorNonce, []*protocol.Hazel{protocol.NewHazelFromPayload(&e3)}) } diff --git a/go.mod b/go.mod index eba5a8e..99c03c8 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ replace ( tea.melonie54.xyz/sean/go-susapp/src/protocol => ./src/protocol tea.melonie54.xyz/sean/go-susapp/src/systemtypes => ./src/systemtypes tea.melonie54.xyz/sean/go-susapp/src/util => ./src/util + tea.melonie54.xyz/sean/go-susapp/src/version => ./src/version ) require ( @@ -24,6 +25,7 @@ require ( tea.melonie54.xyz/sean/go-susapp/src/packets v0.0.0-20211216203152-cbba9006e452 tea.melonie54.xyz/sean/go-susapp/src/protocol v0.0.0 tea.melonie54.xyz/sean/go-susapp/src/util v0.0.0 + tea.melonie54.xyz/sean/go-susapp/src/version v0.0.0-20211217150321-0ba6d712d37d ) require tea.melonie54.xyz/sean/go-susapp/src/systemtypes v0.0.0 // indirect diff --git a/packetprocessor.go b/packetprocessor.go index 0475c1b..6573cdb 100644 --- a/packetprocessor.go +++ b/packetprocessor.go @@ -124,7 +124,7 @@ func (proc *PacketProcessor) captureUnreliableGameDataTo(net *protocol.PacketHan 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("Joined game: %v\n", util.CodeFromGameID(a.GameID)) fmt.Printf("Client id: %v\n", a.JoinedClientID) fmt.Printf("Host client id: %v\n", a.HostClientID) proc.sus.state.CurrentGame = &CurrentGameData{ @@ -142,11 +142,8 @@ func (proc *PacketProcessor) captureJoinedGame(net *protocol.PacketHandler, nonc 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, - } + // Send active pod type + var b1 packets.GameDataSubpacket = &gamedata.SetActivePodType{PodType: "mira"} // TODO: don't hard code this var b2 protocol.HazelPayload = packets.NewGameDataSingleSubpacket(proc.sus.state.CurrentGame.GameID, &b1) net.SendReliablePacket(net.GetNonce(), []*protocol.Hazel{protocol.NewHazelFromPayload(&b2)}) @@ -157,12 +154,20 @@ func (proc *PacketProcessor) captureJoinedGame(net *protocol.PacketHandler, nonc } var c2 protocol.HazelPayload = packets.NewGameDataSingleSubpacket(proc.sus.state.CurrentGame.GameID, &c1) net.SendReliablePacket(net.GetNonce(), []*protocol.Hazel{protocol.NewHazelFromPayload(&c2)}) + + var d1 packets.GameDataSubpacket = gamedata.NewRpcFromRpcSubs(proc.sus.state.CurrentGame.HostClientID, []gamedata.RpcSub{ + &gamedata.RpcSetHat{HatID: "hat_pk04_Bear"}, + &gamedata.RpcSetPet{PetID: "pet_Robot"}, + &gamedata.RpcSetSkin{SkinID: "skin_Winter"}, + }) + var d2 protocol.HazelPayload = packets.NewGameDataSingleSubpacket(proc.sus.state.CurrentGame.GameID, &d1) + net.SendReliablePacket(net.GetNonce(), []*protocol.Hazel{protocol.NewHazelFromPayload(&d2)}) } 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("Alter game: %v\n", util.CodeFromGameID(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 { diff --git a/renderer.go b/renderer.go index c2ee4fc..172089d 100644 --- a/renderer.go +++ b/renderer.go @@ -4,7 +4,6 @@ import ( "fmt" "math" "strconv" - "tea.melonie54.xyz/sean/go-susapp/src/version" "time" "tea.melonie54.xyz/sean/go-susapp/src/enum" @@ -41,7 +40,7 @@ func (r *Renderer) Draw(da *gtk.DrawingArea, cr *cairo.Context) { r.w = float64(allocation.GetWidth()) r.h = float64(allocation.GetHeight()) - versionText := version.GetVersionFormatted(r.state.Version) + versionText := r.state.Version.Formatted() // Background r.DrawFilledRectangle(0, 0, r.w, r.h, 0x14181c) diff --git a/src/enum/hat.go b/src/enum/hat.go deleted file mode 100644 index c414a2f..0000000 --- a/src/enum/hat.go +++ /dev/null @@ -1,119 +0,0 @@ -package enum - -const ( - HAT_NONE = 0 - HAT_ASTRONAUT = 1 - HAT_BASEBALL_CAP = 2 - HAT_BRAIN_SLUG = 3 - HAT_BUSH_HAT = 4 - HAT_CAPTAIN_HAT = 5 - HAT_DOUBLE_TOP_HAT = 6 - HAT_FLOWERPOT = 7 - HAT_GOGGLES = 8 - HAT_HARD_HAT = 9 - HAT_MILITARY_HAT = 10 - HAT_PAPER_HAT = 11 - HAT_PARTY_HAT = 12 - HAT_POLICE_HAT = 13 - HAT_STETHOSCOPE = 14 - HAT_TOP_HAT = 15 - HAT_TOWEL_WIZARD = 16 - HAT_USHANKA = 17 - HAT_VIKING = 18 - HAT_WALL_GUARD_CAP = 19 - HAT_SNOWMAN = 20 - HAT_REINDEER_ANTLERS = 21 - HAT_CHRISTMAS_LIGHTS = 22 - HAT_SANTA_HAT = 23 - HAT_CHRISTMAS_TREE = 24 - HAT_CHRISTMAS_PRESENT = 25 - HAT_CANDY_CANES = 26 - HAT_ELF_HAT = 27 - HAT_NEW_YEARS_2018 = 28 - HAT_WHITE_HAT = 29 - HAT_CROWN = 30 - HAT_EYEBROWS = 31 - HAT_HALO = 32 - HAT_HERO_CAP = 33 - HAT_PIP_CAP = 34 - HAT_PLUNGER = 35 - HAT_SCUBA_MASK = 36 - HAT_HENRY_STICKMIN = 37 - HAT_STRAW_HAT = 38 - HAT_TEN_GALLON_HAT = 39 - HAT_THIRD_EYE = 40 - HAT_TOILET_PAPER = 41 - HAT_TOPPAT_CLAN_LEADER = 42 - HAT_BLACK_FEDORA = 43 - HAT_SKI_GOGGLES = 44 - HAT_HEARING_PROTECTION = 45 - HAT_HAZMAT_MASK = 46 - HAT_FACE_MASK = 47 - HAT_MIRA_SECURITY_CAP = 48 - HAT_SAFARI_HAT = 49 - HAT_BANANA = 50 - HAT_BEANIE = 51 - HAT_BEAR_EARS = 52 - HAT_CHEESE = 53 - HAT_CHERRY = 54 - HAT_EGG = 55 - HAT_GREEN_FEDORA = 56 - HAT_FLAMINGO = 57 - HAT_FLOWER_PIN = 58 - HAT_KNIGHT_HELMET = 59 - HAT_PLANT = 60 - HAT_BAT_EYES = 61 - HAT_BAT_WINGS = 62 - HAT_HORNS = 63 - HAT_MOHAWK = 64 - HAT_PUMPKIN = 65 - HAT_SCARY_PAPER_BAG = 66 - HAT_WITCH_HAT = 67 - HAT_WOLF_EARS = 68 - HAT_PIRATE_HAT = 69 - HAT_PLAGUE_DOCTOR = 70 - HAT_MACHETE = 71 - HAT_HOCKEY_MASK = 72 - HAT_MINER_HELMET = 73 - HAT_WINTER_CAP = 74 - HAT_ARCHAEOLOGIST_HAT = 75 - HAT_ANTENNA = 76 - HAT_BALLOON = 77 - HAT_BIRD_NEST = 78 - HAT_BLACK_BELT = 79 - HAT_CAUTION_SIGN = 80 - HAT_CHEF_HAT = 81 - HAT_COP_HAT = 82 - HAT_DO_RAG = 83 - HAT_DUM_STICKER = 84 - HAT_FEZ = 85 - HAT_GENERAL_HAT = 86 - HAT_POMPADOUR_HAIR = 87 - HAT_HUNTER_HAT = 88 - HAT_JUNGLE_HAT = 89 - HAT_MINI_CREWMATE = 90 - HAT_NINJA_MASK = 91 - HAT_RAM_HORNS = 92 - HAT_MINI_CREWMATE_SNOWMAN = 93 - HAT_GEOFF_KEIGHLEY_MASK = 94 - HAT_DAVE_PANPA_CAP = 95 - HAT_ELLIE_ROSE_HAIR = 96 - HAT_SVEN_SVENSSON_HAT = 97 - HAT_BURT_CURTIS_HAT = 98 - HAT_ELLRY_MOHAWK = 99 - HAT_THOMAS_CHESTERSHIRE_MONOCLES = 100 - HAT_WIZARD_HAT = 101 - HAT_FREDRICK_MUENSTER_HAT = 102 - HAT_MR_MACBETH_HAT = 103 - HAT_TOPPAT_HENRY_STICKMIN_HAT = 104 - HAT_TOPPAT_ELLIE_ROSE_HAT = 105 - HAT_GEOFFREY_PLUMB_HAT = 106 - HAT_ANGRY_EYEBROWS = 107 - HAT_CHOCOLATE_ICE_CREAM = 108 - HAT_HEART_PIN = 109 - HAT_PONYTAIL = 110 - HAT_RUBBER_GLOVE = 111 - HAT_UNICORN_HORN = 112 - HAT_ZIPPER = 113 - HAT_RIGHT_HAND_MAN_HAT = 114 -) diff --git a/src/enum/pet.go b/src/enum/pet.go deleted file mode 100644 index fa4d806..0000000 --- a/src/enum/pet.go +++ /dev/null @@ -1,16 +0,0 @@ -package enum - -const ( - PET_NONE = 0 - PET_ALIEN = 1 - PET_MINI_CREWMATE = 2 - PET_DOG = 3 - PET_HENRY_STICKMIN = 4 - PET_HAMSTER = 5 - PET_ROBOT = 6 - PET_UFO = 7 - PET_ELLIE_ROSE = 8 - PET_SQUIG = 9 - PET_BEDCRAB = 10 - PET_GLITCH = 11 -) diff --git a/src/enum/platform.go b/src/enum/platform.go index 67cf797..a41a4e3 100644 --- a/src/enum/platform.go +++ b/src/enum/platform.go @@ -1,24 +1,15 @@ package enum const ( - PLATFORM_OSXEditor = 0 - PLATFORM_OSXPlayer = 1 - PLATFORM_WindowsPlayer = 2 - PLATFORM_WindowsEditor = 7 - PLATFORM_IPhonePlayer = 8 - PLATFORM_Android = 11 - PLATFORM_LinuxPlayer = 13 - PLATFORM_LinuxEditor = 16 - PLATFORM_WebGLPlayer = 17 - PLATFORM_WSAPlayerX86 = 18 - PLATFORM_WSAPlayerX64 = 19 - PLATFORM_WSAPlayerARM = 20 - PLATFORM_PS4 = 25 - PLATFORM_XboxOne = 27 - PLATFORM_tvOS = 31 - PLATFORM_Switch = 32 - PLATFORM_Lumin = 33 - PLATFORM_Stadia = 34 - PLATFORM_CloudRendering = 35 - PLATFORM_PS5 = 36 + PLATFORM_UNKNOWN = 0 + PLATFORM_STANDALONE_EPIC_PC = 1 + PLATFORM_STANDALONE_STEAM_PC = 1 + PLATFORM_STANDALONE_MAC = 3 + PLATFORM_STANDALONE_WIN10 = 4 + PLATFORM_STANDALONE_ITCH = 5 + PLATFORM_IPHONE = 6 + PLATFORM_ANDROID = 7 + PLATFORM_SWITCH = 8 + PLATFORM_XBOX = 9 + PLATFORM_PLAYSTATION = 10 ) diff --git a/src/enum/playeroutfittype.go b/src/enum/playeroutfittype.go new file mode 100644 index 0000000..0b032cb --- /dev/null +++ b/src/enum/playeroutfittype.go @@ -0,0 +1,8 @@ +package enum + +const ( + PLAYER_OUTFIT_TYPE_DEFAULT = 0 + PLAYER_OUTFIT_TYPE_SHAPESHIFTED = 1 +) + +type PlayerOutfitType byte diff --git a/src/enum/roletypes.go b/src/enum/roletypes.go new file mode 100644 index 0000000..e50969c --- /dev/null +++ b/src/enum/roletypes.go @@ -0,0 +1,10 @@ +package enum + +const ( + ROLE_TYPES_CREWMATE = 0 + ROLE_TYPES_IMPOSTOR = 1 + ROLE_TYPES_SCIENTIST = 2 + ROLE_TYPES_ENGINEER = 3 + ROLE_TYPES_GUARDIAN_ANGEL = 4 + ROLE_TYPES_SHAPESHIFTER = 5 +) diff --git a/src/enum/rpccall.go b/src/enum/rpccall.go index 13c02ef..d0ddbef 100644 --- a/src/enum/rpccall.go +++ b/src/enum/rpccall.go @@ -10,15 +10,15 @@ const ( RPC_SET_NAME = 0x06 RPC_CHECK_COLOR = 0x07 RPC_SET_COLOR = 0x08 - RPC_SET_HAT = 0x09 - RPC_SET_SKIN = 0x0a + RPC_OLD_SET_HAT = 0x09 + RPC_OLD_SET_SKIN = 0x0a RPC_REPORT_DEAD_BODY = 0x0b RPC_MURDER_PLAYER = 0x0c RPC_SEND_CHAT = 0x0d RPC_START_MEETING = 0x0e RPC_SET_SCANNER = 0x0f RPC_SEND_CHAT_NOTE = 0x10 - RPC_SET_PET = 0x11 + RPC_OLD_SET_PET = 0x11 RPC_SET_START_COUNTER = 0x12 RPC_ENTER_VENT = 0x13 RPC_EXIT_VENT = 0x14 @@ -33,4 +33,18 @@ const ( RPC_SET_TASKS = 0x1d RPC_CLIMB_LADDER = 0x1f RPC_USE_PLATFORM = 0x20 + RPC_SEND_QUICK_CHAT = 0x21 + RPC_BOOT_FROM_VENT = 0x22 + RPC_UPDATE_SYSTEM = 0x23 + RPC_SET_LEVEL = 0x26 + RPC_SET_HAT = 0x27 + RPC_SET_SKIN = 0x28 + RPC_SET_PET = 0x29 + RPC_SET_VISOR = 0x2a + RPC_SET_NAMEPLATE = 0x2b + RPC_SET_ROLE = 0x2c + RPC_PROTECT_PLAYER = 0x2d + RPC_SHAPESHIFT = 0x2e + RPC_CHECK_MURDER = 0x2f + RPC_CHECK_PROTECT = 0x30 ) diff --git a/src/enum/skin.go b/src/enum/skin.go deleted file mode 100644 index 2d4e89f..0000000 --- a/src/enum/skin.go +++ /dev/null @@ -1,23 +0,0 @@ -package enum - -const ( - SKIN_NONE = 0 - SKIN_ASTRONAUT = 1 - SKIN_CAPTAIN = 2 - SKIN_MECHANIC = 3 - SKIN_MILITARY = 4 - SKIN_POLICE = 5 - SKIN_SCIENTIST = 6 - SKIN_SUIT_BLACK = 7 - SKIN_SUIT_WHITE = 8 - SKIN_WALL_GUARD = 9 - SKIN_HAZMAT = 10 - SKIN_SECURITY_GUARD = 11 - SKIN_TARMAC = 12 - SKIN_MINER = 13 - SKIN_WINTER = 14 - SKIN_ARCHAEOLOGIST = 15 - SKIN_PRISONER = 16 - SKIN_CCC = 17 - SKIN_RIGHT_HAND_MAN_REBORN = 18 -) diff --git a/src/gamedata/02_rpc.go b/src/gamedata/02_rpc.go index 4db3bfd..2ca59f7 100644 --- a/src/gamedata/02_rpc.go +++ b/src/gamedata/02_rpc.go @@ -12,24 +12,25 @@ import ( type Rpc struct { SenderNetID uint32 - RPCCallID byte - Sub *RpcSub + Subs []RpcSub UnderlyingHazel *protocol.Hazel } func NewRpcFromHazel(h *protocol.Hazel) *Rpc { a := &Rpc{} a.SenderNetID = h.GetUnderlyingPacket().ReadPackedUInt32() - a.RPCCallID = h.GetUnderlyingPacket().Read() a.UnderlyingHazel = h return a } -func NewRpcFromRpcSub(senderNetID uint32, sub *RpcSub) *Rpc { +func NewRpcFromRpcSub(senderNetID uint32, sub RpcSub) *Rpc { + return NewRpcFromRpcSubs(senderNetID, []RpcSub{sub}) +} + +func NewRpcFromRpcSubs(senderNetID uint32, subs []RpcSub) *Rpc { return &Rpc{ SenderNetID: senderNetID, - RPCCallID: (*sub).CallCode(), - Sub: sub, + Subs: subs, } } @@ -45,13 +46,24 @@ func (d *Rpc) AsHazel() *protocol.Hazel { func (d *Rpc) TypeCode() byte { return 0x02 } func (d *Rpc) Write(packet *protocol.Packet) { packet.WritePackedUInt32(d.SenderNetID) - packet.Write(d.RPCCallID) - (*d.Sub).WriteToPacket(packet) + for i := range d.Subs { + packet.Write(d.Subs[i].CallCode()) + d.Subs[i].WriteToPacket(packet) + } } func (d *Rpc) Read(packet *protocol.Packet) { d.SenderNetID = packet.ReadPackedUInt32() - d.RPCCallID = packet.Read() - // TODO: finish this + for packet.Remaining() > 0 { + k := packet.Read() + var v RpcSub + switch k { + case 0x00: + v = &RpcPlayAnimation{} + } + if v != nil { + v.ReadFromPacket(packet) + } + } } type RpcSub interface { @@ -166,26 +178,6 @@ func (d *RpcSetColor) CallCode() byte { return enum.RPC_ func (d *RpcSetColor) WriteToPacket(packet *protocol.Packet) { packet.Write(d.Color) } func (d *RpcSetColor) ReadFromPacket(packet *protocol.Packet) { d.Color = packet.Read() } -// -// 0x09 RpcSetHat -// - -type RpcSetHat struct{ HatID uint32 } - -func (d *RpcSetHat) CallCode() byte { return enum.RPC_SET_HAT } -func (d *RpcSetHat) WriteToPacket(packet *protocol.Packet) { packet.WritePackedUInt32(d.HatID) } -func (d *RpcSetHat) ReadFromPacket(packet *protocol.Packet) { d.HatID = packet.ReadPackedUInt32() } - -// -// 0x0a RpcSetSkin -// - -type RpcSetSkin struct{ SkinID uint32 } - -func (d *RpcSetSkin) CallCode() byte { return enum.RPC_SET_SKIN } -func (d *RpcSetSkin) WriteToPacket(packet *protocol.Packet) { packet.WritePackedUInt32(d.SkinID) } -func (d *RpcSetSkin) ReadFromPacket(packet *protocol.Packet) { d.SkinID = packet.ReadPackedUInt32() } - // // 0x0b RpcReportDeadBody // @@ -270,16 +262,6 @@ func (d *RpcSendChatNote) ReadFromPacket(packet *protocol.Packet) { d.ChatNoteType = packet.Read() } -// -// 0x11 RpcSetPet -// - -type RpcSetPet struct{ PetID uint32 } - -func (d *RpcSetPet) CallCode() byte { return enum.RPC_SET_PET } -func (d *RpcSetPet) WriteToPacket(packet *protocol.Packet) { packet.WritePackedUInt32(d.PetID) } -func (d *RpcSetPet) ReadFromPacket(packet *protocol.Packet) { d.PetID = packet.ReadPackedUInt32() } - // // 0x12 RpcSetStartCounter // @@ -499,3 +481,44 @@ type RpcUsePlatform struct{} func (d *RpcUsePlatform) CallCode() byte { return enum.RPC_CLIMB_LADDER } func (d *RpcUsePlatform) WriteToPacket(packet *protocol.Packet) {} func (d *RpcUsePlatform) ReadFromPacket(packet *protocol.Packet) {} + +// +// 0x27 RpcSetHat +// + +type RpcSetHat struct{ HatID string } + +func (d *RpcSetHat) CallCode() byte { return enum.RPC_SET_HAT } +func (d *RpcSetHat) WriteToPacket(packet *protocol.Packet) { packet.WriteString(d.HatID) } +func (d *RpcSetHat) ReadFromPacket(packet *protocol.Packet) { d.HatID = packet.ReadString() } + +// +// 0x28 RpcSetSkin +// + +type RpcSetSkin struct{ SkinID string } + +func (d *RpcSetSkin) CallCode() byte { return enum.RPC_SET_SKIN } +func (d *RpcSetSkin) WriteToPacket(packet *protocol.Packet) { packet.WriteString(d.SkinID) } +func (d *RpcSetSkin) ReadFromPacket(packet *protocol.Packet) { d.SkinID = packet.ReadString() } + +// +// 0x29 RpcSetPet +// + +type RpcSetPet struct{ PetID string } + +func (d *RpcSetPet) CallCode() byte { return enum.RPC_SET_PET } +func (d *RpcSetPet) WriteToPacket(packet *protocol.Packet) { packet.WriteString(d.PetID) } +func (d *RpcSetPet) ReadFromPacket(packet *protocol.Packet) { d.PetID = packet.ReadString() } + +// +// 0x2c RpcSetRole + +type RpcSetRole struct{ RoleType protocol.RoleTypes } + +func (d *RpcSetRole) CallCode() byte { return enum.RPC_SET_ROLE } +func (d *RpcSetRole) WriteToPacket(packet *protocol.Packet) { packet.Write(byte(d.RoleType)) } +func (d *RpcSetRole) ReadFromPacket(packet *protocol.Packet) { + d.RoleType = protocol.RoleTypes(packet.Read()) +} diff --git a/src/gamedata/21_setactivepodtype.go b/src/gamedata/21_setactivepodtype.go new file mode 100644 index 0000000..a8318c6 --- /dev/null +++ b/src/gamedata/21_setactivepodtype.go @@ -0,0 +1,16 @@ +package gamedata + +import "tea.melonie54.xyz/sean/go-susapp/src/protocol" + +type SetActivePodType struct { + PodType string +} + +func (d *SetActivePodType) AsHazel() *protocol.Hazel { + var a protocol.HazelPayload = d + return protocol.NewHazelFromPayload(&a) +} + +func (d *SetActivePodType) TypeCode() byte { return 0x15 } +func (d *SetActivePodType) Write(packet *protocol.Packet) { packet.WriteString(d.PodType) } +func (d *SetActivePodType) Read(packet *protocol.Packet) { d.PodType = packet.ReadString() } diff --git a/src/gamedata/go.mod b/src/gamedata/go.mod index d27f42a..e34a1a0 100644 --- a/src/gamedata/go.mod +++ b/src/gamedata/go.mod @@ -5,9 +5,11 @@ go 1.17 replace ( tea.melonie54.xyz/sean/go-susapp/src/protocol => ../protocol tea.melonie54.xyz/sean/go-susapp/src/util => ../util + tea.melonie54.xyz/sean/go-susapp/src/enum => ../enum ) require ( tea.melonie54.xyz/sean/go-susapp/src/protocol v0.0.0 tea.melonie54.xyz/sean/go-susapp/src/util v0.0.0 + tea.melonie54.xyz/sean/go-susapp/src/enum v0.0.0 ) diff --git a/src/packets/01_joingameC2S.go b/src/packets/01_joingameC2S.go index d80db8b..5159ddb 100644 --- a/src/packets/01_joingameC2S.go +++ b/src/packets/01_joingameC2S.go @@ -3,7 +3,8 @@ package packets import "tea.melonie54.xyz/sean/go-susapp/src/protocol" type JoinGameC2S struct { - GameID int32 + GameID int32 + Crossplay bool } func (d *JoinGameC2S) TypeCode() byte { @@ -12,8 +13,10 @@ func (d *JoinGameC2S) TypeCode() byte { func (d *JoinGameC2S) Write(packet *protocol.Packet) { packet.WriteInt32(d.GameID) + packet.WriteBool(d.Crossplay) } func (d *JoinGameC2S) Read(packet *protocol.Packet) { d.GameID = packet.ReadInt32() + d.Crossplay = packet.ReadBool() } diff --git a/src/protocol/gameoptionsdata.go b/src/protocol/gameoptionsdata.go index 7e4675f..0390801 100644 --- a/src/protocol/gameoptionsdata.go +++ b/src/protocol/gameoptionsdata.go @@ -23,16 +23,51 @@ type GameOptionsData struct { VisualTasks bool AnonymousVotes bool TaskBarUpdates byte + RoleOptions *RoleOptionsData } -var currentGameOptionsVersion byte = 4 +var currentGameOptionsVersion byte = 5 -// Create new default options +// NewDefaultGameOptionsData Create new default options func NewDefaultGameOptionsData() *GameOptionsData { - return &GameOptionsData{currentGameOptionsVersion, 10, 1, 1, 1, 1, 1.5, 45, 1, 1, 2, 1, 1, 1, 15, 120, true, 15, true, true, false, 0} + return &GameOptionsData{ + Version: currentGameOptionsVersion, + MaxNumberOfPlayers: 10, + Keywords: 1, + Maps: 1, + PlayerSpeedModifier: 1, + CrewmateLightModifier: 1, + ImpostorLightModifier: 1.5, + KillCooldown: 45, + NumberOfCommonTasks: 1, + NumberOfLongTasks: 1, + NumberOfShortTasks: 2, + NumberOfEmergencyMeetings: 1, + NumberOfImpostors: 1, + KillDistance: 1, + DiscussionTime: 15, + VotingTime: 120, + IsDefaults: true, + EmergencyCooldown: 15, + ConfirmEjects: true, + VisualTasks: true, + RoleOptions: &RoleOptionsData{ + ShapeshifterLeaveSkin: false, + ShapeshifterCooldown: 10, + ShapeshifterDuration: 30, + ScientistCooldown: 15, + ScientistBatteryCharge: 5, + GuardianAngelCooldown: 60, + ImpostorsCanSeeProtect: false, + ProtectionDurationSeconds: 10, + EngineerCooldown: 30, + EngineerInVentMaxTime: 15, + RoleRates: make(map[RoleTypes]*RoleRate), + }, + } } -// Create new options from packet data +// NewGameOptionsDataFromPacket Create new options from packet data func NewGameOptionsDataFromPacket(packet *Packet) *GameOptionsData { a := NewDefaultGameOptionsData() a.Read(packet) @@ -63,6 +98,7 @@ func (data *GameOptionsData) Write(packet *Packet) { p.WriteBool(data.VisualTasks) p.WriteBool(data.AnonymousVotes) p.Write(data.TaskBarUpdates) + data.RoleOptions.Write(p) packet.WritePackedUInt32(uint32(p.Size())) p.Copy(packet) } @@ -93,4 +129,6 @@ func (data *GameOptionsData) Read(packet *Packet) { data.VisualTasks = p.ReadBoolDefault(true) data.AnonymousVotes = p.ReadBoolDefault(false) data.TaskBarUpdates = p.ReadDefault(0) + data.RoleOptions = &RoleOptionsData{} + data.RoleOptions.Read(p) } diff --git a/src/protocol/go.mod b/src/protocol/go.mod index cd224a0..0b81a0f 100644 --- a/src/protocol/go.mod +++ b/src/protocol/go.mod @@ -5,9 +5,11 @@ go 1.17 replace ( tea.melonie54.xyz/sean/go-susapp/src/util => ../util tea.melonie54.xyz/sean/go-susapp/src/version => ../version + tea.melonie54.xyz/sean/go-susapp/src/enum => ../enum ) require ( + tea.melonie54.xyz/sean/go-susapp/src/enum v0.0.0-20211217150321-0ba6d712d37d tea.melonie54.xyz/sean/go-susapp/src/util v0.0.0 - tea.melonie54.xyz/sean/go-susapp/src/version v0.0.0 + tea.melonie54.xyz/sean/go-susapp/src/version v0.0.0-20211217150321-0ba6d712d37d ) diff --git a/src/protocol/go.sum b/src/protocol/go.sum new file mode 100644 index 0000000..a3ecba6 --- /dev/null +++ b/src/protocol/go.sum @@ -0,0 +1,2 @@ +tea.melonie54.xyz/sean/go-susapp/src/enum v0.0.0-20211217150321-0ba6d712d37d h1:JfR7qgdhTWjw7nZM4ITT/CfO3djE1p4/qAHtxiuhhxc= +tea.melonie54.xyz/sean/go-susapp/src/enum v0.0.0-20211217150321-0ba6d712d37d/go.mod h1:Jh+hf9VCNIGF2UbEh91R8ROF65KW1wLslRv2d+5iH1w= diff --git a/src/protocol/packet.go b/src/protocol/packet.go index bcc8acd..a06dc92 100644 --- a/src/protocol/packet.go +++ b/src/protocol/packet.go @@ -153,7 +153,7 @@ func (packet *Packet) WriteBool(v bool) { } } -func (packet *Packet) ParsePackedInt32() int32 { +func (packet *Packet) ReadPackedInt32() int32 { return int32(packet.ReadPackedUInt32()) } diff --git a/src/protocol/playerdata.go b/src/protocol/playerdata.go index d59c28a..b4f0a0c 100644 --- a/src/protocol/playerdata.go +++ b/src/protocol/playerdata.go @@ -1,53 +1,63 @@ package protocol +import "tea.melonie54.xyz/sean/go-susapp/src/enum" + type PlayerData struct { - PlayerID byte - Name string - ColorID uint32 - HatID uint32 - PetID uint32 - SkinID uint32 - Flags byte - Tasks []*TaskInfo + PlayerID byte + Name string + Flags byte + Tasks []*TaskInfo + Outfits map[enum.PlayerOutfitType]*PlayerOutfit + CurrentOutfitType enum.PlayerOutfitType + PlayerLevel uint32 + Role RoleTypes +} + +func (player *PlayerData) PlayerOutfit() *PlayerOutfit { + return player.Outfits[player.CurrentOutfitType] } func (player *PlayerData) Write(packet *Packet) { packet.Write(player.PlayerID) - packet.WriteString(player.Name) - packet.WritePackedUInt32(player.ColorID) - packet.WritePackedUInt32(player.HatID) - packet.WritePackedUInt32(player.PetID) - packet.WritePackedUInt32(player.SkinID) + packet.Write(byte(len(player.Outfits))) + for outfitType, outfit := range player.Outfits { + packet.Write(byte(outfitType)) + outfit.Write(packet) + } + packet.WritePackedUInt32(player.PlayerLevel) packet.Write(player.Flags) + packet.WriteUInt16(uint16(player.Role)) packet.Write(byte(len(player.Tasks))) for i := 0; i < len(player.Tasks); i++ { player.Tasks[i].Write(packet) } } + func (player *PlayerData) Read(packet *Packet) { player.PlayerID = packet.Read() - player.Name = packet.ReadString() - player.ColorID = packet.ReadPackedUInt32() - player.HatID = packet.ReadPackedUInt32() - player.PetID = packet.ReadPackedUInt32() - player.SkinID = packet.ReadPackedUInt32() + player.Outfits = make(map[enum.PlayerOutfitType]*PlayerOutfit) + n := packet.Read() + for i := 0; i < int(n); i++ { + key := enum.PlayerOutfitType(packet.Read()) + player.Outfits[key] = &PlayerOutfit{} + player.Outfits[key].Read(packet) + } + + player.PlayerLevel = packet.ReadPackedUInt32() player.Flags = packet.Read() - player.Tasks = make([]*TaskInfo, packet.Read()) - for i := 0; i < len(player.Tasks); i++ { - player.Tasks[i].Read(packet) + taskCount := packet.Read() + if taskCount != byte(len(player.Tasks)) { + player.Tasks = make([]*TaskInfo, taskCount) + for i := 0; i < len(player.Tasks); i++ { + player.Tasks[i].Read(packet) + } } } -type TaskInfo struct { - TaskID uint32 - IsCompleted bool +func (player *PlayerData) IsImpostor() bool { + return player.Role == enum.ROLE_TYPES_IMPOSTOR || player.Role == enum.ROLE_TYPES_SHAPESHIFTER } -func (task *TaskInfo) Write(packet *Packet) { - packet.WritePackedUInt32(task.TaskID) - packet.WriteBool(task.IsCompleted) -} -func (task *TaskInfo) Read(packet *Packet) { - task.TaskID = packet.ReadPackedUInt32() - task.IsCompleted = packet.ReadBool() +func (player *PlayerData) CanVent() bool { + return player.Role == enum.ROLE_TYPES_IMPOSTOR || player.Role == enum.ROLE_TYPES_ENGINEER } diff --git a/src/protocol/playeroutfit.go b/src/protocol/playeroutfit.go new file mode 100644 index 0000000..3cf8442 --- /dev/null +++ b/src/protocol/playeroutfit.go @@ -0,0 +1,67 @@ +package protocol + +type PlayerOutfit struct { + Color int + HatId string + PetId string + SkinId string + VisorId string + NamePlateId string + PlayerName string +} + +func NewPlayerOutfit() *PlayerOutfit { + return &PlayerOutfit{ + Color: -1, + HatId: "missing", + PetId: "missing", + SkinId: "missing", + VisorId: "missing", + NamePlateId: "missing", + PlayerName: "", + } +} + +func (outfit *PlayerOutfit) IsIncomplete() bool { + if outfit.PlayerName == "" { + return true + } + if outfit.Color == -1 { + return true + } + if outfit.HatId == "missing" { + return true + } + if outfit.PetId == "missing" { + return true + } + if outfit.SkinId == "missing" { + return true + } + if outfit.VisorId == "missing" { + return true + } + if outfit.NamePlateId == "missing" { + return true + } + return false +} + +func (outfit *PlayerOutfit) Write(packet *Packet) { + packet.WriteString(outfit.PlayerName) + packet.WritePackedInt32(int32(outfit.Color)) + packet.WriteString(outfit.HatId) + packet.WriteString(outfit.PetId) + packet.WriteString(outfit.SkinId) + packet.WriteString(outfit.VisorId) + packet.WriteString(outfit.NamePlateId) +} +func (outfit *PlayerOutfit) Read(packet *Packet) { + outfit.PlayerName = packet.ReadString() + outfit.Color = int(packet.ReadPackedInt32()) + outfit.HatId = packet.ReadString() + outfit.PetId = packet.ReadString() + outfit.SkinId = packet.ReadString() + outfit.VisorId = packet.ReadString() + outfit.NamePlateId = packet.ReadString() +} diff --git a/src/protocol/roleoptionsdata.go b/src/protocol/roleoptionsdata.go new file mode 100644 index 0000000..db0e6c2 --- /dev/null +++ b/src/protocol/roleoptionsdata.go @@ -0,0 +1,66 @@ +package protocol + +type RoleTypes byte + +type RoleRate struct { + MaxCount byte + Chance byte +} + +type RoleOptionsData struct { + ShapeshifterLeaveSkin bool + ShapeshifterCooldown byte + ShapeshifterDuration byte + ScientistCooldown byte + ScientistBatteryCharge byte + GuardianAngelCooldown byte + ImpostorsCanSeeProtect bool + ProtectionDurationSeconds byte + EngineerCooldown byte + EngineerInVentMaxTime byte + RoleRates map[RoleTypes]*RoleRate +} + +func (options *RoleOptionsData) Write(packet *Packet) { + packet.WritePackedInt32(int32(len(options.RoleRates))) + for k, v := range options.RoleRates { + packet.Write(byte(k)) + packet.Write(v.MaxCount) + packet.Write(v.Chance) + } + + packet.WriteBool(options.ShapeshifterLeaveSkin) + packet.Write(options.ShapeshifterCooldown) + packet.Write(options.ShapeshifterDuration) + packet.Write(options.ScientistCooldown) + packet.Write(options.GuardianAngelCooldown) + packet.Write(options.EngineerCooldown) + packet.Write(options.EngineerInVentMaxTime) + packet.Write(options.ScientistBatteryCharge) + packet.Write(options.ProtectionDurationSeconds) + packet.WriteBool(options.ImpostorsCanSeeProtect) +} + +func (options *RoleOptionsData) Read(packet *Packet) { + options.RoleRates = make(map[RoleTypes]*RoleRate) + n := packet.ReadInt32() + for i := 0; i < int(n); i++ { + key := packet.ReadInt16() + val := &RoleRate{ + MaxCount: packet.Read(), + Chance: packet.Read(), + } + options.RoleRates[RoleTypes(key)] = val + } + + options.ShapeshifterLeaveSkin = packet.ReadBool() + options.ShapeshifterCooldown = packet.Read() + options.ShapeshifterDuration = packet.Read() + options.ScientistCooldown = packet.Read() + options.GuardianAngelCooldown = packet.Read() + options.EngineerCooldown = packet.Read() + options.EngineerInVentMaxTime = packet.Read() + options.ScientistBatteryCharge = packet.Read() + options.ProtectionDurationSeconds = packet.Read() + options.ImpostorsCanSeeProtect = packet.ReadBool() +} diff --git a/src/protocol/taskinfo.go b/src/protocol/taskinfo.go new file mode 100644 index 0000000..aea77e3 --- /dev/null +++ b/src/protocol/taskinfo.go @@ -0,0 +1,15 @@ +package protocol + +type TaskInfo struct { + TaskID uint32 + IsCompleted bool +} + +func (task *TaskInfo) Write(packet *Packet) { + packet.WritePackedUInt32(task.TaskID) + packet.WriteBool(task.IsCompleted) +} +func (task *TaskInfo) Read(packet *Packet) { + task.TaskID = packet.ReadPackedUInt32() + task.IsCompleted = packet.ReadBool() +} diff --git a/state.go b/state.go index 8e84f61..f39c054 100644 --- a/state.go +++ b/state.go @@ -68,9 +68,9 @@ type PlayerObject struct { PlayerNetworkTransform uint32 PlayerName string PlayerColor byte - PlayerPet uint32 - PlayerHat uint32 - PlayerSkin uint32 + PlayerPet string + PlayerHat string + PlayerSkin string InVent bool IsImpostor bool } diff --git a/sus.go b/sus.go index e6241ac..fd6ffe1 100644 --- a/sus.go +++ b/sus.go @@ -132,7 +132,9 @@ func (sus *SusApp) startApp() { r := sus.renderer da.Connect("draw", func(da *gtk.DrawingArea, cr *cairo.Context) { - r.Draw(da, cr) + if r != nil && da != nil && cr != nil { + r.Draw(da, cr) + } }) da.AddEvents(int(gdk.KEY_RELEASE_MASK) | int(gdk.KEY_PRESS_MASK) | int(gdk.EVENT_CONFIGURE) | int(gdk.EVENT_BUTTON_PRESS)) @@ -283,11 +285,11 @@ func (sus *SusApp) handlePingPacket(net *protocol.PacketHandler, nonce uint16) { func (sus *SusApp) sendPetHatAndSkin(net *protocol.PacketHandler) { // Send RPC SetPet, SetHat, SetSkin sus.state.CurrentGame.CheckPetHatAndSkinNonce = net.GetNonce() - var f1a gamedata.RpcSub = &gamedata.RpcSetPet{PetID: enum.PET_ELLIE_ROSE + 1} + var f1a gamedata.RpcSub = &gamedata.RpcSetPet{PetID: "pet_Robot"} var f2a packets.GameDataSubpacket = gamedata.NewRpcFromRpcSub(sus.state.CurrentGame.ClientPlayerNetID, &f1a) - var f1b gamedata.RpcSub = &gamedata.RpcSetHat{HatID: enum.HAT_HEART_PIN + 1} + var f1b gamedata.RpcSub = &gamedata.RpcSetHat{HatID: "hat_pk04_Bear"} var f2b packets.GameDataSubpacket = gamedata.NewRpcFromRpcSub(sus.state.CurrentGame.ClientPlayerNetID, &f1b) - var f1c gamedata.RpcSub = &gamedata.RpcSetSkin{SkinID: enum.SKIN_RIGHT_HAND_MAN_REBORN} + var f1c gamedata.RpcSub = &gamedata.RpcSetSkin{SkinID: "skin_Winter"} var f2c packets.GameDataSubpacket = gamedata.NewRpcFromRpcSub(sus.state.CurrentGame.ClientPlayerNetID, &f1c) var f3 protocol.HazelPayload = &packets.GameDataAll{GameID: sus.state.CurrentGame.GameID, Subpackets: []*protocol.Hazel{ f2a.AsHazel(),