{"id":13529689,"url":"https://github.com/BRA1L0R/go-mcproto","last_synced_at":"2025-04-01T17:30:47.633Z","repository":{"id":46011514,"uuid":"372461375","full_name":"BRA1L0R/go-mcproto","owner":"BRA1L0R","description":"Minecraft Protocol implementation in Go","archived":true,"fork":false,"pushed_at":"2022-06-05T08:36:07.000Z","size":5230,"stargazers_count":44,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-01T13:07:33.453Z","etag":null,"topics":["bot","mcproto","minecraft","protocol","spigot"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BRA1L0R.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-31T10:03:47.000Z","updated_at":"2024-09-29T11:27:30.000Z","dependencies_parsed_at":"2022-07-20T06:13:47.475Z","dependency_job_id":null,"html_url":"https://github.com/BRA1L0R/go-mcproto","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRA1L0R%2Fgo-mcproto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRA1L0R%2Fgo-mcproto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRA1L0R%2Fgo-mcproto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRA1L0R%2Fgo-mcproto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BRA1L0R","download_url":"https://codeload.github.com/BRA1L0R/go-mcproto/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222748053,"owners_count":17031894,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","mcproto","minecraft","protocol","spigot"],"created_at":"2024-08-01T07:00:38.562Z","updated_at":"2024-11-02T16:30:57.222Z","avatar_url":"https://github.com/BRA1L0R.png","language":"Go","funding_links":[],"categories":["Softwares"],"sub_categories":["Libraries"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003ego-mcproto\u003c/h1\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/BRA1L0R/go-mcproto\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/BRA1L0R/go-mcproto.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\n  \u003ca href=\"http://github.com/BRA1L0R/go-mcproto\"\u003e\u003cimg src=\"https://img.shields.io/github/go-mod/go-version/BRA1L0R/go-mcproto\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/BRA1L0R/go-mcproto/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/workflow/status/BRA1L0R/go-mcproto/Test?label=Unit%20Testing\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n## Install\n\nGo 1.16.x is required to use this library\n\n```sh\ngo get github.com/BRA1L0R/go-mcproto\n```\n\n## Opening a connection\n\n```go\n// Define the client\nclient := mcproto.Client{}\n\n// Use the Initialize method which connects to the server and sends Login information\nclient.Initialize(\"127.0.0.1\", 25565, 755, \"GolangBot\")\n```\n\nBefore opening a connection to a server, you'll have to specify some vital information such as the host, the port,\nthe name of your bot (which will login in offline mode) and the protocol version, which will have to match the server one,\nunless the server uses some kind of backward compatibility plugin such as ViaVersion.\n\nIn this case, 755 is the protocol version for Minecraft 1.17 but you can find all the versions [here](https://wiki.vg/Protocol_version_numbers)\n\nOnce you define client, you can either use the already implemented handshake method (`client.Initialize`) or you can manually open the connection using `client.Connect`\n\n`client.Initialize` only supports offline mode (unauthenticated SP) at the moment but I will soon implement online mode as well.\n\n## Defining a packet\n\nNot all packets are implemented in the library there are only the ones that will get you past the login state.\n\nFortunately, defining a packet with go-mcproto is as easy as declaring a struct. Here's a quick example\n\n```go\ntype ChatMessage struct {\n  packets.MinecraftPacket\n\n  JsonData string `mc:\"string\"`\n  Position byte   `mc:\"inherit\"`\n  Sender   []byte `mc:\"bytes\" len:\"16\"` // UUID is 128bit, hence the 16 byte len\n}\n```\n\npackets.MinecraftPackets will add the rest of the fields which are needed for a packet to be conformant to the standard format, compressed or not\n\nChatMessage will also inherit from packets.MinecraftPackets the methods for serialization of the fields into Data and the final serialization which returns the byte slice that can be sent over a connection using `client.WritePacket`\n\n### Arrays\n\nSometimes you might encounter a packet that sends before an array the length of it. Fortunately, you can still deserialize the packet with no extra steps thanks to the len tag:\n\n```go\ntype Biome struct {\n  BiomeID int32 `mc:\"varint\"`\n}\n\ntype ChunkData struct {\n  packets.MinecraftPacket\n\n  BiomesLength int32   `mc:\"varint\"`\n  Biomes       []Biome `mc:\"array\" len:\"BiomesLength\"`\n}\n```\n\nThe Biome struct can contain as many fields as you like, as the minecraft protocol has a lot of cases where there are multi-fielded arrays\n\n### Field Dependency\n\nIn some cases, a field is present only if the previous one is true (in the case of a boolean). You can still manage to do this with only struct tags by using the `depends_on` tag:\n\n```go\ntype PlayerInfo struct {\n  packets.MinecraftPacket\n\n  HasDisplayName bool   `mc:\"inherit\"`\n  DisplayName    string `mc:\"string\" depends_on:\"HasDisplayName\"`\n}\n```\n\n### All the available tags\n\nThis library already integrates all the possible types to define all possible data types, including NBTs.\n\nHere's a list of all the available tags:\n\n- `mc:\"inherit\"`: this tag covers all integers, complexes, floats, and the `byte` type. It inherits the length from the type defined in the struct. See the examples above. Please note: the Minecraft protocol is effectively big-endian, except varints, which are defined using another tag.\n- `mc:\"varint\"` and `mc:\"varlong\"`: Used to encode varints and varlongs respectively. Requires a int32 and int64 (respectively) as the field types\n- `mc:\"string\"`: requires a string field type in the struct, it encodes its length using a varint end then the string is encoded using the UTF-8.\n- `mc:\"bytes\" len:\"X\"`: Reads X bytes from the buffer and puts it in a byte slice, which must be the type of the struct field this tag is assigned to. _X is only required for deserialization in this case_\n- `mc:\"ignore\" len:\"X\"`: Ignores X bytes from the buffer. This means that it discards X bytes from the data buffer in case of deserialization or writes X null bytes in the data buffer in case of serialization\n- `mc:\"nbt\"`: Encodes or decodes an nbt struct. For more information check https://github.com/Tnze/go-mc/tree/master/nbt\n- `mc:\"array\" len:\"X\"`: Can be used to array every previous tags. Check [this section](#arrays)\n\n## Sending a packet\n\nOnce you have defined a packet you want to send, you will have to call `client.WritePacket()` to serialize the data and send it over a connection.\n\n```go\npacket := new(MyPacket)\npacket.PacketID = 0x00\n// you can look up the packet ids on wiki.vg\n// all the other fields\n\nclient.WritePacket(packet)\n```\n\n### Sending a raw packet\n\nIf you already put data into the Data buffer by yourself, without using the included serialized, then you can send the packet using the `WriteRawPacket` method.\n\n## Receiving a packet\n\nReceiving a packet is done by calling `client.ReceivePacket`. The server will receive the packet length and wait for the server until all bytes are fulfilled. If it encounters an error it will return it, but it will keep receiving packets as all the packet length is already consumed from the connection.\n\n`client.ReceivePacket` will return a MinecraftPacket, which can be deserialized using the DeserializeData method. It'a called by passing a pointer to a struct containing mc struct tags, as explained [here](#defining-a-packet)\n\n```go\npacket, err := client.ReceivePacket()\nif err != nil {\n  // an error has been encountered during the reception of the packet\n  panic(err)\n}\n\nkeepalive := new(models.KeepAlivePacket)\nerr := packet.DeserializeData(keepalive)\nif err != nil {\n  panic(err)\n}\n\nfmt.Println(keepalive.KeepAliveID) // 123456\n```\n\n### Variable packet content\n\nThere are multiple cases in the Minecraft protocol where the packet content is variable depending on certain values inside the struct. **This is no problem for the library**, as you can easily receive a part of the packet (by defining only the fixed fields in the struct) and then, later on, continue the deserialization by calling `DeserializeData` on a different struct.\n\nHere's a practical demonstration:\n\n```go\ntype FixedContent struct {\n  packets.MinecraftPacket\n\n  PacketType int32 `mc:\"varint\"`\n}\n\ntype SomeOtherContent struct {\n  packets.MinecraftPacket\n\n  Data string `mc:\"string\"`\n}\n\npacket, _ := client.ReceivePacket()\n// from now on I'm gonna avoid doing error handling in the examples for practical reasons\n// but you MUST do it.\n\nfixedPacket := new(FixedContent)\npacket.DeserializeData(fixedPacket)\n\nif fixedPacket.PacketType == 0x05 {\n  someOtherContent := new(SomeOtherContent)\n  packet.DeserializeData(someOtherContent)\n} else {\n  panic(\"Unknown packet type!\")\n}\n```\n\n## Example ✨\n\nThis example initializes the connection between the client and a server, thus switching to the Play state, and listens for keepalive packets to which it responds\n\n```go\npackage main\n\nimport (\n\t\"github.com/BRA1L0R/go-mcproto\"\n\t\"github.com/BRA1L0R/go-mcproto/packets/models\"\n)\n\nfunc main() {\n  client := mcproto.Client{}\n\tclient.Initialize(\"127.0.0.1\", 25565, 755, \"GolangBot\")\n\n  for {\n    packet, err := client.ReceivePacket()\n    if err != nil {\n      panic(err)\n    }\n\n    if packet.PacketID == 0x1F { // clientbound keepalive packetid\n      receivedKeepalive := new(models.KeepAlivePacket)\n      err := packet.DeserializeData(receivedKeepalive)\n      if err != nil {\n        panic(err)\n      }\n\n      serverBoundKeepalive := new(models.KeepAlivePacket)\n      serverBoundKeepalive.KeepAliveID = receivedKeepalive.KeepAliveID\n      serverBoundKeepalive.PacketID = 0x10 // serverbound keepaliveid\n\n      err = client.WritePacket(serverBoundKeepalive)\n    }\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBRA1L0R%2Fgo-mcproto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBRA1L0R%2Fgo-mcproto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBRA1L0R%2Fgo-mcproto/lists"}