bedrocktool/subcommands/skins/skins.go

192 lines
4.7 KiB
Go
Raw Normal View History

2022-09-04 14:26:32 +00:00
package skins
2022-03-05 11:59:36 +00:00
import (
"context"
"flag"
"fmt"
"os"
2022-03-05 12:59:11 +00:00
"path"
2022-03-05 11:59:36 +00:00
"strings"
2023-02-08 11:00:36 +00:00
"time"
2022-03-05 11:59:36 +00:00
"github.com/bedrock-tool/bedrocktool/locale"
2023-03-18 11:12:54 +00:00
"github.com/bedrock-tool/bedrocktool/ui/messages"
2022-09-04 14:53:21 +00:00
"github.com/bedrock-tool/bedrocktool/utils"
2022-09-04 14:26:32 +00:00
2023-02-08 18:08:26 +00:00
"github.com/google/uuid"
2022-03-05 11:59:36 +00:00
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
2022-09-04 00:24:58 +00:00
"github.com/sirupsen/logrus"
2022-03-05 11:59:36 +00:00
)
type SkinMeta struct {
SkinID string
PlayFabID string
PremiumSkin bool
PersonaSkin bool
CapeID string
SkinColour string
ArmSize string
Trusted bool
PersonaPieces []protocol.PersonaPiece
}
2023-02-08 18:08:26 +00:00
type skinsSession struct {
PlayerNameFilter string
OnlyIfHasGeometry bool
ServerName string
Proxy *utils.ProxyContext
fpath string
2023-02-08 18:08:26 +00:00
playerSkinPacks map[uuid.UUID]*SkinPack
playerNames map[uuid.UUID]string
}
func NewSkinsSession(proxy *utils.ProxyContext, serverName, fpath string) *skinsSession {
2023-02-08 18:08:26 +00:00
return &skinsSession{
ServerName: serverName,
Proxy: proxy,
fpath: fpath,
2022-03-18 18:22:31 +00:00
2023-02-08 18:08:26 +00:00
playerSkinPacks: make(map[uuid.UUID]*SkinPack),
playerNames: make(map[uuid.UUID]string),
}
}
2023-03-18 11:12:54 +00:00
func (s *skinsSession) AddPlayerSkin(playerID uuid.UUID, playerName string, skin *Skin) (added bool) {
2023-02-08 18:08:26 +00:00
p, ok := s.playerSkinPacks[playerID]
if !ok {
creating := fmt.Sprintf("Creating Skinpack for %s", playerName)
s.Proxy.SendPopup(creating)
logrus.Info(creating)
p = NewSkinPack(playerName, s.fpath)
2023-02-08 18:08:26 +00:00
s.playerSkinPacks[playerID] = p
}
2023-02-08 18:08:26 +00:00
if p.AddSkin(skin) {
if ok {
2023-03-18 11:12:54 +00:00
addedStr := fmt.Sprintf("Added a skin to %s", playerName)
s.Proxy.SendPopup(addedStr)
logrus.Info(addedStr)
}
2023-03-18 11:12:54 +00:00
added = true
}
if err := p.Save(path.Join(s.fpath, playerName), s.ServerName); err != nil {
logrus.Error(err)
}
2023-03-18 11:12:54 +00:00
return added
}
2023-03-18 11:12:54 +00:00
func (s *skinsSession) AddSkin(playerName string, playerID uuid.UUID, playerSkin *protocol.Skin) (string, *Skin, bool) {
2023-02-23 09:23:35 +00:00
if playerName == "" {
playerName = s.playerNames[playerID]
2023-02-08 18:08:26 +00:00
if playerName == "" {
2023-02-23 09:23:35 +00:00
playerName = playerID.String()
2022-03-18 18:22:31 +00:00
}
2023-02-23 09:23:35 +00:00
}
if !strings.HasPrefix(playerName, s.PlayerNameFilter) {
2023-03-18 11:12:54 +00:00
return "", nil, false
2023-02-23 09:23:35 +00:00
}
s.playerNames[playerID] = playerName
2023-02-08 18:08:26 +00:00
2023-03-18 11:12:54 +00:00
skin := &Skin{playerSkin}
2023-02-23 09:23:35 +00:00
if s.OnlyIfHasGeometry && !skin.HaveGeometry() {
2023-03-18 11:12:54 +00:00
return "", nil, false
2023-02-23 09:23:35 +00:00
}
2023-03-18 11:12:54 +00:00
wasAdded := s.AddPlayerSkin(playerID, playerName, skin)
return playerName, skin, wasAdded
}
type skinAdd struct {
PlayerName string
Skin *protocol.Skin
2023-02-23 09:23:35 +00:00
}
2023-03-18 11:12:54 +00:00
func (s *skinsSession) ProcessPacket(pk packet.Packet) (out []skinAdd) {
2023-02-23 09:23:35 +00:00
switch pk := pk.(type) {
2022-03-18 18:22:31 +00:00
case *packet.PlayerList:
2023-02-08 18:08:26 +00:00
if pk.ActionType == 1 { // remove
2023-03-18 11:12:54 +00:00
return nil
2022-03-18 18:22:31 +00:00
}
2023-02-08 18:08:26 +00:00
for _, player := range pk.Entries {
2023-03-18 11:12:54 +00:00
playerName, skin, wasAdded := s.AddSkin(utils.CleanupName(player.Username), player.UUID, &player.Skin)
if wasAdded {
out = append(out, skinAdd{
PlayerName: playerName,
Skin: skin.Skin,
})
}
2023-02-23 09:23:35 +00:00
}
case *packet.AddPlayer:
if _, ok := s.playerNames[pk.UUID]; !ok {
s.playerNames[pk.UUID] = utils.CleanupName(pk.Username)
2022-03-18 18:22:31 +00:00
}
}
2023-03-18 11:12:54 +00:00
return out
2022-03-18 18:22:31 +00:00
}
type SkinCMD struct {
2023-03-06 01:03:31 +00:00
ServerAddress string
Filter string
NoProxy bool
}
2022-07-29 16:12:06 +00:00
func (*SkinCMD) Name() string { return "skins" }
func (*SkinCMD) Synopsis() string { return locale.Loc("skins_synopsis", nil) }
2022-07-29 16:12:06 +00:00
func (c *SkinCMD) SetFlags(f *flag.FlagSet) {
2023-03-06 01:03:31 +00:00
f.StringVar(&c.ServerAddress, "address", "", locale.Loc("remote_address", nil))
f.StringVar(&c.Filter, "filter", "", locale.Loc("name_prefix", nil))
f.BoolVar(&c.NoProxy, "no-proxy", false, "use headless version")
2023-03-05 21:50:58 +00:00
}
func (c *SkinCMD) Execute(ctx context.Context, ui utils.UI) error {
2023-03-06 01:03:31 +00:00
address, hostname, err := utils.ServerInput(ctx, c.ServerAddress)
2022-08-13 14:30:46 +00:00
if err != nil {
return err
2022-08-13 14:30:46 +00:00
}
2023-03-06 01:03:31 +00:00
proxy, _ := utils.NewProxy()
proxy.WithClient = !c.NoProxy
2023-03-23 19:39:47 +00:00
proxy.OnClientConnect = func(hasClient bool) {
2023-03-18 11:12:54 +00:00
ui.Message(messages.SetUIState, messages.UIStateConnecting)
}
2023-03-23 19:39:47 +00:00
proxy.ConnectCB = func(err error) bool {
2023-02-22 15:48:24 +00:00
if err != nil {
return false
}
2023-03-18 11:12:54 +00:00
ui.Message(messages.SetUIState, messages.UIStateMain)
logrus.Info(locale.Loc("ctrl_c_to_exit", nil))
2023-02-22 15:48:24 +00:00
return true
}
2022-03-05 11:59:36 +00:00
outPathBase := fmt.Sprintf("skins/%s", hostname)
os.MkdirAll(outPathBase, 0o755)
s := NewSkinsSession(proxy, hostname, outPathBase)
2023-02-08 18:08:26 +00:00
2023-03-23 19:39:47 +00:00
proxy.PacketCB = func(pk packet.Packet, toServer bool, _ time.Time) (packet.Packet, error) {
if !toServer {
2023-03-18 11:12:54 +00:00
for _, s := range s.ProcessPacket(pk) {
ui.Message(messages.NewSkin, messages.NewSkinPayload{
PlayerName: s.PlayerName,
Skin: s.Skin,
})
}
}
return pk, nil
}
2023-03-18 11:12:54 +00:00
if proxy.WithClient {
ui.Message(messages.SetUIState, messages.UIStateConnect)
} else {
ui.Message(messages.SetUIState, messages.UIStateConnecting)
}
2023-02-08 18:08:26 +00:00
err = proxy.Run(ctx, address)
return err
2022-03-05 11:59:36 +00:00
}
func init() {
2022-09-04 14:26:32 +00:00
utils.RegisterCommand(&SkinCMD{})
}