diff --git a/.gitattributes b/.gitattributes index 891d241..4754b74 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -utils/resourcepack-ace.go.ignore filter=git-crypt diff=git-crypt \ No newline at end of file +utils/resourcepack-ace.go filter=git-crypt diff=git-crypt \ No newline at end of file diff --git a/Makefile b/Makefile index 3c2b3fa..2ed334a 100644 --- a/Makefile +++ b/Makefile @@ -8,12 +8,12 @@ GC = go build -ldflags "-s -w -X github.com/bedrock-tool/bedrocktool/utils.Versi # check if packs are supported HAVE_PACKS = false -ifeq ($(shell head -c 7 ./utils/resourcepack-ace.go.ignore),package) +ifeq ($(shell head -c 7 ./utils/resourcepack-ace.go),package) HAVE_PACKS = true endif $(info pack support: ${HAVE_PACKS}) -ifeq ($(HAVE_PACKS),true) +ifneq ($(HAVE_PACKS),true) GC += -overlay overlay.json endif @@ -46,7 +46,6 @@ $(DISTS): dist builds $(SRCS) GOOS=$(OS) GOARCH=$(ARCH) $(GC) -o $(BUILD) ./cmd/bedrocktool cp $(BUILD) $@ - UPDATES=$(BUILDS) $(UPDATES): OS = $(word 1,$(subst _, ,$@)) $(UPDATES): ARCH = $(word 1,$(subst ., ,$(word 2,$(subst _, ,$@)))) diff --git a/overlay.json b/overlay.json index 059ff91..c139207 100644 --- a/overlay.json +++ b/overlay.json @@ -1,5 +1,5 @@ { "Replace": { - "utils/resourcepack.go": "utils/resourcepack-ace.go.ignore" + "utils/resourcepack-ace.go": "utils/dummy" } } \ No newline at end of file diff --git a/subcommands/world/world.go b/subcommands/world/world.go index 8eac5c6..2ec1232 100644 --- a/subcommands/world/world.go +++ b/subcommands/world/world.go @@ -161,6 +161,7 @@ func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{ w.ctx = ctx proxy := utils.NewProxy() + proxy.AlwaysGetPacks = true proxy.ConnectCB = w.OnConnect proxy.PacketCB = func(pk packet.Packet, proxy *utils.ProxyContext, toServer bool) (packet.Packet, error) { var forward bool @@ -442,38 +443,55 @@ func (w *WorldState) SaveAndReset() { provider.Close() w.worldCounter += 1 - for k, p := range w.packs { - logrus.Infof(locale.Loc("adding_pack", locale.Strmap{"Name": k})) - pack_folder := path.Join(folder, "resource_packs", k) - os.MkdirAll(pack_folder, 0o755) - data := make([]byte, p.Len()) - p.ReadAt(data, 0) - utils.UnpackZip(bytes.NewReader(data), int64(len(data)), pack_folder) + type dep struct { + PackId string `json:"pack_id"` + Version [3]int `json:"version"` + } + add_packs_json := func(name string, deps []dep) { + f, err := os.Create(path.Join(folder, name)) + if err != nil { + logrus.Error(err) + return + } + defer f.Close() + if err := json.NewEncoder(f).Encode(deps); err != nil { + logrus.Error(err) + return + } + } + + { + var rdeps []dep + for k, p := range w.packs { + logrus.Infof(locale.Loc("adding_pack", locale.Strmap{"Name": k})) + pack_folder := path.Join(folder, "resource_packs", k) + os.MkdirAll(pack_folder, 0o755) + data := make([]byte, p.Len()) + p.ReadAt(data, 0) + utils.UnpackZip(bytes.NewReader(data), int64(len(data)), pack_folder) + rdeps = append(rdeps, dep{ + PackId: p.Manifest().Header.Name, + Version: p.Manifest().Header.Version, + }) + } + add_packs_json("world_resource_packs.json", rdeps) } if w.bp != nil { name := w.ServerName + "_blocks" pack_folder := path.Join(folder, "behavior_packs", name) os.MkdirAll(pack_folder, 0o755) - w.bp.Save(pack_folder) - { // save file saying to load the behavior pack - f, err := os.Create(path.Join(folder, "world_behavior_packs.json")) - if err != nil { - logrus.Error(err) - } else { - defer f.Close() - type dep struct { - PackId string `json:"pack_id"` - Version [3]int `json:"version"` - } - if err := json.NewEncoder(f).Encode([]dep{{ - PackId: w.bp.Manifest.Header.UUID, - Version: w.bp.Manifest.Header.Version, - }}); err != nil { - logrus.Error(err) - } - } + + for _, p := range w.proxy.Server.ResourcePacks() { + p := utils.PackFromBase(p) + w.bp.CheckAddLink(p) } + + w.bp.Save(pack_folder) + add_packs_json("world_behavior_packs.json", []dep{{ + PackId: w.bp.Manifest.Header.UUID, + Version: w.bp.Manifest.Header.Version, + }}) } if w.saveImage { diff --git a/utils/behaviourpack/bp.go b/utils/behaviourpack/bp.go index 36f619c..1774152 100644 --- a/utils/behaviourpack/bp.go +++ b/utils/behaviourpack/bp.go @@ -1,6 +1,7 @@ package behaviourpack import ( + "archive/zip" "bytes" "crypto/sha256" "encoding/json" @@ -8,6 +9,7 @@ import ( "path" "strings" + "github.com/bedrock-tool/bedrocktool/utils" "github.com/google/uuid" "github.com/sandertv/gophertunnel/minecraft/protocol" "github.com/sandertv/gophertunnel/minecraft/resource" @@ -157,11 +159,7 @@ func (bp *BehaviourPack) AddBlock(block protocol.BlockEntry) { } // fix missing * instance if k == "minecraft:material_instances" { - if mats, ok := v["materials"].(map[string]any); ok { - if _, has_star := mats["*"]; !has_star { - mats["*"] = mats["east"] - } - } + comps[k] = v["materials"].(map[string]any) } } } @@ -184,6 +182,19 @@ func (bp *BehaviourPack) AddBlock(block protocol.BlockEntry) { bp.blocks = append(bp.blocks, entry) } +func (bp *BehaviourPack) CheckAddLink(pack utils.Pack) { + z, err := zip.NewReader(pack, int64(pack.Len())) + if err != nil { + logrus.Error(err) + } + _, err = z.Open("blocks.json") + if err != nil { + return + } + h := pack.Manifest().Header + bp.AddDependency(h.UUID, h.Version) +} + func (bp *BehaviourPack) Save(fpath string) error { { // write manifest w, err := os.Create(path.Join(fpath, "manifest.json")) diff --git a/utils/dummy b/utils/dummy new file mode 100644 index 0000000..5b55d23 --- /dev/null +++ b/utils/dummy @@ -0,0 +1 @@ +package utils \ No newline at end of file diff --git a/utils/proxy.go b/utils/proxy.go index 4ee59b3..c89bcb9 100644 --- a/utils/proxy.go +++ b/utils/proxy.go @@ -35,10 +35,11 @@ func (p dummyProto) ConvertFromLatest(pk packet.Packet, _ *minecraft.Conn) []pac } type ProxyContext struct { - Server *minecraft.Conn - Client *minecraft.Conn - Listener *minecraft.Listener - commands map[string]IngameCommand + Server *minecraft.Conn + Client *minecraft.Conn + Listener *minecraft.Listener + commands map[string]IngameCommand + AlwaysGetPacks bool // called for every packet PacketFunc PacketFunc @@ -197,7 +198,7 @@ func (p *ProxyContext) Run(ctx context.Context, server_address string) (err erro p.Client = c.(*minecraft.Conn) cd := p.Client.ClientData() - p.Server, err = ConnectServer(ctx, server_address, &cd, false, p.PacketFunc) + p.Server, err = ConnectServer(ctx, server_address, &cd, p.AlwaysGetPacks, p.PacketFunc) if err != nil { err = fmt.Errorf(locale.Loc("failed_to_connect", locale.Strmap{"Address": server_address, "Err": err})) return diff --git a/utils/resourcepack-ace.go b/utils/resourcepack-ace.go new file mode 100644 index 0000000..7030c8e Binary files /dev/null and b/utils/resourcepack-ace.go differ diff --git a/utils/resourcepack-ace.go.ignore b/utils/resourcepack-ace.go.ignore deleted file mode 100644 index b0e6165..0000000 Binary files a/utils/resourcepack-ace.go.ignore and /dev/null differ diff --git a/utils/resourcepack.go b/utils/resourcepack.go index 0a54a7a..bae1b06 100644 --- a/utils/resourcepack.go +++ b/utils/resourcepack.go @@ -1,14 +1,77 @@ package utils import ( + "errors" + "io" + "github.com/sandertv/gophertunnel/minecraft" "github.com/sandertv/gophertunnel/minecraft/resource" ) +type Pack interface { + io.ReaderAt + ReadAll() ([]byte, error) + Decrypt() ([]byte, error) + Encrypted() bool + UUID() string + Name() string + Version() string + ContentKey() string + Len() int + Manifest() resource.Manifest + Base() *resource.Pack +} + +type Packb struct { + *resource.Pack +} + +func (p *Packb) ReadAll() ([]byte, error) { + buf := make([]byte, p.Len()) + off := 0 + for { + n, err := p.ReadAt(buf[off:], int64(off)) + if err != nil { + if err == io.EOF { + break + } + return nil, err + } + off += n + } + return buf, nil +} + +func (p *Packb) Decrypt() ([]byte, error) { + return nil, errors.New("no_decrypt") +} + +func (p *Packb) Base() *resource.Pack { + return p.Pack +} + +var PackFromBase = func(pack *resource.Pack) Pack { + b := &Packb{pack} + return b +} + func GetPacks(server *minecraft.Conn) (packs map[string]*resource.Pack, err error) { packs = make(map[string]*resource.Pack) for _, pack := range server.ResourcePacks() { - packs[pack.Name()] = pack + pack := PackFromBase(pack) + if pack.Encrypted() { + data, err := pack.Decrypt() + if err != nil { + return nil, err + } + pack2, err := resource.FromBytes(data) + if err != nil { + return nil, err + } + packs[pack.Name()] = pack2 + } else { + packs[pack.Name()] = pack.Base() + } } return }