1.20.80 support (#1)
This commit is contained in:
@@ -11,7 +11,7 @@ A gophertunnel protocol interface implementation to support older Minecraft Bedr
|
||||
| 712 | 1.21.20 | ✅ |
|
||||
| 686 | 1.21.2 | ✅ |
|
||||
| 685 | 1.21.0 | ✅ |
|
||||
| 671 | 1.20.80 | 🚧 |
|
||||
| 671 | 1.20.80 | ✅ |
|
||||
| 662 | 1.20.70 | 🚧 |
|
||||
| 649 | 1.20.60 | 🚧 |
|
||||
| 630 | 1.20.50 | 🚧 |
|
||||
|
||||
@@ -28,11 +28,12 @@ func main() {
|
||||
listener, err := minecraft.ListenConfig{
|
||||
StatusProvider: p,
|
||||
AcceptedProtocols: []minecraft.Protocol{
|
||||
legacyver.New748(false),
|
||||
legacyver.New729(false),
|
||||
legacyver.New712(false),
|
||||
legacyver.New686(false),
|
||||
legacyver.New685(false),
|
||||
legacyver.New748(),
|
||||
legacyver.New729(),
|
||||
legacyver.New712(),
|
||||
legacyver.New686(),
|
||||
legacyver.New685(),
|
||||
legacyver.New671(),
|
||||
},
|
||||
}.Listen("raknet", config.Connection.LocalAddress)
|
||||
if err != nil {
|
||||
BIN
legacyver/data/block_states_671.nbt
Normal file
BIN
legacyver/data/block_states_671.nbt
Normal file
Binary file not shown.
BIN
legacyver/data/item_runtime_ids_671.nbt
Normal file
BIN
legacyver/data/item_runtime_ids_671.nbt
Normal file
Binary file not shown.
6274
legacyver/data/required_item_list_671.json
Normal file
6274
legacyver/data/required_item_list_671.json
Normal file
File diff suppressed because it is too large
Load Diff
32
legacyver/legacypacket/code_builder_source.go
Normal file
32
legacyver/legacypacket/code_builder_source.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// CodeBuilderSource is an Education Edition packet sent by the client to the server to run an operation with a
|
||||
// code builder.
|
||||
type CodeBuilderSource struct {
|
||||
// Operation is used to distinguish the operation performed. It is always one of the constants listed above.
|
||||
Operation byte
|
||||
// Category is used to distinguish the category of the operation performed. It is always one of the constants
|
||||
// listed above.
|
||||
Category byte
|
||||
// CodeStatus is the status of the code builder. It is always one of the constants listed above.
|
||||
CodeStatus byte
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (pk *CodeBuilderSource) ID() uint32 {
|
||||
return packet.IDCodeBuilderSource
|
||||
}
|
||||
|
||||
func (pk *CodeBuilderSource) Marshal(io protocol.IO) {
|
||||
io.Uint8(&pk.Operation)
|
||||
io.Uint8(&pk.Category)
|
||||
if proto.IsProtoGTE(io, proto.ID685) {
|
||||
io.Uint8(&pk.CodeStatus)
|
||||
}
|
||||
}
|
||||
35
legacyver/legacypacket/container_close.go
Normal file
35
legacyver/legacypacket/container_close.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// ContainerClose is sent by the server to close a container the player currently has opened, which was opened
|
||||
// using the ContainerOpen packet, or by the client to tell the server it closed a particular container, such
|
||||
// as the crafting grid.
|
||||
type ContainerClose struct {
|
||||
// WindowID is the ID representing the window of the container that should be closed. It must be equal to
|
||||
// the one sent in the ContainerOpen packet to close the designated window.
|
||||
WindowID byte
|
||||
// ContainerType is the type of container that the server is trying to close. This is used to validate on
|
||||
// the client side whether or not the server's close request is valid.
|
||||
ContainerType byte
|
||||
// ServerSide determines whether or not the container was force-closed by the server. If this value is
|
||||
// not set correctly, the client may ignore the packet and respond with a PacketViolationWarning.
|
||||
ServerSide bool
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*ContainerClose) ID() uint32 {
|
||||
return packet.IDContainerClose
|
||||
}
|
||||
|
||||
func (pk *ContainerClose) Marshal(io protocol.IO) {
|
||||
io.Uint8(&pk.WindowID)
|
||||
if proto.IsProtoGTE(io, proto.ID685) {
|
||||
io.Uint8(&pk.ContainerType)
|
||||
}
|
||||
io.Bool(&pk.ServerSide)
|
||||
}
|
||||
42
legacyver/legacypacket/crafting_data.go
Normal file
42
legacyver/legacypacket/crafting_data.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// CraftingData is sent by the server to let the client know all crafting data that the server maintains. This
|
||||
// includes shapeless crafting, crafting table recipes, furnace recipes etc. Each crafting station's recipes
|
||||
// are included in it.
|
||||
type CraftingData struct {
|
||||
// Recipes is a list of all recipes available on the server. It includes among others shapeless, shaped
|
||||
// and furnace recipes. The client will only be able to craft these recipes.
|
||||
Recipes []proto.Recipe
|
||||
// PotionRecipes is a list of all potion mixing recipes which may be used in the brewing stand.
|
||||
PotionRecipes []protocol.PotionRecipe
|
||||
// PotionContainerChangeRecipes is a list of all recipes to convert a potion from one type to another,
|
||||
// such as from a drinkable potion to a splash potion, or from a splash potion to a lingering potion.
|
||||
PotionContainerChangeRecipes []protocol.PotionContainerChangeRecipe
|
||||
// MaterialReducers is a list of all material reducers which is used in education edition chemistry.
|
||||
MaterialReducers []protocol.MaterialReducer
|
||||
// ClearRecipes indicates if all recipes currently active on the client should be cleaned. Doing this
|
||||
// means that the client will have no recipes active by itself: Any CraftingData packets previously sent
|
||||
// will also be discarded, and only the recipes in this CraftingData packet will be used.
|
||||
ClearRecipes bool
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*CraftingData) ID() uint32 {
|
||||
return packet.IDCraftingData
|
||||
}
|
||||
|
||||
func (pk *CraftingData) Marshal(io protocol.IO) {
|
||||
protocol.FuncSlice(io, &pk.Recipes, func(p *proto.Recipe) {
|
||||
proto.IORecipe(io, p)
|
||||
})
|
||||
protocol.Slice(io, &pk.PotionRecipes)
|
||||
protocol.Slice(io, &pk.PotionContainerChangeRecipes)
|
||||
protocol.FuncSlice(io, &pk.MaterialReducers, io.MaterialReducer)
|
||||
io.Bool(&pk.ClearRecipes)
|
||||
}
|
||||
329
legacyver/legacypacket/start_game.go
Normal file
329
legacyver/legacypacket/start_game.go
Normal file
@@ -0,0 +1,329 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// StartGame is sent by the server to send information about the world the player will be spawned in. It
|
||||
// contains information about the position the player spawns in, and information about the world in general
|
||||
// such as its game rules.
|
||||
type StartGame struct {
|
||||
// EntityUniqueID is the unique ID of the player. The unique ID is a value that remains consistent across
|
||||
// different sessions of the same world, but most servers simply fill the runtime ID of the entity out for
|
||||
// this field.
|
||||
EntityUniqueID int64
|
||||
// EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and
|
||||
// entities are generally identified in packets using this runtime ID.
|
||||
EntityRuntimeID uint64
|
||||
// PlayerGameMode is the game mode the player currently has. It is a value from 0-4, with 0 being
|
||||
// survival mode, 1 being creative mode, 2 being adventure mode, 3 being survival spectator and 4 being
|
||||
// creative spectator.
|
||||
// This field may be set to 5 to make the client fall back to the game mode set in the WorldGameMode
|
||||
// field.
|
||||
PlayerGameMode int32
|
||||
// PlayerPosition is the spawn position of the player in the world. In servers this is often the same as
|
||||
// the world's spawn position found below.
|
||||
PlayerPosition mgl32.Vec3
|
||||
// Pitch is the vertical rotation of the player. Facing straight forward yields a pitch of 0. Pitch is
|
||||
// measured in degrees.
|
||||
Pitch float32
|
||||
// Yaw is the horizontal rotation of the player. Yaw is also measured in degrees.
|
||||
Yaw float32
|
||||
// WorldSeed is the seed used to generate the world. Unlike in PC edition, the seed is a 32bit integer
|
||||
// here.
|
||||
WorldSeed int64
|
||||
// SpawnBiomeType specifies if the biome that the player spawns in is user defined (through behaviour
|
||||
// packs) or builtin. See the constants above.
|
||||
SpawnBiomeType int16
|
||||
// UserDefinedBiomeName is a readable name of the biome that the player spawned in, such as 'plains'. This
|
||||
// might be a custom biome name if any custom biomes are present through behaviour packs.
|
||||
UserDefinedBiomeName string
|
||||
// Dimension is the ID of the dimension that the player spawns in. It is a value from 0-2, with 0 being
|
||||
// the overworld, 1 being the nether and 2 being the end.
|
||||
Dimension int32
|
||||
// Generator is the generator used for the world. It is a value from 0-4, with 0 being old limited worlds,
|
||||
// 1 being infinite worlds, 2 being flat worlds, 3 being nether worlds and 4 being end worlds. A value of
|
||||
// 0 will actually make the client stop rendering chunks you send beyond the world limit.
|
||||
Generator int32
|
||||
// WorldGameMode is the game mode that a player gets when it first spawns in the world. It is shown in the
|
||||
// settings and is used if the PlayerGameMode is set to 5.
|
||||
WorldGameMode int32
|
||||
// Hardcore is if the world is in hardcore mode. In hardcore mode, the player cannot respawn after dying.
|
||||
Hardcore bool
|
||||
// Difficulty is the difficulty of the world. It is a value from 0-3, with 0 being peaceful, 1 being easy,
|
||||
// 2 being normal and 3 being hard.
|
||||
Difficulty int32
|
||||
// WorldSpawn is the block on which the world spawn of the world. This coordinate has no effect on the
|
||||
// place that the client spawns, but it does have an effect on the direction that a compass points.
|
||||
WorldSpawn protocol.BlockPos
|
||||
// AchievementsDisabled defines if achievements are disabled in the world. The client crashes if this
|
||||
// value is set to true while the player's or the world's game mode is creative, and it's recommended to
|
||||
// simply always set this to false as a server.
|
||||
AchievementsDisabled bool
|
||||
// EditorWorldType is a value to dictate the type of editor mode, a special mode recently introduced adding
|
||||
// "powerful tools for editing worlds, intended for experienced creators." It is one of the constants above.
|
||||
EditorWorldType int32
|
||||
// CreatedInEditor is a value to dictate if the world was created as a project in the editor mode. The functionality
|
||||
// of this field is currently unknown.
|
||||
CreatedInEditor bool
|
||||
// ExportedFromEditor is a value to dictate if the world was exported from editor mode. The functionality of this
|
||||
// field is currently unknown.
|
||||
ExportedFromEditor bool
|
||||
// DayCycleLockTime is the time at which the day cycle was locked if the day cycle is disabled using the
|
||||
// respective game rule. The client will maintain this time as long as the day cycle is disabled.
|
||||
DayCycleLockTime int32
|
||||
// EducationEditionOffer is some Minecraft: Education Edition field that specifies what 'region' the world
|
||||
// was from, with 0 being None, 1 being RestOfWorld, and 2 being China.
|
||||
// The actual use of this field is unknown.
|
||||
EducationEditionOffer int32
|
||||
// EducationFeaturesEnabled specifies if the world has education edition features enabled, such as the
|
||||
// blocks or entities specific to education edition.
|
||||
EducationFeaturesEnabled bool
|
||||
// EducationProductID is a UUID used to identify the education edition server instance. It is generally
|
||||
// unique for education edition servers.
|
||||
EducationProductID string
|
||||
// RainLevel is the level specifying the intensity of the rain falling. When set to 0, no rain falls at
|
||||
// all.
|
||||
RainLevel float32
|
||||
// LightningLevel is the level specifying the intensity of the thunder. This may actually be set
|
||||
// independently from the RainLevel, meaning dark clouds can be produced without rain.
|
||||
LightningLevel float32
|
||||
// ConfirmedPlatformLockedContent ...
|
||||
ConfirmedPlatformLockedContent bool
|
||||
// MultiPlayerGame specifies if the world is a multi-player game. This should always be set to true for
|
||||
// servers.
|
||||
MultiPlayerGame bool
|
||||
// LANBroadcastEnabled specifies if LAN broadcast was intended to be enabled for the world.
|
||||
LANBroadcastEnabled bool
|
||||
// XBLBroadcastMode is the mode used to broadcast the joined game across XBOX Live.
|
||||
XBLBroadcastMode int32
|
||||
// PlatformBroadcastMode is the mode used to broadcast the joined game across the platform.
|
||||
PlatformBroadcastMode int32
|
||||
// CommandsEnabled specifies if commands are enabled for the player. It is recommended to always set this
|
||||
// to true on the server, as setting it to false means the player cannot, under any circumstance, use a
|
||||
// command.
|
||||
CommandsEnabled bool
|
||||
// TexturePackRequired specifies if the texture pack the world might hold is required, meaning the client
|
||||
// was forced to download it before joining.
|
||||
TexturePackRequired bool
|
||||
// GameRules defines game rules currently active with their respective values. The value of these game
|
||||
// rules may be either 'bool', 'int32' or 'float32'. Some game rules are server side only, and don't
|
||||
// necessarily need to be sent to the client.
|
||||
GameRules []protocol.GameRule
|
||||
// Experiments holds a list of experiments that are either enabled or disabled in the world that the
|
||||
// player spawns in.
|
||||
Experiments []protocol.ExperimentData
|
||||
// ExperimentsPreviouslyToggled specifies if any experiments were previously toggled in this world. It is
|
||||
// probably used for some kind of metrics.
|
||||
ExperimentsPreviouslyToggled bool
|
||||
// BonusChestEnabled specifies if the world had the bonus map setting enabled when generating it. It does
|
||||
// not have any effect client-side.
|
||||
BonusChestEnabled bool
|
||||
// StartWithMapEnabled specifies if the world has the start with map setting enabled, meaning each joining
|
||||
// player obtains a map. This should always be set to false, because the client obtains a map all on its
|
||||
// own accord if this is set to true.
|
||||
StartWithMapEnabled bool
|
||||
// PlayerPermissions is the permission level of the player. It is a value from 0-3, with 0 being visitor,
|
||||
// 1 being member, 2 being operator and 3 being custom.
|
||||
PlayerPermissions int32
|
||||
// ServerChunkTickRadius is the radius around the player in which chunks are ticked. Most servers set this
|
||||
// value to a fixed number, as it does not necessarily affect anything client-side.
|
||||
ServerChunkTickRadius int32
|
||||
// HasLockedBehaviourPack specifies if the behaviour pack of the world is locked, meaning it cannot be
|
||||
// disabled from the world. This is typically set for worlds on the marketplace that have a dedicated
|
||||
// behaviour pack.
|
||||
HasLockedBehaviourPack bool
|
||||
// HasLockedTexturePack specifies if the texture pack of the world is locked, meaning it cannot be
|
||||
// disabled from the world. This is typically set for worlds on the marketplace that have a dedicated
|
||||
// texture pack.
|
||||
HasLockedTexturePack bool
|
||||
// FromLockedWorldTemplate specifies if the world from the server was from a locked world template. For
|
||||
// servers this should always be set to false.
|
||||
FromLockedWorldTemplate bool
|
||||
// MSAGamerTagsOnly ..
|
||||
MSAGamerTagsOnly bool
|
||||
// FromWorldTemplate specifies if the world from the server was from a world template. For servers this
|
||||
// should always be set to false.
|
||||
FromWorldTemplate bool
|
||||
// WorldTemplateSettingsLocked specifies if the world was a template that locks all settings that change
|
||||
// properties above in the settings GUI. It is recommended to set this to true for servers that do not
|
||||
// allow things such as setting game rules through the GUI.
|
||||
WorldTemplateSettingsLocked bool
|
||||
// OnlySpawnV1Villagers is a hack that Mojang put in place to preserve backwards compatibility with old
|
||||
// villagers. The bool is never actually read though, so it has no functionality.
|
||||
OnlySpawnV1Villagers bool
|
||||
// PersonaDisabled is true if persona skins are disabled for the current game session.
|
||||
PersonaDisabled bool
|
||||
// CustomSkinsDisabled is true if custom skins are disabled for the current game session.
|
||||
CustomSkinsDisabled bool
|
||||
// EmoteChatMuted specifies if players will be sent a chat message when using certain emotes.
|
||||
EmoteChatMuted bool
|
||||
// BaseGameVersion is the version of the game from which Vanilla features will be used. The exact function
|
||||
// of this field isn't clear.
|
||||
BaseGameVersion string
|
||||
// LimitedWorldWidth and LimitedWorldDepth are the dimensions of the world if the world is a limited
|
||||
// world. For unlimited worlds, these may simply be left as 0.
|
||||
LimitedWorldWidth, LimitedWorldDepth int32
|
||||
// NewNether specifies if the server runs with the new nether introduced in the 1.16 update.
|
||||
NewNether bool
|
||||
// EducationSharedResourceURI is an education edition feature that transmits education resource settings to clients.
|
||||
EducationSharedResourceURI protocol.EducationSharedResourceURI
|
||||
// ForceExperimentalGameplay specifies if experimental gameplay should be force enabled. For servers this
|
||||
// should always be set to false.
|
||||
ForceExperimentalGameplay protocol.Optional[bool]
|
||||
// LevelID is a base64 encoded world ID that is used to identify the world.
|
||||
LevelID string
|
||||
// WorldName is the name of the world that the player is joining. Note that this field shows up above the
|
||||
// player list for the rest of the game session, and cannot be changed. Setting the server name to this
|
||||
// field is recommended.
|
||||
WorldName string
|
||||
// TemplateContentIdentity is a UUID specific to the premium world template that might have been used to
|
||||
// generate the world. Servers should always fill out an empty string for this.
|
||||
TemplateContentIdentity string
|
||||
// Trial specifies if the world was a trial world, meaning features are limited and there is a time limit
|
||||
// on the world.
|
||||
Trial bool
|
||||
// PlayerMovementSettings ...
|
||||
PlayerMovementSettings protocol.PlayerMovementSettings
|
||||
// Time is the total time that has elapsed since the start of the world.
|
||||
Time int64
|
||||
// EnchantmentSeed is the seed used to seed the random used to produce enchantments in the enchantment
|
||||
// table. Note that the exact correct random implementation must be used to produce the correct results
|
||||
// both client- and server-side.
|
||||
EnchantmentSeed int32
|
||||
// Blocks is a list of all custom blocks registered on the server.
|
||||
Blocks []protocol.BlockEntry
|
||||
// Items is a list of all items with their legacy IDs which are available in the game. Failing to send any
|
||||
// of the items that are in the game will crash mobile clients.
|
||||
Items []protocol.ItemEntry
|
||||
// MultiPlayerCorrelationID is a unique ID specifying the multi-player session of the player. A random
|
||||
// UUID should be filled out for this field.
|
||||
MultiPlayerCorrelationID string
|
||||
// ServerAuthoritativeInventory specifies if the server authoritative inventory system is enabled. This
|
||||
// is a new system introduced in 1.16. Backwards compatibility with the inventory transactions has to
|
||||
// some extent been preserved, but will eventually be removed.
|
||||
ServerAuthoritativeInventory bool
|
||||
// GameVersion is the version of the game the server is running. The exact function of this field isn't clear.
|
||||
GameVersion string
|
||||
// PropertyData contains properties that should be applied on the player. These properties are the same as the
|
||||
// ones that are sent in the SyncActorProperty packet.
|
||||
PropertyData map[string]any
|
||||
// ServerBlockStateChecksum is a checksum to ensure block states between the server and client match.
|
||||
// This can simply be left empty, and the client will avoid trying to verify it.
|
||||
ServerBlockStateChecksum uint64
|
||||
// ClientSideGeneration is true if the client should use the features registered in the FeatureRegistry packet to
|
||||
// generate terrain client-side to save on bandwidth.
|
||||
ClientSideGeneration bool
|
||||
// WorldTemplateID is a UUID that identifies the template that was used to generate the world. Servers that do not
|
||||
// use a world based off of a template can set this to an empty UUID.
|
||||
WorldTemplateID uuid.UUID
|
||||
// ChatRestrictionLevel specifies the level of restriction on in-game chat. It is one of the constants above.
|
||||
ChatRestrictionLevel uint8
|
||||
// DisablePlayerInteractions is true if the client should ignore other players when interacting with the world.
|
||||
DisablePlayerInteractions bool
|
||||
// ServerID is always empty in vanilla and its usage is currently unknown.
|
||||
ServerID string
|
||||
// WorldID is always empty in vanilla and its usage is currently unknown.
|
||||
WorldID string
|
||||
// ScenarioID is always empty in vanilla and its usage is currently unknown.
|
||||
ScenarioID string
|
||||
// UseBlockNetworkIDHashes is true if the client should use the hash of a block's name as its network ID rather than
|
||||
// its index in the expected block palette. This is useful for servers that wish to support multiple protocol versions
|
||||
// and custom blocks, but it will result in extra bytes being written for every block in a sub chunk palette.
|
||||
UseBlockNetworkIDHashes bool
|
||||
// ServerAuthoritativeSound is currently unknown as to what it does.
|
||||
ServerAuthoritativeSound bool
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*StartGame) ID() uint32 {
|
||||
return packet.IDStartGame
|
||||
}
|
||||
|
||||
func (pk *StartGame) Marshal(io protocol.IO) {
|
||||
io.Varint64(&pk.EntityUniqueID)
|
||||
io.Varuint64(&pk.EntityRuntimeID)
|
||||
io.Varint32(&pk.PlayerGameMode)
|
||||
io.Vec3(&pk.PlayerPosition)
|
||||
io.Float32(&pk.Pitch)
|
||||
io.Float32(&pk.Yaw)
|
||||
io.Int64(&pk.WorldSeed)
|
||||
io.Int16(&pk.SpawnBiomeType)
|
||||
io.String(&pk.UserDefinedBiomeName)
|
||||
io.Varint32(&pk.Dimension)
|
||||
io.Varint32(&pk.Generator)
|
||||
io.Varint32(&pk.WorldGameMode)
|
||||
io.Bool(&pk.Hardcore)
|
||||
io.Varint32(&pk.Difficulty)
|
||||
io.UBlockPos(&pk.WorldSpawn)
|
||||
io.Bool(&pk.AchievementsDisabled)
|
||||
io.Varint32(&pk.EditorWorldType)
|
||||
io.Bool(&pk.CreatedInEditor)
|
||||
io.Bool(&pk.ExportedFromEditor)
|
||||
io.Varint32(&pk.DayCycleLockTime)
|
||||
io.Varint32(&pk.EducationEditionOffer)
|
||||
io.Bool(&pk.EducationFeaturesEnabled)
|
||||
io.String(&pk.EducationProductID)
|
||||
io.Float32(&pk.RainLevel)
|
||||
io.Float32(&pk.LightningLevel)
|
||||
io.Bool(&pk.ConfirmedPlatformLockedContent)
|
||||
io.Bool(&pk.MultiPlayerGame)
|
||||
io.Bool(&pk.LANBroadcastEnabled)
|
||||
io.Varint32(&pk.XBLBroadcastMode)
|
||||
io.Varint32(&pk.PlatformBroadcastMode)
|
||||
io.Bool(&pk.CommandsEnabled)
|
||||
io.Bool(&pk.TexturePackRequired)
|
||||
protocol.FuncSlice(io, &pk.GameRules, io.GameRule)
|
||||
protocol.SliceUint32Length(io, &pk.Experiments)
|
||||
io.Bool(&pk.ExperimentsPreviouslyToggled)
|
||||
io.Bool(&pk.BonusChestEnabled)
|
||||
io.Bool(&pk.StartWithMapEnabled)
|
||||
io.Varint32(&pk.PlayerPermissions)
|
||||
io.Int32(&pk.ServerChunkTickRadius)
|
||||
io.Bool(&pk.HasLockedBehaviourPack)
|
||||
io.Bool(&pk.HasLockedTexturePack)
|
||||
io.Bool(&pk.FromLockedWorldTemplate)
|
||||
io.Bool(&pk.MSAGamerTagsOnly)
|
||||
io.Bool(&pk.FromWorldTemplate)
|
||||
io.Bool(&pk.WorldTemplateSettingsLocked)
|
||||
io.Bool(&pk.OnlySpawnV1Villagers)
|
||||
io.Bool(&pk.PersonaDisabled)
|
||||
io.Bool(&pk.CustomSkinsDisabled)
|
||||
io.Bool(&pk.EmoteChatMuted)
|
||||
io.String(&pk.BaseGameVersion)
|
||||
io.Int32(&pk.LimitedWorldWidth)
|
||||
io.Int32(&pk.LimitedWorldDepth)
|
||||
io.Bool(&pk.NewNether)
|
||||
protocol.Single(io, &pk.EducationSharedResourceURI)
|
||||
protocol.OptionalFunc(io, &pk.ForceExperimentalGameplay, io.Bool)
|
||||
io.Uint8(&pk.ChatRestrictionLevel)
|
||||
io.Bool(&pk.DisablePlayerInteractions)
|
||||
if proto.IsProtoGTE(io, proto.ID685) {
|
||||
io.String(&pk.ServerID)
|
||||
io.String(&pk.WorldID)
|
||||
io.String(&pk.ScenarioID)
|
||||
}
|
||||
io.String(&pk.LevelID)
|
||||
io.String(&pk.WorldName)
|
||||
io.String(&pk.TemplateContentIdentity)
|
||||
io.Bool(&pk.Trial)
|
||||
protocol.PlayerMoveSettings(io, &pk.PlayerMovementSettings)
|
||||
io.Int64(&pk.Time)
|
||||
io.Varint32(&pk.EnchantmentSeed)
|
||||
protocol.Slice(io, &pk.Blocks)
|
||||
protocol.Slice(io, &pk.Items)
|
||||
io.String(&pk.MultiPlayerCorrelationID)
|
||||
io.Bool(&pk.ServerAuthoritativeInventory)
|
||||
io.String(&pk.GameVersion)
|
||||
io.NBT(&pk.PropertyData, nbt.NetworkLittleEndian)
|
||||
io.Uint64(&pk.ServerBlockStateChecksum)
|
||||
io.UUID(&pk.WorldTemplateID)
|
||||
io.Bool(&pk.ClientSideGeneration)
|
||||
io.Bool(&pk.UseBlockNetworkIDHashes)
|
||||
io.Bool(&pk.ServerAuthoritativeSound)
|
||||
}
|
||||
79
legacyver/legacypacket/text.go
Normal file
79
legacyver/legacypacket/text.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
const (
|
||||
TextTypeRaw = iota
|
||||
TextTypeChat
|
||||
TextTypeTranslation
|
||||
TextTypePopup
|
||||
TextTypeJukeboxPopup
|
||||
TextTypeTip
|
||||
TextTypeSystem
|
||||
TextTypeWhisper
|
||||
TextTypeAnnouncement
|
||||
TextTypeObjectWhisper
|
||||
TextTypeObject
|
||||
TextTypeObjectAnnouncement
|
||||
)
|
||||
|
||||
// Text is sent by the client to the server to send chat messages, and by the server to the client to forward
|
||||
// or send messages, which may be chat, popups, tips etc.
|
||||
type Text struct {
|
||||
// TextType is the type of the text sent. When a client sends this to the server, it should always be
|
||||
// TextTypeChat. If the server sends it, it may be one of the other text types above.
|
||||
TextType byte
|
||||
// NeedsTranslation specifies if any of the messages need to be translated. It seems that where % is found
|
||||
// in translatable text types, these are translated regardless of this bool. Translatable text types
|
||||
// include TextTypeTranslation, TextTypeTip, TextTypePopup and TextTypeJukeboxPopup.
|
||||
NeedsTranslation bool
|
||||
// SourceName is the name of the source of the messages. This source is displayed in text types such as
|
||||
// the TextTypeChat and TextTypeWhisper, where typically the username is shown.
|
||||
SourceName string
|
||||
// Message is the message of the packet. This field is set for each TextType and is the main component of
|
||||
// the packet.
|
||||
Message string
|
||||
// Parameters is a list of parameters that should be filled into the message. These parameters are only
|
||||
// written if the type of the packet is TextTypeTranslation, TextTypeTip, TextTypePopup or TextTypeJukeboxPopup.
|
||||
Parameters []string
|
||||
// XUID is the XBOX Live user ID of the player that sent the message. It is only set for packets of
|
||||
// TextTypeChat. When sent to a player, the player will only be shown the chat message if a player with
|
||||
// this XUID is present in the player list and not muted, or if the XUID is empty.
|
||||
XUID string
|
||||
// PlatformChatID is an identifier only set for particular platforms when chatting (presumably only for
|
||||
// Nintendo Switch). It is otherwise an empty string, and is used to decide which players are able to
|
||||
// chat with each other.
|
||||
PlatformChatID string
|
||||
// FilteredMessage is a filtered version of Message with all the profanity removed. The client will use
|
||||
// this over Message if this field is not empty and they have the "Filter Profanity" setting enabled.
|
||||
FilteredMessage string
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*Text) ID() uint32 {
|
||||
return packet.IDText
|
||||
}
|
||||
|
||||
func (pk *Text) Marshal(io protocol.IO) {
|
||||
io.Uint8(&pk.TextType)
|
||||
io.Bool(&pk.NeedsTranslation)
|
||||
switch pk.TextType {
|
||||
case TextTypeChat, TextTypeWhisper, TextTypeAnnouncement:
|
||||
io.String(&pk.SourceName)
|
||||
io.String(&pk.Message)
|
||||
case TextTypeRaw, TextTypeTip, TextTypeSystem, TextTypeObject, TextTypeObjectWhisper, TextTypeObjectAnnouncement:
|
||||
io.String(&pk.Message)
|
||||
case TextTypeTranslation, TextTypePopup, TextTypeJukeboxPopup:
|
||||
io.String(&pk.Message)
|
||||
protocol.FuncSlice(io, &pk.Parameters, io.String)
|
||||
}
|
||||
io.String(&pk.XUID)
|
||||
io.String(&pk.PlatformChatID)
|
||||
if proto.IsProtoGTE(io, proto.ID685) {
|
||||
io.String(&pk.FilteredMessage)
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ const (
|
||||
ID712 = 712 // v1.21.20
|
||||
ID686 = 686 // v1.21.2
|
||||
ID685 = 685 // v1.21.0
|
||||
ID671 = 671 // v1.20.80
|
||||
)
|
||||
|
||||
func IsProtoGTE(io protocol.IO, proto int32) bool {
|
||||
|
||||
@@ -112,3 +112,22 @@ func IOStackRequestAction(io protocol.IO, x *protocol.StackRequestAction) {
|
||||
}
|
||||
(*x).Marshal(io)
|
||||
}
|
||||
|
||||
func IORecipe(io protocol.IO, recipe *Recipe) {
|
||||
if IsReader(io) {
|
||||
var recipeType int32
|
||||
io.Varint32(&recipeType)
|
||||
if !lookupRecipe(recipeType, recipe) {
|
||||
io.UnknownEnumOption(recipeType, "crafting data recipe type")
|
||||
return
|
||||
}
|
||||
(*recipe).Unmarshal(io.(*Reader))
|
||||
} else {
|
||||
var recipeType int32
|
||||
if !lookupRecipeType(*recipe, &recipeType) {
|
||||
io.UnknownEnumOption(fmt.Sprintf("%T", *recipe), "crafting recipe type")
|
||||
}
|
||||
io.Varint32(&recipeType)
|
||||
(*recipe).Marshal(io.(*Writer))
|
||||
}
|
||||
}
|
||||
|
||||
699
legacyver/proto/recipe.go
Normal file
699
legacyver/proto/recipe.go
Normal file
@@ -0,0 +1,699 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
RecipeUnlockContextNone = iota
|
||||
RecipeUnlockContextAlwaysUnlocked
|
||||
RecipeUnlockContextPlayerInWater
|
||||
RecipeUnlockContextPlayerHasManyItems
|
||||
)
|
||||
|
||||
// RecipeUnlockRequirement represents a requirement that must be met in order to unlock a recipe. This is used
|
||||
// for both shaped and shapeless recipes.
|
||||
type RecipeUnlockRequirement struct {
|
||||
// Context is the context in which the recipe is unlocked. This is one of the constants above.
|
||||
Context byte
|
||||
// Ingredients are the ingredients required to unlock the recipe and only used if Context is set to none.
|
||||
Ingredients []protocol.ItemDescriptorCount
|
||||
}
|
||||
|
||||
func (x *RecipeUnlockRequirement) FromLatest(requirement protocol.RecipeUnlockRequirement) RecipeUnlockRequirement {
|
||||
x.Context = requirement.Context
|
||||
x.Ingredients = requirement.Ingredients
|
||||
return *x
|
||||
}
|
||||
|
||||
func (x *RecipeUnlockRequirement) ToLatest() protocol.RecipeUnlockRequirement {
|
||||
return protocol.RecipeUnlockRequirement{
|
||||
Context: x.Context,
|
||||
Ingredients: x.Ingredients,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (x *RecipeUnlockRequirement) Marshal(r protocol.IO) {
|
||||
r.Uint8(&x.Context)
|
||||
if x.Context == RecipeUnlockContextNone {
|
||||
protocol.FuncSlice(r, &x.Ingredients, r.ItemDescriptorCount)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
RecipeShapeless int32 = iota
|
||||
RecipeShaped
|
||||
RecipeFurnace
|
||||
RecipeFurnaceData
|
||||
RecipeMulti
|
||||
RecipeShulkerBox
|
||||
RecipeShapelessChemistry
|
||||
RecipeShapedChemistry
|
||||
RecipeSmithingTransform
|
||||
RecipeSmithingTrim
|
||||
)
|
||||
|
||||
// Recipe represents a recipe that may be sent in a CraftingData packet to let the client know what recipes
|
||||
// are available server-side.
|
||||
type Recipe interface {
|
||||
// Marshal encodes the recipe data to its binary representation into buf.
|
||||
Marshal(w *Writer)
|
||||
// Unmarshal decodes a serialised recipe from Reader r into the recipe instance.
|
||||
Unmarshal(r *Reader)
|
||||
}
|
||||
|
||||
func takePtr[T any](x T) *T {
|
||||
return &x
|
||||
}
|
||||
|
||||
func RecipeToLatest(x Recipe) protocol.Recipe {
|
||||
switch x := x.(type) {
|
||||
case *ShapelessRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *ShulkerBoxRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *ShapelessChemistryRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *ShapedRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *ShapedChemistryRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *FurnaceRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *FurnaceDataRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *MultiRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *SmithingTransformRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
case *SmithingTrimRecipe:
|
||||
return takePtr(x.ToLatest())
|
||||
}
|
||||
panic("RecipeToLatest: unknown recipe type")
|
||||
}
|
||||
|
||||
func RecipeFromLatest(x protocol.Recipe) Recipe {
|
||||
switch x := x.(type) {
|
||||
case *protocol.ShapelessRecipe:
|
||||
return (&ShapelessRecipe{}).FromLatest(*x)
|
||||
case *protocol.ShulkerBoxRecipe:
|
||||
return (&ShulkerBoxRecipe{}).FromLatest(*x)
|
||||
case *protocol.ShapelessChemistryRecipe:
|
||||
return (&ShapelessChemistryRecipe{}).FromLatest(*x)
|
||||
case *protocol.ShapedRecipe:
|
||||
return (&ShapedRecipe{}).FromLatest(*x)
|
||||
case *protocol.ShapedChemistryRecipe:
|
||||
return (&ShapedChemistryRecipe{}).FromLatest(*x)
|
||||
case *protocol.FurnaceRecipe:
|
||||
return (&FurnaceRecipe{}).FromLatest(*x)
|
||||
case *protocol.FurnaceDataRecipe:
|
||||
return (&FurnaceDataRecipe{}).FromLatest(*x)
|
||||
case *protocol.MultiRecipe:
|
||||
return (&MultiRecipe{}).FromLatest(*x)
|
||||
case *protocol.SmithingTransformRecipe:
|
||||
return (&SmithingTransformRecipe{}).FromLatest(*x)
|
||||
case *protocol.SmithingTrimRecipe:
|
||||
return (&SmithingTrimRecipe{}).FromLatest(*x)
|
||||
}
|
||||
panic("RecipeFromLatest: unknown recipe type")
|
||||
}
|
||||
|
||||
// lookupRecipe looks up the Recipe for a recipe type. False is returned if not
|
||||
// found.
|
||||
func lookupRecipe(recipeType int32, x *Recipe) bool {
|
||||
switch recipeType {
|
||||
case RecipeShapeless:
|
||||
*x = &ShapelessRecipe{}
|
||||
case RecipeShaped:
|
||||
*x = &ShapedRecipe{}
|
||||
case RecipeFurnace:
|
||||
*x = &FurnaceRecipe{}
|
||||
case RecipeFurnaceData:
|
||||
*x = &FurnaceDataRecipe{}
|
||||
case RecipeMulti:
|
||||
*x = &MultiRecipe{}
|
||||
case RecipeShulkerBox:
|
||||
*x = &ShulkerBoxRecipe{}
|
||||
case RecipeShapelessChemistry:
|
||||
*x = &ShapelessChemistryRecipe{}
|
||||
case RecipeShapedChemistry:
|
||||
*x = &ShapedChemistryRecipe{}
|
||||
case RecipeSmithingTransform:
|
||||
*x = &SmithingTransformRecipe{}
|
||||
case RecipeSmithingTrim:
|
||||
*x = &SmithingTrimRecipe{}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// lookupRecipeType looks up the recipe type for a Recipe. False is returned if
|
||||
// none was found.
|
||||
func lookupRecipeType(x Recipe, recipeType *int32) bool {
|
||||
switch x.(type) {
|
||||
case *ShapelessRecipe:
|
||||
*recipeType = RecipeShapeless
|
||||
case *ShapedRecipe:
|
||||
*recipeType = RecipeShaped
|
||||
case *FurnaceRecipe:
|
||||
*recipeType = RecipeFurnace
|
||||
case *FurnaceDataRecipe:
|
||||
*recipeType = RecipeFurnaceData
|
||||
case *MultiRecipe:
|
||||
*recipeType = RecipeMulti
|
||||
case *ShulkerBoxRecipe:
|
||||
*recipeType = RecipeShulkerBox
|
||||
case *ShapelessChemistryRecipe:
|
||||
*recipeType = RecipeShapelessChemistry
|
||||
case *ShapedChemistryRecipe:
|
||||
*recipeType = RecipeShapedChemistry
|
||||
case *SmithingTransformRecipe:
|
||||
*recipeType = RecipeSmithingTransform
|
||||
case *SmithingTrimRecipe:
|
||||
*recipeType = RecipeSmithingTrim
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ShapelessRecipe is a recipe that has no particular shape. Its functionality is shared with the
|
||||
// RecipeShulkerBox and RecipeShapelessChemistry types.
|
||||
type ShapelessRecipe struct {
|
||||
// RecipeID is a unique ID of the recipe. This ID must be unique amongst all other types of recipes too,
|
||||
// but its functionality is not exactly known.
|
||||
RecipeID string
|
||||
// Input is a list of items that serve as the input of the shapeless recipe. These items are the items
|
||||
// required to craft the output.
|
||||
Input []protocol.ItemDescriptorCount
|
||||
// Output is a list of items that are created as a result of crafting the recipe.
|
||||
Output []protocol.ItemStack
|
||||
// UUID is a UUID identifying the recipe. Since the CraftingEvent packet no longer exists, this can always be empty.
|
||||
UUID uuid.UUID
|
||||
// Block is the block name that is required to craft the output of the recipe. The block is not prefixed
|
||||
// with 'minecraft:', so it will look like 'crafting_table' as an example.
|
||||
// The available blocks are:
|
||||
// - crafting_table
|
||||
// - cartography_table
|
||||
// - stonecutter
|
||||
// - furnace
|
||||
// - blast_furnace
|
||||
// - smoker
|
||||
// - campfire
|
||||
Block string
|
||||
// Priority ...
|
||||
Priority int32
|
||||
// UnlockRequirement is a requirement that must be met in order to unlock the recipe.
|
||||
UnlockRequirement RecipeUnlockRequirement
|
||||
// RecipeNetworkID is a unique ID used to identify the recipe over network. Each recipe must have a unique
|
||||
// network ID. Recommended is to just increment a variable for each unique recipe registered.
|
||||
// This field must never be 0.
|
||||
RecipeNetworkID uint32
|
||||
}
|
||||
|
||||
// ShulkerBoxRecipe is a shapeless recipe made specifically for shulker box crafting, so that they don't lose
|
||||
// their user data when dyeing a shulker box.
|
||||
type ShulkerBoxRecipe struct {
|
||||
ShapelessRecipe
|
||||
}
|
||||
|
||||
// ShapelessChemistryRecipe is a recipe specifically made for chemistry related features, which exist only in
|
||||
// the Education Edition. They function the same as shapeless recipes do.
|
||||
type ShapelessChemistryRecipe struct {
|
||||
ShapelessRecipe
|
||||
}
|
||||
|
||||
// ShapedRecipe is a recipe that has a specific shape that must be used to craft the output of the recipe.
|
||||
// Trying to craft the item in any other shape will not work. The ShapedRecipe is of the same structure as the
|
||||
// ShapedChemistryRecipe.
|
||||
type ShapedRecipe struct {
|
||||
// RecipeID is a unique ID of the recipe. This ID must be unique amongst all other types of recipes too,
|
||||
// but its functionality is not exactly known.
|
||||
RecipeID string
|
||||
// Width is the width of the recipe's shape.
|
||||
Width int32
|
||||
// Height is the height of the recipe's shape.
|
||||
Height int32
|
||||
// Input is a list of items that serve as the input of the shapeless recipe. These items are the items
|
||||
// required to craft the output. The amount of input items must be exactly equal to Width * Height.
|
||||
Input []protocol.ItemDescriptorCount
|
||||
// Output is a list of items that are created as a result of crafting the recipe.
|
||||
Output []protocol.ItemStack
|
||||
// UUID is a UUID identifying the recipe. Since the CraftingEvent packet no longer exists, this can always be empty.
|
||||
UUID uuid.UUID
|
||||
// Block is the block name that is required to craft the output of the recipe. The block is not prefixed
|
||||
// with 'minecraft:', so it will look like 'crafting_table' as an example.
|
||||
Block string
|
||||
// Priority ...
|
||||
Priority int32
|
||||
// AssumeSymmetry specifies if the recipe is symmetrical. If this is set to true, the recipe will be
|
||||
// mirrored along the diagonal axis. This means that the recipe will be the same if rotated 180 degrees.
|
||||
AssumeSymmetry bool
|
||||
// UnlockRequirement is a requirement that must be met in order to unlock the recipe.
|
||||
UnlockRequirement RecipeUnlockRequirement
|
||||
// RecipeNetworkID is a unique ID used to identify the recipe over network. Each recipe must have a unique
|
||||
// network ID. Recommended is to just increment a variable for each unique recipe registered.
|
||||
// This field must never be 0.
|
||||
RecipeNetworkID uint32
|
||||
}
|
||||
|
||||
// ShapedChemistryRecipe is a recipe specifically made for chemistry related features, which exist only in the
|
||||
// Education Edition. It functions the same as a normal ShapedRecipe.
|
||||
type ShapedChemistryRecipe struct {
|
||||
ShapedRecipe
|
||||
}
|
||||
|
||||
// FurnaceRecipe is a recipe that is specifically used for all kinds of furnaces. These recipes don't just
|
||||
// apply to furnaces, but also blast furnaces and smokers.
|
||||
type FurnaceRecipe struct {
|
||||
// InputType is the item type of the input item. The metadata value of the item is not used in the
|
||||
// FurnaceRecipe. Use FurnaceDataRecipe to allow an item with only one metadata value.
|
||||
InputType protocol.ItemType
|
||||
// Output is the item that is created as a result of smelting/cooking an item in the furnace.
|
||||
Output protocol.ItemStack
|
||||
// Block is the block name that is required to create the output of the recipe. The block is not prefixed
|
||||
// with 'minecraft:', so it will look like 'furnace' as an example.
|
||||
Block string
|
||||
}
|
||||
|
||||
// FurnaceDataRecipe is a recipe specifically used for furnace-type crafting stations. It is equal to
|
||||
// FurnaceRecipe, except it has an input item with a specific metadata value, instead of any metadata value.
|
||||
type FurnaceDataRecipe struct {
|
||||
FurnaceRecipe
|
||||
}
|
||||
|
||||
// MultiRecipe serves as an 'enable' switch for multi-shape recipes.
|
||||
type MultiRecipe struct {
|
||||
// UUID is a UUID identifying the recipe. Since the CraftingEvent packet no longer exists, this can always be empty.
|
||||
UUID uuid.UUID
|
||||
// RecipeNetworkID is a unique ID used to identify the recipe over network. Each recipe must have a unique
|
||||
// network ID. Recommended is to just increment a variable for each unique recipe registered.
|
||||
// This field must never be 0.
|
||||
RecipeNetworkID uint32
|
||||
}
|
||||
|
||||
// SmithingTransformRecipe is a recipe specifically used for smithing tables. It has three input items and adds them
|
||||
// together, resulting in a new item.
|
||||
type SmithingTransformRecipe struct {
|
||||
// RecipeNetworkID is a unique ID used to identify the recipe over network. Each recipe must have a unique
|
||||
// network ID. Recommended is to just increment a variable for each unique recipe registered.
|
||||
// This field must never be 0.
|
||||
RecipeNetworkID uint32
|
||||
// RecipeID is a unique ID of the recipe. This ID must be unique amongst all other types of recipes too,
|
||||
// but its functionality is not exactly known.
|
||||
RecipeID string
|
||||
// Template is the item that is used to shape the Base item based on the Addition being applied.
|
||||
Template protocol.ItemDescriptorCount
|
||||
// Base is the item that the Addition is being applied to in the smithing table.
|
||||
Base protocol.ItemDescriptorCount
|
||||
// Addition is the item that is being added to the Base item to result in a modified item.
|
||||
Addition protocol.ItemDescriptorCount
|
||||
// Result is the resulting item from the two items being added together.
|
||||
Result protocol.ItemStack
|
||||
// Block is the block name that is required to create the output of the recipe. The block is not prefixed with
|
||||
// 'minecraft:', so it will look like 'smithing_table' as an example.
|
||||
Block string
|
||||
}
|
||||
|
||||
// SmithingTrimRecipe is a recipe specifically used for applying armour trims to an armour piece inside a smithing table.
|
||||
type SmithingTrimRecipe struct {
|
||||
// RecipeNetworkID is a unique ID used to identify the recipe over network. Each recipe must have a unique
|
||||
// network ID. Recommended is to just increment a variable for each unique recipe registered.
|
||||
// This field must never be 0.
|
||||
RecipeNetworkID uint32
|
||||
// RecipeID is a unique ID of the recipe. This ID must be unique amongst all other types of recipes too,
|
||||
// but its functionality is not exactly known.
|
||||
RecipeID string
|
||||
// Template is the item that is used to shape the Base item based on the Addition being applied.
|
||||
Template protocol.ItemDescriptorCount
|
||||
// Base is the item that the Addition is being applied to in the smithing table.
|
||||
Base protocol.ItemDescriptorCount
|
||||
// Addition is the item that is being added to the Base item to result in a modified item.
|
||||
Addition protocol.ItemDescriptorCount
|
||||
// Block is the block name that is required to create the output of the recipe. The block is not prefixed with
|
||||
// 'minecraft:', so it will look like 'smithing_table' as an example.
|
||||
Block string
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *ShapelessRecipe) FromLatest(v protocol.ShapelessRecipe) *ShapelessRecipe {
|
||||
recipe.RecipeID = v.RecipeID
|
||||
recipe.Input = v.Input
|
||||
recipe.Output = v.Output
|
||||
recipe.UUID = v.UUID
|
||||
recipe.Block = v.Block
|
||||
recipe.Priority = v.Priority
|
||||
recipe.UnlockRequirement = (&RecipeUnlockRequirement{}).FromLatest(v.UnlockRequirement)
|
||||
recipe.RecipeNetworkID = v.RecipeNetworkID
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *ShapelessRecipe) ToLatest() protocol.ShapelessRecipe {
|
||||
return protocol.ShapelessRecipe{
|
||||
RecipeID: recipe.RecipeID,
|
||||
Input: recipe.Input,
|
||||
Output: recipe.Output,
|
||||
UUID: recipe.UUID,
|
||||
Block: recipe.Block,
|
||||
Priority: recipe.Priority,
|
||||
UnlockRequirement: recipe.UnlockRequirement.ToLatest(),
|
||||
RecipeNetworkID: recipe.RecipeNetworkID,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *ShapelessRecipe) Marshal(w *Writer) {
|
||||
marshalShapeless(w, recipe)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *ShapelessRecipe) Unmarshal(r *Reader) {
|
||||
marshalShapeless(r, recipe)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *ShulkerBoxRecipe) FromLatest(v protocol.ShulkerBoxRecipe) *ShulkerBoxRecipe {
|
||||
recipe.ShapelessRecipe = *(&ShapelessRecipe{}).FromLatest(v.ShapelessRecipe)
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *ShulkerBoxRecipe) ToLatest() protocol.ShulkerBoxRecipe {
|
||||
return protocol.ShulkerBoxRecipe{
|
||||
ShapelessRecipe: recipe.ShapelessRecipe.ToLatest(),
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *ShulkerBoxRecipe) Marshal(w *Writer) {
|
||||
marshalShapeless(w, &recipe.ShapelessRecipe)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *ShulkerBoxRecipe) Unmarshal(r *Reader) {
|
||||
marshalShapeless(r, &recipe.ShapelessRecipe)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *ShapelessChemistryRecipe) FromLatest(v protocol.ShapelessChemistryRecipe) *ShapelessChemistryRecipe {
|
||||
recipe.ShapelessRecipe = *(&ShapelessRecipe{}).FromLatest(v.ShapelessRecipe)
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *ShapelessChemistryRecipe) ToLatest() protocol.ShapelessChemistryRecipe {
|
||||
return protocol.ShapelessChemistryRecipe{
|
||||
ShapelessRecipe: recipe.ShapelessRecipe.ToLatest(),
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *ShapelessChemistryRecipe) Marshal(w *Writer) {
|
||||
marshalShapeless(w, &recipe.ShapelessRecipe)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *ShapelessChemistryRecipe) Unmarshal(r *Reader) {
|
||||
marshalShapeless(r, &recipe.ShapelessRecipe)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *ShapedRecipe) FromLatest(v protocol.ShapedRecipe) *ShapedRecipe {
|
||||
recipe.RecipeID = v.RecipeID
|
||||
recipe.Width = v.Width
|
||||
recipe.Height = v.Height
|
||||
recipe.Input = v.Input
|
||||
recipe.Output = v.Output
|
||||
recipe.UUID = v.UUID
|
||||
recipe.Block = v.Block
|
||||
recipe.AssumeSymmetry = v.AssumeSymmetry
|
||||
recipe.UnlockRequirement = (&RecipeUnlockRequirement{}).FromLatest(v.UnlockRequirement)
|
||||
recipe.Priority = v.Priority
|
||||
recipe.RecipeNetworkID = v.RecipeNetworkID
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *ShapedRecipe) ToLatest() protocol.ShapedRecipe {
|
||||
return protocol.ShapedRecipe{
|
||||
RecipeID: recipe.RecipeID,
|
||||
Width: recipe.Width,
|
||||
Height: recipe.Height,
|
||||
Input: recipe.Input,
|
||||
Output: recipe.Output,
|
||||
UUID: recipe.UUID,
|
||||
Block: recipe.Block,
|
||||
AssumeSymmetry: recipe.AssumeSymmetry,
|
||||
UnlockRequirement: recipe.UnlockRequirement.ToLatest(),
|
||||
Priority: recipe.Priority,
|
||||
RecipeNetworkID: recipe.RecipeNetworkID,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *ShapedRecipe) Marshal(w *Writer) {
|
||||
marshalShaped(w, recipe)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *ShapedRecipe) Unmarshal(r *Reader) {
|
||||
marshalShaped(r, recipe)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *ShapedChemistryRecipe) FromLatest(v protocol.ShapedChemistryRecipe) *ShapedChemistryRecipe {
|
||||
recipe.ShapedRecipe = *(&ShapedRecipe{}).FromLatest(v.ShapedRecipe)
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *ShapedChemistryRecipe) ToLatest() protocol.ShapedChemistryRecipe {
|
||||
return protocol.ShapedChemistryRecipe{
|
||||
ShapedRecipe: recipe.ShapedRecipe.ToLatest(),
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *ShapedChemistryRecipe) Marshal(w *Writer) {
|
||||
marshalShaped(w, &recipe.ShapedRecipe)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *ShapedChemistryRecipe) Unmarshal(r *Reader) {
|
||||
marshalShaped(r, &recipe.ShapedRecipe)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *FurnaceRecipe) FromLatest(v protocol.FurnaceRecipe) *FurnaceRecipe {
|
||||
recipe.InputType = v.InputType
|
||||
recipe.Output = v.Output
|
||||
recipe.Block = v.Block
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *FurnaceRecipe) ToLatest() protocol.FurnaceRecipe {
|
||||
return protocol.FurnaceRecipe{
|
||||
InputType: recipe.InputType,
|
||||
Output: recipe.Output,
|
||||
Block: recipe.Block,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *FurnaceRecipe) Marshal(w *Writer) {
|
||||
w.Varint32(&recipe.InputType.NetworkID)
|
||||
w.Item(&recipe.Output)
|
||||
w.String(&recipe.Block)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *FurnaceRecipe) Unmarshal(r *Reader) {
|
||||
r.Varint32(&recipe.InputType.NetworkID)
|
||||
r.Item(&recipe.Output)
|
||||
r.String(&recipe.Block)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *FurnaceDataRecipe) FromLatest(v protocol.FurnaceDataRecipe) *FurnaceDataRecipe {
|
||||
recipe.FurnaceRecipe = *(&FurnaceRecipe{}).FromLatest(v.FurnaceRecipe)
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *FurnaceDataRecipe) ToLatest() protocol.FurnaceDataRecipe {
|
||||
return protocol.FurnaceDataRecipe{
|
||||
FurnaceRecipe: recipe.FurnaceRecipe.ToLatest(),
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *FurnaceDataRecipe) Marshal(w *Writer) {
|
||||
w.Varint32(&recipe.InputType.NetworkID)
|
||||
aux := int32(recipe.InputType.MetadataValue)
|
||||
w.Varint32(&aux)
|
||||
w.Item(&recipe.Output)
|
||||
w.String(&recipe.Block)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *FurnaceDataRecipe) Unmarshal(r *Reader) {
|
||||
var dataValue int32
|
||||
r.Varint32(&recipe.InputType.NetworkID)
|
||||
r.Varint32(&dataValue)
|
||||
recipe.InputType.MetadataValue = uint32(dataValue)
|
||||
r.Item(&recipe.Output)
|
||||
r.String(&recipe.Block)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *MultiRecipe) FromLatest(v protocol.MultiRecipe) *MultiRecipe {
|
||||
recipe.UUID = v.UUID
|
||||
recipe.RecipeNetworkID = v.RecipeNetworkID
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *MultiRecipe) ToLatest() protocol.MultiRecipe {
|
||||
return protocol.MultiRecipe{
|
||||
UUID: recipe.UUID,
|
||||
RecipeNetworkID: recipe.RecipeNetworkID,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *MultiRecipe) Marshal(w *Writer) {
|
||||
w.UUID(&recipe.UUID)
|
||||
w.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *MultiRecipe) Unmarshal(r *Reader) {
|
||||
r.UUID(&recipe.UUID)
|
||||
r.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *SmithingTransformRecipe) FromLatest(v protocol.SmithingTransformRecipe) *SmithingTransformRecipe {
|
||||
recipe.RecipeNetworkID = v.RecipeNetworkID
|
||||
recipe.RecipeID = v.RecipeID
|
||||
recipe.Template = v.Template
|
||||
recipe.Base = v.Base
|
||||
recipe.Addition = v.Addition
|
||||
recipe.Result = v.Result
|
||||
recipe.Block = v.Block
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *SmithingTransformRecipe) ToLatest() protocol.SmithingTransformRecipe {
|
||||
return protocol.SmithingTransformRecipe{
|
||||
RecipeNetworkID: recipe.RecipeNetworkID,
|
||||
RecipeID: recipe.RecipeID,
|
||||
Template: recipe.Template,
|
||||
Base: recipe.Base,
|
||||
Addition: recipe.Addition,
|
||||
Result: recipe.Result,
|
||||
Block: recipe.Block,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *SmithingTransformRecipe) Marshal(w *Writer) {
|
||||
w.String(&recipe.RecipeID)
|
||||
w.ItemDescriptorCount(&recipe.Template)
|
||||
w.ItemDescriptorCount(&recipe.Base)
|
||||
w.ItemDescriptorCount(&recipe.Addition)
|
||||
w.Item(&recipe.Result)
|
||||
w.String(&recipe.Block)
|
||||
w.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *SmithingTransformRecipe) Unmarshal(r *Reader) {
|
||||
r.String(&recipe.RecipeID)
|
||||
r.ItemDescriptorCount(&recipe.Template)
|
||||
r.ItemDescriptorCount(&recipe.Base)
|
||||
r.ItemDescriptorCount(&recipe.Addition)
|
||||
r.Item(&recipe.Result)
|
||||
r.String(&recipe.Block)
|
||||
r.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
|
||||
// FromLatest ...
|
||||
func (recipe *SmithingTrimRecipe) FromLatest(v protocol.SmithingTrimRecipe) *SmithingTrimRecipe {
|
||||
recipe.RecipeNetworkID = v.RecipeNetworkID
|
||||
recipe.RecipeID = v.RecipeID
|
||||
recipe.Template = v.Template
|
||||
recipe.Base = v.Base
|
||||
recipe.Addition = v.Addition
|
||||
recipe.Block = v.Block
|
||||
return recipe
|
||||
}
|
||||
|
||||
// ToLatest ...
|
||||
func (recipe *SmithingTrimRecipe) ToLatest() protocol.SmithingTrimRecipe {
|
||||
return protocol.SmithingTrimRecipe{
|
||||
RecipeNetworkID: recipe.RecipeNetworkID,
|
||||
RecipeID: recipe.RecipeID,
|
||||
Template: recipe.Template,
|
||||
Base: recipe.Base,
|
||||
Addition: recipe.Addition,
|
||||
Block: recipe.Block,
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal ...
|
||||
func (recipe *SmithingTrimRecipe) Marshal(w *Writer) {
|
||||
w.String(&recipe.RecipeID)
|
||||
w.ItemDescriptorCount(&recipe.Template)
|
||||
w.ItemDescriptorCount(&recipe.Base)
|
||||
w.ItemDescriptorCount(&recipe.Addition)
|
||||
w.String(&recipe.Block)
|
||||
w.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
|
||||
// Unmarshal ...
|
||||
func (recipe *SmithingTrimRecipe) Unmarshal(r *Reader) {
|
||||
r.String(&recipe.RecipeID)
|
||||
r.ItemDescriptorCount(&recipe.Template)
|
||||
r.ItemDescriptorCount(&recipe.Base)
|
||||
r.ItemDescriptorCount(&recipe.Addition)
|
||||
r.String(&recipe.Block)
|
||||
r.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
|
||||
// marshalShaped ...
|
||||
func marshalShaped(r protocol.IO, recipe *ShapedRecipe) {
|
||||
r.String(&recipe.RecipeID)
|
||||
r.Varint32(&recipe.Width)
|
||||
r.Varint32(&recipe.Height)
|
||||
protocol.FuncSliceOfLen(r, uint32(recipe.Width*recipe.Height), &recipe.Input, r.ItemDescriptorCount)
|
||||
protocol.FuncSlice(r, &recipe.Output, r.Item)
|
||||
r.UUID(&recipe.UUID)
|
||||
r.String(&recipe.Block)
|
||||
r.Varint32(&recipe.Priority)
|
||||
r.Bool(&recipe.AssumeSymmetry)
|
||||
if IsProtoGTE(r, ID685) {
|
||||
protocol.Single(r, &recipe.UnlockRequirement)
|
||||
}
|
||||
r.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
|
||||
// marshalShapeless ...
|
||||
func marshalShapeless(r protocol.IO, recipe *ShapelessRecipe) {
|
||||
r.String(&recipe.RecipeID)
|
||||
protocol.FuncSlice(r, &recipe.Input, r.ItemDescriptorCount)
|
||||
protocol.FuncSlice(r, &recipe.Output, r.Item)
|
||||
r.UUID(&recipe.UUID)
|
||||
r.String(&recipe.Block)
|
||||
r.Varint32(&recipe.Priority)
|
||||
if IsProtoGTE(r, ID685) {
|
||||
protocol.Single(r, &recipe.UnlockRequirement)
|
||||
}
|
||||
r.Varuint32(&recipe.RecipeNetworkID)
|
||||
}
|
||||
@@ -76,6 +76,16 @@ func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packe
|
||||
return func() packet.Packet { return &legacypacket.InventoryTransaction{} }
|
||||
case packet.IDItemStackRequest:
|
||||
return func() packet.Packet { return &legacypacket.ItemStackRequest{} }
|
||||
case packet.IDCraftingData:
|
||||
return func() packet.Packet { return &legacypacket.CraftingData{} }
|
||||
case packet.IDContainerClose:
|
||||
return func() packet.Packet { return &legacypacket.ContainerClose{} }
|
||||
case packet.IDText:
|
||||
return func() packet.Packet { return &legacypacket.Text{} }
|
||||
case packet.IDStartGame:
|
||||
return func() packet.Packet { return &legacypacket.StartGame{} }
|
||||
case packet.IDCodeBuilderSource:
|
||||
return func() packet.Packet { return &legacypacket.CodeBuilderSource{} }
|
||||
default:
|
||||
return cur
|
||||
}
|
||||
@@ -127,6 +137,8 @@ func (p *Protocol) ConvertFromLatest(pk packet.Packet, conn *minecraft.Conn) []p
|
||||
func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) []packet.Packet {
|
||||
for pkIndex, pk := range pks {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.ClientCacheStatus:
|
||||
pk.Enabled = false // TODO: enable when chunk translation is not broken
|
||||
case *packet.CameraPresets:
|
||||
presets := make([]proto.CameraPreset, len(pk.Presets))
|
||||
for i, p := range pk.Presets {
|
||||
@@ -135,9 +147,6 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
||||
pks[pkIndex] = &legacypacket.CameraPresets{
|
||||
Presets: presets,
|
||||
}
|
||||
case *packet.StartGame:
|
||||
pk.GameVersion = p.ver
|
||||
pk.BaseGameVersion = p.ver
|
||||
case *packet.PlayerAuthInput:
|
||||
inputData := pk.InputData
|
||||
if p.ID() < proto.ID766 {
|
||||
@@ -398,6 +407,126 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
||||
requests[i] = (&proto.ItemStackRequest{}).FromLatest(r)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.ItemStackRequest{Requests: requests}
|
||||
case *packet.Text:
|
||||
pks[pkIndex] = &legacypacket.Text{
|
||||
TextType: pk.TextType,
|
||||
NeedsTranslation: pk.NeedsTranslation,
|
||||
SourceName: pk.SourceName,
|
||||
Message: pk.Message,
|
||||
Parameters: pk.Parameters,
|
||||
XUID: pk.XUID,
|
||||
PlatformChatID: pk.PlatformChatID,
|
||||
FilteredMessage: pk.FilteredMessage,
|
||||
}
|
||||
case *packet.ContainerClose:
|
||||
pks[pkIndex] = &legacypacket.ContainerClose{
|
||||
WindowID: pk.WindowID,
|
||||
ContainerType: pk.ContainerType,
|
||||
ServerSide: pk.ServerSide,
|
||||
}
|
||||
case *packet.CraftingData:
|
||||
recipes := make([]proto.Recipe, len(pk.Recipes))
|
||||
for i, r := range pk.Recipes {
|
||||
recipes[i] = proto.RecipeFromLatest(r)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.CraftingData{
|
||||
Recipes: recipes,
|
||||
PotionRecipes: pk.PotionRecipes,
|
||||
PotionContainerChangeRecipes: pk.PotionContainerChangeRecipes,
|
||||
MaterialReducers: pk.MaterialReducers,
|
||||
ClearRecipes: pk.ClearRecipes,
|
||||
}
|
||||
case *packet.StartGame:
|
||||
// Adjust game version
|
||||
pk.GameVersion = p.ver
|
||||
pk.BaseGameVersion = p.ver
|
||||
|
||||
pks[pkIndex] = &legacypacket.StartGame{
|
||||
EntityUniqueID: pk.EntityUniqueID,
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
PlayerGameMode: pk.PlayerGameMode,
|
||||
PlayerPosition: pk.PlayerPosition,
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
WorldSeed: pk.WorldSeed,
|
||||
SpawnBiomeType: pk.SpawnBiomeType,
|
||||
UserDefinedBiomeName: pk.UserDefinedBiomeName,
|
||||
Dimension: pk.Dimension,
|
||||
Generator: pk.Generator,
|
||||
WorldGameMode: pk.WorldGameMode,
|
||||
Hardcore: pk.Hardcore,
|
||||
Difficulty: pk.Difficulty,
|
||||
WorldSpawn: pk.WorldSpawn,
|
||||
AchievementsDisabled: pk.AchievementsDisabled,
|
||||
EditorWorldType: pk.EditorWorldType,
|
||||
CreatedInEditor: pk.CreatedInEditor,
|
||||
ExportedFromEditor: pk.ExportedFromEditor,
|
||||
DayCycleLockTime: pk.DayCycleLockTime,
|
||||
EducationEditionOffer: pk.EducationEditionOffer,
|
||||
EducationFeaturesEnabled: pk.EducationFeaturesEnabled,
|
||||
EducationProductID: pk.EducationProductID,
|
||||
RainLevel: pk.RainLevel,
|
||||
LightningLevel: pk.LightningLevel,
|
||||
ConfirmedPlatformLockedContent: pk.ConfirmedPlatformLockedContent,
|
||||
MultiPlayerGame: pk.MultiPlayerGame,
|
||||
LANBroadcastEnabled: pk.LANBroadcastEnabled,
|
||||
XBLBroadcastMode: pk.XBLBroadcastMode,
|
||||
PlatformBroadcastMode: pk.PlatformBroadcastMode,
|
||||
CommandsEnabled: pk.CommandsEnabled,
|
||||
TexturePackRequired: pk.TexturePackRequired,
|
||||
GameRules: pk.GameRules,
|
||||
Experiments: pk.Experiments,
|
||||
ExperimentsPreviouslyToggled: pk.ExperimentsPreviouslyToggled,
|
||||
BonusChestEnabled: pk.BonusChestEnabled,
|
||||
StartWithMapEnabled: pk.StartWithMapEnabled,
|
||||
PlayerPermissions: pk.PlayerPermissions,
|
||||
ServerChunkTickRadius: pk.ServerChunkTickRadius,
|
||||
HasLockedBehaviourPack: pk.HasLockedBehaviourPack,
|
||||
HasLockedTexturePack: pk.HasLockedTexturePack,
|
||||
FromLockedWorldTemplate: pk.FromLockedWorldTemplate,
|
||||
MSAGamerTagsOnly: pk.MSAGamerTagsOnly,
|
||||
FromWorldTemplate: pk.FromWorldTemplate,
|
||||
WorldTemplateSettingsLocked: pk.WorldTemplateSettingsLocked,
|
||||
OnlySpawnV1Villagers: pk.OnlySpawnV1Villagers,
|
||||
PersonaDisabled: pk.PersonaDisabled,
|
||||
CustomSkinsDisabled: pk.CustomSkinsDisabled,
|
||||
EmoteChatMuted: pk.EmoteChatMuted,
|
||||
BaseGameVersion: pk.BaseGameVersion,
|
||||
LimitedWorldWidth: pk.LimitedWorldWidth,
|
||||
LimitedWorldDepth: pk.LimitedWorldDepth,
|
||||
NewNether: pk.NewNether,
|
||||
EducationSharedResourceURI: pk.EducationSharedResourceURI,
|
||||
ForceExperimentalGameplay: pk.ForceExperimentalGameplay,
|
||||
LevelID: pk.LevelID,
|
||||
WorldName: pk.WorldName,
|
||||
TemplateContentIdentity: pk.TemplateContentIdentity,
|
||||
Trial: pk.Trial,
|
||||
PlayerMovementSettings: pk.PlayerMovementSettings,
|
||||
Time: pk.Time,
|
||||
EnchantmentSeed: pk.EnchantmentSeed,
|
||||
Blocks: pk.Blocks,
|
||||
Items: pk.Items,
|
||||
MultiPlayerCorrelationID: pk.MultiPlayerCorrelationID,
|
||||
ServerAuthoritativeInventory: pk.ServerAuthoritativeInventory,
|
||||
GameVersion: pk.GameVersion,
|
||||
PropertyData: pk.PropertyData,
|
||||
ServerBlockStateChecksum: pk.ServerBlockStateChecksum,
|
||||
ClientSideGeneration: pk.ClientSideGeneration,
|
||||
WorldTemplateID: pk.WorldTemplateID,
|
||||
ChatRestrictionLevel: pk.ChatRestrictionLevel,
|
||||
DisablePlayerInteractions: pk.DisablePlayerInteractions,
|
||||
ServerID: pk.ServerID,
|
||||
WorldID: pk.WorldID,
|
||||
ScenarioID: pk.ScenarioID,
|
||||
UseBlockNetworkIDHashes: pk.UseBlockNetworkIDHashes,
|
||||
ServerAuthoritativeSound: pk.ServerAuthoritativeSound,
|
||||
}
|
||||
case *packet.CodeBuilderSource:
|
||||
pks[pkIndex] = &legacypacket.CodeBuilderSource{
|
||||
Operation: pk.Operation,
|
||||
Category: pk.Category,
|
||||
CodeStatus: pk.CodeStatus,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,6 +803,122 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
||||
requests[i] = r.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.ItemStackRequest{Requests: requests}
|
||||
case *legacypacket.CraftingData:
|
||||
recipes := make([]protocol.Recipe, len(pk.Recipes))
|
||||
for i, r := range pk.Recipes {
|
||||
recipes[i] = proto.RecipeToLatest(r)
|
||||
}
|
||||
pks[pkIndex] = &packet.CraftingData{
|
||||
Recipes: recipes,
|
||||
PotionRecipes: pk.PotionRecipes,
|
||||
PotionContainerChangeRecipes: pk.PotionContainerChangeRecipes,
|
||||
MaterialReducers: pk.MaterialReducers,
|
||||
ClearRecipes: pk.ClearRecipes,
|
||||
}
|
||||
case *legacypacket.ContainerClose:
|
||||
pks[pkIndex] = &packet.ContainerClose{
|
||||
WindowID: pk.WindowID,
|
||||
ContainerType: pk.ContainerType,
|
||||
ServerSide: pk.ServerSide,
|
||||
}
|
||||
case *legacypacket.Text:
|
||||
pks[pkIndex] = &packet.Text{
|
||||
TextType: pk.TextType,
|
||||
NeedsTranslation: pk.NeedsTranslation,
|
||||
SourceName: pk.SourceName,
|
||||
Message: pk.Message,
|
||||
Parameters: pk.Parameters,
|
||||
XUID: pk.XUID,
|
||||
PlatformChatID: pk.PlatformChatID,
|
||||
FilteredMessage: pk.FilteredMessage,
|
||||
}
|
||||
case *legacypacket.StartGame:
|
||||
pks[pkIndex] = &packet.StartGame{
|
||||
EntityUniqueID: pk.EntityUniqueID,
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
PlayerGameMode: pk.PlayerGameMode,
|
||||
PlayerPosition: pk.PlayerPosition,
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
WorldSeed: pk.WorldSeed,
|
||||
SpawnBiomeType: pk.SpawnBiomeType,
|
||||
UserDefinedBiomeName: pk.UserDefinedBiomeName,
|
||||
Dimension: pk.Dimension,
|
||||
Generator: pk.Generator,
|
||||
WorldGameMode: pk.WorldGameMode,
|
||||
Hardcore: pk.Hardcore,
|
||||
Difficulty: pk.Difficulty,
|
||||
WorldSpawn: pk.WorldSpawn,
|
||||
AchievementsDisabled: pk.AchievementsDisabled,
|
||||
EditorWorldType: pk.EditorWorldType,
|
||||
CreatedInEditor: pk.CreatedInEditor,
|
||||
ExportedFromEditor: pk.ExportedFromEditor,
|
||||
DayCycleLockTime: pk.DayCycleLockTime,
|
||||
EducationEditionOffer: pk.EducationEditionOffer,
|
||||
EducationFeaturesEnabled: pk.EducationFeaturesEnabled,
|
||||
EducationProductID: pk.EducationProductID,
|
||||
RainLevel: pk.RainLevel,
|
||||
LightningLevel: pk.LightningLevel,
|
||||
ConfirmedPlatformLockedContent: pk.ConfirmedPlatformLockedContent,
|
||||
MultiPlayerGame: pk.MultiPlayerGame,
|
||||
LANBroadcastEnabled: pk.LANBroadcastEnabled,
|
||||
XBLBroadcastMode: pk.XBLBroadcastMode,
|
||||
PlatformBroadcastMode: pk.PlatformBroadcastMode,
|
||||
CommandsEnabled: pk.CommandsEnabled,
|
||||
TexturePackRequired: pk.TexturePackRequired,
|
||||
GameRules: pk.GameRules,
|
||||
Experiments: pk.Experiments,
|
||||
ExperimentsPreviouslyToggled: pk.ExperimentsPreviouslyToggled,
|
||||
BonusChestEnabled: pk.BonusChestEnabled,
|
||||
StartWithMapEnabled: pk.StartWithMapEnabled,
|
||||
PlayerPermissions: pk.PlayerPermissions,
|
||||
ServerChunkTickRadius: pk.ServerChunkTickRadius,
|
||||
HasLockedBehaviourPack: pk.HasLockedBehaviourPack,
|
||||
HasLockedTexturePack: pk.HasLockedTexturePack,
|
||||
FromLockedWorldTemplate: pk.FromLockedWorldTemplate,
|
||||
MSAGamerTagsOnly: pk.MSAGamerTagsOnly,
|
||||
FromWorldTemplate: pk.FromWorldTemplate,
|
||||
WorldTemplateSettingsLocked: pk.WorldTemplateSettingsLocked,
|
||||
OnlySpawnV1Villagers: pk.OnlySpawnV1Villagers,
|
||||
PersonaDisabled: pk.PersonaDisabled,
|
||||
CustomSkinsDisabled: pk.CustomSkinsDisabled,
|
||||
EmoteChatMuted: pk.EmoteChatMuted,
|
||||
BaseGameVersion: pk.BaseGameVersion,
|
||||
LimitedWorldWidth: pk.LimitedWorldWidth,
|
||||
LimitedWorldDepth: pk.LimitedWorldDepth,
|
||||
NewNether: pk.NewNether,
|
||||
EducationSharedResourceURI: pk.EducationSharedResourceURI,
|
||||
ForceExperimentalGameplay: pk.ForceExperimentalGameplay,
|
||||
LevelID: pk.LevelID,
|
||||
WorldName: pk.WorldName,
|
||||
TemplateContentIdentity: pk.TemplateContentIdentity,
|
||||
Trial: pk.Trial,
|
||||
PlayerMovementSettings: pk.PlayerMovementSettings,
|
||||
Time: pk.Time,
|
||||
EnchantmentSeed: pk.EnchantmentSeed,
|
||||
Blocks: pk.Blocks,
|
||||
Items: pk.Items,
|
||||
MultiPlayerCorrelationID: pk.MultiPlayerCorrelationID,
|
||||
ServerAuthoritativeInventory: pk.ServerAuthoritativeInventory,
|
||||
GameVersion: pk.GameVersion,
|
||||
PropertyData: pk.PropertyData,
|
||||
ServerBlockStateChecksum: pk.ServerBlockStateChecksum,
|
||||
ClientSideGeneration: pk.ClientSideGeneration,
|
||||
WorldTemplateID: pk.WorldTemplateID,
|
||||
ChatRestrictionLevel: pk.ChatRestrictionLevel,
|
||||
DisablePlayerInteractions: pk.DisablePlayerInteractions,
|
||||
ServerID: pk.ServerID,
|
||||
WorldID: pk.WorldID,
|
||||
ScenarioID: pk.ScenarioID,
|
||||
UseBlockNetworkIDHashes: pk.UseBlockNetworkIDHashes,
|
||||
ServerAuthoritativeSound: pk.ServerAuthoritativeSound,
|
||||
}
|
||||
case *legacypacket.CodeBuilderSource:
|
||||
pks[pkIndex] = &packet.CodeBuilderSource{
|
||||
Operation: pk.Operation,
|
||||
Category: pk.Category,
|
||||
CodeStatus: pk.CodeStatus,
|
||||
}
|
||||
}
|
||||
}
|
||||
return pks
|
||||
|
||||
37
legacyver/v671.go
Normal file
37
legacyver/v671.go
Normal file
@@ -0,0 +1,37 @@
|
||||
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 (
|
||||
// ItemVersion671 ...
|
||||
ItemVersion671 = 181
|
||||
// BlockVersion671 ...
|
||||
BlockVersion671 int32 = (1 << 24) | (20 << 16) | (80 << 8)
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed data/item_runtime_ids_671.nbt
|
||||
itemRuntimeIDData671 []byte
|
||||
//go:embed data/required_item_list_671.json
|
||||
requiredItemList671 []byte
|
||||
//go:embed data/block_states_671.nbt
|
||||
blockStateData671 []byte
|
||||
)
|
||||
|
||||
// New671 ...
|
||||
func New671() *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData671, requiredItemList671, ItemVersion671, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData671)
|
||||
|
||||
return &Protocol{
|
||||
ver: "1.20.80",
|
||||
id: proto.ID671,
|
||||
blockTranslator: NewBlockTranslator(blockMapping, latestBlockMapping, chunk.NewNetworkPersistentEncoding(blockMapping, BlockVersion671), chunk.NewBlockPaletteEncoding(blockMapping, BlockVersion671), false),
|
||||
itemTranslator: NewItemTranslator(itemMapping, itemMappingLatest, blockMapping, blockMappingLatest),
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ const (
|
||||
)
|
||||
|
||||
// New685 uses same data as 686
|
||||
func New685(direct bool) *Protocol {
|
||||
func New685() *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData686, requiredItemList686, ItemVersion685, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData686)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ var (
|
||||
blockStateData686 []byte
|
||||
)
|
||||
|
||||
func New686(direct bool) *Protocol {
|
||||
func New686() *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData686, requiredItemList686, ItemVersion686, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData686)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ var (
|
||||
blockStateData712 []byte
|
||||
)
|
||||
|
||||
func New712(direct bool) *Protocol {
|
||||
func New712() *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData712, requiredItemList712, ItemVersion712, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData712)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ var (
|
||||
blockStateData729 []byte
|
||||
)
|
||||
|
||||
func New729(direct bool) *Protocol {
|
||||
func New729() *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData729, requiredItemList729, ItemVersion729, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData729)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ var (
|
||||
blockStateData748 []byte
|
||||
)
|
||||
|
||||
func New748(direct bool) *Protocol {
|
||||
func New748() *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData748, requiredItemList748, ItemVersion748, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData748)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user