This commit is contained in:
2024-10-26 12:41:37 +02:00
parent 78b2a2f022
commit a6a7a94c20
5 changed files with 2021 additions and 135 deletions

350
main.go
View File

@@ -28,6 +28,7 @@ const (
var maxPlayers int32
var icon string
var iconData []byte
var serverID = make([]byte, 20)
var serverPrivateKey *rsa.PrivateKey
@@ -38,7 +39,8 @@ var usernameRegex = regexp.MustCompile("^[a-zA-Z0-9_]{3,16}$")
var world World
func readIcon(fileName string) (icon string) {
iconData, err := os.ReadFile(fileName)
var err error
iconData, err = os.ReadFile(fileName)
if err != nil {
return
}
@@ -85,6 +87,7 @@ func main() {
LabelInt: 0,
URL: "https://brn.systems",
}},
TickRate: 20,
}
var err error
@@ -125,7 +128,6 @@ func handleRequest(conn net.Conn) {
var player = Player{
state: 0,
conn: conn,
name: "",
version: 0,
requestedAddress: "",
requestedPort: 0,
@@ -195,9 +197,9 @@ func handleRequest(conn net.Conn) {
errOut = err
break
}
player.name = username
player.Entity.Name = username
player.uuid = playerUUID
if !usernameRegex.MatchString(player.name) {
if !usernameRegex.MatchString(player.Entity.Name) {
errOut = errors.New("bad username")
break
}
@@ -235,7 +237,7 @@ func handleRequest(conn net.Conn) {
errOut = errors.New("joined session not found")
break
}
if player.profile.ID != strings.Replace(player.uuid.String(), "-", "", -1) || player.profile.Name != player.name {
if player.profile.ID != strings.Replace(player.uuid.String(), "-", "", -1) || player.profile.Name != player.Entity.Name {
errOut = errors.New("wrong session name")
break
}
@@ -354,6 +356,341 @@ func handleRequest(conn net.Conn) {
case 4:
switch packetID {
case 0x00: // Confirm Teleportation
teleportID, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
// Handle teleport confirmation logic here
if player.teleportID == teleportID {
player.waitingForTeleportConfirm = false
}
case 0x01: // Query Block Entity Tag
transactionID, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
var position BlockPosition
err = position.receivePosition(packetData)
if err != nil {
errOut = err
break
}
// Handle block entity query logic here
player.queryBlockEntityTag(transactionID, position)
case 0x02: // Change Difficulty
difficulty, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
// Change difficulty logic, ensure player is an operator
if player.PermissionLevel >= 2 {
world.Difficulty = difficulty
for _, iterPlayer := range world.Players {
iterPlayer.sendDifficulty()
}
}
case 0x03: // Acknowledge Message
messageCount, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
// Acknowledge message logic here
player.acknowledgeMessage(messageCount)
case 0x04, 0x05: // Chat Command & Signed Chat Command
command, err := receiveString(packetData)
if err != nil {
errOut = err
break
}
player.processChatCommand(command)
case 0x06: // Chat Message
message, err := receiveString(packetData)
if err != nil {
errOut = err
break
}
_ = receiveInt64(packetData)
_ = receiveInt64(packetData)
// Handle the chat message here
player.handleChatMessage(message)
case 0x07: // Player Session
//sessionId, err := receiveUUID(packetData)
//if err != nil {
// errOut = err
// break
//}
//expiresAt := receiveInt64(packetData)
//pubKeyLen, err := receiveVarint(packetData)
//
//maybe implement in the future
case 0x08: // Chunk Batch Received
_ = receiveFloat32(packetData) //chunks per tick
case 0x09: // Client Status
actionID, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
switch actionID {
case 0:
player.sendRespawn(true, true)
case 1:
player.sendAwardStatistics()
}
case 0x0A: // Client Information
// Read Locale (16-character string)
locale, err := receiveString(packetData)
if err != nil {
errOut = err
break
}
player.locale = locale
// Read View Distance (1 byte)
viewDistance, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
player.viewDistance = int8(viewDistance)
// Read Chat Mode (VarInt Enum)
chatMode, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
player.chatMode = chatMode
// Read Chat Colors (Boolean)
chatColors, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
player.chatColors = chatColors != 0
// Read Displayed Skin Parts (Unsigned Byte)
displayedSkinParts, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
player.skinParts = displayedSkinParts
// Read Main Hand (VarInt Enum)
mainHand, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
player.isRightHanded = mainHand == 1
// Read Enable Text Filtering (Boolean)
enableTextFiltering, err := receiveBool(packetData)
if err != nil {
errOut = err
break
}
player.textFiltering = enableTextFiltering
// Read Allow Server Listings (Boolean)
allowServerListings, err := receiveBool(packetData)
if err != nil {
errOut = err
break
}
player.serverListing = allowServerListings
// Successfully parsed the packet
errOut = nil
case 0x0B: // Command Suggestions Request
transactionId, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
text, err := receiveString(packetData)
if err != nil {
errOut = err
break
}
player.requestCommandSuggestions(transactionId, text)
case 0x0C: // Acknowledge Configuration
player.state = 3
case 0x0D: // Click Container Button
windowID, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
if windowID != player.WindowID {
break
}
buttonID, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
_ = buttonID
//TODO implement logic
case 0x0E: // Click Container
// Parse fields and handle click container logic here
windowID, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
if windowID != player.WindowID {
break
}
// Read StateID (VarInt)
stateID, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
// Read Slot (Short)
var slot int16
slot = receiveInt16(packetData)
if err != nil {
errOut = err
break
}
// Read Button (Byte)
button, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
// Read Mode (VarInt)
mode, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
// Read number of ChangedSlots (VarInt)
changedSlotsCount, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
var packet ClickContainerPacket
// Initialize ChangedSlots slice
packet.ChangedSlots = make([]Slot, changedSlotsCount)
// Read each Slot in the ChangedSlots array
for i := 0; i < int(changedSlotsCount); i++ {
slotData, err := readSlot(data)
if err != nil {
errOut = err
break
}
packet.ChangedSlots[i] = slotData
}
// Read CarriedItem (ItemStack)
carriedItem, err := readSlot(data)
if err != nil {
errOut = err
break
}
// Populate the packet struct
packet.WindowID = windowID
packet.StateID = stateID
packet.Slot = slot
packet.Button = int8(button)
packet.Mode = mode
packet.CarriedItem = carriedItem
player.handleClickContainer(packet)
case 0x0F: // Close Container
windowID, err := packetData.ReadByte()
if err != nil {
errOut = err
break
}
player.sendCloseContainer(windowID)
case 0x10: // Change Container ItemStack State
slotID, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
windowID, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
state, err := receiveBool(packetData)
if err != nil {
errOut = err
break
}
player.changeContainerSlotState(slotID, windowID, state)
case 0x11: // Cookie Response
key, err := receiveString(packetData)
if err != nil {
errOut = err
break
}
hasPayload, err := receiveBool(packetData)
if err != nil {
errOut = err
break
}
// Handle cookie response logic here
player.handleCookieResponse(key, hasPayload)
case 0x12: // Serverbound Plugin Message
channel, err := receiveString(packetData)
if err != nil {
errOut = err
break
}
data := packetData // Rest is the byte array
player.handlePluginMessage(channel, data)
case 0x13: // Debug Sample Subscription
sampleType, err := receiveVarint(packetData)
if err != nil {
errOut = err
break
}
player.subscribeToDebugSample(sampleType)
case 0x14: // Edit Book
// Parse fields and handle book editing logic
player.handleEditBook(packetData)
default:
errOut = fmt.Errorf("unexpected packet %x in play state", packetID)
log.Println(errOut)
@@ -368,7 +705,8 @@ func handleRequest(conn net.Conn) {
}
}
if errOut != nil {
if //goland:noinspection GoDfaConstantCondition
errOut != nil {
log.Println(errOut.Error())
_ = player.sendDisconnect(fmt.Sprintf("Your server thread crashed: %s", errOut.Error()))
}