First commit

This commit is contained in:
Melon 2021-09-12 00:25:10 +01:00
commit 4ec1b9bdb7
126 changed files with 5145 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
dist/
package/

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
Copyright 2020 Sean
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

26
Makefile Normal file
View File

@ -0,0 +1,26 @@
all:
make build-main
build-main:
mkdir -p dist/ && go build -o dist/susapp .
package:
./scripts/package-susapp.sh
deb:
make clean && \
make all && \
make package
clean:
rm -rf dist/ && \
rm -rf package/
.PHONY: run
run:
make && \
cd ./dist/ && \
./susapp

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

157
gamedataprocessor.go Normal file
View File

@ -0,0 +1,157 @@
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/mapdata"
"codehub.onpointcoding.net/sean/go-susapp/packets"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type GameDataProcessor struct {
sus *SusApp
gameRpcProcessor *GameRPCProcessor
subpacketTagMap map[byte]func(net *protocol.PacketHandler, GameID int32, h *protocol.Hazel)
}
func NewGameDataProcessor(sus *SusApp) *GameDataProcessor {
proc := &GameDataProcessor{sus: sus, gameRpcProcessor: NewGameRPCProcessor(sus)}
proc.subpacketTagMap = map[byte]func(net *protocol.PacketHandler, GameID int32, h *protocol.Hazel){
0x01: proc.captureGameData,
0x02: proc.captureGameRPC,
0x04: proc.captureGameSpawn,
0x05: proc.captureGameDespawn,
}
return proc
}
func (proc *GameDataProcessor) receiveGameDataSubpacket(net *protocol.PacketHandler, GameID int32, h []*protocol.Hazel) {
for i := 0; i < len(h); i++ {
v, ok := proc.subpacketTagMap[h[i].GetTag()]
if ok {
v(net, GameID, h[i])
} else {
fmt.Printf("Unable to parse gamedata subpackets with tag of %x\n", h[i].GetTag())
fmt.Printf("Packet: %v\n", hex.EncodeToString(h[i].GetUnderlyingPacket().Dump()))
}
}
}
func (proc *GameDataProcessor) captureGameData(net *protocol.PacketHandler, GameID int32, h *protocol.Hazel) {
a := &gamedata.DataH2G{}
a.Read(h.GetUnderlyingPacket())
netId := a.Component.NetID
if netId != 0 {
b, ok := proc.sus.state.CurrentGame.NetObjects[netId]
if ok {
(*b).Read(a.Component.RawData, false)
}
}
}
func (proc *GameDataProcessor) captureGameRPC(net *protocol.PacketHandler, GameID int32, h *protocol.Hazel) {
proc.gameRpcProcessor.receiveGameRpcCall(net, GameID, gamedata.NewRpcFromHazel(h))
}
func (proc *GameDataProcessor) captureGameSpawn(net *protocol.PacketHandler, GameID int32, h *protocol.Hazel) {
a := &gamedata.SpawnH2G{}
a.Read(h.GetUnderlyingPacket())
if len(a.Components) >= 1 {
z := a.Components[0]
netId := z.NetID
switch a.SpawnType {
case enum.SPAWNTYPE_GAME_DATA:
b := &innernetobjects.GameData{}
b.Read(z.ComponentData.GetUnderlyingPacket(), true)
var c innernetobjects.InnerNetObject = b
proc.sus.state.CurrentGame.NetObjects[netId] = &c
proc.sus.state.CurrentGame.GameDataNetID = netId
fmt.Printf("GameData Net ID: %v\n", netId)
case enum.SPAWNTYPE_SKELD_SHIP_STATUS:
b := innernetobjects.NewSkeldShipStatus()
b.Read(z.ComponentData.GetUnderlyingPacket(), true)
var c innernetobjects.InnerNetObject = b
proc.sus.state.CurrentGame.NetObjects[netId] = &c
proc.sus.state.CurrentGame.MapNetObjectNetID = netId
fmt.Printf("SkeldShipStatus Net ID: %v\n", netId)
case enum.SPAWNTYPE_MIRA_SHIP_STATUS:
b := innernetobjects.NewMiraShipStatus()
b.Read(z.ComponentData.GetUnderlyingPacket(), true)
var c innernetobjects.InnerNetObject = b
proc.sus.state.CurrentGame.NetObjects[netId] = &c
proc.sus.state.CurrentGame.MapNetObjectNetID = netId
fmt.Printf("MiraShipStatus Net ID: %v\n", netId)
case enum.SPAWNTYPE_POLUS_SHIP_STATUS:
b := innernetobjects.NewPolusShipStatus()
b.Read(z.ComponentData.GetUnderlyingPacket(), true)
var c innernetobjects.InnerNetObject = b
proc.sus.state.CurrentGame.NetObjects[netId] = &c
proc.sus.state.CurrentGame.MapNetObjectNetID = netId
fmt.Printf("PolusShipStatus Net ID: %v\n", netId)
case enum.SPAWNTYPE_PLAYER_CONTROL:
b := &innernetobjects.PlayerControl{}
b.Read(z.ComponentData.GetUnderlyingPacket(), true)
var c innernetobjects.InnerNetObject = b
proc.sus.state.CurrentGame.NetObjects[netId] = &c
y := &PlayerObject{}
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID[netId] = y
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerClientID[a.OwnerID] = y
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerClientID[a.OwnerID].PlayerClientNetID = netId
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerClientID[a.OwnerID].PlayerControllerNetID = netId
fmt.Printf("Player Net ID: %v\n", netId)
fmt.Printf("Player Owner ID: %v\n", a.OwnerID)
isMyPlayer := a.OwnerID == proc.sus.state.CurrentGame.ClientID
if isMyPlayer {
fmt.Println("Owner ID matches current Client ID so its my player controller")
proc.sus.state.CurrentGame.ClientPlayerNetID = z.NetID
// 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 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 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)})
}
if len(a.Components) >= 2 {
y := a.Components[1].NetID
d := innernetobjects.PlayerPhysics{}
d.Read(a.Components[1].ComponentData.GetUnderlyingPacket(), true)
var e innernetobjects.InnerNetObject = &d
proc.sus.state.CurrentGame.NetObjects[y] = &e
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerClientID[a.OwnerID].PlayerPhysicsNetID = y
}
if len(a.Components) >= 3 {
y := a.Components[2].NetID
d := innernetobjects.PlayerNetworkTransform{}
d.Read(a.Components[2].ComponentData.GetUnderlyingPacket(), true)
var e innernetobjects.InnerNetObject = &d
proc.sus.state.CurrentGame.NetObjects[y] = &e
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerClientID[a.OwnerID].PlayerNetworkTransform = y
if isMyPlayer {
d.TargetPosition = mapdata.LobbySpawnPositions[int(b.PlayerID)%len(mapdata.LobbySpawnPositions)]
proc.sus.movementProcessor.Tick(0)
}
}
}
}
}
func (proc *GameDataProcessor) captureGameDespawn(net *protocol.PacketHandler, GameID int32, h *protocol.Hazel) {
}

101
gamerpcprocessor.go Normal file
View File

@ -0,0 +1,101 @@
package main
import (
"encoding/hex"
"fmt"
"codehub.onpointcoding.net/sean/go-susapp/gamedata"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type GameRPCProcessor struct {
sus *SusApp
rpcCallMap map[byte]func(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc)
}
func NewGameRPCProcessor(sus *SusApp) *GameRPCProcessor {
proc := &GameRPCProcessor{sus: sus}
proc.rpcCallMap = map[byte]func(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc){
0x00: proc.captureRpcPlayAnimation,
0x02: proc.captureRpcSyncSettings,
0x03: proc.captureRpcSetInfected,
0x04: proc.captureRpcExiled,
0x06: proc.captureRpcSetName,
0x08: proc.captureRpcSetColor,
0x09: proc.captureRpcSetHat,
0x0a: proc.captureRpcSetSkin,
0x11: proc.captureRpcSetPet,
0x12: proc.captureRpcSetStartCounter,
}
return proc
}
func (proc *GameRPCProcessor) receiveGameRpcCall(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
v, ok := proc.rpcCallMap[rpc.RPCCallID]
if ok {
v(net, GameID, rpc)
} else {
fmt.Printf("Unable to parse gamedata rpc call with id of %x\n", rpc.RPCCallID)
fmt.Printf("Packet: %v\n", hex.EncodeToString(rpc.UnderlyingHazel.GetUnderlyingPacket().Dump()))
}
}
func (proc *GameRPCProcessor) captureRpcPlayAnimation(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
}
func (proc *GameRPCProcessor) captureRpcSyncSettings(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
a := &gamedata.RpcSyncSettings{}
a.ReadFromPacket(rpc.UnderlyingHazel.GetUnderlyingPacket())
if a.Options.IsDefaults {
proc.sus.state.CurrentGame.GameOptions = protocol.NewDefaultGameOptionsData()
} else {
proc.sus.state.CurrentGame.GameOptions = a.Options
}
}
func (proc *GameRPCProcessor) captureRpcSetInfected(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
}
func (proc *GameRPCProcessor) captureRpcExiled(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
}
func (proc *GameRPCProcessor) captureRpcSetName(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
a := &gamedata.RpcSetName{}
a.ReadFromPacket(rpc.UnderlyingHazel.GetUnderlyingPacket())
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID[rpc.SenderNetID].PlayerName = a.Name
}
func (proc *GameRPCProcessor) captureRpcSetColor(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
a := &gamedata.RpcSetColor{}
a.ReadFromPacket(rpc.UnderlyingHazel.GetUnderlyingPacket())
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID[rpc.SenderNetID].PlayerColor = a.Color
}
func (proc *GameRPCProcessor) captureRpcSetHat(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
a := &gamedata.RpcSetHat{}
a.ReadFromPacket(rpc.UnderlyingHazel.GetUnderlyingPacket())
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID[rpc.SenderNetID].PlayerHat = a.HatID
}
func (proc *GameRPCProcessor) captureRpcSetSkin(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
a := &gamedata.RpcSetSkin{}
a.ReadFromPacket(rpc.UnderlyingHazel.GetUnderlyingPacket())
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID[rpc.SenderNetID].PlayerSkin = a.SkinID
}
func (proc *GameRPCProcessor) captureRpcSetPet(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
a := &gamedata.RpcSetPet{}
a.ReadFromPacket(rpc.UnderlyingHazel.GetUnderlyingPacket())
proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID[rpc.SenderNetID].PlayerPet = a.PetID
}
func (proc *GameRPCProcessor) captureRpcSetStartCounter(net *protocol.PacketHandler, GameID int32, rpc *gamedata.Rpc) {
a := &gamedata.RpcSetStartCounter{}
a.ReadFromPacket(rpc.UnderlyingHazel.GetUnderlyingPacket())
if proc.sus.state.CurrentGame != nil {
proc.sus.state.CurrentGame.StartGameTimer = a.TimeRemaining
}
}

26
go.mod Normal file
View File

@ -0,0 +1,26 @@
module codehub.onpointcoding.net/sean/go-susapp
go 1.17
replace (
codehub.onpointcoding.net/sean/go-susapp/enum => ./src/enum
codehub.onpointcoding.net/sean/go-susapp/gamedata => ./src/gamedata
codehub.onpointcoding.net/sean/go-susapp/innernetobjects => ./src/innernetobjects
codehub.onpointcoding.net/sean/go-susapp/mapdata => ./src/mapdata
codehub.onpointcoding.net/sean/go-susapp/packets => ./src/packets
codehub.onpointcoding.net/sean/go-susapp/protocol => ./src/protocol
codehub.onpointcoding.net/sean/go-susapp/systemtypes => ./src/systemtypes
codehub.onpointcoding.net/sean/go-susapp/util => ./src/util
)
require (
codehub.onpointcoding.net/sean/go-susapp/enum v1.0.0
codehub.onpointcoding.net/sean/go-susapp/gamedata v0.0.0-00010101000000-000000000000
codehub.onpointcoding.net/sean/go-susapp/innernetobjects v0.0.0-00010101000000-000000000000
codehub.onpointcoding.net/sean/go-susapp/packets v0.0.0-00010101000000-000000000000
codehub.onpointcoding.net/sean/go-susapp/protocol v1.0.0
codehub.onpointcoding.net/sean/go-susapp/systemtypes v1.0.0 // indirect
codehub.onpointcoding.net/sean/go-susapp/util v1.0.0
codehub.onpointcoding.net/sean/go-susapp/mapdata v1.0.0
github.com/gotk3/gotk3 v0.6.1
)

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/gotk3/gotk3 v0.6.1 h1:GJ400a0ecEEWrzjBvzBzH+pB/esEMIGdB9zPSmBdoeo=
github.com/gotk3/gotk3 v0.6.1/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=

80
keyhandler.go Normal file
View File

@ -0,0 +1,80 @@
package main
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
)
type KeyInputHandler struct {
state *State
}
func NewKeyInputHandler(state *State) *KeyInputHandler {
return &KeyInputHandler{state}
}
func (input *KeyInputHandler) keyPressEvent(win *gtk.ApplicationWindow, ev *gdk.Event) {
keyEvent := gdk.EventKeyNewFromEvent(ev)
k := gdk.KeyvalToUpper(keyEvent.KeyVal())
if input.state.Screen == enum.SCREEN_TITLE && input.state.IsTypingReady {
if k >= gdk.KEY_A && k <= gdk.KEY_Z {
input.state.TypedGameID = input.state.TypedGameID + string(gdk.KeyvalToUnicode(k))
} else if k == gdk.KEY_BackSpace {
if len(input.state.TypedGameID) > 0 {
input.state.TypedGameID = input.state.TypedGameID[:len(input.state.TypedGameID)-1]
}
}
} else if input.state.Screen == enum.SCREEN_LOBBY {
if k == gdk.KEY_W {
input.state.HoldingUp = true
}
if k == gdk.KEY_A {
input.state.HoldingLeft = true
}
if k == gdk.KEY_S {
input.state.HoldingDown = true
}
if k == gdk.KEY_D {
input.state.HoldingRight = true
}
input.updateMovementDirections()
}
}
func (input *KeyInputHandler) keyReleaseEvent(win *gtk.ApplicationWindow, ev *gdk.Event) {
keyEvent := gdk.EventKeyNewFromEvent(ev)
k := gdk.KeyvalToUpper(keyEvent.KeyVal())
if input.state.Screen == enum.SCREEN_LOBBY {
if k == gdk.KEY_W {
input.state.HoldingUp = false
}
if k == gdk.KEY_A {
input.state.HoldingLeft = false
}
if k == gdk.KEY_S {
input.state.HoldingDown = false
}
if k == gdk.KEY_D {
input.state.HoldingRight = false
}
input.updateMovementDirections()
}
}
func (input *KeyInputHandler) updateMovementDirections() {
input.state.MovementX = 0
input.state.MovementY = 0
if input.state.HoldingUp {
input.state.MovementY--
}
if input.state.HoldingLeft {
input.state.MovementX--
}
if input.state.HoldingDown {
input.state.MovementY++
}
if input.state.HoldingRight {
input.state.MovementX++
}
}

79
mousehandler.go Normal file
View File

@ -0,0 +1,79 @@
package main
import (
"time"
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/util"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
)
type MouseInputHandler struct {
state *State
renderer *Renderer
playGame func()
openSettings func()
disconnectFromGame func()
prevTime int64
}
func NewMouseInputHandler(state *State, renderer *Renderer, playGame func(), openSettings func(), disconnectFromGame func()) *MouseInputHandler {
return &MouseInputHandler{state, renderer, playGame, openSettings, disconnectFromGame, time.Now().UnixMilli()}
}
/*func (input *MouseInputHandler) pollingEvent(delta int64) {
}*/
func (input *MouseInputHandler) motionEvent(da *gtk.DrawingArea, event *gdk.Event) bool {
eventMotion := gdk.EventMotionNewFromEvent(event)
input.renderer.mouseX, input.renderer.mouseY = eventMotion.MotionVal()
return false
}
func (input *MouseInputHandler) buttonPressEvent(window *gtk.ApplicationWindow, ev *gdk.Event) bool {
btn := gdk.EventButtonNewFromEvent(ev)
switch btn.Button() {
case gdk.BUTTON_PRIMARY:
w := input.renderer.w
h := input.renderer.h
if input.state.Screen == enum.SCREEN_TITLE {
if util.CollisionIntersectCenter(input.renderer.mouseX, input.renderer.mouseY, w/2, h/2, 200, 40) {
input.playGame()
} else if util.CollisionIntersectCenter(input.renderer.mouseX, input.renderer.mouseY, w-40, h-40, 40, 40) {
input.openSettings()
} else {
if util.CollisionIntersectCenter(input.renderer.mouseX, input.renderer.mouseY, w/2, h/2-60, 200, 40) {
input.state.IsTypingReady = true
} else {
input.state.IsTypingReady = false
}
}
} else if input.state.Screen == enum.SCREEN_LOBBY {
if input.state.IsLobbyMenuOpen {
mw := w / 2
mh := h / 2
overlayBottom := mh + 200
if util.CollisionIntersectCenter(input.renderer.mouseX, input.renderer.mouseY, mw, overlayBottom-40, 200, 40) {
input.state.IsLobbyMenuOpen = false
} else if util.CollisionIntersectCenter(input.renderer.mouseX, input.renderer.mouseY, mw, overlayBottom-100, 200, 40) {
input.disconnectFromGame()
}
} else {
if util.CollisionIntersectCenter(input.renderer.mouseX, input.renderer.mouseY, w-40, 40, 40, 40) {
input.state.IsLobbyMenuOpen = true
}
}
} else if input.state.Screen == enum.SCREEN_ERROR {
mw := w / 2
mh := h / 2
if util.CollisionIntersectCenter(input.renderer.mouseX, input.renderer.mouseY, mw+190, mh-190, 40, 40) {
input.state.Screen = enum.SCREEN_TITLE
input.state.IsLobbyMenuOpen = false
}
}
return true
}
return false
}

41
movementprocessor.go Normal file
View File

@ -0,0 +1,41 @@
package main
import (
"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"
)
type MovementProcessor struct {
sus *SusApp
}
func (proc *MovementProcessor) Tick(delta int64) {
if proc.sus.state.CurrentGame != nil && proc.sus.networkHandler != nil {
p := protocol.NewEmptyPacket()
cp, ok := proc.sus.state.CurrentGame.PlayerNetObjects.ByPlayerNetID[proc.sus.state.CurrentGame.ClientPlayerNetID]
if ok {
netId := cp.PlayerNetworkTransform
var c0 innernetobjects.InnerNetObject = *proc.sus.state.CurrentGame.NetObjects[netId]
a, ok := c0.(*innernetobjects.PlayerNetworkTransform)
if ok {
a.LastSequenceID++
prevVelocityZero := a.TargetVelocity.X == 0 && a.TargetVelocity.Y == 0
a.TargetVelocity.X = enum.PLAYER_SPEED * proc.sus.state.CurrentGame.GameOptions.PlayerSpeedModifier * proc.sus.state.MovementX / 2
a.TargetVelocity.Y = enum.PLAYER_SPEED * proc.sus.state.CurrentGame.GameOptions.PlayerSpeedModifier * proc.sus.state.MovementY / 2
nextVelocityZero := a.TargetVelocity.X == 0 && a.TargetVelocity.Y == 0
if !nextVelocityZero || prevVelocityZero != nextVelocityZero {
a.TargetPosition.X += a.TargetVelocity.X * (float32(delta) / 1000)
a.TargetPosition.Y -= a.TargetVelocity.Y * (float32(delta) / 1000)
c0.Write(p, false)
var c1 protocol.UpdateComponent = protocol.UpdateComponent{NetID: netId, RawData: p}
var c2 packets.GameDataSubpacket = &gamedata.DataH2G{Component: &c1}
var c3 protocol.HazelPayload = packets.NewGameDataSingleSubpacket(proc.sus.state.CurrentGame.GameID, &c2)
proc.sus.networkHandler.SendNormalPacket([]*protocol.Hazel{protocol.NewHazelFromPayload(&c3)})
}
}
}
}
}

172
packetprocessor.go Normal file
View File

@ -0,0 +1,172 @@
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()
}
}

9
project.json Normal file
View File

@ -0,0 +1,9 @@
{
"Package": "melonapp",
"Version": "1.0-0",
"Section": "base",
"Priority": "optional",
"Architecture": "amd64",
"Maintainer": "MrMelon54 <github@onpointcoding.net>",
"Description": "Melon App"
}

273
renderer.go Normal file
View File

@ -0,0 +1,273 @@
package main
import (
"math"
"strconv"
"time"
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/innernetobjects"
"codehub.onpointcoding.net/sean/go-susapp/util"
"github.com/gotk3/gotk3/cairo"
"github.com/gotk3/gotk3/gtk"
"github.com/gotk3/gotk3/pango"
)
type Renderer struct {
state *State
da *gtk.DrawingArea
cr *cairo.Context
w float64
h float64
mouseX float64
mouseY float64
delta int64
}
var defaultRenderFont string = "Noto Sans"
func NewRenderer(state *State) *Renderer {
return &Renderer{state: state}
}
func (r *Renderer) Draw(da *gtk.DrawingArea, cr *cairo.Context) {
r.delta = time.Now().UnixMilli()
r.da = da
r.cr = cr
allocation := da.GetAllocation()
r.w = float64(allocation.GetWidth())
r.h = float64(allocation.GetHeight())
versionText := GetVersionFormatted(r.state.Version)
// Background
r.DrawFilledRectangle(0, 0, r.w, r.h, 0x14181c)
// Version numbers
r.DrawText(10, 10, versionText, "Noto Sans Display", 16, 0xffffff)
if r.state.Screen == enum.SCREEN_TITLE {
colorLen := enum.GetPlayerTotalColors()
for i := 0; i < colorLen; i++ {
r.DrawFilledRectangle(float64(i)*20+(r.w-float64(colorLen)-float64(colorLen*20))/2, 0, 20, 20, enum.GetPlayerMainColor(i))
r.DrawFilledRectangle(float64(i)*20+(r.w-float64(colorLen)-float64(colorLen*20))/2, 20, 20, 20, enum.GetPlayerShadedColor(i))
}
r.DrawButton(r.w-120, 20, 100, 40, r.state.Settings.PlayerName, defaultRenderFont, 16)
r.DrawButton(r.w-120, 60, 100, 40, r.state.Settings.ServerAddress, defaultRenderFont, 16)
r.DrawButton(r.w-120, 100, 100, 40, strconv.FormatInt(r.state.Settings.ServerPort, 10), defaultRenderFont, 16)
r.DrawTextInput((r.w-200)/2, (r.h-20)/2-60, 200, 40, r.state.TypedGameID, defaultRenderFont, 16, r.state.IsTypingReady)
r.DrawButton((r.w-200)/2, (r.h-20)/2, 200, 40, "Play", defaultRenderFont, 16)
r.DrawButton(r.w-60, r.h-60, 40, 40, "⚙", defaultRenderFont, 16)
} else if r.state.Screen == enum.SCREEN_WAITING {
mw := r.w / 2
mh := r.h / 2
a := float64(r.delta/10) * (math.Pi / 180)
b := a + math.Pi/2
c := a + math.Pi
d := a + math.Pi*3/2
r.DrawFilledRoundedRectangle(mw+50*math.Sin(a)-20, mh+50*math.Cos(a)-20, 40, 40, 1, 20, 0xffffff)
r.DrawFilledRoundedRectangle(mw+50*math.Sin(b)-20, mh+50*math.Cos(b)-20, 40, 40, 1, 20, 0xffffff)
r.DrawFilledRoundedRectangle(mw+50*math.Sin(c)-20, mh+50*math.Cos(c)-20, 40, 40, 1, 20, 0xffffff)
r.DrawFilledRoundedRectangle(mw+50*math.Sin(d)-20, mh+50*math.Cos(d)-20, 40, 40, 1, 20, 0xffffff)
} else if r.state.Screen == enum.SCREEN_LOBBY {
r.DrawButton((r.w-100)/2, r.h-60, 100, 40, util.CodeFromGameID(r.state.CurrentGame.GameID), defaultRenderFont, 16)
r.DrawButton(r.w-60, 20, 40, 40, "⚙", defaultRenderFont, 16)
if r.state.CurrentGame.GamePrivacy == 1 {
r.DrawButton((r.w-100)/2+120, r.h-60, 100, 40, "Public", defaultRenderFont, 16)
} else if r.state.CurrentGame.GamePrivacy == 0 {
r.DrawButton((r.w-100)/2+120, r.h-60, 100, 40, "Private", defaultRenderFont, 16)
}
r.DrawPlayers()
if r.state.IsLobbyMenuOpen {
mw := r.w / 2
mh := r.h / 2
overlayBottom := mh + 200
r.DrawFilledRectangle(0, 0, r.w, r.h, 0x80000000)
r.DrawFilledRoundedRectangle(mw-200, mh-200, 400, 400, 1, 20, 0x000000)
r.DrawButton((r.w-200)/2, overlayBottom-60, 200, 40, "Return to Game", defaultRenderFont, 16)
r.DrawButton((r.w-200)/2, overlayBottom-120, 200, 40, "Leave Game", defaultRenderFont, 16)
}
} else if r.state.Screen == enum.SCREEN_ERROR {
mw := r.w / 2
mh := r.h / 2
r.DrawFilledRoundedRectangle(mw-200, mh-200, 400, 400, 1, 20, 0x000000)
r.DrawText(mw-190, mh-190, "Disconnected", defaultRenderFont, 16, 0xffffff)
r.DrawButton(mw+170, mh-210, 40, 40, "×", defaultRenderFont, 16)
if r.state.DisconnectReason == 0xfe {
r.DrawWrappedText(mw-190, mh-156, 380, r.state.DisconnectStringReason, defaultRenderFont, 16, 0xffffff)
} else {
r.DrawWrappedText(mw-190, mh-156, 380, enum.DisconnectMessageText(r.state.DisconnectReason), defaultRenderFont, 16, 0xffffff)
}
}
}
func (r *Renderer) SetRGB(red int, green int, blue int, alpha int) {
r.cr.SetSourceRGBA(float64(red)/0xff, float64(green)/0xff, float64(blue)/0xff, 0xff/float64(alpha))
}
func (r *Renderer) SetHex(hex int) {
r.SetRGB((hex/(256*256))%256, (hex/256)%256, hex%256, (hex/(256*256*256))%256)
}
func (r *Renderer) DrawRectangle(x float64, y float64, w float64, h float64, color int) {
r.SetHex(color)
r.cr.Rectangle(x, y, w, h)
r.cr.Stroke()
}
func (r *Renderer) DrawFilledRectangle(x float64, y float64, w float64, h float64, color int) {
r.SetHex(color)
r.cr.Rectangle(x, y, w, h)
r.cr.Fill()
}
func (r *Renderer) DrawBorderedRectangle(x float64, y float64, w float64, h float64, color int, border int) {
r.DrawFilledRectangle(x, y, w, h, color)
r.DrawRectangle(x, y, w, h, border)
}
func (r *Renderer) DrawRoundedRectangle(x float64, y float64, w float64, h float64, aspect float64, corner_radius float64, color int) {
a := corner_radius / aspect
d := math.Pi / 180
r.cr.NewPath()
r.cr.Arc(x+w-a, y+a, a, -90*d, 0*d)
r.cr.Arc(x+w-a, y+h-a, a, 0*d, 90*d)
r.cr.Arc(x+a, y+h-a, a, 90*d, 180*d)
r.cr.Arc(x+a, y+a, a, 180*d, 270*d)
r.cr.ClosePath()
r.SetHex(color)
r.cr.Stroke()
}
func (r *Renderer) DrawFilledRoundedRectangle(x float64, y float64, w float64, h float64, aspect float64, corner_radius float64, color int) {
a := corner_radius / aspect
d := math.Pi / 180
r.cr.NewPath()
r.cr.Arc(x+w-a, y+a, a, -90*d, 0*d)
r.cr.Arc(x+w-a, y+h-a, a, 0*d, 90*d)
r.cr.Arc(x+a, y+h-a, a, 90*d, 180*d)
r.cr.Arc(x+a, y+a, a, 180*d, 270*d)
r.cr.ClosePath()
r.SetHex(color)
r.cr.FillPreserve()
}
func (r *Renderer) DrawBorderedRoundedRectangle(x float64, y float64, w float64, h float64, aspect float64, corner_radius float64, color int, border int) {
a := corner_radius / aspect
d := math.Pi / 180
r.cr.NewPath()
r.cr.Arc(x+w-a, y+a, a, -90*d, 0*d)
r.cr.Arc(x+w-a, y+h-a, a, 0*d, 90*d)
r.cr.Arc(x+a, y+h-a, a, 90*d, 180*d)
r.cr.Arc(x+a, y+a, a, 180*d, 270*d)
r.cr.ClosePath()
r.SetHex(color)
r.cr.FillPreserve()
r.SetHex(border)
r.cr.Stroke()
}
func (r *Renderer) DrawText(x float64, y float64, text string, fontFamily string, fontSize float64, color int) {
layout := pango.CairoCreateLayout(r.cr)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
r.SetHex(color)
r.cr.MoveTo(x, y)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
}
func (r *Renderer) DrawWrappedText(x float64, y float64, w float64, text string, fontFamily string, fontSize float64, color int) {
layout := pango.CairoCreateLayout(r.cr)
layout.SetWidth(int(w) * pango.SCALE)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
r.SetHex(color)
r.cr.MoveTo(x, y)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
}
func (r *Renderer) DrawButton(x float64, y float64, w float64, h float64, text string, fontFamily string, fontSize float64) {
r.DrawFilledRoundedRectangle(x, y, w-4, h-4, w/h, 10, 0x000000)
if r.mouseX > x && r.mouseX < x+w && r.mouseY > y && r.mouseY < y+h {
r.DrawRoundedRectangle(x, y, w-4, h-4, w/h, 10, 0x00ff00)
} else {
r.DrawRoundedRectangle(x, y, w-4, h-4, w/h, 10, 0xffffff)
}
layout := pango.CairoCreateLayout(r.cr)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
textWidth, textHeight := layout.GetSize()
textWidth /= pango.SCALE
textHeight /= pango.SCALE
r.SetHex(0xffffff)
r.cr.MoveTo(x+(w-4-float64(textWidth))/2, y+(h-4-float64(textHeight))/2)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
}
func (r *Renderer) DrawTextInput(x float64, y float64, w float64, h float64, text string, fontFamily string, fontSize float64, inFocus bool) {
if r.mouseX > x && r.mouseX < x+w && r.mouseY > y && r.mouseY < y+h {
r.DrawFilledRectangle(x, y+h-6, w-4, 2, 0x00ffff)
} else {
r.DrawFilledRectangle(x, y+h-6, w-4, 2, 0xffffff)
}
layout := pango.CairoCreateLayout(r.cr)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
textWidth, textHeight := layout.GetSize()
textWidth /= pango.SCALE
textHeight /= pango.SCALE
r.SetHex(0xffffff)
r.cr.MoveTo(x+(w-float64(textWidth))/2, y+(h-12-float64(textHeight))/2)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
if inFocus && r.delta%1600 < 800 {
r.DrawFilledRectangle(x+(w+float64(textWidth))/2, y+4, 2, 20, 0xffffff)
}
}
func (r *Renderer) DrawPlayers() {
for _, item := range r.state.CurrentGame.PlayerNetObjects.ByPlayerClientID {
var t innernetobjects.InnerNetObject = *r.state.CurrentGame.NetObjects[item.PlayerNetworkTransform]
a, ok := t.(*innernetobjects.PlayerNetworkTransform)
if ok {
x := r.w/2 + float64(a.TargetPosition.X)*50
y := r.h/2 - float64(a.TargetPosition.Y)*50
r.DrawFilledRectangle(float64(x-5), float64(y-5), 10, 10, enum.GetPlayerMainColor(int(item.PlayerColor)))
r.DrawText(x, y, strconv.FormatFloat(float64(a.TargetPosition.X), 'e', 4, 64)+strconv.FormatFloat(float64(a.TargetPosition.Y), 'e', 4, 64), defaultRenderFont, 10, 0xffffff)
}
}
}

37
settings.go Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"encoding/json"
"codehub.onpointcoding.net/sean/go-susapp/enum"
)
type SettingsJSON struct {
PlayerName string `json:"PlayerName"`
PlayerColor byte `json:"PlayerColor"`
ServerAddress string `json:"ServerAddress"`
ServerPort int64 `json:"ServerPort"`
Language uint32 `json:"Language"`
QuickChatMode byte `json:"QuickChatMode"`
}
func UnmarshalSettings(data []byte) (SettingsJSON, error) {
var r SettingsJSON
err := json.Unmarshal(data, &r)
return r, err
}
func (r *SettingsJSON) Marshal() ([]byte, error) {
return json.Marshal(r)
}
func NewDefaultSettingsJSON() SettingsJSON {
return SettingsJSON{
PlayerName: "Player 1",
PlayerColor: 0,
ServerAddress: "localhost",
ServerPort: 22023,
Language: enum.GAMEKEYWORD_ALL,
QuickChatMode: enum.QUICK_CHAT_ONLY,
}
}

225
settingswindow.go Normal file
View File

@ -0,0 +1,225 @@
package main
import (
"fmt"
"log"
"strconv"
"codehub.onpointcoding.net/sean/go-susapp/enum"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
var langaugeIdxMap = []int{
enum.GAMEKEYWORD_ALL,
enum.GAMEKEYWORD_OTHER,
enum.GAMEKEYWORD_SPANISH,
enum.GAMEKEYWORD_KOREAN,
enum.GAMEKEYWORD_RUSSIAN,
enum.GAMEKEYWORD_PORTUGUESE,
enum.GAMEKEYWORD_ARABIC,
enum.GAMEKEYWORD_FILIPINO,
enum.GAMEKEYWORD_POLISH,
enum.GAMEKEYWORD_ENGLISH,
enum.GAMEKEYWORD_JAPANESE,
}
var quickChatIdxMap = []int{
enum.FREE_CHAT_OR_QUICK_CHAT,
enum.QUICK_CHAT_ONLY,
}
func openSettingsWindow(application *gtk.Application, mainWindow *gtk.ApplicationWindow, state *State) {
optWindow, err := gtk.ApplicationWindowNew(application)
if err != nil {
log.Fatal("Could not create application window.", err)
}
// Set ApplicationWindow Properties
optWindow.SetTitle("Sus App > Settings")
optWindow.SetDefaultSize(350, 350)
layout, _ := gtk.LayoutNew(nil, nil)
optWindow.Add(layout)
_, usernameEntry := addTextWidget(layout, 8, "Username:", state.Settings.PlayerName)
_, colorEntry := addColorWidget(layout, 50, "Color:", state.Settings.PlayerColor)
_, serverEntry := addTextWidget(layout, 92, "Address:", state.Settings.ServerAddress)
_, portEntry := addTextWidget(layout, 134, "Port:", strconv.FormatInt(state.Settings.ServerPort, 10))
_, languageEntry := addLanguageWidget(layout, 176, "Language:", state.Settings.Language)
_, quickChatEntry := addQuickChatWidget(layout, 218, "Quick Chat:", state.Settings.QuickChatMode)
applyBtn, _ := gtk.ButtonNewWithLabel("Apply")
layout.Put(applyBtn, 8, 218)
applyBtn.SetSizeRequest(334, 34)
applyBtn.Connect("clicked", func(b *gtk.Button) {
//
// Username
//
a1, err := usernameEntry.GetText()
if err == nil {
state.Settings.PlayerName = a1
} else {
showSettingsErrorDialog(optWindow, "Failed to get new player name")
}
//
// Server
//
a2, err := serverEntry.GetText()
if err == nil {
state.Settings.ServerAddress = a2
} else {
showSettingsErrorDialog(optWindow, "Failed to get new server address")
}
//
// Port
//
a3, err := portEntry.GetText()
if err == nil {
b3, err := strconv.ParseInt(a3, 10, 64)
if err == nil {
state.Settings.ServerPort = b3
} else {
showSettingsErrorDialog(optWindow, fmt.Sprintf("Failed to parse port %v as it is not a valid integer", a3))
}
} else {
showSettingsErrorDialog(optWindow, "Failed to get new port")
}
//
// Language
//
a4 := languageEntry.GetActive()
state.Settings.Language = uint32(langaugeIdxMap[a4])
//
// Quick chat mode
//
a5 := quickChatEntry.GetActive()
state.Settings.QuickChatMode = byte(quickChatIdxMap[a5])
//
// Color
//
a6 := colorEntry.GetActive()
state.Settings.PlayerColor = byte(a6)
//
// Save
//
state.SaveSettings()
})
optWindow.ShowAll()
}
func showSettingsErrorDialog(optWindow *gtk.ApplicationWindow, msg string) {
mDialog := gtk.MessageDialogNew(optWindow, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg)
mDialog.SetTitle("Sus App Error")
mDialog.Run()
mDialog.Destroy()
}
func addTextWidget(layout *gtk.Layout, y int, txt string, orig string) (*gtk.Label, *gtk.Entry) {
label, _ := gtk.LabelNew(txt)
layout.Put(label, 8, y+6)
entry, _ := gtk.EntryNew()
layout.Put(entry, 100, y)
entry.SetSizeRequest(242, 34)
entry.SetText(orig)
return label, entry
}
func addLanguageWidget(layout *gtk.Layout, y int, txt string, orig uint32) (*gtk.Label, *gtk.ComboBox) {
var origIter *gtk.TreeIter
langStore, _ := gtk.ListStoreNew(glib.TYPE_UINT, glib.TYPE_STRING)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_ALL, "All", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_OTHER, "Other", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_SPANISH, "Spanish", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_KOREAN, "Korean", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_RUSSIAN, "Russian", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_PORTUGUESE, "Portuguese", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_ARABIC, "Arabic", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_FILIPINO, "Filipino", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_POLISH, "Polish", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_ENGLISH, "English", orig, origIter)
_, origIter = addRow(langStore, enum.GAMEKEYWORD_JAPANESE, "Japanese", orig, origIter)
label, _ := gtk.LabelNew(txt)
layout.Put(label, 8, y+6)
combo, _ := gtk.ComboBoxNewWithModel(langStore)
rendererText, _ := gtk.CellRendererTextNew()
combo.PackStart(rendererText, true)
combo.AddAttribute(rendererText, "text", 1)
combo.SetSizeRequest(242, 34)
combo.SetActiveIter(origIter)
layout.Put(combo, 100, y)
return label, combo
}
func addQuickChatWidget(layout *gtk.Layout, y int, txt string, orig byte) (*gtk.Label, *gtk.ComboBox) {
var origIter *gtk.TreeIter
modeStore, _ := gtk.ListStoreNew(glib.TYPE_UINT, glib.TYPE_STRING)
_, origIter = addRow(modeStore, enum.FREE_CHAT_OR_QUICK_CHAT, "Free Chat or Quick Chat", uint32(orig), origIter)
_, origIter = addRow(modeStore, enum.QUICK_CHAT_ONLY, "Quick Chat Only", uint32(orig), origIter)
label, _ := gtk.LabelNew(txt)
layout.Put(label, 8, y+6)
combo, _ := gtk.ComboBoxNewWithModel(modeStore)
rendererText, _ := gtk.CellRendererTextNew()
combo.PackStart(rendererText, true)
combo.AddAttribute(rendererText, "text", 1)
combo.SetSizeRequest(242, 34)
combo.SetActiveIter(origIter)
layout.Put(combo, 100, y)
return label, combo
}
func addColorWidget(layout *gtk.Layout, y int, txt string, orig byte) (*gtk.Label, *gtk.ComboBox) {
var origIter *gtk.TreeIter
modeStore, _ := gtk.ListStoreNew(glib.TYPE_UINT, glib.TYPE_STRING)
for i := 0; i < enum.GetPlayerTotalColors(); i++ {
_, origIter = addRow(modeStore, uint32(i), enum.GetPlayerColorName(i), uint32(orig), origIter)
}
label, _ := gtk.LabelNew(txt)
layout.Put(label, 8, y+6)
combo, _ := gtk.ComboBoxNewWithModel(modeStore)
rendererText, _ := gtk.CellRendererTextNew()
combo.PackStart(rendererText, true)
combo.AddAttribute(rendererText, "text", 1)
combo.SetSizeRequest(242, 34)
combo.SetActiveIter(origIter)
layout.Put(combo, 100, y)
return label, combo
}
// Append a row to the list store for the tree view
func addRow(listStore *gtk.ListStore, id uint32, feature string, origId uint32, origIter *gtk.TreeIter) (*gtk.TreeIter, *gtk.TreeIter) {
// Get an iterator for a new row at the end of the list store
iter := listStore.Append()
if id == origId {
origIter = iter
}
// Set the contents of the list store row that the iterator represents
err := listStore.Set(iter,
[]int{0, 1},
[]interface{}{id, feature})
if err != nil {
log.Fatal("Unable to add row:", err)
}
return iter, origIter
}

View File

@ -0,0 +1,61 @@
package enum
const (
DISCONNECT_EXIT_GAME = 0
DISCONNECT_GAME_FULL = 1
DISCONNECT_GAME_STARTED = 2
DISCONNECT_GAME_NOT_FOUND = 3
DISCONNECT_INCORRECT_VERSION = 5
DISCONNECT_BANNED = 6
DISCONNECT_KICKED = 7
DISCONNECT_CUSTOM = 8
DISCONNECT_INVALID_NAME = 9
DISCONNECT_HACKING = 10
DISCONNECT_NOT_AUTHORIZED = 11
DISCONNECT_DESTROY = 16
DISCONNECT_ERROR = 17
DISCONNECT_INCORRECT_GAME = 18
DISCONNECT_SERVER_REQUEST = 19
DISCONNECT_SERVER_FULL = 20
DISCONNECT_FOCUS_LOST_BACKGROUND = 207
)
func DisconnectMessageText(reason byte) string {
switch reason {
case DISCONNECT_EXIT_GAME:
return "Exit game"
case DISCONNECT_GAME_FULL:
return "Game full"
case DISCONNECT_GAME_STARTED:
return "Game started"
case DISCONNECT_GAME_NOT_FOUND:
return "Game not found"
case DISCONNECT_INCORRECT_VERSION:
return "Incorrect version"
case DISCONNECT_BANNED:
return "Banned"
case DISCONNECT_KICKED:
return "Kicked"
case DISCONNECT_CUSTOM:
return "Custom"
case DISCONNECT_INVALID_NAME:
return "Invalid name"
case DISCONNECT_HACKING:
return "Hacking"
case DISCONNECT_NOT_AUTHORIZED:
return "Not authorized"
case DISCONNECT_DESTROY:
return "Destroy"
case DISCONNECT_ERROR:
return "Error"
case DISCONNECT_INCORRECT_GAME:
return "Incorrect game"
case DISCONNECT_SERVER_REQUEST:
return "Server request"
case DISCONNECT_SERVER_FULL:
return "Server full"
case DISCONNECT_FOCUS_LOST_BACKGROUND:
return "Focus lost background"
}
return "Lost connection"
}

15
src/enum/gamekeyword.go Normal file
View File

@ -0,0 +1,15 @@
package enum
const (
GAMEKEYWORD_ALL = 0
GAMEKEYWORD_OTHER = 1
GAMEKEYWORD_SPANISH = 2
GAMEKEYWORD_KOREAN = 4
GAMEKEYWORD_RUSSIAN = 8
GAMEKEYWORD_PORTUGUESE = 16
GAMEKEYWORD_ARABIC = 32
GAMEKEYWORD_FILIPINO = 64
GAMEKEYWORD_POLISH = 128
GAMEKEYWORD_ENGLISH = 256
GAMEKEYWORD_JAPANESE = 512
)

View File

@ -0,0 +1,11 @@
package enum
const (
GAMEOVERREASON_CREWMATES_BY_VOTE = 0
GAMEOVERREASON_CREWMATES_BY_TASK = 1
GAMEOVERREASON_IMPOSTORS_BY_VOTE = 2
GAMEOVERREASON_IMPOSTORS_BY_KILL = 3
GAMEOVERREASON_IMPOSTORS_BY_SABOTAGE = 4
GAMEOVERREASON_IMPOSTOR_DISCONNECT = 5
GAMEOVERREASON_CREWMATE_DISCONNECT = 6
)

8
src/enum/gamestate.go Normal file
View File

@ -0,0 +1,8 @@
package enum
const (
GAMESTATE_NOT_STARTED = 0
GAMESTATE_STARTED = 1
GAMESTATE_ENDED = 2
GAMESTATE_DESTROYED = 3
)

3
src/enum/go.mod Normal file
View File

@ -0,0 +1,3 @@
module codehub.onpointcoding.net/sean/go-susapp/enum
go 1.17

119
src/enum/hat.go Normal file
View File

@ -0,0 +1,119 @@
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
)

16
src/enum/killdistance.go Normal file
View File

@ -0,0 +1,16 @@
package enum
const (
KILLDISTANCE_SHORT = 0
KILLDISTANCE_NORMAL = 1
KILLDISTANCE_LONG = 2
)
var distanceMap = []float64{1, 1.8, 2.5}
func GetKillDistanceMagnitude(a int) float64 {
if a < 0 || a > len(distanceMap) {
return 0
}
return distanceMap[a]
}

7
src/enum/limbostate.go Normal file
View File

@ -0,0 +1,7 @@
package enum
const (
LIMBOSTATE_PRE_SPAWN = 0
LIMBOSTATE_NOT_LIMBO = 1
LIMBOSTATE_WAITING_FOR_HOST = 2
)

20
src/enum/map.go Normal file
View File

@ -0,0 +1,20 @@
package enum
const (
MAP_THE_SKELD = 0
MAP_MIRA_HQ = 1
MAP_POLUS = 2
MAP_THE_AIRSHIP = 3
)
func MapBitfield(a []int) byte {
var b byte = 0
for i := 0; i < len(a); i++ {
b |= 1 << a[i]
}
return b
}
func BitfieldHasMap(b byte, a int) bool {
return b&(1<<a) != 0
}

16
src/enum/pet.go Normal file
View File

@ -0,0 +1,16 @@
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
)

24
src/enum/platform.go Normal file
View File

@ -0,0 +1,24 @@
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
)

View File

@ -0,0 +1,6 @@
package enum
const (
PLAYER_COLLISION_RADIUS = 0.2234
PLAYER_COLLISION_OFFSET_Y = -0.3636
)

75
src/enum/playercolor.go Normal file
View File

@ -0,0 +1,75 @@
package enum
var playerColorNames = []string{
"Red",
"Blue",
"Green",
"Pink",
"Orange",
"Yellow",
"Grey",
"White",
"Purple",
"Brown",
"Cyan",
"Light Green",
}
var playerColors = []int{
rgb(198, 17, 17),
rgb(19, 46, 210),
rgb(17, 128, 45),
rgb(238, 84, 187),
rgb(240, 125, 13),
rgb(246, 246, 87),
rgb(63, 71, 78),
rgb(215, 225, 241),
rgb(107, 47, 188),
rgb(113, 73, 30),
rgb(56, 255, 221),
rgb(80, 240, 57),
}
var playerShadedColors = []int{
rgb(122, 8, 56),
rgb(9, 21, 142),
rgb(10, 77, 46),
rgb(172, 43, 174),
rgb(180, 62, 21),
rgb(195, 136, 34),
rgb(30, 31, 38),
rgb(132, 149, 192),
rgb(59, 23, 124),
rgb(94, 38, 21),
rgb(36, 169, 191),
rgb(21, 168, 66),
}
func rgb(r int, g int, b int) int {
return r<<16 + g<<8 + b
}
func GetPlayerTotalColors() int {
return len(playerColors)
}
func GetPlayerColorName(a int) string {
if a < 0 || a > len(playerColorNames) {
return "Invalid Color"
}
return playerColorNames[a]
}
func GetPlayerMainColor(a int) int {
if a < 0 || a > len(playerColors) {
return 0
}
return playerColors[a]
}
func GetPlayerShadedColor(a int) int {
if a < 0 || a > len(playerShadedColors) {
return 0
}
return playerShadedColors[a]
}

6
src/enum/playerspeed.go Normal file
View File

@ -0,0 +1,6 @@
package enum
const (
PLAYER_SPEED = 4.5
PLAYER_GHOST_SPEED = 3.0
)

View File

@ -0,0 +1,6 @@
package enum
const (
FREE_CHAT_OR_QUICK_CHAT = 1
QUICK_CHAT_ONLY = 2
)

View File

@ -0,0 +1,9 @@
package enum
const (
REPORTOUTCOME_NOT_REPORTED_UNKNOWN = 0
REPORTOUTCOME_NOT_REPORTED_NO_ACCOUNT = 1
REPORTOUTCOME_NOT_REPORTED_NOT_FOUND = 2
REPORTOUTCOME_NOT_REPORTED_RATE_LIMIT = 3
REPORTOUTCOME_REPORTED = 4
)

8
src/enum/reportreason.go Normal file
View File

@ -0,0 +1,8 @@
package enum
const (
REPORTREASON_INAPPROPRIATE_NAME = 0
REPORTREASON_INAPPROPRIATE_CHAT = 1
REPORTREASON_CHEATING_HACKING = 2
REPORTREASON_HARASSMENT_MISCONDUCT = 3
)

36
src/enum/rpccall.go Normal file
View File

@ -0,0 +1,36 @@
package enum
const (
RPC_PLAY_ANIMATION = 0x00
RPC_COMPLETE_TASK = 0x01
RPC_SYNC_SETTINGS = 0x02
RPC_SET_INFECTED = 0x03
RPC_EXILED = 0x04
RPC_CHECK_NAME = 0x05
RPC_SET_NAME = 0x06
RPC_CHECK_COLOR = 0x07
RPC_SET_COLOR = 0x08
RPC_SET_HAT = 0x09
RPC_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_SET_START_COUNTER = 0x12
RPC_ENTER_VENT = 0x13
RPC_EXIT_VENT = 0x14
RPC_SNAP_TO = 0x15
RPC_CLOSE = 0x16
RPC_VOTING_COMPLETE = 0x17
RPC_CAST_VOTE = 0x18
RPC_CLEAR_VOTE = 0x19
RPC_ADD_VOTE = 0x1a
RPC_CLOSE_DOORS_OF_TYPE = 0x1b
RPC_REPAIR_SYSTEM = 0x1c
RPC_SET_TASKS = 0x1d
RPC_CLIMB_LADDER = 0x1f
RPC_USE_PLATFORM = 0x20
)

9
src/enum/screenstate.go Normal file
View File

@ -0,0 +1,9 @@
package enum
const (
SCREEN_TITLE = 0
SCREEN_WAITING = 1
SCREEN_LOBBY = 2
SCREEN_INGAME = 3
SCREEN_ERROR = 4
)

23
src/enum/skin.go Normal file
View File

@ -0,0 +1,23 @@
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
)

6
src/enum/spawnflag.go Normal file
View File

@ -0,0 +1,6 @@
package enum
const (
SPAWNFLAG_NONE = 0
SPAWNFLAG_IS_CLIENT_CHARACTER = 1
)

13
src/enum/spawntype.go Normal file
View File

@ -0,0 +1,13 @@
package enum
const (
SPAWNTYPE_SKELD_SHIP_STATUS = 0
SPAWNTYPE_MEETING_HUD = 1
SPAWNTYPE_LOBBY_BEHAVIOUR = 2
SPAWNTYPE_GAME_DATA = 3
SPAWNTYPE_PLAYER_CONTROL = 4
SPAWNTYPE_MIRA_SHIP_STATUS = 5
SPAWNTYPE_POLUS_SHIP_STATUS = 6
SPAWNTYPE_DLEKS_SHIP_STATUS = 7
SPAWNTYPE_AIRSHIP_STATUS = 8
)

53
src/enum/systemtype.go Normal file
View File

@ -0,0 +1,53 @@
package enum
const (
SYSTEMTYPE_HALLWAY = 0
SYSTEMTYPE_STORAGE = 1
SYSTEMTYPE_CAFETERIA = 2
SYSTEMTYPE_REACTOR = 3
SYSTEMTYPE_UPPER_ENGINE = 4
SYSTEMTYPE_NAVIGATION = 5
SYSTEMTYPE_ADMIN = 6
SYSTEMTYPE_ELECTRICAL = 7
SYSTEMTYPE_O2 = 8
SYSTEMTYPE_SHIELDS = 9
SYSTEMTYPE_MEDBAY = 10
SYSTEMTYPE_SECURITY = 11
SYSTEMTYPE_WEAPONS = 12
SYSTEMTYPE_LOWER_ENGINE = 13
SYSTEMTYPE_COMMUNICATIONS = 14
SYSTEMTYPE_SHIP_TASKS = 15
SYSTEMTYPE_DOORS = 16
SYSTEMTYPE_SABOTAGE = 17
SYSTEMTYPE_DECONTAMINATION = 18
SYSTEMTYPE_LAUNCHPAD = 19
SYSTEMTYPE_LOCKER_ROOM = 20
SYSTEMTYPE_LABORATORY = 21
SYSTEMTYPE_BALCONY = 22
SYSTEMTYPE_OFFICE = 23
SYSTEMTYPE_GREENHOUSE = 24
SYSTEMTYPE_DROPSHIP = 25
SYSTEMTYPE_DECONTAMINATION_2 = 26
SYSTEMTYPE_OUTSIDE = 27
SYSTEMTYPE_SPECIMENS = 28
SYSTEMTYPE_BOILER_ROOM = 29
SYSTEMTYPE_VAULT_ROOM = 30
SYSTEMTYPE_COCKPIT = 31
SYSTEMTYPE_ARMORY = 32
SYSTEMTYPE_KITCHEN = 33
SYSTEMTYPE_VIEWING_DECK = 34
SYSTEMTYPE_HALL_OF_PORTRAITS = 35
SYSTEMTYPE_CARGO_BAY = 36
SYSTEMTYPE_VENTILATION = 37
SYSTEMTYPE_SHOWERS = 38
SYSTEMTYPE_ENGINE = 39
SYSTEMTYPE_BRIG = 40
SYSTEMTYPE_MEETING_ROOM = 41
SYSTEMTYPE_RECORDS = 42
SYSTEMTYPE_LOUNGE = 43
SYSTEMTYPE_GAP_ROOM = 44
SYSTEMTYPE_MAIN_HALL = 45
SYSTEMTYPE_MEDICAL = 46
TOTAL_SYSTEMTYPE = 47
)

7
src/enum/taskbarmode.go Normal file
View File

@ -0,0 +1,7 @@
package enum
const (
TASKBARMODE_ALWAYS = 0
TASKBARMODE_MEETINGS = 1
TASKBARMODE_NEVER = 2
)

64
src/enum/tasktypes.go Normal file
View File

@ -0,0 +1,64 @@
package enum
const (
TASKTYPES_SUBMIT_SCAN = 0
TASKTYPES_PRIME_SHIELDS = 1
TASKTYPES_FUEL_ENGINES = 2
TASKTYPES_CHART_COURSE = 3
TASKTYPES_START_REACTOR = 4
TASKTYPES_SWIPE_CARD = 5
TASKTYPES_CLEAR_ASTEROIDS = 6
TASKTYPES_UPLOAD_DATA = 7
TASKTYPES_INSPECT_SAMPLE = 8
TASKTYPES_EMPTY_CHUTE = 9
TASKTYPES_EMPTY_GARBAGE = 10
TASKTYPES_ALIGN_ENGINE_OUTPUT = 11
TASKTYPES_FIX_WIRING = 12
TASKTYPES_CALIBRATE_DISTRIBUTOR = 13
TASKTYPES_DIVERT_POWER = 14
TASKTYPES_UNLOCK_MANIFOLDS = 15
TASKTYPES_RESET_REACTOR = 16
TASKTYPES_FIX_LIGHTS = 17
TASKTYPES_CLEAN_O2_FILTER = 18
TASKTYPES_FIX_COMMS = 19
TASKTYPES_RESTORE_O2 = 20
TASKTYPES_STABILIZE_STEERING = 21
TASKTYPES_ASSEMBLE_ARTIFACT = 22
TASKTYPES_SORT_SAMPLES = 23
TASKTYPES_MEASURE_WEATHER = 24
TASKTYPES_ENTER_ID_CODE = 25
TASKTYPES_BUY_BEVERAGE = 26
TASKTYPES_PROCESS_DATA = 27
TASKTYPES_RUN_DIAGNOSTICS = 28
TASKTYPES_WATER_PLANTS = 29
TASKTYPES_MONITOR_O2 = 30
TASKTYPES_STORE_ARTIFACTS = 31
TASKTYPES_FILL_CANISTERS = 32
TASKTYPES_ACTIVATE_WEATHER_NODES = 33
TASKTYPES_INSERT_KEYS = 34
TASKTYPES_RESET_SEISMIC = 35
TASKTYPES_SCAN_BOARDING_PASS = 36
TASKTYPES_OPEN_WATERWAYS = 37
TASKTYPES_REPLACE_WATER_JUG = 38
TASKTYPES_REPAIR_DRILL = 39
TASKTYPES_ALIGN_TELESCOPE = 40
TASKTYPES_RECORD_TEMPERATURE = 41
TASKTYPES_REBOOT_WIFI = 42
TASKTYPES_POLISH_RUBY = 43
TASKTYPES_RESET_BREAKERS = 44
TASKTYPES_DECONTAMINATE = 45
TASKTYPES_MAKE_BURGER = 46
TASKTYPES_UNLOCK_SAFE = 47
TASKTYPES_SORT_RECORDS = 48
TASKTYPES_PUT_AWAY_PISTOLS = 49
TASKTYPES_FIX_SHOWER = 50
TASKTYPES_CLEAN_TOILET = 51
TASKTYPES_DRESS_MANNEQUIN = 52
TASKTYPES_PICK_UP_TOWELS = 53
TASKTYPES_REWIND_TAPES = 54
TASKTYPES_START_FANS = 55
TASKTYPES_DEVELOP_PHOTOS = 56
TASKTYPES_GET_BIGGOL_SWORD = 57
TASKTYPES_PUT_AWAY_RIFLES = 58
TASKTYPES_STOP_CHARLES = 59
)

23
src/gamedata/01_data.go Normal file
View File

@ -0,0 +1,23 @@
package gamedata
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type DataH2G struct {
Component *protocol.UpdateComponent
}
func (d *DataH2G) AsHazel() *protocol.Hazel {
var a protocol.HazelPayload = d
return protocol.NewHazelFromPayload(&a)
}
func (d *DataH2G) TypeCode() byte { return 0x01 }
func (d *DataH2G) Write(packet *protocol.Packet) {
d.Component.Write(packet)
}
func (d *DataH2G) Read(packet *protocol.Packet) {
d.Component = &protocol.UpdateComponent{}
d.Component.Read(packet)
}

501
src/gamedata/02_rpc.go Normal file
View File

@ -0,0 +1,501 @@
package gamedata
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/util"
)
//
// RPC base
//
type Rpc struct {
SenderNetID uint32
RPCCallID byte
Sub *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 {
return &Rpc{
SenderNetID: senderNetID,
RPCCallID: (*sub).CallCode(),
Sub: sub,
}
}
func (d *Rpc) GetUnderlyingHazel() *protocol.Hazel {
return d.UnderlyingHazel
}
func (d *Rpc) AsHazel() *protocol.Hazel {
var a protocol.HazelPayload = d
return protocol.NewHazelFromPayload(&a)
}
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)
}
func (d *Rpc) Read(packet *protocol.Packet) {
d.SenderNetID = packet.ReadPackedUInt32()
d.RPCCallID = packet.Read()
// TODO: finish this
}
type RpcSub interface {
CallCode() byte
WriteToPacket(packet *protocol.Packet)
ReadFromPacket(packet *protocol.Packet)
}
//
// 0x00 RpcPlayAnimation
//
type RpcPlayAnimation struct{ TaskID byte }
func (d *RpcPlayAnimation) CallCode() byte { return enum.RPC_PLAY_ANIMATION }
func (d *RpcPlayAnimation) WriteToPacket(packet *protocol.Packet) { packet.Write(d.TaskID) }
func (d *RpcPlayAnimation) ReadFromPacket(packet *protocol.Packet) { d.TaskID = packet.Read() }
//
// 0x01 RpcCompleteTask
//
type RpcCompleteTask struct{ TaskIndex uint32 }
func (d *RpcCompleteTask) CallCode() byte { return enum.RPC_COMPLETE_TASK }
func (d *RpcCompleteTask) WriteToPacket(packet *protocol.Packet) {
packet.WritePackedUInt32(d.TaskIndex)
}
func (d *RpcCompleteTask) ReadFromPacket(packet *protocol.Packet) {
d.TaskIndex = packet.ReadPackedUInt32()
}
//
// 0x02 RpcSyncSettings
//
type RpcSyncSettings struct{ Options *protocol.GameOptionsData }
func (d *RpcSyncSettings) CallCode() byte { return enum.RPC_SYNC_SETTINGS }
func (d *RpcSyncSettings) WriteToPacket(packet *protocol.Packet) { d.Options.Write(packet) }
func (d *RpcSyncSettings) ReadFromPacket(packet *protocol.Packet) {
d.Options = protocol.NewGameOptionsDataFromPacket(packet)
}
//
// 0x03 RpcSetInfected
//
type RpcSetInfected struct{ Impostors []byte }
func (d *RpcSetInfected) CallCode() byte { return enum.RPC_SET_INFECTED }
func (d *RpcSetInfected) WriteToPacket(packet *protocol.Packet) {
packet.Write(byte(len(d.Impostors)))
for i := 0; i < len(d.Impostors); i++ {
packet.Write(d.Impostors[i])
}
}
func (d *RpcSetInfected) ReadFromPacket(packet *protocol.Packet) {
d.Impostors = make([]byte, packet.Read())
for i := 0; i < len(d.Impostors); i++ {
d.Impostors[i] = packet.Read()
}
}
//
// 0x04 RpcExiled
//
type RpcExiled struct{}
func (d *RpcExiled) CallCode() byte { return enum.RPC_EXILED }
func (d *RpcExiled) WriteToPacket(packet *protocol.Packet) {}
func (d *RpcExiled) ReadFromPacket(packet *protocol.Packet) {}
//
// 0x05 RpcCheckName
//
type RpcCheckName struct{ Name string }
func (d *RpcCheckName) CallCode() byte { return enum.RPC_CHECK_NAME }
func (d *RpcCheckName) WriteToPacket(packet *protocol.Packet) { packet.WriteString(d.Name) }
func (d *RpcCheckName) ReadFromPacket(packet *protocol.Packet) { d.Name = packet.ReadString() }
//
// 0x06 RpcSetName
//
type RpcSetName struct{ Name string }
func (d *RpcSetName) CallCode() byte { return enum.RPC_SET_NAME }
func (d *RpcSetName) WriteToPacket(packet *protocol.Packet) { packet.WriteString(d.Name) }
func (d *RpcSetName) ReadFromPacket(packet *protocol.Packet) { d.Name = packet.ReadString() }
//
// 0x07 RpcCheckColor
//
type RpcCheckColor struct{ Color byte }
func (d *RpcCheckColor) CallCode() byte { return enum.RPC_CHECK_COLOR }
func (d *RpcCheckColor) WriteToPacket(packet *protocol.Packet) { packet.Write(d.Color) }
func (d *RpcCheckColor) ReadFromPacket(packet *protocol.Packet) { d.Color = packet.Read() }
//
// 0x08 RpcSetColor
//
type RpcSetColor struct{ Color byte }
func (d *RpcSetColor) CallCode() byte { return enum.RPC_SET_COLOR }
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
//
type RpcReportDeadBody struct{ VictimPlayerID byte }
func (d *RpcReportDeadBody) CallCode() byte { return enum.RPC_REPORT_DEAD_BODY }
func (d *RpcReportDeadBody) WriteToPacket(packet *protocol.Packet) { packet.Write(d.VictimPlayerID) }
func (d *RpcReportDeadBody) ReadFromPacket(packet *protocol.Packet) { d.VictimPlayerID = packet.Read() }
func (d *RpcReportDeadBody) IsEmergencyMeetingButton() bool { return d.VictimPlayerID == 255 }
//
// 0x0c RpcMurderPlayer
//
type RpcMurderPlayer struct{ VictimNetID uint32 }
func (d *RpcMurderPlayer) CallCode() byte { return enum.RPC_MURDER_PLAYER }
func (d *RpcMurderPlayer) WriteToPacket(packet *protocol.Packet) {
packet.WritePackedUInt32(d.VictimNetID)
}
func (d *RpcMurderPlayer) ReadFromPacket(packet *protocol.Packet) {
d.VictimNetID = packet.ReadPackedUInt32()
}
//
// 0x0d RpcSendChat
//
type RpcSendChat struct{ Message string }
func (d *RpcSendChat) CallCode() byte { return enum.RPC_SEND_CHAT }
func (d *RpcSendChat) WriteToPacket(packet *protocol.Packet) { packet.WriteString(d.Message) }
func (d *RpcSendChat) ReadFromPacket(packet *protocol.Packet) { d.Message = packet.ReadString() }
//
// 0x0e RpcStartMeeting
//
type RpcStartMeeting struct{ VictimPlayerID byte }
func (d *RpcStartMeeting) CallCode() byte { return enum.RPC_START_MEETING }
func (d *RpcStartMeeting) WriteToPacket(packet *protocol.Packet) { packet.Write(d.VictimPlayerID) }
func (d *RpcStartMeeting) ReadFromPacket(packet *protocol.Packet) { d.VictimPlayerID = packet.Read() }
func (d *RpcStartMeeting) IsEmergencyMeetingButton() bool { return d.VictimPlayerID == 255 }
//
// 0x0f RpcSetScanner
//
type RpcSetScanner struct {
IsScanning bool
SequenceID byte
}
func (d *RpcSetScanner) CallCode() byte { return enum.RPC_SET_SCANNER }
func (d *RpcSetScanner) WriteToPacket(packet *protocol.Packet) {
packet.WriteBool(d.IsScanning)
packet.Write(d.SequenceID)
}
func (d *RpcSetScanner) ReadFromPacket(packet *protocol.Packet) {
d.IsScanning = packet.ReadBool()
d.SequenceID = packet.Read()
}
//
// 0x10 RpcSendChatNote
//
type RpcSendChatNote struct {
PlayerID byte
ChatNoteType byte
}
func (d *RpcSendChatNote) CallCode() byte { return enum.RPC_SEND_CHAT_NOTE }
func (d *RpcSendChatNote) WriteToPacket(packet *protocol.Packet) {
packet.Write(d.PlayerID)
packet.Write(d.ChatNoteType)
}
func (d *RpcSendChatNote) ReadFromPacket(packet *protocol.Packet) {
d.PlayerID = packet.Read()
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
//
type RpcSetStartCounter struct {
SequenceID uint32
TimeRemaining byte
}
func (d *RpcSetStartCounter) CallCode() byte { return enum.RPC_SET_START_COUNTER }
func (d *RpcSetStartCounter) WriteToPacket(packet *protocol.Packet) {
packet.WritePackedUInt32(d.SequenceID)
packet.Write(d.TimeRemaining)
}
func (d *RpcSetStartCounter) ReadFromPacket(packet *protocol.Packet) {
d.SequenceID = packet.ReadPackedUInt32()
d.TimeRemaining = packet.Read()
}
func (d *RpcSetStartCounter) ShouldResetTimer() bool { return d.TimeRemaining == 0xff }
//
// 0x13 RpcEnterVent
//
type RpcEnterVent struct{ VentID uint32 }
func (d *RpcEnterVent) CallCode() byte { return enum.RPC_ENTER_VENT }
func (d *RpcEnterVent) WriteToPacket(packet *protocol.Packet) { packet.WritePackedUInt32(d.VentID) }
func (d *RpcEnterVent) ReadFromPacket(packet *protocol.Packet) { d.VentID = packet.ReadPackedUInt32() }
//
// 0x14 RpcExitVent
//
type RpcExitVent struct{ VentID uint32 }
func (d *RpcExitVent) CallCode() byte { return enum.RPC_EXIT_VENT }
func (d *RpcExitVent) WriteToPacket(packet *protocol.Packet) { packet.WritePackedUInt32(d.VentID) }
func (d *RpcExitVent) ReadFromPacket(packet *protocol.Packet) { d.VentID = packet.ReadPackedUInt32() }
//
// 0x15 RpcSnapTo
//
type RpcSnapTo struct {
Position util.Vec2
LastSequenceID uint16
}
func (d *RpcSnapTo) CallCode() byte { return enum.RPC_SNAP_TO }
func (d *RpcSnapTo) WriteToPacket(packet *protocol.Packet) {
packet.WriteVector2(d.Position)
packet.WriteUInt16(d.LastSequenceID)
}
func (d *RpcSnapTo) ReadFromPacket(packet *protocol.Packet) {
d.Position = packet.ReadVector2()
d.LastSequenceID = packet.ReadUInt16()
}
//
// 0x16 RpcClose
//
type RpcClose struct{}
func (d *RpcClose) CallCode() byte { return enum.RPC_CLOSE }
func (d *RpcClose) WriteToPacket(packet *protocol.Packet) {}
func (d *RpcClose) ReadFromPacket(packet *protocol.Packet) {}
//
// 0x17 RpcVotingComplete
//
type RpcVotingComplete struct {
VoteStates []byte
ExiledPlayerID byte
IsTie bool
}
// TODO: write serializer for voting complete
func (d *RpcVotingComplete) CallCode() byte { return enum.RPC_VOTING_COMPLETE }
func (d *RpcVotingComplete) WriteToPacket(packet *protocol.Packet) {}
func (d *RpcVotingComplete) ReadFromPacket(packet *protocol.Packet) {}
//
// 0x18 RpcCastVote
//
type RpcCastVote struct {
VotingPlayerID byte
SuspectPlayerID byte
}
func (d *RpcCastVote) CallCode() byte { return enum.RPC_CAST_VOTE }
func (d *RpcCastVote) WriteToPacket(packet *protocol.Packet) {
packet.Write(d.VotingPlayerID)
packet.Write(d.SuspectPlayerID)
}
func (d *RpcCastVote) ReadFromPacket(packet *protocol.Packet) {
d.VotingPlayerID = packet.Read()
d.SuspectPlayerID = packet.Read()
}
//
// 0x19 RpcClearVote
//
type RpcClearVote struct{}
func (d *RpcClearVote) CallCode() byte { return enum.RPC_CLEAR_VOTE }
func (d *RpcClearVote) WriteToPacket(packet *protocol.Packet) {}
func (d *RpcClearVote) ReadFromPacket(packet *protocol.Packet) {}
//
// 0x1a RpcAddVote
//
type RpcAddVote struct {
VotingClientID uint32
TargetClientID uint32
}
func (d *RpcAddVote) CallCode() byte { return enum.RPC_ADD_VOTE }
func (d *RpcAddVote) WriteToPacket(packet *protocol.Packet) {
packet.WriteUInt32(d.VotingClientID)
packet.WriteUInt32(d.TargetClientID)
}
func (d *RpcAddVote) ReadFromPacket(packet *protocol.Packet) {
d.VotingClientID = packet.ReadUInt32()
d.TargetClientID = packet.ReadUInt32()
}
//
// 0x1b RpcCloseDoorsOfType
//
type RpcCloseDoorsOfType struct {
SystemID byte
}
func (d *RpcCloseDoorsOfType) CallCode() byte { return enum.RPC_CLOSE_DOORS_OF_TYPE }
func (d *RpcCloseDoorsOfType) WriteToPacket(packet *protocol.Packet) { packet.Write(d.SystemID) }
func (d *RpcCloseDoorsOfType) ReadFromPacket(packet *protocol.Packet) { d.SystemID = packet.Read() }
//
// 0x1c RpcRepairSystem
//
type RpcRepairSystem struct {
SystemID byte
PlayerControlNetID uint32
Amount byte
}
func (d *RpcRepairSystem) CallCode() byte { return enum.RPC_REPAIR_SYSTEM }
func (d *RpcRepairSystem) WriteToPacket(packet *protocol.Packet) {
packet.Write(d.SystemID)
packet.WritePackedUInt32(d.PlayerControlNetID)
packet.Write(d.Amount)
}
func (d *RpcRepairSystem) ReadFromPacket(packet *protocol.Packet) {
d.SystemID = packet.Read()
d.PlayerControlNetID = packet.ReadPackedUInt32()
d.Amount = packet.Read()
}
//
// 0x1d RpcSetTasks
//
type RpcSetTasks struct {
PlayerID byte
Tasks []byte
}
func (d *RpcSetTasks) CallCode() byte { return enum.RPC_SET_TASKS }
func (d *RpcSetTasks) WriteToPacket(packet *protocol.Packet) {
packet.Write(d.PlayerID)
packet.WritePackedUInt32(uint32(len(d.Tasks)))
for i := 0; i < len(d.Tasks); i++ {
packet.Write(d.Tasks[i])
}
}
func (d *RpcSetTasks) ReadFromPacket(packet *protocol.Packet) {
d.PlayerID = packet.Read()
d.Tasks = make([]byte, packet.ReadPackedUInt32())
for i := 0; i < len(d.Tasks); i++ {
d.Tasks[i] = packet.Read()
}
}
//
// 0x1f RpcClimbLadder
//
type RpcClimbLadder struct {
LadderID byte
SequenceID byte
}
func (d *RpcClimbLadder) CallCode() byte { return enum.RPC_CLIMB_LADDER }
func (d *RpcClimbLadder) WriteToPacket(packet *protocol.Packet) {
packet.Write(d.LadderID)
packet.Write(d.SequenceID)
}
func (d *RpcClimbLadder) ReadFromPacket(packet *protocol.Packet) {
d.LadderID = packet.Read()
d.SequenceID = packet.Read()
}
//
// 0x1f RpcUsePlatform
//
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) {}

36
src/gamedata/04_spawn.go Normal file
View File

@ -0,0 +1,36 @@
package gamedata
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type SpawnH2G struct {
SpawnType uint32
OwnerID uint32
SpawnFlags byte
Components []*protocol.SpawnComponent
}
func (d *SpawnH2G) AsHazel() *protocol.Hazel {
var a protocol.HazelPayload = d
return protocol.NewHazelFromPayload(&a)
}
func (d *SpawnH2G) TypeCode() byte { return 0x04 }
func (d *SpawnH2G) Write(packet *protocol.Packet) {
packet.WritePackedUInt32(d.SpawnType)
packet.WritePackedUInt32(d.OwnerID)
packet.Write(d.SpawnFlags)
for i := 0; i < len(d.Components); i++ {
d.Components[i].Write(packet)
}
}
func (d *SpawnH2G) Read(packet *protocol.Packet) {
d.SpawnType = packet.ReadPackedUInt32()
d.OwnerID = packet.ReadPackedUInt32()
d.SpawnFlags = packet.Read()
d.Components = make([]*protocol.SpawnComponent, packet.Read())
for i := 0; i < len(d.Components); i++ {
d.Components[i] = &protocol.SpawnComponent{}
d.Components[i].Read(packet)
}
}

View File

@ -0,0 +1,16 @@
package gamedata
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type DespawnH2G struct {
NetID uint32
}
func (d *DespawnH2G) AsHazel() *protocol.Hazel {
var a protocol.HazelPayload = d
return protocol.NewHazelFromPayload(&a)
}
func (d *DespawnH2G) TypeCode() byte { return 0x05 }
func (d *DespawnH2G) Write(packet *protocol.Packet) { packet.WritePackedUInt32(d.NetID) }
func (d *DespawnH2G) Read(packet *protocol.Packet) { d.NetID = packet.ReadPackedUInt32() }

View File

@ -0,0 +1,23 @@
package gamedata
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type SceneChangeC2H struct {
ClientID uint32
SceneName string
}
func (d *SceneChangeC2H) AsHazel() *protocol.Hazel {
var a protocol.HazelPayload = d
return protocol.NewHazelFromPayload(&a)
}
func (d *SceneChangeC2H) TypeCode() byte { return 0x06 }
func (d *SceneChangeC2H) Write(packet *protocol.Packet) {
packet.WritePackedUInt32(d.ClientID)
packet.WriteString(d.SceneName)
}
func (d *SceneChangeC2H) Read(packet *protocol.Packet) {
d.ClientID = packet.ReadPackedUInt32()
d.SceneName = packet.ReadString()
}

16
src/gamedata/07_ready.go Normal file
View File

@ -0,0 +1,16 @@
package gamedata
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type ReadyC2H struct {
ReadyClientID uint32
}
func (d *ReadyC2H) AsHazel() *protocol.Hazel {
var a protocol.HazelPayload = d
return protocol.NewHazelFromPayload(&a)
}
func (d *ReadyC2H) TypeCode() byte { return 0x07 }
func (d *ReadyC2H) Write(packet *protocol.Packet) { packet.WritePackedUInt32(d.ReadyClientID) }
func (d *ReadyC2H) Read(packet *protocol.Packet) { d.ReadyClientID = packet.ReadPackedUInt32() }

View File

@ -0,0 +1,5 @@
package gamedata
// ChangeSettingsAll is never used
type ChangeSettingsAll struct {
}

View File

@ -0,0 +1,23 @@
package gamedata
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type ClientInfoC2S struct {
ClientID uint32
PlatformID uint32
}
func (d *ClientInfoC2S) AsHazel() *protocol.Hazel {
var a protocol.HazelPayload = d
return protocol.NewHazelFromPayload(&a)
}
func (d *ClientInfoC2S) TypeCode() byte { return 0xcd }
func (d *ClientInfoC2S) Write(packet *protocol.Packet) {
packet.WritePackedUInt32(d.ClientID)
packet.WritePackedUInt32(d.PlatformID)
}
func (d *ClientInfoC2S) Read(packet *protocol.Packet) {
d.ClientID = packet.ReadPackedUInt32()
d.PlatformID = packet.ReadPackedUInt32()
}

13
src/gamedata/go.mod Normal file
View File

@ -0,0 +1,13 @@
module codehub.onpointcoding.net/sean/go-susapp/gamedata
go 1.17
replace (
codehub.onpointcoding.net/sean/go-susapp/protocol => ../protocol
codehub.onpointcoding.net/sean/go-susapp/util => ../util
)
require (
codehub.onpointcoding.net/sean/go-susapp/protocol v1.0.0
codehub.onpointcoding.net/sean/go-susapp/util v1.0.0
)

View File

@ -0,0 +1,35 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type GameData struct {
Players []*protocol.PlayerData
}
func (data *GameData) Write(packet *protocol.Packet, isSpawn bool) {
if isSpawn {
packet.WriteUInt32(uint32(len(data.Players)))
} else {
packet.Write(byte(len(data.Players)))
}
for i := 0; i < len(data.Players); i++ {
data.Players[i].Write(packet)
}
}
func (data *GameData) Read(packet *protocol.Packet, isSpawn bool) {
packet.ReadBytes(4)
if packet.Dump()[0] == 0x0c {
return
}
if isSpawn {
data.Players = make([]*protocol.PlayerData, packet.ReadPackedUInt32())
} else {
data.Players = make([]*protocol.PlayerData, packet.Read())
}
for i := 0; i < len(data.Players); i++ {
data.Players[i] = &protocol.PlayerData{}
data.Players[i].Read(packet)
}
}

View File

@ -0,0 +1,17 @@
module codehub.onpointcoding.net/sean/go-susapp/innernetobjects
go 1.17
replace (
codehub.onpointcoding.net/sean/go-susapp/enum => ../enum
codehub.onpointcoding.net/sean/go-susapp/protocol => ../protocol
codehub.onpointcoding.net/sean/go-susapp/systemtypes => ../systemtypes
codehub.onpointcoding.net/sean/go-susapp/util => ../util
)
require (
codehub.onpointcoding.net/sean/go-susapp/enum v1.0.0
codehub.onpointcoding.net/sean/go-susapp/protocol v1.0.0
codehub.onpointcoding.net/sean/go-susapp/systemtypes v1.0.0
codehub.onpointcoding.net/sean/go-susapp/util v1.0.0 // indirect
)

View File

@ -0,0 +1,8 @@
package innernetobjects
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type InnerNetObject interface {
Write(packet *protocol.Packet, isSpawn bool)
Read(packet *protocol.Packet, isSpawn bool)
}

View File

@ -0,0 +1,33 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/systemtypes"
)
type MiraShipStatus struct {
Systems map[int]*systemtypes.SystemType
SystemsMask uint32
}
func NewMiraShipStatus() *MiraShipStatus {
a := &MiraShipStatus{}
a.Systems = make(map[int]*systemtypes.SystemType)
a.Systems[enum.SYSTEMTYPE_REACTOR] = systemtypes.SystemTypeCast(&systemtypes.ReactorSystem{})
a.Systems[enum.SYSTEMTYPE_ELECTRICAL] = systemtypes.SystemTypeCast(&systemtypes.SwitchSystem{})
a.Systems[enum.SYSTEMTYPE_O2] = systemtypes.SystemTypeCast(&systemtypes.LifeSuppSystem{})
a.Systems[enum.SYSTEMTYPE_MEDBAY] = systemtypes.SystemTypeCast(&systemtypes.MedScanSystem{})
a.Systems[enum.SYSTEMTYPE_COMMUNICATIONS] = systemtypes.SystemTypeCast(&systemtypes.HqHudSystem{})
a.Systems[enum.SYSTEMTYPE_SABOTAGE] = systemtypes.SystemTypeCast(&systemtypes.SabotageSystem{})
a.Systems[enum.SYSTEMTYPE_DECONTAMINATION] = systemtypes.SystemTypeCast(&systemtypes.DeconSystem{})
return a
}
func (mira *MiraShipStatus) Write(packet *protocol.Packet, isSpawn bool) {
WriteShipStatus(mira.Systems, &mira.SystemsMask, packet, isSpawn)
}
func (mira *MiraShipStatus) Read(packet *protocol.Packet, isSpawn bool) {
ReadShipStatus(mira.Systems, &mira.SystemsMask, packet, isSpawn)
}

View File

@ -0,0 +1,32 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type PlayerControl struct {
IsNew bool
PlayerID byte
}
func (control *PlayerControl) Write(packet *protocol.Packet, isSpawn bool) {
p := protocol.NewEmptyPacket()
if isSpawn {
p.WriteBool(control.IsNew)
p.Write(control.PlayerID)
h := protocol.NewHazelFromRawData(0, p.Dump())
h.WriteToPacket(packet)
} else {
p.Write(control.PlayerID)
p.Copy(packet)
}
}
func (control *PlayerControl) Read(packet *protocol.Packet, isSpawn bool) {
p := packet
if isSpawn {
p = packet.ReadHazel().GetUnderlyingPacket()
control.IsNew = p.ReadBool()
}
control.PlayerID = p.Read()
}

View File

@ -0,0 +1,35 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/util"
)
type PlayerNetworkTransform struct {
LastSequenceID uint16
TargetPosition util.Vec2
TargetVelocity util.Vec2
}
func (transform *PlayerNetworkTransform) Write(packet *protocol.Packet, isSpawn bool) {
p := protocol.NewEmptyPacket()
p.WriteUInt16(transform.LastSequenceID)
p.WriteVector2(transform.TargetPosition)
p.WriteVector2(transform.TargetVelocity)
if isSpawn {
h := protocol.NewHazelFromRawData(0, p.Dump())
h.WriteToPacket(packet)
} else {
p.Copy(packet)
}
}
func (transform *PlayerNetworkTransform) Read(packet *protocol.Packet, isSpawn bool) {
p := packet
if isSpawn {
p = packet.ReadHazel().GetUnderlyingPacket()
}
transform.LastSequenceID = p.ReadUInt16()
transform.TargetPosition = p.ReadVector2()
transform.TargetVelocity = p.ReadVector2()
}

View File

@ -0,0 +1,9 @@
package innernetobjects
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
// PlayerPhysics has no data
type PlayerPhysics struct{}
func (control *PlayerPhysics) Write(packet *protocol.Packet, isSpawn bool) {}
func (control *PlayerPhysics) Read(packet *protocol.Packet, isSpawn bool) {}

View File

@ -0,0 +1,35 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/systemtypes"
)
type PolusShipStatus struct {
Systems map[int]*systemtypes.SystemType
SystemsMask uint32
}
func NewPolusShipStatus() *MiraShipStatus {
a := &MiraShipStatus{}
a.Systems = make(map[int]*systemtypes.SystemType)
a.Systems[enum.SYSTEMTYPE_ELECTRICAL] = systemtypes.SystemTypeCast(&systemtypes.SwitchSystem{})
a.Systems[enum.SYSTEMTYPE_MEDBAY] = systemtypes.SystemTypeCast(&systemtypes.MedScanSystem{})
a.Systems[enum.SYSTEMTYPE_SECURITY] = systemtypes.SystemTypeCast(&systemtypes.SecurityCameraSystem{})
a.Systems[enum.SYSTEMTYPE_COMMUNICATIONS] = systemtypes.SystemTypeCast(&systemtypes.HudOverrideSystem{})
a.Systems[enum.SYSTEMTYPE_DOORS] = systemtypes.SystemTypeCast(&systemtypes.DoorsSystem{})
a.Systems[enum.SYSTEMTYPE_DECONTAMINATION] = systemtypes.SystemTypeCast(&systemtypes.DeconSystem{})
a.Systems[enum.SYSTEMTYPE_DECONTAMINATION_2] = systemtypes.SystemTypeCast(&systemtypes.DeconSystem{})
a.Systems[enum.SYSTEMTYPE_SABOTAGE] = systemtypes.SystemTypeCast(&systemtypes.SabotageSystem{})
a.Systems[enum.SYSTEMTYPE_LABORATORY] = systemtypes.SystemTypeCast(&systemtypes.ReactorSystem{})
return a
}
func (polus *PolusShipStatus) Write(packet *protocol.Packet, isSpawn bool) {
WriteShipStatus(polus.Systems, &polus.SystemsMask, packet, isSpawn)
}
func (polus *PolusShipStatus) Read(packet *protocol.Packet, isSpawn bool) {
ReadShipStatus(polus.Systems, &polus.SystemsMask, packet, isSpawn)
}

View File

@ -0,0 +1,50 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/systemtypes"
)
func WriteShipStatus(Systems map[int]*systemtypes.SystemType, SystemsMask *uint32, packet *protocol.Packet, isSpawn bool) {
p := protocol.NewEmptyPacket()
for i := 0; i < enum.TOTAL_SYSTEMTYPE; i++ {
if isSpawn {
if val, ok := Systems[i]; ok {
(*val).Write(p, isSpawn)
}
} else {
if (*SystemsMask & (1 << i)) != 0 {
(*Systems[i]).Write(p, isSpawn)
}
}
}
if isSpawn {
h := protocol.NewHazelFromRawData(0, p.Dump())
h.WriteToPacket(packet)
} else {
packet.WritePackedUInt32(*SystemsMask)
p.Copy(packet)
}
}
func ReadShipStatus(Systems map[int]*systemtypes.SystemType, SystemsMask *uint32, packet *protocol.Packet, isSpawn bool) {
p := packet
if isSpawn {
p = packet.ReadHazel().GetUnderlyingPacket()
} else {
*SystemsMask = p.ReadPackedUInt32()
}
for i := 0; i < enum.TOTAL_SYSTEMTYPE; i++ {
if isSpawn {
if val, ok := Systems[i]; ok {
(*val).Read(p, isSpawn)
}
} else {
if (*SystemsMask & (1 << i)) != 0 {
(*Systems[i]).Read(p, isSpawn)
}
}
}
}

View File

@ -0,0 +1,34 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/systemtypes"
)
type SkeldShipStatus struct {
Systems map[int]*systemtypes.SystemType
SystemsMask uint32
}
func NewSkeldShipStatus() *SkeldShipStatus {
a := &SkeldShipStatus{}
a.Systems = make(map[int]*systemtypes.SystemType)
a.Systems[enum.SYSTEMTYPE_REACTOR] = systemtypes.SystemTypeCast(&systemtypes.ReactorSystem{})
a.Systems[enum.SYSTEMTYPE_ELECTRICAL] = systemtypes.SystemTypeCast(&systemtypes.SwitchSystem{})
a.Systems[enum.SYSTEMTYPE_O2] = systemtypes.SystemTypeCast(&systemtypes.LifeSuppSystem{})
a.Systems[enum.SYSTEMTYPE_MEDBAY] = systemtypes.SystemTypeCast(&systemtypes.MedScanSystem{})
a.Systems[enum.SYSTEMTYPE_SECURITY] = systemtypes.SystemTypeCast(&systemtypes.SecurityCameraSystem{})
a.Systems[enum.SYSTEMTYPE_COMMUNICATIONS] = systemtypes.SystemTypeCast(&systemtypes.HudOverrideSystem{})
a.Systems[enum.SYSTEMTYPE_DOORS] = systemtypes.SystemTypeCast(&systemtypes.AutoDoorsSystem{})
a.Systems[enum.SYSTEMTYPE_SABOTAGE] = systemtypes.SystemTypeCast(&systemtypes.SabotageSystem{})
return a
}
func (skeld *SkeldShipStatus) Write(packet *protocol.Packet, isSpawn bool) {
WriteShipStatus(skeld.Systems, &skeld.SystemsMask, packet, isSpawn)
}
func (skeld *SkeldShipStatus) Read(packet *protocol.Packet, isSpawn bool) {
ReadShipStatus(skeld.Systems, &skeld.SystemsMask, packet, isSpawn)
}

View File

@ -0,0 +1,46 @@
package innernetobjects
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type VoteBanSystem struct {
VotedPlayers []*VoteBanItem
}
type VoteBanItem struct {
Player uint32
Votes [3]uint32
}
func (ban *VoteBanSystem) Write(packet *protocol.Packet, isSpawn bool) {
p := protocol.NewEmptyPacket()
p.Write(byte(len(ban.VotedPlayers)))
for i := 0; i < len(ban.VotedPlayers); i++ {
p.WriteUInt32(ban.VotedPlayers[i].Player)
for j := 0; j < 3; j++ {
p.WritePackedUInt32(ban.VotedPlayers[i].Votes[j])
}
}
if isSpawn {
h := protocol.NewHazelFromRawData(0, p.Dump())
h.WriteToPacket(packet)
} else {
p.Copy(packet)
}
}
func (ban *VoteBanSystem) Read(packet *protocol.Packet, isSpawn bool) {
p := packet
if isSpawn {
p = packet.ReadHazel().GetUnderlyingPacket()
}
ban.VotedPlayers = make([]*VoteBanItem, p.Read())
for i := 0; i < len(ban.VotedPlayers); i++ {
ban.VotedPlayers[i].Player = p.ReadUInt32()
for j := 0; j < 3; j++ {
ban.VotedPlayers[i].Votes[j] = p.ReadPackedUInt32()
}
}
}

10
src/mapdata/go.mod Normal file
View File

@ -0,0 +1,10 @@
module codehub.onpointcoding.net/sean/go-susapp/mapdata
go 1.17
replace (
codehub.onpointcoding.net/sean/go-susapp/protocol => ../protocol
codehub.onpointcoding.net/sean/go-susapp/util => ../util
)
require codehub.onpointcoding.net/sean/go-susapp/util v1.0.0

16
src/mapdata/lobby.go Normal file
View File

@ -0,0 +1,16 @@
package mapdata
import "codehub.onpointcoding.net/sean/go-susapp/util"
var LobbySpawnPositions = []util.Vec2{
util.NewVec2(-1.6, 2.4),
util.NewVec2(-1.3, 2.5),
util.NewVec2(-1.1, 2.5),
util.NewVec2(-0.8, 2.6),
util.NewVec2(-0.6, 2.7),
util.NewVec2(0.7, 2.8),
util.NewVec2(0.9, 2.6),
util.NewVec2(1.1, 2.6),
util.NewVec2(1.4, 2.6),
util.NewVec2(1.7, 2.4),
}

View File

@ -0,0 +1,24 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type HostGameC2S struct {
Options *protocol.GameOptionsData
QuickChatMode byte
}
func (d *HostGameC2S) TypeCode() byte {
return 0x00
}
func (d *HostGameC2S) Write(packet *protocol.Packet) {
d.Options.Write(packet)
packet.Write(d.QuickChatMode)
}
func (d *HostGameC2S) Read(packet *protocol.Packet) {
d.Options = protocol.NewGameOptionsDataFromPacket(packet)
d.QuickChatMode = packet.Read()
}

View File

@ -0,0 +1,19 @@
package packets
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type HostGameS2C struct {
GameID int32
}
func (d *HostGameS2C) TypeCode() int {
return 0x00
}
func (d *HostGameS2C) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
}
func (d *HostGameS2C) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
}

View File

@ -0,0 +1,19 @@
package packets
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type JoinGameC2S struct {
GameID int32
}
func (d *JoinGameC2S) TypeCode() byte {
return 0x01
}
func (d *JoinGameC2S) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
}
func (d *JoinGameC2S) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
}

View File

@ -0,0 +1,19 @@
package packets
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type JoinGameS2C struct {
DisconnectReason int32
}
func (d *JoinGameS2C) TypeCode() byte {
return 0x01
}
func (d *JoinGameS2C) Write(packet *protocol.Packet) {
packet.WriteInt32(d.DisconnectReason)
}
func (d *JoinGameS2C) Read(packet *protocol.Packet) {
d.DisconnectReason = packet.ReadInt32()
}

View File

@ -0,0 +1,25 @@
package packets
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type JoinGameS2G struct {
GameID int32
JoiningClientID uint32
HostClientID uint32
}
func (d *JoinGameS2G) TypeCode() byte {
return 0x01
}
func (d *JoinGameS2G) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WriteUInt32(d.JoiningClientID)
packet.WriteUInt32(d.HostClientID)
}
func (d *JoinGameS2G) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.JoiningClientID = packet.ReadUInt32()
d.HostClientID = packet.ReadUInt32()
}

View File

@ -0,0 +1,19 @@
package packets
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
type StartGameH2G struct {
GameID int32
}
func (d *StartGameH2G) TypeCode() byte {
return 0x02
}
func (d *StartGameH2G) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
}
func (d *StartGameH2G) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
}

View File

@ -0,0 +1,22 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type RemoveGameS2C struct {
DisconnectReason byte
}
func (d *RemoveGameS2C) TypeCode() byte {
return 0x03
}
func (d *RemoveGameS2C) Write(packet *protocol.Packet) {
packet.Write(d.DisconnectReason)
}
func (d *RemoveGameS2C) Read(packet *protocol.Packet) {
d.DisconnectReason = packet.ReadDefault(enum.DISCONNECT_SERVER_REQUEST)
}

View File

@ -0,0 +1,28 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type RemovePlayerH2C struct {
GameID int32
DisconnectedClientID uint32
DisconnectReason byte
}
func (d *RemovePlayerH2C) TypeCode() byte {
return 0x04
}
func (d *RemovePlayerH2C) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WritePackedUInt32(d.DisconnectedClientID)
packet.Write(d.DisconnectReason)
}
func (d *RemovePlayerH2C) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.DisconnectedClientID = packet.ReadPackedUInt32()
d.DisconnectReason = packet.ReadDefault(enum.DISCONNECT_SERVER_REQUEST)
}

View File

@ -0,0 +1,31 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type RemovePlayerS2G struct {
GameID int32
DisconnectedClientID uint32
HostClientID uint32
DisconnectReason byte
}
func (d *RemovePlayerS2G) TypeCode() byte {
return 0x04
}
func (d *RemovePlayerS2G) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WriteUInt32(d.DisconnectedClientID)
packet.WriteUInt32(d.HostClientID)
packet.Write(d.DisconnectReason)
}
func (d *RemovePlayerS2G) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.DisconnectedClientID = packet.ReadUInt32()
d.HostClientID = packet.ReadUInt32()
d.DisconnectReason = packet.ReadDefault(enum.DISCONNECT_SERVER_REQUEST)
}

View File

@ -0,0 +1,36 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type GameDataAll struct {
GameID int32
Subpackets []*protocol.Hazel
}
func NewGameDataSingleSubpacket(GameID int32, h *GameDataSubpacket) *GameDataAll {
return &GameDataAll{
GameID,
[]*protocol.Hazel{(*h).AsHazel()},
}
}
func (d *GameDataAll) TypeCode() byte { return 0x05 }
func (d *GameDataAll) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
for i := 0; i < len(d.Subpackets); i++ {
d.Subpackets[i].WriteToPacket(packet)
}
}
func (d *GameDataAll) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
for packet.Remaining() > 0 {
a := protocol.NewHazel(packet)
d.Subpackets = append(d.Subpackets, a)
}
}
type GameDataSubpacket interface {
AsHazel() *protocol.Hazel
}

View File

@ -0,0 +1,38 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type GameDataTo struct {
GameID int32
TargetClientID uint32
Subpackets []*protocol.Hazel
}
func NewGameDataToSingleSubpacket(GameID int32, TargetClientID uint32, h *GameDataSubpacket) *GameDataTo {
return &GameDataTo{
GameID,
TargetClientID,
[]*protocol.Hazel{(*h).AsHazel()},
}
}
func (d *GameDataTo) TypeCode() byte { return 0x06 }
func (d *GameDataTo) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WritePackedUInt32(d.TargetClientID)
for i := 0; i < len(d.Subpackets); i++ {
d.Subpackets[i].WriteToPacket(packet)
}
}
func (d *GameDataTo) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.TargetClientID = packet.ReadPackedUInt32()
for packet.Remaining() > 0 {
a := protocol.NewHazel(packet)
d.Subpackets = append(d.Subpackets, a)
}
}

View File

@ -0,0 +1,37 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type JoinedGameH2C struct {
GameID int32
JoinedClientID uint32
HostClientID uint32
OtherClientIDs []uint32
}
func (d *JoinedGameH2C) TypeCode() byte {
return 0x07
}
func (d *JoinedGameH2C) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WriteUInt32(d.JoinedClientID)
packet.WriteUInt32(d.HostClientID)
packet.WritePackedUInt32(uint32(len(d.OtherClientIDs)))
for i := 0; i < len(d.OtherClientIDs); i++ {
packet.WritePackedUInt32(d.OtherClientIDs[i])
}
}
func (d *JoinedGameH2C) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.JoinedClientID = packet.ReadUInt32()
d.HostClientID = packet.ReadUInt32()
l := int(packet.ReadUInt32())
d.OtherClientIDs = make([]uint32, l)
for i := 0; i < l; i++ {
d.OtherClientIDs[i] = packet.ReadUInt32()
}
}

View File

@ -0,0 +1,27 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type EndGameH2G struct {
GameID int32
GameOverReason byte
ShowAd bool
}
func (d *EndGameH2G) TypeCode() byte {
return 0x08
}
func (d *EndGameH2G) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.Write(d.GameOverReason)
packet.WriteBool(d.ShowAd)
}
func (d *EndGameH2G) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.GameOverReason = packet.Read()
d.ShowAd = packet.ReadBool()
}

View File

@ -0,0 +1,5 @@
package packets
// GetGameListAll is a legacy packet
type GetGameListAll struct {
}

View File

@ -0,0 +1,27 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type AlterGameH2G struct {
GameID int32
TagID byte
TagValue byte
}
func (d *AlterGameH2G) TypeCode() byte {
return 0x0a
}
func (d *AlterGameH2G) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.Write(d.TagID)
packet.Write(d.TagValue)
}
func (d *AlterGameH2G) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.TagID = packet.Read()
d.TagValue = packet.Read()
}

View File

@ -0,0 +1,30 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type KickPlayerH2G struct {
GameID int32
KickedClientID uint32
IsBanned bool
DisconnectReason byte
}
func (d *KickPlayerH2G) TypeCode() byte {
return 0x0b
}
func (d *KickPlayerH2G) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WritePackedUInt32(d.KickedClientID)
packet.WriteBool(d.IsBanned)
packet.Write(d.DisconnectReason)
}
func (d *KickPlayerH2G) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.KickedClientID = packet.ReadPackedUInt32()
d.IsBanned = packet.ReadBool()
d.DisconnectReason = packet.Read()
}

View File

@ -0,0 +1,24 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type WaitForHostC2H struct {
GameID int32
RejoiningClientID uint32
}
func (d *WaitForHostC2H) TypeCode() byte {
return 0x0c
}
func (d *WaitForHostC2H) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WriteUInt32(d.RejoiningClientID)
}
func (d *WaitForHostC2H) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.RejoiningClientID = packet.ReadUInt32()
}

View File

@ -0,0 +1,26 @@
package packets
import (
"net"
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type RedirectS2C struct {
IPAddress net.IP
Port uint16
}
func (d *RedirectS2C) TypeCode() byte {
return 0x0d
}
func (d *RedirectS2C) Write(packet *protocol.Packet) {
packet.WriteIP(d.IPAddress)
packet.WriteUInt16(d.Port)
}
func (d *RedirectS2C) Read(packet *protocol.Packet) {
d.IPAddress = packet.ReadIP()
d.Port = packet.ReadUInt16()
}

View File

@ -0,0 +1,42 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
"codehub.onpointcoding.net/sean/go-susapp/util"
)
type ReselectServerS2C struct {
Version byte
MasterServers []*util.MasterServer
}
var currentReselectServerVerion byte = 1
func (d *ReselectServerS2C) TypeCode() byte {
return 0x0e
}
func (d *ReselectServerS2C) Write(packet *protocol.Packet) {
packet.Write(currentReselectServerVerion)
packet.WritePackedUInt32(uint32(len(d.MasterServers)))
for i := 0; i < len(d.MasterServers); i++ {
packet.WriteString(d.MasterServers[i].Name)
packet.WriteIP(d.MasterServers[i].IPAddress)
packet.WriteUInt16(d.MasterServers[i].Port)
packet.WritePackedUInt32(d.MasterServers[i].NumberOfConnections)
}
}
func (d *ReselectServerS2C) Read(packet *protocol.Packet) {
d.Version = packet.Read()
l := int(packet.ReadPackedUInt32())
d.MasterServers = make([]*util.MasterServer, l)
for i := 0; i < l; i++ {
d.MasterServers[i] = &util.MasterServer{
Name: packet.ReadString(),
IPAddress: packet.ReadIP(),
Port: packet.ReadUInt16(),
NumberOfConnections: packet.ReadPackedUInt32(),
}
}
}

View File

@ -0,0 +1,29 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type GetGameListV2C2S struct {
Unknown02 int32
Options *protocol.GameOptionsData
QuickChatMode byte
}
var currentUnknown02Value int32 = 0x02
func (d *GetGameListV2C2S) TypeCode() byte {
return 0x10
}
func (d *GetGameListV2C2S) Write(packet *protocol.Packet) {
packet.WritePackedInt32(currentUnknown02Value)
d.Options.Write(packet)
packet.Write(d.QuickChatMode)
}
func (d *GetGameListV2C2S) Read(packet *protocol.Packet) {
d.Unknown02 = packet.ReadInt32()
d.Options = protocol.NewGameOptionsDataFromPacket(packet)
d.QuickChatMode = packet.Read()
}

View File

@ -0,0 +1,30 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type GetGameListV2S2C struct {
GameCounts *protocol.Hazel // tag = 0x01
GameList *protocol.Hazel // tag = 0x00
}
func (d *GetGameListV2S2C) TypeCode() byte {
return 0x10
}
func (d *GetGameListV2S2C) Write(packet *protocol.Packet) {
d.GameCounts.WriteToPacket(packet)
d.GameList.WriteToPacket(packet)
}
func (d *GetGameListV2S2C) Read(packet *protocol.Packet) {
for packet.Remaining() > 0 {
h := packet.ReadHazel()
if h.GetTag() == 0x01 {
d.GameCounts = h
} else if h.GetTag() == 0x00 {
d.GameList = h
}
}
}

View File

@ -0,0 +1,27 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type ReportPlayerC2S struct {
GameID int32
ReportedClientID uint32
ReportReason byte
}
func (d *ReportPlayerC2S) TypeCode() byte {
return 0x11
}
func (d *ReportPlayerC2S) Write(packet *protocol.Packet) {
packet.WriteInt32(d.GameID)
packet.WritePackedUInt32(d.ReportedClientID)
packet.Write(d.ReportReason)
}
func (d *ReportPlayerC2S) Read(packet *protocol.Packet) {
d.GameID = packet.ReadInt32()
d.ReportedClientID = packet.ReadPackedUInt32()
d.ReportReason = packet.Read()
}

View File

@ -0,0 +1,30 @@
package packets
import (
"codehub.onpointcoding.net/sean/go-susapp/protocol"
)
type ReportPlayerS2C struct {
ReportedClientID uint32
ReportReason uint32
ReportOutcome byte
ReportedPlayerName string
}
func (d *ReportPlayerS2C) TypeCode() byte {
return 0x11
}
func (d *ReportPlayerS2C) Write(packet *protocol.Packet) {
packet.WritePackedUInt32(d.ReportedClientID)
packet.WriteUInt32(d.ReportReason)
packet.Write(d.ReportOutcome)
packet.WriteString(d.ReportedPlayerName)
}
func (d *ReportPlayerS2C) Read(packet *protocol.Packet) {
d.ReportedClientID = packet.ReadPackedUInt32()
d.ReportReason = packet.ReadUInt32()
d.ReportOutcome = packet.Read()
d.ReportedPlayerName = packet.ReadString()
}

16
src/packets/gamepacket.go Normal file
View File

@ -0,0 +1,16 @@
package packets
import "codehub.onpointcoding.net/sean/go-susapp/protocol"
// PacketBase PacketType
// C2S = client to server
// S2C = server to client
// S2G = server to game (broadcast to all clients from the server)
// H2G = host to game (broadcast to all clients from the host)
type GamePacket interface {
Write(packet *protocol.Packet)
Read(packet *protocol.Packet)
TypeCode() byte
}

15
src/packets/go.mod Normal file
View File

@ -0,0 +1,15 @@
module codehub.onpointcoding.net/sean/go-susapp/packets
go 1.17
replace (
codehub.onpointcoding.net/sean/go-susapp/enum => ../enum
codehub.onpointcoding.net/sean/go-susapp/protocol => ../protocol
codehub.onpointcoding.net/sean/go-susapp/util => ../util
)
require (
codehub.onpointcoding.net/sean/go-susapp/enum v1.0.0
codehub.onpointcoding.net/sean/go-susapp/protocol v1.0.0
codehub.onpointcoding.net/sean/go-susapp/util v1.0.0
)

60
src/protocol/gamelist.go Normal file
View File

@ -0,0 +1,60 @@
package protocol
import (
"net"
)
type GameList struct {
Games []GameListItem
}
func NewGameList(packet *Packet) *GameList {
games := make([]GameListItem, 0)
for packet.Remaining() > 0 {
games = append(games, *NewGameListItem(packet))
}
return &GameList{games}
}
func (list *GameList) WriteToPacket(packet *Packet) {
for i := 0; i < len(list.Games); i++ {
list.Games[i].WriteToPacket(packet)
}
}
type GameListItem struct {
IPAddress net.IP
Port uint16
GameID int32
HostPlayer string
NumberOfPlayers byte
Age uint32
MapID byte
NumberOfImpostors byte
MaxNumberOfPlayers byte
}
func NewGameListItem(packet *Packet) *GameListItem {
ip := packet.ReadIP()
port := packet.ReadUInt16()
gameId := packet.ReadInt32()
hostPlayer := packet.ReadString()
numberOfPlayers := packet.Read()
age := packet.ReadPackedUInt32()
mapId := packet.Read()
numberOfImpostors := packet.Read()
maxNumberOfPlayers := packet.Read()
return &GameListItem{ip, port, gameId, hostPlayer, numberOfPlayers, age, mapId, numberOfImpostors, maxNumberOfPlayers}
}
func (item *GameListItem) WriteToPacket(packet *Packet) {
packet.WriteIP(item.IPAddress)
packet.WriteUInt16(item.Port)
packet.WriteInt32(item.GameID)
packet.WriteString(item.HostPlayer)
packet.Write(item.NumberOfPlayers)
packet.WritePackedUInt32(item.Age)
packet.Write(item.MapID)
packet.Write(item.NumberOfImpostors)
packet.Write(item.MaxNumberOfPlayers)
}

View File

@ -0,0 +1,96 @@
package protocol
type GameOptionsData struct {
Version byte
MaxNumberOfPlayers byte
Keywords uint32
Maps byte
PlayerSpeedModifier float32
CrewmateLightModifier float32
ImpostorLightModifier float32
KillCooldown float32
NumberOfCommonTasks byte
NumberOfLongTasks byte
NumberOfShortTasks byte
NumberOfEmergencyMeetings uint32
NumberOfImpostors byte
KillDistance byte
DiscussionTime uint32
VotingTime uint32
IsDefaults bool
EmergencyCooldown byte
ConfirmEjects bool
VisualTasks bool
AnonymousVotes bool
TaskBarUpdates byte
}
var currentGameOptionsVersion byte = 4
// 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}
}
// Create new options from packet data
func NewGameOptionsDataFromPacket(packet *Packet) *GameOptionsData {
a := NewDefaultGameOptionsData()
a.Read(packet)
return a
}
func (data *GameOptionsData) Write(packet *Packet) {
p := NewEmptyPacket()
p.Write(data.Version)
p.Write(data.MaxNumberOfPlayers)
p.WriteUInt32(data.Keywords)
p.Write(data.Maps)
p.WriteFloat(data.PlayerSpeedModifier)
p.WriteFloat(data.CrewmateLightModifier)
p.WriteFloat(data.ImpostorLightModifier)
p.WriteFloat(data.KillCooldown)
p.Write(data.NumberOfCommonTasks)
p.Write(data.NumberOfLongTasks)
p.Write(data.NumberOfShortTasks)
p.WritePackedUInt32(data.NumberOfEmergencyMeetings)
p.Write(data.NumberOfImpostors)
p.Write(data.KillDistance)
p.WriteUInt32(data.DiscussionTime)
p.WriteUInt32(data.VotingTime)
p.WriteBool(data.IsDefaults)
p.Write(data.EmergencyCooldown)
p.WriteBool(data.ConfirmEjects)
p.WriteBool(data.VisualTasks)
p.WriteBool(data.AnonymousVotes)
p.Write(data.TaskBarUpdates)
packet.WritePackedUInt32(uint32(p.Size()))
p.Copy(packet)
}
func (data *GameOptionsData) Read(packet *Packet) {
l := packet.ReadPackedUInt32()
p := NewPacket(packet.ReadBytes(int(l)))
data.Version = p.Read()
data.MaxNumberOfPlayers = p.Read()
data.Keywords = p.ReadUInt32()
data.Maps = p.Read()
data.PlayerSpeedModifier = p.ReadFloat()
data.CrewmateLightModifier = p.ReadFloat()
data.ImpostorLightModifier = p.ReadFloat()
data.KillCooldown = p.ReadFloat()
data.NumberOfCommonTasks = p.Read()
data.NumberOfLongTasks = p.Read()
data.NumberOfShortTasks = p.Read()
data.NumberOfEmergencyMeetings = p.ReadPackedUInt32()
data.NumberOfImpostors = p.Read()
data.KillDistance = p.Read()
data.DiscussionTime = p.ReadUInt32()
data.VotingTime = p.ReadUInt32()
data.IsDefaults = p.ReadBool()
data.EmergencyCooldown = p.ReadDefault(15)
data.ConfirmEjects = p.ReadBoolDefault(true)
data.VisualTasks = p.ReadBoolDefault(true)
data.AnonymousVotes = p.ReadBoolDefault(false)
data.TaskBarUpdates = p.ReadDefault(0)
}

6
src/protocol/go.mod Normal file
View File

@ -0,0 +1,6 @@
module codehub.onpointcoding.net/sean/go-susapp/protocol
go 1.17
replace codehub.onpointcoding.net/sean/go-susapp/util => ../util
require codehub.onpointcoding.net/sean/go-susapp/util v1.0.0

View File

@ -0,0 +1,59 @@
package protocol
type Hazel struct {
p *Packet
l uint16
t byte
payload *HazelPayload
readPacket bool
}
func NewHazel(packet *Packet) *Hazel {
l := packet.ReadUInt16()
t := packet.Read()
p := NewPacket(packet.ReadBytes(int(l)))
return &Hazel{p, l, t, nil, true}
}
func NewHazelFromPayload(payload *HazelPayload) *Hazel {
p := NewEmptyPacket()
return &Hazel{p, 0, (*payload).TypeCode(), payload, false}
}
func NewHazelFromRawData(tag byte, b []byte) *Hazel {
p := NewEmptyPacket()
p.WriteBytes(b)
return &Hazel{p, 0, tag, nil, true}
}
func (hazel *Hazel) WriteToPacket(packet *Packet) {
if hazel.readPacket {
packet.WriteUInt16(hazel.l)
packet.Write(hazel.t)
hazel.p.Copy(packet)
} else {
p := NewEmptyPacket()
(*hazel.payload).Write(p)
packet.WriteUInt16(uint16(p.Size()))
packet.Write((*hazel.payload).TypeCode())
p.Copy(packet)
}
}
func (hazel *Hazel) GetUnderlyingPacket() *Packet {
return hazel.p
}
func (hazel *Hazel) Length() uint16 {
return hazel.l
}
func (hazel *Hazel) GetTag() byte {
return hazel.t
}
type HazelPayload interface {
Write(packet *Packet)
Read(packet *Packet)
TypeCode() byte
}

View File

@ -0,0 +1,29 @@
package protocol
type SpawnComponent struct {
NetID uint32
ComponentData *Hazel
}
func (d *SpawnComponent) Write(packet *Packet) {
packet.WritePackedUInt32(d.NetID)
d.ComponentData.WriteToPacket(packet)
}
func (d *SpawnComponent) Read(packet *Packet) {
d.NetID = packet.ReadPackedUInt32()
d.ComponentData = NewHazel(packet)
}
type UpdateComponent struct {
NetID uint32
RawData *Packet
}
func (d *UpdateComponent) Write(packet *Packet) {
packet.WritePackedUInt32(d.NetID)
d.RawData.Copy(packet)
}
func (d *UpdateComponent) Read(packet *Packet) {
d.NetID = packet.ReadPackedUInt32()
d.RawData = packet
}

241
src/protocol/packet.go Normal file
View File

@ -0,0 +1,241 @@
package protocol
import (
"encoding/binary"
"math"
"net"
"codehub.onpointcoding.net/sean/go-susapp/util"
)
type Packet struct {
data []byte
idx int
l int
}
func NewPacket(d []byte) *Packet {
return &Packet{
data: d,
l: len(d),
}
}
func NewEmptyPacket() *Packet {
return &Packet{
data: []byte{},
l: 0,
}
}
func (packet *Packet) Seek(v int) {
packet.idx = v
}
func (packet *Packet) Size() int {
return len(packet.data)
}
func (packet *Packet) Dump() []byte {
return packet.data
}
func (packet *Packet) Remaining() int {
return packet.Size() - packet.idx
}
func (packet *Packet) Copy(p *Packet) {
p.WriteBytes(packet.data)
}
func (packet *Packet) Read() byte {
return packet.ReadDefault(0)
}
func (packet *Packet) ReadDefault(d byte) byte {
if packet.idx >= len(packet.data) {
return d
}
v := packet.data[packet.idx]
packet.idx++
return v
}
func (packet *Packet) Write(v byte) {
packet.data = append(packet.data, v)
}
func (packet *Packet) ReadBytes(n int) []byte {
b := make([]byte, n)
for i := 0; i < n; i++ {
b[i] = packet.Read()
}
return b
}
func (packet *Packet) WriteBytes(v []byte) {
packet.data = append(packet.data, v...)
}
func (packet *Packet) ReadInt16() int16 {
return int16(packet.ReadUInt16())
}
func (packet *Packet) WriteInt16(v int16) {
packet.WriteUInt16(uint16(v))
}
func (packet *Packet) ReadUInt16() uint16 {
return binary.LittleEndian.Uint16(packet.ReadBytes(2))
}
func (packet *Packet) WriteUInt16(v uint16) {
var b [2]byte
binary.LittleEndian.PutUint16(b[:], v)
packet.WriteBytes(b[:])
}
func (packet *Packet) ReadUInt16BigEndian() uint16 {
return binary.BigEndian.Uint16(packet.ReadBytes(2))
}
func (packet *Packet) WriteUInt16BigEndian(v uint16) {
var b [2]byte
binary.BigEndian.PutUint16(b[:], v)
packet.WriteBytes(b[:])
}
func (packet *Packet) ReadInt32() int32 {
return int32(packet.ReadUInt32())
}
func (packet *Packet) WriteInt32(v int32) {
packet.WriteUInt32(uint32(v))
}
func (packet *Packet) ReadUInt32() uint32 {
return binary.LittleEndian.Uint32(packet.ReadBytes(4))
}
func (packet *Packet) WriteUInt32(v uint32) {
var b [4]byte
binary.LittleEndian.PutUint32(b[:], v)
packet.WriteBytes(b[:])
}
func (packet *Packet) ReadFloat() float32 {
return math.Float32frombits(packet.ReadUInt32())
}
func (packet *Packet) WriteFloat(v float32) {
var b [4]byte
binary.LittleEndian.PutUint32(b[:], math.Float32bits(v))
packet.WriteBytes(b[:])
}
func (packet *Packet) ReadBool() bool {
return packet.Read() == 1
}
func (packet *Packet) ReadBoolDefault(v bool) bool {
if v {
return packet.ReadDefault(1) == 1
} else {
return packet.ReadDefault(0) == 1
}
}
func (packet *Packet) WriteBool(v bool) {
if v {
packet.Write(1)
} else {
packet.Write(0)
}
}
func (packet *Packet) ParsePackedInt32() int32 {
return int32(packet.ReadPackedUInt32())
}
func (packet *Packet) WritePackedInt32(v int32) {
packet.WritePackedUInt32(uint32(v))
}
func (packet *Packet) ReadPackedUInt32() uint32 {
readMore := true
shift := 0
var output uint32 = 0
for readMore {
b := packet.Read()
if b > 0x80 {
readMore = true
b ^= 0x80
} else {
readMore = false
}
output |= uint32(b) << shift
shift += 7
}
return output
}
func (packet *Packet) WritePackedUInt32(v uint32) {
writeMore := true
for writeMore {
b := byte(v & 0xff)
if v >= 0x80 {
b |= 0x80
}
packet.Write(b)
v >>= 7
writeMore = v > 0
}
}
func (packet *Packet) ReadString() string {
l := int(packet.ReadPackedUInt32())
return string(packet.ReadBytes(l))
}
func (packet *Packet) WriteString(v string) {
l := len(v)
packet.WritePackedUInt32(uint32(l))
packet.WriteBytes([]byte(v))
}
func (packet *Packet) ReadHazel() *Hazel {
return NewHazel(packet)
}
func (packet *Packet) WriteHazel(hazel *Hazel) {
hazel.WriteToPacket(packet)
}
func (packet *Packet) ReadIP() net.IP {
b := packet.ReadBytes(4)
return net.IPv4(b[0], b[1], b[2], b[3])
}
func (packet *Packet) WriteIP(v net.IP) {
packet.Write(v[0])
packet.Write(v[1])
packet.Write(v[2])
packet.Write(v[3])
}
func (packet *Packet) ReadVector2() util.Vec2 {
x := float32(packet.ReadUInt16()) / 65535
y := float32(packet.ReadUInt16()) / 65535
return util.NewVec2(util.Lerp(-50, 50, x), util.Lerp(-50, 50, y))
}
func (packet *Packet) WriteVector2(v util.Vec2) {
x := uint16(util.LerpReverse(-50, 50, v.X) * 65535)
y := uint16(util.LerpReverse(-50, 50, v.Y) * 65535)
packet.WriteUInt16(x)
packet.WriteUInt16(y)
}

View File

@ -0,0 +1,161 @@
package protocol
import (
"fmt"
"net"
"sync"
)
const (
PacketNormal = 0x0
PacketReliable = 0x1
PacketHello = 0x8
PacketDisconnect = 0x9
PacketAcknowledgement = 0xa
PacketFragment = 0xb
PacketPing = 0xc
)
type PacketHandler struct {
conn *net.UDPConn
addr *net.UDPAddr
HandleNormalPacket func(net *PacketHandler, h []*Hazel)
HandleReliablePacket func(net *PacketHandler, id uint16, h []*Hazel)
HandleForceDisconnectPacket func(net *PacketHandler, h *Hazel)
HandleNormalDisconnectPacket func(net *PacketHandler)
HandleAcknowledgementPacket func(net *PacketHandler, nonce uint16, missing byte)
HandlePingPacket func(net *PacketHandler, id uint16)
currentNonce uint16
nonceMutex sync.Mutex
currentSequence uint16
sequenceMutex sync.Mutex
}
func NewPacketHandler(conn *net.UDPConn, addr *net.UDPAddr) *PacketHandler {
return &PacketHandler{conn: conn, addr: addr, currentNonce: 0}
}
func (ph *PacketHandler) GetNonce() uint16 {
ph.nonceMutex.Lock()
a := ph.currentNonce
ph.currentNonce++
ph.nonceMutex.Unlock()
return a
}
func (ph *PacketHandler) GetSequence() uint16 {
ph.sequenceMutex.Lock()
a := ph.currentSequence
ph.currentSequence++
ph.sequenceMutex.Unlock()
return a
}
func (ph *PacketHandler) ReadPacket(data []byte) {
p := NewPacket(data)
b := p.Read()
if b == PacketNormal {
var h []*Hazel
for p.Remaining() > 0 {
h = append(h, p.ReadHazel())
}
ph.HandleNormalPacket(ph, h)
} else if b == PacketReliable {
id := p.ReadUInt16BigEndian()
var h []*Hazel
for p.Remaining() > 0 {
h = append(h, p.ReadHazel())
}
if len(h) > 0 {
ph.HandleReliablePacket(ph, id, h)
}
} else if b == PacketHello {
// Client doesn't need to read this
} else if b == PacketDisconnect {
isForced := p.ReadBool()
if isForced {
ph.HandleForceDisconnectPacket(ph, p.ReadHazel())
} else {
ph.HandleNormalDisconnectPacket(ph)
}
} else if b == PacketAcknowledgement {
nonce := p.ReadUInt16BigEndian()
missing := p.Read()
ph.HandleAcknowledgementPacket(ph, nonce, missing)
} else if b == PacketFragment {
// Currently not used
} else if b == PacketPing {
id := p.ReadUInt16BigEndian()
ph.HandlePingPacket(ph, id)
}
}
func (ph *PacketHandler) NewPacketFromType(packetType byte) *Packet {
return NewPacket([]byte{packetType})
}
func (ph *PacketHandler) SendPacket(packet *Packet) {
_, err := ph.conn.Write(packet.data)
if err != nil {
fmt.Printf("Failed to send packet to server %v\n", err)
}
}
func (ph *PacketHandler) SendNormalPacket(h []*Hazel) {
p := ph.NewPacketFromType(0x00)
for i := 0; i < len(h); i++ {
p.WriteHazel(h[i])
}
ph.SendPacket(p)
}
func (ph *PacketHandler) SendReliablePacket(nonce uint16, h []*Hazel) {
p := ph.NewPacketFromType(0x01)
p.WriteUInt16BigEndian(nonce)
for i := 0; i < len(h); i++ {
p.WriteHazel(h[i])
}
ph.SendPacket(p)
}
func (ph *PacketHandler) SendHelloPacket(nonce uint16, hazelVersion byte, clientVersion int32, username string, authNonce uint32, keyword uint32, quickChatMode byte) {
p := ph.NewPacketFromType(0x08)
p.WriteUInt16BigEndian(nonce)
p.Write(hazelVersion)
p.WriteInt32(clientVersion)
p.WriteString(username)
p.WriteUInt32(authNonce)
p.WriteUInt32(keyword)
p.Write(quickChatMode)
ph.SendPacket(p)
}
func (ph *PacketHandler) SendForceDisconnectPacket(h *Hazel) {
p := ph.NewPacketFromType(0x09)
p.Write(0x01)
p.WriteHazel(h)
ph.SendPacket(p)
}
func (ph *PacketHandler) SendNormalDisconnectPacket() {
p := ph.NewPacketFromType(0x09)
p.Write(0x00)
ph.SendPacket(p)
}
func (ph *PacketHandler) SendAcknowledgementPacket(nonce uint16, missing byte) {
p := ph.NewPacketFromType(0x0a)
p.WriteUInt16BigEndian(nonce)
p.Write(missing)
ph.SendPacket(p)
}
func (ph *PacketHandler) SendPingPacket(id uint16) {
p := ph.NewPacketFromType(0x0c)
p.WriteUInt16(id)
ph.conn.WriteToUDP(p.data, ph.addr)
}
func (ph *PacketHandler) Close() {
ph.conn.Close()
}

View File

@ -0,0 +1,53 @@
package protocol
type PlayerData struct {
PlayerID byte
Name string
ColorID uint32
HatID uint32
PetID uint32
SkinID uint32
Flags byte
Tasks []*TaskInfo
}
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(player.Flags)
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.Flags = packet.Read()
player.Tasks = make([]*TaskInfo, packet.Read())
for i := 0; i < len(player.Tasks); i++ {
player.Tasks[i].Read(packet)
}
}
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()
}

3
src/states/go.mod Normal file
View File

@ -0,0 +1,3 @@
module codehub.onpointcoding.net/sean/go-susapp/states
go 1.17

Some files were not shown because too many files have changed in this diff Show More