1.21.60 support
This commit is contained in:
@@ -5,6 +5,7 @@ A gophertunnel protocol interface implementation to support older Minecraft Bedr
|
||||
## Supported Versions
|
||||
| Protocol ID | Version | Support |
|
||||
|-------------|---------|---------|
|
||||
| 776 | 1.21.60 | ✅ |
|
||||
| 766 | 1.21.50 | ✅ |
|
||||
| 748 | 1.21.40 | ✅ |
|
||||
| 729 | 1.21.30 | ✅ |
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The following program implements a proxy that forwards players from one local address to a remote address.
|
||||
@@ -28,6 +29,7 @@ func main() {
|
||||
listener, err := minecraft.ListenConfig{
|
||||
StatusProvider: p,
|
||||
AcceptedProtocols: []minecraft.Protocol{
|
||||
legacyver.New766(),
|
||||
legacyver.New748(),
|
||||
legacyver.New729(),
|
||||
legacyver.New712(),
|
||||
@@ -54,7 +56,7 @@ func handleConn(conn *minecraft.Conn, listener *minecraft.Listener, config confi
|
||||
serverConn, err := minecraft.Dialer{
|
||||
TokenSource: src,
|
||||
ClientData: conn.ClientData(),
|
||||
}.Dial("raknet", config.Connection.RemoteAddress)
|
||||
}.DialTimeout("raknet", config.Connection.RemoteAddress, time.Second*100)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
10
go.mod
10
go.mod
@@ -10,11 +10,11 @@ require (
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/rogpeppe/go-internal v1.13.1
|
||||
github.com/samber/lo v1.47.0
|
||||
github.com/sandertv/gophertunnel v1.43.1
|
||||
github.com/sandertv/gophertunnel v1.44.1-0.20250211173944-b0dbda19ad6a
|
||||
github.com/segmentio/fasthash v1.0.3
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67
|
||||
golang.org/x/image v0.21.0
|
||||
golang.org/x/oauth2 v0.24.0
|
||||
golang.org/x/oauth2 v0.26.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -27,8 +27,8 @@ require (
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
|
||||
github.com/sandertv/go-raknet v1.14.2 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
)
|
||||
|
||||
14
go.sum
14
go.sum
@@ -49,6 +49,10 @@ github.com/sandertv/gophertunnel v1.43.1-0.20241229203958-5af8736ae319 h1:yxDqIv
|
||||
github.com/sandertv/gophertunnel v1.43.1-0.20241229203958-5af8736ae319/go.mod h1:XuEJo+ARim+NKiD90Z56sQRcDtCOErz26e2bt3LEd9I=
|
||||
github.com/sandertv/gophertunnel v1.43.1 h1:wY6Fy8dRMKtpZUQzCR35o9k05135vOJZhrz0GF6OXFI=
|
||||
github.com/sandertv/gophertunnel v1.43.1/go.mod h1:XuEJo+ARim+NKiD90Z56sQRcDtCOErz26e2bt3LEd9I=
|
||||
github.com/sandertv/gophertunnel v1.43.2-0.20250207144337-b2857453171d h1:JK3btKqp1QUPWLfgXyTUaKa8wUHJnO0Z3jqdKebbNq0=
|
||||
github.com/sandertv/gophertunnel v1.43.2-0.20250207144337-b2857453171d/go.mod h1:XuEJo+ARim+NKiD90Z56sQRcDtCOErz26e2bt3LEd9I=
|
||||
github.com/sandertv/gophertunnel v1.44.1-0.20250211173944-b0dbda19ad6a h1:1dFrVCwemoApT79gWY0PMjMTjZooS553YNRvml6IA2Y=
|
||||
github.com/sandertv/gophertunnel v1.44.1-0.20250211173944-b0dbda19ad6a/go.mod h1:XuEJo+ARim+NKiD90Z56sQRcDtCOErz26e2bt3LEd9I=
|
||||
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
|
||||
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -61,6 +65,8 @@ golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
@@ -80,10 +86,16 @@ golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
||||
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
|
||||
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -112,6 +124,8 @@ golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"remappedMetas": {
|
||||
"minecraft:boat": {
|
||||
"9": "minecraft:pale_oak_boat"
|
||||
},
|
||||
"minecraft:chest_boat": {
|
||||
"9": "minecraft:pale_oak_chest_boat"
|
||||
},
|
||||
"minecraft:spawn_egg": {
|
||||
"146": "minecraft:creaking_spawn_egg"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
legacyver/data/block_states_776.nbt
Normal file
BIN
legacyver/data/block_states_776.nbt
Normal file
Binary file not shown.
BIN
legacyver/data/item_runtime_ids_776.nbt
Normal file
BIN
legacyver/data/item_runtime_ids_776.nbt
Normal file
Binary file not shown.
8947
legacyver/data/required_item_list_776.json
Normal file
8947
legacyver/data/required_item_list_776.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,8 @@ package legacyver
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/akmalfairuz/legacy-version/internal/item"
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/akmalfairuz/legacy-version/mapping"
|
||||
"github.com/akmalfairuz/legacy-version/packbuilder"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
@@ -39,6 +39,10 @@ type ItemTranslator interface {
|
||||
Register(item world.CustomItem, replacement string)
|
||||
// CustomItems lists all custom items used as substitutes, with the runtime id as the key
|
||||
CustomItems() map[int32]world.CustomItem
|
||||
// DowngradeLegacyItemRegistry ...
|
||||
DowngradeLegacyItemRegistry(entries []proto.LegacyItemRegistryEntry) []proto.LegacyItemRegistryEntry
|
||||
// UpgradeLegacyItemRegistry ...
|
||||
UpgradeLegacyItemRegistry(entries []proto.LegacyItemRegistryEntry) []proto.LegacyItemRegistryEntry
|
||||
}
|
||||
|
||||
type DefaultItemTranslator struct {
|
||||
@@ -480,15 +484,29 @@ func (t *DefaultItemTranslator) DowngradeItemPackets(pks []packet.Packet, _ *min
|
||||
})
|
||||
pk.EventData = (itemType.NetworkID << 16) | int32(itemType.MetadataValue)
|
||||
}
|
||||
case *packet.StartGame:
|
||||
for i, entry := range pk.Items {
|
||||
//case *packet.ItemRegistry:
|
||||
// for _, i := range t.CustomItems() {
|
||||
// name, _ := i.EncodeItem()
|
||||
// pk.Items = append(pk.Items, protocol.ItemEntry{
|
||||
// Name: name,
|
||||
// Data: packbuilder.Components(i),
|
||||
// })
|
||||
// }
|
||||
}
|
||||
result = append(result, pk)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) DowngradeLegacyItemRegistry(entries []proto.LegacyItemRegistryEntry) []proto.LegacyItemRegistryEntry {
|
||||
for i, entry := range entries {
|
||||
if !entry.ComponentBased {
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{
|
||||
NetworkID: int32(entry.RuntimeID),
|
||||
MetadataValue: 0,
|
||||
})
|
||||
if itemType.NetworkID == t.mapping.Air() {
|
||||
removeIndex(pk.Items, i)
|
||||
removeIndex(entries, i)
|
||||
continue
|
||||
}
|
||||
entry.RuntimeID = int16(itemType.NetworkID)
|
||||
@@ -498,31 +516,50 @@ func (t *DefaultItemTranslator) DowngradeItemPackets(pks []packet.Packet, _ *min
|
||||
panic(itemType)
|
||||
}
|
||||
} else {
|
||||
t.latest.RegisterEntry(entry.Name)
|
||||
t.latest.RegisterEntryRID(entry.Name, int32(entry.RuntimeID), 2)
|
||||
entry.RuntimeID = int16(t.mapping.RegisterEntry(entry.Name))
|
||||
}
|
||||
pk.Items[i] = entry
|
||||
entries[i] = entry
|
||||
}
|
||||
for rid, i := range t.CustomItems() {
|
||||
name, _ := i.EncodeItem()
|
||||
pk.Items = append(pk.Items, protocol.ItemEntry{
|
||||
entries = append(entries, proto.LegacyItemRegistryEntry{
|
||||
Name: name,
|
||||
RuntimeID: int16(rid),
|
||||
ComponentBased: true,
|
||||
})
|
||||
}
|
||||
case *packet.ItemComponent:
|
||||
for _, i := range t.CustomItems() {
|
||||
return entries
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeLegacyItemRegistry(entries []proto.LegacyItemRegistryEntry) []proto.LegacyItemRegistryEntry {
|
||||
for i, entry := range entries {
|
||||
if !entry.ComponentBased {
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{
|
||||
NetworkID: int32(entry.RuntimeID),
|
||||
MetadataValue: 0,
|
||||
})
|
||||
entry.RuntimeID = int16(itemType.NetworkID)
|
||||
|
||||
var ok bool
|
||||
if entry.Name, ok = t.latest.ItemRuntimeIDToName(itemType.NetworkID); !ok {
|
||||
panic(itemType)
|
||||
}
|
||||
} else {
|
||||
t.latest.RegisterEntryRID(entry.Name, int32(entry.RuntimeID), 2)
|
||||
entry.RuntimeID = int16(t.mapping.RegisterEntry(entry.Name))
|
||||
}
|
||||
entries[i] = entry
|
||||
}
|
||||
for rid, i := range t.CustomItems() {
|
||||
name, _ := i.EncodeItem()
|
||||
pk.Items = append(pk.Items, protocol.ItemComponentEntry{
|
||||
entries = append(entries, proto.LegacyItemRegistryEntry{
|
||||
Name: name,
|
||||
Data: packbuilder.Components(i),
|
||||
RuntimeID: int16(rid),
|
||||
ComponentBased: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
result = append(result, pk)
|
||||
}
|
||||
return result
|
||||
return entries
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeItemPackets(pks []packet.Packet, _ *minecraft.Conn) (result []packet.Packet) {
|
||||
@@ -703,41 +740,14 @@ func (t *DefaultItemTranslator) UpgradeItemPackets(pks []packet.Packet, _ *minec
|
||||
})
|
||||
pk.EventData = (itemType.NetworkID << 16) | int32(itemType.MetadataValue)
|
||||
}
|
||||
case *packet.StartGame:
|
||||
for i, entry := range pk.Items {
|
||||
if !entry.ComponentBased {
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{
|
||||
NetworkID: int32(entry.RuntimeID),
|
||||
MetadataValue: 0,
|
||||
})
|
||||
entry.RuntimeID = int16(itemType.NetworkID)
|
||||
|
||||
var ok bool
|
||||
if entry.Name, ok = t.latest.ItemRuntimeIDToName(itemType.NetworkID); !ok {
|
||||
panic(itemType)
|
||||
}
|
||||
} else {
|
||||
t.latest.RegisterEntry(entry.Name)
|
||||
entry.RuntimeID = int16(t.mapping.RegisterEntry(entry.Name))
|
||||
}
|
||||
pk.Items[i] = entry
|
||||
}
|
||||
for rid, i := range t.CustomItems() {
|
||||
name, _ := i.EncodeItem()
|
||||
pk.Items = append(pk.Items, protocol.ItemEntry{
|
||||
Name: name,
|
||||
RuntimeID: int16(rid),
|
||||
ComponentBased: true,
|
||||
})
|
||||
}
|
||||
case *packet.ItemComponent:
|
||||
for _, i := range t.CustomItems() {
|
||||
name, _ := i.EncodeItem()
|
||||
pk.Items = append(pk.Items, protocol.ItemComponentEntry{
|
||||
Name: name,
|
||||
Data: packbuilder.Components(i),
|
||||
})
|
||||
}
|
||||
//case *packet.ItemRegistry:
|
||||
// for _, i := range t.CustomItems() {
|
||||
// name, _ := i.EncodeItem()
|
||||
// pk.Items = append(pk.Items, protocol.ItemEntry{
|
||||
// Name: name,
|
||||
// Data: packbuilder.Components(i),
|
||||
// })
|
||||
// }
|
||||
}
|
||||
result = append(result, pk)
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ type AddPlayer struct {
|
||||
// attributes of the entity.
|
||||
EntityProperties protocol.EntityProperties
|
||||
// AbilityData represents various data about the abilities of a player, such as ability layers or permissions.
|
||||
AbilityData protocol.AbilityData
|
||||
AbilityData proto.AbilityData
|
||||
// EntityLinks is a list of entity links that are currently active on the player. These links alter the
|
||||
// way the player shows up when first spawned in terms of it shown as riding an entity. Setting these
|
||||
// links is important for new viewers to see the player is riding another entity.
|
||||
|
||||
115
legacyver/legacypacket/boss_event.go
Normal file
115
legacyver/legacypacket/boss_event.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
const (
|
||||
BossEventShow = iota
|
||||
BossEventRegisterPlayer
|
||||
BossEventHide
|
||||
BossEventUnregisterPlayer
|
||||
BossEventHealthPercentage
|
||||
BossEventTitle
|
||||
BossEventAppearanceProperties
|
||||
BossEventTexture
|
||||
BossEventRequest
|
||||
)
|
||||
|
||||
const (
|
||||
BossEventColourGrey = iota
|
||||
BossEventColourBlue
|
||||
BossEventColourRed
|
||||
BossEventColourGreen
|
||||
BossEventColourYellow
|
||||
BossEventColourPurple
|
||||
BossEventColourWhite
|
||||
)
|
||||
|
||||
// BossEvent is sent by the server to make a specific 'boss event' occur in the
|
||||
// world. It includes features such as showing a boss bar to the player and
|
||||
// turning the sky dark.
|
||||
type BossEvent struct {
|
||||
// BossEntityUniqueID is the unique ID of the boss entity that the boss
|
||||
// event sent involves. By default, the health percentage and title of the
|
||||
// boss bar depend on the health and name tag of this entity. If
|
||||
// BossEntityUniqueID is the same as the client's entity unique ID, its
|
||||
// HealthPercentage and BossBarTitle can be freely altered.
|
||||
BossEntityUniqueID int64
|
||||
// EventType is the type of the event. The fields written depend on the
|
||||
// event type set, and some event types are sent by the client, whereas
|
||||
// others are sent by the server. The event type is one of the constants
|
||||
// above.
|
||||
EventType uint32
|
||||
// PlayerUniqueID is the unique ID of the player that is registered to or
|
||||
// unregistered from the boss fight. It is set if EventType is either
|
||||
// BossEventRegisterPlayer or BossEventUnregisterPlayer.
|
||||
PlayerUniqueID int64
|
||||
// BossBarTitle is the title shown above the boss bar. It may be set to set
|
||||
// a different title if the BossEntityUniqueID matches the client's entity
|
||||
// unique ID.
|
||||
BossBarTitle string
|
||||
// FilteredBossBarTitle is a filtered version of BossBarTitle with all the
|
||||
// profanity removed. The client will use this over BossBarTitle if this
|
||||
// field is not empty and they have the "Filter Profanity" setting enabled.
|
||||
FilteredBossBarTitle string
|
||||
// HealthPercentage is the percentage of health that is shown in the boss
|
||||
// bar (0.0-1.0). The HealthPercentage may be set to a specific value if the
|
||||
// BossEntityUniqueID matches the client's entity unique ID.
|
||||
HealthPercentage float32
|
||||
// ScreenDarkening currently seems not to do anything.
|
||||
ScreenDarkening uint16
|
||||
// Colour is the colour of the boss bar that is shown when a player is
|
||||
// subscribed. It is only set if the EventType is BossEventShow,
|
||||
// BossEventAppearanceProperties or BossEventTexture. This is functional as
|
||||
// of 1.18 and can be any of the BossEventColour constants listed above.
|
||||
Colour uint32
|
||||
// Overlay is the overlay of the boss bar that is shown on top of the boss
|
||||
// bar when a player is subscribed. It currently does not function. It is
|
||||
// only set if the EventType is BossEventShow, BossEventAppearanceProperties
|
||||
// or BossEventTexture.
|
||||
Overlay uint32
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*BossEvent) ID() uint32 {
|
||||
return packet.IDBossEvent
|
||||
}
|
||||
|
||||
func (pk *BossEvent) Marshal(io protocol.IO) {
|
||||
io.Varint64(&pk.BossEntityUniqueID)
|
||||
io.Varuint32(&pk.EventType)
|
||||
switch pk.EventType {
|
||||
case BossEventShow:
|
||||
io.String(&pk.BossBarTitle)
|
||||
if proto.IsProtoGTE(io, proto.ID776) {
|
||||
io.String(&pk.FilteredBossBarTitle)
|
||||
}
|
||||
io.Float32(&pk.HealthPercentage)
|
||||
io.Uint16(&pk.ScreenDarkening)
|
||||
io.Varuint32(&pk.Colour)
|
||||
io.Varuint32(&pk.Overlay)
|
||||
case BossEventRegisterPlayer, BossEventUnregisterPlayer, BossEventRequest:
|
||||
io.Varint64(&pk.PlayerUniqueID)
|
||||
case BossEventHide:
|
||||
// No extra payload for this boss event type.
|
||||
case BossEventHealthPercentage:
|
||||
io.Float32(&pk.HealthPercentage)
|
||||
case BossEventTitle:
|
||||
io.String(&pk.BossBarTitle)
|
||||
if proto.IsProtoGTE(io, proto.ID776) {
|
||||
io.String(&pk.FilteredBossBarTitle)
|
||||
}
|
||||
case BossEventAppearanceProperties:
|
||||
io.Uint16(&pk.ScreenDarkening)
|
||||
io.Varuint32(&pk.Colour)
|
||||
io.Varuint32(&pk.Overlay)
|
||||
case BossEventTexture:
|
||||
io.Varuint32(&pk.Colour)
|
||||
io.Varuint32(&pk.Overlay)
|
||||
default:
|
||||
io.UnknownEnumOption(pk.EventType, "boss event type")
|
||||
}
|
||||
}
|
||||
36
legacyver/legacypacket/camera_aim_assist_presets.go
Normal file
36
legacyver/legacypacket/camera_aim_assist_presets.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
const (
|
||||
CameraAunAssistPresetOperationSet = iota
|
||||
CameraAunAssistPresetOperationAddToExisting
|
||||
)
|
||||
|
||||
// CameraAimAssistPresets is sent by the server to the client to provide a list of categories and presets
|
||||
// that can be used when sending a CameraAimAssist packet or a CameraInstruction including aim assist.
|
||||
type CameraAimAssistPresets struct {
|
||||
// CategoryGroups is a list of groups of categories which can be referenced by one of the Presets.
|
||||
CategoryGroups []protocol.CameraAimAssistCategoryGroup
|
||||
// Presets is a list of presets which define a base for how aim assist should behave
|
||||
Presets []protocol.CameraAimAssistPreset
|
||||
// Operation is the operation to perform with the presets. It is one of the constants above.
|
||||
Operation byte
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*CameraAimAssistPresets) ID() uint32 {
|
||||
return packet.IDCameraAimAssistPresets
|
||||
}
|
||||
|
||||
func (pk *CameraAimAssistPresets) Marshal(io protocol.IO) {
|
||||
protocol.Slice(io, &pk.CategoryGroups)
|
||||
protocol.Slice(io, &pk.Presets)
|
||||
if proto.IsProtoGTE(io, proto.ID776) {
|
||||
io.Uint8(&pk.Operation)
|
||||
}
|
||||
}
|
||||
24
legacyver/legacypacket/client_cheat_ability.go
Normal file
24
legacyver/legacypacket/client_cheat_ability.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// ClientCheatAbility functions the same as UpdateAbilities. It is unclear why these two were separated.
|
||||
//
|
||||
// Deprecated: ClientCheatAbility is deprecated as of 1.20.10.
|
||||
type ClientCheatAbility struct {
|
||||
// AbilityData represents various data about the abilities of a player, such as ability layers or permissions.
|
||||
AbilityData proto.AbilityData
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*ClientCheatAbility) ID() uint32 {
|
||||
return packet.IDClientCheatAbility
|
||||
}
|
||||
|
||||
func (pk *ClientCheatAbility) Marshal(io protocol.IO) {
|
||||
protocol.Single(io, &pk.AbilityData)
|
||||
}
|
||||
88
legacyver/legacypacket/command_block_update.go
Normal file
88
legacyver/legacypacket/command_block_update.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
const (
|
||||
CommandBlockImpulse = iota
|
||||
CommandBlockRepeating
|
||||
CommandBlockChain
|
||||
)
|
||||
|
||||
// CommandBlockUpdate is sent by the client to update a command block at a specific position. The command
|
||||
// block may be either a physical block or an entity.
|
||||
type CommandBlockUpdate struct {
|
||||
// Block specifies if the command block updated was an actual physical block. If false, the command block
|
||||
// is in a minecart and has an entity runtime ID instead.
|
||||
Block bool
|
||||
|
||||
// Position is the position of the command block updated. It is only set if Block is set to true. Nothing
|
||||
// happens if no command block is set at this position.
|
||||
Position protocol.BlockPos
|
||||
// Mode is the mode of the command block. It is either CommandBlockImpulse, CommandBlockChain or
|
||||
// CommandBlockRepeat. It is only set if Block is set to true.
|
||||
Mode uint32
|
||||
// NeedsRedstone specifies if the command block needs to be powered by redstone to be activated. If false,
|
||||
// the command block is always active. The field is only set if Block is set to true.
|
||||
NeedsRedstone bool
|
||||
// Conditional specifies the behaviour of the command block if the command block before it (the opposite
|
||||
// side of the direction the arrow if facing) fails to execute. If set to false, it will activate at all
|
||||
// times, whereas if set to true, it will activate only if the previous command block executed
|
||||
// successfully. The field is only set if Block is set to true.
|
||||
Conditional bool
|
||||
|
||||
// MinecartEntityRuntimeID is the runtime ID of the minecart entity carrying the command block that is
|
||||
// updated. It is set only if Block is set to false.
|
||||
MinecartEntityRuntimeID uint64
|
||||
|
||||
// Command is the command currently entered in the command block. This is the command that is executed
|
||||
// when the command block is activated.
|
||||
Command string
|
||||
// LastOutput is the output of the last command executed by the command block. It may be left empty to
|
||||
// show simply no output at all, in combination with setting ShouldTrackOutput to false.
|
||||
LastOutput string
|
||||
// Name is the name of the command block updated. If not empty, it will show this name hovering above the
|
||||
// command block when hovering over the block with the cursor.
|
||||
Name string
|
||||
// FilteredName is a filtered version of Name with all the profanity removed. The client will use this
|
||||
// over Name if this field is not empty and they have the "Filter Profanity" setting enabled.
|
||||
FilteredName string
|
||||
// ShouldTrackOutput specifies if the command block tracks output. If set to false, the output box won't
|
||||
// be shown within the command block.
|
||||
ShouldTrackOutput bool
|
||||
// TickDelay is the delay in ticks between executions of a command block, if it is a repeating command
|
||||
// block.
|
||||
TickDelay int32
|
||||
// ExecuteOnFirstTick specifies if the command block should execute on the first tick, AKA as soon as the
|
||||
// command block is enabled.
|
||||
ExecuteOnFirstTick bool
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*CommandBlockUpdate) ID() uint32 {
|
||||
return packet.IDCommandBlockUpdate
|
||||
}
|
||||
|
||||
func (pk *CommandBlockUpdate) Marshal(io protocol.IO) {
|
||||
io.Bool(&pk.Block)
|
||||
if pk.Block {
|
||||
io.UBlockPos(&pk.Position)
|
||||
io.Varuint32(&pk.Mode)
|
||||
io.Bool(&pk.NeedsRedstone)
|
||||
io.Bool(&pk.Conditional)
|
||||
} else {
|
||||
io.Varuint64(&pk.MinecartEntityRuntimeID)
|
||||
}
|
||||
io.String(&pk.Command)
|
||||
io.String(&pk.LastOutput)
|
||||
io.String(&pk.Name)
|
||||
if proto.IsProtoGTE(io, proto.ID776) {
|
||||
io.String(&pk.FilteredName)
|
||||
}
|
||||
io.Bool(&pk.ShouldTrackOutput)
|
||||
io.Int32(&pk.TickDelay)
|
||||
io.Bool(&pk.ExecuteOnFirstTick)
|
||||
}
|
||||
53
legacyver/legacypacket/creative_content.go
Normal file
53
legacyver/legacypacket/creative_content.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// CreativeContent is a packet sent by the server to set the creative inventory's content for a player.
|
||||
// Introduced in 1.16, this packet replaces the previous method - sending an InventoryContent packet with
|
||||
// creative inventory window ID.
|
||||
// As of v1.21.60, this packet is no longer required to be sent as part of the login sequence however the
|
||||
// client will crash if they try to open their creative inventory before receiving this packet. Every item
|
||||
// must be part of a group, any items that are not part of a group will need to reference an "anonymous group"
|
||||
// which has an empty name OR no icon. The order of Groups and Items is how the client will render items
|
||||
// in the creative inventory compared to the previous, hard coded order.
|
||||
//
|
||||
// Below is an example of defining 2 ungrouped items, 2 grouped items and then another 2 ungrouped items, all
|
||||
// in the nature category.
|
||||
//
|
||||
// CreativeContent{
|
||||
// Groups: []protocol.CreativeGroup{
|
||||
// {Category: 1}, // No name or icon, this is the "anonymous group"
|
||||
// {Category: 1, Name: "itemGroup.name.planks", Icon: protocol.ItemStack{...}}, // A "planks" group
|
||||
// {Category: 1}, // Another "anonymous group"
|
||||
// },
|
||||
// Items: []protocol.CreativeItem{
|
||||
// {CreativeItemNetworkID: 0, Item: protocol.ItemStack{...}, GroupIndex: 0}, // Ungrouped before "planks"
|
||||
// {CreativeItemNetworkID: 1, Item: protocol.ItemStack{...}, GroupIndex: 0}, // Ungrouped before "planks"
|
||||
// {CreativeItemNetworkID: 2, Item: protocol.ItemStack{...}, GroupIndex: 1}, // Grouped under the "planks" group
|
||||
// {CreativeItemNetworkID: 3, Item: protocol.ItemStack{...}, GroupIndex: 1}, // Grouped under the "planks" group
|
||||
// {CreativeItemNetworkID: 4, Item: protocol.ItemStack{...}, GroupIndex: 2}, // Ungrouped after "planks"
|
||||
// {CreativeItemNetworkID: 5, Item: protocol.ItemStack{...}, GroupIndex: 2}, // Ungrouped after "planks"
|
||||
// }
|
||||
// }
|
||||
type CreativeContent struct {
|
||||
// Groups is a list of the groups that should be added to the creative inventory.
|
||||
Groups []protocol.CreativeGroup
|
||||
// Items is a list of the items that should be added to the creative inventory.
|
||||
Items []proto.CreativeItem
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*CreativeContent) ID() uint32 {
|
||||
return packet.IDCreativeContent
|
||||
}
|
||||
|
||||
func (pk *CreativeContent) Marshal(io protocol.IO) {
|
||||
if proto.IsProtoGTE(io, proto.ID776) {
|
||||
protocol.Slice(io, &pk.Groups)
|
||||
}
|
||||
protocol.Slice(io, &pk.Items)
|
||||
}
|
||||
25
legacyver/legacypacket/item_registry.go
Normal file
25
legacyver/legacypacket/item_registry.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// ItemRegistry is sent by the server to send the client a list of available items and attach client-side
|
||||
// components to a custom item. This packet was formerly known as the ItemComponent packet before 1.21.60,
|
||||
// which did not include item definitions but only the components.
|
||||
type ItemRegistry struct {
|
||||
// Items is a list of all items with their legacy IDs which are available in the game. Failing to send any
|
||||
// of the items that are in the game will crash mobile clients. Any custom components are also attached to
|
||||
// the items in this list.
|
||||
Items []proto.ItemEntry
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*ItemRegistry) ID() uint32 {
|
||||
return packet.IDItemRegistry
|
||||
}
|
||||
func (pk *ItemRegistry) Marshal(io protocol.IO) {
|
||||
protocol.Slice(io, &pk.Items)
|
||||
}
|
||||
@@ -200,7 +200,7 @@ type StartGame struct {
|
||||
Blocks []protocol.BlockEntry
|
||||
// Items is a list of all items with their legacy IDs which are available in the game. Failing to send any
|
||||
// of the items that are in the game will crash mobile clients.
|
||||
Items []protocol.ItemEntry
|
||||
Items []proto.LegacyItemRegistryEntry
|
||||
// MultiPlayerCorrelationID is a unique ID specifying the multi-player session of the player. A random
|
||||
// UUID should be filled out for this field.
|
||||
MultiPlayerCorrelationID string
|
||||
@@ -316,7 +316,11 @@ func (pk *StartGame) Marshal(io protocol.IO) {
|
||||
io.Int64(&pk.Time)
|
||||
io.Varint32(&pk.EnchantmentSeed)
|
||||
protocol.Slice(io, &pk.Blocks)
|
||||
if proto.IsProtoLT(io, proto.ID776) {
|
||||
protocol.Slice(io, &pk.Items)
|
||||
} else {
|
||||
proto.EmptySlice(io, &pk.Items)
|
||||
}
|
||||
io.String(&pk.MultiPlayerCorrelationID)
|
||||
io.Bool(&pk.ServerAuthoritativeInventory)
|
||||
io.String(&pk.GameVersion)
|
||||
|
||||
82
legacyver/legacypacket/structure_block_update.go
Normal file
82
legacyver/legacypacket/structure_block_update.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
const (
|
||||
StructureBlockData = iota
|
||||
StructureBlockSave
|
||||
StructureBlockLoad
|
||||
StructureBlockCorner
|
||||
StructureBlockInvalid
|
||||
StructureBlockExport
|
||||
)
|
||||
|
||||
const (
|
||||
StructureRedstoneSaveModeMemory = iota
|
||||
StructureRedstoneSaveModeDisk
|
||||
)
|
||||
|
||||
// StructureBlockUpdate is sent by the client when it updates a structure block using the in-game UI. The
|
||||
// data it contains depends on the type of structure block that it is. In Minecraft Bedrock Edition v1.11,
|
||||
// there is only the Export structure block type, but in v1.13 the ones present in Java Edition will,
|
||||
// according to the wiki, be added too.
|
||||
type StructureBlockUpdate struct {
|
||||
// Position is the position of the structure block that is updated.
|
||||
Position protocol.BlockPos
|
||||
// StructureName is the name of the structure that was set in the structure block's UI. This is the name
|
||||
// used to export the structure to a file.
|
||||
StructureName string
|
||||
// FilteredStructureName is a filtered version of StructureName with all the profanity removed. The client
|
||||
// will use this over StructureName if this field is not empty and they have the "Filter Profanity"
|
||||
// setting enabled.
|
||||
FilteredStructureName string
|
||||
// DataField is the name of a function to run, usually used during natural generation. A description can
|
||||
// be found here: https://minecraft.wiki/w/Structure_Block#Data.
|
||||
DataField string
|
||||
// IncludePlayers specifies if the 'Include Players' toggle has been enabled, meaning players are also
|
||||
// exported by the structure block.
|
||||
IncludePlayers bool
|
||||
// ShowBoundingBox specifies if the structure block should have its bounds outlined. A thin line will
|
||||
// encapsulate the bounds of the structure if set to true.
|
||||
ShowBoundingBox bool
|
||||
// StructureBlockType is the type of the structure block updated. A list of structure block types that
|
||||
// will be used can be found in the constants above.
|
||||
StructureBlockType int32
|
||||
// Settings is a struct of settings that should be used for exporting the structure. These settings are
|
||||
// identical to the last sent in the StructureBlockUpdate packet by the client.
|
||||
Settings protocol.StructureSettings
|
||||
// RedstoneSaveMode is the mode that should be used to save the structure when used with redstone. In
|
||||
// Java Edition, this is always stored in memory, but in Bedrock Edition it can be stored either to disk
|
||||
// or memory. See the constants above for the options.
|
||||
RedstoneSaveMode int32
|
||||
// ShouldTrigger specifies if the structure block should be triggered immediately after this packet
|
||||
// reaches the server.
|
||||
ShouldTrigger bool
|
||||
// Waterlogged specifies if non-air blocks replace water or combine with water.
|
||||
Waterlogged bool
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*StructureBlockUpdate) ID() uint32 {
|
||||
return packet.IDStructureBlockUpdate
|
||||
}
|
||||
|
||||
func (pk *StructureBlockUpdate) Marshal(io protocol.IO) {
|
||||
io.UBlockPos(&pk.Position)
|
||||
io.String(&pk.StructureName)
|
||||
if proto.IsProtoGTE(io, proto.ID776) {
|
||||
io.String(&pk.FilteredStructureName)
|
||||
}
|
||||
io.String(&pk.DataField)
|
||||
io.Bool(&pk.IncludePlayers)
|
||||
io.Bool(&pk.ShowBoundingBox)
|
||||
io.Varint32(&pk.StructureBlockType)
|
||||
protocol.Single(io, &pk.Settings)
|
||||
io.Varint32(&pk.RedstoneSaveMode)
|
||||
io.Bool(&pk.ShouldTrigger)
|
||||
io.Bool(&pk.Waterlogged)
|
||||
}
|
||||
23
legacyver/legacypacket/update_abilities.go
Normal file
23
legacyver/legacypacket/update_abilities.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// UpdateAbilities is a packet sent from the server to the client to update the abilities of the player. It, along with
|
||||
// the UpdateAdventureSettings packet, are replacements of the AdventureSettings packet since v1.19.10.
|
||||
type UpdateAbilities struct {
|
||||
// AbilityData represents various data about the abilities of a player, such as ability layers or permissions.
|
||||
AbilityData proto.AbilityData
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*UpdateAbilities) ID() uint32 {
|
||||
return packet.IDUpdateAbilities
|
||||
}
|
||||
|
||||
func (pk *UpdateAbilities) Marshal(io protocol.IO) {
|
||||
protocol.Single(io, &pk.AbilityData)
|
||||
}
|
||||
108
legacyver/proto/ability.go
Normal file
108
legacyver/proto/ability.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
)
|
||||
|
||||
// AbilityData represents various data about the abilities of a player, such as ability layers or permissions.
|
||||
type AbilityData struct {
|
||||
// EntityUniqueID is a unique identifier of the player. It appears it is not required to fill this field
|
||||
// out with a correct value. Simply writing 0 seems to work.
|
||||
EntityUniqueID int64
|
||||
// PlayerPermissions is the permission level of the player as it shows up in the player list built up using
|
||||
// the PlayerList packet.
|
||||
PlayerPermissions byte
|
||||
// CommandPermissions is a set of permissions that specify what commands a player is allowed to execute.
|
||||
CommandPermissions byte
|
||||
// Layers contains all ability layers and their potential values. This should at least have one entry, being the
|
||||
// base layer.
|
||||
Layers []AbilityLayer
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes an AbilityData.
|
||||
func (x *AbilityData) Marshal(r protocol.IO) {
|
||||
r.Int64(&x.EntityUniqueID)
|
||||
r.Uint8(&x.PlayerPermissions)
|
||||
r.Uint8(&x.CommandPermissions)
|
||||
protocol.SliceUint8Length(r, &x.Layers)
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (x *AbilityData) ToLatest() protocol.AbilityData {
|
||||
layers := make([]protocol.AbilityLayer, len(x.Layers))
|
||||
for i, layer := range x.Layers {
|
||||
layers[i] = layer.ToLatest()
|
||||
}
|
||||
return protocol.AbilityData{
|
||||
EntityUniqueID: x.EntityUniqueID,
|
||||
PlayerPermissions: x.PlayerPermissions,
|
||||
CommandPermissions: x.CommandPermissions,
|
||||
Layers: layers,
|
||||
}
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (x *AbilityData) FromLatest(y protocol.AbilityData) AbilityData {
|
||||
layers := make([]AbilityLayer, len(y.Layers))
|
||||
for i, layer := range y.Layers {
|
||||
layers[i] = (&AbilityLayer{}).FromLatest(layer)
|
||||
}
|
||||
x.EntityUniqueID = y.EntityUniqueID
|
||||
x.PlayerPermissions = y.PlayerPermissions
|
||||
x.CommandPermissions = y.CommandPermissions
|
||||
x.Layers = layers
|
||||
return *x
|
||||
}
|
||||
|
||||
// AbilityLayer represents the abilities of a specific layer, such as the base layer or the spectator layer.
|
||||
type AbilityLayer struct {
|
||||
// Type represents the type of the layer. This is one of the AbilityLayerType constants defined above.
|
||||
Type uint16
|
||||
// Abilities is a set of abilities that are enabled for the layer. This is one of the Ability constants defined
|
||||
// above.
|
||||
Abilities uint32
|
||||
// Values is a set of values that are associated with the enabled abilities, representing the values of the
|
||||
// abilities.
|
||||
Values uint32
|
||||
// FlySpeed is the default horizontal fly speed of the layer.
|
||||
FlySpeed float32
|
||||
// VerticalFlySpeed is the default vertical fly speed of the layer.
|
||||
VerticalFlySpeed float32
|
||||
// WalkSpeed is the default walk speed of the layer.
|
||||
WalkSpeed float32
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes an AbilityLayer.
|
||||
func (x *AbilityLayer) Marshal(r protocol.IO) {
|
||||
r.Uint16(&x.Type)
|
||||
r.Uint32(&x.Abilities)
|
||||
r.Uint32(&x.Values)
|
||||
r.Float32(&x.FlySpeed)
|
||||
if IsProtoGTE(r, ID776) {
|
||||
r.Float32(&x.VerticalFlySpeed)
|
||||
}
|
||||
r.Float32(&x.WalkSpeed)
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (x *AbilityLayer) ToLatest() protocol.AbilityLayer {
|
||||
return protocol.AbilityLayer{
|
||||
Type: x.Type,
|
||||
Abilities: x.Abilities,
|
||||
Values: x.Values,
|
||||
FlySpeed: x.FlySpeed,
|
||||
VerticalFlySpeed: x.VerticalFlySpeed,
|
||||
WalkSpeed: x.WalkSpeed,
|
||||
}
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (x *AbilityLayer) FromLatest(y protocol.AbilityLayer) AbilityLayer {
|
||||
x.Type = y.Type
|
||||
x.Abilities = y.Abilities
|
||||
x.Values = y.Values
|
||||
x.FlySpeed = y.FlySpeed
|
||||
x.VerticalFlySpeed = y.VerticalFlySpeed
|
||||
x.WalkSpeed = y.WalkSpeed
|
||||
return *x
|
||||
}
|
||||
@@ -41,6 +41,10 @@ type CameraPreset struct {
|
||||
// Radius is only used in a follow_orbit camera and controls how far away from the player the camera should
|
||||
// be rendered.
|
||||
Radius protocol.Optional[float32]
|
||||
// MinYawLimit is the minimum yaw limit of the camera.
|
||||
MinYawLimit protocol.Optional[float32]
|
||||
// MaxYawLimit is the maximum yaw limit of the camera.
|
||||
MaxYawLimit protocol.Optional[float32]
|
||||
// AudioListener defines where the audio should be played from when using this preset. This is one of the
|
||||
// constants above.
|
||||
AudioListener protocol.Optional[byte]
|
||||
@@ -95,6 +99,8 @@ func (x *CameraPreset) ToLatest() protocol.CameraPreset {
|
||||
ViewOffset: x.ViewOffset,
|
||||
EntityOffset: x.EntityOffset,
|
||||
Radius: x.Radius,
|
||||
MinYawLimit: x.MinYawLimit,
|
||||
MaxYawLimit: x.MaxYawLimit,
|
||||
AudioListener: x.AudioListener,
|
||||
PlayerEffects: x.PlayerEffects,
|
||||
AlignTargetAndCameraForward: x.AlignTargetAndCameraForward,
|
||||
@@ -123,6 +129,10 @@ func (x *CameraPreset) Marshal(r protocol.IO) {
|
||||
if IsProtoGTE(r, ID766) {
|
||||
protocol.OptionalFunc(r, &x.TrackingRadius, r.Float32)
|
||||
}
|
||||
if IsProtoGTE(r, ID776) {
|
||||
protocol.OptionalFunc(r, &x.MinYawLimit, r.Float32)
|
||||
protocol.OptionalFunc(r, &x.MaxYawLimit, r.Float32)
|
||||
}
|
||||
protocol.OptionalFunc(r, &x.ViewOffset, r.Vec2)
|
||||
if IsProtoGTE(r, ID729) {
|
||||
protocol.OptionalFunc(r, &x.EntityOffset, r.Vec3)
|
||||
|
||||
41
legacyver/proto/creative.go
Normal file
41
legacyver/proto/creative.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package proto
|
||||
|
||||
import "github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
|
||||
// CreativeItem represents a creative item present in the creative inventory.
|
||||
type CreativeItem struct {
|
||||
// CreativeItemNetworkID is a unique ID for the creative item. It has to be unique for each creative item
|
||||
// sent to the client. An incrementing ID per creative item does the job.
|
||||
CreativeItemNetworkID uint32
|
||||
// Item is the item that should be added to the creative inventory.
|
||||
Item protocol.ItemStack
|
||||
// GroupIndex is the index of the group that the item should be placed in. It is the index of the group in
|
||||
// the CreativeContent packet previously sent to the client.
|
||||
GroupIndex uint32
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (x *CreativeItem) ToLatest() protocol.CreativeItem {
|
||||
return protocol.CreativeItem{
|
||||
CreativeItemNetworkID: x.CreativeItemNetworkID,
|
||||
Item: x.Item,
|
||||
GroupIndex: x.GroupIndex,
|
||||
}
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (x *CreativeItem) FromLatest(y protocol.CreativeItem) CreativeItem {
|
||||
x.CreativeItemNetworkID = y.CreativeItemNetworkID
|
||||
x.Item = y.Item
|
||||
x.GroupIndex = y.GroupIndex
|
||||
return *x
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes a CreativeItem.
|
||||
func (x *CreativeItem) Marshal(r protocol.IO) {
|
||||
r.Varuint32(&x.CreativeItemNetworkID)
|
||||
r.Item(&x.Item)
|
||||
if IsProtoGTE(r, ID776) {
|
||||
r.Varuint32(&x.GroupIndex)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package proto
|
||||
import "github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
|
||||
const (
|
||||
ID776 = 776 // v1.21.60
|
||||
ID766 = 766 // v1.21.50
|
||||
ID748 = 748 // v1.21.40
|
||||
ID729 = 729 // v1.21.30
|
||||
|
||||
92
legacyver/proto/item.go
Normal file
92
legacyver/proto/item.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
)
|
||||
|
||||
// LegacyItemRegistryEntry is an item sent in the StartGame item table. It holds a name and a legacy ID, which is used to
|
||||
// point back to that name.
|
||||
type LegacyItemRegistryEntry struct {
|
||||
// Name if the name of the item, which is a name like 'minecraft:stick'.
|
||||
Name string
|
||||
// RuntimeID is the ID that is used to identify the item over network. After sending all items in the
|
||||
// StartGame packet, items will then be identified using these numerical IDs.
|
||||
RuntimeID int16
|
||||
// ComponentBased specifies if the item was created using components, meaning the item is a custom item.
|
||||
ComponentBased bool
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes an LegacyItemRegistryEntry.
|
||||
func (x *LegacyItemRegistryEntry) Marshal(r protocol.IO) {
|
||||
r.String(&x.Name)
|
||||
r.Int16(&x.RuntimeID)
|
||||
r.Bool(&x.ComponentBased)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (x *LegacyItemRegistryEntry) FromLatest(y protocol.ItemEntry) LegacyItemRegistryEntry {
|
||||
x.Name = y.Name
|
||||
x.RuntimeID = y.RuntimeID
|
||||
x.ComponentBased = y.ComponentBased
|
||||
return *x
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (x *LegacyItemRegistryEntry) ToLatest() protocol.ItemEntry {
|
||||
return protocol.ItemEntry{
|
||||
Name: x.Name,
|
||||
RuntimeID: x.RuntimeID,
|
||||
ComponentBased: x.ComponentBased,
|
||||
Version: 2,
|
||||
}
|
||||
}
|
||||
|
||||
// ItemEntry is an item sent in the StartGame item table. It holds a name and a legacy ID, which is used to
|
||||
// point back to that name.
|
||||
type ItemEntry struct {
|
||||
// Name if the name of the item, which is a name like 'minecraft:stick'.
|
||||
Name string
|
||||
// RuntimeID is the ID that is used to identify the item over network. After sending all items in the
|
||||
// StartGame packet, items will then be identified using these numerical IDs.
|
||||
RuntimeID int16
|
||||
// ComponentBased specifies if the item was created using components, meaning the item is a custom item.
|
||||
ComponentBased bool
|
||||
// Version is the version of the item entry which is used by the client to determine how to handle the
|
||||
// item entry. It is one of the constants above.
|
||||
Version int32
|
||||
// Data is a map containing the components and properties of the item, if the item is component based.
|
||||
Data map[string]any
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (x *ItemEntry) ToLatest() protocol.ItemEntry {
|
||||
return protocol.ItemEntry{
|
||||
Name: x.Name,
|
||||
RuntimeID: x.RuntimeID,
|
||||
ComponentBased: x.ComponentBased,
|
||||
Version: x.Version,
|
||||
Data: x.Data,
|
||||
}
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (x *ItemEntry) FromLatest(y protocol.ItemEntry) ItemEntry {
|
||||
x.Name = y.Name
|
||||
x.RuntimeID = y.RuntimeID
|
||||
x.ComponentBased = y.ComponentBased
|
||||
x.Version = y.Version
|
||||
x.Data = y.Data
|
||||
return *x
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes an ItemEntry.
|
||||
func (x *ItemEntry) Marshal(r protocol.IO) {
|
||||
r.String(&x.Name)
|
||||
if IsProtoGTE(r, ID776) {
|
||||
r.Int16(&x.RuntimeID)
|
||||
r.Bool(&x.ComponentBased)
|
||||
r.Varint32(&x.Version)
|
||||
}
|
||||
r.NBT(&x.Data, nbt.NetworkLittleEndian)
|
||||
}
|
||||
@@ -20,6 +20,10 @@ func init() {
|
||||
for pkId, cur := range packetPoolClient {
|
||||
packetPoolClient[pkId] = convertPacketFunc(pkId, cur)
|
||||
}
|
||||
|
||||
for pkId, cur := range packetPoolServer {
|
||||
packetPoolServer[pkId] = convertPacketFunc(pkId, cur)
|
||||
}
|
||||
}
|
||||
|
||||
func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packet {
|
||||
@@ -86,6 +90,22 @@ func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packe
|
||||
return func() packet.Packet { return &legacypacket.StartGame{} }
|
||||
case packet.IDCodeBuilderSource:
|
||||
return func() packet.Packet { return &legacypacket.CodeBuilderSource{} }
|
||||
case packet.IDItemRegistry:
|
||||
return func() packet.Packet { return &legacypacket.ItemRegistry{} }
|
||||
case packet.IDStructureBlockUpdate:
|
||||
return func() packet.Packet { return &legacypacket.StructureBlockUpdate{} }
|
||||
case packet.IDBossEvent:
|
||||
return func() packet.Packet { return &legacypacket.BossEvent{} }
|
||||
case packet.IDCameraAimAssistPresets:
|
||||
return func() packet.Packet { return &legacypacket.CameraAimAssistPresets{} }
|
||||
case packet.IDCommandBlockUpdate:
|
||||
return func() packet.Packet { return &legacypacket.CommandBlockUpdate{} }
|
||||
case packet.IDCreativeContent:
|
||||
return func() packet.Packet { return &legacypacket.CreativeContent{} }
|
||||
case packet.IDUpdateAbilities:
|
||||
return func() packet.Packet { return &legacypacket.UpdateAbilities{} }
|
||||
case packet.IDClientCheatAbility:
|
||||
return func() packet.Packet { return &legacypacket.ClientCheatAbility{} }
|
||||
default:
|
||||
return cur
|
||||
}
|
||||
@@ -309,7 +329,7 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
||||
GameType: pk.GameType,
|
||||
EntityMetadata: pk.EntityMetadata,
|
||||
EntityProperties: pk.EntityProperties,
|
||||
AbilityData: pk.AbilityData,
|
||||
AbilityData: (&proto.AbilityData{}).FromLatest(pk.AbilityData),
|
||||
EntityLinks: links,
|
||||
DeviceID: pk.DeviceID,
|
||||
BuildPlatform: pk.BuildPlatform,
|
||||
@@ -441,7 +461,15 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
||||
pk.GameVersion = p.ver
|
||||
pk.BaseGameVersion = p.ver
|
||||
|
||||
items := make([]proto.LegacyItemRegistryEntry, len(conn.GameData().Items))
|
||||
for i, it := range conn.GameData().Items {
|
||||
items[i] = (&proto.LegacyItemRegistryEntry{}).FromLatest(it)
|
||||
}
|
||||
|
||||
items = p.itemTranslator.DowngradeLegacyItemRegistry(items)
|
||||
|
||||
pks[pkIndex] = &legacypacket.StartGame{
|
||||
Items: items,
|
||||
EntityUniqueID: pk.EntityUniqueID,
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
PlayerGameMode: pk.PlayerGameMode,
|
||||
@@ -505,7 +533,6 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
||||
Time: pk.Time,
|
||||
EnchantmentSeed: pk.EnchantmentSeed,
|
||||
Blocks: pk.Blocks,
|
||||
Items: pk.Items,
|
||||
MultiPlayerCorrelationID: pk.MultiPlayerCorrelationID,
|
||||
ServerAuthoritativeInventory: pk.ServerAuthoritativeInventory,
|
||||
GameVersion: pk.GameVersion,
|
||||
@@ -527,6 +554,75 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
||||
Category: pk.Category,
|
||||
CodeStatus: pk.CodeStatus,
|
||||
}
|
||||
case *packet.ItemRegistry:
|
||||
items := make([]proto.ItemEntry, len(pk.Items))
|
||||
for i, it := range pk.Items {
|
||||
items[i] = (&proto.ItemEntry{}).FromLatest(it)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.ItemRegistry{
|
||||
Items: items,
|
||||
}
|
||||
case *packet.StructureBlockUpdate:
|
||||
pks[pkIndex] = &legacypacket.StructureBlockUpdate{
|
||||
Position: pk.Position,
|
||||
StructureName: pk.StructureName,
|
||||
FilteredStructureName: pk.FilteredStructureName,
|
||||
DataField: pk.DataField,
|
||||
IncludePlayers: pk.IncludePlayers,
|
||||
ShowBoundingBox: pk.ShowBoundingBox,
|
||||
StructureBlockType: pk.StructureBlockType,
|
||||
Settings: pk.Settings,
|
||||
RedstoneSaveMode: pk.RedstoneSaveMode,
|
||||
ShouldTrigger: pk.ShouldTrigger,
|
||||
Waterlogged: pk.Waterlogged,
|
||||
}
|
||||
case *packet.BossEvent:
|
||||
pks[pkIndex] = &legacypacket.BossEvent{
|
||||
BossEntityUniqueID: pk.BossEntityUniqueID,
|
||||
EventType: pk.EventType,
|
||||
PlayerUniqueID: pk.PlayerUniqueID,
|
||||
BossBarTitle: pk.BossBarTitle,
|
||||
FilteredBossBarTitle: pk.FilteredBossBarTitle,
|
||||
HealthPercentage: pk.HealthPercentage,
|
||||
ScreenDarkening: pk.ScreenDarkening,
|
||||
Colour: pk.Colour,
|
||||
Overlay: pk.Overlay,
|
||||
}
|
||||
case *packet.CameraAimAssistPresets:
|
||||
pks[pkIndex] = &legacypacket.CameraAimAssistPresets{
|
||||
CategoryGroups: pk.CategoryGroups,
|
||||
Presets: pk.Presets,
|
||||
Operation: pk.Operation,
|
||||
}
|
||||
case *packet.CommandBlockUpdate:
|
||||
pks[pkIndex] = &legacypacket.CommandBlockUpdate{
|
||||
Block: pk.Block,
|
||||
Position: pk.Position,
|
||||
Mode: pk.Mode,
|
||||
NeedsRedstone: pk.NeedsRedstone,
|
||||
Conditional: pk.Conditional,
|
||||
MinecartEntityRuntimeID: pk.MinecartEntityRuntimeID,
|
||||
Command: pk.Command,
|
||||
LastOutput: pk.LastOutput,
|
||||
Name: pk.Name,
|
||||
FilteredName: pk.FilteredName,
|
||||
ShouldTrackOutput: pk.ShouldTrackOutput,
|
||||
TickDelay: pk.TickDelay,
|
||||
ExecuteOnFirstTick: pk.ExecuteOnFirstTick,
|
||||
}
|
||||
case *packet.CreativeContent:
|
||||
items := make([]proto.CreativeItem, len(pk.Items))
|
||||
for i, it := range pk.Items {
|
||||
items[i] = (&proto.CreativeItem{}).FromLatest(it)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.CreativeContent{
|
||||
Groups: pk.Groups,
|
||||
Items: items,
|
||||
}
|
||||
case *packet.UpdateAbilities:
|
||||
pks[pkIndex] = &legacypacket.UpdateAbilities{
|
||||
AbilityData: (&proto.AbilityData{}).FromLatest(pk.AbilityData),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,7 +801,7 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
||||
GameType: pk.GameType,
|
||||
EntityMetadata: pk.EntityMetadata,
|
||||
EntityProperties: pk.EntityProperties,
|
||||
AbilityData: pk.AbilityData,
|
||||
AbilityData: pk.AbilityData.ToLatest(),
|
||||
EntityLinks: links,
|
||||
DeviceID: pk.DeviceID,
|
||||
BuildPlatform: pk.BuildPlatform,
|
||||
@@ -897,7 +993,6 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
||||
Time: pk.Time,
|
||||
EnchantmentSeed: pk.EnchantmentSeed,
|
||||
Blocks: pk.Blocks,
|
||||
Items: pk.Items,
|
||||
MultiPlayerCorrelationID: pk.MultiPlayerCorrelationID,
|
||||
ServerAuthoritativeInventory: pk.ServerAuthoritativeInventory,
|
||||
GameVersion: pk.GameVersion,
|
||||
@@ -919,6 +1014,65 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
||||
Category: pk.Category,
|
||||
CodeStatus: pk.CodeStatus,
|
||||
}
|
||||
case *legacypacket.BossEvent:
|
||||
pks[pkIndex] = &packet.BossEvent{
|
||||
BossEntityUniqueID: pk.BossEntityUniqueID,
|
||||
EventType: pk.EventType,
|
||||
PlayerUniqueID: pk.PlayerUniqueID,
|
||||
BossBarTitle: pk.BossBarTitle,
|
||||
FilteredBossBarTitle: pk.FilteredBossBarTitle,
|
||||
HealthPercentage: pk.HealthPercentage,
|
||||
ScreenDarkening: pk.ScreenDarkening,
|
||||
Colour: pk.Colour,
|
||||
Overlay: pk.Overlay,
|
||||
}
|
||||
case *legacypacket.CommandBlockUpdate:
|
||||
pks[pkIndex] = &packet.CommandBlockUpdate{
|
||||
Block: pk.Block,
|
||||
Position: pk.Position,
|
||||
Mode: pk.Mode,
|
||||
NeedsRedstone: pk.NeedsRedstone,
|
||||
Conditional: pk.Conditional,
|
||||
MinecartEntityRuntimeID: pk.MinecartEntityRuntimeID,
|
||||
Command: pk.Command,
|
||||
LastOutput: pk.LastOutput,
|
||||
Name: pk.Name,
|
||||
FilteredName: pk.FilteredName,
|
||||
ShouldTrackOutput: pk.ShouldTrackOutput,
|
||||
TickDelay: pk.TickDelay,
|
||||
ExecuteOnFirstTick: pk.ExecuteOnFirstTick,
|
||||
}
|
||||
case *legacypacket.CreativeContent:
|
||||
items := make([]protocol.CreativeItem, len(pk.Items))
|
||||
for i, it := range pk.Items {
|
||||
items[i] = it.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.CreativeContent{
|
||||
Groups: pk.Groups,
|
||||
Items: items,
|
||||
}
|
||||
case *legacypacket.ItemRegistry:
|
||||
items := make([]protocol.ItemEntry, len(pk.Items))
|
||||
for i, it := range pk.Items {
|
||||
items[i] = it.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.ItemRegistry{Items: items}
|
||||
case *legacypacket.StructureBlockUpdate:
|
||||
pks[pkIndex] = &packet.StructureBlockUpdate{
|
||||
Position: pk.Position,
|
||||
StructureName: pk.StructureName,
|
||||
FilteredStructureName: pk.FilteredStructureName,
|
||||
DataField: pk.DataField,
|
||||
IncludePlayers: pk.IncludePlayers,
|
||||
ShowBoundingBox: pk.ShowBoundingBox,
|
||||
StructureBlockType: pk.StructureBlockType,
|
||||
Settings: pk.Settings,
|
||||
RedstoneSaveMode: pk.RedstoneSaveMode,
|
||||
ShouldTrigger: pk.ShouldTrigger,
|
||||
Waterlogged: pk.Waterlogged,
|
||||
}
|
||||
case *legacypacket.UpdateAbilities:
|
||||
pks[pkIndex] = &packet.UpdateAbilities{AbilityData: pk.AbilityData.ToLatest()}
|
||||
}
|
||||
}
|
||||
return pks
|
||||
|
||||
@@ -2,12 +2,14 @@ package legacyver
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"github.com/akmalfairuz/legacy-version/internal/chunk"
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/akmalfairuz/legacy-version/mapping"
|
||||
)
|
||||
|
||||
const (
|
||||
// ItemVersion766 ...
|
||||
ItemVersion766 = 231
|
||||
ItemVersion766 = 221
|
||||
// BlockVersion766 ...
|
||||
BlockVersion766 int32 = (1 << 24) | (21 << 16) | (50 << 8)
|
||||
)
|
||||
@@ -20,6 +22,15 @@ var (
|
||||
//go:embed data/block_states_766.nbt
|
||||
blockStateData766 []byte
|
||||
|
||||
itemMappingLatest = mapping.NewItemMapping(itemRuntimeIDData766, requiredItemList766, ItemVersion766, false)
|
||||
blockMappingLatest = mapping.NewBlockMapping(blockStateData766)
|
||||
itemMapping766 = mapping.NewItemMapping(itemRuntimeIDData766, requiredItemList766, ItemVersion766, false)
|
||||
blockMapping766 = mapping.NewBlockMapping(blockStateData766)
|
||||
)
|
||||
|
||||
func New766() *Protocol {
|
||||
return &Protocol{
|
||||
ver: "1.21.50",
|
||||
id: proto.ID766,
|
||||
blockTranslator: NewBlockTranslator(blockMapping766, latestBlockMapping, chunk.NewNetworkPersistentEncoding(blockMapping766, BlockVersion766), chunk.NewBlockPaletteEncoding(blockMapping766, BlockVersion766), false),
|
||||
itemTranslator: NewItemTranslator(itemMapping766, itemMappingLatest, blockMapping766, blockMappingLatest),
|
||||
}
|
||||
}
|
||||
|
||||
25
legacyver/v776.go
Normal file
25
legacyver/v776.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package legacyver
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"github.com/akmalfairuz/legacy-version/mapping"
|
||||
)
|
||||
|
||||
const (
|
||||
// ItemVersion776 ...
|
||||
ItemVersion776 = 241
|
||||
// BlockVersion776 ...
|
||||
BlockVersion776 int32 = (1 << 24) | (21 << 16) | (60 << 8)
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed data/item_runtime_ids_776.nbt
|
||||
itemRuntimeIDData776 []byte
|
||||
//go:embed data/required_item_list_776.json
|
||||
requiredItemList776 []byte
|
||||
//go:embed data/block_states_776.nbt
|
||||
blockStateData776 []byte
|
||||
|
||||
itemMappingLatest = mapping.NewItemMapping(itemRuntimeIDData776, requiredItemList776, ItemVersion776, false)
|
||||
blockMappingLatest = mapping.NewBlockMapping(blockStateData776)
|
||||
)
|
||||
@@ -12,6 +12,7 @@ type Item interface {
|
||||
// ItemNameToRuntimeID converts a string ID to an item runtime ID.
|
||||
ItemNameToRuntimeID(string) (int32, bool)
|
||||
RegisterEntry(string) int32
|
||||
RegisterEntryRID(string, int32, uint8)
|
||||
Air() int32
|
||||
ItemVersion() uint16
|
||||
}
|
||||
@@ -22,6 +23,8 @@ type DefaultItemMapping struct {
|
||||
itemRuntimeIDsToNames map[int32]string
|
||||
// itemNamesToRuntimeIDs holds a map to translate item string IDs to runtime IDs.
|
||||
itemNamesToRuntimeIDs map[string]int32
|
||||
// itemRuntimeIDToVersion holds a map to translate item runtime IDs to versions.
|
||||
itemRuntimeIDToVersion map[int32]uint8
|
||||
airRID int32
|
||||
itemVersion uint16
|
||||
}
|
||||
@@ -29,6 +32,7 @@ type DefaultItemMapping struct {
|
||||
func NewItemMapping(itemRuntimeIDData []byte, requiredItemList []byte, itemVersion uint16, direct bool) *DefaultItemMapping {
|
||||
itemRuntimeIDsToNames := make(map[int32]string)
|
||||
itemNamesToRuntimeIDs := make(map[string]int32)
|
||||
itemRuntimeIDToVersion := make(map[int32]uint8)
|
||||
var airRID *int32
|
||||
|
||||
if direct {
|
||||
@@ -48,6 +52,7 @@ func NewItemMapping(itemRuntimeIDData []byte, requiredItemList []byte, itemVersi
|
||||
var m map[string]struct {
|
||||
RuntimeID int16 `json:"runtime_id"`
|
||||
ComponentBased bool `json:"component_based"`
|
||||
Version *uint8 `json:"version"`
|
||||
}
|
||||
if err := json.Unmarshal(requiredItemList, &m); err != nil {
|
||||
panic(err)
|
||||
@@ -60,6 +65,9 @@ func NewItemMapping(itemRuntimeIDData []byte, requiredItemList []byte, itemVersi
|
||||
|
||||
itemNamesToRuntimeIDs[name] = rid
|
||||
itemRuntimeIDsToNames[rid] = name
|
||||
if data.Version != nil {
|
||||
itemRuntimeIDToVersion[rid] = *data.Version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +75,7 @@ func NewItemMapping(itemRuntimeIDData []byte, requiredItemList []byte, itemVersi
|
||||
panic("couldn't find air")
|
||||
}
|
||||
|
||||
return &DefaultItemMapping{itemRuntimeIDsToNames: itemRuntimeIDsToNames, itemNamesToRuntimeIDs: itemNamesToRuntimeIDs, itemVersion: itemVersion}
|
||||
return &DefaultItemMapping{itemRuntimeIDsToNames: itemRuntimeIDsToNames, itemNamesToRuntimeIDs: itemNamesToRuntimeIDs, itemRuntimeIDToVersion: itemRuntimeIDToVersion, airRID: *airRID, itemVersion: itemVersion}
|
||||
}
|
||||
|
||||
func (m *DefaultItemMapping) ItemRuntimeIDToName(runtimeID int32) (name string, found bool) {
|
||||
@@ -84,6 +92,13 @@ func (m *DefaultItemMapping) ItemNameToRuntimeID(name string) (runtimeID int32,
|
||||
return rid, ok
|
||||
}
|
||||
|
||||
func (m *DefaultItemMapping) ItemRuntimeIDToVersion(runtimeID int32) (version uint8, found bool) {
|
||||
defer m.mu.Unlock()
|
||||
m.mu.Lock()
|
||||
v, ok := m.itemRuntimeIDToVersion[runtimeID]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (m *DefaultItemMapping) RegisterEntry(name string) int32 {
|
||||
defer m.mu.Unlock()
|
||||
m.mu.Lock()
|
||||
@@ -96,6 +111,16 @@ func (m *DefaultItemMapping) RegisterEntry(name string) int32 {
|
||||
return nextRID
|
||||
}
|
||||
|
||||
func (m *DefaultItemMapping) RegisterEntryRID(name string, rid int32, version uint8) {
|
||||
defer m.mu.Unlock()
|
||||
m.mu.Lock()
|
||||
if _, ok := m.itemNamesToRuntimeIDs[name]; !ok {
|
||||
m.itemNamesToRuntimeIDs[name] = rid
|
||||
m.itemRuntimeIDsToNames[rid] = name
|
||||
m.itemRuntimeIDToVersion[rid] = version
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DefaultItemMapping) Air() int32 {
|
||||
defer m.mu.Unlock()
|
||||
m.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user