update 1.21.130
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
|
token.tok
|
||||||
|
example-proxy
|
||||||
@@ -7,21 +7,21 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/akmalfairuz/legacy-version/legacyver"
|
"github.com/akmalfairuz/legacy-version/legacyver"
|
||||||
"github.com/pelletier/go-toml"
|
"github.com/pelletier/go-toml"
|
||||||
"github.com/sandertv/gophertunnel/minecraft"
|
"github.com/sandertv/gophertunnel/minecraft"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/auth"
|
"github.com/sandertv/gophertunnel/minecraft/auth"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The following program implements a proxy that forwards players from one local address to a remote address.
|
// The following program implements a proxy that forwards players from one local address to a remote address.
|
||||||
func main() {
|
func main() {
|
||||||
config := readConfig()
|
config := readConfig()
|
||||||
token, err := auth.RequestLiveToken()
|
src := tokenSource()
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
src := auth.RefreshTokenSource(token)
|
|
||||||
|
|
||||||
p, err := minecraft.NewForeignStatusProvider(config.Connection.RemoteAddress)
|
p, err := minecraft.NewForeignStatusProvider(config.Connection.RemoteAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -98,6 +98,12 @@ func handleConn(conn *minecraft.Conn, listener *minecraft.Listener, config confi
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fmt.Println(pk.ID())
|
||||||
|
time.Sleep(time.Millisecond * 1000)
|
||||||
|
if pk.ID() == 498 {
|
||||||
|
fmt.Println("skipping packet 498")
|
||||||
|
continue
|
||||||
|
}
|
||||||
if err := conn.WritePacket(pk); err != nil {
|
if err := conn.WritePacket(pk); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -144,3 +150,41 @@ func readConfig() config {
|
|||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tokenSource returns a token source for using with a gophertunnel client. It either reads it from the
|
||||||
|
// token.tok file if cached or requests logging in with a device code.
|
||||||
|
func tokenSource() oauth2.TokenSource {
|
||||||
|
check := func(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token := new(oauth2.Token)
|
||||||
|
tokenData, err := os.ReadFile("token.tok")
|
||||||
|
if err == nil {
|
||||||
|
_ = json.Unmarshal(tokenData, token)
|
||||||
|
} else {
|
||||||
|
token, err = auth.RequestLiveToken()
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
src := auth.RefreshTokenSource(token)
|
||||||
|
_, err = src.Token()
|
||||||
|
if err != nil {
|
||||||
|
// The cached refresh token expired and can no longer be used to obtain a new token. We require the
|
||||||
|
// user to log in again and use that token instead.
|
||||||
|
token, err = auth.RequestLiveToken()
|
||||||
|
check(err)
|
||||||
|
src = auth.RefreshTokenSource(token)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
c := make(chan os.Signal, 3)
|
||||||
|
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
|
||||||
|
<-c
|
||||||
|
|
||||||
|
tok, _ := src.Token()
|
||||||
|
b, _ := json.Marshal(tok)
|
||||||
|
_ = os.WriteFile("token.tok", b, 0644)
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -11,7 +11,7 @@ require (
|
|||||||
github.com/pelletier/go-toml v1.9.5
|
github.com/pelletier/go-toml v1.9.5
|
||||||
github.com/rogpeppe/go-internal v1.14.1
|
github.com/rogpeppe/go-internal v1.14.1
|
||||||
github.com/samber/lo v1.49.1
|
github.com/samber/lo v1.49.1
|
||||||
github.com/sandertv/gophertunnel v1.51.0
|
github.com/sandertv/gophertunnel v1.51.1
|
||||||
github.com/segmentio/fasthash v1.0.3
|
github.com/segmentio/fasthash v1.0.3
|
||||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b
|
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b
|
||||||
golang.org/x/image v0.25.0
|
golang.org/x/image v0.25.0
|
||||||
@@ -24,7 +24,7 @@ require (
|
|||||||
github.com/df-mc/jsonc v1.0.5 // indirect
|
github.com/df-mc/jsonc v1.0.5 // indirect
|
||||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||||
github.com/golang/snappy v1.0.0 // indirect
|
github.com/golang/snappy v1.0.0 // indirect
|
||||||
github.com/klauspost/compress v1.18.1 // indirect
|
github.com/klauspost/compress v1.18.2 // indirect
|
||||||
github.com/sandertv/go-raknet v1.14.3-0.20250305181847-6af3e95113d6 // indirect
|
github.com/sandertv/go-raknet v1.14.3-0.20250305181847-6af3e95113d6 // indirect
|
||||||
golang.org/x/mod v0.28.0 // indirect
|
golang.org/x/mod v0.28.0 // indirect
|
||||||
golang.org/x/net v0.46.0 // indirect
|
golang.org/x/net v0.46.0 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -24,8 +24,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
|
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||||
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
|
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"renamedIds": {
|
||||||
|
"minecraft:chain": "minecraft:iron_chain"
|
||||||
|
}
|
||||||
|
}
|
||||||
40
internal/typeconf/types.go
Normal file
40
internal/typeconf/types.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package typeconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StringToInt[T ~uint8 | ~int8 | ~uint16 | ~int16 | ~uint32 | ~int32 | ~uint64 | ~int64](s string, fallback int) T {
|
||||||
|
var result T
|
||||||
|
_, err := fmt.Sscanf(s, "%d", &result)
|
||||||
|
if err != nil {
|
||||||
|
return T(fallback)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func IntToString[T ~uint8 | ~int8 | ~uint16 | ~int16 | ~uint32 | ~int32 | ~uint64 | ~int64](i T, fallback string) string {
|
||||||
|
return fmt.Sprintf("%d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BoolToByte(b bool) byte {
|
||||||
|
if b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ByteToBool(b byte) bool {
|
||||||
|
return b != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IntToInt[T1 ~uint8 | ~int8 | ~uint16 | ~int16 | ~uint32 | ~int32 | ~uint64 | ~int64, T2 ~uint8 | ~int8 | ~uint16 | ~int16 | ~uint32 | ~int32 | ~uint64 | ~int64](i T1) T2 {
|
||||||
|
return T2(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SliceIntToSliceInt[T1 ~uint8 | ~int8 | ~uint16 | ~int16 | ~uint32 | ~int32 | ~uint64 | ~int64, T2 ~uint8 | ~int8 | ~uint16 | ~int16 | ~uint32 | ~int32 | ~uint64 | ~int64](in []T1) []T2 {
|
||||||
|
return lo.Map(in, func(i T1, _ int) T2 {
|
||||||
|
return T2(i)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ var (
|
|||||||
// must be set to true if you're using Dragonfly.
|
// must be set to true if you're using Dragonfly.
|
||||||
func All(dragonflyMapping bool) []minecraft.Protocol {
|
func All(dragonflyMapping bool) []minecraft.Protocol {
|
||||||
return []minecraft.Protocol{
|
return []minecraft.Protocol{
|
||||||
|
New859(dragonflyMapping),
|
||||||
New844(dragonflyMapping),
|
New844(dragonflyMapping),
|
||||||
New827(dragonflyMapping),
|
New827(dragonflyMapping),
|
||||||
New819(dragonflyMapping),
|
New819(dragonflyMapping),
|
||||||
|
|||||||
BIN
legacyver/data/block_states_898.nbt
Normal file
BIN
legacyver/data/block_states_898.nbt
Normal file
Binary file not shown.
9608
legacyver/data/required_item_list_898.json
Normal file
9608
legacyver/data/required_item_list_898.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,15 +11,16 @@ import (
|
|||||||
type Animate struct {
|
type Animate struct {
|
||||||
// ActionType is the ID of the animation action to execute. It is one of the action type constants that
|
// ActionType is the ID of the animation action to execute. It is one of the action type constants that
|
||||||
// may be found above.
|
// may be found above.
|
||||||
ActionType int32
|
ActionType uint8
|
||||||
// EntityRuntimeID is the runtime ID of the player that the animation should be played upon. The runtime
|
// EntityRuntimeID is the runtime ID of the player that the animation should be played upon. The runtime
|
||||||
// ID is unique for each world session, and entities are generally identified in packets using this
|
// ID is unique for each world session, and entities are generally identified in packets using this
|
||||||
// runtime ID.
|
// runtime ID.
|
||||||
EntityRuntimeID uint64
|
EntityRuntimeID uint64
|
||||||
// Data ...
|
// Data ...
|
||||||
Data float32
|
Data float32
|
||||||
// RowingTime is the time for rowing actions.
|
// SwingSource is the source for swing actions. It is one of the action type constants that
|
||||||
RowingTime float32
|
// may be found above.
|
||||||
|
SwingSource protocol.Optional[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID ...
|
// ID ...
|
||||||
@@ -28,16 +29,18 @@ func (*Animate) ID() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pk *Animate) Marshal(io protocol.IO) {
|
func (pk *Animate) Marshal(io protocol.IO) {
|
||||||
io.Varint32(&pk.ActionType)
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
io.Varuint64(&pk.EntityRuntimeID)
|
io.Uint8(&pk.ActionType)
|
||||||
if proto.IsProtoGTE(io, proto.ID859) {
|
|
||||||
io.Float32(&pk.Data)
|
|
||||||
if pk.ActionType == packet.AnimateActionRowLeft || pk.ActionType == packet.AnimateActionRowRight {
|
|
||||||
io.Float32(&pk.RowingTime)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if pk.ActionType&0x80 != 0 {
|
v := int32(pk.ActionType)
|
||||||
io.Float32(&pk.RowingTime)
|
io.Varint32(&v)
|
||||||
}
|
pk.ActionType = uint8(v)
|
||||||
|
}
|
||||||
|
io.Varuint64(&pk.EntityRuntimeID)
|
||||||
|
if proto.IsProtoGTE(io, proto.ID859) || (pk.ActionType == 128 || pk.ActionType == 127) {
|
||||||
|
io.Float32(&pk.Data)
|
||||||
|
}
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
protocol.OptionalFunc(io, &pk.SwingSource, io.String)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
legacyver/legacypacket/available_commands.go
Normal file
59
legacyver/legacypacket/available_commands.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package legacypacket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AvailableCommands is sent by the server to send a list of all commands that
|
||||||
|
// the player is able to use on the server. This packet holds all the arguments
|
||||||
|
// of each commands as well, making it possible for the client to provide
|
||||||
|
// auto-completion and command usages. AvailableCommands packets can be resent,
|
||||||
|
// but the packet is often very big, so doing this very often should be avoided.
|
||||||
|
type AvailableCommands struct {
|
||||||
|
// EnumValues is a slice of all enum values of any enum in the
|
||||||
|
// AvailableCommands packet. EnumValues generally should contain each
|
||||||
|
// possible value only once. Enums are built by pointing to entries in this
|
||||||
|
// slice.
|
||||||
|
EnumValues []string
|
||||||
|
// ChainedSubcommandValues is a slice of all chained subcommand names. ChainedSubcommandValues generally should
|
||||||
|
//contain each possible value only once. ChainedSubcommands are built by pointing to entries in this slice.
|
||||||
|
ChainedSubcommandValues []string
|
||||||
|
// Suffixes, like EnumValues, is a slice of all suffix values of any command
|
||||||
|
// parameter in the AvailableCommands packet.
|
||||||
|
Suffixes []string
|
||||||
|
// Enums is a slice of all (fixed) command enums present in any of the
|
||||||
|
// commands.
|
||||||
|
Enums []proto.CommandEnum
|
||||||
|
// ChainedSubcommands is a slice of all subcommands that are followed by a chained command. An example usage of this
|
||||||
|
// is /execute which allows you to run another command as another entity or at a different position etc.
|
||||||
|
ChainedSubcommands []proto.ChainedSubcommand
|
||||||
|
// Commands is a list of all commands that the client should show
|
||||||
|
// client-side. The AvailableCommands packet replaces any commands sent
|
||||||
|
// before. It does not only add the commands that are sent in it.
|
||||||
|
Commands []proto.Command
|
||||||
|
// DynamicEnums is a slice of dynamic command enums. These command enums can
|
||||||
|
// be changed during runtime without having to resend an AvailableCommands
|
||||||
|
// packet.
|
||||||
|
DynamicEnums []protocol.DynamicEnum
|
||||||
|
// Constraints is a list of constraints that should be applied to certain
|
||||||
|
// options of enums in the commands above.
|
||||||
|
Constraints []protocol.CommandEnumConstraint
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID ...
|
||||||
|
func (*AvailableCommands) ID() uint32 {
|
||||||
|
return packet.IDAvailableCommands
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *AvailableCommands) Marshal(io protocol.IO) {
|
||||||
|
protocol.FuncSlice(io, &pk.EnumValues, io.String)
|
||||||
|
protocol.FuncSlice(io, &pk.ChainedSubcommandValues, io.String)
|
||||||
|
protocol.FuncSlice(io, &pk.Suffixes, io.String)
|
||||||
|
protocol.FuncIOSlice(io, &pk.Enums, proto.CommandEnumContext{EnumValues: pk.EnumValues}.Marshal)
|
||||||
|
protocol.Slice(io, &pk.ChainedSubcommands)
|
||||||
|
protocol.Slice(io, &pk.Commands)
|
||||||
|
protocol.Slice(io, &pk.DynamicEnums)
|
||||||
|
protocol.Slice(io, &pk.Constraints)
|
||||||
|
}
|
||||||
@@ -6,7 +6,10 @@ import (
|
|||||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ClientMovementPredictionSyncBitsetSize = 123
|
const (
|
||||||
|
ClientMovementPredictionSyncBitsetSize786 = 123
|
||||||
|
ClientMovementPredictionSyncBitsetSize898 = 124
|
||||||
|
)
|
||||||
|
|
||||||
// ClientMovementPredictionSync is sent by the client to the server periodically if the client has received
|
// ClientMovementPredictionSync is sent by the client to the server periodically if the client has received
|
||||||
// movement corrections from the server, containing information about client-predictions that are relevant
|
// movement corrections from the server, containing information about client-predictions that are relevant
|
||||||
@@ -45,11 +48,7 @@ func (*ClientMovementPredictionSync) ID() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pk *ClientMovementPredictionSync) Marshal(io protocol.IO) {
|
func (pk *ClientMovementPredictionSync) Marshal(io protocol.IO) {
|
||||||
if proto.IsProtoGTE(io, proto.ID786) {
|
io.Bitset(&pk.ActorFlags, proto.EntityDataFlagsLength(proto.FetchProtoID(io)))
|
||||||
io.Bitset(&pk.ActorFlags, ClientMovementPredictionSyncBitsetSize)
|
|
||||||
} else {
|
|
||||||
io.Bitset(&pk.ActorFlags, 120)
|
|
||||||
}
|
|
||||||
io.Float32(&pk.BoundingBoxScale)
|
io.Float32(&pk.BoundingBoxScale)
|
||||||
io.Float32(&pk.BoundingBoxWidth)
|
io.Float32(&pk.BoundingBoxWidth)
|
||||||
io.Float32(&pk.BoundingBoxHeight)
|
io.Float32(&pk.BoundingBoxHeight)
|
||||||
|
|||||||
86
legacyver/legacypacket/command_output.go
Normal file
86
legacyver/legacypacket/command_output.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package legacypacket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandOutput is sent by the server to the client to send text as output of a command. Most servers do not
|
||||||
|
// use this packet and instead simply send Text packets, but there is reason to send it.
|
||||||
|
// If the origin of a CommandRequest packet is not the player itself, but, for example, a websocket server,
|
||||||
|
// sending a Text packet will not do what is expected: The message should go to the websocket server, not to
|
||||||
|
// the client's chat. The CommandOutput packet will make sure the messages are relayed to the correct origin
|
||||||
|
// of the command request.
|
||||||
|
type CommandOutput struct {
|
||||||
|
// CommandOrigin is the data specifying the origin of the command. In other words, the source that the
|
||||||
|
// command request was from, such as the player itself or a websocket server. The client forwards the
|
||||||
|
// messages in this packet to the right origin, depending on what is sent here.
|
||||||
|
CommandOrigin protocol.CommandOrigin
|
||||||
|
// OutputType specifies the type of output that is sent. The OutputType sent by vanilla games appears to
|
||||||
|
// be 3, which seems to work.
|
||||||
|
OutputType string
|
||||||
|
// SuccessCount is the amount of times that a command was executed successfully as a result of the command
|
||||||
|
// that was requested. For servers, this is usually a rather meaningless fields, but for vanilla, this is
|
||||||
|
// applicable for commands created with Functions.
|
||||||
|
SuccessCount uint32
|
||||||
|
// OutputMessages is a list of all output messages that should be sent to the player. Whether they are
|
||||||
|
// shown or not, depends on the type of the messages.
|
||||||
|
OutputMessages []proto.CommandOutputMessage
|
||||||
|
// DataSet ... TODO: Find out what this is for.
|
||||||
|
DataSet protocol.Optional[string]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID ...
|
||||||
|
func (*CommandOutput) ID() uint32 {
|
||||||
|
return packet.IDCommandOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *CommandOutput) Marshal(io protocol.IO) {
|
||||||
|
proto.CommandOriginData(io, &pk.CommandOrigin)
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
io.String(&pk.OutputType)
|
||||||
|
io.Uint32(&pk.SuccessCount)
|
||||||
|
} else {
|
||||||
|
v := LegacyCommandOutputType(pk.OutputType)
|
||||||
|
io.Uint8(&v)
|
||||||
|
pk.OutputType = LatestCommandOutputType(v)
|
||||||
|
io.Varuint32(&pk.SuccessCount)
|
||||||
|
}
|
||||||
|
protocol.Slice(io, &pk.OutputMessages)
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
protocol.OptionalFunc(io, &pk.DataSet, io.String)
|
||||||
|
} else if pk.OutputType == "dataset" {
|
||||||
|
v, _ := pk.DataSet.Value()
|
||||||
|
io.String(&v)
|
||||||
|
if v != "" {
|
||||||
|
pk.DataSet = protocol.Option(v)
|
||||||
|
} else {
|
||||||
|
pk.DataSet = protocol.Optional[string]{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var legacyCommandOutputTypeMap = map[byte]string{
|
||||||
|
0: "none", // packet.CommandOutputTypeNone
|
||||||
|
1: "lastoutput", // packet.CommandOutputTypeLastOutput
|
||||||
|
2: "silent", // packet.CommandOutputTypeSilent
|
||||||
|
3: "alloutput", // packet.CommandOutputTypeAllOutput
|
||||||
|
4: "dataset", // packet.CommandOutputTypeDataSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func LegacyCommandOutputType(outputType string) byte {
|
||||||
|
for k, v := range legacyCommandOutputTypeMap {
|
||||||
|
if v == outputType {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 3 // Default to all output.
|
||||||
|
}
|
||||||
|
|
||||||
|
func LatestCommandOutputType(outputType byte) string {
|
||||||
|
if v, ok := legacyCommandOutputTypeMap[outputType]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return "alloutput" // packet.CommandOutputTypeAllOutput
|
||||||
|
}
|
||||||
43
legacyver/legacypacket/command_request.go
Normal file
43
legacyver/legacypacket/command_request.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package legacypacket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/akmalfairuz/legacy-version/internal/typeconf"
|
||||||
|
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandRequest is sent by the client to request the execution of a server-side command. Although some
|
||||||
|
// servers support sending commands using the Text packet, this packet is guaranteed to have the correct
|
||||||
|
// result.
|
||||||
|
type CommandRequest struct {
|
||||||
|
// CommandLine is the raw entered command line. The client does no parsing of the command line by itself
|
||||||
|
// (unlike it did in the early stages), but lets the server do that.
|
||||||
|
CommandLine string
|
||||||
|
// CommandOrigin is the data specifying the origin of the command. In other words, the source that the
|
||||||
|
// command was from, such as the player itself or a websocket server.
|
||||||
|
CommandOrigin protocol.CommandOrigin
|
||||||
|
// Internal specifies if the command request internal. Setting it to false seems to work and the usage of
|
||||||
|
// this field is not known.
|
||||||
|
Internal bool
|
||||||
|
// Version is the version of the command that is being executed. This field currently has no purpose or functionality.
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID ...
|
||||||
|
func (*CommandRequest) ID() uint32 {
|
||||||
|
return packet.IDCommandRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *CommandRequest) Marshal(io protocol.IO) {
|
||||||
|
io.String(&pk.CommandLine)
|
||||||
|
proto.CommandOriginData(io, &pk.CommandOrigin)
|
||||||
|
io.Bool(&pk.Internal)
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
io.String(&pk.Version)
|
||||||
|
} else {
|
||||||
|
v := typeconf.StringToInt[int32](pk.Version, 0)
|
||||||
|
io.Varint32(&v)
|
||||||
|
pk.Version = typeconf.IntToString[int32](v, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
39
legacyver/legacypacket/event.go
Normal file
39
legacyver/legacypacket/event.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package legacypacket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/akmalfairuz/legacy-version/internal/typeconf"
|
||||||
|
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event is sent by the server to send an event with additional data. It is typically sent to the client for
|
||||||
|
// telemetry reasons, much like the SimpleEvent packet.
|
||||||
|
type Event struct {
|
||||||
|
// EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and
|
||||||
|
// entities are generally identified in packets using this runtime ID.
|
||||||
|
EntityRuntimeID int64
|
||||||
|
// UsePlayerID ...
|
||||||
|
// TODO: Figure out what UsePlayerID is for.
|
||||||
|
UsePlayerID bool
|
||||||
|
// Event is the event that is transmitted.
|
||||||
|
Event protocol.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID ...
|
||||||
|
func (*Event) ID() uint32 {
|
||||||
|
return packet.IDEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *Event) Marshal(io protocol.IO) {
|
||||||
|
io.Varint64(&pk.EntityRuntimeID)
|
||||||
|
io.EventType(&pk.Event)
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
io.Bool(&pk.UsePlayerID)
|
||||||
|
} else {
|
||||||
|
v := typeconf.BoolToByte(pk.UsePlayerID)
|
||||||
|
io.Uint8(&v)
|
||||||
|
pk.UsePlayerID = typeconf.ByteToBool(v)
|
||||||
|
}
|
||||||
|
pk.Event.Marshal(io)
|
||||||
|
}
|
||||||
44
legacyver/legacypacket/interact.go
Normal file
44
legacyver/legacypacket/interact.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package legacypacket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||||
|
"github.com/go-gl/mathgl/mgl32"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interact is sent by the client when it interacts with another entity in some way. It used to be used for
|
||||||
|
// normal entity and block interaction, but this is no longer the case now.
|
||||||
|
type Interact struct {
|
||||||
|
// Action type is the ID of the action that was executed by the player. It is one of the constants that
|
||||||
|
// may be found above.
|
||||||
|
ActionType byte
|
||||||
|
// TargetEntityRuntimeID is the runtime ID of the entity that the player interacted with. This is empty
|
||||||
|
// for the InteractActionOpenInventory action type.
|
||||||
|
TargetEntityRuntimeID uint64
|
||||||
|
// Position associated with the ActionType above. For the InteractActionMouseOverEntity, this is the
|
||||||
|
// position relative to the entity moused over over which the player hovered with its mouse/touch. For the
|
||||||
|
// InteractActionLeaveVehicle, this is the position that the player spawns at after leaving the vehicle.
|
||||||
|
Position protocol.Optional[mgl32.Vec3]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID ...
|
||||||
|
func (*Interact) ID() uint32 {
|
||||||
|
return packet.IDInteract
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *Interact) Marshal(io protocol.IO) {
|
||||||
|
io.Uint8(&pk.ActionType)
|
||||||
|
io.Varuint64(&pk.TargetEntityRuntimeID)
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
protocol.OptionalFunc(io, &pk.Position, io.Vec3)
|
||||||
|
} else if pk.ActionType == packet.InteractActionMouseOverEntity || pk.ActionType == packet.InteractActionLeaveVehicle {
|
||||||
|
pos, _ := pk.Position.Value()
|
||||||
|
io.Vec3(&pos)
|
||||||
|
if pos != (mgl32.Vec3{}) {
|
||||||
|
pk.Position = protocol.Option(pos)
|
||||||
|
} else {
|
||||||
|
pk.Position = protocol.Optional[mgl32.Vec3]{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,8 @@ type MobEffect struct {
|
|||||||
Duration int32
|
Duration int32
|
||||||
// Tick is the server tick at which the packet was sent. It is used in relation to CorrectPlayerMovePrediction.
|
// Tick is the server tick at which the packet was sent. It is used in relation to CorrectPlayerMovePrediction.
|
||||||
Tick uint64
|
Tick uint64
|
||||||
|
// Ambient specifies if the effect is ambient. If set to false, it will not get treated as an ambient effect.
|
||||||
|
Ambient bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID ...
|
// ID ...
|
||||||
@@ -50,5 +52,9 @@ func (pk *MobEffect) Marshal(io protocol.IO) {
|
|||||||
} else {
|
} else {
|
||||||
io.Uint64(&pk.Tick)
|
io.Uint64(&pk.Tick)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
io.Bool(&pk.Ambient)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ type ResourcePackStack struct {
|
|||||||
// join the server. If set to true, the client gets the option to either download the resource packs and
|
// join the server. If set to true, the client gets the option to either download the resource packs and
|
||||||
// join, or quit entirely. Behaviour packs never have to be downloaded.
|
// join, or quit entirely. Behaviour packs never have to be downloaded.
|
||||||
TexturePackRequired bool
|
TexturePackRequired bool
|
||||||
// BehaviourPack is a list of behaviour packs that the client needs to download before joining the server.
|
|
||||||
// All of these behaviour packs will be applied together, and the order does not necessarily matter.
|
|
||||||
BehaviourPacks []protocol.StackResourcePack
|
|
||||||
// TexturePacks is a list of texture packs that the client needs to download before joining the server.
|
// TexturePacks is a list of texture packs that the client needs to download before joining the server.
|
||||||
// The order of these texture packs specifies the order that they are applied in on the client side. The
|
// The order of these texture packs specifies the order that they are applied in on the client side. The
|
||||||
// first in the list will be applied first.
|
// first in the list will be applied first.
|
||||||
@@ -41,7 +38,10 @@ func (*ResourcePackStack) ID() uint32 {
|
|||||||
|
|
||||||
func (pk *ResourcePackStack) Marshal(io protocol.IO) {
|
func (pk *ResourcePackStack) Marshal(io protocol.IO) {
|
||||||
io.Bool(&pk.TexturePackRequired)
|
io.Bool(&pk.TexturePackRequired)
|
||||||
protocol.Slice(io, &pk.BehaviourPacks)
|
if proto.IsProtoLT(io, proto.ID898) {
|
||||||
|
var emptyResourcePack []protocol.StackResourcePack
|
||||||
|
protocol.Slice(io, &emptyResourcePack)
|
||||||
|
}
|
||||||
protocol.Slice(io, &pk.TexturePacks)
|
protocol.Slice(io, &pk.TexturePacks)
|
||||||
io.String(&pk.BaseGameVersion)
|
io.String(&pk.BaseGameVersion)
|
||||||
protocol.SliceUint32Length(io, &pk.Experiments)
|
protocol.SliceUint32Length(io, &pk.Experiments)
|
||||||
|
|||||||
@@ -238,8 +238,6 @@ type StartGame struct {
|
|||||||
// its index in the expected block palette. This is useful for servers that wish to support multiple protocol versions
|
// its index in the expected block palette. This is useful for servers that wish to support multiple protocol versions
|
||||||
// and custom blocks, but it will result in extra bytes being written for every block in a sub chunk palette.
|
// and custom blocks, but it will result in extra bytes being written for every block in a sub chunk palette.
|
||||||
UseBlockNetworkIDHashes bool
|
UseBlockNetworkIDHashes bool
|
||||||
// TickDeathSystemsEnabled specifies if the new tick death systems are enabled.
|
|
||||||
TickDeathSystemsEnabled bool
|
|
||||||
// ServerAuthoritativeSound is currently unknown as to what it does.
|
// ServerAuthoritativeSound is currently unknown as to what it does.
|
||||||
ServerAuthoritativeSound bool
|
ServerAuthoritativeSound bool
|
||||||
}
|
}
|
||||||
@@ -338,8 +336,9 @@ func (pk *StartGame) Marshal(io protocol.IO) {
|
|||||||
io.UUID(&pk.WorldTemplateID)
|
io.UUID(&pk.WorldTemplateID)
|
||||||
io.Bool(&pk.ClientSideGeneration)
|
io.Bool(&pk.ClientSideGeneration)
|
||||||
io.Bool(&pk.UseBlockNetworkIDHashes)
|
io.Bool(&pk.UseBlockNetworkIDHashes)
|
||||||
if proto.IsProtoGTE(io, proto.ID827) {
|
if proto.IsProtoGTE(io, proto.ID827) && proto.IsProtoLT(io, proto.ID898) {
|
||||||
io.Bool(&pk.TickDeathSystemsEnabled)
|
v := false
|
||||||
|
io.Bool(&v)
|
||||||
}
|
}
|
||||||
io.Bool(&pk.ServerAuthoritativeSound)
|
io.Bool(&pk.ServerAuthoritativeSound)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ type Text struct {
|
|||||||
PlatformChatID string
|
PlatformChatID string
|
||||||
// FilteredMessage is a filtered version of Message with all the profanity removed. The client will use
|
// FilteredMessage is a filtered version of Message with all the profanity removed. The client will use
|
||||||
// this over Message if this field is not empty and they have the "Filter Profanity" setting enabled.
|
// this over Message if this field is not empty and they have the "Filter Profanity" setting enabled.
|
||||||
FilteredMessage string
|
FilteredMessage protocol.Optional[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID ...
|
// ID ...
|
||||||
@@ -59,8 +59,22 @@ func (*Text) ID() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pk *Text) Marshal(io protocol.IO) {
|
func (pk *Text) Marshal(io protocol.IO) {
|
||||||
|
if proto.IsProtoLT(io, proto.ID898) {
|
||||||
io.Uint8(&pk.TextType)
|
io.Uint8(&pk.TextType)
|
||||||
|
}
|
||||||
io.Bool(&pk.NeedsTranslation)
|
io.Bool(&pk.NeedsTranslation)
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
var categoryType uint8
|
||||||
|
if pk.TextType == TextTypeRaw || pk.TextType == TextTypeTip || pk.TextType == TextTypeSystem || pk.TextType == TextTypeObjectWhisper || pk.TextType == TextTypeObjectAnnouncement || pk.TextType == TextTypeObject {
|
||||||
|
categoryType = protocol.TextCategoryMessageOnly
|
||||||
|
} else if pk.TextType == TextTypeChat || pk.TextType == TextTypeWhisper || pk.TextType == TextTypeAnnouncement {
|
||||||
|
categoryType = protocol.TextCategoryAuthoredMessage
|
||||||
|
} else {
|
||||||
|
categoryType = protocol.TextCategoryMessageWithParameters
|
||||||
|
}
|
||||||
|
io.TextCategory(&categoryType)
|
||||||
|
io.Uint8(&pk.TextType)
|
||||||
|
}
|
||||||
switch pk.TextType {
|
switch pk.TextType {
|
||||||
case TextTypeChat, TextTypeWhisper, TextTypeAnnouncement:
|
case TextTypeChat, TextTypeWhisper, TextTypeAnnouncement:
|
||||||
io.String(&pk.SourceName)
|
io.String(&pk.SourceName)
|
||||||
@@ -71,9 +85,24 @@ func (pk *Text) Marshal(io protocol.IO) {
|
|||||||
io.String(&pk.Message)
|
io.String(&pk.Message)
|
||||||
protocol.FuncSlice(io, &pk.Parameters, io.String)
|
protocol.FuncSlice(io, &pk.Parameters, io.String)
|
||||||
}
|
}
|
||||||
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
if len(pk.Message) == 0 {
|
||||||
|
io.InvalidValue(pk.Message, "message", "string cannot be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
io.String(&pk.XUID)
|
io.String(&pk.XUID)
|
||||||
io.String(&pk.PlatformChatID)
|
io.String(&pk.PlatformChatID)
|
||||||
if proto.IsProtoGTE(io, proto.ID685) {
|
if proto.IsProtoGTE(io, proto.ID685) {
|
||||||
io.String(&pk.FilteredMessage)
|
if proto.IsProtoGTE(io, proto.ID898) {
|
||||||
|
protocol.OptionalFunc(io, &pk.FilteredMessage, io.String)
|
||||||
|
} else {
|
||||||
|
v, _ := pk.FilteredMessage.Value()
|
||||||
|
io.String(&v)
|
||||||
|
if v != "" {
|
||||||
|
pk.FilteredMessage = protocol.Option(v)
|
||||||
|
} else {
|
||||||
|
pk.FilteredMessage = protocol.Optional[string]{}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
371
legacyver/proto/command.go
Normal file
371
legacyver/proto/command.go
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/akmalfairuz/legacy-version/internal/typeconf"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
func legacyCommandPermToNew(x byte) string {
|
||||||
|
switch x {
|
||||||
|
case protocol.CommandPermissionLevelAny:
|
||||||
|
return "any"
|
||||||
|
case protocol.CommandPermissionLevelGameDirectors:
|
||||||
|
return "gamedirectors"
|
||||||
|
case protocol.CommandPermissionLevelAdmin:
|
||||||
|
return "admin"
|
||||||
|
case protocol.CommandPermissionLevelHost:
|
||||||
|
return "host"
|
||||||
|
case protocol.CommandPermissionLevelOwner:
|
||||||
|
return "owner"
|
||||||
|
case protocol.CommandPermissionLevelInternal:
|
||||||
|
return "internal"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCommandPermToLegacy(x string) byte {
|
||||||
|
switch x {
|
||||||
|
case "any":
|
||||||
|
return protocol.CommandPermissionLevelAny
|
||||||
|
case "gamedirectors":
|
||||||
|
return protocol.CommandPermissionLevelGameDirectors
|
||||||
|
case "admin":
|
||||||
|
return protocol.CommandPermissionLevelAdmin
|
||||||
|
case "host":
|
||||||
|
return protocol.CommandPermissionLevelHost
|
||||||
|
case "owner":
|
||||||
|
return protocol.CommandPermissionLevelOwner
|
||||||
|
case "internal":
|
||||||
|
return protocol.CommandPermissionLevelInternal
|
||||||
|
default:
|
||||||
|
return protocol.CommandPermissionLevelAny
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command holds the data that a command requires to be shown to a player client-side. The command is shown in
|
||||||
|
// the /help command and auto-completed using this data.
|
||||||
|
type Command struct {
|
||||||
|
// Name is the name of the command. The command may be executed using this name, and will be shown in the
|
||||||
|
// /help list with it. It currently seems that the client crashes if the Name contains uppercase letters.
|
||||||
|
Name string
|
||||||
|
// Description is the description of the command. It is shown in the /help list and when starting to write
|
||||||
|
// a command.
|
||||||
|
Description string
|
||||||
|
// Flags is a combination of flags not currently known. Leaving the Flags field empty appears to work.
|
||||||
|
Flags uint16
|
||||||
|
// PermissionLevel is the command permission level that the player required to execute this command. The
|
||||||
|
// field no longer seems to serve a purpose, as the client does not handle the execution of commands
|
||||||
|
// anymore: The permissions should be checked server-side.
|
||||||
|
PermissionLevel string
|
||||||
|
// AliasesOffset is the offset to a CommandEnum that holds the values that
|
||||||
|
// should be used as aliases for this command.
|
||||||
|
AliasesOffset uint32
|
||||||
|
// ChainedSubcommandOffsets is a slice of offsets that all point to a different ChainedSubcommand from the
|
||||||
|
// ChainedSubcommands slice in the AvailableCommands packet.
|
||||||
|
ChainedSubcommandOffsets []uint32
|
||||||
|
// Overloads is a list of command overloads that specify the ways in which a command may be executed. The
|
||||||
|
// overloads may be completely different.
|
||||||
|
Overloads []protocol.CommandOverload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) Marshal(r protocol.IO) {
|
||||||
|
r.String(&c.Name)
|
||||||
|
r.String(&c.Description)
|
||||||
|
r.Uint16(&c.Flags)
|
||||||
|
|
||||||
|
if IsProtoGTE(r, ID898) {
|
||||||
|
r.String(&c.PermissionLevel)
|
||||||
|
} else {
|
||||||
|
permLevel := byte(0)
|
||||||
|
r.Uint8(&permLevel)
|
||||||
|
c.PermissionLevel = "any"
|
||||||
|
}
|
||||||
|
r.Uint32(&c.AliasesOffset)
|
||||||
|
if IsProtoGTE(r, ID898) {
|
||||||
|
protocol.FuncSlice(r, &c.ChainedSubcommandOffsets, r.Uint32)
|
||||||
|
} else {
|
||||||
|
offsets := typeconf.SliceIntToSliceInt[uint32, uint16](c.ChainedSubcommandOffsets)
|
||||||
|
protocol.FuncSlice(r, &offsets, r.Uint16)
|
||||||
|
c.ChainedSubcommandOffsets = typeconf.SliceIntToSliceInt[uint16, uint32](offsets)
|
||||||
|
}
|
||||||
|
protocol.Slice(r, &c.Overloads)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) ToLatest() protocol.Command {
|
||||||
|
return protocol.Command{
|
||||||
|
Name: c.Name,
|
||||||
|
Description: c.Description,
|
||||||
|
Flags: c.Flags,
|
||||||
|
PermissionLevel: newCommandPermToLegacy(c.PermissionLevel),
|
||||||
|
AliasesOffset: c.AliasesOffset,
|
||||||
|
ChainedSubcommandOffsets: c.ChainedSubcommandOffsets,
|
||||||
|
Overloads: c.Overloads,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) FromLatest(latest protocol.Command) Command {
|
||||||
|
c.Name = latest.Name
|
||||||
|
c.Description = latest.Description
|
||||||
|
c.Flags = latest.Flags
|
||||||
|
c.PermissionLevel = legacyCommandPermToNew(latest.PermissionLevel)
|
||||||
|
c.AliasesOffset = latest.AliasesOffset
|
||||||
|
c.ChainedSubcommandOffsets = latest.ChainedSubcommandOffsets
|
||||||
|
c.Overloads = latest.Overloads
|
||||||
|
return *c
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandEnum represents an enum in a command usage. The enum typically has a type and a set of options that
|
||||||
|
// are valid. A value that is not one of the options results in a failure during execution.
|
||||||
|
type CommandEnum struct {
|
||||||
|
// Type is the type of the command enum. The type will show up in the command usage as the type of the
|
||||||
|
// argument if it has a certain amount of arguments, or when Options is set to true in the
|
||||||
|
// command holding the enum.
|
||||||
|
Type string
|
||||||
|
// ValueIndices holds a list of indices that point to the EnumValues slice in the
|
||||||
|
// AvailableCommandsPacket. These represent the options of the enum.
|
||||||
|
ValueIndices []uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandEnumContext holds context required for encoding command enums.
|
||||||
|
type CommandEnumContext struct {
|
||||||
|
EnumValues []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal encodes/decodes a CommandEnum.
|
||||||
|
func (ctx CommandEnumContext) Marshal(r protocol.IO, x *CommandEnum) {
|
||||||
|
r.String(&x.Type)
|
||||||
|
if IsProtoGTE(r, ID898) {
|
||||||
|
protocol.FuncSlice(r, &x.ValueIndices, r.Uint32)
|
||||||
|
} else {
|
||||||
|
protocol.FuncIOSlice(r, &x.ValueIndices, ctx.enumOption)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// enumOption writes/reads a command enum option as a byte/uint16/uint32,
|
||||||
|
// depending on the amount of enum values.
|
||||||
|
func (ctx CommandEnumContext) enumOption(r protocol.IO, opt *uint32) {
|
||||||
|
n := len(ctx.EnumValues)
|
||||||
|
switch {
|
||||||
|
case n <= math.MaxUint8:
|
||||||
|
val := byte(*opt)
|
||||||
|
r.Uint8(&val)
|
||||||
|
*opt = uint32(val)
|
||||||
|
case n <= math.MaxUint16:
|
||||||
|
val := uint16(*opt)
|
||||||
|
r.Uint16(&val)
|
||||||
|
*opt = uint32(val)
|
||||||
|
default:
|
||||||
|
r.Uint32(opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToLatest ...
|
||||||
|
func (ce *CommandEnum) ToLatest() protocol.CommandEnum {
|
||||||
|
return protocol.CommandEnum{
|
||||||
|
Type: ce.Type,
|
||||||
|
ValueIndices: ce.ValueIndices,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromLatest ...
|
||||||
|
func (ce *CommandEnum) FromLatest(latest protocol.CommandEnum) CommandEnum {
|
||||||
|
ce.Type = latest.Type
|
||||||
|
ce.ValueIndices = latest.ValueIndices
|
||||||
|
return *ce
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainedSubcommand represents a subcommand that can have chained commands, such as /execute which allows you to run
|
||||||
|
// another command as another entity or at a different position etc.
|
||||||
|
type ChainedSubcommand struct {
|
||||||
|
// Name is the name of the chained subcommand and shows up in the list as a regular subcommand enum.
|
||||||
|
Name string
|
||||||
|
// Values contains the index and parameter type of the chained subcommand.
|
||||||
|
Values []ChainedSubcommandValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ChainedSubcommand) Marshal(r protocol.IO) {
|
||||||
|
r.String(&x.Name)
|
||||||
|
protocol.Slice(r, &x.Values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToLatest ...
|
||||||
|
func (x *ChainedSubcommand) ToLatest() protocol.ChainedSubcommand {
|
||||||
|
values := make([]protocol.ChainedSubcommandValue, len(x.Values))
|
||||||
|
for i, v := range x.Values {
|
||||||
|
values[i] = v.ToLatest()
|
||||||
|
}
|
||||||
|
return protocol.ChainedSubcommand{
|
||||||
|
Name: x.Name,
|
||||||
|
Values: values,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromLatest ...
|
||||||
|
func (x *ChainedSubcommand) FromLatest(latest protocol.ChainedSubcommand) ChainedSubcommand {
|
||||||
|
x.Name = latest.Name
|
||||||
|
x.Values = make([]ChainedSubcommandValue, len(latest.Values))
|
||||||
|
for i, v := range latest.Values {
|
||||||
|
x.Values[i] = (&ChainedSubcommandValue{}).FromLatest(v)
|
||||||
|
}
|
||||||
|
return *x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainedSubcommandValue represents the value for a chained subcommand argument.
|
||||||
|
type ChainedSubcommandValue struct {
|
||||||
|
// Index is the index of the argument in the ChainedSubcommandValues slice from the AvailableCommands packet. This is
|
||||||
|
// then used to set the type specified by the Value field below.
|
||||||
|
Index uint32
|
||||||
|
// Value is a combination of the flags above and specified the type of argument. Unlike regular parameter types,
|
||||||
|
// this should NOT contain any of the special flags (valid, enum, suffixed or soft enum) but only the basic types.
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ChainedSubcommandValue) Marshal(r protocol.IO) {
|
||||||
|
if IsProtoGTE(r, ID898) {
|
||||||
|
r.Varuint32(&x.Index)
|
||||||
|
r.Varuint32(&x.Value)
|
||||||
|
} else {
|
||||||
|
v := uint16(x.Index)
|
||||||
|
r.Uint16(&v)
|
||||||
|
x.Index = uint32(v)
|
||||||
|
vv := uint16(x.Value)
|
||||||
|
r.Uint16(&vv)
|
||||||
|
x.Value = uint32(vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToLatest ...
|
||||||
|
func (x *ChainedSubcommandValue) ToLatest() protocol.ChainedSubcommandValue {
|
||||||
|
return protocol.ChainedSubcommandValue{
|
||||||
|
Index: x.Index,
|
||||||
|
Value: x.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromLatest ...
|
||||||
|
func (x *ChainedSubcommandValue) FromLatest(latest protocol.ChainedSubcommandValue) ChainedSubcommandValue {
|
||||||
|
x.Index = latest.Index
|
||||||
|
x.Value = latest.Value
|
||||||
|
return *x
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
commandOrigins = []string{
|
||||||
|
"player", // protocol.CommandOriginPlayer
|
||||||
|
"commandblock", // protocol.CommandOriginBlock
|
||||||
|
"minecartcommandblock", // protocol.CommandOriginMinecartBlock
|
||||||
|
"devconsole", // protocol.CommandOriginDevConsole
|
||||||
|
"test", // protocol.CommandOriginTest
|
||||||
|
"automationplayer", // protocol.CommandOriginAutomationPlayer
|
||||||
|
"clientautomation", // protocol.CommandOriginClientAutomation
|
||||||
|
"dedicatedserver", // protocol.CommandOriginDedicatedServer
|
||||||
|
"entity", // protocol.CommandOriginEntity
|
||||||
|
"virtual", // protocol.CommandOriginVirtual
|
||||||
|
"gameargument", // protocol.CommandOriginGameArgument
|
||||||
|
"entityserver", // protocol.CommandOriginEntityServer
|
||||||
|
"precompiled", // protocol.CommandOriginPrecompiled
|
||||||
|
"gamedirectorentityserver", // protocol.CommandOriginGameDirectorEntityServer
|
||||||
|
"scripting", // protocol.CommandOriginScript
|
||||||
|
"executecontext", // protocol.CommandOriginExecutor
|
||||||
|
}
|
||||||
|
originToLegacyMap = map[string]uint32{
|
||||||
|
"player": protocol.CommandOriginPlayer,
|
||||||
|
"commandblock": protocol.CommandOriginBlock,
|
||||||
|
"minecartcommandblock": protocol.CommandOriginMinecartBlock,
|
||||||
|
"devconsole": protocol.CommandOriginDevConsole,
|
||||||
|
"test": protocol.CommandOriginTest,
|
||||||
|
"automationplayer": protocol.CommandOriginAutomationPlayer,
|
||||||
|
"clientautomation": protocol.CommandOriginClientAutomation,
|
||||||
|
"dedicatedserver": protocol.CommandOriginDedicatedServer,
|
||||||
|
"entity": protocol.CommandOriginEntity,
|
||||||
|
"virtual": protocol.CommandOriginVirtual,
|
||||||
|
"gameargument": protocol.CommandOriginGameArgument,
|
||||||
|
"entityserver": protocol.CommandOriginEntityServer,
|
||||||
|
"precompiled": protocol.CommandOriginPrecompiled,
|
||||||
|
"gamedirectorentityserver": protocol.CommandOriginGameDirectorEntityServer,
|
||||||
|
"scripting": protocol.CommandOriginScript,
|
||||||
|
"executecontext": protocol.CommandOriginExecutor,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func commandOriginFromLegacy(legacy uint32) string {
|
||||||
|
if int(legacy) < len(commandOrigins) {
|
||||||
|
return commandOrigins[legacy]
|
||||||
|
}
|
||||||
|
return "player" // default to protocol.CommandOriginPlayer
|
||||||
|
}
|
||||||
|
|
||||||
|
func commandOriginToLegacy(origin string) uint32 {
|
||||||
|
legacy, ok := originToLegacyMap[origin]
|
||||||
|
if ok {
|
||||||
|
return legacy
|
||||||
|
}
|
||||||
|
return protocol.CommandOriginPlayer
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandOriginData reads/writes a CommandOrigin x using IO r.
|
||||||
|
func CommandOriginData(r protocol.IO, x *protocol.CommandOrigin) {
|
||||||
|
originV898 := commandOriginFromLegacy(x.Origin)
|
||||||
|
if IsProtoGTE(r, ID898) {
|
||||||
|
r.String(&originV898)
|
||||||
|
x.Origin = commandOriginToLegacy(originV898)
|
||||||
|
} else {
|
||||||
|
r.Varuint32(&x.Origin)
|
||||||
|
}
|
||||||
|
r.UUID(&x.UUID)
|
||||||
|
r.String(&x.RequestID)
|
||||||
|
if IsProtoGTE(r, ID898) {
|
||||||
|
r.Int64(&x.PlayerUniqueID)
|
||||||
|
} else if x.Origin == protocol.CommandOriginDevConsole || x.Origin == protocol.CommandOriginTest {
|
||||||
|
r.Varint64(&x.PlayerUniqueID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandOutputMessage represents a message sent by a command that holds the output of one of the commands
|
||||||
|
// executed.
|
||||||
|
type CommandOutputMessage struct {
|
||||||
|
// Success indicates if the output message was one of a successful command execution. If set to true, the
|
||||||
|
// output message is by default coloured white, whereas if set to false, the message is by default
|
||||||
|
// coloured red.
|
||||||
|
Success bool
|
||||||
|
// Message is the message that is sent to the client in the chat window. It may either be simply a
|
||||||
|
// message or a translated built-in string like 'commands.tp.success.coordinates', combined with specific
|
||||||
|
// parameters below.
|
||||||
|
Message string
|
||||||
|
// Parameters is a list of parameters that serve to supply the message sent with additional information,
|
||||||
|
// such as the position that a player was teleported to or the effect that was applied to an entity.
|
||||||
|
// These parameters only apply for the Minecraft built-in command output.
|
||||||
|
Parameters []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal encodes/decodes a CommandOutputMessage.
|
||||||
|
func (x *CommandOutputMessage) Marshal(r protocol.IO) {
|
||||||
|
if IsProtoLT(r, ID898) {
|
||||||
|
r.Bool(&x.Success)
|
||||||
|
}
|
||||||
|
r.String(&x.Message)
|
||||||
|
if IsProtoGTE(r, ID898) {
|
||||||
|
r.Bool(&x.Success)
|
||||||
|
}
|
||||||
|
protocol.FuncSlice(r, &x.Parameters, r.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToLatest ...
|
||||||
|
func (x *CommandOutputMessage) ToLatest() protocol.CommandOutputMessage {
|
||||||
|
return protocol.CommandOutputMessage{
|
||||||
|
Success: x.Success,
|
||||||
|
Message: x.Message,
|
||||||
|
Parameters: x.Parameters,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromLatest ...
|
||||||
|
func (x *CommandOutputMessage) FromLatest(latest protocol.CommandOutputMessage) CommandOutputMessage {
|
||||||
|
x.Success = latest.Success
|
||||||
|
x.Message = latest.Message
|
||||||
|
x.Parameters = latest.Parameters
|
||||||
|
return *x
|
||||||
|
}
|
||||||
@@ -28,11 +28,13 @@ func (x *FullContainerName) Marshal(r protocol.IO) {
|
|||||||
r.Uint8(&x.ContainerID)
|
r.Uint8(&x.ContainerID)
|
||||||
if IsProtoGTE(r, ID729) {
|
if IsProtoGTE(r, ID729) {
|
||||||
protocol.OptionalFunc(r, &x.DynamicContainerID, r.Uint32)
|
protocol.OptionalFunc(r, &x.DynamicContainerID, r.Uint32)
|
||||||
} else if IsProtoGTE(r, 712) {
|
} else if IsProtoGTE(r, ID712) {
|
||||||
dynamicContainerID, _ := x.DynamicContainerID.Value()
|
dynamicContainerID, _ := x.DynamicContainerID.Value()
|
||||||
r.Uint32(&dynamicContainerID)
|
r.Uint32(&dynamicContainerID)
|
||||||
if dynamicContainerID != 0 {
|
if dynamicContainerID != 0 {
|
||||||
x.DynamicContainerID = protocol.Option(dynamicContainerID)
|
x.DynamicContainerID = protocol.Option(dynamicContainerID)
|
||||||
|
} else {
|
||||||
|
x.DynamicContainerID = protocol.Optional[uint32]{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
legacyver/proto/entity_metadata.go
Normal file
20
legacyver/proto/entity_metadata.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package proto
|
||||||
|
|
||||||
|
func EntityDataFlagsLength(protoID int32) int {
|
||||||
|
if protoID >= ID898 {
|
||||||
|
return 127
|
||||||
|
}
|
||||||
|
if protoID >= ID844 {
|
||||||
|
return 126
|
||||||
|
}
|
||||||
|
if protoID >= ID818 {
|
||||||
|
return 125
|
||||||
|
}
|
||||||
|
if protoID >= ID800 {
|
||||||
|
return 124
|
||||||
|
}
|
||||||
|
if protoID >= ID786 {
|
||||||
|
return 123
|
||||||
|
}
|
||||||
|
return 120
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package proto
|
|||||||
import "github.com/sandertv/gophertunnel/minecraft/protocol"
|
import "github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
ID898 = 898 // v1.21.130
|
||||||
ID859 = 859 // v1.21.120
|
ID859 = 859 // v1.21.120
|
||||||
ID844 = 844 // v1.21.110
|
ID844 = 844 // v1.21.110
|
||||||
ID827 = 827 // v1.21.100
|
ID827 = 827 // v1.21.100
|
||||||
|
|||||||
@@ -131,6 +131,16 @@ func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packe
|
|||||||
return func() packet.Packet { return &legacypacket.GameRulesChanged{} }
|
return func() packet.Packet { return &legacypacket.GameRulesChanged{} }
|
||||||
case packet.IDAnimate:
|
case packet.IDAnimate:
|
||||||
return func() packet.Packet { return &legacypacket.Animate{} }
|
return func() packet.Packet { return &legacypacket.Animate{} }
|
||||||
|
case packet.IDAvailableCommands:
|
||||||
|
return func() packet.Packet { return &legacypacket.AvailableCommands{} }
|
||||||
|
case packet.IDCommandOutput:
|
||||||
|
return func() packet.Packet { return &legacypacket.CommandOutput{} }
|
||||||
|
case packet.IDCommandRequest:
|
||||||
|
return func() packet.Packet { return &legacypacket.CommandRequest{} }
|
||||||
|
case packet.IDEvent:
|
||||||
|
return func() packet.Packet { return &legacypacket.Event{} }
|
||||||
|
case packet.IDInteract:
|
||||||
|
return func() packet.Packet { return &legacypacket.Interact{} }
|
||||||
default:
|
default:
|
||||||
return cur
|
return cur
|
||||||
}
|
}
|
||||||
@@ -193,7 +203,6 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
|||||||
case *packet.ResourcePackStack:
|
case *packet.ResourcePackStack:
|
||||||
pks[pkIndex] = &legacypacket.ResourcePackStack{
|
pks[pkIndex] = &legacypacket.ResourcePackStack{
|
||||||
TexturePackRequired: pk.TexturePackRequired,
|
TexturePackRequired: pk.TexturePackRequired,
|
||||||
BehaviourPacks: pk.BehaviourPacks,
|
|
||||||
TexturePacks: pk.TexturePacks,
|
TexturePacks: pk.TexturePacks,
|
||||||
BaseGameVersion: pk.BaseGameVersion,
|
BaseGameVersion: pk.BaseGameVersion,
|
||||||
Experiments: pk.Experiments,
|
Experiments: pk.Experiments,
|
||||||
@@ -296,6 +305,7 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
|||||||
Particles: pk.Particles,
|
Particles: pk.Particles,
|
||||||
Duration: pk.Duration,
|
Duration: pk.Duration,
|
||||||
Tick: pk.Tick,
|
Tick: pk.Tick,
|
||||||
|
Ambient: pk.Ambient,
|
||||||
}
|
}
|
||||||
case *packet.CameraAimAssist:
|
case *packet.CameraAimAssist:
|
||||||
pks[pkIndex] = &legacypacket.CameraAimAssist{
|
pks[pkIndex] = &legacypacket.CameraAimAssist{
|
||||||
@@ -599,7 +609,6 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
|||||||
ScenarioID: pk.ScenarioID,
|
ScenarioID: pk.ScenarioID,
|
||||||
OwnerID: pk.OwnerID,
|
OwnerID: pk.OwnerID,
|
||||||
UseBlockNetworkIDHashes: pk.UseBlockNetworkIDHashes,
|
UseBlockNetworkIDHashes: pk.UseBlockNetworkIDHashes,
|
||||||
TickDeathSystemsEnabled: pk.TickDeathSystemsEnabled,
|
|
||||||
ServerAuthoritativeSound: pk.ServerAuthoritativeSound,
|
ServerAuthoritativeSound: pk.ServerAuthoritativeSound,
|
||||||
}
|
}
|
||||||
case *packet.CodeBuilderSource:
|
case *packet.CodeBuilderSource:
|
||||||
@@ -693,10 +702,7 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
|||||||
case *packet.PlayerSkin:
|
case *packet.PlayerSkin:
|
||||||
pk.Skin.GeometryDataEngineVersion = []byte(p.Ver())
|
pk.Skin.GeometryDataEngineVersion = []byte(p.Ver())
|
||||||
case *packet.ClientMovementPredictionSync:
|
case *packet.ClientMovementPredictionSync:
|
||||||
actorFlags := pk.ActorFlags
|
actorFlags := fitBitset(pk.ActorFlags, proto.EntityDataFlagsLength(p.ID()))
|
||||||
if p.ID() < proto.ID786 {
|
|
||||||
actorFlags = fitBitset(actorFlags, 120)
|
|
||||||
}
|
|
||||||
pks[pkIndex] = &legacypacket.ClientMovementPredictionSync{
|
pks[pkIndex] = &legacypacket.ClientMovementPredictionSync{
|
||||||
ActorFlags: actorFlags,
|
ActorFlags: actorFlags,
|
||||||
BoundingBoxScale: pk.BoundingBoxScale,
|
BoundingBoxScale: pk.BoundingBoxScale,
|
||||||
@@ -764,7 +770,61 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
|||||||
ActionType: pk.ActionType,
|
ActionType: pk.ActionType,
|
||||||
EntityRuntimeID: pk.EntityRuntimeID,
|
EntityRuntimeID: pk.EntityRuntimeID,
|
||||||
Data: pk.Data,
|
Data: pk.Data,
|
||||||
RowingTime: pk.RowingTime,
|
SwingSource: pk.SwingSource,
|
||||||
|
}
|
||||||
|
case *packet.AvailableCommands:
|
||||||
|
commands := make([]proto.Command, len(pk.Commands))
|
||||||
|
for i, c := range pk.Commands {
|
||||||
|
commands[i] = (&proto.Command{}).FromLatest(c)
|
||||||
|
}
|
||||||
|
enums := make([]proto.CommandEnum, len(pk.Enums))
|
||||||
|
for i, e := range pk.Enums {
|
||||||
|
enums[i] = (&proto.CommandEnum{}).FromLatest(e)
|
||||||
|
}
|
||||||
|
chainedSubcommands := make([]proto.ChainedSubcommand, len(pk.ChainedSubcommands))
|
||||||
|
for i, c := range pk.ChainedSubcommands {
|
||||||
|
chainedSubcommands[i] = (&proto.ChainedSubcommand{}).FromLatest(c)
|
||||||
|
}
|
||||||
|
pks[pkIndex] = &legacypacket.AvailableCommands{
|
||||||
|
EnumValues: pk.EnumValues,
|
||||||
|
ChainedSubcommandValues: pk.ChainedSubcommandValues,
|
||||||
|
Suffixes: pk.Suffixes,
|
||||||
|
Enums: enums,
|
||||||
|
ChainedSubcommands: chainedSubcommands,
|
||||||
|
Commands: commands,
|
||||||
|
DynamicEnums: pk.DynamicEnums,
|
||||||
|
Constraints: pk.Constraints,
|
||||||
|
}
|
||||||
|
case *packet.CommandOutput:
|
||||||
|
outputMessages := make([]proto.CommandOutputMessage, len(pk.OutputMessages))
|
||||||
|
for i, outputMessage := range pk.OutputMessages {
|
||||||
|
outputMessages[i] = (&proto.CommandOutputMessage{}).FromLatest(outputMessage)
|
||||||
|
}
|
||||||
|
pks[pkIndex] = &legacypacket.CommandOutput{
|
||||||
|
CommandOrigin: pk.CommandOrigin,
|
||||||
|
OutputType: legacypacket.LatestCommandOutputType(pk.OutputType),
|
||||||
|
SuccessCount: pk.SuccessCount,
|
||||||
|
OutputMessages: outputMessages,
|
||||||
|
DataSet: pk.DataSet,
|
||||||
|
}
|
||||||
|
case *packet.CommandRequest:
|
||||||
|
pks[pkIndex] = &legacypacket.CommandRequest{
|
||||||
|
CommandLine: pk.CommandLine,
|
||||||
|
CommandOrigin: pk.CommandOrigin,
|
||||||
|
Internal: pk.Internal,
|
||||||
|
Version: pk.Version,
|
||||||
|
}
|
||||||
|
case *packet.Event:
|
||||||
|
pks[pkIndex] = &legacypacket.Event{
|
||||||
|
EntityRuntimeID: pk.EntityRuntimeID,
|
||||||
|
UsePlayerID: pk.UsePlayerID,
|
||||||
|
Event: pk.Event,
|
||||||
|
}
|
||||||
|
case *packet.Interact:
|
||||||
|
pks[pkIndex] = &legacypacket.Interact{
|
||||||
|
ActionType: pk.ActionType,
|
||||||
|
TargetEntityRuntimeID: pk.TargetEntityRuntimeID,
|
||||||
|
Position: pk.Position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -786,7 +846,6 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
|||||||
case *legacypacket.ResourcePackStack:
|
case *legacypacket.ResourcePackStack:
|
||||||
pks[pkIndex] = &packet.ResourcePackStack{
|
pks[pkIndex] = &packet.ResourcePackStack{
|
||||||
TexturePackRequired: pk.TexturePackRequired,
|
TexturePackRequired: pk.TexturePackRequired,
|
||||||
BehaviourPacks: pk.BehaviourPacks,
|
|
||||||
TexturePacks: pk.TexturePacks,
|
TexturePacks: pk.TexturePacks,
|
||||||
BaseGameVersion: pk.BaseGameVersion,
|
BaseGameVersion: pk.BaseGameVersion,
|
||||||
Experiments: pk.Experiments,
|
Experiments: pk.Experiments,
|
||||||
@@ -886,6 +945,7 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
|||||||
Particles: pk.Particles,
|
Particles: pk.Particles,
|
||||||
Duration: pk.Duration,
|
Duration: pk.Duration,
|
||||||
Tick: pk.Tick,
|
Tick: pk.Tick,
|
||||||
|
Ambient: pk.Ambient,
|
||||||
}
|
}
|
||||||
case *legacypacket.CameraAimAssist:
|
case *legacypacket.CameraAimAssist:
|
||||||
pks[pkIndex] = &packet.CameraAimAssist{
|
pks[pkIndex] = &packet.CameraAimAssist{
|
||||||
@@ -1177,7 +1237,6 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
|||||||
ScenarioID: pk.ScenarioID,
|
ScenarioID: pk.ScenarioID,
|
||||||
OwnerID: pk.OwnerID,
|
OwnerID: pk.OwnerID,
|
||||||
UseBlockNetworkIDHashes: pk.UseBlockNetworkIDHashes,
|
UseBlockNetworkIDHashes: pk.UseBlockNetworkIDHashes,
|
||||||
TickDeathSystemsEnabled: pk.TickDeathSystemsEnabled,
|
|
||||||
ServerAuthoritativeSound: pk.ServerAuthoritativeSound,
|
ServerAuthoritativeSound: pk.ServerAuthoritativeSound,
|
||||||
}
|
}
|
||||||
case *legacypacket.CodeBuilderSource:
|
case *legacypacket.CodeBuilderSource:
|
||||||
@@ -1316,7 +1375,61 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
|||||||
ActionType: pk.ActionType,
|
ActionType: pk.ActionType,
|
||||||
EntityRuntimeID: pk.EntityRuntimeID,
|
EntityRuntimeID: pk.EntityRuntimeID,
|
||||||
Data: pk.Data,
|
Data: pk.Data,
|
||||||
RowingTime: pk.RowingTime,
|
SwingSource: pk.SwingSource,
|
||||||
|
}
|
||||||
|
case *legacypacket.AvailableCommands:
|
||||||
|
enums := make([]protocol.CommandEnum, len(pk.Enums))
|
||||||
|
for i, e := range pk.Enums {
|
||||||
|
enums[i] = e.ToLatest()
|
||||||
|
}
|
||||||
|
chainedSubcommands := make([]protocol.ChainedSubcommand, len(pk.ChainedSubcommands))
|
||||||
|
for i, c := range pk.ChainedSubcommands {
|
||||||
|
chainedSubcommands[i] = c.ToLatest()
|
||||||
|
}
|
||||||
|
commands := make([]protocol.Command, len(pk.Commands))
|
||||||
|
for i, c := range pk.Commands {
|
||||||
|
commands[i] = c.ToLatest()
|
||||||
|
}
|
||||||
|
pks[pkIndex] = &packet.AvailableCommands{
|
||||||
|
EnumValues: pk.EnumValues,
|
||||||
|
ChainedSubcommandValues: pk.ChainedSubcommandValues,
|
||||||
|
Suffixes: pk.Suffixes,
|
||||||
|
Enums: enums,
|
||||||
|
ChainedSubcommands: chainedSubcommands,
|
||||||
|
Commands: commands,
|
||||||
|
DynamicEnums: pk.DynamicEnums,
|
||||||
|
Constraints: pk.Constraints,
|
||||||
|
}
|
||||||
|
case *legacypacket.CommandOutput:
|
||||||
|
outputMessages := make([]protocol.CommandOutputMessage, len(pk.OutputMessages))
|
||||||
|
for i, outputMessage := range pk.OutputMessages {
|
||||||
|
outputMessages[i] = outputMessage.ToLatest()
|
||||||
|
}
|
||||||
|
pks[pkIndex] = &packet.CommandOutput{
|
||||||
|
CommandOrigin: pk.CommandOrigin,
|
||||||
|
OutputType: legacypacket.LegacyCommandOutputType(pk.OutputType),
|
||||||
|
SuccessCount: pk.SuccessCount,
|
||||||
|
OutputMessages: outputMessages,
|
||||||
|
DataSet: pk.DataSet,
|
||||||
|
}
|
||||||
|
case *legacypacket.CommandRequest:
|
||||||
|
pks[pkIndex] = &packet.CommandRequest{
|
||||||
|
CommandLine: pk.CommandLine,
|
||||||
|
CommandOrigin: pk.CommandOrigin,
|
||||||
|
Internal: pk.Internal,
|
||||||
|
Version: pk.Version,
|
||||||
|
}
|
||||||
|
case *legacypacket.Event:
|
||||||
|
pks[pkIndex] = &packet.Event{
|
||||||
|
EntityRuntimeID: pk.EntityRuntimeID,
|
||||||
|
UsePlayerID: pk.UsePlayerID,
|
||||||
|
Event: pk.Event,
|
||||||
|
}
|
||||||
|
case *legacypacket.Interact:
|
||||||
|
pks[pkIndex] = &packet.Interact{
|
||||||
|
ActionType: pk.ActionType,
|
||||||
|
TargetEntityRuntimeID: pk.TargetEntityRuntimeID,
|
||||||
|
Position: pk.Position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// ItemVersion844 ...
|
// ItemVersion844 ...
|
||||||
ItemVersion844 = 241
|
ItemVersion844 = 251
|
||||||
// BlockVersion844 ...
|
// BlockVersion844 ...
|
||||||
BlockVersion844 int32 = (1 << 24) | (21 << 16) | (111 << 8)
|
BlockVersion844 int32 = (1 << 24) | (21 << 16) | (111 << 8)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,32 +3,31 @@ package legacyver
|
|||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||||
"github.com/akmalfairuz/legacy-version/mapping"
|
"github.com/akmalfairuz/legacy-version/mapping"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ItemVersion859 ...
|
// ItemVersion859 ...
|
||||||
ItemVersion859 = 241
|
ItemVersion859 = 251
|
||||||
// BlockVersion859 ...
|
// BlockVersion859 ...
|
||||||
BlockVersion859 int32 = (1 << 24) | (21 << 16) | (120 << 8)
|
BlockVersion859 int32 = (1 << 24) | (21 << 16) | (120 << 8)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
//go:embed data/dragonfly_items.json
|
|
||||||
dragonflyLatestItemList []byte
|
|
||||||
//go:embed data/required_item_list_859.json
|
//go:embed data/required_item_list_859.json
|
||||||
requiredItemList859 []byte
|
requiredItemList859 []byte
|
||||||
//go:embed data/block_states_859.nbt
|
//go:embed data/block_states_859.nbt
|
||||||
blockStateData859 []byte
|
blockStateData859 []byte
|
||||||
|
|
||||||
itemMappingLatestPocketMine = mapping.NewItemMapping(requiredItemList859, ItemVersion859)
|
|
||||||
itemMappingLatestDragonfly = mapping.NewItemMapping(dragonflyLatestItemList, ItemVersion859)
|
|
||||||
blockMappingLatest = mapping.NewBlockMapping(blockStateData859)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func itemMappingLatest(dragonflyMapping bool) mapping.Item {
|
func New859(dragonflyMapping bool) *Protocol {
|
||||||
if dragonflyMapping {
|
itemMapping := mapping.NewItemMapping(requiredItemList859, ItemVersion859)
|
||||||
return itemMappingLatestDragonfly
|
blockTranslator := lookupOrCreateBlockTranslator(859, BlockVersion859, blockStateData859)
|
||||||
|
return &Protocol{
|
||||||
|
ver: "1.21.120",
|
||||||
|
id: proto.ID859,
|
||||||
|
blockTranslator: blockTranslator,
|
||||||
|
itemTranslator: NewItemTranslator(itemMapping, itemMappingLatest(dragonflyMapping), blockTranslator.BlockMapping(), blockMappingLatest),
|
||||||
}
|
}
|
||||||
return itemMappingLatestPocketMine
|
|
||||||
}
|
}
|
||||||
|
|||||||
34
legacyver/v898.go
Normal file
34
legacyver/v898.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package legacyver
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/akmalfairuz/legacy-version/mapping"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ItemVersion898 ...
|
||||||
|
ItemVersion898 = 251
|
||||||
|
// BlockVersion898 ...
|
||||||
|
BlockVersion898 int32 = (1 << 24) | (21 << 16) | (130 << 8)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed data/dragonfly_items.json
|
||||||
|
dragonflyLatestItemList []byte
|
||||||
|
//go:embed data/required_item_list_898.json
|
||||||
|
requiredItemList898 []byte
|
||||||
|
//go:embed data/block_states_898.nbt
|
||||||
|
blockStateData898 []byte
|
||||||
|
|
||||||
|
itemMappingLatestPocketMine = mapping.NewItemMapping(requiredItemList898, ItemVersion898)
|
||||||
|
itemMappingLatestDragonfly = mapping.NewItemMapping(dragonflyLatestItemList, ItemVersion898)
|
||||||
|
blockMappingLatest = mapping.NewBlockMapping(blockStateData898)
|
||||||
|
)
|
||||||
|
|
||||||
|
func itemMappingLatest(dragonflyMapping bool) mapping.Item {
|
||||||
|
if dragonflyMapping {
|
||||||
|
return itemMappingLatestDragonfly
|
||||||
|
}
|
||||||
|
return itemMappingLatestPocketMine
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user