From 51ba4c2fdde233bdc44596279b6d7c2ded401791 Mon Sep 17 00:00:00 2001 From: Tnze Date: Thu, 13 Jun 2024 22:29:05 +0800 Subject: [PATCH] go fmt --- examples/playerdataconvert/advancements.go | 116 ++++----- examples/playerdataconvert/main.go | 180 +++++++------- examples/playerdataconvert/pets.go | 258 ++++++++++----------- examples/playerdataconvert/playerdata.go | 240 +++++++++---------- examples/playerdataconvert/utils.go | 96 ++++---- 5 files changed, 445 insertions(+), 445 deletions(-) diff --git a/examples/playerdataconvert/advancements.go b/examples/playerdataconvert/advancements.go index 6792a60..1b1066c 100644 --- a/examples/playerdataconvert/advancements.go +++ b/examples/playerdataconvert/advancements.go @@ -1,58 +1,58 @@ -package main - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/google/uuid" -) - -func readAdvancements(dir string, m map[uuid.UUID]UserCache) { - entries, err := os.ReadDir(dir) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to open playerdata folder: %v", err) - return - } - for _, files := range entries { - filename := files.Name() - if ext := filepath.Ext(filename); ext != ".json" { - fmt.Fprintf(os.Stderr, "Unkown file type: %s\n", ext) - continue - } - - // Parse old UUID from filename - oldID, err := uuid.Parse(strings.TrimSuffix(filename, ".json")) - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to parse filename as uuid: %v\n", err) - continue - } - - if ver := oldID.Version(); ver != 3 { // v3 is for offline players - fmt.Printf("Ignoring UUID: %v version: %d\n", oldID, ver) - continue - } - - newUser, ok := m[oldID] - if !ok { - fmt.Printf("Skip user: %v\n", oldID) - continue - } - - content, err := os.ReadFile(filepath.Join(dir, filename)) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to read json file: %v\n", err) - continue - } - - newFile := newUser.UUID.String() + ".json" - err = os.WriteFile(filepath.Join(dir, newFile), content, 0o666) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to write json file: %v\n", err) - continue - } - - fmt.Printf("Converted advancement file: %s\n", newFile) - } -} +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/google/uuid" +) + +func readAdvancements(dir string, m map[uuid.UUID]UserCache) { + entries, err := os.ReadDir(dir) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to open playerdata folder: %v", err) + return + } + for _, files := range entries { + filename := files.Name() + if ext := filepath.Ext(filename); ext != ".json" { + fmt.Fprintf(os.Stderr, "Unkown file type: %s\n", ext) + continue + } + + // Parse old UUID from filename + oldID, err := uuid.Parse(strings.TrimSuffix(filename, ".json")) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to parse filename as uuid: %v\n", err) + continue + } + + if ver := oldID.Version(); ver != 3 { // v3 is for offline players + fmt.Printf("Ignoring UUID: %v version: %d\n", oldID, ver) + continue + } + + newUser, ok := m[oldID] + if !ok { + fmt.Printf("Skip user: %v\n", oldID) + continue + } + + content, err := os.ReadFile(filepath.Join(dir, filename)) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to read json file: %v\n", err) + continue + } + + newFile := newUser.UUID.String() + ".json" + err = os.WriteFile(filepath.Join(dir, newFile), content, 0o666) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write json file: %v\n", err) + continue + } + + fmt.Printf("Converted advancement file: %s\n", newFile) + } +} diff --git a/examples/playerdataconvert/main.go b/examples/playerdataconvert/main.go index ce16440..50cb98e 100644 --- a/examples/playerdataconvert/main.go +++ b/examples/playerdataconvert/main.go @@ -1,90 +1,90 @@ -// playerdataconvert is a program to convert player data form offline server to online server. -// -// When a player with official account login connect to a offline-mode server, -// the server store the player data with their "offline UUID". While you open -// the online-mode switch, the player data loose. -// -// By using this tool, you can convert the offline data into online data. -// The players will keep everything they got, yay! -package main - -import ( - "encoding/json" - "flag" - "fmt" - "os" - "path/filepath" - - "github.com/google/uuid" -) - -var ( - savePath = flag.String("save", ".", "The save folder with \"usercache.json\" file inside") - convertPlayerData = flag.Bool("cplayerdata", true, "Whether convert files at /world/playerdata/*.dat") - convertEntities = flag.Bool("centities", true, "Whether convert pets' Owner at /world/entities/*") - convertAdvancements = flag.Bool("cadvancements", true, "Whether convert advancements at /world/advancements/*") -) - -func main() { - flag.Parse() - - usercaches, err := readUsercache(filepath.Join(*savePath, "usercache.json")) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to parse usercache file: %v\n", err) - return - } - fmt.Printf("Successfully reading usercache\n") - m := mappingUsers(usercaches) - - if *convertPlayerData { - readPlayerdata(filepath.Join(*savePath, "world", "playerdata"), m) - } - - if *convertEntities { - readEntities(filepath.Join(*savePath, "world", "entities"), m) - } - - if *convertAdvancements { - readAdvancements(filepath.Join(*savePath, "world", "advancements"), m) - } -} - -type UserCache struct { - Name string `json:"name"` - UUID uuid.UUID `json:"uuid"` -} - -func readUsercache(path string) ([]UserCache, error) { - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - var usercache []UserCache - err = json.Unmarshal(data, &usercache) - if err != nil { - return nil, err - } - return usercache, nil -} - -func mappingUsers(users []UserCache) map[uuid.UUID]UserCache { - m := make(map[uuid.UUID]UserCache) - for _, user := range users { - name := user.Name - // // You can add your maps here - // if v, ok := offlineOnlineMaps[name]; ok { - // name = v - // } - - name, id, err := usernameToUUID(name) - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to fetch username for %s from Mojang server: %v\n", name, err) - continue - } - - fmt.Printf("[%s] %v -> %v\n", name, user.UUID, id) - m[user.UUID] = UserCache{name, id} - } - return m -} +// playerdataconvert is a program to convert player data form offline server to online server. +// +// When a player with official account login connect to a offline-mode server, +// the server store the player data with their "offline UUID". While you open +// the online-mode switch, the player data loose. +// +// By using this tool, you can convert the offline data into online data. +// The players will keep everything they got, yay! +package main + +import ( + "encoding/json" + "flag" + "fmt" + "os" + "path/filepath" + + "github.com/google/uuid" +) + +var ( + savePath = flag.String("save", ".", "The save folder with \"usercache.json\" file inside") + convertPlayerData = flag.Bool("cplayerdata", true, "Whether convert files at /world/playerdata/*.dat") + convertEntities = flag.Bool("centities", true, "Whether convert pets' Owner at /world/entities/*") + convertAdvancements = flag.Bool("cadvancements", true, "Whether convert advancements at /world/advancements/*") +) + +func main() { + flag.Parse() + + usercaches, err := readUsercache(filepath.Join(*savePath, "usercache.json")) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to parse usercache file: %v\n", err) + return + } + fmt.Printf("Successfully reading usercache\n") + m := mappingUsers(usercaches) + + if *convertPlayerData { + readPlayerdata(filepath.Join(*savePath, "world", "playerdata"), m) + } + + if *convertEntities { + readEntities(filepath.Join(*savePath, "world", "entities"), m) + } + + if *convertAdvancements { + readAdvancements(filepath.Join(*savePath, "world", "advancements"), m) + } +} + +type UserCache struct { + Name string `json:"name"` + UUID uuid.UUID `json:"uuid"` +} + +func readUsercache(path string) ([]UserCache, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + var usercache []UserCache + err = json.Unmarshal(data, &usercache) + if err != nil { + return nil, err + } + return usercache, nil +} + +func mappingUsers(users []UserCache) map[uuid.UUID]UserCache { + m := make(map[uuid.UUID]UserCache) + for _, user := range users { + name := user.Name + // // You can add your maps here + // if v, ok := offlineOnlineMaps[name]; ok { + // name = v + // } + + name, id, err := usernameToUUID(name) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to fetch username for %s from Mojang server: %v\n", name, err) + continue + } + + fmt.Printf("[%s] %v -> %v\n", name, user.UUID, id) + m[user.UUID] = UserCache{name, id} + } + return m +} diff --git a/examples/playerdataconvert/pets.go b/examples/playerdataconvert/pets.go index c9c2108..4daae41 100644 --- a/examples/playerdataconvert/pets.go +++ b/examples/playerdataconvert/pets.go @@ -1,129 +1,129 @@ -package main - -import ( - "bytes" - "compress/gzip" - "compress/zlib" - "errors" - "fmt" - "io" - "os" - "path/filepath" - - "github.com/Tnze/go-mc/nbt" - "github.com/Tnze/go-mc/nbt/dynbt" - "github.com/Tnze/go-mc/save/region" - "github.com/google/uuid" -) - -func readEntities(dir string, m map[uuid.UUID]UserCache) { - entries, err := os.ReadDir(dir) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to read entities dir: %v\n", err) - return - } - for i := range entries { - readEntityMcaFile(filepath.Join(dir, entries[i].Name()), m) - } -} - -func readEntityMcaFile(path string, m map[uuid.UUID]UserCache) { - r, err := region.Open(path) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to open entities region file %s: %v\n", path, err) - return - } - defer r.Close() - - for i := 0; i < 32; i++ { - for j := 0; j < 32; j++ { - if !r.ExistSector(i, j) { - continue - } - - data, err := r.ReadSector(i, j) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to read entities region sector: %v\n", err) - continue - } - - newdata, err := readEntityMcaSector(data, m) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to parse entities region sector: %v\n", err) - continue - } - - if newdata != nil { - err = r.WriteSector(i, j, newdata) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to update region sector data: %v\n", err) - continue - } - } - } - } -} - -func readEntityMcaSector(data []byte, m map[uuid.UUID]UserCache) ([]byte, error) { - var r io.Reader = bytes.NewReader(data[1:]) - var err error - switch data[0] { - default: - return nil, errors.New("unknown compression") - case 1: - r, err = gzip.NewReader(r) - case 2: - r, err = zlib.NewReader(r) - case 3: - } - if err != nil { - return nil, err - } - - var nbtdata dynbt.Value - _, err = nbt.NewDecoder(r).Decode(&nbtdata) - if err != nil { - return nil, err - } - - updated := false - - entities := nbtdata.Get("Entities") - if entities == nil { - return nil, fmt.Errorf("no Entities field in nbt, what happen?") - } - entities2 := entities.List() - for _, entity := range entities2 { - id := entity.Get("id").String() - if owner := entity.Get("Owner"); owner != nil { - owner, _ := intArrayToUUID(owner.IntArray()) - fmt.Printf("Found %s: owner=%s\n", id, owner) - - if owner.Version() != 3 { - continue - } - - if newOwner, ok := m[owner]; ok { - ownerInts := uuidToIntArray(newOwner.UUID) - entity.Set("Owner", dynbt.NewIntArray(ownerInts[:])) - updated = true - } - } - } - - if updated { - var w bytes.Buffer - w.WriteByte(1) - gw := gzip.NewWriter(&w) - - err := nbt.NewEncoder(gw).Encode(&nbtdata, "") - if err != nil { - gw.Close() - return nil, err - } - - err = gw.Close() - return w.Bytes(), err - } - return nil, nil -} +package main + +import ( + "bytes" + "compress/gzip" + "compress/zlib" + "errors" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/Tnze/go-mc/nbt" + "github.com/Tnze/go-mc/nbt/dynbt" + "github.com/Tnze/go-mc/save/region" + "github.com/google/uuid" +) + +func readEntities(dir string, m map[uuid.UUID]UserCache) { + entries, err := os.ReadDir(dir) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to read entities dir: %v\n", err) + return + } + for i := range entries { + readEntityMcaFile(filepath.Join(dir, entries[i].Name()), m) + } +} + +func readEntityMcaFile(path string, m map[uuid.UUID]UserCache) { + r, err := region.Open(path) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to open entities region file %s: %v\n", path, err) + return + } + defer r.Close() + + for i := 0; i < 32; i++ { + for j := 0; j < 32; j++ { + if !r.ExistSector(i, j) { + continue + } + + data, err := r.ReadSector(i, j) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to read entities region sector: %v\n", err) + continue + } + + newdata, err := readEntityMcaSector(data, m) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to parse entities region sector: %v\n", err) + continue + } + + if newdata != nil { + err = r.WriteSector(i, j, newdata) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to update region sector data: %v\n", err) + continue + } + } + } + } +} + +func readEntityMcaSector(data []byte, m map[uuid.UUID]UserCache) ([]byte, error) { + var r io.Reader = bytes.NewReader(data[1:]) + var err error + switch data[0] { + default: + return nil, errors.New("unknown compression") + case 1: + r, err = gzip.NewReader(r) + case 2: + r, err = zlib.NewReader(r) + case 3: + } + if err != nil { + return nil, err + } + + var nbtdata dynbt.Value + _, err = nbt.NewDecoder(r).Decode(&nbtdata) + if err != nil { + return nil, err + } + + updated := false + + entities := nbtdata.Get("Entities") + if entities == nil { + return nil, fmt.Errorf("no Entities field in nbt, what happen?") + } + entities2 := entities.List() + for _, entity := range entities2 { + id := entity.Get("id").String() + if owner := entity.Get("Owner"); owner != nil { + owner, _ := intArrayToUUID(owner.IntArray()) + fmt.Printf("Found %s: owner=%s\n", id, owner) + + if owner.Version() != 3 { + continue + } + + if newOwner, ok := m[owner]; ok { + ownerInts := uuidToIntArray(newOwner.UUID) + entity.Set("Owner", dynbt.NewIntArray(ownerInts[:])) + updated = true + } + } + } + + if updated { + var w bytes.Buffer + w.WriteByte(1) + gw := gzip.NewWriter(&w) + + err := nbt.NewEncoder(gw).Encode(&nbtdata, "") + if err != nil { + gw.Close() + return nil, err + } + + err = gw.Close() + return w.Bytes(), err + } + return nil, nil +} diff --git a/examples/playerdataconvert/playerdata.go b/examples/playerdataconvert/playerdata.go index b0ee4f1..9bfcad4 100644 --- a/examples/playerdataconvert/playerdata.go +++ b/examples/playerdataconvert/playerdata.go @@ -1,120 +1,120 @@ -package main - -import ( - "compress/gzip" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/Tnze/go-mc/nbt" - "github.com/Tnze/go-mc/nbt/dynbt" - "github.com/google/uuid" -) - -func readPlayerdata(dir string, m map[uuid.UUID]UserCache) { - entries, err := os.ReadDir(dir) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to open playerdata folder: %v", err) - return - } - for _, files := range entries { - filename := files.Name() - if ext := filepath.Ext(filename); ext != ".dat" { - fmt.Fprintf(os.Stderr, "Unkown file type: %s\n", ext) - continue - } - - // Parse old UUID from filename - oldID, err := uuid.Parse(strings.TrimSuffix(filename, ".dat")) - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to parse filename as uuid: %v\n", err) - continue - } - - nbtdata, err := readNbtData(filepath.Join(dir, filename)) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to read %s nbt data\n", filename) - continue - } - - // Read old UUID from nbt - uuidInts := nbtdata.Get("UUID").IntArray() - uuidBytes, err := intArrayToUUID(uuidInts) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to read %s UUID\n", filename) - continue - } - - // Does they matche? - if oldID != uuidBytes { - fmt.Fprintf(os.Stderr, "UUID in filename and nbt data don't match, what happend?\n") - } - - if ver := uuidBytes.Version(); ver != 3 { // v3 is for offline players - fmt.Printf("Ignoring UUID: %v version: %d\n", uuidBytes, ver) - continue - } - - newUser, ok := m[oldID] - if !ok { - fmt.Printf("Skip user: %v\n", oldID) - continue - } - - // Update UUID - ints := uuidToIntArray(newUser.UUID) - nbtdata.Set("UUID", dynbt.NewIntArray(ints[:])) - - // Create new .dat file - err = writeNbtData(dir, newUser.UUID.String(), &nbtdata) - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to write %s's .dat file: %v\n", newUser.Name, err) - continue - } - } -} - -func readNbtData(filepath string) (nbtdata dynbt.Value, err error) { - file, err := os.Open(filepath) - if err != nil { - return nbtdata, fmt.Errorf("failed to open userdata: %w", err) - } - defer file.Close() - - r, err := gzip.NewReader(file) - if err != nil { - return nbtdata, fmt.Errorf("failed to decompress userdata: %w", err) - } - - _, err = nbt.NewDecoder(r).Decode(&nbtdata) - if err != nil { - return nbtdata, fmt.Errorf("failed to parse userdata: %w", err) - } - return nbtdata, nil -} - -func writeNbtData(dir string, id string, nbtdata *dynbt.Value) error { - newDatFilePath := filepath.Join(dir, id+".dat") - file, err := os.Create(newDatFilePath) - if err != nil { - return err - } - - w := gzip.NewWriter(file) - err = nbt.NewEncoder(w).Encode(&nbtdata, "") - if err != nil { - return err - } - - err = w.Close() - if err != nil { - return err - } - - err = file.Close() - if err != nil { - return err - } - return nil -} +package main + +import ( + "compress/gzip" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/Tnze/go-mc/nbt" + "github.com/Tnze/go-mc/nbt/dynbt" + "github.com/google/uuid" +) + +func readPlayerdata(dir string, m map[uuid.UUID]UserCache) { + entries, err := os.ReadDir(dir) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to open playerdata folder: %v", err) + return + } + for _, files := range entries { + filename := files.Name() + if ext := filepath.Ext(filename); ext != ".dat" { + fmt.Fprintf(os.Stderr, "Unkown file type: %s\n", ext) + continue + } + + // Parse old UUID from filename + oldID, err := uuid.Parse(strings.TrimSuffix(filename, ".dat")) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to parse filename as uuid: %v\n", err) + continue + } + + nbtdata, err := readNbtData(filepath.Join(dir, filename)) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to read %s nbt data\n", filename) + continue + } + + // Read old UUID from nbt + uuidInts := nbtdata.Get("UUID").IntArray() + uuidBytes, err := intArrayToUUID(uuidInts) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to read %s UUID\n", filename) + continue + } + + // Does they matche? + if oldID != uuidBytes { + fmt.Fprintf(os.Stderr, "UUID in filename and nbt data don't match, what happend?\n") + } + + if ver := uuidBytes.Version(); ver != 3 { // v3 is for offline players + fmt.Printf("Ignoring UUID: %v version: %d\n", uuidBytes, ver) + continue + } + + newUser, ok := m[oldID] + if !ok { + fmt.Printf("Skip user: %v\n", oldID) + continue + } + + // Update UUID + ints := uuidToIntArray(newUser.UUID) + nbtdata.Set("UUID", dynbt.NewIntArray(ints[:])) + + // Create new .dat file + err = writeNbtData(dir, newUser.UUID.String(), &nbtdata) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to write %s's .dat file: %v\n", newUser.Name, err) + continue + } + } +} + +func readNbtData(filepath string) (nbtdata dynbt.Value, err error) { + file, err := os.Open(filepath) + if err != nil { + return nbtdata, fmt.Errorf("failed to open userdata: %w", err) + } + defer file.Close() + + r, err := gzip.NewReader(file) + if err != nil { + return nbtdata, fmt.Errorf("failed to decompress userdata: %w", err) + } + + _, err = nbt.NewDecoder(r).Decode(&nbtdata) + if err != nil { + return nbtdata, fmt.Errorf("failed to parse userdata: %w", err) + } + return nbtdata, nil +} + +func writeNbtData(dir string, id string, nbtdata *dynbt.Value) error { + newDatFilePath := filepath.Join(dir, id+".dat") + file, err := os.Create(newDatFilePath) + if err != nil { + return err + } + + w := gzip.NewWriter(file) + err = nbt.NewEncoder(w).Encode(&nbtdata, "") + if err != nil { + return err + } + + err = w.Close() + if err != nil { + return err + } + + err = file.Close() + if err != nil { + return err + } + return nil +} diff --git a/examples/playerdataconvert/utils.go b/examples/playerdataconvert/utils.go index 1da0e45..fdcf13e 100644 --- a/examples/playerdataconvert/utils.go +++ b/examples/playerdataconvert/utils.go @@ -1,48 +1,48 @@ -package main - -import ( - "encoding/binary" - "encoding/json" - "fmt" - "net/http" - - "github.com/google/uuid" -) - -func usernameToUUID(name string) (string, uuid.UUID, error) { - var id uuid.UUID - resp, err := http.Get("https://api.mojang.com/users/profiles/minecraft/" + name) - if err != nil { - return "", id, err - } - - var body struct { - Name string `json:"name"` - ID string `json:"id"` - } - err = json.NewDecoder(resp.Body).Decode(&body) - if err != nil { - return "", id, err - } - - id, err = uuid.Parse(body.ID) - return body.Name, id, err -} - -func intArrayToUUID(uuidInts []int32) (id uuid.UUID, err error) { - if uuidLen := len(uuidInts); uuidLen != 4 { - err = fmt.Errorf("invalid UUID len: %d * int32", uuidLen) - return - } - for i, v := range uuidInts { - binary.BigEndian.PutUint32(id[i*4:], uint32(v)) - } - return -} - -func uuidToIntArray(id uuid.UUID) (ints [4]int32) { - for i := range ints { - ints[i] = int32(binary.BigEndian.Uint32(id[i*4:])) - } - return -} +package main + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "net/http" + + "github.com/google/uuid" +) + +func usernameToUUID(name string) (string, uuid.UUID, error) { + var id uuid.UUID + resp, err := http.Get("https://api.mojang.com/users/profiles/minecraft/" + name) + if err != nil { + return "", id, err + } + + var body struct { + Name string `json:"name"` + ID string `json:"id"` + } + err = json.NewDecoder(resp.Body).Decode(&body) + if err != nil { + return "", id, err + } + + id, err = uuid.Parse(body.ID) + return body.Name, id, err +} + +func intArrayToUUID(uuidInts []int32) (id uuid.UUID, err error) { + if uuidLen := len(uuidInts); uuidLen != 4 { + err = fmt.Errorf("invalid UUID len: %d * int32", uuidLen) + return + } + for i, v := range uuidInts { + binary.BigEndian.PutUint32(id[i*4:], uint32(v)) + } + return +} + +func uuidToIntArray(id uuid.UUID) (ints [4]int32) { + for i := range ints { + ints[i] = int32(binary.BigEndian.Uint32(id[i*4:])) + } + return +}