Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Sandertv/gophertunnel/llms.txt
Use this file to discover all available pages before exploring further.
This guide covers working with Minecraft Bedrock Edition resource packs using the minecraft/resource package.
Overview
Gophertunnel provides a complete resource pack management system that can:
- Read resource packs from files, directories, or URLs
- Parse manifest.json and extract metadata
- Calculate checksums for validation
- Serve packs to clients over RakNet or HTTP
- Handle encrypted packs
Reading Resource Packs
From File or Directory
Import the Package
import "github.com/sandertv/gophertunnel/minecraft/resource"
Load a Pack
The ReadPath function accepts both .mcpack files and directories:pack, err := resource.ReadPath("path/to/pack.mcpack")
if err != nil {
panic(err)
}
Or use MustReadPath to panic on error:pack := resource.MustReadPath("path/to/pack.mcpack")
From URL
Download and load a pack from a remote URL:
pack, err := resource.ReadURL("https://example.com/pack.mcpack")
if err != nil {
panic(err)
}
// Or use MustReadURL
pack := resource.MustReadURL("https://example.com/pack.mcpack")
From io.Reader
Load a pack from any reader:
import "os"
file, err := os.Open("pack.mcpack")
if err != nil {
panic(err)
}
defer file.Close()
pack, err := resource.Read(file)
if err != nil {
panic(err)
}
Access resource pack information:
pack, err := resource.ReadPath("pack.mcpack")
if err != nil {
panic(err)
}
// Basic information
name := pack.Name() // "My Resource Pack"
uuid := pack.UUID() // uuid.UUID
desc := pack.Description() // "A cool pack"
version := pack.Version() // "1.0.0"
// Manifest data
manifest := pack.Manifest()
modules := pack.Modules() // []resource.Module
deps := pack.Dependencies() // []resource.Dependency
// Pack properties
hasScripts := pack.HasScripts() // bool
hasTextures := pack.HasTextures() // bool
hasBehaviors := pack.HasBehaviours() // bool
isWorldTemplate := pack.HasWorldTemplate() // bool
Pack Types
Resource Packs
Contain textures, models, sounds:
if pack.HasTextures() {
fmt.Println("This pack has custom textures")
}
Behavior Packs
Contain scripts and data:
if pack.HasBehaviours() {
fmt.Println("This pack has behaviors")
}
if pack.HasScripts() {
fmt.Println("This pack has client scripts")
}
World Templates
Contain a level.dat:
if pack.HasWorldTemplate() {
fmt.Println("This is a world template")
}
Serving Packs to Clients
RakNet Download
Serve packs directly through the Minecraft protocol:
import "github.com/sandertv/gophertunnel/minecraft"
pack, err := resource.ReadPath("pack.mcpack")
if err != nil {
panic(err)
}
cfg := minecraft.ListenConfig{
StatusProvider: minecraft.NewStatusProvider("My Server", "Gophertunnel"),
ResourcePacks: []*resource.Pack{pack},
}
listener, err := cfg.Listen("raknet", ":19132")
if err != nil {
panic(err)
}
HTTP Download
Serve packs via HTTP for faster downloads:
packURL := "https://example.com/packs/pack.mcpack"
pack, err := resource.ReadURL(packURL)
if err != nil {
panic(err)
}
// The pack will be downloaded by clients over HTTP
url := pack.DownloadURL() // "https://example.com/packs/pack.mcpack"
Pack Content
Reading Files
Read specific files from a pack:
data, err := pack.ReadFile("manifest.json")
if err != nil {
panic(err)
}
fmt.Println(string(data))
Checksums
Get the SHA256 checksum for validation:
checksum := pack.Checksum() // [32]byte
totalSize := pack.Len() // Total bytes
chunkCount := pack.DataChunkCount(1024) // Number of chunks
Reading Chunks
Read pack data in chunks:
buffer := make([]byte, 1024)
offset := int64(0)
n, err := pack.ReadAt(buffer, offset)
if err != nil {
panic(err)
}
fmt.Printf("Read %d bytes\n", n)
Encrypted Packs
Setting Encryption Key
encryptedPack := pack.WithContentKey("my-encryption-key")
if encryptedPack.Encrypted() {
key := encryptedPack.ContentKey() // "my-encryption-key"
}
Pack Manifest
The manifest contains pack metadata:
type Manifest struct {
Header struct {
Name string
Description string
UUID uuid.UUID
Version [3]int
}
Modules []Module
Dependencies []Dependency
}
Accessing Manifest
manifest := pack.Manifest()
fmt.Printf("Pack: %s v%d.%d.%d\n",
manifest.Header.Name,
manifest.Header.Version[0],
manifest.Header.Version[1],
manifest.Header.Version[2])
for _, module := range manifest.Modules {
fmt.Printf("Module: %s (Type: %s)\n", module.UUID, module.Type)
}
for _, dep := range manifest.Dependencies {
fmt.Printf("Depends on: %s v%s\n", dep.UUID, dep.Version)
}
Module Types
Resource packs consist of modules:
type Module struct {
Type string // "resources", "data", "client_data"
UUID uuid.UUID
Version [3]int
}
Common module types:
resources - Textures, models, sounds
data - Behavior scripts
client_data - Client-side scripts
Complete Example
Here’s a complete example of loading and serving a resource pack:
package main
import (
"fmt"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/resource"
)
func main() {
// Load resource pack
pack, err := resource.ReadPath("MyPack.mcpack")
if err != nil {
panic(err)
}
// Print pack information
fmt.Printf("Loaded: %s\n", pack)
fmt.Printf("UUID: %s\n", pack.UUID())
fmt.Printf("Version: %s\n", pack.Version())
fmt.Printf("Size: %d bytes\n", pack.Len())
fmt.Printf("Checksum: %x\n", pack.Checksum())
// Check pack type
if pack.HasTextures() {
fmt.Println("Contains textures")
}
if pack.HasBehaviours() {
fmt.Println("Contains behaviors")
}
// Create server with the pack
cfg := minecraft.ListenConfig{
StatusProvider: minecraft.NewStatusProvider("Pack Server", "Gophertunnel"),
ResourcePacks: []*resource.Pack{pack},
}
listener, err := cfg.Listen("raknet", ":19132")
if err != nil {
panic(err)
}
defer listener.Close()
fmt.Println("Server started with resource pack")
for {
c, err := listener.Accept()
if err != nil {
return
}
go handleConnection(c.(*minecraft.Conn))
}
}
func handleConnection(conn *minecraft.Conn) {
defer conn.Close()
worldData := minecraft.GameData{}
if err := conn.StartGame(worldData); err != nil {
return
}
// Client will download the resource pack before spawning
for {
pk, err := conn.ReadPacket()
if err != nil {
break
}
// Handle packets...
}
}
Building Packs from Directories
If you have a pack directory structure:
MyPack/
├── manifest.json
├── pack_icon.png
├── textures/
│ └── blocks/
└── sounds/
Read it directly:
pack, err := resource.ReadPath("MyPack/")
if err != nil {
panic(err)
}
// Automatically compiled to zip format
Best Practices
- Validate Manifests: Ensure
manifest.json exists and is valid
- Check Pack Size: Large packs may take time to transfer
- Use HTTP for Large Packs: HTTP downloads are faster than RakNet
- Cache Packs: Load packs once and reuse them
- Verify Checksums: Use checksums to ensure pack integrity
Next Steps