initial commit
This commit is contained in:
22
legacyver/bitset.go
Normal file
22
legacyver/bitset.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package legacyver
|
||||
|
||||
import "github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
|
||||
func fitBitset(b protocol.Bitset, size int) protocol.Bitset {
|
||||
if b.Len() != size {
|
||||
ret := protocol.NewBitset(size)
|
||||
|
||||
copySize := b.Len()
|
||||
if copySize > size {
|
||||
copySize = size
|
||||
}
|
||||
|
||||
for i := 0; i < copySize; i++ {
|
||||
if b.Load(i) {
|
||||
ret.Set(i)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
return b
|
||||
}
|
||||
BIN
legacyver/block_states_748.nbt
Normal file
BIN
legacyver/block_states_748.nbt
Normal file
Binary file not shown.
BIN
legacyver/block_states_766.nbt
Normal file
BIN
legacyver/block_states_766.nbt
Normal file
Binary file not shown.
340
legacyver/block_translator.go
Normal file
340
legacyver/block_translator.go
Normal file
@@ -0,0 +1,340 @@
|
||||
package legacyver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"github.com/akmalfairuz/legacy-version/internal/chunk"
|
||||
"github.com/akmalfairuz/legacy-version/mapping"
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
const (
|
||||
BlockVersionLatest int32 = (1 << 24) | (21 << 16) | (50 << 8) | 29
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed block_states_766.nbt
|
||||
latestBlockStateData []byte
|
||||
|
||||
// latestBlockMapping is the BlockMapping used for translating blocks between versions.
|
||||
latestBlockMapping = mapping.NewBlockMapping(latestBlockStateData)
|
||||
// LatestNetworkPersistentEncoding is the Encoding used for sending a Chunk over network. It uses NBT, unlike NetworkEncoding.
|
||||
LatestNetworkPersistentEncoding = chunk.NewNetworkPersistentEncoding(latestBlockMapping, BlockVersionLatest)
|
||||
// LatestBlockPaletteEncoding is the paletteEncoding used for encoding a palette of block states encoded as NBT.
|
||||
LatestBlockPaletteEncoding = chunk.NewBlockPaletteEncoding(latestBlockMapping, BlockVersionLatest)
|
||||
)
|
||||
|
||||
type BlockTranslator interface {
|
||||
// DowngradeBlockPackets downgrades the input block packets to legacy block packets.
|
||||
DowngradeBlockPackets([]packet.Packet, *minecraft.Conn) (result []packet.Packet)
|
||||
// UpgradeBlockPackets upgrades the input block packets to the latest block packets.
|
||||
UpgradeBlockPackets([]packet.Packet, *minecraft.Conn) (result []packet.Packet)
|
||||
}
|
||||
|
||||
type DefaultBlockTranslator struct {
|
||||
mapping mapping.Block
|
||||
latest mapping.Block
|
||||
pse chunk.Encoding
|
||||
pe chunk.PaletteEncoding
|
||||
oldFormat bool
|
||||
}
|
||||
|
||||
func NewBlockTranslator(mapping mapping.Block, latestMapping mapping.Block, pse chunk.Encoding, pe chunk.PaletteEncoding, oldFormat bool) *DefaultBlockTranslator {
|
||||
return &DefaultBlockTranslator{mapping: mapping, latest: latestMapping, pse: pse, pe: pe, oldFormat: oldFormat}
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) DowngradeBlockPackets(pks []packet.Packet, conn *minecraft.Conn) (result []packet.Packet) {
|
||||
for _, pk := range pks {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.LevelChunk:
|
||||
count := int(pk.SubChunkCount)
|
||||
if count == protocol.SubChunkRequestModeLimitless || count == protocol.SubChunkRequestModeLimited {
|
||||
break
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(pk.RawPayload)
|
||||
writeBuf := bytes.NewBuffer(nil)
|
||||
if !pk.CacheEnabled {
|
||||
c, err := chunk.NetworkDecode(t.latest.Air(), buf, count, false, world.Overworld.Range(), LatestNetworkPersistentEncoding, LatestBlockPaletteEncoding)
|
||||
if err != nil {
|
||||
//fmt.Println(err)
|
||||
break
|
||||
}
|
||||
c = t.DowngradeChunk(c)
|
||||
|
||||
payload, err := chunk.NetworkEncode(t.mapping.Air(), c, t.oldFormat, t.pe)
|
||||
if err != nil {
|
||||
//fmt.Println(err)
|
||||
break
|
||||
}
|
||||
writeBuf.Write(payload)
|
||||
pk.SubChunkCount = uint32(len(c.Sub()))
|
||||
}
|
||||
safeBytes := buf.Bytes()
|
||||
|
||||
countBorder, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
pk.RawPayload = append(writeBuf.Bytes(), safeBytes...)
|
||||
break
|
||||
}
|
||||
borderBytes := make([]byte, countBorder)
|
||||
if _, err = buf.Read(borderBytes); err != nil {
|
||||
pk.RawPayload = append(writeBuf.Bytes(), safeBytes...)
|
||||
break
|
||||
}
|
||||
writeBuf.WriteByte(countBorder)
|
||||
writeBuf.Write(borderBytes)
|
||||
|
||||
enc := nbt.NewEncoderWithEncoding(writeBuf, nbt.NetworkLittleEndian)
|
||||
dec := nbt.NewDecoderWithEncoding(buf, nbt.NetworkLittleEndian)
|
||||
for {
|
||||
var decNbt map[string]any
|
||||
if err = dec.Decode(&decNbt); err != nil {
|
||||
break
|
||||
}
|
||||
t.mapping.DowngradeBlockActorData(decNbt)
|
||||
|
||||
if err = enc.Encode(decNbt); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
pk.RawPayload = append(writeBuf.Bytes(), buf.Bytes()...)
|
||||
case *packet.SubChunk:
|
||||
r := world.Overworld.Range()
|
||||
if t.oldFormat {
|
||||
r = cube.Range{0, 255}
|
||||
}
|
||||
|
||||
for i, entry := range pk.SubChunkEntries {
|
||||
if entry.Result == protocol.SubChunkResultSuccess {
|
||||
buf := bytes.NewBuffer(entry.RawPayload)
|
||||
writeBuf := bytes.NewBuffer(nil)
|
||||
if !pk.CacheEnabled && !conn.ClientCacheEnabled() {
|
||||
ind := byte(i)
|
||||
subChunk, err := chunk.DecodeSubChunk(t.latest.Air(), r, buf, &ind, chunk.NetworkEncoding, LatestNetworkPersistentEncoding, LatestBlockPaletteEncoding)
|
||||
if err != nil {
|
||||
//fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
t.DowngradeSubChunk(subChunk)
|
||||
writeBuf.Write(chunk.EncodeSubChunk(subChunk, chunk.NetworkEncoding, t.pe, chunk.SubChunkVersion9, r, int(ind)))
|
||||
}
|
||||
|
||||
enc := nbt.NewEncoderWithEncoding(writeBuf, nbt.NetworkLittleEndian)
|
||||
dec := nbt.NewDecoderWithEncoding(buf, nbt.NetworkLittleEndian)
|
||||
for {
|
||||
var decNbt map[string]any
|
||||
if err := dec.Decode(&decNbt); err != nil {
|
||||
break
|
||||
}
|
||||
t.mapping.DowngradeBlockActorData(decNbt)
|
||||
|
||||
if err := enc.Encode(decNbt); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
entry.RawPayload = append(writeBuf.Bytes(), buf.Bytes()...)
|
||||
pk.SubChunkEntries[i] = entry
|
||||
}
|
||||
}
|
||||
case *packet.ClientCacheMissResponse:
|
||||
r := world.Overworld.Range()
|
||||
if t.oldFormat {
|
||||
r = cube.Range{0, 255}
|
||||
}
|
||||
|
||||
for i, blob := range pk.Blobs {
|
||||
buf := bytes.NewBuffer(blob.Payload)
|
||||
ind := byte(0)
|
||||
subChunk, err := chunk.DecodeSubChunk(t.latest.Air(), r, buf, &ind, chunk.NetworkEncoding, LatestNetworkPersistentEncoding, LatestBlockPaletteEncoding)
|
||||
if err != nil {
|
||||
// Has a possibility to be a biome, ignore then
|
||||
continue
|
||||
}
|
||||
t.DowngradeSubChunk(subChunk)
|
||||
|
||||
blob.Payload = append(chunk.EncodeSubChunk(subChunk, chunk.NetworkEncoding, t.pe, chunk.SubChunkVersion9, r, int(ind)), buf.Bytes()...)
|
||||
pk.Blobs[i] = blob
|
||||
}
|
||||
case *packet.UpdateSubChunkBlocks:
|
||||
for i, block := range pk.Blocks {
|
||||
block.BlockRuntimeID = t.DowngradeBlockRuntimeID(block.BlockRuntimeID)
|
||||
pk.Blocks[i] = block
|
||||
}
|
||||
for i, block := range pk.Extra {
|
||||
block.BlockRuntimeID = t.DowngradeBlockRuntimeID(block.BlockRuntimeID)
|
||||
pk.Extra[i] = block
|
||||
}
|
||||
case *packet.UpdateBlock:
|
||||
pk.NewBlockRuntimeID = t.DowngradeBlockRuntimeID(pk.NewBlockRuntimeID)
|
||||
case *packet.UpdateBlockSynced:
|
||||
pk.NewBlockRuntimeID = t.DowngradeBlockRuntimeID(pk.NewBlockRuntimeID)
|
||||
case *packet.InventoryTransaction:
|
||||
if transactionData, ok := pk.TransactionData.(*protocol.UseItemTransactionData); ok {
|
||||
transactionData.BlockRuntimeID = t.DowngradeBlockRuntimeID(transactionData.BlockRuntimeID)
|
||||
pk.TransactionData = transactionData
|
||||
}
|
||||
case *packet.LevelEvent:
|
||||
switch pk.EventType {
|
||||
case packet.LevelEventParticleLegacyEvent | 20: // terrain
|
||||
fallthrough
|
||||
case packet.LevelEventParticlesDestroyBlock:
|
||||
fallthrough
|
||||
case packet.LevelEventParticlesDestroyBlockNoSound:
|
||||
pk.EventData = int32(t.DowngradeBlockRuntimeID(uint32(pk.EventData)))
|
||||
case packet.LevelEventParticlesCrackBlock:
|
||||
face := pk.EventData >> 24
|
||||
rid := t.DowngradeBlockRuntimeID(uint32(pk.EventData & 0xffff))
|
||||
pk.EventData = int32(rid) | (face << 24)
|
||||
}
|
||||
case *packet.LevelSoundEvent:
|
||||
switch pk.SoundType {
|
||||
case packet.SoundEventBreak:
|
||||
fallthrough
|
||||
case packet.SoundEventPlace:
|
||||
fallthrough
|
||||
case packet.SoundEventHit:
|
||||
fallthrough
|
||||
case packet.SoundEventLand:
|
||||
fallthrough
|
||||
case packet.SoundEventItemUseOn:
|
||||
pk.ExtraData = int32(t.DowngradeBlockRuntimeID(uint32(pk.ExtraData)))
|
||||
}
|
||||
case *packet.AddActor:
|
||||
if pk.EntityType == "minecraft:falling_block" {
|
||||
pk.EntityMetadata = t.downgradeEntityMetadata(pk.EntityMetadata)
|
||||
}
|
||||
case *packet.SetActorData:
|
||||
pk.EntityMetadata = t.downgradeEntityMetadata(pk.EntityMetadata)
|
||||
case *packet.StartGame:
|
||||
t.latest.Adjust(pk.Blocks)
|
||||
t.mapping.Adjust(pk.Blocks)
|
||||
case *packet.ResourcePackStack:
|
||||
var packs []protocol.StackResourcePack
|
||||
for _, pack := range pk.TexturePacks {
|
||||
if pack.UUID == "0fba4063-dba1-4281-9b89-ff9390653530" {
|
||||
continue
|
||||
}
|
||||
packs = append(packs, pack)
|
||||
}
|
||||
pk.TexturePacks = packs
|
||||
}
|
||||
result = append(result, pk)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) UpgradeBlockPackets(pks []packet.Packet, conn *minecraft.Conn) (result []packet.Packet) {
|
||||
for _, pk := range pks {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.InventoryTransaction:
|
||||
if transactionData, ok := pk.TransactionData.(*protocol.UseItemTransactionData); ok {
|
||||
transactionData.BlockRuntimeID = t.UpgradeBlockRuntimeID(transactionData.BlockRuntimeID)
|
||||
pk.TransactionData = transactionData
|
||||
}
|
||||
case *packet.SetActorData:
|
||||
pk.EntityMetadata = t.upgradeEntityMetadata(pk.EntityMetadata)
|
||||
}
|
||||
result = append(result, pk)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) DowngradeBlockRuntimeID(input uint32) uint32 {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
state, ok := t.latest.RuntimeIDToState(input)
|
||||
if !ok {
|
||||
return t.mapping.Air()
|
||||
}
|
||||
runtimeID, ok := t.mapping.StateToRuntimeID(state)
|
||||
if !ok {
|
||||
return t.mapping.Air()
|
||||
}
|
||||
return runtimeID
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) DowngradeChunk(input *chunk.Chunk) *chunk.Chunk {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
|
||||
start := 0
|
||||
r := world.Overworld.Range()
|
||||
if t.oldFormat {
|
||||
start = 4
|
||||
r = cube.Range{0, 255}
|
||||
}
|
||||
downgraded := chunk.New(t.mapping.Air(), r)
|
||||
|
||||
i := 0
|
||||
// First downgrade the blocks.
|
||||
for _, sub := range input.Sub()[start : len(input.Sub())-start] {
|
||||
t.DowngradeSubChunk(sub)
|
||||
downgraded.Sub()[i] = sub
|
||||
i += 1
|
||||
}
|
||||
i = 0
|
||||
// Then downgrade the biome ids.
|
||||
for _, sub := range input.BiomeSub()[start : len(input.BiomeSub())-start] {
|
||||
// todo
|
||||
sub.Palette().Replace(func(v uint32) uint32 {
|
||||
return 0 // at least the client doesn't crash now
|
||||
})
|
||||
downgraded.BiomeSub()[i] = sub
|
||||
i += 1
|
||||
}
|
||||
|
||||
return downgraded
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) DowngradeSubChunk(input *chunk.SubChunk) {
|
||||
if t.latest == t.mapping {
|
||||
return
|
||||
}
|
||||
for _, storage := range input.Layers() {
|
||||
storage.Palette().Replace(t.DowngradeBlockRuntimeID)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) downgradeEntityMetadata(metadata map[uint32]any) map[uint32]any {
|
||||
if t.latest == t.mapping {
|
||||
return metadata
|
||||
}
|
||||
if latestRID, ok := metadata[protocol.EntityDataKeyVariant]; ok {
|
||||
metadata[protocol.EntityDataKeyVariant] = int32(t.DowngradeBlockRuntimeID(uint32(latestRID.(int32))))
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) UpgradeBlockRuntimeID(input uint32) uint32 {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
state, ok := t.mapping.RuntimeIDToState(input)
|
||||
if !ok {
|
||||
return t.latest.Air()
|
||||
}
|
||||
runtimeID, ok := t.latest.StateToRuntimeID(state)
|
||||
if !ok {
|
||||
return t.latest.Air()
|
||||
}
|
||||
return runtimeID
|
||||
}
|
||||
|
||||
func (t *DefaultBlockTranslator) upgradeEntityMetadata(metadata map[uint32]any) map[uint32]any {
|
||||
if t.latest == t.mapping {
|
||||
return metadata
|
||||
}
|
||||
if latestRID, ok := metadata[protocol.EntityDataKeyVariant]; ok {
|
||||
metadata[protocol.EntityDataKeyVariant] = int32(t.UpgradeBlockRuntimeID(uint32(latestRID.(int32))))
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
BIN
legacyver/item_runtime_ids_748.nbt
Normal file
BIN
legacyver/item_runtime_ids_748.nbt
Normal file
Binary file not shown.
BIN
legacyver/item_runtime_ids_766.nbt
Normal file
BIN
legacyver/item_runtime_ids_766.nbt
Normal file
Binary file not shown.
767
legacyver/item_translator.go
Normal file
767
legacyver/item_translator.go
Normal file
@@ -0,0 +1,767 @@
|
||||
package legacyver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/akmalfairuz/legacy-version/internal/item"
|
||||
"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"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
type ItemTranslator interface {
|
||||
// DowngradeItemType downgrades the input item type to a legacy item type.
|
||||
DowngradeItemType(input protocol.ItemType) protocol.ItemType
|
||||
// DowngradeItemStack downgrades the input item stack to a legacy item stack.
|
||||
DowngradeItemStack(input protocol.ItemStack) protocol.ItemStack
|
||||
// DowngradeItemInstance downgrades the input item instance to a legacy item instance.
|
||||
DowngradeItemInstance(input protocol.ItemInstance) protocol.ItemInstance
|
||||
// DowngradeItemDescriptor downgrades the input item descriptor to a legacy item descriptor.
|
||||
DowngradeItemDescriptor(input protocol.ItemDescriptor) protocol.ItemDescriptor
|
||||
// DowngradeItemDescriptorCount downgrades the input item descriptor (with count) to a legacy item descriptor (with count).
|
||||
DowngradeItemDescriptorCount(input protocol.ItemDescriptorCount) protocol.ItemDescriptorCount
|
||||
DowngradeItemPackets(pks []packet.Packet, conn *minecraft.Conn) []packet.Packet
|
||||
// UpgradeItemType upgrades the input item type to the latest item type.
|
||||
UpgradeItemType(input protocol.ItemType) protocol.ItemType
|
||||
// UpgradeItemStack upgrades the input item stack to the latest item stack.
|
||||
UpgradeItemStack(input protocol.ItemStack) protocol.ItemStack
|
||||
// UpgradeItemInstance upgrades the input item instance to the latest item instance.
|
||||
UpgradeItemInstance(input protocol.ItemInstance) protocol.ItemInstance
|
||||
// UpgradeItemDescriptor upgrades the input item descriptor to the latest item descriptor.
|
||||
UpgradeItemDescriptor(input protocol.ItemDescriptor) protocol.ItemDescriptor
|
||||
// UpgradeItemDescriptorCount upgrades the input item descriptor (with count) to the latest item descriptor (with count).
|
||||
UpgradeItemDescriptorCount(input protocol.ItemDescriptorCount) protocol.ItemDescriptorCount
|
||||
UpgradeItemPackets(pks []packet.Packet, conn *minecraft.Conn) []packet.Packet
|
||||
// Register registers a custom item entry.
|
||||
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
|
||||
}
|
||||
|
||||
type DefaultItemTranslator struct {
|
||||
mapping mapping.Item
|
||||
latest mapping.Item
|
||||
blockMapping mapping.Block
|
||||
blockMappingLatest mapping.Block
|
||||
ridToCustomItem map[int32]world.CustomItem
|
||||
originalToCustom map[int32]int32
|
||||
customToOriginal map[int32]int32
|
||||
}
|
||||
|
||||
func NewItemTranslator(mapping mapping.Item, latestMapping mapping.Item, blockMapping mapping.Block, blockMappingLatest mapping.Block) *DefaultItemTranslator {
|
||||
return &DefaultItemTranslator{mapping: mapping, latest: latestMapping, blockMapping: blockMapping, blockMappingLatest: blockMappingLatest,
|
||||
ridToCustomItem: make(map[int32]world.CustomItem), originalToCustom: make(map[int32]int32), customToOriginal: make(map[int32]int32)}
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) DowngradeItemType(input protocol.ItemType) protocol.ItemType {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
if input.NetworkID == t.latest.Air() || input.NetworkID == 0 {
|
||||
return protocol.ItemType{
|
||||
NetworkID: t.mapping.Air(),
|
||||
}
|
||||
}
|
||||
networkID := input.NetworkID
|
||||
metadata := input.MetadataValue
|
||||
|
||||
var ok bool
|
||||
if networkID, ok = t.originalToCustom[input.NetworkID]; !ok {
|
||||
name, _ := t.latest.ItemRuntimeIDToName(input.NetworkID)
|
||||
i := item.Downgrade(item.Item{
|
||||
Name: name,
|
||||
Metadata: input.MetadataValue,
|
||||
Version: t.latest.ItemVersion(),
|
||||
}, t.mapping.ItemVersion())
|
||||
metadata = i.Metadata
|
||||
|
||||
if i.Name == "minecraft:netherstar" {
|
||||
i.Name = "minecraft:nether_star"
|
||||
}
|
||||
|
||||
networkID, ok = t.mapping.ItemNameToRuntimeID(i.Name)
|
||||
if !ok {
|
||||
networkID, _ = t.mapping.ItemNameToRuntimeID("minecraft:info_update")
|
||||
}
|
||||
}
|
||||
|
||||
return protocol.ItemType{
|
||||
NetworkID: networkID,
|
||||
MetadataValue: metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) DowngradeItemStack(input protocol.ItemStack) protocol.ItemStack {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
input.ItemType = t.DowngradeItemType(input.ItemType)
|
||||
|
||||
blockRuntimeId := uint32(0)
|
||||
if input.NetworkID != t.mapping.Air() {
|
||||
name, _ := t.mapping.ItemRuntimeIDToName(input.NetworkID)
|
||||
if latestBlockState, ok := item.BlockStateFromItemName(name, input.MetadataValue); ok {
|
||||
var found bool
|
||||
if blockRuntimeId, found = t.blockMapping.StateToRuntimeID(latestBlockState); !found {
|
||||
blockRuntimeId = t.blockMapping.Air()
|
||||
}
|
||||
}
|
||||
}
|
||||
return protocol.ItemStack{
|
||||
ItemType: input.ItemType,
|
||||
BlockRuntimeID: int32(blockRuntimeId),
|
||||
Count: input.Count,
|
||||
NBTData: input.NBTData,
|
||||
CanBePlacedOn: input.CanBePlacedOn,
|
||||
CanBreak: input.CanBreak,
|
||||
HasNetworkID: input.HasNetworkID,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) DowngradeItemInstance(input protocol.ItemInstance) protocol.ItemInstance {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
input.Stack = t.DowngradeItemStack(input.Stack)
|
||||
return input
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) DowngradeItemDescriptor(input protocol.ItemDescriptor) protocol.ItemDescriptor {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
switch descriptor := input.(type) {
|
||||
case *protocol.InvalidItemDescriptor:
|
||||
return input
|
||||
case *protocol.DefaultItemDescriptor:
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{NetworkID: int32(descriptor.NetworkID), MetadataValue: uint32(descriptor.MetadataValue)})
|
||||
descriptor.NetworkID, descriptor.MetadataValue = int16(itemType.NetworkID), int16(itemType.MetadataValue)
|
||||
return descriptor
|
||||
case *protocol.MoLangItemDescriptor:
|
||||
return input
|
||||
case *protocol.ItemTagItemDescriptor:
|
||||
return input
|
||||
case *protocol.DeferredItemDescriptor:
|
||||
rid, ok := t.latest.ItemNameToRuntimeID(descriptor.Name)
|
||||
descriptor.Name = "minecraft:air"
|
||||
if !ok {
|
||||
descriptor.MetadataValue = 0
|
||||
return descriptor
|
||||
}
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{NetworkID: rid, MetadataValue: uint32(descriptor.MetadataValue)})
|
||||
descriptor.MetadataValue = int16(itemType.MetadataValue)
|
||||
if name, ok := t.mapping.ItemRuntimeIDToName(itemType.NetworkID); ok {
|
||||
descriptor.Name = name
|
||||
}
|
||||
return descriptor
|
||||
case *protocol.ComplexAliasItemDescriptor:
|
||||
rid, ok := t.latest.ItemNameToRuntimeID(descriptor.Name)
|
||||
descriptor.Name = "minecraft:air"
|
||||
if !ok {
|
||||
return descriptor
|
||||
}
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{NetworkID: rid})
|
||||
if name, ok := t.mapping.ItemRuntimeIDToName(itemType.NetworkID); ok {
|
||||
descriptor.Name = name
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
panic("unknown item descriptor")
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) DowngradeItemDescriptorCount(input protocol.ItemDescriptorCount) protocol.ItemDescriptorCount {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
input.Descriptor = t.DowngradeItemDescriptor(input.Descriptor)
|
||||
return input
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeItemType(input protocol.ItemType) protocol.ItemType {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
if input.NetworkID == t.mapping.Air() || input.NetworkID == 0 {
|
||||
return protocol.ItemType{
|
||||
NetworkID: t.latest.Air(),
|
||||
}
|
||||
}
|
||||
networkID := input.NetworkID
|
||||
metadata := input.MetadataValue
|
||||
|
||||
var ok bool
|
||||
if networkID, ok = t.customToOriginal[input.NetworkID]; !ok {
|
||||
name, _ := t.mapping.ItemRuntimeIDToName(input.NetworkID)
|
||||
i := item.Upgrade(item.Item{
|
||||
Name: name,
|
||||
Metadata: input.MetadataValue,
|
||||
Version: t.mapping.ItemVersion(),
|
||||
}, t.latest.ItemVersion())
|
||||
networkID, ok = t.latest.ItemNameToRuntimeID(i.Name)
|
||||
if !ok {
|
||||
networkID, _ = t.latest.ItemNameToRuntimeID("minecraft:info_update")
|
||||
}
|
||||
}
|
||||
|
||||
return protocol.ItemType{
|
||||
NetworkID: networkID,
|
||||
MetadataValue: metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeItemStack(input protocol.ItemStack) protocol.ItemStack {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
input.ItemType = t.UpgradeItemType(input.ItemType)
|
||||
|
||||
blockRuntimeId := uint32(0)
|
||||
if input.NetworkID != t.latest.Air() {
|
||||
name, _ := t.latest.ItemRuntimeIDToName(input.NetworkID)
|
||||
if latestBlockState, ok := item.BlockStateFromItemName(name, input.MetadataValue); ok {
|
||||
blockRuntimeId, _ = t.blockMappingLatest.StateToRuntimeID(latestBlockState)
|
||||
}
|
||||
}
|
||||
return protocol.ItemStack{
|
||||
ItemType: input.ItemType,
|
||||
BlockRuntimeID: int32(blockRuntimeId),
|
||||
Count: input.Count,
|
||||
NBTData: input.NBTData,
|
||||
CanBePlacedOn: input.CanBePlacedOn,
|
||||
CanBreak: input.CanBreak,
|
||||
HasNetworkID: input.HasNetworkID,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeItemInstance(input protocol.ItemInstance) protocol.ItemInstance {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
input.Stack = t.UpgradeItemStack(input.Stack)
|
||||
return input
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeItemDescriptor(input protocol.ItemDescriptor) protocol.ItemDescriptor {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
switch descriptor := input.(type) {
|
||||
case *protocol.InvalidItemDescriptor:
|
||||
return input
|
||||
case *protocol.DefaultItemDescriptor:
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{NetworkID: int32(descriptor.NetworkID), MetadataValue: uint32(descriptor.MetadataValue)})
|
||||
descriptor.NetworkID, descriptor.MetadataValue = int16(itemType.NetworkID), int16(itemType.MetadataValue)
|
||||
return descriptor
|
||||
case *protocol.MoLangItemDescriptor:
|
||||
return input
|
||||
case *protocol.ItemTagItemDescriptor:
|
||||
return input
|
||||
case *protocol.DeferredItemDescriptor:
|
||||
rid, ok := t.mapping.ItemNameToRuntimeID(descriptor.Name)
|
||||
descriptor.Name = "minecraft:air"
|
||||
if !ok {
|
||||
descriptor.MetadataValue = 0
|
||||
return descriptor
|
||||
}
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{NetworkID: rid, MetadataValue: uint32(descriptor.MetadataValue)})
|
||||
descriptor.MetadataValue = int16(itemType.MetadataValue)
|
||||
if name, ok := t.latest.ItemRuntimeIDToName(itemType.NetworkID); ok {
|
||||
descriptor.Name = name
|
||||
}
|
||||
return descriptor
|
||||
case *protocol.ComplexAliasItemDescriptor:
|
||||
rid, ok := t.mapping.ItemNameToRuntimeID(descriptor.Name)
|
||||
descriptor.Name = "minecraft:air"
|
||||
if !ok {
|
||||
return descriptor
|
||||
}
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{NetworkID: rid})
|
||||
if name, ok := t.latest.ItemRuntimeIDToName(itemType.NetworkID); ok {
|
||||
descriptor.Name = name
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
panic("unknown item descriptor")
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeItemDescriptorCount(input protocol.ItemDescriptorCount) protocol.ItemDescriptorCount {
|
||||
if t.latest == t.mapping {
|
||||
return input
|
||||
}
|
||||
input.Descriptor = t.UpgradeItemDescriptor(input.Descriptor)
|
||||
return input
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) DowngradeItemPackets(pks []packet.Packet, _ *minecraft.Conn) (result []packet.Packet) {
|
||||
for _, pk := range pks {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.MobEquipment:
|
||||
pk.NewItem = t.DowngradeItemInstance(pk.NewItem)
|
||||
case *packet.MobArmourEquipment:
|
||||
pk.Helmet = t.DowngradeItemInstance(pk.Helmet)
|
||||
pk.Chestplate = t.DowngradeItemInstance(pk.Chestplate)
|
||||
pk.Leggings = t.DowngradeItemInstance(pk.Leggings)
|
||||
pk.Boots = t.DowngradeItemInstance(pk.Boots)
|
||||
pk.Body = t.DowngradeItemInstance(pk.Body)
|
||||
case *packet.ActorEvent:
|
||||
if pk.EventType == packet.ActorEventFeed {
|
||||
value := pk.EventData
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{NetworkID: value >> 16, MetadataValue: uint32(value & 0xf)})
|
||||
pk.EventData = (itemType.NetworkID << 16) | int32(itemType.MetadataValue)
|
||||
}
|
||||
case *packet.AddItemActor:
|
||||
pk.Item = t.DowngradeItemInstance(pk.Item)
|
||||
case *packet.AddPlayer:
|
||||
pk.HeldItem = t.DowngradeItemInstance(pk.HeldItem)
|
||||
case *packet.InventorySlot:
|
||||
pk.NewItem = t.DowngradeItemInstance(pk.NewItem)
|
||||
case *packet.InventoryContent:
|
||||
pk.Content = lo.Map(pk.Content, func(item protocol.ItemInstance, _ int) protocol.ItemInstance {
|
||||
return t.DowngradeItemInstance(item)
|
||||
})
|
||||
case *packet.ItemStackRequest:
|
||||
for i, request := range pk.Requests {
|
||||
for i2, action := range request.Actions {
|
||||
if act, ok := action.(*protocol.CraftResultsDeprecatedStackRequestAction); ok {
|
||||
act.ResultItems = lo.Map(act.ResultItems, func(item protocol.ItemStack, _ int) protocol.ItemStack {
|
||||
return t.DowngradeItemStack(item)
|
||||
})
|
||||
pk.Requests[i].Actions[i2] = act
|
||||
}
|
||||
}
|
||||
}
|
||||
case *packet.CraftingData:
|
||||
for i, recipe := range pk.Recipes {
|
||||
switch recipe := recipe.(type) {
|
||||
case *protocol.ShapelessRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.DowngradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.DowngradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShapedRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.DowngradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.DowngradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.FurnaceRecipe:
|
||||
recipe.InputType = t.DowngradeItemType(recipe.InputType)
|
||||
recipe.Output = t.DowngradeItemStack(recipe.Output)
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.FurnaceDataRecipe:
|
||||
recipe.InputType = t.DowngradeItemType(recipe.InputType)
|
||||
recipe.Output = t.DowngradeItemStack(recipe.Output)
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShulkerBoxRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.DowngradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.DowngradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShapelessChemistryRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.DowngradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.DowngradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShapedChemistryRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.DowngradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.DowngradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.SmithingTransformRecipe:
|
||||
recipe.Template = t.DowngradeItemDescriptorCount(recipe.Template)
|
||||
recipe.Base = t.DowngradeItemDescriptorCount(recipe.Base)
|
||||
recipe.Addition = t.DowngradeItemDescriptorCount(recipe.Addition)
|
||||
recipe.Result = t.DowngradeItemStack(recipe.Result)
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.SmithingTrimRecipe:
|
||||
recipe.Template = t.DowngradeItemDescriptorCount(recipe.Template)
|
||||
recipe.Base = t.DowngradeItemDescriptorCount(recipe.Base)
|
||||
recipe.Addition = t.DowngradeItemDescriptorCount(recipe.Addition)
|
||||
}
|
||||
}
|
||||
for i, recipe := range pk.PotionRecipes {
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{NetworkID: recipe.InputPotionID, MetadataValue: uint32(recipe.InputPotionMetadata)})
|
||||
recipe.InputPotionID, recipe.InputPotionMetadata = itemType.NetworkID, int32(itemType.MetadataValue)
|
||||
itemType = t.DowngradeItemType(protocol.ItemType{NetworkID: recipe.ReagentItemID, MetadataValue: uint32(recipe.ReagentItemMetadata)})
|
||||
recipe.ReagentItemID, recipe.ReagentItemMetadata = itemType.NetworkID, int32(itemType.MetadataValue)
|
||||
itemType = t.DowngradeItemType(protocol.ItemType{NetworkID: recipe.OutputPotionID, MetadataValue: uint32(recipe.OutputPotionMetadata)})
|
||||
recipe.OutputPotionID, recipe.OutputPotionMetadata = itemType.NetworkID, int32(itemType.MetadataValue)
|
||||
pk.PotionRecipes[i] = recipe
|
||||
}
|
||||
for i, recipe := range pk.PotionContainerChangeRecipes {
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{NetworkID: recipe.InputItemID})
|
||||
recipe.InputItemID = itemType.NetworkID
|
||||
itemType = t.DowngradeItemType(protocol.ItemType{NetworkID: recipe.ReagentItemID})
|
||||
recipe.ReagentItemID = itemType.NetworkID
|
||||
itemType = t.DowngradeItemType(protocol.ItemType{NetworkID: recipe.OutputItemID})
|
||||
recipe.OutputItemID = itemType.NetworkID
|
||||
pk.PotionContainerChangeRecipes[i] = recipe
|
||||
}
|
||||
for i, recipe := range pk.MaterialReducers {
|
||||
recipe.InputItem = t.DowngradeItemType(recipe.InputItem)
|
||||
for i2, output := range recipe.Outputs {
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{NetworkID: output.NetworkID})
|
||||
output.NetworkID = itemType.NetworkID
|
||||
recipe.Outputs[i2] = output
|
||||
}
|
||||
pk.MaterialReducers[i] = recipe
|
||||
}
|
||||
//case *packet.CraftingEvent:
|
||||
// pk.Input = lo.Map(pk.Input, func(item protocol.ItemInstance, _ int) protocol.ItemInstance {
|
||||
// return t.DowngradeItemInstance(item)
|
||||
// })
|
||||
// pk.Output = lo.Map(pk.Output, func(item protocol.ItemInstance, _ int) protocol.ItemInstance {
|
||||
// return t.DowngradeItemInstance(item)
|
||||
// })
|
||||
case *packet.PlayerAuthInput:
|
||||
for i, action := range pk.ItemStackRequest.Actions {
|
||||
if act, ok := action.(*protocol.CraftResultsDeprecatedStackRequestAction); ok {
|
||||
act.ResultItems = lo.Map(act.ResultItems, func(item protocol.ItemStack, _ int) protocol.ItemStack {
|
||||
return t.DowngradeItemStack(item)
|
||||
})
|
||||
pk.ItemStackRequest.Actions[i] = act
|
||||
}
|
||||
}
|
||||
for i, action := range pk.ItemInteractionData.Actions {
|
||||
action.OldItem = t.DowngradeItemInstance(action.OldItem)
|
||||
action.NewItem = t.DowngradeItemInstance(action.NewItem)
|
||||
pk.ItemInteractionData.Actions[i] = action
|
||||
}
|
||||
pk.ItemInteractionData.HeldItem = t.DowngradeItemInstance(pk.ItemInteractionData.HeldItem)
|
||||
case *packet.CreativeContent:
|
||||
for i, creativeItem := range pk.Items {
|
||||
creativeItem.Item = t.DowngradeItemStack(creativeItem.Item)
|
||||
|
||||
pk.Items[i] = creativeItem
|
||||
}
|
||||
case *packet.InventoryTransaction:
|
||||
for i, action := range pk.Actions {
|
||||
action.OldItem = t.DowngradeItemInstance(action.OldItem)
|
||||
action.NewItem = t.DowngradeItemInstance(action.NewItem)
|
||||
pk.Actions[i] = action
|
||||
}
|
||||
switch transactionData := pk.TransactionData.(type) {
|
||||
case *protocol.UseItemTransactionData:
|
||||
transactionData.HeldItem = t.DowngradeItemInstance(transactionData.HeldItem)
|
||||
for i, action := range transactionData.Actions {
|
||||
action.OldItem = t.DowngradeItemInstance(action.OldItem)
|
||||
action.NewItem = t.DowngradeItemInstance(action.NewItem)
|
||||
transactionData.Actions[i] = action
|
||||
}
|
||||
case *protocol.UseItemOnEntityTransactionData:
|
||||
transactionData.HeldItem = t.DowngradeItemInstance(transactionData.HeldItem)
|
||||
case *protocol.ReleaseItemTransactionData:
|
||||
transactionData.HeldItem = t.DowngradeItemInstance(transactionData.HeldItem)
|
||||
}
|
||||
case *packet.LevelEvent:
|
||||
if pk.EventType == packet.LevelEventParticleLegacyEvent|14 { // egg crack
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{
|
||||
NetworkID: pk.EventData >> 16,
|
||||
MetadataValue: uint32(pk.EventData & 0xf),
|
||||
})
|
||||
pk.EventData = (itemType.NetworkID << 16) | int32(itemType.MetadataValue)
|
||||
}
|
||||
case *packet.StartGame:
|
||||
for i, entry := range pk.Items {
|
||||
if !entry.ComponentBased {
|
||||
itemType := t.DowngradeItemType(protocol.ItemType{
|
||||
NetworkID: int32(entry.RuntimeID),
|
||||
MetadataValue: 0,
|
||||
})
|
||||
if itemType.NetworkID == t.mapping.Air() {
|
||||
removeIndex(pk.Items, i)
|
||||
continue
|
||||
}
|
||||
entry.RuntimeID = int16(itemType.NetworkID)
|
||||
|
||||
var ok bool
|
||||
if entry.Name, ok = t.mapping.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),
|
||||
})
|
||||
}
|
||||
}
|
||||
result = append(result, pk)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) UpgradeItemPackets(pks []packet.Packet, _ *minecraft.Conn) (result []packet.Packet) {
|
||||
for _, pk := range pks {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.MobEquipment:
|
||||
pk.NewItem = t.UpgradeItemInstance(pk.NewItem)
|
||||
case *packet.MobArmourEquipment:
|
||||
pk.Helmet = t.UpgradeItemInstance(pk.Helmet)
|
||||
pk.Chestplate = t.UpgradeItemInstance(pk.Chestplate)
|
||||
pk.Leggings = t.UpgradeItemInstance(pk.Leggings)
|
||||
pk.Boots = t.UpgradeItemInstance(pk.Boots)
|
||||
pk.Body = t.UpgradeItemInstance(pk.Body)
|
||||
case *packet.AddItemActor:
|
||||
pk.Item = t.UpgradeItemInstance(pk.Item)
|
||||
case *packet.AddPlayer:
|
||||
pk.HeldItem = t.UpgradeItemInstance(pk.HeldItem)
|
||||
case *packet.InventorySlot:
|
||||
pk.NewItem = t.UpgradeItemInstance(pk.NewItem)
|
||||
case *packet.InventoryContent:
|
||||
pk.Content = lo.Map(pk.Content, func(item protocol.ItemInstance, _ int) protocol.ItemInstance {
|
||||
return t.UpgradeItemInstance(item)
|
||||
})
|
||||
case *packet.ItemStackRequest:
|
||||
for i, request := range pk.Requests {
|
||||
for i2, action := range request.Actions {
|
||||
if act, ok := action.(*protocol.CraftResultsDeprecatedStackRequestAction); ok {
|
||||
act.ResultItems = lo.Map(act.ResultItems, func(item protocol.ItemStack, _ int) protocol.ItemStack {
|
||||
return t.UpgradeItemStack(item)
|
||||
})
|
||||
pk.Requests[i].Actions[i2] = act
|
||||
}
|
||||
}
|
||||
}
|
||||
case *packet.CraftingData:
|
||||
for i, recipe := range pk.Recipes {
|
||||
switch recipe := recipe.(type) {
|
||||
case *protocol.ShapelessRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.UpgradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.UpgradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShapedRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.UpgradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.UpgradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.FurnaceRecipe:
|
||||
recipe.InputType = t.UpgradeItemType(recipe.InputType)
|
||||
recipe.Output = t.UpgradeItemStack(recipe.Output)
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.FurnaceDataRecipe:
|
||||
recipe.InputType = t.UpgradeItemType(recipe.InputType)
|
||||
recipe.Output = t.UpgradeItemStack(recipe.Output)
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShulkerBoxRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.UpgradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.UpgradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShapelessChemistryRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.UpgradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.UpgradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.ShapedChemistryRecipe:
|
||||
for i2, input := range recipe.Input {
|
||||
recipe.Input[i2] = t.UpgradeItemDescriptorCount(input)
|
||||
}
|
||||
for i2, stack := range recipe.Output {
|
||||
recipe.Output[i2] = t.UpgradeItemStack(stack)
|
||||
}
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.SmithingTransformRecipe:
|
||||
recipe.Template = t.UpgradeItemDescriptorCount(recipe.Template)
|
||||
recipe.Base = t.UpgradeItemDescriptorCount(recipe.Base)
|
||||
recipe.Addition = t.UpgradeItemDescriptorCount(recipe.Addition)
|
||||
recipe.Result = t.UpgradeItemStack(recipe.Result)
|
||||
pk.Recipes[i] = recipe
|
||||
case *protocol.SmithingTrimRecipe:
|
||||
recipe.Template = t.UpgradeItemDescriptorCount(recipe.Template)
|
||||
recipe.Base = t.UpgradeItemDescriptorCount(recipe.Base)
|
||||
recipe.Addition = t.UpgradeItemDescriptorCount(recipe.Addition)
|
||||
}
|
||||
}
|
||||
for i, recipe := range pk.PotionRecipes {
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{NetworkID: recipe.InputPotionID, MetadataValue: uint32(recipe.InputPotionMetadata)})
|
||||
recipe.InputPotionID, recipe.InputPotionMetadata = itemType.NetworkID, int32(itemType.MetadataValue)
|
||||
itemType = t.UpgradeItemType(protocol.ItemType{NetworkID: recipe.ReagentItemID, MetadataValue: uint32(recipe.ReagentItemMetadata)})
|
||||
recipe.ReagentItemID, recipe.ReagentItemMetadata = itemType.NetworkID, int32(itemType.MetadataValue)
|
||||
itemType = t.UpgradeItemType(protocol.ItemType{NetworkID: recipe.OutputPotionID, MetadataValue: uint32(recipe.OutputPotionMetadata)})
|
||||
recipe.OutputPotionID, recipe.OutputPotionMetadata = itemType.NetworkID, int32(itemType.MetadataValue)
|
||||
pk.PotionRecipes[i] = recipe
|
||||
}
|
||||
for i, recipe := range pk.PotionContainerChangeRecipes {
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{NetworkID: recipe.InputItemID})
|
||||
recipe.InputItemID = itemType.NetworkID
|
||||
itemType = t.UpgradeItemType(protocol.ItemType{NetworkID: recipe.ReagentItemID})
|
||||
recipe.ReagentItemID = itemType.NetworkID
|
||||
itemType = t.UpgradeItemType(protocol.ItemType{NetworkID: recipe.OutputItemID})
|
||||
recipe.OutputItemID = itemType.NetworkID
|
||||
pk.PotionContainerChangeRecipes[i] = recipe
|
||||
}
|
||||
for i, recipe := range pk.MaterialReducers {
|
||||
recipe.InputItem = t.UpgradeItemType(recipe.InputItem)
|
||||
for i2, output := range recipe.Outputs {
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{NetworkID: output.NetworkID})
|
||||
output.NetworkID = itemType.NetworkID
|
||||
recipe.Outputs[i2] = output
|
||||
}
|
||||
pk.MaterialReducers[i] = recipe
|
||||
}
|
||||
//case *packet.CraftingEvent:
|
||||
// pk.Input = lo.Map(pk.Input, func(item protocol.ItemInstance, _ int) protocol.ItemInstance {
|
||||
// return t.UpgradeItemInstance(item)
|
||||
// })
|
||||
// pk.Output = lo.Map(pk.Output, func(item protocol.ItemInstance, _ int) protocol.ItemInstance {
|
||||
// return t.UpgradeItemInstance(item)
|
||||
// })
|
||||
case *packet.PlayerAuthInput:
|
||||
for i, action := range pk.ItemStackRequest.Actions {
|
||||
if act, ok := action.(*protocol.CraftResultsDeprecatedStackRequestAction); ok {
|
||||
act.ResultItems = lo.Map(act.ResultItems, func(item protocol.ItemStack, _ int) protocol.ItemStack {
|
||||
return t.UpgradeItemStack(item)
|
||||
})
|
||||
pk.ItemStackRequest.Actions[i] = act
|
||||
}
|
||||
}
|
||||
for i, action := range pk.ItemInteractionData.Actions {
|
||||
action.OldItem = t.UpgradeItemInstance(action.OldItem)
|
||||
action.NewItem = t.UpgradeItemInstance(action.NewItem)
|
||||
pk.ItemInteractionData.Actions[i] = action
|
||||
}
|
||||
pk.ItemInteractionData.HeldItem = t.UpgradeItemInstance(pk.ItemInteractionData.HeldItem)
|
||||
case *packet.CreativeContent:
|
||||
for i, creativeItem := range pk.Items {
|
||||
creativeItem.Item = t.UpgradeItemStack(creativeItem.Item)
|
||||
pk.Items[i] = creativeItem
|
||||
}
|
||||
case *packet.InventoryTransaction:
|
||||
for i, action := range pk.Actions {
|
||||
action.OldItem = t.UpgradeItemInstance(action.OldItem)
|
||||
action.NewItem = t.UpgradeItemInstance(action.NewItem)
|
||||
pk.Actions[i] = action
|
||||
}
|
||||
switch transactionData := pk.TransactionData.(type) {
|
||||
case *protocol.UseItemTransactionData:
|
||||
transactionData.HeldItem = t.UpgradeItemInstance(transactionData.HeldItem)
|
||||
for i, action := range transactionData.Actions {
|
||||
action.OldItem = t.UpgradeItemInstance(action.OldItem)
|
||||
action.NewItem = t.UpgradeItemInstance(action.NewItem)
|
||||
transactionData.Actions[i] = action
|
||||
}
|
||||
case *protocol.UseItemOnEntityTransactionData:
|
||||
transactionData.HeldItem = t.UpgradeItemInstance(transactionData.HeldItem)
|
||||
case *protocol.ReleaseItemTransactionData:
|
||||
transactionData.HeldItem = t.UpgradeItemInstance(transactionData.HeldItem)
|
||||
}
|
||||
case *packet.LevelEvent:
|
||||
if pk.EventType == packet.LevelEventParticleLegacyEvent|14 { // egg crack
|
||||
itemType := t.UpgradeItemType(protocol.ItemType{
|
||||
NetworkID: pk.EventData >> 16,
|
||||
MetadataValue: uint32(pk.EventData & 0xf),
|
||||
})
|
||||
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),
|
||||
})
|
||||
}
|
||||
}
|
||||
result = append(result, pk)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) Register(item world.CustomItem, replacement string) {
|
||||
name, _ := item.EncodeItem()
|
||||
originalRid, ok := t.latest.ItemNameToRuntimeID(replacement)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("%v not found in latest items", replacement))
|
||||
}
|
||||
if _, ok := t.originalToCustom[originalRid]; ok {
|
||||
panic(fmt.Errorf("%v is already mapped", replacement))
|
||||
}
|
||||
|
||||
nextRID := t.mapping.RegisterEntry(name)
|
||||
t.ridToCustomItem[nextRID] = item
|
||||
t.originalToCustom[originalRid] = nextRID
|
||||
t.customToOriginal[nextRID] = originalRid
|
||||
}
|
||||
|
||||
func (t *DefaultItemTranslator) CustomItems() map[int32]world.CustomItem {
|
||||
return t.ridToCustomItem
|
||||
}
|
||||
|
||||
func removeIndex[T any](s []T, index int) []T {
|
||||
ret := make([]T, 0)
|
||||
ret = append(ret, s[:index]...)
|
||||
return append(ret, s[index+1:]...)
|
||||
}
|
||||
27
legacyver/legacypacket/item_stack_response.go
Normal file
27
legacyver/legacypacket/item_stack_response.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// ItemStackResponse is sent by the server in response to an ItemStackRequest packet from the client. This
|
||||
// packet is used to either approve or reject ItemStackRequests from the client. If a request is approved, the
|
||||
// client will simply continue as normal. If rejected, the client will undo the actions so that the inventory
|
||||
// should be in sync with the server again.
|
||||
type ItemStackResponse struct {
|
||||
// Responses is a list of responses to ItemStackRequests sent by the client before. Responses either
|
||||
// approve or reject a request from the client.
|
||||
// Vanilla limits the size of this slice to 4096.
|
||||
Responses []proto.ItemStackResponse
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*ItemStackResponse) ID() uint32 {
|
||||
return packet.IDItemStackResponse
|
||||
}
|
||||
|
||||
func (pk *ItemStackResponse) Marshal(io protocol.IO) {
|
||||
protocol.Slice(io, &pk.Responses)
|
||||
}
|
||||
1
legacyver/legacypacket/packet.go
Normal file
1
legacyver/legacypacket/packet.go
Normal file
@@ -0,0 +1 @@
|
||||
package legacypacket
|
||||
210
legacyver/legacypacket/player_auth_input.go
Normal file
210
legacyver/legacypacket/player_auth_input.go
Normal file
@@ -0,0 +1,210 @@
|
||||
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"
|
||||
)
|
||||
|
||||
const PlayerAuthInputBitsetSize = 65
|
||||
|
||||
const (
|
||||
InputFlagAscend = iota
|
||||
InputFlagDescend
|
||||
InputFlagNorthJump
|
||||
InputFlagJumpDown
|
||||
InputFlagSprintDown
|
||||
InputFlagChangeHeight
|
||||
InputFlagJumping
|
||||
InputFlagAutoJumpingInWater
|
||||
InputFlagSneaking
|
||||
InputFlagSneakDown
|
||||
InputFlagUp
|
||||
InputFlagDown
|
||||
InputFlagLeft
|
||||
InputFlagRight
|
||||
InputFlagUpLeft
|
||||
InputFlagUpRight
|
||||
InputFlagWantUp
|
||||
InputFlagWantDown
|
||||
InputFlagWantDownSlow
|
||||
InputFlagWantUpSlow
|
||||
InputFlagSprinting
|
||||
InputFlagAscendBlock
|
||||
InputFlagDescendBlock
|
||||
InputFlagSneakToggleDown
|
||||
InputFlagPersistSneak
|
||||
InputFlagStartSprinting
|
||||
InputFlagStopSprinting
|
||||
InputFlagStartSneaking
|
||||
InputFlagStopSneaking
|
||||
InputFlagStartSwimming
|
||||
InputFlagStopSwimming
|
||||
InputFlagStartJumping
|
||||
InputFlagStartGliding
|
||||
InputFlagStopGliding
|
||||
InputFlagPerformItemInteraction
|
||||
InputFlagPerformBlockActions
|
||||
InputFlagPerformItemStackRequest
|
||||
InputFlagHandledTeleport
|
||||
InputFlagEmoting
|
||||
InputFlagMissedSwing
|
||||
InputFlagStartCrawling
|
||||
InputFlagStopCrawling
|
||||
InputFlagStartFlying
|
||||
InputFlagStopFlying
|
||||
InputFlagClientAckServerData
|
||||
InputFlagClientPredictedVehicle
|
||||
InputFlagPaddlingLeft
|
||||
InputFlagPaddlingRight
|
||||
InputFlagBlockBreakingDelayEnabled
|
||||
InputFlagHorizontalCollision
|
||||
InputFlagVerticalCollision
|
||||
InputFlagDownLeft
|
||||
InputFlagDownRight
|
||||
InputFlagStartUsingItem
|
||||
InputFlagCameraRelativeMovementEnabled
|
||||
InputFlagRotControlledByMoveDirection
|
||||
InputFlagStartSpinAttack
|
||||
InputFlagStopSpinAttack
|
||||
InputFlagIsHotbarTouchOnly
|
||||
InputFlagJumpReleasedRaw
|
||||
InputFlagJumpPressedRaw
|
||||
InputFlagJumpCurrentRaw
|
||||
InputFlagSneakReleasedRaw
|
||||
InputFlagSneakPressedRaw
|
||||
InputFlagSneakCurrentRaw
|
||||
)
|
||||
|
||||
const (
|
||||
InputModeMouse = iota + 1
|
||||
InputModeTouch
|
||||
InputModeGamePad
|
||||
InputModeMotionController
|
||||
)
|
||||
|
||||
const (
|
||||
PlayModeNormal = iota
|
||||
PlayModeTeaser
|
||||
PlayModeScreen
|
||||
PlayModeViewer
|
||||
PlayModeReality
|
||||
PlayModePlacement
|
||||
PlayModeLivingRoom
|
||||
PlayModeExitLevel
|
||||
PlayModeExitLevelLivingRoom
|
||||
PlayModeNumModes
|
||||
)
|
||||
|
||||
const (
|
||||
InteractionModelTouch = iota
|
||||
InteractionModelCrosshair
|
||||
InteractionModelClassic
|
||||
)
|
||||
|
||||
// PlayerAuthInput is sent by the client to allow for server authoritative movement. It is used to synchronise
|
||||
// the player input with the position server-side.
|
||||
// The client sends this packet when the ServerAuthoritativeMovementMode field in the StartGame packet is set
|
||||
// to true, instead of the MovePlayer packet. The client will send this packet once every tick.
|
||||
type PlayerAuthInput struct {
|
||||
// Pitch and Yaw hold the rotation that the player reports it has.
|
||||
Pitch, Yaw float32
|
||||
// Position holds the position that the player reports it has.
|
||||
Position mgl32.Vec3
|
||||
// MoveVector is a Vec2 that specifies the direction in which the player moved, as a combination of X/Z
|
||||
// values which are created using the WASD/controller stick state.
|
||||
MoveVector mgl32.Vec2
|
||||
// HeadYaw is the horizontal rotation of the head that the player reports it has.
|
||||
HeadYaw float32
|
||||
// InputData is a combination of bit flags that together specify the way the player moved last tick. It
|
||||
// is a combination of the flags above.
|
||||
InputData protocol.Bitset
|
||||
// InputMode specifies the way that the client inputs data to the screen. It is one of the constants that
|
||||
// may be found above.
|
||||
InputMode uint32
|
||||
// PlayMode specifies the way that the player is playing. The values it holds, which are rather random,
|
||||
// may be found above.
|
||||
PlayMode uint32
|
||||
// InteractionModel is a constant representing the interaction model the player is using. It is one of the
|
||||
// constants that may be found above.
|
||||
InteractionModel uint32
|
||||
// InteractPitch and interactYaw is the rotation the player is looking that they intend to use for
|
||||
// interactions. This is only different to Pitch and Yaw in cases such as VR or when custom cameras
|
||||
// being used.
|
||||
InteractPitch, InteractYaw float32
|
||||
// Tick is the server tick at which the packet was sent. It is used in relation to
|
||||
// CorrectPlayerMovePrediction.
|
||||
Tick uint64
|
||||
// Delta was the delta between the old and the new position. There isn't any practical use for this field
|
||||
// as it can be calculated by the server itself.
|
||||
Delta mgl32.Vec3
|
||||
// ItemInteractionData is the transaction data if the InputData includes an item interaction.
|
||||
ItemInteractionData protocol.UseItemTransactionData
|
||||
// ItemStackRequest is sent by the client to change an item in their inventory.
|
||||
ItemStackRequest protocol.ItemStackRequest
|
||||
// BlockActions is a slice of block actions that the client has interacted with.
|
||||
BlockActions []protocol.PlayerBlockAction
|
||||
// VehicleRotation is the rotation of the vehicle that the player is in, if any.
|
||||
VehicleRotation mgl32.Vec2
|
||||
// ClientPredictedVehicle is the unique ID of the vehicle that the client predicts the player to be in.
|
||||
ClientPredictedVehicle int64
|
||||
// AnalogueMoveVector is a Vec2 that specifies the direction in which the player moved, as a combination
|
||||
// of X/Z values which are created using an analogue input.
|
||||
AnalogueMoveVector mgl32.Vec2
|
||||
// CameraOrientation is the vector that represents the camera's forward direction which can be used to
|
||||
// transform movement to be camera relative.
|
||||
CameraOrientation mgl32.Vec3
|
||||
// RawMoveVector is the value of MoveVector before it is affected by input permissions, sneaking/fly
|
||||
// speeds and isn't normalised for analogue inputs.
|
||||
RawMoveVector mgl32.Vec2
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (pk *PlayerAuthInput) ID() uint32 {
|
||||
return packet.IDPlayerAuthInput
|
||||
}
|
||||
|
||||
func (pk *PlayerAuthInput) Marshal(io protocol.IO) {
|
||||
io.Float32(&pk.Pitch)
|
||||
io.Float32(&pk.Yaw)
|
||||
io.Vec3(&pk.Position)
|
||||
io.Vec2(&pk.MoveVector)
|
||||
io.Float32(&pk.HeadYaw)
|
||||
if proto.IsProtoGTE(io, proto.ID766) {
|
||||
io.Bitset(&pk.InputData, PlayerAuthInputBitsetSize)
|
||||
} else {
|
||||
io.Bitset(&pk.InputData, 64)
|
||||
}
|
||||
io.Varuint32(&pk.InputMode)
|
||||
io.Varuint32(&pk.PlayMode)
|
||||
io.Varuint32(&pk.InteractionModel)
|
||||
io.Float32(&pk.InteractPitch)
|
||||
io.Float32(&pk.InteractYaw)
|
||||
io.Varuint64(&pk.Tick)
|
||||
io.Vec3(&pk.Delta)
|
||||
|
||||
if pk.InputData.Load(InputFlagPerformItemInteraction) {
|
||||
io.PlayerInventoryAction(&pk.ItemInteractionData)
|
||||
}
|
||||
|
||||
if pk.InputData.Load(InputFlagPerformItemStackRequest) {
|
||||
protocol.Single(io, &pk.ItemStackRequest)
|
||||
}
|
||||
|
||||
if pk.InputData.Load(InputFlagPerformBlockActions) {
|
||||
protocol.SliceVarint32Length(io, &pk.BlockActions)
|
||||
}
|
||||
|
||||
if pk.InputData.Load(InputFlagClientPredictedVehicle) {
|
||||
io.Vec2(&pk.VehicleRotation)
|
||||
io.Varint64(&pk.ClientPredictedVehicle)
|
||||
}
|
||||
|
||||
io.Vec2(&pk.AnalogueMoveVector)
|
||||
io.Vec3(&pk.CameraOrientation)
|
||||
|
||||
if proto.IsProtoGTE(io, proto.ID766) {
|
||||
io.Vec2(&pk.RawMoveVector)
|
||||
}
|
||||
}
|
||||
50
legacyver/legacypacket/resource_packs_info.go
Normal file
50
legacyver/legacypacket/resource_packs_info.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It
|
||||
// sends a list of the resource packs it has and basic information on them like the version and description.
|
||||
type ResourcePacksInfo struct {
|
||||
// TexturePackRequired specifies if the client must accept the texture packs the server has in order to
|
||||
// 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.
|
||||
TexturePackRequired bool
|
||||
// HasAddons specifies if any of the resource packs contain addons in them. If set to true, only clients
|
||||
// that support addons will be able to download them.
|
||||
HasAddons bool
|
||||
// HasScripts specifies if any of the resource packs contain scripts in them. If set to true, only clients
|
||||
// that support scripts will be able to download them.
|
||||
HasScripts bool
|
||||
// WorldTemplateUUID is the UUID of the template that has been used to generate the world. Templates can
|
||||
// be downloaded from the marketplace or installed via '.mctemplate' files. If the world was not generated
|
||||
// from a template, this field is empty.
|
||||
WorldTemplateUUID uuid.UUID
|
||||
// WorldTemplateVersion is the version of the world template that has been used to generate the world. If
|
||||
// the world was not generated from a template, this field is empty.
|
||||
WorldTemplateVersion string
|
||||
// TexturePacks is a list of texture packs that the client needs to download before joining the server.
|
||||
// The order of these texture packs is not relevant in this packet. It is however important in the
|
||||
// ResourcePackStack packet.
|
||||
TexturePacks []proto.TexturePackInfo
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*ResourcePacksInfo) ID() uint32 {
|
||||
return packet.IDResourcePacksInfo
|
||||
}
|
||||
|
||||
func (pk *ResourcePacksInfo) Marshal(io protocol.IO) {
|
||||
io.Bool(&pk.TexturePackRequired)
|
||||
io.Bool(&pk.HasAddons)
|
||||
io.Bool(&pk.HasScripts)
|
||||
if proto.IsProtoGTE(io, proto.ID766) {
|
||||
io.UUID(&pk.WorldTemplateUUID)
|
||||
io.String(&pk.WorldTemplateVersion)
|
||||
}
|
||||
protocol.SliceUint16Length(io, &pk.TexturePacks)
|
||||
}
|
||||
32
legacyver/proto/id.go
Normal file
32
legacyver/proto/id.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package proto
|
||||
|
||||
import "github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
|
||||
const (
|
||||
ID766 = 766
|
||||
ID748 = 748
|
||||
ID729 = 729
|
||||
ID712 = 712
|
||||
ID686 = 686
|
||||
ID685 = 685
|
||||
)
|
||||
|
||||
func IsProtoGTE(io protocol.IO, proto int32) bool {
|
||||
return io.(IO).ProtocolID() >= proto
|
||||
}
|
||||
|
||||
func IsProtoLTE(io protocol.IO, proto int32) bool {
|
||||
return io.(IO).ProtocolID() <= proto
|
||||
}
|
||||
|
||||
func IsProtoLT(io protocol.IO, proto int32) bool {
|
||||
return io.(IO).ProtocolID() < proto
|
||||
}
|
||||
|
||||
func IsProtoGT(io protocol.IO, proto int32) bool {
|
||||
return io.(IO).ProtocolID() > proto
|
||||
}
|
||||
|
||||
func FetchProtoID(io protocol.IO) int32 {
|
||||
return io.(IO).ProtocolID()
|
||||
}
|
||||
53
legacyver/proto/io.go
Normal file
53
legacyver/proto/io.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
)
|
||||
|
||||
type IO interface {
|
||||
protocol.IO
|
||||
|
||||
SetProtocolID(protocolID int32)
|
||||
ProtocolID() int32
|
||||
}
|
||||
|
||||
type Reader struct {
|
||||
*protocol.Reader
|
||||
|
||||
protocolID int32
|
||||
}
|
||||
|
||||
func NewReader(r *protocol.Reader, protocolID int32) *Reader {
|
||||
return &Reader{
|
||||
Reader: r,
|
||||
protocolID: protocolID,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reader) SetProtocolID(protocolID int32) { r.protocolID = protocolID }
|
||||
func (r *Reader) ProtocolID() int32 { return r.protocolID }
|
||||
func (r *Reader) Reads() bool { return true }
|
||||
|
||||
type Writer struct {
|
||||
*protocol.Writer
|
||||
|
||||
protocolID int32
|
||||
}
|
||||
|
||||
func NewWriter(w *protocol.Writer, protocolID int32) *Writer {
|
||||
return &Writer{w, protocolID}
|
||||
}
|
||||
|
||||
func (w *Writer) SetProtocolID(protocolID int32) { w.protocolID = protocolID }
|
||||
func (w *Writer) ProtocolID() int32 { return w.protocolID }
|
||||
func (w *Writer) Reads() bool { return false }
|
||||
|
||||
func IsReader(r protocol.IO) bool {
|
||||
_, ok := r.(*Reader)
|
||||
return ok
|
||||
}
|
||||
|
||||
func IsWriter(w protocol.IO) bool {
|
||||
_, ok := w.(*Writer)
|
||||
return ok
|
||||
}
|
||||
652
legacyver/proto/item_stack.go
Normal file
652
legacyver/proto/item_stack.go
Normal file
@@ -0,0 +1,652 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
FilterCauseServerChatPublic = iota
|
||||
FilterCauseServerChatWhisper
|
||||
FilterCauseSignText
|
||||
FilterCauseAnvilText
|
||||
FilterCauseBookAndQuillText
|
||||
FilterCauseCommandBlockText
|
||||
FilterCauseBlockActorDataText
|
||||
FilterCauseJoinEventText
|
||||
FilterCauseLeaveEventText
|
||||
FilterCauseSlashCommandChat
|
||||
FilterCauseCartographyText
|
||||
FilterCauseKickCommand
|
||||
FilterCauseTitleCommand
|
||||
FilterCauseSummonCommand
|
||||
)
|
||||
|
||||
// ItemStackRequest represents a single request present in an ItemStackRequest packet sent by the client to
|
||||
// change an item in an inventory.
|
||||
// Item stack requests are either approved or rejected by the server using the ItemStackResponse packet.
|
||||
type ItemStackRequest struct {
|
||||
// RequestID is a unique ID for the request. This ID is used by the server to send a response for this
|
||||
// specific request in the ItemStackResponse packet.
|
||||
RequestID int32
|
||||
// Actions is a list of actions performed by the client. The actual type of the actions depends on which
|
||||
// ID was present, and is one of the concrete types below.
|
||||
Actions []protocol.StackRequestAction
|
||||
// FilterStrings is a list of filter strings involved in the request. This is typically filled with one string
|
||||
// when an anvil or cartography is used.
|
||||
FilterStrings []string
|
||||
// FilterCause represents the cause of any potential filtering. This is one of the constants above.
|
||||
FilterCause int32
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes an ItemStackRequest.
|
||||
func (x *ItemStackRequest) Marshal(r protocol.IO) {
|
||||
r.Varint32(&x.RequestID)
|
||||
protocol.FuncSlice(r, &x.Actions, r.StackRequestAction)
|
||||
protocol.FuncSlice(r, &x.FilterStrings, r.String)
|
||||
r.Int32(&x.FilterCause)
|
||||
}
|
||||
|
||||
// lookupStackRequestActionType looks up the ID of a StackRequestAction.
|
||||
func lookupStackRequestActionType(x StackRequestAction, id *uint8) bool {
|
||||
switch x.(type) {
|
||||
case *TakeStackRequestAction:
|
||||
*id = StackRequestActionTake
|
||||
case *PlaceStackRequestAction:
|
||||
*id = StackRequestActionPlace
|
||||
case *SwapStackRequestAction:
|
||||
*id = StackRequestActionSwap
|
||||
case *DropStackRequestAction:
|
||||
*id = StackRequestActionDrop
|
||||
case *DestroyStackRequestAction:
|
||||
*id = StackRequestActionDestroy
|
||||
case *ConsumeStackRequestAction:
|
||||
*id = StackRequestActionConsume
|
||||
case *CreateStackRequestAction:
|
||||
*id = StackRequestActionCreate
|
||||
case *LabTableCombineStackRequestAction:
|
||||
*id = StackRequestActionLabTableCombine
|
||||
case *BeaconPaymentStackRequestAction:
|
||||
*id = StackRequestActionBeaconPayment
|
||||
case *MineBlockStackRequestAction:
|
||||
*id = StackRequestActionMineBlock
|
||||
case *CraftRecipeStackRequestAction:
|
||||
*id = StackRequestActionCraftRecipe
|
||||
case *AutoCraftRecipeStackRequestAction:
|
||||
*id = StackRequestActionCraftRecipeAuto
|
||||
case *CraftCreativeStackRequestAction:
|
||||
*id = StackRequestActionCraftCreative
|
||||
case *CraftRecipeOptionalStackRequestAction:
|
||||
*id = StackRequestActionCraftRecipeOptional
|
||||
case *CraftGrindstoneRecipeStackRequestAction:
|
||||
*id = StackRequestActionCraftGrindstone
|
||||
case *CraftLoomRecipeStackRequestAction:
|
||||
*id = StackRequestActionCraftLoom
|
||||
case *CraftNonImplementedStackRequestAction:
|
||||
*id = StackRequestActionCraftNonImplementedDeprecated
|
||||
case *CraftResultsDeprecatedStackRequestAction:
|
||||
*id = StackRequestActionCraftResultsDeprecated
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// lookupStackRequestAction looks up the StackRequestAction matching an ID.
|
||||
func lookupStackRequestAction(id uint8, x *StackRequestAction) bool {
|
||||
switch id {
|
||||
case StackRequestActionTake:
|
||||
*x = &TakeStackRequestAction{}
|
||||
case StackRequestActionPlace:
|
||||
*x = &PlaceStackRequestAction{}
|
||||
case StackRequestActionSwap:
|
||||
*x = &SwapStackRequestAction{}
|
||||
case StackRequestActionDrop:
|
||||
*x = &DropStackRequestAction{}
|
||||
case StackRequestActionDestroy:
|
||||
*x = &DestroyStackRequestAction{}
|
||||
case StackRequestActionConsume:
|
||||
*x = &ConsumeStackRequestAction{}
|
||||
case StackRequestActionCreate:
|
||||
*x = &CreateStackRequestAction{}
|
||||
case StackRequestActionPlaceInContainer:
|
||||
*x = &PlaceInContainerStackRequestAction{}
|
||||
case StackRequestActionTakeOutContainer:
|
||||
*x = &TakeOutContainerStackRequestAction{}
|
||||
case StackRequestActionLabTableCombine:
|
||||
*x = &LabTableCombineStackRequestAction{}
|
||||
case StackRequestActionBeaconPayment:
|
||||
*x = &BeaconPaymentStackRequestAction{}
|
||||
case StackRequestActionMineBlock:
|
||||
*x = &MineBlockStackRequestAction{}
|
||||
case StackRequestActionCraftRecipe:
|
||||
*x = &CraftRecipeStackRequestAction{}
|
||||
case StackRequestActionCraftRecipeAuto:
|
||||
*x = &AutoCraftRecipeStackRequestAction{}
|
||||
case StackRequestActionCraftCreative:
|
||||
*x = &CraftCreativeStackRequestAction{}
|
||||
case StackRequestActionCraftRecipeOptional:
|
||||
*x = &CraftRecipeOptionalStackRequestAction{}
|
||||
case StackRequestActionCraftGrindstone:
|
||||
*x = &CraftGrindstoneRecipeStackRequestAction{}
|
||||
case StackRequestActionCraftLoom:
|
||||
*x = &CraftLoomRecipeStackRequestAction{}
|
||||
case StackRequestActionCraftNonImplementedDeprecated:
|
||||
*x = &CraftNonImplementedStackRequestAction{}
|
||||
case StackRequestActionCraftResultsDeprecated:
|
||||
*x = &CraftResultsDeprecatedStackRequestAction{}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
ItemStackResponseStatusOK = iota
|
||||
ItemStackResponseStatusError
|
||||
ItemStackResponseStatusInvalidRequestActionType
|
||||
ItemStackResponseStatusActionRequestNotAllowed
|
||||
ItemStackResponseStatusScreenHandlerEndRequestFailed
|
||||
ItemStackResponseStatusItemRequestActionHandlerCommitFailed
|
||||
ItemStackResponseStatusInvalidRequestCraftActionType
|
||||
ItemStackResponseStatusInvalidCraftRequest
|
||||
ItemStackResponseStatusInvalidCraftRequestScreen
|
||||
ItemStackResponseStatusInvalidCraftResult
|
||||
ItemStackResponseStatusInvalidCraftResultIndex
|
||||
ItemStackResponseStatusInvalidCraftResultItem
|
||||
ItemStackResponseStatusInvalidItemNetId
|
||||
ItemStackResponseStatusMissingCreatedOutputContainer
|
||||
ItemStackResponseStatusFailedToSetCreatedItemOutputSlot
|
||||
ItemStackResponseStatusRequestAlreadyInProgress
|
||||
ItemStackResponseStatusFailedToInitSparseContainer
|
||||
ItemStackResponseStatusResultTransferFailed
|
||||
ItemStackResponseStatusExpectedItemSlotNotFullyConsumed
|
||||
ItemStackResponseStatusExpectedAnywhereItemNotFullyConsumed
|
||||
ItemStackResponseStatusItemAlreadyConsumedFromSlot
|
||||
ItemStackResponseStatusConsumedTooMuchFromSlot
|
||||
ItemStackResponseStatusMismatchSlotExpectedConsumedItem
|
||||
ItemStackResponseStatusMismatchSlotExpectedConsumedItemNetIdVariant
|
||||
ItemStackResponseStatusFailedToMatchExpectedSlotConsumedItem
|
||||
ItemStackResponseStatusFailedToMatchExpectedAllowedAnywhereConsumedItem
|
||||
ItemStackResponseStatusConsumedItemOutOfAllowedSlotRange
|
||||
ItemStackResponseStatusConsumedItemNotAllowed
|
||||
ItemStackResponseStatusPlayerNotInCreativeMode
|
||||
ItemStackResponseStatusInvalidExperimentalRecipeRequest
|
||||
ItemStackResponseStatusFailedToCraftCreative
|
||||
ItemStackResponseStatusFailedToGetLevelRecipe
|
||||
ItemStackResponseStatusFailedToFindRecipeByNetId
|
||||
ItemStackResponseStatusMismatchedCraftingSize
|
||||
ItemStackResponseStatusMissingInputSparseContainer
|
||||
ItemStackResponseStatusMismatchedRecipeForInputGridItems
|
||||
ItemStackResponseStatusEmptyCraftResults
|
||||
ItemStackResponseStatusFailedToEnchant
|
||||
ItemStackResponseStatusMissingInputItem
|
||||
ItemStackResponseStatusInsufficientPlayerLevelToEnchant
|
||||
ItemStackResponseStatusMissingMaterialItem
|
||||
ItemStackResponseStatusMissingActor
|
||||
ItemStackResponseStatusUnknownPrimaryEffect
|
||||
ItemStackResponseStatusPrimaryEffectOutOfRange
|
||||
ItemStackResponseStatusPrimaryEffectUnavailable
|
||||
ItemStackResponseStatusSecondaryEffectOutOfRange
|
||||
ItemStackResponseStatusSecondaryEffectUnavailable
|
||||
ItemStackResponseStatusDstContainerEqualToCreatedOutputContainer
|
||||
ItemStackResponseStatusDstContainerAndSlotEqualToSrcContainerAndSlot
|
||||
ItemStackResponseStatusFailedToValidateSrcSlot
|
||||
ItemStackResponseStatusFailedToValidateDstSlot
|
||||
ItemStackResponseStatusInvalidAdjustedAmount
|
||||
ItemStackResponseStatusInvalidItemSetType
|
||||
ItemStackResponseStatusInvalidTransferAmount
|
||||
ItemStackResponseStatusCannotSwapItem
|
||||
ItemStackResponseStatusCannotPlaceItem
|
||||
ItemStackResponseStatusUnhandledItemSetType
|
||||
ItemStackResponseStatusInvalidRemovedAmount
|
||||
ItemStackResponseStatusInvalidRegion
|
||||
ItemStackResponseStatusCannotDropItem
|
||||
ItemStackResponseStatusCannotDestroyItem
|
||||
ItemStackResponseStatusInvalidSourceContainer
|
||||
ItemStackResponseStatusItemNotConsumed
|
||||
ItemStackResponseStatusInvalidNumCrafts
|
||||
ItemStackResponseStatusInvalidCraftResultStackSize
|
||||
ItemStackResponseStatusCannotRemoveItem
|
||||
ItemStackResponseStatusCannotConsumeItem
|
||||
ItemStackResponseStatusScreenStackError
|
||||
)
|
||||
|
||||
// ItemStackResponse is a response to an individual ItemStackRequest.
|
||||
type ItemStackResponse struct {
|
||||
// Status specifies if the request with the RequestID below was successful. If this is the case, the
|
||||
// ContainerInfo below will have information on what slots ended up changing. If not, the container info
|
||||
// will be empty.
|
||||
// A non-0 status means an error occurred and will result in the action being reverted.
|
||||
Status uint8
|
||||
// RequestID is the unique ID of the request that this response is in reaction to. If rejected, the client
|
||||
// will undo the actions from the request with this ID.
|
||||
RequestID int32
|
||||
// ContainerInfo holds information on the containers that had their contents changed as a result of the
|
||||
// request.
|
||||
ContainerInfo []StackResponseContainerInfo
|
||||
}
|
||||
|
||||
func (x *ItemStackResponse) ToLatest() protocol.ItemStackResponse {
|
||||
ret := protocol.ItemStackResponse{
|
||||
Status: x.Status,
|
||||
RequestID: x.RequestID,
|
||||
ContainerInfo: make([]protocol.StackResponseContainerInfo, len(x.ContainerInfo)),
|
||||
}
|
||||
for i, v := range x.ContainerInfo {
|
||||
ret.ContainerInfo[i] = protocol.StackResponseContainerInfo{
|
||||
Container: v.Container,
|
||||
SlotInfo: make([]protocol.StackResponseSlotInfo, len(v.SlotInfo)),
|
||||
}
|
||||
for j, w := range v.SlotInfo {
|
||||
ret.ContainerInfo[i].SlotInfo[j] = protocol.StackResponseSlotInfo{
|
||||
Slot: w.Slot,
|
||||
HotbarSlot: w.HotbarSlot,
|
||||
Count: w.Count,
|
||||
StackNetworkID: w.StackNetworkID,
|
||||
CustomName: w.CustomName,
|
||||
FilteredCustomName: w.FilteredCustomName,
|
||||
DurabilityCorrection: w.DurabilityCorrection,
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes an ItemStackResponse.
|
||||
func (x *ItemStackResponse) Marshal(r protocol.IO) {
|
||||
r.Uint8(&x.Status)
|
||||
r.Varint32(&x.RequestID)
|
||||
if x.Status == ItemStackResponseStatusOK {
|
||||
protocol.Slice(r, &x.ContainerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// StackResponseContainerInfo holds information on what slots in a container have what item stack in them.
|
||||
type StackResponseContainerInfo struct {
|
||||
// Container is the FullContainerName that describes the container that the slots that follow are in. For
|
||||
// the main inventory, the ContainerID seems to be 0x1b. Fur the cursor, this value seems to be 0x3a. For
|
||||
// the crafting grid, this value seems to be 0x0d.
|
||||
Container protocol.FullContainerName
|
||||
// SlotInfo holds information on what item stack should be present in specific slots in the container.
|
||||
SlotInfo []StackResponseSlotInfo
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes a StackResponseContainerInfo.
|
||||
func (x *StackResponseContainerInfo) Marshal(r protocol.IO) {
|
||||
protocol.Single(r, &x.Container)
|
||||
protocol.Slice(r, &x.SlotInfo)
|
||||
}
|
||||
|
||||
// StackResponseSlotInfo holds information on what item stack should be present in a specific slot.
|
||||
type StackResponseSlotInfo struct {
|
||||
// Slot and HotbarSlot seem to be the same value every time: The slot that was actually changed. I'm not
|
||||
// sure if these slots ever differ.
|
||||
Slot, HotbarSlot byte
|
||||
// Count is the total count of the item stack. This count will be shown client-side after the response is
|
||||
// sent to the client.
|
||||
Count byte
|
||||
// StackNetworkID is the network ID of the new stack at a specific slot.
|
||||
StackNetworkID int32
|
||||
// CustomName is the custom name of the item stack. It is used in relation to text filtering.
|
||||
CustomName string
|
||||
// FilteredCustomName is a filtered version of CustomName with all the profanity removed. The client will
|
||||
// use this over CustomName if this field is not empty and they have the "Filter Profanity" setting enabled.
|
||||
FilteredCustomName string
|
||||
// DurabilityCorrection is the current durability of the item stack. This durability will be shown
|
||||
// client-side after the response is sent to the client.
|
||||
DurabilityCorrection int32
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes a StackResponseSlotInfo.
|
||||
func (x *StackResponseSlotInfo) Marshal(r protocol.IO) {
|
||||
r.Uint8(&x.Slot)
|
||||
r.Uint8(&x.HotbarSlot)
|
||||
r.Uint8(&x.Count)
|
||||
r.Varint32(&x.StackNetworkID)
|
||||
if x.Slot != x.HotbarSlot {
|
||||
r.InvalidValue(x.HotbarSlot, "hotbar slot", "hot bar slot must be equal to normal slot")
|
||||
}
|
||||
r.String(&x.CustomName)
|
||||
if IsProtoGTE(r, ID766) {
|
||||
r.String(&x.FilteredCustomName)
|
||||
}
|
||||
r.Varint32(&x.DurabilityCorrection)
|
||||
}
|
||||
|
||||
// StackRequestAction represents a single action related to the inventory present in an ItemStackRequest.
|
||||
// The action is one of the concrete types below, each of which are indicative of a different action by the
|
||||
// client, such as moving an item around the inventory or placing a block. It is an alias of Marshaler.
|
||||
type StackRequestAction interface {
|
||||
protocol.Marshaler
|
||||
}
|
||||
|
||||
const (
|
||||
StackRequestActionTake = iota
|
||||
StackRequestActionPlace
|
||||
StackRequestActionSwap
|
||||
StackRequestActionDrop
|
||||
StackRequestActionDestroy
|
||||
StackRequestActionConsume
|
||||
StackRequestActionCreate
|
||||
StackRequestActionPlaceInContainer
|
||||
StackRequestActionTakeOutContainer
|
||||
StackRequestActionLabTableCombine
|
||||
StackRequestActionBeaconPayment
|
||||
StackRequestActionMineBlock
|
||||
StackRequestActionCraftRecipe
|
||||
StackRequestActionCraftRecipeAuto
|
||||
StackRequestActionCraftCreative
|
||||
StackRequestActionCraftRecipeOptional
|
||||
StackRequestActionCraftGrindstone
|
||||
StackRequestActionCraftLoom
|
||||
StackRequestActionCraftNonImplementedDeprecated
|
||||
StackRequestActionCraftResultsDeprecated
|
||||
)
|
||||
|
||||
// transferStackRequestAction is the structure shared by StackRequestActions that transfer items from one
|
||||
// slot into another.
|
||||
type transferStackRequestAction struct {
|
||||
// Count is the count of the item in the source slot that was taken towards the destination slot.
|
||||
Count byte
|
||||
// Source and Destination point to the source slot from which Count of the item stack were taken and the
|
||||
// destination slot to which this item was moved.
|
||||
Source, Destination StackRequestSlotInfo
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *transferStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Uint8(&a.Count)
|
||||
StackReqSlotInfo(r, &a.Source)
|
||||
StackReqSlotInfo(r, &a.Destination)
|
||||
}
|
||||
|
||||
// TakeStackRequestAction is sent by the client to the server to take x amount of items from one slot in a
|
||||
// container to the cursor.
|
||||
type TakeStackRequestAction struct {
|
||||
transferStackRequestAction
|
||||
}
|
||||
|
||||
// PlaceStackRequestAction is sent by the client to the server to place x amount of items from one slot into
|
||||
// another slot, such as when shift clicking an item in the inventory to move it around or when moving an item
|
||||
// in the cursor into a slot.
|
||||
type PlaceStackRequestAction struct {
|
||||
transferStackRequestAction
|
||||
}
|
||||
|
||||
// SwapStackRequestAction is sent by the client to swap the item in its cursor with an item present in another
|
||||
// container. The two item stacks swap places.
|
||||
type SwapStackRequestAction struct {
|
||||
// Source and Destination point to the source slot from which Count of the item stack were taken and the
|
||||
// destination slot to which this item was moved.
|
||||
Source, Destination StackRequestSlotInfo
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *SwapStackRequestAction) Marshal(r protocol.IO) {
|
||||
StackReqSlotInfo(r, &a.Source)
|
||||
StackReqSlotInfo(r, &a.Destination)
|
||||
}
|
||||
|
||||
// DropStackRequestAction is sent by the client when it drops an item out of the inventory when it has its
|
||||
// inventory opened. This action is not sent when a player drops an item out of the hotbar using the Q button
|
||||
// (or the equivalent on mobile). The InventoryTransaction packet is still used for that action, regardless of
|
||||
// whether the item stack network IDs are used or not.
|
||||
type DropStackRequestAction struct {
|
||||
// Count is the count of the item in the source slot that was taken towards the destination slot.
|
||||
Count byte
|
||||
// Source is the source slot from which items were dropped to the ground.
|
||||
Source StackRequestSlotInfo
|
||||
// Randomly seems to be set to false in most cases. I'm not entirely sure what this does, but this is what
|
||||
// vanilla calls this field.
|
||||
Randomly bool
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *DropStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Uint8(&a.Count)
|
||||
StackReqSlotInfo(r, &a.Source)
|
||||
r.Bool(&a.Randomly)
|
||||
}
|
||||
|
||||
// DestroyStackRequestAction is sent by the client when it destroys an item in creative mode by moving it
|
||||
// back into the creative inventory.
|
||||
type DestroyStackRequestAction struct {
|
||||
// Count is the count of the item in the source slot that was destroyed.
|
||||
Count byte
|
||||
// Source is the source slot from which items came that were destroyed by moving them into the creative
|
||||
// inventory.
|
||||
Source StackRequestSlotInfo
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *DestroyStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Uint8(&a.Count)
|
||||
StackReqSlotInfo(r, &a.Source)
|
||||
}
|
||||
|
||||
// ConsumeStackRequestAction is sent by the client when it uses an item to craft another item. The original
|
||||
// item is 'consumed'.
|
||||
type ConsumeStackRequestAction struct {
|
||||
DestroyStackRequestAction
|
||||
}
|
||||
|
||||
// CreateStackRequestAction is sent by the client when an item is created through being used as part of a
|
||||
// recipe. For example, when milk is used to craft a cake, the buckets are leftover. The buckets are moved to
|
||||
// the slot sent by the client here.
|
||||
// Note that before this is sent, an action for consuming all items in the crafting table/grid is sent. Items
|
||||
// that are not fully consumed when used for a recipe should not be destroyed there, but instead, should be
|
||||
// turned into their respective resulting items.
|
||||
type CreateStackRequestAction struct {
|
||||
// ResultsSlot is the slot in the inventory in which the results of the crafting ingredients are to be
|
||||
// placed.
|
||||
ResultsSlot byte
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *CreateStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Uint8(&a.ResultsSlot)
|
||||
}
|
||||
|
||||
// PlaceInContainerStackRequestAction currently has no known purpose.
|
||||
type PlaceInContainerStackRequestAction struct {
|
||||
transferStackRequestAction
|
||||
}
|
||||
|
||||
// TakeOutContainerStackRequestAction currently has no known purpose.
|
||||
type TakeOutContainerStackRequestAction struct {
|
||||
transferStackRequestAction
|
||||
}
|
||||
|
||||
// LabTableCombineStackRequestAction is sent by the client when it uses a lab table to combine item stacks.
|
||||
type LabTableCombineStackRequestAction struct{}
|
||||
|
||||
// Marshal ...
|
||||
func (a *LabTableCombineStackRequestAction) Marshal(protocol.IO) {}
|
||||
|
||||
// BeaconPaymentStackRequestAction is sent by the client when it submits an item to enable effects from a
|
||||
// beacon. These items will have been moved into the beacon item slot in advance.
|
||||
type BeaconPaymentStackRequestAction struct {
|
||||
// PrimaryEffect and SecondaryEffect are the effects that were selected from the beacon.
|
||||
PrimaryEffect, SecondaryEffect int32
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *BeaconPaymentStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Varint32(&a.PrimaryEffect)
|
||||
r.Varint32(&a.SecondaryEffect)
|
||||
}
|
||||
|
||||
// MineBlockStackRequestAction is sent by the client when it breaks a block.
|
||||
type MineBlockStackRequestAction struct {
|
||||
// HotbarSlot is the slot held by the player while mining a block.
|
||||
HotbarSlot int32
|
||||
// PredictedDurability is the durability of the item that the client assumes to be present at the time.
|
||||
PredictedDurability int32
|
||||
// StackNetworkID is the unique stack ID that the client assumes to be present at the time. The server
|
||||
// must check if these IDs match. If they do not match, servers should reject the stack request that the
|
||||
// action holding this info was in.
|
||||
StackNetworkID int32
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *MineBlockStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Varint32(&a.HotbarSlot)
|
||||
r.Varint32(&a.PredictedDurability)
|
||||
r.Varint32(&a.StackNetworkID)
|
||||
}
|
||||
|
||||
// CraftRecipeStackRequestAction is sent by the client the moment it begins crafting an item. This is the
|
||||
// first action sent, before the Consume and Create item stack request actions.
|
||||
// This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as
|
||||
// crafting, where the old item is consumed.
|
||||
type CraftRecipeStackRequestAction struct {
|
||||
// RecipeNetworkID is the network ID of the recipe that is about to be crafted. This network ID matches
|
||||
// one of the recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as
|
||||
// of 1.16.
|
||||
RecipeNetworkID uint32
|
||||
// NumberOfCrafts is how many times the recipe was crafted. This field appears to be boilerplate and
|
||||
// has no effect.
|
||||
NumberOfCrafts byte
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *CraftRecipeStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Varuint32(&a.RecipeNetworkID)
|
||||
r.Uint8(&a.NumberOfCrafts)
|
||||
}
|
||||
|
||||
// AutoCraftRecipeStackRequestAction is sent by the client similarly to the CraftRecipeStackRequestAction. The
|
||||
// only difference is that the recipe is automatically created and crafted by shift clicking the recipe book.
|
||||
type AutoCraftRecipeStackRequestAction struct {
|
||||
// RecipeNetworkID is the network ID of the recipe that is about to be crafted. This network ID matches
|
||||
// one of the recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as
|
||||
// of 1.16.
|
||||
RecipeNetworkID uint32
|
||||
// NumberOfCrafts is how many times the recipe was crafted. This field is just a duplicate of TimesCrafted.
|
||||
NumberOfCrafts byte
|
||||
// TimesCrafted is how many times the recipe was crafted.
|
||||
TimesCrafted byte
|
||||
// Ingredients is a slice of ItemDescriptorCount that contains the ingredients that were used to craft the recipe.
|
||||
// It is not exactly clear what this is used for, but it is sent by the vanilla client.
|
||||
Ingredients []protocol.ItemDescriptorCount
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *AutoCraftRecipeStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Varuint32(&a.RecipeNetworkID)
|
||||
r.Uint8(&a.NumberOfCrafts)
|
||||
r.Uint8(&a.TimesCrafted)
|
||||
protocol.FuncSlice(r, &a.Ingredients, r.ItemDescriptorCount)
|
||||
}
|
||||
|
||||
// CraftCreativeStackRequestAction is sent by the client when it takes an item out fo the creative inventory.
|
||||
// The item is thus not really crafted, but instantly created.
|
||||
type CraftCreativeStackRequestAction struct {
|
||||
// CreativeItemNetworkID is the network ID of the creative item that is being created. This is one of the
|
||||
// creative item network IDs sent in the CreativeContent packet.
|
||||
CreativeItemNetworkID uint32
|
||||
// NumberOfCrafts is how many times the recipe was crafted. This field appears to be boilerplate and
|
||||
// has no effect.
|
||||
NumberOfCrafts byte
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *CraftCreativeStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Varuint32(&a.CreativeItemNetworkID)
|
||||
r.Uint8(&a.NumberOfCrafts)
|
||||
}
|
||||
|
||||
// CraftRecipeOptionalStackRequestAction is sent when using an anvil. When this action is sent, the
|
||||
// FilterStrings field in the respective stack request is non-empty and contains the name of the item created
|
||||
// using the anvil or cartography table.
|
||||
type CraftRecipeOptionalStackRequestAction struct {
|
||||
// RecipeNetworkID is the network ID of the multi-recipe that is about to be crafted. This network ID matches
|
||||
// one of the multi-recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as
|
||||
// of 1.16.
|
||||
RecipeNetworkID uint32
|
||||
// FilterStringIndex is the index of a filter string sent in a ItemStackRequest.
|
||||
FilterStringIndex int32
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (c *CraftRecipeOptionalStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Varuint32(&c.RecipeNetworkID)
|
||||
r.Int32(&c.FilterStringIndex)
|
||||
}
|
||||
|
||||
// CraftGrindstoneRecipeStackRequestAction is sent when a grindstone recipe is crafted. It contains the RecipeNetworkID
|
||||
// to identify the recipe crafted, and the cost for crafting the recipe.
|
||||
type CraftGrindstoneRecipeStackRequestAction struct {
|
||||
// RecipeNetworkID is the network ID of the recipe that is about to be crafted. This network ID matches
|
||||
// one of the recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as
|
||||
// of 1.16.
|
||||
RecipeNetworkID uint32
|
||||
// NumberOfCrafts is how many times the recipe was crafted. This field appears to be boilerplate and
|
||||
// has no effect.
|
||||
NumberOfCrafts byte
|
||||
// Cost is the cost of the recipe that was crafted.
|
||||
Cost int32
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (c *CraftGrindstoneRecipeStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.Varuint32(&c.RecipeNetworkID)
|
||||
r.Uint8(&c.NumberOfCrafts)
|
||||
r.Varint32(&c.Cost)
|
||||
}
|
||||
|
||||
// CraftLoomRecipeStackRequestAction is sent when a loom recipe is crafted. It simply contains the
|
||||
// pattern identifier to figure out what pattern is meant to be applied to the item.
|
||||
type CraftLoomRecipeStackRequestAction struct {
|
||||
// Pattern is the pattern identifier for the loom recipe.
|
||||
Pattern string
|
||||
// TimesCrafted is how many times the recipe was crafted.
|
||||
TimesCrafted byte
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (c *CraftLoomRecipeStackRequestAction) Marshal(r protocol.IO) {
|
||||
r.String(&c.Pattern)
|
||||
r.Uint8(&c.TimesCrafted)
|
||||
}
|
||||
|
||||
// CraftNonImplementedStackRequestAction is an action sent for inventory actions that aren't yet implemented
|
||||
// in the new system. These include, for example, anvils.
|
||||
type CraftNonImplementedStackRequestAction struct{}
|
||||
|
||||
// Marshal ...
|
||||
func (*CraftNonImplementedStackRequestAction) Marshal(protocol.IO) {}
|
||||
|
||||
// CraftResultsDeprecatedStackRequestAction is an additional, deprecated packet sent by the client after
|
||||
// crafting. It holds the final results and the amount of times the recipe was crafted. It shouldn't be used.
|
||||
// This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as
|
||||
// crafting, where the old item is consumed.
|
||||
type CraftResultsDeprecatedStackRequestAction struct {
|
||||
ResultItems []protocol.ItemStack
|
||||
TimesCrafted byte
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (a *CraftResultsDeprecatedStackRequestAction) Marshal(r protocol.IO) {
|
||||
protocol.FuncSlice(r, &a.ResultItems, r.Item)
|
||||
r.Uint8(&a.TimesCrafted)
|
||||
}
|
||||
|
||||
// StackRequestSlotInfo holds information on a specific slot client-side.
|
||||
type StackRequestSlotInfo struct {
|
||||
// Container is the FullContainerName that describes the container that the slot is in.
|
||||
Container protocol.FullContainerName
|
||||
// Slot is the index of the slot within the container with the ContainerID above.
|
||||
Slot byte
|
||||
// StackNetworkID is the unique stack ID that the client assumes to be present in this slot. The server
|
||||
// must check if these IDs match. If they do not match, servers should reject the stack request that the
|
||||
// action holding this info was in.
|
||||
StackNetworkID int32
|
||||
}
|
||||
|
||||
// StackReqSlotInfo reads/writes a StackRequestSlotInfo x using IO r.
|
||||
func StackReqSlotInfo(r protocol.IO, x *StackRequestSlotInfo) {
|
||||
protocol.Single(r, &x.Container)
|
||||
r.Uint8(&x.Slot)
|
||||
r.Varint32(&x.StackNetworkID)
|
||||
}
|
||||
79
legacyver/proto/resource_pack.go
Normal file
79
legacyver/proto/resource_pack.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
)
|
||||
|
||||
// TexturePackInfo represents a texture pack's info sent over network. It holds information about the
|
||||
// texture pack such as its name, description and version.
|
||||
type TexturePackInfo struct {
|
||||
// UUID is the UUID of the texture pack. Each texture pack downloaded must have a different UUID in
|
||||
// order for the client to be able to handle them properly.
|
||||
UUID uuid.UUID
|
||||
// Version is the version of the texture pack. The client will cache texture packs sent by the server as
|
||||
// long as they carry the same version. Sending a texture pack with a different version than previously
|
||||
// will force the client to re-download it.
|
||||
Version string
|
||||
// Size is the total size in bytes that the texture pack occupies. This is the size of the compressed
|
||||
// archive (zip) of the texture pack.
|
||||
Size uint64
|
||||
// ContentKey is the key used to decrypt the behaviour pack if it is encrypted. This is generally the case
|
||||
// for marketplace texture packs.
|
||||
ContentKey string
|
||||
// SubPackName ...
|
||||
SubPackName string
|
||||
// ContentIdentity is another UUID for the resource pack, and is generally set for marketplace texture
|
||||
// packs. It is also required for client-side validations when the resource pack is encrypted.
|
||||
ContentIdentity string
|
||||
// HasScripts specifies if the texture packs has any scripts in it. A client will only download the
|
||||
// behaviour pack if it supports scripts, which, up to 1.11, only includes Windows 10.
|
||||
HasScripts bool
|
||||
// AddonPack specifies if the texture pack is from an addon.
|
||||
AddonPack bool
|
||||
// RTXEnabled specifies if the texture pack uses the raytracing technology introduced in 1.16.200.
|
||||
RTXEnabled bool
|
||||
// DownloadURL is a URL that the client can use to download the pack instead of the server sending it in
|
||||
// chunks, which it will continue to do if this field is left empty.
|
||||
DownloadURL string
|
||||
}
|
||||
|
||||
func (x *TexturePackInfo) ToLatest() protocol.TexturePackInfo {
|
||||
return protocol.TexturePackInfo{
|
||||
UUID: x.UUID,
|
||||
Version: x.Version,
|
||||
Size: x.Size,
|
||||
ContentKey: x.ContentKey,
|
||||
SubPackName: x.SubPackName,
|
||||
ContentIdentity: x.ContentIdentity,
|
||||
HasScripts: x.HasScripts,
|
||||
AddonPack: x.AddonPack,
|
||||
RTXEnabled: x.RTXEnabled,
|
||||
DownloadURL: x.DownloadURL,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal encodes/decodes a TexturePackInfo.
|
||||
func (x *TexturePackInfo) Marshal(r protocol.IO) {
|
||||
if IsProtoGTE(r, ID766) {
|
||||
r.UUID(&x.UUID)
|
||||
} else {
|
||||
if IsReader(r) {
|
||||
uuidStr := ""
|
||||
r.String(&uuidStr)
|
||||
x.UUID = uuid.MustParse(uuidStr)
|
||||
} else {
|
||||
uuidStr := x.UUID.String()
|
||||
r.String(&uuidStr)
|
||||
}
|
||||
}
|
||||
r.String(&x.Version)
|
||||
r.Uint64(&x.Size)
|
||||
r.String(&x.ContentKey)
|
||||
r.String(&x.SubPackName)
|
||||
r.String(&x.ContentIdentity)
|
||||
r.Bool(&x.HasScripts)
|
||||
r.Bool(&x.AddonPack)
|
||||
r.Bool(&x.RTXEnabled)
|
||||
r.String(&x.DownloadURL)
|
||||
}
|
||||
5
legacyver/proto/type.go
Normal file
5
legacyver/proto/type.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package proto
|
||||
|
||||
type legacyType struct {
|
||||
ProtocolID int32
|
||||
}
|
||||
215
legacyver/protocol.go
Normal file
215
legacyver/protocol.go
Normal file
@@ -0,0 +1,215 @@
|
||||
package legacyver
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/legacypacket"
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
var (
|
||||
packetPoolClient packet.Pool
|
||||
packetPoolServer packet.Pool
|
||||
)
|
||||
|
||||
func init() {
|
||||
packetPoolClient = packet.NewClientPool()
|
||||
packetPoolServer = packet.NewServerPool()
|
||||
|
||||
packetPoolServer[packet.IDItemStackResponse] = func() packet.Packet { return &legacypacket.ItemStackResponse{} }
|
||||
packetPoolServer[packet.IDResourcePacksInfo] = func() packet.Packet { return &legacypacket.ResourcePacksInfo{} }
|
||||
|
||||
packetPoolClient[packet.IDPlayerAuthInput] = func() packet.Packet { return &legacypacket.PlayerAuthInput{} }
|
||||
}
|
||||
|
||||
type Protocol struct {
|
||||
ver string
|
||||
id int32
|
||||
|
||||
blockTranslator BlockTranslator
|
||||
itemTranslator ItemTranslator
|
||||
}
|
||||
|
||||
func (p *Protocol) Ver() string {
|
||||
return p.ver
|
||||
}
|
||||
|
||||
func (p *Protocol) ID() int32 {
|
||||
return p.id
|
||||
}
|
||||
|
||||
func (p *Protocol) Packets(listener bool) packet.Pool {
|
||||
if listener {
|
||||
return packetPoolClient
|
||||
}
|
||||
return packetPoolServer
|
||||
}
|
||||
|
||||
func (p *Protocol) NewReader(r minecraft.ByteReader, shieldID int32, enableLimits bool) protocol.IO {
|
||||
return proto.NewReader(protocol.NewReader(r, shieldID, enableLimits), p.id)
|
||||
}
|
||||
|
||||
func (p *Protocol) NewWriter(w minecraft.ByteWriter, shieldID int32) protocol.IO {
|
||||
return proto.NewWriter(protocol.NewWriter(w, shieldID), p.id)
|
||||
}
|
||||
|
||||
func (p *Protocol) ConvertToLatest(pk packet.Packet, conn *minecraft.Conn) []packet.Packet {
|
||||
return p.blockTranslator.UpgradeBlockPackets(
|
||||
p.itemTranslator.UpgradeItemPackets(p.upgradePackets([]packet.Packet{pk}, conn), conn),
|
||||
conn)
|
||||
}
|
||||
|
||||
func (p *Protocol) ConvertFromLatest(pk packet.Packet, conn *minecraft.Conn) []packet.Packet {
|
||||
return p.downgradePackets(p.blockTranslator.DowngradeBlockPackets(
|
||||
p.itemTranslator.DowngradeItemPackets([]packet.Packet{pk}, conn),
|
||||
conn), conn)
|
||||
}
|
||||
|
||||
func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) []packet.Packet {
|
||||
for pkIndex, pk := range pks {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.StartGame:
|
||||
pk.GameVersion = p.ver
|
||||
pk.BaseGameVersion = p.ver
|
||||
case *packet.PlayerAuthInput:
|
||||
inputData := pk.InputData
|
||||
if p.ID() < proto.ID766 {
|
||||
inputData = fitBitset(inputData, 64)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.PlayerAuthInput{
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
Position: pk.Position,
|
||||
MoveVector: pk.MoveVector,
|
||||
HeadYaw: pk.HeadYaw,
|
||||
InputData: inputData,
|
||||
InputMode: pk.InputMode,
|
||||
PlayMode: pk.PlayMode,
|
||||
InteractionModel: pk.InteractionModel,
|
||||
InteractPitch: pk.InteractPitch,
|
||||
InteractYaw: pk.InteractYaw,
|
||||
Tick: pk.Tick,
|
||||
Delta: pk.Delta,
|
||||
ItemInteractionData: pk.ItemInteractionData,
|
||||
ItemStackRequest: pk.ItemStackRequest,
|
||||
BlockActions: pk.BlockActions,
|
||||
VehicleRotation: pk.VehicleRotation,
|
||||
ClientPredictedVehicle: pk.ClientPredictedVehicle,
|
||||
AnalogueMoveVector: pk.AnalogueMoveVector,
|
||||
CameraOrientation: pk.CameraOrientation,
|
||||
RawMoveVector: pk.RawMoveVector,
|
||||
}
|
||||
case *packet.ItemStackResponse:
|
||||
responses := make([]proto.ItemStackResponse, len(pk.Responses))
|
||||
for i, r := range pk.Responses {
|
||||
containerInfo := make([]proto.StackResponseContainerInfo, len(r.ContainerInfo))
|
||||
for j, c := range r.ContainerInfo {
|
||||
slotInfo := make([]proto.StackResponseSlotInfo, len(c.SlotInfo))
|
||||
for k, s := range c.SlotInfo {
|
||||
slotInfo[k] = proto.StackResponseSlotInfo{
|
||||
Slot: s.Slot,
|
||||
HotbarSlot: s.HotbarSlot,
|
||||
Count: s.Count,
|
||||
StackNetworkID: s.StackNetworkID,
|
||||
CustomName: s.CustomName,
|
||||
FilteredCustomName: s.FilteredCustomName,
|
||||
DurabilityCorrection: s.DurabilityCorrection,
|
||||
}
|
||||
}
|
||||
containerInfo[j] = proto.StackResponseContainerInfo{
|
||||
Container: c.Container,
|
||||
SlotInfo: slotInfo,
|
||||
}
|
||||
}
|
||||
|
||||
responses[i] = proto.ItemStackResponse{
|
||||
Status: r.Status,
|
||||
RequestID: r.RequestID,
|
||||
ContainerInfo: containerInfo,
|
||||
}
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.ItemStackResponse{Responses: responses}
|
||||
case *packet.ResourcePacksInfo:
|
||||
texturePacks := make([]proto.TexturePackInfo, len(pk.TexturePacks))
|
||||
for i, t := range pk.TexturePacks {
|
||||
texturePacks[i] = proto.TexturePackInfo{
|
||||
UUID: t.UUID,
|
||||
Version: t.Version,
|
||||
Size: t.Size,
|
||||
ContentKey: t.ContentKey,
|
||||
SubPackName: t.SubPackName,
|
||||
ContentIdentity: t.ContentIdentity,
|
||||
HasScripts: t.HasScripts,
|
||||
AddonPack: t.AddonPack,
|
||||
RTXEnabled: t.RTXEnabled,
|
||||
DownloadURL: t.DownloadURL,
|
||||
}
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.ResourcePacksInfo{
|
||||
TexturePackRequired: pk.TexturePackRequired,
|
||||
HasAddons: pk.HasAddons,
|
||||
HasScripts: pk.HasScripts,
|
||||
WorldTemplateUUID: pk.WorldTemplateUUID,
|
||||
WorldTemplateVersion: pk.WorldTemplateVersion,
|
||||
TexturePacks: texturePacks,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pks
|
||||
}
|
||||
|
||||
func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []packet.Packet {
|
||||
for pkIndex, pk := range pks {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.StartGame:
|
||||
pk.GameVersion = p.ver
|
||||
pk.BaseGameVersion = p.ver
|
||||
case *legacypacket.PlayerAuthInput:
|
||||
pks[pkIndex] = &packet.PlayerAuthInput{
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
Position: pk.Position,
|
||||
MoveVector: pk.MoveVector,
|
||||
HeadYaw: pk.HeadYaw,
|
||||
InputData: fitBitset(pk.InputData, packet.PlayerAuthInputBitsetSize),
|
||||
InputMode: pk.InputMode,
|
||||
PlayMode: pk.PlayMode,
|
||||
InteractionModel: pk.InteractionModel,
|
||||
InteractPitch: pk.InteractPitch,
|
||||
InteractYaw: pk.InteractYaw,
|
||||
Tick: pk.Tick,
|
||||
Delta: pk.Delta,
|
||||
ItemInteractionData: pk.ItemInteractionData,
|
||||
ItemStackRequest: pk.ItemStackRequest,
|
||||
BlockActions: pk.BlockActions,
|
||||
VehicleRotation: pk.VehicleRotation,
|
||||
ClientPredictedVehicle: pk.ClientPredictedVehicle,
|
||||
AnalogueMoveVector: pk.AnalogueMoveVector,
|
||||
CameraOrientation: pk.CameraOrientation,
|
||||
RawMoveVector: pk.RawMoveVector,
|
||||
}
|
||||
case *legacypacket.ItemStackResponse:
|
||||
responses := make([]protocol.ItemStackResponse, len(pk.Responses))
|
||||
for i, r := range pk.Responses {
|
||||
responses[i] = r.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.ItemStackResponse{Responses: responses}
|
||||
case *legacypacket.ResourcePacksInfo:
|
||||
texturePacks := make([]protocol.TexturePackInfo, len(pk.TexturePacks))
|
||||
for i, t := range pk.TexturePacks {
|
||||
texturePacks[i] = t.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.ResourcePacksInfo{
|
||||
TexturePackRequired: pk.TexturePackRequired,
|
||||
HasAddons: pk.HasAddons,
|
||||
HasScripts: pk.HasScripts,
|
||||
WorldTemplateUUID: pk.WorldTemplateUUID,
|
||||
WorldTemplateVersion: pk.WorldTemplateVersion,
|
||||
TexturePacks: texturePacks,
|
||||
}
|
||||
}
|
||||
}
|
||||
return pks
|
||||
}
|
||||
6998
legacyver/required_item_list_748.json
Normal file
6998
legacyver/required_item_list_748.json
Normal file
File diff suppressed because it is too large
Load Diff
7158
legacyver/required_item_list_766.json
Normal file
7158
legacyver/required_item_list_766.json
Normal file
File diff suppressed because it is too large
Load Diff
36
legacyver/v748.go
Normal file
36
legacyver/v748.go
Normal file
@@ -0,0 +1,36 @@
|
||||
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 (
|
||||
// ItemVersion748 ...
|
||||
ItemVersion748 = 221
|
||||
// BlockVersion748 ...
|
||||
BlockVersion748 int32 = (1 << 24) | (21 << 16) | (40 << 8)
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed item_runtime_ids_748.nbt
|
||||
itemRuntimeIDData748 []byte
|
||||
//go:embed required_item_list_748.json
|
||||
requiredItemList748 []byte
|
||||
//go:embed block_states_748.nbt
|
||||
blockStateData748 []byte
|
||||
)
|
||||
|
||||
func New748(direct bool) *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData748, requiredItemList748, ItemVersion748, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData748)
|
||||
|
||||
return &Protocol{
|
||||
ver: "1.21.40",
|
||||
id: proto.ID748,
|
||||
blockTranslator: NewBlockTranslator(blockMapping, latestBlockMapping, chunk.NewNetworkPersistentEncoding(blockMapping, BlockVersion748), chunk.NewBlockPaletteEncoding(blockMapping, BlockVersion748), false),
|
||||
itemTranslator: NewItemTranslator(itemMapping, itemMappingLatest, blockMapping, blockMappingLatest),
|
||||
}
|
||||
}
|
||||
25
legacyver/v766.go
Normal file
25
legacyver/v766.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package legacyver
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"github.com/akmalfairuz/legacy-version/mapping"
|
||||
)
|
||||
|
||||
const (
|
||||
// ItemVersion766 ...
|
||||
ItemVersion766 = 231
|
||||
// BlockVersion766 ...
|
||||
BlockVersion766 int32 = (1 << 24) | (21 << 16) | (50 << 8)
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed item_runtime_ids_766.nbt
|
||||
itemRuntimeIDData766 []byte
|
||||
//go:embed required_item_list_766.json
|
||||
requiredItemList766 []byte
|
||||
//go:embed block_states_766.nbt
|
||||
blockStateData766 []byte
|
||||
|
||||
itemMappingLatest = mapping.NewItemMapping(itemRuntimeIDData766, requiredItemList766, ItemVersion766, false)
|
||||
blockMappingLatest = mapping.NewBlockMapping(blockStateData766)
|
||||
)
|
||||
Reference in New Issue
Block a user