2023-12-18 15:28:58 +01:00
/ *
* This file is part of ViaVersion - https : //github.com/ViaVersion/ViaVersion
* Copyright ( C ) 2023 ViaVersion and contributors
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter ;
2024-01-24 17:34:40 +01:00
import com.github.steveice10.opennbt.tag.builtin.CompoundTag ;
import com.github.steveice10.opennbt.tag.builtin.ListTag ;
import com.github.steveice10.opennbt.tag.builtin.NumberTag ;
import com.github.steveice10.opennbt.tag.builtin.StringTag ;
import com.github.steveice10.opennbt.tag.builtin.Tag ;
import com.viaversion.viaversion.api.data.entity.DimensionData ;
import com.viaversion.viaversion.api.minecraft.RegistryEntry ;
2023-12-18 15:28:58 +01:00
import com.viaversion.viaversion.api.minecraft.entities.EntityType ;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5 ;
2024-01-24 17:34:40 +01:00
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper ;
2023-12-18 15:28:58 +01:00
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers ;
import com.viaversion.viaversion.api.type.Type ;
import com.viaversion.viaversion.api.type.types.version.Types1_20_3 ;
2023-12-18 19:34:53 +01:00
import com.viaversion.viaversion.api.type.types.version.Types1_20_5 ;
2023-12-18 15:28:58 +01:00
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundConfigurationPackets1_20_3 ;
2024-01-26 15:48:10 +01:00
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPacket1_20_3 ;
2023-12-18 15:28:58 +01:00
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPackets1_20_3 ;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.Protocol1_20_5To1_20_3 ;
2023-12-18 17:14:24 +01:00
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.AttributeMappings ;
2024-01-24 17:34:40 +01:00
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundConfigurationPackets1_20_5 ;
2023-12-18 15:28:58 +01:00
import com.viaversion.viaversion.rewriter.EntityRewriter ;
import com.viaversion.viaversion.util.Key ;
2024-01-26 16:05:58 +01:00
import java.util.Arrays ;
2024-01-24 17:34:40 +01:00
import java.util.Map ;
2024-01-26 16:05:58 +01:00
import java.util.UUID ;
2023-12-18 15:28:58 +01:00
2024-01-26 15:48:10 +01:00
public final class EntityPacketRewriter1_20_5 extends EntityRewriter < ClientboundPacket1_20_3 , Protocol1_20_5To1_20_3 > {
2023-12-18 15:28:58 +01:00
public EntityPacketRewriter1_20_5 ( final Protocol1_20_5To1_20_3 protocol ) {
super ( protocol ) ;
}
@Override
public void registerPackets ( ) {
registerTrackerWithData1_19 ( ClientboundPackets1_20_3 . SPAWN_ENTITY , EntityTypes1_20_5 . FALLING_BLOCK ) ;
2023-12-18 19:34:53 +01:00
registerMetadataRewriter ( ClientboundPackets1_20_3 . ENTITY_METADATA , Types1_20_3 . METADATA_LIST , Types1_20_5 . METADATA_LIST ) ;
2023-12-18 15:28:58 +01:00
registerRemoveEntities ( ClientboundPackets1_20_3 . REMOVE_ENTITIES ) ;
2024-01-27 13:48:08 +01:00
protocol . registerClientbound ( ClientboundConfigurationPackets1_20_3 . REGISTRY_DATA , wrapper - > {
final CompoundTag registryData = wrapper . read ( Type . COMPOUND_TAG ) ;
cacheDimensionData ( wrapper . user ( ) , registryData ) ;
trackBiomeSize ( wrapper . user ( ) , registryData ) ;
for ( final Map . Entry < String , Tag > entry : registryData . entrySet ( ) ) {
final CompoundTag entryTag = ( CompoundTag ) entry . getValue ( ) ;
final StringTag typeTag = entryTag . get ( " type " ) ;
final ListTag valueTag = entryTag . get ( " value " ) ;
RegistryEntry [ ] registryEntries = new RegistryEntry [ valueTag . size ( ) ] ;
boolean requiresDummyValues = false ;
int entriesLength = registryEntries . length ;
for ( final Tag tag : valueTag ) {
final CompoundTag compoundTag = ( CompoundTag ) tag ;
final StringTag nameTag = compoundTag . get ( " name " ) ;
final int id = ( ( NumberTag ) compoundTag . get ( " id " ) ) . asInt ( ) ;
entriesLength = Math . max ( entriesLength , id + 1 ) ;
if ( id > = registryEntries . length ) {
// It was previously possible to have arbitrary ids
registryEntries = Arrays . copyOf ( registryEntries , Math . max ( registryEntries . length * 2 , id + 1 ) ) ;
requiresDummyValues = true ;
2024-01-24 17:34:40 +01:00
}
2024-01-27 13:48:08 +01:00
registryEntries [ id ] = new RegistryEntry ( nameTag . getValue ( ) , compoundTag . get ( " element " ) ) ;
}
if ( requiresDummyValues ) {
// Truncate and replace null values
if ( registryEntries . length ! = entriesLength ) {
registryEntries = Arrays . copyOf ( registryEntries , entriesLength ) ;
}
replaceNullValues ( registryEntries ) ;
}
final PacketWrapper registryPacket = wrapper . create ( ClientboundConfigurationPackets1_20_5 . REGISTRY_DATA ) ;
registryPacket . write ( Type . STRING , typeTag . getValue ( ) ) ;
registryPacket . write ( Type . REGISTRY_ENTRY_ARRAY , registryEntries ) ;
registryPacket . send ( Protocol1_20_5To1_20_3 . class ) ;
2023-12-18 15:28:58 +01:00
}
2024-01-27 13:48:08 +01:00
wrapper . cancel ( ) ;
2023-12-18 15:28:58 +01:00
} ) ;
protocol . registerClientbound ( ClientboundPackets1_20_3 . JOIN_GAME , new PacketHandlers ( ) {
@Override
public void register ( ) {
2023-12-18 17:14:24 +01:00
map ( Type . INT ) ; // Entity ID
2023-12-18 15:28:58 +01:00
map ( Type . BOOLEAN ) ; // Hardcore
map ( Type . STRING_ARRAY ) ; // World List
map ( Type . VAR_INT ) ; // Max players
map ( Type . VAR_INT ) ; // View distance
map ( Type . VAR_INT ) ; // Simulation distance
map ( Type . BOOLEAN ) ; // Reduced debug info
map ( Type . BOOLEAN ) ; // Show death screen
map ( Type . BOOLEAN ) ; // Limited crafting
2024-01-24 17:34:40 +01:00
handler ( wrapper - > {
final String dimensionKey = wrapper . read ( Type . STRING ) ;
final DimensionData data = tracker ( wrapper . user ( ) ) . dimensionData ( dimensionKey ) ;
wrapper . write ( Type . VAR_INT , data . id ( ) ) ;
} ) ;
2023-12-18 15:28:58 +01:00
map ( Type . STRING ) ; // World
2024-01-17 21:04:44 +01:00
map ( Type . LONG ) ; // Seed
map ( Type . BYTE ) ; // Gamemode
map ( Type . BYTE ) ; // Previous gamemode
map ( Type . BOOLEAN ) ; // Debug
map ( Type . BOOLEAN ) ; // Flat
map ( Type . OPTIONAL_GLOBAL_POSITION ) ; // Last death location
create ( Type . BOOLEAN , false ) ; // Enforces secure chat - moved from server data (which is unfortunately sent a while after this)
2024-01-24 17:34:40 +01:00
handler ( worldDataTrackerHandlerByKey1_20_5 ( 3 ) ) ; // Tracks world height and name for chunk data and entity (un)tracking
2023-12-18 15:28:58 +01:00
}
} ) ;
2024-01-27 13:48:08 +01:00
protocol . registerClientbound ( ClientboundPackets1_20_3 . RESPAWN , wrapper - > {
final String dimensionKey = wrapper . read ( Type . STRING ) ;
final DimensionData data = tracker ( wrapper . user ( ) ) . dimensionData ( dimensionKey ) ;
wrapper . write ( Type . VAR_INT , data . id ( ) ) ;
wrapper . passthrough ( Type . STRING ) ; // World
worldDataTrackerHandlerByKey1_20_5 ( 0 ) . handle ( wrapper ) ; // Tracks world height and name for chunk data and entity (un)tracking
2023-12-18 15:28:58 +01:00
} ) ;
protocol . registerClientbound ( ClientboundPackets1_20_3 . ENTITY_EFFECT , wrapper - > {
2023-12-18 17:14:24 +01:00
wrapper . passthrough ( Type . VAR_INT ) ; // Entity ID
wrapper . passthrough ( Type . VAR_INT ) ; // Effect ID
2024-02-01 17:49:58 +01:00
final byte amplifier = wrapper . read ( Type . BYTE ) ;
wrapper . write ( Type . VAR_INT , ( int ) amplifier ) ;
2023-12-18 15:28:58 +01:00
wrapper . passthrough ( Type . VAR_INT ) ; // Duration
wrapper . passthrough ( Type . BYTE ) ; // Flags
wrapper . read ( Type . OPTIONAL_COMPOUND_TAG ) ; // Remove factor data
} ) ;
protocol . registerClientbound ( ClientboundPackets1_20_3 . ENTITY_PROPERTIES , wrapper - > {
2023-12-18 17:14:24 +01:00
wrapper . passthrough ( Type . VAR_INT ) ; // Entity ID
2023-12-18 15:28:58 +01:00
final int size = wrapper . passthrough ( Type . VAR_INT ) ;
for ( int i = 0 ; i < size ; i + + ) {
2023-12-18 17:14:24 +01:00
// From a string to a registry int ID
final String attributeIdentifier = Key . stripMinecraftNamespace ( wrapper . read ( Type . STRING ) ) ;
final int id = AttributeMappings . id ( attributeIdentifier ) ;
wrapper . write ( Type . VAR_INT , protocol . getMappingData ( ) . getNewAttributeId ( id ) ) ;
2023-12-18 15:28:58 +01:00
wrapper . passthrough ( Type . DOUBLE ) ; // Base
final int modifierSize = wrapper . passthrough ( Type . VAR_INT ) ;
for ( int j = 0 ; j < modifierSize ; j + + ) {
2023-12-18 17:14:24 +01:00
wrapper . passthrough ( Type . UUID ) ; // ID
2023-12-18 15:28:58 +01:00
wrapper . passthrough ( Type . DOUBLE ) ; // Amount
wrapper . passthrough ( Type . BYTE ) ; // Operation
}
}
} ) ;
}
2024-01-27 13:48:08 +01:00
private void replaceNullValues ( final RegistryEntry [ ] entries ) {
2024-01-26 16:05:58 +01:00
// Find the first non-null entry and fill the array with dummy values where needed (which is easier than remapping them to different ids in a new, smaller array)
RegistryEntry first = null ;
for ( final RegistryEntry registryEntry : entries ) {
if ( registryEntry ! = null ) {
first = registryEntry ;
break ;
}
}
for ( int i = 0 ; i < entries . length ; i + + ) {
if ( entries [ i ] = = null ) {
entries [ i ] = first . withKey ( UUID . randomUUID ( ) . toString ( ) ) ;
}
}
}
2023-12-18 15:28:58 +01:00
@Override
protected void registerRewrites ( ) {
2024-01-12 16:01:30 +01:00
filter ( ) . mapMetaType ( typeId - > {
int id = typeId ;
2023-12-18 19:34:53 +01:00
if ( id > = Types1_20_5 . META_TYPES . armadilloState . typeId ( ) ) {
id + + ;
}
2024-01-12 16:01:30 +01:00
return Types1_20_5 . META_TYPES . byId ( id ) ;
2023-12-18 19:34:53 +01:00
} ) ;
2023-12-18 15:28:58 +01:00
registerMetaTypeHandler (
2023-12-18 19:34:53 +01:00
Types1_20_5 . META_TYPES . itemType ,
Types1_20_5 . META_TYPES . blockStateType ,
Types1_20_5 . META_TYPES . optionalBlockStateType ,
Types1_20_5 . META_TYPES . particleType
2023-12-18 15:28:58 +01:00
) ;
2024-01-31 17:36:12 +01:00
filter ( ) . type ( EntityTypes1_20_5 . LLAMA ) . removeIndex ( 20 ) ; // Carpet color
2024-01-26 16:05:58 +01:00
2024-01-12 16:01:30 +01:00
filter ( ) . type ( EntityTypes1_20_5 . MINECART_ABSTRACT ) . index ( 11 ) . handler ( ( event , meta ) - > {
2023-12-18 15:28:58 +01:00
final int blockState = meta . value ( ) ;
meta . setValue ( protocol . getMappingData ( ) . getNewBlockStateId ( blockState ) ) ;
} ) ;
}
@Override
public void onMappingDataLoaded ( ) {
mapTypes ( ) ;
}
@Override
public EntityType typeFromId ( final int type ) {
return EntityTypes1_20_5 . getTypeFromId ( type ) ;
}
}