Compare commits

..
49 Commits
Author SHA1 Message Date
Nassim Jahnke 48d5aaf8fa 5.0.2 Release 2024-07-28 14:37:59 +02:00
EnZaXD 41b0d95d70 Fix horse/llama's armor/carpet not visible in 1.20.3->1.20.5 (#4052) 2024-07-27 20:26:53 +02:00
EnZaXD b599399c48 Cleanup 1.20->1.20.2 item and recipe rewriter (#4050) 2024-07-27 19:53:59 +02:00
EnZaXD 721e27eb39 Rewrite show_item in translation components in 1.11.1->1.12 (#4053)
Fixes https://github.com/ViaVersion/ViaVersion/issues/4051
2024-07-27 19:53:44 +02:00
EnZaXD c9d6fbfcd0 Add VersionProvider#getServerProtocol (#4049)
Most platforms won't ever throw an error and usually ViaVersion shouldn't even load when the server version can't be found. Therefore, I added this bouncer function, so I don't need to try catch my code in ViaLoader/VFP where an exception is never thrown
2024-07-27 19:53:33 +02:00
RK_01 b1f64fd081 Use enhanced switches in more places (#4043) 2024-07-24 14:32:36 +02:00
EnZaXD 2b508567db Move damage types 1.20.3 into nbt file (#4026) 2024-07-24 13:13:36 +02:00
EnZaXD 24d0ae7607 Add ViaManager#addPostEnableListener (#4038) 2024-07-22 18:24:06 +02:00
EnZaXD 40a44d5dc5 Remove version type from dump (#4036) 2024-07-22 17:45:21 +02:00
EnZaXD b5a06181d4 Fix item projectile hierarchy in 1.14+ (#4034) 2024-07-22 17:44:07 +02:00
EnZaXD 35fa7e78a0 Handle attribute_modifiers inside container components in 1.21->1.20.5 (#4035)
Closes https://github.com/ViaVersion/ViaVersion/issues/3968
2024-07-22 17:42:25 +02:00
EnZaXD 7f4faab4ab Add 1.21 to the version table (#4037) 2024-07-22 17:40:37 +02:00
EnZaXD 3906b47654 Apply required changes for ViaAprilFools (#4033)
1. Allow the version provider to get the client version sent through the handshake packet
2. Allow platform to override provider instead
2024-07-21 17:45:13 +02:00
Nassim Jahnke 1476adb281 Slightly improve logging on config loading errors 2024-07-21 12:12:06 +02:00
EnZaXD 6fb072120b Removes VFP as well and recommends ViaBackwards/ViaRewind on both platforms (#4032) 2024-07-21 09:43:40 +02:00
EnZaXD f2f0be0581 Allow base protocols to set client version (#4029) 2024-07-20 09:15:15 +02:00
EnZaXD 5ec30ef18a Expose origin version in RedirectProtocolVersion (#4030) 2024-07-20 09:12:44 +02:00
Nassim Jahnke 0915afe43b Handle 1.21 attribute id changes
Fixes #4005
2024-07-19 11:26:28 +02:00
EnZaXD 87b041bf3a Fix block predicate conversion in 1.20.3->1.20.5 (#4025) 2024-07-19 11:00:00 +02:00
EnZaXD 275b09bdbb Use SerializerVersion#toTag when converting 1.20.5->1.20.3 block predicates (#4024) 2024-07-19 10:54:40 +02:00
Nassim Jahnke cc87c02020 Add shulker box block entity id if missing 2024-07-17 18:48:07 +02:00
EnZaXD a45985ed58 Validate index when reading structured data type (#4020) 2024-07-16 09:59:33 +02:00
Nassim Jahnke 92dedfb950 Update Gradle wrapper 2024-07-14 21:31:38 +02:00
RK_01 6bbcf7d784 Fix respawn "keep data" translation (#4015) 2024-07-13 11:00:12 +02:00
EnZaXD 465a2354c0 Call component rewriter in pre 1.20.3 advancement handler (#4014)
Required for ViaBackwards where we need to rewrite the translation key (and it also doesn't hurt to have this in forward protocols).

Closes https://github.com/ViaVersion/ViaBackwards/issues/819
2024-07-13 11:00:00 +02:00
EnZaXD c59c15d6f3 [ci skip] Fix player combat packet value comments (#4013) 2024-07-13 10:59:47 +02:00
EnZaXD 20f7738f08 Add cancel-block-sounds option for 1.8->1.9 place/break fix (#4011) 2024-07-12 00:11:11 +02:00
EnZaXD 323f0fa087 Remove minimize-cooldown config option (#4009) 2024-07-07 18:03:35 +02:00
RK_01 3138d667a6 Fix crossbow max damage and 1.8 sword blocking using item data components (#4010) 2024-07-07 18:02:51 +02:00
EnZaXD 365040f59d Handle rarity changes in trident/banner pattern item in 1.20.5->1.21 (#4001) 2024-07-07 17:39:30 +02:00
lowercasebtwandEnZaXD 303d9ecf51 Hide cooldown indicator completely in 1.8->1.9 (#4006)
* Change 1.8 to 1.9 Attack Speed

* Fix The Attack Speed Value Type

* Change Attack Speed to 20

Requested/Suggested change from FlorianMichael

Co-authored-by: EnZaXD <florian.michael07@gmail.com>

---------

Co-authored-by: EnZaXD <florian.michael07@gmail.com>
2024-07-06 23:12:01 +02:00
EnZaXD 463381b84e Rename missing metadata references to entity data (#4007) 2024-07-06 21:05:40 +02:00
Nassim Jahnke 7fef96d77e Remove unneeded 1.13 enchantment translatable mappings 2024-07-03 11:32:25 +02:00
Gegy 17358120cd Fix: delay chat acknowledgements instead of spoofing (#3997)
An easy reproduction case is to mute a player using the Social Interactions screen, let them chat, and then send a message. As ViaVersion produces its own acknowledgements, this now does not match with what the client produced and signed its messages with - so the signature will fail verification.

As an alternative, we *always* pass through the same acknowledgement bit set - and for 'spoofed' messages, we reuse the last one that we received. In the case of the chat ack packet with just an offset, we need to hold back the window by at least 20 messages to ensure we don't start making claims about whether the client saw a message that ViaVersion cannot yet make a judgement on.
2024-07-03 10:52:01 +02:00
EnZaXD e6da77cf47 Handle Slot tag inside CONTAINER tag in 1.20.3->1.20.5 (#3995)
Fixes shulker box tooltips not showing all items for 1.20.3 clients on 1.20.5+ servers
2024-07-02 11:53:34 +02:00
EnZaXD dc503cd613 Update legacy Minecraft version warning (#3989) 2024-06-30 11:30:54 +02:00
Nassim Jahnke 8aa2f4be46 Handle show item hovers in more component packets
Because servers do weird things
2024-06-30 11:10:44 +02:00
Nassim Jahnke c5dc5b2bf8 Actually restrict velocity change to fishing hooks 2024-06-28 15:29:06 +02:00
EnZaXD f4d6659760 Only print broken json in component type when debug mode is enabled (#3990) 2024-06-28 13:44:31 +02:00
EnZaXD bfbb80f708 Update unsupported java version warning (#3988)
Now links to the release which contains a guide on how to update
2024-06-27 14:56:15 +02:00
EnZaXD 248da118a9 Move bukkit-only settings into BukkitViaConfig (#3985) 2024-06-27 09:56:50 +02:00
EnZaXD a987882132 Rework unsupported config options in AbstractViaConfig (#3986) 2024-06-27 09:54:44 +02:00
EnZaXD bca25d4744 Rewrite filtered_pages in 1.20.2->1.20.3 (#3983) 2024-06-26 10:58:50 +02:00
EnZaXD 2417ffe483 Fixup horse inventory translation in 1.20.5->1.21 (#3980)
Fixes #3978
2024-06-25 15:27:02 +02:00
EnZaXD 8606e5d663 Handle both json and plain text in CommonBoss (#3981) 2024-06-25 15:21:34 +02:00
EnZaXD 5a0ca55b97 Add test command handler to DummyInitializer test (#3970) 2024-06-25 15:21:26 +02:00
Nassim Jahnke ceb1cffb00 Cancel "message not delivered" messages
Fixes #3438
2024-06-25 15:19:03 +02:00
Nassim Jahnke 1ff3035bc0 Make 1.10->1.11 fishing hook position desync slightly less bad 2024-06-25 15:17:29 +02:00
Nassim Jahnke 1f221ea828 Bump version to 5.0.2-SNAPSHOT 2024-06-25 15:16:36 +02:00
109 changed files with 1213 additions and 1233 deletions

No files matched your search

+2 -2
View File
@@ -2,7 +2,7 @@
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = false
insert_final_newline = true
tab_width = 4
[*.java]
@@ -13,4 +13,4 @@ ij_java_generate_final_locals = true
ij_java_generate_final_parameters = true
[{*.json,*.yml}]
indent_size = 2
indent_size = 2
+1 -1
View File
@@ -16,7 +16,7 @@ direct access to client/server state and more extensive API.
Supported Versions:
![Table (https://i.imgur.com/sTrVnC2.png)](https://i.imgur.com/sTrVnC2.png)
![Table (https://i.imgur.com/zrQTcf0.png)](https://i.imgur.com/zrQTcf0.png)
**User Docs:** https://docs.viaversion.com/display/VIAVERSION/
@@ -140,6 +140,13 @@ public interface ViaManager {
*/
void addEnableListener(Runnable runnable);
/**
* Adds a runnable to be executed when ViaVersion has finished its init after the full server load.
*
* @param runnable runnable to be executed
*/
void addPostEnableListener(Runnable runnable);
/**
* Returns whether the manager has been initialized (and protocols have been loaded).
*
@@ -67,9 +67,9 @@ public interface ViaVersionConfig extends Config {
boolean isShowNewDeathMessages();
/**
* Get if metadata errors will be suppressed
* Get if entity data errors will be suppressed
*
* @return true if metadata errors suppression is enabled
* @return true if entity data errors suppression is enabled
*/
boolean isSuppressMetadataErrors();
@@ -292,13 +292,6 @@ public interface ViaVersionConfig extends Config {
*/
boolean isDisable1_13AutoComplete();
/**
* Tries to minimize cooldown animation.
*
* @return true if enabled
*/
boolean isMinimizeCooldown();
/**
* Enable the serverside blockconnections for 1.13+ clients
*
@@ -464,4 +457,11 @@ public interface ViaVersionConfig extends Config {
* @return true if enabled
*/
boolean handleInvalidItemCount();
/**
* Tries to cancel block break/place sounds sent by 1.8 servers to 1.9+ clients to prevent them from playing twice
*
* @return true if enabled
*/
boolean cancelBlockSounds();
}
@@ -46,6 +46,7 @@ public class MappingDataBase implements MappingData {
protected ParticleMappings particleMappings;
protected BiMappings itemMappings;
protected BiMappings blockMappings;
protected BiMappings attributeMappings;
protected Mappings blockStateMappings;
protected Mappings blockEntityMappings;
protected Mappings soundMappings;
@@ -53,7 +54,6 @@ public class MappingDataBase implements MappingData {
protected Mappings enchantmentMappings;
protected Mappings paintingMappings;
protected Mappings menuMappings;
protected Mappings attributeMappings;
protected Map<RegistryType, List<TagData>> tags;
public MappingDataBase(final String unmappedVersion, final String mappedVersion) {
@@ -76,7 +76,7 @@ public class MappingDataBase implements MappingData {
menuMappings = loadMappings(data, "menus");
enchantmentMappings = loadMappings(data, "enchantments");
paintingMappings = loadMappings(data, "paintings");
attributeMappings = loadMappings(data, "attributes");
attributeMappings = loadBiMappings(data, "attributes");
final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt");
@@ -51,11 +51,12 @@ public enum EntityTypes1_14 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -51,11 +51,12 @@ public enum EntityTypes1_15 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -51,11 +51,12 @@ public enum EntityTypes1_16 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -51,11 +51,12 @@ public enum EntityTypes1_16_2 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -53,11 +53,12 @@ public enum EntityTypes1_17 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -53,11 +53,12 @@ public enum EntityTypes1_19 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -53,11 +53,12 @@ public enum EntityTypes1_19_3 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -59,11 +59,12 @@ public enum EntityTypes1_19_4 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -59,11 +59,12 @@ public enum EntityTypes1_20_3 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -59,12 +59,13 @@ public enum EntityTypes1_20_5 implements EntityType {
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -93,7 +93,7 @@ public class EntityTypes1_8 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking and metadata indexing
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking and entity data indexing
// Living entities as a larger subclass
LIVING_ENTITY(48, LIVING_ENTITY_BASE),
@@ -28,21 +28,21 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class EntityData {
private int id;
private EntityDataType metaType;
private EntityDataType dataType;
private Object value;
/**
* Creates a new metadata instance.
* Creates a new entity data instance.
*
* @param id metadata index
* @param metaType metadata type
* @param id data index
* @param dataType data type
* @param value value if present
* @throws IllegalArgumentException if the value and metaType are incompatible
* @throws IllegalArgumentException if the value and dataType are incompatible
*/
public EntityData(int id, EntityDataType metaType, @Nullable Object value) {
public EntityData(int id, EntityDataType dataType, @Nullable Object value) {
this.id = id;
this.metaType = metaType;
this.value = checkValue(metaType, value);
this.dataType = dataType;
this.value = checkValue(dataType, value);
}
public int id() {
@@ -54,19 +54,19 @@ public final class EntityData {
}
public EntityDataType dataType() {
return metaType;
return dataType;
}
/**
* Sets the metadata type if compatible with the current value.
* Sets the entity data type if compatible with the current value.
*
* @param metaType metadata type
* @throws IllegalArgumentException if the metadata type and current value are incompatible
* @param dataType entity data type
* @throws IllegalArgumentException if the entity data type and current value are incompatible
* @see #setTypeAndValue(EntityDataType, Object)
*/
public void setDataType(EntityDataType metaType) {
checkValue(metaType, this.value);
this.metaType = metaType;
public void setDataType(EntityDataType dataType) {
checkValue(dataType, this.value);
this.dataType = dataType;
}
public @Nullable <T> T value() {
@@ -78,32 +78,32 @@ public final class EntityData {
}
/**
* Sets the metadata value if compatible with the current meta type.
* Sets the entity data value if compatible with the current data type.
*
* @param value value
* @throws IllegalArgumentException if the value and current metaType are incompatible
* @throws IllegalArgumentException if the value and current dataType are incompatible
* @see #setTypeAndValue(EntityDataType, Object)
*/
public void setValue(@Nullable Object value) {
this.value = checkValue(this.metaType, value);
this.value = checkValue(this.dataType, value);
}
/**
* Sets metadata type and value.
* Sets entity data type and value.
*
* @param metaType metadata type
* @param dataType entity data type
* @param value value
* @throws IllegalArgumentException if the value and metaType are incompatible
* @throws IllegalArgumentException if the value and dataType are incompatible
*/
public void setTypeAndValue(EntityDataType metaType, @Nullable Object value) {
this.value = checkValue(metaType, value);
this.metaType = metaType;
public void setTypeAndValue(EntityDataType dataType, @Nullable Object value) {
this.value = checkValue(dataType, value);
this.dataType = dataType;
}
private Object checkValue(EntityDataType metaType, @Nullable Object value) {
Preconditions.checkNotNull(metaType);
if (value != null && !metaType.type().getOutputClass().isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Metadata value and metaType are incompatible. Type=" + metaType
private Object checkValue(EntityDataType dataType, @Nullable Object value) {
Preconditions.checkNotNull(dataType);
if (value != null && !dataType.type().getOutputClass().isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Entity data value and dataType are incompatible. Type=" + dataType
+ ", value=" + value + " (" + value.getClass().getSimpleName() + ")");
}
return value;
@@ -111,32 +111,32 @@ public final class EntityData {
@Deprecated
public void setDataTypeUnsafe(EntityDataType type) {
this.metaType = type;
this.dataType = type;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EntityData metadata = (EntityData) o;
if (id != metadata.id) return false;
if (metaType != metadata.metaType) return false;
return Objects.equals(value, metadata.value);
EntityData entityData = (EntityData) o;
if (id != entityData.id) return false;
if (dataType != entityData.dataType) return false;
return Objects.equals(value, entityData.value);
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + metaType.hashCode();
result = 31 * result + dataType.hashCode();
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Metadata{" +
return "EntityData{" +
"id=" + id +
", metaType=" + metaType +
", dataType=" + dataType +
", value=" + value +
'}';
}
@@ -35,7 +35,7 @@ public interface EntityDataType {
Type type();
/**
* Get type id from the specific MetaDataType
* Get type id from the specific EntityDataType
*
* @return Type id as an integer
*/
@@ -77,9 +77,9 @@ public interface EntityDataType {
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final EntityDataTypeImpl metaType = (EntityDataTypeImpl) o;
if (typeId != metaType.typeId) return false;
return type.equals(metaType.type);
final EntityDataTypeImpl dataType = (EntityDataTypeImpl) o;
if (typeId != dataType.typeId) return false;
return type.equals(dataType.type);
}
@Override
@@ -44,8 +44,8 @@ public abstract class AbstractEntityDataTypes implements EntityDataTypes {
}
protected EntityDataType add(final int typeId, final Type<?> type) {
final EntityDataType metaType = EntityDataType.create(typeId, type);
values[typeId] = metaType;
return metaType;
final EntityDataType dataType = EntityDataType.create(typeId, type);
values[typeId] = dataType;
return dataType;
}
}
@@ -27,18 +27,18 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
public interface EntityDataTypes {
/**
* Returns the meta type by the given id.
* Returns the data type by the given id.
*
* @param id type id
* @return meta type by id
* @return data type by id
* @throws IndexOutOfBoundsException if id is out of bounds
*/
EntityDataType byId(int id);
/**
* Returns an array of meta types.
* Returns an array of data types.
*
* @return array of meta types
* @return array of data types
*/
EntityDataType[] values();
}
@@ -28,6 +28,31 @@ import com.viaversion.viaversion.api.platform.providers.Provider;
@FunctionalInterface
public interface VersionProvider extends Provider {
/**
* Optionally allows platforms to specify the client version of a user. This is needed when the platform supports
* connecting other version types then {@link VersionType#RELEASE} to the server.
*
* @param connection connection
* @return client protocol version, or null if handshake packet should be used
*/
default ProtocolVersion getClientProtocol(UserConnection connection) {
return null;
}
/**
* Calls {@link #getClosestServerProtocol(UserConnection)} and catches any exceptions by returning null.
*
* @param connection connection
* @return closest server protocol version to the user's protocol version
*/
default ProtocolVersion getServerProtocol(UserConnection connection) {
try {
return getClosestServerProtocol(connection);
} catch (Exception e) {
return null;
}
}
/**
* Returns the closest server protocol version to the user's protocol version.
* On non-proxy servers, this returns the actual server version.
@@ -59,13 +59,13 @@ public interface EntityRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter
int newEntityId(int id);
/**
* Handles and transforms metadata of an entity.
* Handles and transforms entity data of an entity.
*
* @param entityId entity id
* @param metadataList full, mutable list of metadata
* @param dataList full, mutable list of entity data
* @param connection user connection
*/
void handleEntityData(int entityId, List<EntityData> metadataList, UserConnection connection);
void handleEntityData(int entityId, List<EntityData> dataList, UserConnection connection);
/**
* Returns the entity tracker for the current protocol.
@@ -44,7 +44,9 @@ public class ComponentType extends Type<JsonElement> {
try {
return JsonParser.parseString(s);
} catch (JsonSyntaxException e) {
Via.getPlatform().getLogger().severe("Error when trying to parse json: " + s);
if (Via.getManager().isDebug()) {
Via.getPlatform().getLogger().severe("Error when trying to parse json: " + s);
}
throw e;
}
}
@@ -40,20 +40,20 @@ public final class EntityDataListType extends EntityDataListTypeTemplate {
@Override
public List<EntityData> read(final ByteBuf buffer) {
final List<EntityData> list = new ArrayList<>();
EntityData meta;
EntityData data;
do {
meta = this.type.read(buffer);
if (meta != null) {
list.add(meta);
data = this.type.read(buffer);
if (data != null) {
list.add(data);
}
} while (meta != null);
} while (data != null);
return list;
}
@Override
public void write(final ByteBuf buffer, final List<EntityData> object) {
for (final EntityData metadata : object) {
this.type.write(buffer, metadata);
for (final EntityData data : object) {
this.type.write(buffer, data);
}
this.type.write(buffer, null);
}
@@ -26,14 +26,14 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes;
public final class EntityDataType extends ModernEntityDataType {
private final EntityDataTypes metaTypes;
private final EntityDataTypes dataTypes;
public EntityDataType(final EntityDataTypes metaTypes) {
this.metaTypes = metaTypes;
public EntityDataType(final EntityDataTypes dataTypes) {
this.dataTypes = dataTypes;
}
@Override
protected com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType getType(final int index) {
return metaTypes.byId(index);
return dataTypes.byId(index);
}
}
@@ -33,7 +33,7 @@ public abstract class ModernEntityDataType extends EntityDataTypeTemplate {
@Override
public EntityData read(final ByteBuf buffer) {
final short index = buffer.readUnsignedByte();
if (index == END) return null; // End of metadata
if (index == END) return null; // End of data
final EntityDataType type = this.getType(Types.VAR_INT.readPrimitive(buffer));
return new EntityData(index, type, type.type().read(buffer));
}
@@ -32,7 +32,7 @@ public abstract class OldEntityDataType extends EntityDataTypeTemplate {
@Override
public EntityData read(final ByteBuf buffer) {
final byte index = buffer.readByte();
if (index == END) return null; // End of metadata
if (index == END) return null; // End of data
final EntityDataType type = this.getType((index & 224) >> 5);
return new EntityData(index & 31, type, type.type().read(buffer));
}
@@ -50,7 +50,7 @@ public class StructuredDataType extends Type<StructuredData<?>> {
public StructuredData<?> read(final ByteBuf buffer) {
Preconditions.checkNotNull(types, "StructuredDataType has not been initialized");
final int id = Types.VAR_INT.readPrimitive(buffer);
final StructuredDataKey<?> key = this.types[id];
final StructuredDataKey<?> key = key(id);
if (key == null) {
throw new IllegalArgumentException("No data component serializer found for id " + id);
}
@@ -31,11 +31,11 @@ import java.util.List;
public final class Types1_12 {
/**
* Metadata type for 1.12
* Entity data type for 1.12
*/
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_12();
/**
* Metadata list type for 1.12
* Entity data list type for 1.12
*/
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -33,11 +33,11 @@ import java.util.List;
public final class Types1_8 {
/**
* Metadata type for 1.8
* Entity data type for 1.8
*/
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_8();
/**
* Metadata list type for 1.8
* Entity data list type for 1.8
*/
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
@@ -32,11 +32,11 @@ import java.util.List;
public final class Types1_9 {
/**
* Metadata type for 1.9
* Entity data type for 1.9
*/
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_9();
/**
* Metadata list type for 1.9
* Entity data list type for 1.9
*/
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
@@ -51,13 +51,13 @@ public class EntityToggleGlideListener extends ViaBukkitListener {
if (!isOnPipe(player)) return;
// Cancelling can only be done by updating the player's metadata
// Cancelling can only be done by updating the player's entity data
if (event.isGliding() && event.isCancelled()) {
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_15.SET_ENTITY_DATA, null, getUserConnection(player));
packet.write(Types.VAR_INT, player.getEntityId());
byte bitmask = 0;
// Collect other metadata for the mitmask
// Collect other entity data for the mitmask
if (player.getFireTicks() > 0) {
bitmask |= 0x01;
}
@@ -19,19 +19,20 @@ package com.viaversion.viaversion.bukkit.platform;
import com.viaversion.viaversion.configuration.AbstractViaConfig;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class BukkitViaConfig extends AbstractViaConfig {
private static final List<String> UNSUPPORTED = Arrays.asList("velocity-ping-interval", "velocity-ping-save", "velocity-servers");
private boolean quickMoveActionFix;
private boolean hitboxFix1_9;
private boolean hitboxFix1_14;
private String blockConnectionMethod;
private boolean armorToggleFix;
private boolean registerUserConnectionOnJoin;
private boolean useNewDeathMessages;
private boolean itemCache;
private boolean nmsPlayerTicking;
public BukkitViaConfig(final File folder, final Logger logger) {
super(new File(folder, "config.yml"), logger);
@@ -46,6 +47,9 @@ public class BukkitViaConfig extends AbstractViaConfig {
hitboxFix1_14 = getBoolean("change-1_14-hitbox", false);
blockConnectionMethod = getString("blockconnection-method", "packet");
armorToggleFix = getBoolean("armor-toggle-fix", true);
useNewDeathMessages = getBoolean("use-new-deathmessages", true);
itemCache = getBoolean("item-cache", true);
nmsPlayerTicking = getBoolean("nms-player-ticking", true);
}
@Override
@@ -82,8 +86,23 @@ public class BukkitViaConfig extends AbstractViaConfig {
return armorToggleFix;
}
@Override
public boolean isShowNewDeathMessages() {
return useNewDeathMessages;
}
@Override
public boolean isItemCache() {
return itemCache;
}
@Override
public boolean isNMSPlayerTicking() {
return nmsPlayerTicking;
}
@Override
public List<String> getUnsupportedOptions() {
return UNSUPPORTED;
return VELOCITY_ONLY_OPTIONS;
}
}
@@ -87,7 +87,9 @@ public class BukkitViaLoader implements ViaPlatformLoader {
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_9)) {
new ArmorListener(plugin).register();
new DeathListener(plugin).register();
new BlockListener(plugin).register();
if (plugin.getConf().cancelBlockSounds()) {
new BlockListener(plugin).register();
}
if (plugin.getConf().isItemCache()) {
handItemCache = new HandItemCache();
@@ -67,6 +67,7 @@ public class ViaManagerImpl implements ViaManager {
private final ViaPlatformLoader loader;
private final Set<String> subPlatforms = new HashSet<>();
private List<Runnable> enableListeners = new ArrayList<>();
private List<Runnable> postEnableListeners = new ArrayList<>();
private PlatformTask<?> mappingLoadingTask;
private boolean initialized;
@@ -150,7 +151,7 @@ public class ViaManagerImpl implements ViaManager {
platform.getLogger().warning("and if you're still unsure, feel free to join our Discord-Server for further assistance.");
} else if (protocolVersion.highestSupportedProtocolVersion().olderThan(ProtocolVersion.v1_13)) {
platform.getLogger().warning("This version of Minecraft is extremely outdated and support for it has reached its end of life. "
+ "You will still be able to run Via on this Minecraft version, but we are unlikely to provide any further fixes or help with problems specific to legacy Minecraft versions. "
+ "You will still be able to run Via on this Minecraft version, but we will prioritize issues with legacy Minecraft versions less. "
+ "Please consider updating to give your players a better experience and to avoid issues that have long been fixed.");
}
}
@@ -184,6 +185,11 @@ public class ViaManagerImpl implements ViaManager {
// Refresh Versions
protocolManager.refreshVersions();
for (final Runnable listener : postEnableListeners) {
listener.run();
}
postEnableListeners = null;
}
private void loadServerProtocol() {
@@ -235,7 +241,8 @@ public class ViaManagerImpl implements ViaManager {
if (version < 17) {
platform.getLogger().warning("You are running an outdated Java version, please update it to at least Java 17 (your version is " + javaVersion + ").");
platform.getLogger().warning("Starting with Minecraft 1.21, ViaVersion will no longer officially be compatible with this version of Java, only offering unsupported compatibility builds.");
platform.getLogger().warning("ViaVersion no longer officially supports this version of Java, only offering unsupported compatibility builds.");
platform.getLogger().warning("See https://github.com/ViaVersion/ViaVersion/releases/tag/5.0.0 for more information.");
}
}
@@ -316,25 +323,21 @@ public class ViaManagerImpl implements ViaManager {
return configurationProvider;
}
/**
* Returns a mutable set of self-added subplatform version strings.
* This set is expanded by the subplatform itself (e.g. ViaBackwards), and may not contain all running ones.
*
* @return mutable set of subplatform versions
*/
@Override
public Set<String> getSubPlatforms() {
return subPlatforms;
}
/**
* Adds a runnable to be executed when ViaVersion has finished its init before the full server load.
*
* @param runnable runnable to be executed
*/
@Override
public void addEnableListener(Runnable runnable) {
enableListeners.add(runnable);
}
@Override
public void addPostEnableListener(final Runnable runnable) {
postEnableListeners.add(runnable);
}
@Override
public boolean isInitialized() {
return initialized;
@@ -26,6 +26,7 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.BlockedProtocolVersionsImpl;
import com.viaversion.viaversion.util.Config;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -35,11 +36,15 @@ import it.unimi.dsi.fastutil.objects.ObjectSet;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class AbstractViaConfig extends Config implements ViaVersionConfig {
public static final List<String> BUKKIT_ONLY_OPTIONS = Arrays.asList("register-userconnections-on-join", "quick-move-action-fix",
"change-1_9-hitbox", "change-1_14-hitbox", "blockconnection-method", "armor-toggle-fix", "use-new-deathmessages",
"item-cache", "nms-player-ticking");
public static final List<String> VELOCITY_ONLY_OPTIONS = Arrays.asList("velocity-ping-interval", "velocity-ping-save", "velocity-servers");
private boolean checkForUpdates;
private boolean preventCollision;
private boolean useNewEffectIndicator;
private boolean useNewDeathmessages;
private boolean suppressMetadataErrors;
private boolean shieldBlocking;
private boolean noDelayShieldBlocking;
@@ -57,8 +62,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private String maxPPSWarningsKickMessage;
private boolean sendSupportedVersions;
private boolean simulatePlayerTick;
private boolean itemCache;
private boolean nmsPlayerTicking;
private boolean replacePistons;
private int pistonReplacementId;
private boolean chunkBorderFix;
@@ -69,7 +72,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private String reloadDisconnectMessage;
private boolean suppressConversionWarnings;
private boolean disable1_13TabComplete;
private boolean minimizeCooldown;
private boolean teamColourFix;
private boolean serversideBlockConnections;
private boolean reduceBlockStorageMemory;
@@ -91,6 +93,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean translateOcelotToCat;
private boolean enforceSecureChat;
private boolean handleInvalidItemCount;
private boolean cancelBlockSounds;
protected AbstractViaConfig(final File configFile, final Logger logger) {
super(configFile, logger);
@@ -106,7 +109,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
checkForUpdates = getBoolean("check-for-updates", true);
preventCollision = getBoolean("prevent-collision", true);
useNewEffectIndicator = getBoolean("use-new-effect-indicator", true);
useNewDeathmessages = getBoolean("use-new-deathmessages", true);
suppressMetadataErrors = getBoolean("suppress-metadata-errors", false);
shieldBlocking = getBoolean("shield-blocking", true);
noDelayShieldBlocking = getBoolean("no-delay-shield-blocking", false);
@@ -124,8 +126,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
maxPPSWarningsKickMessage = getString("tracking-max-kick-msg", "You are sending too many packets, :(");
sendSupportedVersions = getBoolean("send-supported-versions", false);
simulatePlayerTick = getBoolean("simulate-pt", true);
itemCache = getBoolean("item-cache", true);
nmsPlayerTicking = getBoolean("nms-player-ticking", true);
replacePistons = getBoolean("replace-pistons", false);
pistonReplacementId = getInt("replacement-piston-id", 0);
chunkBorderFix = getBoolean("chunk-border-fix", false);
@@ -134,7 +134,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
blockedProtocolVersions = loadBlockedProtocolVersions();
blockedDisconnectMessage = getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
reloadDisconnectMessage = getString("reload-disconnect-msg", "Server reload, please rejoin!");
minimizeCooldown = getBoolean("minimize-cooldown", true);
teamColourFix = getBoolean("team-colour-fix", true);
suppressConversionWarnings = getBoolean("suppress-conversion-warnings", false);
disable1_13TabComplete = getBoolean("disable-1_13-auto-complete", false);
@@ -161,6 +160,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
translateOcelotToCat = getBoolean("translate-ocelot-to-cat", true);
enforceSecureChat = getBoolean("enforce-secure-chat", false);
handleInvalidItemCount = getBoolean("handle-invalid-item-count", false);
cancelBlockSounds = getBoolean("cancel-block-sounds", true);
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
@@ -254,7 +254,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
@Override
public boolean isShowNewDeathMessages() {
return useNewDeathmessages;
return false;
}
@Override
@@ -344,12 +344,12 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
@Override
public boolean isItemCache() {
return itemCache;
return false;
}
@Override
public boolean isNMSPlayerTicking() {
return nmsPlayerTicking;
return false;
}
@Override
@@ -403,11 +403,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
return reloadDisconnectMessage;
}
@Override
public boolean isMinimizeCooldown() {
return minimizeCooldown;
}
@Override
public boolean is1_13TeamColourFix() {
return teamColourFix;
@@ -542,4 +537,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
public boolean handleInvalidItemCount() {
return handleInvalidItemCount;
}
@Override
public boolean cancelBlockSounds() {
return cancelBlockSounds;
}
}
@@ -17,10 +17,9 @@
*/
package com.viaversion.viaversion.dump;
import com.viaversion.viaversion.api.protocol.version.VersionType;
import java.util.Set;
public record VersionInfo(String javaVersion, String operatingSystem, VersionType versionType,
public record VersionInfo(String javaVersion, String operatingSystem,
int serverProtocol, String serverVersion,
Set<String> enabledProtocols, String platformName,
String platformVersion, String pluginVersion,
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.legacy.bossbar;
import com.google.common.base.Preconditions;
import com.google.common.collect.MapMaker;
import com.google.gson.JsonParser;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.legacy.bossbar.BossBar;
@@ -26,7 +27,6 @@ import com.viaversion.viaversion.api.legacy.bossbar.BossColor;
import com.viaversion.viaversion.api.legacy.bossbar.BossFlag;
import com.viaversion.viaversion.api.legacy.bossbar.BossStyle;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
@@ -246,28 +246,32 @@ public class CommonBoss implements BossBar {
wrapper.write(Types.UUID, uuid);
wrapper.write(Types.VAR_INT, action.getId());
switch (action) {
case ADD:
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(title));
case ADD -> {
try {
wrapper.write(Types.COMPONENT, JsonParser.parseString(this.title));
} catch (Exception e) {
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(this.title));
}
wrapper.write(Types.FLOAT, health);
wrapper.write(Types.VAR_INT, color.getId());
wrapper.write(Types.VAR_INT, style.getId());
wrapper.write(Types.BYTE, (byte) flagToBytes());
break;
case REMOVE:
break;
case UPDATE_HEALTH:
wrapper.write(Types.FLOAT, health);
break;
case UPDATE_TITLE:
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(title));
break;
case UPDATE_STYLE:
}
case REMOVE -> {
}
case UPDATE_HEALTH -> wrapper.write(Types.FLOAT, health);
case UPDATE_TITLE -> {
try {
wrapper.write(Types.COMPONENT, JsonParser.parseString(this.title));
} catch (Exception e) {
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(this.title));
}
}
case UPDATE_STYLE -> {
wrapper.write(Types.VAR_INT, color.getId());
wrapper.write(Types.VAR_INT, style.getId());
break;
case UPDATE_FLAGS:
wrapper.write(Types.BYTE, (byte) flagToBytes());
break;
}
case UPDATE_FLAGS -> wrapper.write(Types.BYTE, (byte) flagToBytes());
}
return wrapper;
@@ -52,4 +52,7 @@ public class RedirectProtocolVersion extends ProtocolVersion {
};
}
public ProtocolVersion getOrigin() {
return origin;
}
}
@@ -61,15 +61,21 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
wrapper.passthrough(Types.UNSIGNED_SHORT); // Server Port
int state = wrapper.passthrough(Types.VAR_INT);
ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setProtocolVersion(ProtocolVersion.getProtocol(protocolVersion));
// Ensure the server has a version provider
VersionProvider versionProvider = Via.getManager().getProviders().get(VersionProvider.class);
// Ensure the server has a version provider
if (versionProvider == null) {
wrapper.user().setActive(false);
return;
}
ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setProtocolVersion(ProtocolVersion.getProtocol(protocolVersion));
ProtocolVersion clientVersion = versionProvider.getClientProtocol(wrapper.user());
if (clientVersion != null) {
info.setProtocolVersion(clientVersion);
}
// Choose the pipe
ProtocolVersion serverProtocol;
try {
@@ -20,6 +20,7 @@ package com.viaversion.viaversion.protocols.v1_10to1_11.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11.EntityType;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
@@ -53,8 +54,20 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.BYTE); // 2 - Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - Data
// Track Entity
handler(wrapper -> {
byte type = wrapper.get(Types.BYTE, 0);
if (type == EntityTypes1_10.ObjectType.FISHIHNG_HOOK.getId()) {
tryFixFishingHookVelocity(wrapper);
}
});
handler(objectTrackerHandler());
}
});
@@ -74,7 +87,7 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_9.ENTITY_DATA_LIST); // 12 - Metadata
map(Types1_9.ENTITY_DATA_LIST); // 12 - Entity data
handler(wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
@@ -132,6 +145,13 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.SET_ENTITY_MOTION, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
if (tracker(wrapper.user()).entityType(entityId) == EntityTypes1_10.EntityType.FISHING_HOOK) {
tryFixFishingHookVelocity(wrapper);
}
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_9_3.BLOCK_ENTITY_DATA, new PacketHandlers() {
@@ -159,50 +179,50 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
if (meta.getValue() instanceof DataItem) {
filter().handler((event, data) -> {
if (data.getValue() instanceof DataItem) {
// Apply rewrite
EntityMappings1_11.toClientItem(meta.value());
EntityMappings1_11.toClientItem(data.value());
}
});
filter().type(EntityType.GUARDIAN).index(12).handler((event, meta) -> {
boolean value = (((byte) meta.getValue()) & 0x02) == 0x02;
meta.setTypeAndValue(EntityDataTypes1_9.BOOLEAN, value);
filter().type(EntityType.GUARDIAN).index(12).handler((event, data) -> {
boolean value = (((byte) data.getValue()) & 0x02) == 0x02;
data.setTypeAndValue(EntityDataTypes1_9.BOOLEAN, value);
});
filter().type(EntityType.ABSTRACT_SKELETON).removeIndex(12);
filter().type(EntityType.ZOMBIE).handler((event, meta) -> {
if ((event.entityType() == EntityType.ZOMBIE || event.entityType() == EntityType.HUSK) && meta.id() == 14) {
filter().type(EntityType.ZOMBIE).handler((event, data) -> {
if ((event.entityType() == EntityType.ZOMBIE || event.entityType() == EntityType.HUSK) && data.id() == 14) {
event.cancel();
} else if (meta.id() == 15) {
meta.setId(14);
} else if (data.id() == 15) {
data.setId(14);
}
});
filter().type(EntityType.ABSTRACT_HORSE).handler((event, metadata) -> {
filter().type(EntityType.ABSTRACT_HORSE).handler((event, data) -> {
final com.viaversion.viaversion.api.minecraft.entities.EntityType type = event.entityType();
int id = metadata.id();
int id = data.id();
if (id == 14) { // Type
event.cancel();
return;
}
if (id == 16) { // Owner
metadata.setId(14);
data.setId(14);
} else if (id == 17) { // Armor
metadata.setId(16);
data.setId(16);
}
// Process per type
if (!type.is(EntityType.HORSE) && metadata.id() == 15 || metadata.id() == 16) {
if (!type.is(EntityType.HORSE) && data.id() == 15 || data.id() == 16) {
event.cancel();
return;
}
if ((type == EntityType.DONKEY || type == EntityType.MULE) && metadata.id() == 13) {
if ((((byte) metadata.getValue()) & 0x08) == 0x08) {
if ((type == EntityType.DONKEY || type == EntityType.MULE) && data.id() == 13) {
if ((((byte) data.getValue()) & 0x08) == 0x08) {
event.createExtraData(new EntityData(15, EntityDataTypes1_9.BOOLEAN, true));
} else {
event.createExtraData(new EntityData(15, EntityDataTypes1_9.BOOLEAN, false));
@@ -210,7 +230,7 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
}
});
filter().type(EntityType.ARMOR_STAND).index(0).handler((event, meta) -> {
filter().type(EntityType.ARMOR_STAND).index(0).handler((event, data) -> {
if (!Via.getConfig().isHologramPatch()) {
return;
}
@@ -222,9 +242,9 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
return;
}
byte data = meta.value();
byte value = data.value();
// Check invisible | Check small | Check if custom name is empty | Check if custom name visible is true
if ((data & 0x20) == 0x20 && ((byte) flags.getValue() & 0x01) == 0x01
if ((value & 0x20) == 0x20 && ((byte) flags.getValue() & 0x01) == 0x01
&& !((String) customName.getValue()).isEmpty() && (boolean) customNameVisible.getValue()) {
EntityTracker1_11 tracker = tracker(event.user());
int entityId = event.entityId();
@@ -243,6 +263,17 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
});
}
private void tryFixFishingHookVelocity(final PacketWrapper wrapper) {
// TODO Fix properly
// Velocity handling of this changed on the client, this code still isn't entirely correct
final short x = wrapper.read(Types.SHORT);
final short y = wrapper.read(Types.SHORT);
final short z = wrapper.read(Types.SHORT);
wrapper.write(Types.SHORT, (short) (x * 1.33));
wrapper.write(Types.SHORT, (short) (y * 1.2));
wrapper.write(Types.SHORT, (short) (z * 1.33));
}
@Override
public com.viaversion.viaversion.api.minecraft.entities.EntityType typeFromId(int type) {
return EntityTypes1_11.getTypeFromId(type, false);
@@ -253,17 +284,17 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
return EntityTypes1_11.getTypeFromId(type, true);
}
public EntityType rewriteEntityType(int numType, List<EntityData> metadata) {
public EntityType rewriteEntityType(int numType, List<EntityData> entityData) {
EntityType type = EntityType.findById(numType);
if (type == null) {
Via.getManager().getPlatform().getLogger().severe("Error: could not find Entity type " + numType + " with metadata: " + metadata);
Via.getManager().getPlatform().getLogger().severe("Error: could not find Entity type " + numType + " with entity data: " + entityData);
return null;
}
try {
if (type.is(EntityType.GUARDIAN)) {
// ElderGuardian - 4
Optional<EntityData> options = getById(metadata, 12);
Optional<EntityData> options = getById(entityData, 12);
if (options.isPresent()) {
if ((((byte) options.get().getValue()) & 0x04) == 0x04) {
return EntityType.ELDER_GUARDIAN;
@@ -273,7 +304,7 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
if (type.is(EntityType.SKELETON)) {
// WitherSkeleton - 5
// Stray - 6
Optional<EntityData> options = getById(metadata, 12);
Optional<EntityData> options = getById(entityData, 12);
if (options.isPresent()) {
if (((int) options.get().getValue()) == 1) {
return EntityType.WITHER_SKELETON;
@@ -286,11 +317,11 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
if (type.is(EntityType.ZOMBIE)) {
// ZombieVillager - 27
// Husk - 23
Optional<EntityData> options = getById(metadata, 13);
Optional<EntityData> options = getById(entityData, 13);
if (options.isPresent()) {
int value = (int) options.get().getValue();
if (value > 0 && value < 6) {
metadata.add(new EntityData(16, EntityDataTypes1_9.VAR_INT, value - 1)); // Add profession type to new metadata
entityData.add(new EntityData(16, EntityDataTypes1_9.VAR_INT, value - 1)); // Add profession type to new entity data
return EntityType.ZOMBIE_VILLAGER;
}
if (value == 6) {
@@ -303,7 +334,7 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
// ZombieHorse - 29
// Donkey - 31
// Mule - 32
Optional<EntityData> options = getById(metadata, 14);
Optional<EntityData> options = getById(entityData, 14);
if (options.isPresent()) {
if (((int) options.get().getValue()) == 0) {
return EntityType.HORSE;
@@ -325,7 +356,7 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
} catch (Exception e) {
if (!Via.getConfig().isSuppressMetadataErrors() || Via.getManager().isDebug()) {
protocol.getLogger().warning("An error occurred with entity type rewriter");
protocol.getLogger().warning("Metadata: " + metadata);
protocol.getLogger().warning("Entity data: " + entityData);
protocol.getLogger().log(Level.WARNING, "Error: ", e);
}
}
@@ -333,9 +364,9 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
return type;
}
public Optional<EntityData> getById(List<EntityData> metadatas, int id) {
for (EntityData metadata : metadatas) {
if (metadata.id() == id) return Optional.of(metadata);
public Optional<EntityData> getById(List<EntityData> entityData, int id) {
for (EntityData data : entityData) {
if (data.id() == id) return Optional.of(data);
}
return Optional.empty();
}
@@ -46,6 +46,8 @@ public final class ChatItemRewriter {
}
} else if (obj.has("extra")) {
toClient(obj.get("extra"));
} else if (obj.has("translate") && obj.has("with")) {
toClient(obj.get("with"));
}
} else if (element instanceof final JsonArray array) {
for (JsonElement value : array) {
@@ -62,9 +62,9 @@ public class EntityPacketRewriter1_12 extends EntityRewriter<ClientboundPackets1
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_12.ENTITY_DATA_LIST); // 12 - Metadata
map(Types1_12.ENTITY_DATA_LIST); // 12 - Entity data
// Track mob and rewrite metadata
// Track mob and rewrite entity data
handler(trackerAndRewriterHandler(Types1_12.ENTITY_DATA_LIST));
}
});
@@ -75,9 +75,9 @@ public class EntityPacketRewriter1_12 extends EntityRewriter<ClientboundPackets1
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
if (meta.getValue() instanceof Item) {
meta.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), meta.value()));
filter().handler((event, data) -> {
if (data.getValue() instanceof Item) {
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), data.value()));
}
});
@@ -779,7 +779,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
// Clone item arrays because array and item are mutable, also make sure the array type is the interface
switch (recipe.type()) {
case "crafting_shapeless": {
case "crafting_shapeless" -> {
recipesPacket.write(Types.STRING, recipe.group());
recipesPacket.write(Types.VAR_INT, recipe.ingredients().length);
for (Item[] ingredient : recipe.ingredients()) {
@@ -791,9 +791,8 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
recipesPacket.write(Types.ITEM1_13_ARRAY, clone);
}
recipesPacket.write(Types.ITEM1_13, recipe.result().copy());
break;
}
case "crafting_shaped": {
case "crafting_shaped" -> {
recipesPacket.write(Types.VAR_INT, recipe.width());
recipesPacket.write(Types.VAR_INT, recipe.height());
recipesPacket.write(Types.STRING, recipe.group());
@@ -806,9 +805,8 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
recipesPacket.write(Types.ITEM1_13_ARRAY, clone);
}
recipesPacket.write(Types.ITEM1_13, recipe.result().copy());
break;
}
case "smelting": {
case "smelting" -> {
recipesPacket.write(Types.STRING, recipe.group());
Item[] ingredient = new Item[recipe.ingredient().length];
for (int i = 0; i < ingredient.length; i++) {
@@ -819,7 +817,6 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
recipesPacket.write(Types.ITEM1_13, recipe.result().copy());
recipesPacket.write(Types.FLOAT, recipe.experience());
recipesPacket.write(Types.VAR_INT, recipe.cookingTime());
break;
}
}
}
@@ -922,4 +919,4 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
public ComponentRewriter1_13 getComponentRewriter() {
return componentRewriter;
}
}
}
@@ -61,23 +61,14 @@ public class StairConnectionHandler implements ConnectionHandler {
byte shape;
switch (blockData.getValue("shape")) {
case "straight":
shape = 0;
break;
case "inner_left":
shape = 1;
break;
case "inner_right":
shape = 2;
break;
case "outer_left":
shape = 3;
break;
case "outer_right":
shape = 4;
break;
default:
case "straight" -> shape = 0;
case "inner_left" -> shape = 1;
case "inner_right" -> shape = 2;
case "outer_left" -> shape = 3;
case "outer_right" -> shape = 4;
default -> {
return;
}
}
StairData stairData = new StairData(
@@ -102,7 +102,7 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_12.ENTITY_DATA_LIST, Types1_13.ENTITY_DATA_LIST); // 12 - Metadata
map(Types1_12.ENTITY_DATA_LIST, Types1_13.ENTITY_DATA_LIST); // 12 - Entity data
handler(trackerAndRewriterHandler(Types1_13.ENTITY_DATA_LIST));
}
@@ -118,7 +118,7 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_12.ENTITY_DATA_LIST, Types1_13.ENTITY_DATA_LIST); // 7 - Metadata
map(Types1_12.ENTITY_DATA_LIST, Types1_13.ENTITY_DATA_LIST); // 7 - Entity data
handler(trackerAndRewriterHandler(Types1_13.ENTITY_DATA_LIST, EntityTypes1_13.EntityType.PLAYER));
}
@@ -167,55 +167,55 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
@Override
protected void registerRewrites() {
filter().mapDataType(typeId -> Types1_13.ENTITY_DATA_TYPES.byId(typeId > 4 ? typeId + 1 : typeId));
filter().dataType(Types1_13.ENTITY_DATA_TYPES.itemType).handler(((event, meta) -> protocol.getItemRewriter().handleItemToClient(event.user(), meta.value())));
filter().dataType(Types1_13.ENTITY_DATA_TYPES.optionalBlockStateType).handler(((event, meta) -> {
final int oldId = meta.value();
filter().dataType(Types1_13.ENTITY_DATA_TYPES.itemType).handler(((event, data) -> protocol.getItemRewriter().handleItemToClient(event.user(), data.value())));
filter().dataType(Types1_13.ENTITY_DATA_TYPES.optionalBlockStateType).handler(((event, data) -> {
final int oldId = data.value();
if (oldId != 0) {
final int combined = (((oldId & 4095) << 4) | (oldId >> 12 & 15));
final int newId = WorldPacketRewriter1_13.toNewId(combined);
meta.setValue(newId);
data.setValue(newId);
}
}));
// Previously unused, now swimming
filter().index(0).handler((event, meta) -> meta.setValue((byte) ((byte) meta.getValue() & ~0x10)));
filter().index(0).handler((event, data) -> data.setValue((byte) ((byte) data.getValue() & ~0x10)));
filter().index(2).handler(((event, meta) -> {
if (meta.getValue() != null && !((String) meta.getValue()).isEmpty()) {
meta.setTypeAndValue(Types1_13.ENTITY_DATA_TYPES.optionalComponentType, ComponentUtil.legacyToJson((String) meta.getValue()));
filter().index(2).handler(((event, data) -> {
if (data.getValue() != null && !((String) data.getValue()).isEmpty()) {
data.setTypeAndValue(Types1_13.ENTITY_DATA_TYPES.optionalComponentType, ComponentUtil.legacyToJson((String) data.getValue()));
} else {
meta.setTypeAndValue(Types1_13.ENTITY_DATA_TYPES.optionalComponentType, null);
data.setTypeAndValue(Types1_13.ENTITY_DATA_TYPES.optionalComponentType, null);
}
}));
filter().type(EntityTypes1_13.EntityType.WOLF).index(17).handler((event, meta) -> {
filter().type(EntityTypes1_13.EntityType.WOLF).index(17).handler((event, data) -> {
// Handle new colors
meta.setValue(15 - (int) meta.getValue());
data.setValue(15 - (int) data.getValue());
});
filter().type(EntityTypes1_13.EntityType.ZOMBIE).addIndex(15); // Shaking
filter().type(EntityTypes1_13.EntityType.ABSTRACT_MINECART).index(9).handler((event, meta) -> {
final int oldId = meta.value();
filter().type(EntityTypes1_13.EntityType.ABSTRACT_MINECART).index(9).handler((event, data) -> {
final int oldId = data.value();
final int combined = (((oldId & 4095) << 4) | (oldId >> 12 & 15));
final int newId = WorldPacketRewriter1_13.toNewId(combined);
meta.setValue(newId);
data.setValue(newId);
});
filter().type(EntityTypes1_13.EntityType.AREA_EFFECT_CLOUD).handler((event, meta) -> {
if (meta.id() == 9) {
int particleId = meta.value();
EntityData parameter1Meta = event.dataAtIndex(10);
EntityData parameter2Meta = event.dataAtIndex(11);
int parameter1 = parameter1Meta != null ? parameter1Meta.value() : 0;
int parameter2 = parameter2Meta != null ? parameter2Meta.value() : 0;
filter().type(EntityTypes1_13.EntityType.AREA_EFFECT_CLOUD).handler((event, data) -> {
if (data.id() == 9) {
int particleId = data.value();
EntityData parameter1Data = event.dataAtIndex(10);
EntityData parameter2Data = event.dataAtIndex(11);
int parameter1 = parameter1Data != null ? parameter1Data.value() : 0;
int parameter2 = parameter2Data != null ? parameter2Data.value() : 0;
Particle particle = ParticleIdMappings1_13.rewriteParticle(particleId, new Integer[]{parameter1, parameter2});
if (particle != null && particle.id() != -1) {
event.createExtraData(new EntityData(9, Types1_13.ENTITY_DATA_TYPES.particleType, particle));
}
}
if (meta.id() >= 9) {
if (data.id() >= 9) {
event.cancel();
}
});
@@ -453,30 +453,22 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
public static String getNewPluginChannelId(String old) {
// Default channels that should not be modifiable
switch (old) {
case "MC|TrList":
return "minecraft:trader_list";
case "MC|Brand":
return "minecraft:brand";
case "MC|BOpen":
return "minecraft:book_open";
case "MC|DebugPath":
return "minecraft:debug/paths";
case "MC|DebugNeighborsUpdate":
return "minecraft:debug/neighbors_update";
case "REGISTER":
return "minecraft:register";
case "UNREGISTER":
return "minecraft:unregister";
case "BungeeCord":
return "bungeecord:main";
case "bungeecord:main":
return null;
default:
return switch (old) {
case "MC|TrList" -> "minecraft:trader_list";
case "MC|Brand" -> "minecraft:brand";
case "MC|BOpen" -> "minecraft:book_open";
case "MC|DebugPath" -> "minecraft:debug/paths";
case "MC|DebugNeighborsUpdate" -> "minecraft:debug/neighbors_update";
case "REGISTER" -> "minecraft:register";
case "UNREGISTER" -> "minecraft:unregister";
case "BungeeCord" -> "bungeecord:main";
case "bungeecord:main" -> null;
default -> {
String mappedChannel = Protocol1_12_2To1_13.MAPPINGS.getChannelMappings().get(old);
if (mappedChannel != null) return mappedChannel;
return MappingData1_13.validateNewChannel(old);
}
if (mappedChannel != null) yield mappedChannel;
yield MappingData1_13.validateNewChannel(old);
}
};
}
@Override
@@ -687,28 +679,21 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
if (newId == null) return null;
// Default channels that should not be modifiable
switch (newId) {
case "minecraft:trader_list":
return "MC|TrList";
case "minecraft:book_open":
return "MC|BOpen";
case "minecraft:debug/paths":
return "MC|DebugPath";
case "minecraft:debug/neighbors_update":
return "MC|DebugNeighborsUpdate";
case "minecraft:register":
return "REGISTER";
case "minecraft:unregister":
return "UNREGISTER";
case "minecraft:brand":
return "MC|Brand";
case "bungeecord:main":
return "BungeeCord";
default:
return switch (newId) {
case "minecraft:trader_list" -> "MC|TrList";
case "minecraft:book_open" -> "MC|BOpen";
case "minecraft:debug/paths" -> "MC|DebugPath";
case "minecraft:debug/neighbors_update" -> "MC|DebugNeighborsUpdate";
case "minecraft:register" -> "REGISTER";
case "minecraft:unregister" -> "UNREGISTER";
case "minecraft:brand" -> "MC|Brand";
case "bungeecord:main" -> "BungeeCord";
default -> {
String mappedChannel = Protocol1_12_2To1_13.MAPPINGS.getChannelMappings().inverse().get(newId);
if (mappedChannel != null) return mappedChannel;
return newId.length() > 20 ? newId.substring(0, 20) : newId;
}
if (mappedChannel != null) yield mappedChannel;
yield newId.length() > 20 ? newId.substring(0, 20) : newId;
}
};
}
public static boolean isDamageable(int id) {
@@ -724,4 +709,4 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
|| id == 442 // shield
|| id == 443; // elytra
}
}
}
@@ -29,9 +29,9 @@ import com.viaversion.viaversion.protocols.v1_13_1to1_13_2.Protocol1_13_1To1_13_
public class EntityPacketRewriter1_13_2 {
public static void register(Protocol1_13_1To1_13_2 protocol) {
final PacketHandler metaTypeHandler = wrapper -> {
for (EntityData metadata : wrapper.get(Types1_13_2.ENTITY_DATA_LIST, 0)) {
metadata.setDataType(Types1_13_2.ENTITY_DATA_TYPES.byId(metadata.dataType().typeId()));
final PacketHandler dataTypeHandler = wrapper -> {
for (EntityData data : wrapper.get(Types1_13_2.ENTITY_DATA_LIST, 0)) {
data.setDataType(Types1_13_2.ENTITY_DATA_TYPES.byId(data.dataType().typeId()));
}
};
@@ -50,9 +50,9 @@ public class EntityPacketRewriter1_13_2 {
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_13.ENTITY_DATA_LIST, Types1_13_2.ENTITY_DATA_LIST); // 12 - Metadata
map(Types1_13.ENTITY_DATA_LIST, Types1_13_2.ENTITY_DATA_LIST); // 12 - Entity data
handler(metaTypeHandler);
handler(dataTypeHandler);
}
});
@@ -66,9 +66,9 @@ public class EntityPacketRewriter1_13_2 {
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_13.ENTITY_DATA_LIST, Types1_13_2.ENTITY_DATA_LIST); // 7 - Metadata
map(Types1_13.ENTITY_DATA_LIST, Types1_13_2.ENTITY_DATA_LIST); // 7 - Entity data
handler(metaTypeHandler);
handler(dataTypeHandler);
}
});
@@ -76,9 +76,9 @@ public class EntityPacketRewriter1_13_2 {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types1_13.ENTITY_DATA_LIST, Types1_13_2.ENTITY_DATA_LIST); // 1 - Metadata list
map(Types1_13.ENTITY_DATA_LIST, Types1_13_2.ENTITY_DATA_LIST); // 1 - Entity data list
handler(metaTypeHandler);
handler(dataTypeHandler);
}
});
}
@@ -105,7 +105,7 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
wrapper.set(Types.INT, 0, data - 1);
}
// send velocity in separate packet, 1.14 is now ignoring the velocity
PacketWrapper velocity = wrapper.create(0x45);
PacketWrapper velocity = wrapper.create(ClientboundPackets1_14.SET_ENTITY_MOTION);
velocity.write(Types.VAR_INT, entityId);
velocity.write(Types.SHORT, wrapper.get(Types.SHORT, 0));
velocity.write(Types.SHORT, wrapper.get(Types.SHORT, 1));
@@ -137,7 +137,7 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_13_2.ENTITY_DATA_LIST, Types1_14.ENTITY_DATA_LIST); // 12 - Metadata
map(Types1_13_2.ENTITY_DATA_LIST, Types1_14.ENTITY_DATA_LIST); // 12 - Entity data
handler(trackerAndRewriterHandler(Types1_14.ENTITY_DATA_LIST));
}
@@ -165,7 +165,7 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_13_2.ENTITY_DATA_LIST, Types1_14.ENTITY_DATA_LIST); // 7 - Metadata
map(Types1_13_2.ENTITY_DATA_LIST, Types1_14.ENTITY_DATA_LIST); // 7 - Entity data
handler(trackerAndRewriterHandler(Types1_14.ENTITY_DATA_LIST, EntityTypes1_14.PLAYER));
}
@@ -182,15 +182,15 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
int entityId = wrapper.get(Types.VAR_INT, 0);
tracker.setSleeping(entityId, false);
PacketWrapper metadataPacket = wrapper.create(ClientboundPackets1_14.SET_ENTITY_DATA);
metadataPacket.write(Types.VAR_INT, entityId);
List<EntityData> metadataList = new ArrayList<>();
PacketWrapper entityDataPacket = wrapper.create(ClientboundPackets1_14.SET_ENTITY_DATA);
entityDataPacket.write(Types.VAR_INT, entityId);
List<EntityData> entityDataList = new ArrayList<>();
if (tracker.clientEntityId() != entityId) {
metadataList.add(new EntityData(6, Types1_14.ENTITY_DATA_TYPES.poseType, EntityPacketRewriter1_14.recalculatePlayerPose(entityId, tracker)));
entityDataList.add(new EntityData(6, Types1_14.ENTITY_DATA_TYPES.poseType, EntityPacketRewriter1_14.recalculatePlayerPose(entityId, tracker)));
}
metadataList.add(new EntityData(12, Types1_14.ENTITY_DATA_TYPES.optionalBlockPositionType, null));
metadataPacket.write(Types1_14.ENTITY_DATA_LIST, metadataList);
metadataPacket.scheduleSend(Protocol1_13_2To1_14.class);
entityDataList.add(new EntityData(12, Types1_14.ENTITY_DATA_TYPES.optionalBlockPositionType, null));
entityDataPacket.write(Types1_14.ENTITY_DATA_LIST, entityDataList);
entityDataPacket.scheduleSend(Protocol1_13_2To1_14.class);
}
});
}
@@ -242,12 +242,12 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
tracker.setSleeping(entityId, true);
BlockPosition position = wrapper.read(Types.BLOCK_POSITION1_8);
List<EntityData> metadataList = new ArrayList<>();
metadataList.add(new EntityData(12, Types1_14.ENTITY_DATA_TYPES.optionalBlockPositionType, position));
List<EntityData> entityDataList = new ArrayList<>();
entityDataList.add(new EntityData(12, Types1_14.ENTITY_DATA_TYPES.optionalBlockPositionType, position));
if (tracker.clientEntityId() != entityId) {
metadataList.add(new EntityData(6, Types1_14.ENTITY_DATA_TYPES.poseType, EntityPacketRewriter1_14.recalculatePlayerPose(entityId, tracker)));
entityDataList.add(new EntityData(6, Types1_14.ENTITY_DATA_TYPES.poseType, EntityPacketRewriter1_14.recalculatePlayerPose(entityId, tracker)));
}
wrapper.write(Types1_14.ENTITY_DATA_LIST, metadataList);
wrapper.write(Types1_14.ENTITY_DATA_LIST, entityDataList);
});
}
});
@@ -267,55 +267,55 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
filter().type(EntityTypes1_14.LIVING_ENTITY).addIndex(12);
filter().type(EntityTypes1_14.LIVING_ENTITY).index(8).handler((event, meta) -> {
float value = ((Number) meta.getValue()).floatValue();
filter().type(EntityTypes1_14.LIVING_ENTITY).index(8).handler((event, data) -> {
float value = ((Number) data.getValue()).floatValue();
if (Float.isNaN(value) && Via.getConfig().is1_14HealthNaNFix()) {
meta.setValue(1F);
data.setValue(1F);
}
});
filter().type(EntityTypes1_14.MOB).index(13).handler((event, meta) -> {
filter().type(EntityTypes1_14.MOB).index(13).handler((event, data) -> {
EntityTracker1_14 tracker = tracker(event.user());
int entityId = event.entityId();
tracker.setInsentientData(entityId, (byte) ((((Number) meta.getValue()).byteValue() & ~0x4)
| (tracker.getInsentientData(entityId) & 0x4))); // New attacking metadata
meta.setValue(tracker.getInsentientData(entityId));
tracker.setInsentientData(entityId, (byte) ((((Number) data.getValue()).byteValue() & ~0x4)
| (tracker.getInsentientData(entityId) & 0x4))); // New attacking entity data
data.setValue(tracker.getInsentientData(entityId));
});
filter().type(EntityTypes1_14.PLAYER).handler((event, meta) -> {
filter().type(EntityTypes1_14.PLAYER).handler((event, data) -> {
EntityTracker1_14 tracker = tracker(event.user());
int entityId = event.entityId();
if (entityId != tracker.clientEntityId()) {
if (meta.id() == 0) {
byte flags = ((Number) meta.getValue()).byteValue();
if (data.id() == 0) {
byte flags = ((Number) data.getValue()).byteValue();
// Mojang overrides the client-side pose updater, see OtherPlayerEntity#updateSize
tracker.setEntityFlags(entityId, flags);
} else if (meta.id() == 7) {
tracker.setRiptide(entityId, (((Number) meta.getValue()).byteValue() & 0x4) != 0);
} else if (data.id() == 7) {
tracker.setRiptide(entityId, (((Number) data.getValue()).byteValue() & 0x4) != 0);
}
if (meta.id() == 0 || meta.id() == 7) {
if (data.id() == 0 || data.id() == 7) {
event.createExtraData(new EntityData(6, Types1_14.ENTITY_DATA_TYPES.poseType, recalculatePlayerPose(entityId, tracker)));
}
}
});
filter().type(EntityTypes1_14.ZOMBIE).handler((event, meta) -> {
if (meta.id() == 16) {
filter().type(EntityTypes1_14.ZOMBIE).handler((event, data) -> {
if (data.id() == 16) {
EntityTracker1_14 tracker = tracker(event.user());
int entityId = event.entityId();
tracker.setInsentientData(entityId, (byte) ((tracker.getInsentientData(entityId) & ~0x4)
| ((boolean) meta.getValue() ? 0x4 : 0))); // New attacking
| ((boolean) data.getValue() ? 0x4 : 0))); // New attacking
event.createExtraData(new EntityData(13, Types1_14.ENTITY_DATA_TYPES.byteType, tracker.getInsentientData(entityId)));
event.cancel(); // "Are hands held up"
} else if (meta.id() > 16) {
meta.setId(meta.id() - 1);
} else if (data.id() > 16) {
data.setId(data.id() - 1);
}
});
filter().type(EntityTypes1_14.HORSE).index(18).handler((event, meta) -> {
filter().type(EntityTypes1_14.HORSE).index(18).handler((event, data) -> {
event.cancel();
int armorType = meta.value();
int armorType = data.value();
Item armorItem = null;
if (armorType == 1) { //iron armor
armorItem = new DataItem(protocol.getMappingData().getNewItemId(727), (byte) 1, null);
@@ -336,42 +336,42 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
}
});
filter().type(EntityTypes1_14.VILLAGER).index(15).handler((event, meta) -> {
meta.setTypeAndValue(Types1_14.ENTITY_DATA_TYPES.villagerDatatType, new VillagerData(2, getNewProfessionId(meta.value()), 0));
filter().type(EntityTypes1_14.VILLAGER).index(15).handler((event, data) -> {
data.setTypeAndValue(Types1_14.ENTITY_DATA_TYPES.villagerDatatType, new VillagerData(2, getNewProfessionId(data.value()), 0));
});
filter().type(EntityTypes1_14.ZOMBIE_VILLAGER).index(18).handler((event, meta) -> {
meta.setTypeAndValue(Types1_14.ENTITY_DATA_TYPES.villagerDatatType, new VillagerData(2, getNewProfessionId(meta.value()), 0));
filter().type(EntityTypes1_14.ZOMBIE_VILLAGER).index(18).handler((event, data) -> {
data.setTypeAndValue(Types1_14.ENTITY_DATA_TYPES.villagerDatatType, new VillagerData(2, getNewProfessionId(data.value()), 0));
});
filter().type(EntityTypes1_14.ABSTRACT_ARROW).addIndex(9); // Piercing level added
filter().type(EntityTypes1_14.FIREWORK_ROCKET).index(8).handler((event, meta) -> {
meta.setDataType(Types1_14.ENTITY_DATA_TYPES.optionalVarIntType);
if (meta.getValue().equals(0)) {
meta.setValue(null); // https://bugs.mojang.com/browse/MC-111480
filter().type(EntityTypes1_14.FIREWORK_ROCKET).index(8).handler((event, data) -> {
data.setDataType(Types1_14.ENTITY_DATA_TYPES.optionalVarIntType);
if (data.getValue().equals(0)) {
data.setValue(null); // https://bugs.mojang.com/browse/MC-111480
}
});
filter().type(EntityTypes1_14.ABSTRACT_SKELETON).index(14).handler((event, meta) -> {
filter().type(EntityTypes1_14.ABSTRACT_SKELETON).index(14).handler((event, data) -> {
EntityTracker1_14 tracker = tracker(event.user());
int entityId = event.entityId();
tracker.setInsentientData(entityId, (byte) ((tracker.getInsentientData(entityId) & ~0x4)
| ((boolean) meta.getValue() ? 0x4 : 0))); // New attacking
| ((boolean) data.getValue() ? 0x4 : 0))); // New attacking
event.createExtraData(new EntityData(13, Types1_14.ENTITY_DATA_TYPES.byteType, tracker.getInsentientData(entityId)));
event.cancel(); // "Is swinging arms"
});
filter().type(EntityTypes1_14.ABSTRACT_ILLAGER).handler((event, meta) -> {
filter().type(EntityTypes1_14.ABSTRACT_ILLAGER).handler((event, data) -> {
if (event.index() == 14) {
EntityTracker1_14 tracker = tracker(event.user());
int entityId = event.entityId();
tracker.setInsentientData(entityId, (byte) ((tracker.getInsentientData(entityId) & ~0x4)
| (((Number) meta.getValue()).byteValue() != 0 ? 0x4 : 0))); // New attacking
| (((Number) data.getValue()).byteValue() != 0 ? 0x4 : 0))); // New attacking
event.createExtraData(new EntityData(13, Types1_14.ENTITY_DATA_TYPES.byteType, tracker.getInsentientData(entityId)));
event.cancel(); // "Has target (aggressive state)"
} else if (event.index() > 14) {
meta.setId(meta.id() - 1);
data.setId(data.id() - 1);
}
});
@@ -86,42 +86,21 @@ public class ItemPacketRewriter1_14 extends ItemRewriter<ClientboundPackets1_13,
int typeId = -1;
switch (type) {
case "minecraft:crafting_table":
typeId = 11;
break;
case "minecraft:furnace":
typeId = 13;
break;
case "minecraft:dropper", "minecraft:dispenser":
typeId = 6;
break;
case "minecraft:enchanting_table":
typeId = 12;
break;
case "minecraft:brewing_stand":
typeId = 10;
break;
case "minecraft:villager":
typeId = 18;
break;
case "minecraft:beacon":
typeId = 8;
break;
case "minecraft:anvil":
typeId = 7;
break;
case "minecraft:hopper":
typeId = 15;
break;
case "minecraft:shulker_box":
typeId = 19;
break;
case "minecraft:container", "minecraft:chest":
default:
case "minecraft:crafting_table" -> typeId = 11;
case "minecraft:furnace" -> typeId = 13;
case "minecraft:dropper", "minecraft:dispenser" -> typeId = 6;
case "minecraft:enchanting_table" -> typeId = 12;
case "minecraft:brewing_stand" -> typeId = 10;
case "minecraft:villager" -> typeId = 18;
case "minecraft:beacon" -> typeId = 8;
case "minecraft:anvil" -> typeId = 7;
case "minecraft:hopper" -> typeId = 15;
case "minecraft:shulker_box" -> typeId = 19;
default -> {
if (slots > 0 && slots <= 54) {
typeId = slots / 9 - 1;
}
break;
}
}
if (typeId == -1) {
@@ -80,7 +80,7 @@ public class EntityPacketRewriter1_13_1 extends EntityRewriter<ClientboundPacket
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_13.ENTITY_DATA_LIST); // 12 - Metadata
map(Types1_13.ENTITY_DATA_LIST); // 12 - Entity data
handler(trackerAndRewriterHandler(Types1_13.ENTITY_DATA_LIST));
}
@@ -96,7 +96,7 @@ public class EntityPacketRewriter1_13_1 extends EntityRewriter<ClientboundPacket
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_13.ENTITY_DATA_LIST); // 7 - Metadata
map(Types1_13.ENTITY_DATA_LIST); // 7 - Entity data
handler(trackerAndRewriterHandler(Types1_13.ENTITY_DATA_LIST, EntityTypes1_13.EntityType.PLAYER));
}
@@ -58,7 +58,7 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
map(Types.SHORT); // 11 - Velocity Z
handler(trackerHandler());
handler(wrapper -> sendMetadataPacket(wrapper, wrapper.get(Types.VAR_INT, 0)));
handler(wrapper -> sendEntityDataPacket(wrapper, wrapper.get(Types.VAR_INT, 0)));
}
});
@@ -77,7 +77,7 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
int entityId = wrapper.get(Types.VAR_INT, 0);
wrapper.user().getEntityTracker(Protocol1_14_4To1_15.class).addEntity(entityId, EntityTypes1_15.PLAYER);
sendMetadataPacket(wrapper, entityId);
sendEntityDataPacket(wrapper, entityId);
});
}
});
@@ -122,10 +122,10 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
}
private void sendMetadataPacket(PacketWrapper wrapper, int entityId) {
// Meta is no longer included in the spawn packets, but sent separately
List<EntityData> metadata = wrapper.read(Types1_14.ENTITY_DATA_LIST);
if (metadata.isEmpty()) {
private void sendEntityDataPacket(PacketWrapper wrapper, int entityId) {
// Data is no longer included in the spawn packets, but sent separately
List<EntityData> entityData = wrapper.read(Types1_14.ENTITY_DATA_LIST);
if (entityData.isEmpty()) {
return;
}
@@ -133,13 +133,13 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
wrapper.send(Protocol1_14_4To1_15.class);
wrapper.cancel();
// Handle meta
handleEntityData(entityId, metadata, wrapper.user());
// Handle data
handleEntityData(entityId, entityData, wrapper.user());
PacketWrapper metadataPacket = PacketWrapper.create(ClientboundPackets1_15.SET_ENTITY_DATA, wrapper.user());
metadataPacket.write(Types.VAR_INT, entityId);
metadataPacket.write(Types1_14.ENTITY_DATA_LIST, metadata);
metadataPacket.send(Protocol1_14_4To1_15.class);
PacketWrapper entityDataPacket = PacketWrapper.create(ClientboundPackets1_15.SET_ENTITY_DATA, wrapper.user());
entityDataPacket.write(Types.VAR_INT, entityId);
entityDataPacket.write(Types1_14.ENTITY_DATA_LIST, entityData);
entityDataPacket.send(Protocol1_14_4To1_15.class);
}
@Override
@@ -49,7 +49,7 @@ public class EntityPacketRewriter1_14_1 extends EntityRewriter<ClientboundPacket
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_14.ENTITY_DATA_LIST); // 12 - Metadata
map(Types1_14.ENTITY_DATA_LIST); // 12 - Entity data
handler(trackerAndRewriterHandler(Types1_14.ENTITY_DATA_LIST));
}
@@ -67,7 +67,7 @@ public class EntityPacketRewriter1_14_1 extends EntityRewriter<ClientboundPacket
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_14.ENTITY_DATA_LIST); // 7 - Metadata
map(Types1_14.ENTITY_DATA_LIST); // 7 - Entity data
handler(trackerAndRewriterHandler(Types1_14.ENTITY_DATA_LIST, EntityTypes1_14.PLAYER));
}
@@ -24,6 +24,7 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
import com.viaversion.viaversion.api.type.types.version.Types1_16;
@@ -50,22 +51,23 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
String dimensionName;
String outputName;
switch (dimension) {
case -1:
case -1 -> {
dimensionName = "minecraft:the_nether";
outputName = map.nether();
break;
case 0:
}
case 0 -> {
dimensionName = "minecraft:overworld";
outputName = map.overworld();
break;
case 1:
}
case 1 -> {
dimensionName = "minecraft:the_end";
outputName = map.end();
break;
default:
}
default -> {
protocol.getLogger().warning("Invalid dimension id: " + dimension);
dimensionName = "minecraft:overworld";
outputName = map.overworld();
}
}
wrapper.write(Types.STRING, dimensionName); // dimension
@@ -119,10 +121,13 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
handler(wrapper -> {
wrapper.write(Types.BYTE, (byte) -1); // Previous gamemode, set to none
// <= 1.14.4 didn't keep attributes on respawn and 1.15.x always kept them
final boolean keepAttributes = wrapper.user().getProtocolInfo().serverProtocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_15);
String levelType = wrapper.read(Types.STRING);
wrapper.write(Types.BOOLEAN, false); // debug
wrapper.write(Types.BOOLEAN, levelType.equals("flat"));
wrapper.write(Types.BOOLEAN, true); // keep all playerdata
wrapper.write(Types.BOOLEAN, keepAttributes); // keep player attributes
});
}
});
@@ -211,8 +216,8 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
registerBlockStateHandler(EntityTypes1_16.ABSTRACT_MINECART, 10);
filter().type(EntityTypes1_16.ABSTRACT_ARROW).removeIndex(8);
filter().type(EntityTypes1_16.WOLF).index(16).handler((event, meta) -> {
byte mask = meta.value();
filter().type(EntityTypes1_16.WOLF).index(16).handler((event, data) -> {
byte mask = data.value();
int angerTime = (mask & 0x02) != 0 ? Integer.MAX_VALUE : 0;
event.createExtraData(new EntityData(20, Types1_16.ENTITY_DATA_TYPES.varIntType, angerTime));
});
@@ -80,11 +80,11 @@ public class EntityPacketRewriter1_16_2 extends EntityRewriter<ClientboundPacket
registerEntityDataTypeHandler(Types1_16.ENTITY_DATA_TYPES.itemType, Types1_16.ENTITY_DATA_TYPES.optionalBlockStateType, Types1_16.ENTITY_DATA_TYPES.particleType);
registerBlockStateHandler(EntityTypes1_16_2.ABSTRACT_MINECART, 10);
filter().type(EntityTypes1_16_2.ABSTRACT_PIGLIN).handler((metadatas, meta) -> {
if (meta.id() == 15) {
meta.setId(16);
} else if (meta.id() == 16) {
meta.setId(15);
filter().type(EntityTypes1_16_2.ABSTRACT_PIGLIN).handler((event, data) -> {
if (data.id() == 15) {
data.setId(16);
} else if (data.id() == 16) {
data.setId(15);
}
});
}
@@ -136,11 +136,11 @@ public final class EntityPacketRewriter1_17 extends EntityRewriter<ClientboundPa
@Override
protected void registerRewrites() {
filter().mapDataType(Types1_17.ENTITY_DATA_TYPES::byId);
filter().dataType(Types1_17.ENTITY_DATA_TYPES.poseType).handler((event, meta) -> {
int pose = meta.value();
filter().dataType(Types1_17.ENTITY_DATA_TYPES.poseType).handler((event, data) -> {
int pose = data.value();
if (pose > 5) {
// Added LONG_JUMP at 6
meta.setValue(pose + 1);
data.setValue(pose + 1);
}
});
registerEntityDataTypeHandler(Types1_17.ENTITY_DATA_TYPES.itemType, Types1_17.ENTITY_DATA_TYPES.optionalBlockStateType, Types1_17.ENTITY_DATA_TYPES.particleType);
@@ -82,8 +82,8 @@ public final class EntityPacketRewriter1_18 extends EntityRewriter<ClientboundPa
@Override
protected void registerRewrites() {
filter().mapDataType(Types1_18.ENTITY_DATA_TYPES::byId);
filter().dataType(Types1_18.ENTITY_DATA_TYPES.particleType).handler((event, meta) -> {
final Particle particle = (Particle) meta.getValue();
filter().dataType(Types1_18.ENTITY_DATA_TYPES.particleType).handler((event, data) -> {
final Particle particle = (Particle) data.getValue();
if (particle.id() == 2) { // Barrier
particle.setId(3); // Block marker
particle.add(Types.VAR_INT, 7754); // Barrier state
@@ -26,8 +26,8 @@ import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.data.entity.DimensionData;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
@@ -115,13 +115,13 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
wrapper.send(Protocol1_18_2To1_19.class);
wrapper.cancel();
// Send motive in metadata
final PacketWrapper metaPacket = wrapper.create(ClientboundPackets1_19.SET_ENTITY_DATA);
metaPacket.write(Types.VAR_INT, wrapper.get(Types.VAR_INT, 0)); // Entity id
final List<EntityData> metadata = new ArrayList<>();
metadata.add(new EntityData(8, Types1_19.ENTITY_DATA_TYPES.paintingVariantType, protocol.getMappingData().getPaintingMappings().getNewIdOrDefault(motive, 0)));
metaPacket.write(Types1_19.ENTITY_DATA_LIST, metadata);
metaPacket.send(Protocol1_18_2To1_19.class);
// Send motive in entity data
final PacketWrapper entityDataPacket = wrapper.create(ClientboundPackets1_19.SET_ENTITY_DATA);
entityDataPacket.write(Types.VAR_INT, wrapper.get(Types.VAR_INT, 0)); // Entity id
final List<EntityData> entityData = new ArrayList<>();
entityData.add(new EntityData(8, Types1_19.ENTITY_DATA_TYPES.paintingVariantType, protocol.getMappingData().getPaintingMappings().getNewIdOrDefault(motive, 0)));
entityDataPacket.write(Types1_19.ENTITY_DATA_LIST, entityData);
entityDataPacket.send(Protocol1_18_2To1_19.class);
});
}
});
@@ -227,7 +227,7 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
map(Types.BYTE); // Previous gamemode
map(Types.BOOLEAN); // Debug
map(Types.BOOLEAN); // Flat
map(Types.BOOLEAN); // Keep player data
map(Types.BOOLEAN); // Keep player attributes
create(Types.OPTIONAL_GLOBAL_POSITION, null); // Last death location
handler(worldDataTrackerHandlerByKey());
}
@@ -317,8 +317,8 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
@Override
protected void registerRewrites() {
filter().mapDataType(Types1_19.ENTITY_DATA_TYPES::byId);
filter().dataType(Types1_19.ENTITY_DATA_TYPES.particleType).handler((event, meta) -> {
final Particle particle = (Particle) meta.getValue();
filter().dataType(Types1_19.ENTITY_DATA_TYPES.particleType).handler((event, data) -> {
final Particle particle = (Particle) data.getValue();
final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings();
if (particle.id() == particleMappings.id("vibration")) {
// Remove the position
@@ -349,4 +349,4 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
public EntityType typeFromId(final int type) {
return EntityTypes1_19.getTypeFromId(type);
}
}
}
@@ -155,11 +155,11 @@ public final class EntityPacketRewriter1_19_3 extends EntityRewriter<Clientbound
registerEntityDataTypeHandler(Types1_19_3.ENTITY_DATA_TYPES.itemType, Types1_19_3.ENTITY_DATA_TYPES.optionalBlockStateType, Types1_19_3.ENTITY_DATA_TYPES.particleType);
registerBlockStateHandler(EntityTypes1_19_3.ABSTRACT_MINECART, 11);
filter().type(EntityTypes1_19_3.ENTITY).index(6).handler((event, meta) -> {
filter().type(EntityTypes1_19_3.ENTITY).index(6).handler((event, data) -> {
// Sitting pose added
final int pose = meta.value();
final int pose = data.value();
if (pose >= 10) {
meta.setValue(pose + 1);
data.setValue(pose + 1);
}
});
}
@@ -19,7 +19,6 @@ package com.viaversion.viaversion.protocols.v1_19_1to1_19_3.rewriter;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.Protocol1_19_1To1_19_3;
@@ -66,7 +65,7 @@ public final class ItemPacketRewriter1_19_3 extends ItemRewriter<ClientboundPack
final String type = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING));
wrapper.passthrough(Types.STRING); // Recipe Identifier
switch (type) {
case "crafting_shapeless": {
case "crafting_shapeless" -> {
wrapper.passthrough(Types.STRING); // Group
wrapper.write(Types.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
final int ingredients = wrapper.passthrough(Types.VAR_INT);
@@ -77,9 +76,8 @@ public final class ItemPacketRewriter1_19_3 extends ItemRewriter<ClientboundPack
}
}
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Result
break;
}
case "crafting_shaped": {
case "crafting_shaped" -> {
final int ingredients = wrapper.passthrough(Types.VAR_INT) * wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.STRING); // Group
wrapper.write(Types.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
@@ -90,12 +88,8 @@ public final class ItemPacketRewriter1_19_3 extends ItemRewriter<ClientboundPack
}
}
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Result
break;
}
case "smelting":
case "campfire_cooking":
case "blasting":
case "smoking":
case "smelting", "campfire_cooking", "blasting", "smoking" -> {
wrapper.passthrough(Types.STRING); // Group
wrapper.write(Types.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
final Item[] items = wrapper.passthrough(Types.ITEM1_13_2_ARRAY); // Ingredients
@@ -105,25 +99,12 @@ public final class ItemPacketRewriter1_19_3 extends ItemRewriter<ClientboundPack
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2)); // Result
wrapper.passthrough(Types.FLOAT); // EXP
wrapper.passthrough(Types.VAR_INT); // Cooking time
break;
case "crafting_special_armordye":
case "crafting_special_bookcloning":
case "crafting_special_mapcloning":
case "crafting_special_mapextending":
case "crafting_special_firework_rocket":
case "crafting_special_firework_star":
case "crafting_special_firework_star_fade":
case "crafting_special_tippedarrow":
case "crafting_special_bannerduplicate":
case "crafting_special_shielddecoration":
case "crafting_special_shulkerboxcoloring":
case "crafting_special_suspiciousstew":
case "crafting_special_repairitem":
wrapper.write(Types.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
break;
default:
recipeRewriter.handleRecipeType(wrapper, type);
break;
}
case "crafting_special_armordye", "crafting_special_bookcloning", "crafting_special_mapcloning", "crafting_special_mapextending",
"crafting_special_firework_rocket", "crafting_special_firework_star", "crafting_special_firework_star_fade", "crafting_special_tippedarrow",
"crafting_special_bannerduplicate", "crafting_special_shielddecoration", "crafting_special_shulkerboxcoloring", "crafting_special_suspiciousstew",
"crafting_special_repairitem" -> wrapper.write(Types.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
default -> recipeRewriter.handleRecipeType(wrapper, type);
}
}
});
@@ -223,10 +223,10 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter<Clientbound
registerEntityDataTypeHandler(Types1_19_4.ENTITY_DATA_TYPES.itemType, Types1_19_4.ENTITY_DATA_TYPES.blockStateType, Types1_19_4.ENTITY_DATA_TYPES.optionalBlockStateType, Types1_19_4.ENTITY_DATA_TYPES.particleType, null);
registerBlockStateHandler(EntityTypes1_19_4.ABSTRACT_MINECART, 11);
filter().type(EntityTypes1_19_4.BOAT).index(11).handler((event, meta) -> {
final int boatType = meta.value();
filter().type(EntityTypes1_19_4.BOAT).index(11).handler((event, data) -> {
final int boatType = data.value();
if (boatType > 4) { // Cherry added
meta.setValue(boatType + 1);
data.setValue(boatType + 1);
}
});
@@ -63,7 +63,7 @@ public final class Protocol1_19_4To1_20 extends AbstractProtocol<ClientboundPack
wrapper.read(Types.INT); // Killer ID
});
registerClientbound(ClientboundPackets1_19_4.PLAYER_COMBAT_KILL, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Duration
wrapper.passthrough(Types.VAR_INT); // Player ID
wrapper.read(Types.INT); // Killer ID
});
}
@@ -132,7 +132,7 @@ public final class EntityPacketRewriter1_20 extends EntityRewriter<ClientboundPa
registerBlockStateHandler(EntityTypes1_19_4.ABSTRACT_MINECART, 11);
// Rotate item display by 180 degrees around the Y axis
filter().type(EntityTypes1_19_4.ITEM_DISPLAY).handler((event, meta) -> {
filter().type(EntityTypes1_19_4.ITEM_DISPLAY).handler((event, data) -> {
if (event.trackedEntity().hasSentEntityData() || event.hasExtraData()) {
return;
}
@@ -141,9 +141,9 @@ public final class EntityPacketRewriter1_20 extends EntityRewriter<ClientboundPa
event.createExtraData(new EntityData(12, Types1_20.ENTITY_DATA_TYPES.quaternionType, Y_FLIPPED_ROTATION));
}
});
filter().type(EntityTypes1_19_4.ITEM_DISPLAY).index(12).handler((event, meta) -> {
final Quaternion quaternion = meta.value();
meta.setValue(rotateY180(quaternion));
filter().type(EntityTypes1_19_4.ITEM_DISPLAY).index(12).handler((event, data) -> {
final Quaternion quaternion = data.value();
data.setValue(rotateY180(quaternion));
});
}
@@ -399,19 +399,13 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
for (final StringTag element : parameters) {
JsonElement argument = null;
switch (element.getValue()) {
case "sender":
argument = senderName;
break;
case "content":
argument = message;
break;
case "team_name":
case "target": // So that this method can also be used in VB
case "sender" -> argument = senderName;
case "content" -> argument = message;
case "team_name", "target" /*So that this method can also be used in VB*/ -> {
Preconditions.checkNotNull(targetName, "Team name is null");
argument = targetName;
break;
default:
LOGGER.warning("Unknown parameter for chat decoration: " + element.getValue());
}
default -> LOGGER.warning("Unknown parameter for chat decoration: " + element.getValue());
}
if (argument != null) {
arguments.add(SerializerVersion.V1_18.toComponent(argument));
@@ -258,7 +258,7 @@ public final class Protocol1_20_2To1_20_3 extends AbstractProtocol<ClientboundPa
registerClientbound(ClientboundPackets1_20_2.PLAYER_COMBAT_KILL, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Duration
map(Types.VAR_INT); // Player ID
handler(wrapper -> convertComponent(wrapper));
}
});
@@ -146,25 +146,28 @@ public final class BlockItemPacketRewriter1_20_3 extends ItemRewriter<Clientboun
final CompoundTag tag = item.tag();
if (tag != null && item.identifier() == 1047) { // Written book
updatePages(tag, "pages");
updatePages(tag, "filtered_pages"); // TODO This isn't a list
final ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
if (pages != null) {
for (final StringTag pageTag : pages) {
updatePageTag(pageTag);
}
}
final CompoundTag filteredPages = tag.getCompoundTag("filtered_pages");
if (filteredPages != null) {
for (final String string : filteredPages.keySet()) {
updatePageTag(filteredPages.getStringTag(string));
}
}
}
return super.handleItemToClient(connection, item);
}
private void updatePages(final CompoundTag tag, final String key) {
final ListTag<StringTag> pages = tag.getListTag(key, StringTag.class);
if (pages == null) {
return;
}
for (final StringTag pageTag : pages) {
try {
final JsonElement updatedComponent = ComponentUtil.convertJson(pageTag.getValue(), SerializerVersion.V1_19_4, SerializerVersion.V1_20_3);
pageTag.setValue(updatedComponent.toString());
} catch (final Exception e) {
Via.getManager().debugHandler().error("Error during book conversion", e);
}
private void updatePageTag(final StringTag pageTag) {
try {
final JsonElement updatedComponent = ComponentUtil.convertJson(pageTag.getValue(), SerializerVersion.V1_19_4, SerializerVersion.V1_20_3);
pageTag.setValue(updatedComponent.toString());
} catch (final Exception e) {
Via.getManager().debugHandler().error("Error during book conversion", e);
}
}
}
@@ -103,18 +103,18 @@ public final class EntityPacketRewriter1_20_3 extends EntityRewriter<Clientbound
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
final EntityDataType type = meta.dataType();
filter().handler((event, data) -> {
final EntityDataType type = data.dataType();
if (type == Types1_20_2.ENTITY_DATA_TYPES.componentType) {
meta.setTypeAndValue(Types1_20_3.ENTITY_DATA_TYPES.componentType, ComponentUtil.jsonToTag(meta.value()));
data.setTypeAndValue(Types1_20_3.ENTITY_DATA_TYPES.componentType, ComponentUtil.jsonToTag(data.value()));
} else if (type == Types1_20_2.ENTITY_DATA_TYPES.optionalComponentType) {
meta.setTypeAndValue(Types1_20_3.ENTITY_DATA_TYPES.optionalComponentType, ComponentUtil.jsonToTag(meta.value()));
data.setTypeAndValue(Types1_20_3.ENTITY_DATA_TYPES.optionalComponentType, ComponentUtil.jsonToTag(data.value()));
} else {
meta.setDataType(Types1_20_3.ENTITY_DATA_TYPES.byId(type.typeId()));
data.setDataType(Types1_20_3.ENTITY_DATA_TYPES.byId(type.typeId()));
}
});
filter().dataType(Types1_20_3.ENTITY_DATA_TYPES.particleType).handler((event, meta) -> {
final Particle particle = meta.value();
filter().dataType(Types1_20_3.ENTITY_DATA_TYPES.particleType).handler((event, data) -> {
final Particle particle = data.value();
final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings();
if (particle.id() == particleMappings.id("vibration")) {
// Change the type of the resource key argument
@@ -56,6 +56,7 @@ import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.ProtocolLogger;
import java.util.BitSet;
import java.util.UUID;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -93,6 +94,16 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.DISGUISED_CHAT);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_20_3.PLAYER_COMBAT_KILL);
// People add item hovers to all sorts of weird places...
componentRewriter.registerOpenScreen(ClientboundPackets1_20_3.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_20_3.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_20_3.TAB_LIST);
componentRewriter.registerPing();
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, wrapper -> {
wrapper.passthrough(Types.STRING); // Server ID
wrapper.passthrough(Types.BYTE_ARRAY_PRIMITIVE); // Public key
@@ -114,26 +125,6 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
}
});
// Big problem with this update: Without access to the client, this cannot 100% predict the
// correct offset. This means we have to entirely discard client acknowledgements and fake them.
registerClientbound(ClientboundPackets1_20_3.PLAYER_CHAT, wrapper -> {
wrapper.passthrough(Types.UUID); // Sender
wrapper.passthrough(Types.VAR_INT); // Index
final byte[] signature = wrapper.passthrough(Types.OPTIONAL_SIGNATURE_BYTES);
if (signature == null) {
return;
}
// Mimic client behavior for acknowledgements
final AcknowledgedMessagesStorage storage = wrapper.user().get(AcknowledgedMessagesStorage.class);
if (storage.add(signature) && storage.offset() > 64) {
final PacketWrapper chatAck = wrapper.create(ServerboundPackets1_20_3.CHAT_ACK);
chatAck.write(Types.VAR_INT, storage.offset());
chatAck.sendToServer(Protocol1_20_3To1_20_5.class);
storage.clearOffset();
}
});
registerServerbound(ServerboundPackets1_20_5.CHAT, wrapper -> {
wrapper.passthrough(Types.STRING); // Message
wrapper.passthrough(Types.LONG); // Timestamp
@@ -151,7 +142,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
wrapper.write(Types.OPTIONAL_SIGNATURE_BYTES, null);
}
replaceChatAck(wrapper, storage);
fixChatAck(wrapper, storage);
});
registerServerbound(ServerboundPackets1_20_5.CHAT_COMMAND_SIGNED, ServerboundPackets1_20_3.CHAT_COMMAND, wrapper -> {
wrapper.passthrough(Types.STRING); // Command
@@ -178,7 +169,16 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
}
}
replaceChatAck(wrapper, storage);
fixChatAck(wrapper, storage);
});
registerServerbound(ServerboundPackets1_20_5.CHAT_ACK, wrapper -> {
final int offset = wrapper.read(Types.VAR_INT);
final int fixedOffset = wrapper.user().get(AcknowledgedMessagesStorage.class).accumulateAckCount(offset);
if (fixedOffset > 0) {
wrapper.write(Types.VAR_INT, fixedOffset);
} else {
wrapper.cancel();
}
});
registerServerbound(ServerboundPackets1_20_5.CHAT_COMMAND, wrapper -> {
wrapper.passthrough(Types.STRING); // Command
@@ -187,7 +187,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
wrapper.write(Types.LONG, 0L); // Salt
wrapper.write(Types.VAR_INT, 0); // No signatures
writeChatAck(wrapper, wrapper.user().get(AcknowledgedMessagesStorage.class));
writeSpoofedChatAck(wrapper, wrapper.user().get(AcknowledgedMessagesStorage.class));
});
registerServerbound(ServerboundPackets1_20_5.CHAT_SESSION_UPDATE, wrapper -> {
// Delay this until we know whether the server enforces secure chat
@@ -204,7 +204,6 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
wrapper.cancel();
});
cancelServerbound(ServerboundPackets1_20_5.CHAT_ACK);
registerClientbound(ClientboundPackets1_20_3.START_CONFIGURATION, wrapper -> wrapper.user().put(new AcknowledgedMessagesStorage()));
@@ -231,16 +230,19 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
cancelServerbound(ServerboundPackets1_20_5.DEBUG_SAMPLE_SUBSCRIPTION);
}
private void replaceChatAck(final PacketWrapper wrapper, final AcknowledgedMessagesStorage storage) {
wrapper.read(Types.VAR_INT); // Offset
wrapper.read(Types.ACKNOWLEDGED_BIT_SET); // Acknowledged
writeChatAck(wrapper, storage);
private void fixChatAck(final PacketWrapper wrapper, final AcknowledgedMessagesStorage storage) {
final int offset = wrapper.read(Types.VAR_INT);
final BitSet acknowledged = wrapper.read(Types.ACKNOWLEDGED_BIT_SET);
final int fixedOffset = storage.updateFromMessage(offset, acknowledged);
wrapper.write(Types.VAR_INT, fixedOffset);
// Never change this, as this message (and future ones) are signed with it
wrapper.write(Types.ACKNOWLEDGED_BIT_SET, acknowledged);
}
private void writeChatAck(final PacketWrapper wrapper, final AcknowledgedMessagesStorage storage) {
wrapper.write(Types.VAR_INT, storage.offset());
wrapper.write(Types.ACKNOWLEDGED_BIT_SET, storage.toAck());
storage.clearOffset();
private void writeSpoofedChatAck(final PacketWrapper wrapper, final AcknowledgedMessagesStorage storage) {
// As we don't have the new state from the client, replay what we last received
wrapper.write(Types.VAR_INT, 0); // Offset
wrapper.write(Types.ACKNOWLEDGED_BIT_SET, storage.createSpoofedAck()); // Acknowledged
}
@Override
@@ -1,110 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.v1_20_3to1_20_5.data;
import com.viaversion.nbt.tag.CompoundTag;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectSet;
public final class DamageTypes1_20_3 {
private static final Object2ObjectMap<String, CompoundTag> DAMAGE_TYPES = new Object2ObjectOpenHashMap<>();
static {
DAMAGE_TYPES.put("in_fire", create("inFire", 0.1F));
DAMAGE_TYPES.put("lightning_bolt", create("lightningBolt", 0.1F));
DAMAGE_TYPES.put("on_fire", create("onFire", 0.0F, "burning"));
DAMAGE_TYPES.put("lava", create("lava", 0.1F, "burning"));
DAMAGE_TYPES.put("hot_floor", create("hotFloor", 0.1F, "burning"));
DAMAGE_TYPES.put("in_wall", create("inWall", 0.0F));
DAMAGE_TYPES.put("cramming", create("cramming", 0.0F));
DAMAGE_TYPES.put("drown", create("drown", 0.0F, "drowning"));
DAMAGE_TYPES.put("starve", create("starve", 0.0F));
DAMAGE_TYPES.put("cactus", create("cactus", 0.1F));
DAMAGE_TYPES.put("fall", create("fall", "when_caused_by_living_non_player", 0.0F, null, "fall_variants"));
DAMAGE_TYPES.put("fly_into_wall", create("flyIntoWall", 0.0F));
DAMAGE_TYPES.put("out_of_world", create("outOfWorld", 0.0F));
DAMAGE_TYPES.put("generic", create("generic", 0.0F));
DAMAGE_TYPES.put("magic", create("magic", 0.0F));
DAMAGE_TYPES.put("wither", create("wither", 0.0F));
DAMAGE_TYPES.put("dragon_breath", create("dragonBreath", 0.0F));
DAMAGE_TYPES.put("dry_out", create("dryout", 0.1F));
DAMAGE_TYPES.put("sweet_berry_bush", create("sweetBerryBush", 0.1F, "poking"));
DAMAGE_TYPES.put("freeze", create("freeze", 0.0F, "freezing"));
DAMAGE_TYPES.put("stalagmite", create("stalagmite", 0.0F));
DAMAGE_TYPES.put("falling_block", create("fallingBlock", 0.1F));
DAMAGE_TYPES.put("falling_anvil", create("anvil", 0.1F));
DAMAGE_TYPES.put("falling_stalactite", create("fallingStalactite", 0.1F));
DAMAGE_TYPES.put("sting", create("sting", 0.1F));
DAMAGE_TYPES.put("mob_attack", create("mob", 0.1F));
DAMAGE_TYPES.put("mob_attack_no_aggro", create("mob", 0.1F));
DAMAGE_TYPES.put("player_attack", create("player", 0.1F));
DAMAGE_TYPES.put("arrow", create("arrow", 0.1F));
DAMAGE_TYPES.put("trident", create("trident", 0.1F));
DAMAGE_TYPES.put("mob_projectile", create("mob", 0.1F));
DAMAGE_TYPES.put("fireworks", create("fireworks", 0.1F));
DAMAGE_TYPES.put("unattributed_fireball", create("onFire", 0.1F, "burning"));
DAMAGE_TYPES.put("fireball", create("fireball", 0.1F, "burning"));
DAMAGE_TYPES.put("wither_skull", create("witherSkull", 0.1F));
DAMAGE_TYPES.put("thrown", create("thrown", 0.1F));
DAMAGE_TYPES.put("indirect_magic", create("indirectMagic", 0.0F));
DAMAGE_TYPES.put("thorns", create("thorns", 0.1F, "thorns"));
DAMAGE_TYPES.put("explosion", create("explosion", "always", 0.1F));
DAMAGE_TYPES.put("player_explosion", create("explosion.player", "always", 0.1F));
DAMAGE_TYPES.put("sonic_boom", create("sonic_boom", "always", 0.0F));
DAMAGE_TYPES.put("bad_respawn_point", create("badRespawnPoint", "always", 0.1F, "hurt", "intentional_game_design"));
DAMAGE_TYPES.put("outside_border", create("outsideBorder", 0.0F));
DAMAGE_TYPES.put("generic_kill", create("genericKill", 0.0F));
}
public static CompoundTag get(String key) {
return DAMAGE_TYPES.get(key);
}
public static ObjectSet<String> keys() {
return DAMAGE_TYPES.keySet();
}
private static CompoundTag create(String messageId, String scaling, float exhaustion) {
return create(messageId, scaling, exhaustion, null, null);
}
private static CompoundTag create(String messageId, float exhaustion, String effects) {
return create(messageId, "when_caused_by_living_non_player", exhaustion, effects, null);
}
private static CompoundTag create(String messageId, float exhaustion) {
return create(messageId, "when_caused_by_living_non_player", exhaustion);
}
private static CompoundTag create(String messageId, String scaling, float exhaustion, String damageEffects, String deathMessageType) {
final CompoundTag tag = new CompoundTag();
tag.putString("message_id", messageId);
tag.putString("scaling", scaling);
tag.putFloat("exhaustion", exhaustion);
if (damageEffects != null) {
tag.putString("effects", damageEffects);
}
if (deathMessageType != null) {
tag.putString("death_message_type", deathMessageType);
}
return tag;
}
}
@@ -22,10 +22,14 @@ import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.util.KeyMappings;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import org.checkerframework.checker.nullness.qual.Nullable;
public class MappingData1_20_5 extends MappingDataBase {
private final Object2ObjectMap<String, CompoundTag> damageTypes = new Object2ObjectOpenHashMap<>();
private KeyMappings blocks;
private KeyMappings sounds;
@@ -40,6 +44,11 @@ public class MappingData1_20_5 extends MappingDataBase {
final CompoundTag extraMappings = MappingDataLoader.INSTANCE.loadNBT("extra-identifiers-1.20.3.nbt");
blocks = new KeyMappings(extraMappings.getListTag("blocks", StringTag.class));
sounds = new KeyMappings(extraMappings.getListTag("sounds", StringTag.class));
final CompoundTag damageTypes = MappingDataLoader.INSTANCE.loadNBT("damage-types-1.20.3.nbt");
for (final String key : damageTypes.keySet()) {
this.damageTypes.put(key, damageTypes.getCompoundTag(key));
}
}
public int blockId(final String name) {
@@ -57,4 +66,12 @@ public class MappingData1_20_5 extends MappingDataBase {
public @Nullable String soundName(final int id) {
return sounds.idToKey(id);
}
public CompoundTag damageType(final String key) {
return damageTypes.get(key).copy();
}
public ObjectSet<String> damageKeys() {
return damageTypes.keySet();
}
}
@@ -17,7 +17,6 @@
*/
package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter;
import com.viaversion.nbt.stringified.SNBT;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
@@ -75,6 +74,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.ToolRule;
import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_20_3;
@@ -174,10 +174,10 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
registerCooldown(ClientboundPackets1_20_3.COOLDOWN);
registerSetContent1_17_1(ClientboundPackets1_20_3.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_20_3.CONTAINER_SET_SLOT);
registerSetEquipment(ClientboundPackets1_20_3.SET_EQUIPMENT);
registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerContainerSetData(ClientboundPackets1_20_3.CONTAINER_SET_DATA);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
protocol.registerServerbound(ServerboundPackets1_20_5.CONTAINER_BUTTON_CLICK, wrapper -> {
final byte containerId = wrapper.read(Types.VAR_INT).byteValue();
final byte buttonId = wrapper.read(Types.VAR_INT).byteValue();
@@ -384,6 +384,8 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
}
final Item structuredItem = toStructuredItem(connection, item);
// Add data components to fix issues in older protocols
appendItemDataFixComponents(connection, structuredItem);
if (Via.getConfig().handleInvalidItemCount()) {
// Server can send amounts which are higher than vanilla's default, and 1.20.4 will still accept them,
@@ -407,7 +409,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
}
public Item toOldItem(final UserConnection connection, final Item item, final StructuredDataConverter dataConverter) {
// Start out with custom data and add the rest on top, or short-curcuit with the original item
// Start out with custom data and add the rest on top, or short-circuit with the original item
final StructuredDataContainer data = item.dataContainer();
data.setIdLookup(protocol, true);
@@ -609,6 +611,22 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return item;
}
private void appendItemDataFixComponents(final UserConnection connection, final Item item) {
final ProtocolVersion serverVersion = connection.getProtocolInfo().serverProtocolVersion();
if (serverVersion.olderThanOrEqualTo(ProtocolVersion.v1_17_1)) {
if (item.identifier() == 1182) { // crossbow
// Change crossbow damage to value used in 1.17.1 and lower
item.dataContainer().set(StructuredDataKey.MAX_DAMAGE, 326);
}
}
if (serverVersion.olderThanOrEqualTo(ProtocolVersion.v1_8)) {
if (item.identifier() == 814 || item.identifier() == 819 || item.identifier() == 824 || item.identifier() == 829 || item.identifier() == 834) { // swords
// Make sword "eatable" to enable clientside instant blocking on 1.8. Consume time is set really high, so the eating animation doesn't play
item.dataContainer().set(StructuredDataKey.FOOD1_20_5, new FoodProperties(0, 0F, true, 3600, null, new FoodEffect[0]));
}
}
}
private int unmappedItemId(final String name) {
return protocol.getMappingData().getFullItemMappings().id(name);
}
@@ -840,7 +858,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
CompoundTag tag = null;
if (tagStartIndex != -1 && tagEndIndex != -1) {
try {
tag = SNBT.deserializeCompoundTag(rawPredicate.substring(tagStartIndex, tagEndIndex + 1));
tag = (CompoundTag) SerializerVersion.V1_20_3.toTag(rawPredicate.substring(tagStartIndex, tagEndIndex + 1));
} catch (final Exception e) {
if (Via.getManager().isDebug()) {
Protocol1_20_3To1_20_5.LOGGER.log(Level.SEVERE, "Failed to parse block predicate tag: " + rawPredicate.substring(tagStartIndex, tagEndIndex + 1), e);
@@ -1461,7 +1479,10 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
data.set(StructuredDataKey.BASE_COLOR, baseColorIntTag.asInt());
}
updateItemList(connection, data, tag, "Items", StructuredDataKey.CONTAINER1_20_5, true);
if (tag.contains("Items")) {
updateItemList(connection, data, tag, "Items", StructuredDataKey.CONTAINER1_20_5, true);
addBlockEntityId(tag, "shulker_box"); // Won't happen to the others and doesn't actually have to be correct otherwise
}
}
final Tag skullOwnerTag = tag.remove("SkullOwner");
@@ -1576,4 +1597,4 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return true;
}
}
}
@@ -26,10 +26,12 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.DimensionData;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
@@ -41,12 +43,10 @@ import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ClientboundPac
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.Protocol1_20_3To1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.data.Attributes1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.data.BannerPatterns1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.data.DamageTypes1_20_3;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.AcknowledgedMessagesStorage;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandler;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.TagUtil;
import it.unimi.dsi.fastutil.ints.IntArraySet;
@@ -74,6 +74,22 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
registerSetEntityData(ClientboundPackets1_20_3.SET_ENTITY_DATA, Types1_20_3.ENTITY_DATA_LIST, Types1_20_5.ENTITY_DATA_LIST);
registerRemoveEntities(ClientboundPackets1_20_3.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_20_3.SET_EQUIPMENT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity id
final EntityType type = tracker(wrapper.user()).entityType(entityId);
byte slot;
do {
slot = wrapper.read(Types.BYTE);
if (type != null && type.isOrHasParent(EntityTypes1_20_5.ABSTRACT_HORSE) && slot == 4) {
slot = 6; // Map chest slot index to body slot index for horses
}
wrapper.write(Types.BYTE, slot);
Item item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_20_2));
wrapper.write(Types1_20_5.ITEM, item);
} while (slot < 0);
});
protocol.registerClientbound(ClientboundConfigurationPackets1_20_3.REGISTRY_DATA, wrapper -> {
final PacketWrapper knownPacksPacket = wrapper.create(ClientboundConfigurationPackets1_20_5.SELECT_KNOWN_PACKS);
knownPacksPacket.write(Types.VAR_INT, 0); // No known packs, everything is sent here
@@ -152,14 +168,14 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
// Fill in missing damage types with 1.20.3/4 defaults
final Set<String> registryEntryKeys = Arrays.stream(registryEntries).map(e -> Key.stripMinecraftNamespace(e.key())).collect(Collectors.toSet());
for (final String key : DamageTypes1_20_3.keys()) {
for (final String key : protocol.getMappingData().damageKeys()) {
if (registryEntryKeys.contains(key)) {
continue;
}
highestId++;
registryEntries = Arrays.copyOf(registryEntries, highestId + 1);
registryEntries[highestId] = new RegistryEntry(Key.namespaced(key), DamageTypes1_20_3.get(key));
registryEntries[highestId] = new RegistryEntry(Key.namespaced(key), protocol.getMappingData().damageType(key));
}
}
@@ -418,27 +434,43 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
);
registerBlockStateHandler(EntityTypes1_20_5.ABSTRACT_MINECART, 11);
filter().type(EntityTypes1_20_5.LIVING_ENTITY).index(10).handler((event, meta) -> {
final int effectColor = meta.value();
filter().type(EntityTypes1_20_5.LIVING_ENTITY).index(10).handler((event, data) -> {
final int effectColor = data.value();
if (effectColor == 0) {
// No effect
meta.setTypeAndValue(Types1_20_5.ENTITY_DATA_TYPES.particlesType, new Particle[0]);
data.setTypeAndValue(Types1_20_5.ENTITY_DATA_TYPES.particlesType, new Particle[0]);
return;
}
final Particle particle = new Particle(protocol.getMappingData().getParticleMappings().mappedId("entity_effect"));
particle.add(Types.INT, withAlpha(effectColor));
meta.setTypeAndValue(Types1_20_5.ENTITY_DATA_TYPES.particlesType, new Particle[]{particle});
data.setTypeAndValue(Types1_20_5.ENTITY_DATA_TYPES.particlesType, new Particle[]{particle});
});
filter().type(EntityTypes1_20_5.LLAMA).removeIndex(20); // Carpet color
filter().type(EntityTypes1_20_5.AREA_EFFECT_CLOUD).handler((event, meta) -> {
filter().type(EntityTypes1_20_5.LLAMA).handler((event, data) -> {
// Carpet color removed - now set via the set equipment packet
final int dataIndex = event.index();
if (dataIndex == 20) {
event.cancel();
final int color = data.value();
// Convert dyed color id to carpet item id
final PacketWrapper setEquipment = PacketWrapper.create(ClientboundPackets1_20_5.SET_EQUIPMENT, event.user());
setEquipment.write(Types.VAR_INT, event.entityId());
setEquipment.write(Types.BYTE, (byte) 6);
setEquipment.write(Types1_20_5.ITEM, new StructuredItem(color + 446, 1, new StructuredDataContainer()));
setEquipment.scheduleSend(Protocol1_20_3To1_20_5.class);
} else if (dataIndex > 20) {
event.setIndex(dataIndex - 1);
}
});
filter().type(EntityTypes1_20_5.AREA_EFFECT_CLOUD).handler((event, data) -> {
// Color removed - Now put into the actual particle
final int metaIndex = event.index();
if (metaIndex == 9) {
final int dataIndex = event.index();
if (dataIndex == 9) {
// If the color is found first
final EntityData particleData = event.dataAtIndex(11);
final int color = meta.value();
final int color = data.value();
if (particleData == null) {
if (color != 0) {
// Add default particle with data
@@ -454,37 +486,33 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
return;
}
if (metaIndex > 9) {
event.setIndex(metaIndex - 1);
if (dataIndex > 9) {
event.setIndex(dataIndex - 1);
}
if (metaIndex == 11) {
if (dataIndex == 11) {
// If the particle is found first
final EntityData colorData = event.dataAtIndex(9);
if (colorData != null && colorData.dataType() == Types1_20_5.ENTITY_DATA_TYPES.varIntType) {
addColor(meta, colorData.value());
addColor(data, colorData.value());
}
}
});
filter().type(EntityTypes1_20_5.ARROW).index(10).handler((event, meta) -> {
final int color = meta.value();
filter().type(EntityTypes1_20_5.ARROW).index(10).handler((event, data) -> {
final int color = data.value();
if (color != -1) {
meta.setValue(withAlpha(color));
data.setValue(withAlpha(color));
}
});
final EntityDataHandler emptyItemHandler = (event, data) -> {
filter().type(EntityTypes1_20_5.ITEM_PROJECTILE).index(8).handler((event, data) -> {
final Item item = data.value();
if (item == null || item.isEmpty()) {
// The item is used for particles or projectile display and can no longer be empty
event.cancel();
}
};
filter().type(EntityTypes1_20_5.EGG).index(8).handler(emptyItemHandler);
filter().type(EntityTypes1_20_5.SNOWBALL).index(8).handler(emptyItemHandler);
filter().type(EntityTypes1_20_5.ENDER_PEARL).index(8).handler(emptyItemHandler);
filter().type(EntityTypes1_20_5.EXPERIENCE_BOTTLE).index(8).handler(emptyItemHandler);
});
}
private void addColor(@Nullable final EntityData particleMeta, final int color) {
@@ -515,4 +543,4 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
public EntityType typeFromId(final int type) {
return EntityTypes1_20_5.getTypeFromId(type);
}
}
}
@@ -18,6 +18,7 @@
package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter;
import com.google.common.base.Preconditions;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.FloatTag;
import com.viaversion.nbt.tag.IntArrayTag;
@@ -738,8 +739,8 @@ public final class StructuredDataConverter {
predicatedListTag.add(serializeBlockPredicate(predicate, tagKey));
} else {
for (final int id : holders.ids()) {
final String name = toMappedItemName(id);
if (name.isEmpty()) {
final String name = Protocol1_20_3To1_20_5.MAPPINGS.blockName(id);
if (name == null) {
if (backupInconvertibleData) {
// TODO Backup
}
@@ -798,30 +799,39 @@ public final class StructuredDataConverter {
private void convertItemList(final UserConnection connection, final Item[] items, final CompoundTag tag, final String key) {
final ListTag<CompoundTag> itemsTag = new ListTag<>(CompoundTag.class);
for (final Item item : items) {
final CompoundTag savedItem = new CompoundTag();
if (item != null) {
final String name = toMappedItemName(item.identifier());
savedItem.putString("id", name);
if (backupInconvertibleData && name.isEmpty()) {
savedItem.putInt(ITEM_BACKUP_TAG_KEY, item.identifier());
}
savedItem.putByte("Count", (byte) item.amount());
final CompoundTag itemTag = new CompoundTag();
for (final StructuredData<?> data : item.dataContainer().data().values()) {
writeToTag(connection, data, itemTag);
}
savedItem.put("tag", itemTag);
} else {
savedItem.putString("id", "air");
for (int i = 0; i < items.length; i++) {
final Item item = items[i];
final CompoundTag savedItem = itemToTag(connection, item);
// 1.20.4 clients need the Slot to display the item correctly
if (backupInconvertibleData) {
savedItem.putByte("Slot", (byte) i);
}
itemsTag.add(savedItem);
}
tag.put(key, itemsTag);
}
private CompoundTag itemToTag(final UserConnection connection, final Item item) {
final CompoundTag savedItem = new CompoundTag();
if (item != null) {
final String name = toMappedItemName(item.identifier());
savedItem.putString("id", name);
if (backupInconvertibleData && name.isEmpty()) {
savedItem.putInt(ITEM_BACKUP_TAG_KEY, item.identifier());
}
savedItem.putByte("Count", (byte) item.amount());
final CompoundTag itemTag = new CompoundTag();
for (final StructuredData<?> data : item.dataContainer().data().values()) {
writeToTag(connection, data, itemTag);
}
savedItem.put("tag", itemTag);
} else {
savedItem.putString("id", "air");
}
return savedItem;
}
private void convertEnchantments(final Enchantments data, final CompoundTag tag, final boolean storedEnchantments) {
final ListTag<CompoundTag> enchantments = new ListTag<>(CompoundTag.class);
for (final Int2IntMap.Entry entry : data.enchantments().int2IntEntrySet()) {
@@ -23,46 +23,59 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ServerboundPackets1_20_3;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.Protocol1_20_3To1_20_5;
import java.util.Arrays;
import java.util.BitSet;
import java.util.UUID;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Tracks the last Secure Chat state that we received from the client. This is important to always have a valid 'last
* seen' state that is consistent with future and past updates from the client (which may be signed). This state is
* used to construct signed command packets to the outdated server from unsigned ones from the modern client.
* <ul>
* <li>If we last forwarded a chat or command packet from the client, we have a known 'last seen' that we can
* reuse.</li>
* <li>If we last forwarded a chat acknowledgement packet, the previous 'last seen' cannot be reused. We
* cannot predict an up-to-date 'last seen', as we do not know which messages the client actually saw.</li>
* <li>Therefore, we need to hold back any acknowledgement packets so that we can continue to reuse the last valid
* 'last seen' state.</li>
* <li>However, there is a limit to the number of messages that can remain unacknowledged on the server.</li>
* <li>To address this, we know that if the client has moved its 'last seen' window far enough, we can fill in the
* gap with dummy 'last seen', and it will never be checked.</li>
* </ul>
*/
public final class AcknowledgedMessagesStorage implements StorableObject {
private static final int MAX_HISTORY = 20;
private final boolean[] trackedMessages = new boolean[MAX_HISTORY];
private static final int MINIMUM_DELAYED_ACK_COUNT = MAX_HISTORY;
private static final BitSet DUMMY_LAST_SEEN_MESSAGES = new BitSet();
private Boolean secureChatEnforced;
private ChatSession chatSession;
private int offset;
private int tail;
private byte[] lastMessage;
public boolean add(final byte[] message) {
if (Arrays.equals(message, lastMessage)) {
return false;
private BitSet lastSeenMessages = new BitSet();
private int delayedAckCount;
public int updateFromMessage(int ackCount, BitSet lastSeenMessages) {
// We held back some acknowledged messages, so flush that out now that we have a known 'last seen' state again
int delayedAckCount = this.delayedAckCount;
this.delayedAckCount = 0;
this.lastSeenMessages = lastSeenMessages;
return ackCount + delayedAckCount;
}
public int accumulateAckCount(int ackCount) {
delayedAckCount += ackCount;
int ackCountToForward = delayedAckCount - MINIMUM_DELAYED_ACK_COUNT;
if (ackCountToForward >= MAX_HISTORY) {
// Because we only forward acknowledgements above the window size, we don't have to shift the previous 'last seen' state
lastSeenMessages = DUMMY_LAST_SEEN_MESSAGES;
delayedAckCount = MINIMUM_DELAYED_ACK_COUNT;
return ackCountToForward;
}
this.lastMessage = message;
this.offset++;
this.trackedMessages[this.tail] = true;
this.tail = (this.tail + 1) % MAX_HISTORY;
return true;
return 0;
}
public BitSet toAck() {
final BitSet acks = new BitSet(MAX_HISTORY);
for (int i = 0; i < MAX_HISTORY; i++) {
final int messageIndex = (this.tail + i) % MAX_HISTORY;
acks.set(i, this.trackedMessages[messageIndex]);
}
return acks;
}
public int offset() {
return this.offset;
}
public void clearOffset() {
this.offset = 0;
public BitSet createSpoofedAck() {
return lastSeenMessages;
}
public void setSecureChatEnforced(final boolean secureChatEnforced) {
@@ -98,10 +111,8 @@ public final class AcknowledgedMessagesStorage implements StorableObject {
}
public void clear() {
this.offset = 0;
this.tail = 0;
this.lastMessage = null;
Arrays.fill(this.trackedMessages, false);
lastSeenMessages = new BitSet();
delayedAckCount = 0;
}
@Override
@@ -17,7 +17,10 @@
*/
package com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
@@ -38,6 +41,7 @@ import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<ClientboundPacket1_20_5, ServerboundPacket1_20_5, Protocol1_20_5To1_21> {
@@ -64,7 +68,6 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerMerchantOffers1_20_5(ClientboundPackets1_20_5.MERCHANT_OFFERS, Types1_20_5.ITEM_COST, Types1_21.ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST, Types1_21.OPTIONAL_ITEM_COST);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
registerContainerSetData(ClientboundPackets1_20_5.CONTAINER_SET_DATA);
registerLevelParticles1_20_5(ClientboundPackets1_20_5.LEVEL_PARTICLES, Types1_20_5.PARTICLE, Types1_21.PARTICLE);
registerExplosion(ClientboundPackets1_20_5.EXPLODE, Types1_20_5.PARTICLE, Types1_21.PARTICLE); // Rewrites the included sound and particles
@@ -73,7 +76,7 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
// Now written as columns
final int size = wrapper.read(Types.VAR_INT);
wrapper.write(Types.VAR_INT, Math.max(1, (size - 1) / 3));
wrapper.write(Types.VAR_INT, Math.max(0, (size - 1) / 3));
});
protocol.registerClientbound(ClientboundPackets1_20_5.LEVEL_EVENT, wrapper -> {
@@ -114,6 +117,17 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
super.handleItemToClient(connection, item);
updateItemData(item);
final StructuredDataContainer dataContainer = item.dataContainer();
if (dataContainer.contains(StructuredDataKey.RARITY)) {
return item;
}
// Change rarity of trident and piglin banner pattern
if (item.identifier() == 1188 || item.identifier() == 1200) {
dataContainer.set(StructuredDataKey.RARITY, 0); // Common
saveTag(createCustomTag(item), new ByteTag(true), "rarity");
}
return item;
}
@@ -125,9 +139,10 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
dataContainer.replaceKey(StructuredDataKey.BUNDLE_CONTENTS1_20_5, StructuredDataKey.BUNDLE_CONTENTS1_21);
dataContainer.replace(StructuredDataKey.ATTRIBUTE_MODIFIERS1_20_5, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21, attributeModifiers -> {
final AttributeModifiers1_21.AttributeModifier[] modifiers = Arrays.stream(attributeModifiers.modifiers()).map(modifier -> {
final int mappedAttributeId = Protocol1_20_5To1_21.MAPPINGS.getNewAttributeId(modifier.attribute());
final AttributeModifiers1_20_5.ModifierData modData = modifier.modifier();
final AttributeModifiers1_21.ModifierData updatedModData = new AttributeModifiers1_21.ModifierData(Protocol1_20_5To1_21.mapAttributeUUID(modData.uuid(), modData.name()), modData.amount(), modData.operation());
return new AttributeModifiers1_21.AttributeModifier(modifier.attribute(), updatedModData, modifier.slotType());
return new AttributeModifiers1_21.AttributeModifier(mappedAttributeId, updatedModData, modifier.slotType());
}).toArray(AttributeModifiers1_21.AttributeModifier[]::new);
return new AttributeModifiers1_21(modifiers, attributeModifiers.showInTooltip());
});
@@ -141,6 +156,7 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
super.handleItemToServer(connection, item);
downgradeItemData(item);
resetRarityValues(item, nbtTagName("rarity"));
return item;
}
@@ -153,6 +169,11 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
dataContainer.remove(StructuredDataKey.JUKEBOX_PLAYABLE);
dataContainer.replace(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21, StructuredDataKey.ATTRIBUTE_MODIFIERS1_20_5, attributeModifiers -> {
final AttributeModifiers1_20_5.AttributeModifier[] modifiers = Arrays.stream(attributeModifiers.modifiers()).map(modifier -> {
final int mappedAttributeId = Protocol1_20_5To1_21.MAPPINGS.getAttributeMappings().inverse().getNewId(modifier.attribute());
if (mappedAttributeId == -1) {
return null;
}
final AttributeModifiers1_21.ModifierData modData = modifier.modifier();
final String name = AttributeModifierMappings1_21.idToName(modData.id());
final AttributeModifiers1_20_5.ModifierData updatedModData = new AttributeModifiers1_20_5.ModifierData(
@@ -161,12 +182,27 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
modData.amount(),
modData.operation()
);
return new AttributeModifiers1_20_5.AttributeModifier(modifier.attribute(), updatedModData, modifier.slotType());
}).toArray(AttributeModifiers1_20_5.AttributeModifier[]::new);
return new AttributeModifiers1_20_5.AttributeModifier(mappedAttributeId, updatedModData, modifier.slotType());
}).filter(Objects::nonNull).toArray(AttributeModifiers1_20_5.AttributeModifier[]::new);
return new AttributeModifiers1_20_5(modifiers, attributeModifiers.showInTooltip());
});
}
public static void resetRarityValues(final Item item, final String tagName) {
final StructuredDataContainer dataContainer = item.dataContainer();
final StructuredData<CompoundTag> customData = dataContainer.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
return;
}
if (customData.value().remove(tagName) != null) {
dataContainer.remove(StructuredDataKey.RARITY);
if (customData.value().isEmpty()) {
dataContainer.remove(StructuredDataKey.CUSTOM_DATA);
}
}
}
private int itemToJubeboxSong(final int id) {
String identifier = Protocol1_20_5To1_21.MAPPINGS.getFullItemMappings().identifier(id);
if (!identifier.contains("music_disc_")) {
@@ -34,20 +34,42 @@ public final class ComponentRewriter1_21 extends ComponentRewriter<ClientboundPa
super(protocol, ReadType.NBT);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag componentsTag) {
final CompoundTag attributeModifiers = TagUtil.getNamespacedCompoundTag(componentsTag, "minecraft:attribute_modifiers");
if (attributeModifiers != null) {
final ListTag<CompoundTag> modifiers = attributeModifiers.getListTag("modifiers", CompoundTag.class);
for (final CompoundTag modifier : modifiers) {
final String name = modifier.getString("name");
final UUID uuid = UUIDUtil.fromIntArray(modifier.getIntArrayTag("uuid").getValue());
final String id = Protocol1_20_5To1_21.mapAttributeUUID(uuid, name);
modifier.putString("id", id);
private void convertAttributeModifiersComponent(final CompoundTag tag) {
final CompoundTag attributeModifiers = TagUtil.getNamespacedCompoundTag(tag, "minecraft:attribute_modifiers");
if (attributeModifiers == null) {
return;
}
final ListTag<CompoundTag> modifiers = attributeModifiers.getListTag("modifiers", CompoundTag.class);
for (final CompoundTag modifier : modifiers) {
final String name = modifier.getString("name");
final UUID uuid = UUIDUtil.fromIntArray(modifier.getIntArrayTag("uuid").getValue());
final String id = Protocol1_20_5To1_21.mapAttributeUUID(uuid, name);
modifier.putString("id", id);
}
}
private void handleContainerComponent(final CompoundTag tag) {
final ListTag<CompoundTag> container = TagUtil.getNamespacedCompoundTagList(tag, "minecraft:container");
if (container == null) {
return;
}
for (final CompoundTag entryTag : container) {
final CompoundTag itemTag = entryTag.getCompoundTag("item");
final CompoundTag componentsTag = itemTag.getCompoundTag("components");
if (componentsTag != null) {
convertAttributeModifiersComponent(componentsTag);
handleContainerComponent(componentsTag);
}
}
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag componentsTag) {
convertAttributeModifiersComponent(componentsTag);
handleContainerComponent(componentsTag);
}
@Override
protected SerializerVersion inputSerializerVersion() {
return SerializerVersion.V1_20_5;
@@ -18,6 +18,7 @@
package com.viaversion.viaversion.protocols.v1_20to1_20_2;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
@@ -90,6 +91,22 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
sanitizeCustomPayload(wrapper);
});
registerClientbound(ClientboundPackets1_19_4.SYSTEM_CHAT, wrapper -> {
if (wrapper.user().isClientSide() || Via.getPlatform().isProxy()) {
return;
}
// Workaround for GH-3438, where chat messages are sent before the login has completed, usually during proxy server switches
// The server will unnecessarily send an error text message, thinking a packet ran into an error, when it was just cancelled and re-queued
final JsonElement component = wrapper.passthrough(Types.COMPONENT);
if (component instanceof JsonObject object && object.has("translate")) {
final JsonElement translate = object.get("translate");
if (translate != null && translate.getAsString().equals("multiplayer.message_not_delivered")) {
wrapper.cancel();
}
}
});
registerClientbound(ClientboundPackets1_19_4.RESOURCE_PACK, wrapper -> {
final String url = wrapper.passthrough(Types.STRING);
final String hash = wrapper.passthrough(Types.STRING);
@@ -23,7 +23,6 @@ import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
@@ -32,7 +31,6 @@ import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.ChunkPosition;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
@@ -51,7 +49,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<ClientboundPackets1_19_4, ServerboundPackets1_20_2, Protocol1_20To1_20_2> {
public BlockItemPacketRewriter1_20_2(final Protocol1_20To1_20_2 protocol) {
super(protocol, Types.ITEM1_13_2, Types.ITEM1_13_2_ARRAY);
super(protocol, Types.ITEM1_13_2, Types.ITEM1_13_2_ARRAY, Types.ITEM1_20_2, Types.ITEM1_20_2_ARRAY);
}
@Override
@@ -62,6 +60,13 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_19_4.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent(ClientboundPackets1_19_4.LEVEL_EVENT, 1010, 2001);
registerSetContent1_17_1(ClientboundPackets1_19_4.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_19_4.CONTAINER_SET_SLOT);
registerContainerClick1_17_1(ServerboundPackets1_20_2.CONTAINER_CLICK);
registerMerchantOffers1_19(ClientboundPackets1_19_4.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_2.SET_CREATIVE_MODE_SLOT);
registerLevelParticles1_19(ClientboundPackets1_19_4.LEVEL_PARTICLES);
protocol.registerServerbound(ServerboundPackets1_20_2.SET_BEACON, wrapper -> {
// Effects start at 1 before 1.20.2
if (wrapper.passthrough(Types.BOOLEAN)) { // Primary effect
@@ -114,31 +119,6 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
}
});
// Replace the NBT type everywhere
protocol.registerClientbound(ClientboundPackets1_19_4.CONTAINER_SET_CONTENT, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Window id
map(Types.VAR_INT); // State id
handler(wrapper -> {
final Item[] items = wrapper.read(Types.ITEM1_13_2_ARRAY);
for (final Item item : items) {
handleItemToClient(wrapper.user(), item);
}
wrapper.write(Types.ITEM1_20_2_ARRAY, items);
wrapper.write(Types.ITEM1_20_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2))); // Carried item
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.CONTAINER_SET_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Window id
map(Types.VAR_INT); // State id
map(Types.SHORT); // Slot id
handler(wrapper -> wrapper.write(Types.ITEM1_20_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2))));
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.UPDATE_ADVANCEMENTS, wrapper -> {
wrapper.passthrough(Types.BOOLEAN); // Reset/clear
final int size = wrapper.passthrough(Types.VAR_INT); // Mapping size
@@ -184,160 +164,18 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
});
}
});
protocol.registerServerbound(ServerboundPackets1_20_2.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Window Id
map(Types.VAR_INT); // State id
map(Types.SHORT); // Slot
map(Types.BYTE); // Button
map(Types.VAR_INT); // Mode
handler(wrapper -> {
// Affected items
final int length = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < length; i++) {
wrapper.passthrough(Types.SHORT); // Slot
wrapper.write(Types.ITEM1_13_2, handleItemToServer(wrapper.user(), wrapper.read(Types.ITEM1_20_2)));
}
// Carried item
wrapper.write(Types.ITEM1_13_2, handleItemToServer(wrapper.user(), wrapper.read(Types.ITEM1_20_2)));
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.MERCHANT_OFFERS, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Container id
final int size = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < size; i++) {
wrapper.write(Types.ITEM1_20_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2))); // Input
wrapper.write(Types.ITEM1_20_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2))); // Output
wrapper.write(Types.ITEM1_20_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2))); // Second Item
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
wrapper.passthrough(Types.INT); // Number of tools uses
wrapper.passthrough(Types.INT); // Maximum number of trade uses
wrapper.passthrough(Types.INT); // XP
wrapper.passthrough(Types.INT); // Special price
wrapper.passthrough(Types.FLOAT); // Price multiplier
wrapper.passthrough(Types.INT); // Demand
}
});
protocol.registerServerbound(ServerboundPackets1_20_2.SET_CREATIVE_MODE_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Types.SHORT); // 0 - Slot
handler(wrapper -> wrapper.write(Types.ITEM1_13_2, handleItemToServer(wrapper.user(), wrapper.read(Types.ITEM1_20_2)))); // 1 - Clicked Item
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.LEVEL_PARTICLES, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Particle ID
map(Types.BOOLEAN); // 1 - Long Distance
map(Types.DOUBLE); // 2 - X
map(Types.DOUBLE); // 3 - Y
map(Types.DOUBLE); // 4 - Z
map(Types.FLOAT); // 5 - Offset X
map(Types.FLOAT); // 6 - Offset Y
map(Types.FLOAT); // 7 - Offset Z
map(Types.FLOAT); // 8 - Particle Data
map(Types.INT); // 9 - Particle Count
handler(wrapper -> {
final int id = wrapper.get(Types.VAR_INT, 0);
final ParticleMappings mappings = Protocol1_20To1_20_2.MAPPINGS.getParticleMappings();
if (mappings.isBlockParticle(id)) {
final int data = wrapper.read(Types.VAR_INT);
wrapper.write(Types.VAR_INT, protocol.getMappingData().getNewBlockStateId(data));
} else if (mappings.isItemParticle(id)) {
wrapper.write(Types.ITEM1_20_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2)));
}
});
}
});
new RecipeRewriter1_19_4<>(protocol) {
@Override
public void handleCraftingShapeless(final PacketWrapper wrapper) {
wrapper.passthrough(Types.STRING); // Group
wrapper.passthrough(Types.VAR_INT); // Crafting book category
handleIngredients(wrapper);
final Item result = wrapper.read(itemType());
rewrite(wrapper.user(), result);
wrapper.write(Types.ITEM1_20_2, result);
protected Type<Item> mappedItemType() {
return BlockItemPacketRewriter1_20_2.this.mappedItemType();
}
@Override
public void handleSmelting(final PacketWrapper wrapper) {
wrapper.passthrough(Types.STRING); // Group
wrapper.passthrough(Types.VAR_INT); // Crafting book category
handleIngredient(wrapper);
final Item result = wrapper.read(itemType());
rewrite(wrapper.user(), result);
wrapper.write(Types.ITEM1_20_2, result);
wrapper.passthrough(Types.FLOAT); // EXP
wrapper.passthrough(Types.VAR_INT); // Cooking time
protected Type<Item[]> mappedItemArrayType() {
return BlockItemPacketRewriter1_20_2.this.mappedItemArrayType();
}
@Override
public void handleCraftingShaped(final PacketWrapper wrapper) {
final int ingredients = wrapper.passthrough(Types.VAR_INT) * wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.STRING); // Group
wrapper.passthrough(Types.VAR_INT); // Crafting book category
for (int i = 0; i < ingredients; i++) {
handleIngredient(wrapper);
}
final Item result = wrapper.read(itemType());
rewrite(wrapper.user(), result);
wrapper.write(Types.ITEM1_20_2, result);
wrapper.passthrough(Types.BOOLEAN); // Show notification
}
@Override
public void handleStonecutting(final PacketWrapper wrapper) {
wrapper.passthrough(Types.STRING); // Group
handleIngredient(wrapper);
final Item result = wrapper.read(itemType());
rewrite(wrapper.user(), result);
wrapper.write(Types.ITEM1_20_2, result);
}
@Override
public void handleSmithing(final PacketWrapper wrapper) {
handleIngredient(wrapper); // Base
handleIngredient(wrapper); // Addition
final Item result = wrapper.read(itemType());
rewrite(wrapper.user(), result);
wrapper.write(Types.ITEM1_20_2, result);
}
@Override
public void handleSmithingTransform(final PacketWrapper wrapper) {
handleIngredient(wrapper); // Template
handleIngredient(wrapper); // Base
handleIngredient(wrapper); // Additions
final Item result = wrapper.read(itemType());
rewrite(wrapper.user(), result);
wrapper.write(Types.ITEM1_20_2, result);
}
@Override
protected void handleIngredient(final PacketWrapper wrapper) {
final Item[] items = wrapper.read(itemArrayType());
wrapper.write(Types.ITEM1_20_2_ARRAY, items);
for (final Item item : items) {
rewrite(wrapper.user(), item);
}
}
}.register(ClientboundPackets1_19_4.UPDATE_RECIPES);
}
@@ -446,4 +284,4 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
}
return tag;
}
}
}
@@ -67,15 +67,16 @@ public class Protocol1_8To1_9 extends AbstractProtocol<ClientboundPackets1_8, Cl
}
public static boolean isSword(int id) {
return switch (id) {
case 267, // Iron sword
268, // Wooden sword
272, // Stone sword
276, // Diamond sword
283 // Gold sword
-> true;
default -> false;
};
switch (id) {
case 267: // Iron sword
case 268: // Wooden sword
case 272: // Stone sword
case 276: // Diamond sword
case 283: // Gold sword
return true;
default:
return false;
}
}
@Override
@@ -189,11 +189,11 @@ public enum EntityDataIndex1_9 {
// Ender dragon
ENDER_DRAGON_PHASE(ENDER_DRAGON, 11, EntityDataTypes1_9.VAR_INT);
private static final HashMap<Pair<EntityTypes1_9.EntityType, Integer>, EntityDataIndex1_9> metadataRewrites = new HashMap<>();
private static final HashMap<Pair<EntityTypes1_9.EntityType, Integer>, EntityDataIndex1_9> entityDataRewriters = new HashMap<>();
static {
for (EntityDataIndex1_9 index : EntityDataIndex1_9.values()) {
metadataRewrites.put(new Pair<>(index.clazz, index.index), index);
entityDataRewriters.put(new Pair<>(index.clazz, index.index), index);
}
}
@@ -249,16 +249,16 @@ public enum EntityDataIndex1_9 {
private static Optional<EntityDataIndex1_9> getIndex(EntityType type, int index) {
Pair pair = new Pair<>(type, index);
return Optional.ofNullable(metadataRewrites.get(pair));
return Optional.ofNullable(entityDataRewriters.get(pair));
}
public static EntityDataIndex1_9 searchIndex(EntityType type, int index) {
EntityType currentType = type;
do {
Optional<EntityDataIndex1_9> optMeta = getIndex(currentType, index);
Optional<EntityDataIndex1_9> optData = getIndex(currentType, index);
if (optMeta.isPresent()) {
return optMeta.get();
if (optData.isPresent()) {
return optData.get();
}
currentType = currentType.getParent();
@@ -23,10 +23,10 @@ import com.viaversion.viaversion.api.minecraft.EulerAngle;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_8;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
@@ -210,30 +210,30 @@ public class EntityPacketRewriter1_9 extends EntityRewriter<ClientboundPackets1_
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types1_8.ENTITY_DATA_LIST, Types1_9.ENTITY_DATA_LIST); // 1 - Metadata List
map(Types1_8.ENTITY_DATA_LIST, Types1_9.ENTITY_DATA_LIST); // 1 - Entity data List
handler(wrapper -> {
List<EntityData> metadataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
List<EntityData> entityDataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (tracker.hasEntity(entityId)) {
handleEntityData(entityId, metadataList, wrapper.user());
handleEntityData(entityId, entityDataList, wrapper.user());
} else {
wrapper.cancel();
}
});
// Handler for meta data
// Handler for entity data
handler(wrapper -> {
List<EntityData> metadataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
List<EntityData> entityDataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
int entityID = wrapper.get(Types.VAR_INT, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
tracker.handleMetadata(entityID, metadataList);
tracker.handleEntityData(entityID, entityDataList);
});
// Cancel packet if list empty
handler(wrapper -> {
List<EntityData> metadataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
if (metadataList.isEmpty()) {
List<EntityData> entityDataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
if (entityDataList.isEmpty()) {
wrapper.cancel();
}
});
@@ -278,8 +278,6 @@ public class EntityPacketRewriter1_9 extends EntityRewriter<ClientboundPackets1_
public void register() {
map(Types.VAR_INT);
handler(wrapper -> {
if (!Via.getConfig().isMinimizeCooldown()) return;
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (wrapper.get(Types.VAR_INT, 0) != tracker.getProvidedEntityId()) {
return;
@@ -302,11 +300,8 @@ public class EntityPacketRewriter1_9 extends EntityRewriter<ClientboundPackets1_
}
properties.put(key, new Pair<>(value, modifiers));
}
// == Why 15.9? ==
// Higher values hides the cooldown but it bugs visual animation on hand
// when removing item from hand with inventory gui
properties.put("generic.attackSpeed", new Pair<>(15.9, ImmutableList.of( // Neutralize modifiers
properties.put("generic.attackSpeed", new Pair<>(20.0, ImmutableList.of( // Neutralize modifiers
new Triple<>(UUID.fromString("FA233E1C-4180-4865-B01B-BCCE9785ACA3"), 0.0, (byte) 0), // Tool and weapon modifier
new Triple<>(UUID.fromString("AF8B6E3F-3328-4C0A-AA36-5BA2BB9DBEF3"), 0.0, (byte) 2), // Dig speed
new Triple<>(UUID.fromString("55FCED67-E92A-486E-9800-B47F202C4386"), 0.0, (byte) 2) // Dig slow down
@@ -388,48 +383,48 @@ public class EntityPacketRewriter1_9 extends EntityRewriter<ClientboundPackets1_
@Override
protected void registerRewrites() {
filter().handler(this::handleMetadata);
filter().handler(this::handleEntityData);
}
private void handleMetadata(EntityDataHandlerEvent event, EntityData metadata) {
private void handleEntityData(EntityDataHandlerEvent event, EntityData data) {
EntityType type = event.entityType();
EntityDataIndex1_9 metaIndex = EntityDataIndex1_9.searchIndex(type, metadata.id());
if (metaIndex == null) {
EntityDataIndex1_9 dataIndex = EntityDataIndex1_9.searchIndex(type, data.id());
if (dataIndex == null) {
// Almost certainly bad data, remove it
event.cancel();
return;
}
if (metaIndex.getNewType() == null) {
if (dataIndex.getNewType() == null) {
event.cancel();
return;
}
metadata.setId(metaIndex.getNewIndex());
metadata.setDataTypeUnsafe(metaIndex.getNewType());
data.setId(dataIndex.getNewIndex());
data.setDataTypeUnsafe(dataIndex.getNewType());
Object value = metadata.getValue();
switch (metaIndex.getNewType()) {
case BYTE:
Object value = data.getValue();
switch (dataIndex.getNewType()) {
case BYTE -> {
// convert from int, byte
if (metaIndex.getOldType() == EntityDataTypes1_8.BYTE) {
metadata.setValue(value);
if (dataIndex.getOldType() == EntityDataTypes1_8.BYTE) {
data.setValue(value);
}
if (metaIndex.getOldType() == EntityDataTypes1_8.INT) {
metadata.setValue(((Integer) value).byteValue());
if (dataIndex.getOldType() == EntityDataTypes1_8.INT) {
data.setValue(((Integer) value).byteValue());
}
// After writing the last one
if (metaIndex == EntityDataIndex1_9.ENTITY_STATUS && type == EntityTypes1_9.EntityType.PLAYER) {
if (dataIndex == EntityDataIndex1_9.ENTITY_STATUS && type == EntityTypes1_9.EntityType.PLAYER) {
byte val = 0;
if ((((Byte) value) & 0x10) == 0x10) { // Player eating/aiming/drinking
val = 1;
}
int newIndex = EntityDataIndex1_9.PLAYER_HAND.getNewIndex();
EntityDataType metaType = EntityDataIndex1_9.PLAYER_HAND.getNewType();
event.createExtraData(new EntityData(newIndex, metaType, val));
EntityDataType dataType = EntityDataIndex1_9.PLAYER_HAND.getNewType();
event.createExtraData(new EntityData(newIndex, dataType, val));
}
break;
case OPTIONAL_UUID:
}
case OPTIONAL_UUID -> {
String owner = (String) value;
UUID toWrite = null;
if (!owner.isEmpty()) {
@@ -438,52 +433,46 @@ public class EntityPacketRewriter1_9 extends EntityRewriter<ClientboundPackets1_
} catch (Exception ignored) {
}
}
metadata.setValue(toWrite);
break;
case VAR_INT:
data.setValue(toWrite);
}
case VAR_INT -> {
// convert from int, short, byte
if (metaIndex.getOldType() == EntityDataTypes1_8.BYTE) {
metadata.setValue(((Byte) value).intValue());
if (dataIndex.getOldType() == EntityDataTypes1_8.BYTE) {
data.setValue(((Byte) value).intValue());
}
if (metaIndex.getOldType() == EntityDataTypes1_8.SHORT) {
metadata.setValue(((Short) value).intValue());
if (dataIndex.getOldType() == EntityDataTypes1_8.SHORT) {
data.setValue(((Short) value).intValue());
}
if (metaIndex.getOldType() == EntityDataTypes1_8.INT) {
metadata.setValue(value);
if (dataIndex.getOldType() == EntityDataTypes1_8.INT) {
data.setValue(value);
}
break;
case FLOAT, STRING:
metadata.setValue(value);
break;
case BOOLEAN:
if (metaIndex == EntityDataIndex1_9.ABSTRACT_AGEABLE_AGE)
metadata.setValue((Byte) value < 0);
}
case FLOAT, STRING -> data.setValue(value);
case BOOLEAN -> {
if (dataIndex == EntityDataIndex1_9.ABSTRACT_AGEABLE_AGE)
data.setValue((Byte) value < 0);
else
metadata.setValue((Byte) value != 0);
break;
case ITEM:
metadata.setValue(value);
protocol.getItemRewriter().handleItemToClient(event.user(), (Item) metadata.getValue());
break;
case BLOCK_POSITION:
data.setValue((Byte) value != 0);
}
case ITEM -> {
data.setValue(value);
protocol.getItemRewriter().handleItemToClient(event.user(), (Item) data.getValue());
}
case BLOCK_POSITION -> {
Vector vector = (Vector) value;
metadata.setValue(vector);
break;
case ROTATIONS:
data.setValue(vector);
}
case ROTATIONS -> {
EulerAngle angle = (EulerAngle) value;
metadata.setValue(angle);
break;
case COMPONENT:
data.setValue(angle);
}
case COMPONENT -> {
// Was previously also a component, so just convert it
String text = (String) value;
metadata.setValue(ComponentUtil.convertJsonOrEmpty(text, SerializerVersion.V1_8, SerializerVersion.V1_9));
break;
case OPTIONAL_BLOCK_STATE:
// Convert from int, short, byte
metadata.setValue(((Number) value).intValue());
break;
default:
throw new RuntimeException("Unhandled MetaDataType: " + metaIndex.getNewType());
data.setValue(ComponentUtil.convertJsonOrEmpty(text, SerializerVersion.V1_8, SerializerVersion.V1_9));
}
case OPTIONAL_BLOCK_STATE -> data.setValue(((Number) value).intValue()); // Convert from int, short, byte
default -> throw new RuntimeException("Unhandled EntityDataType: " + dataIndex.getNewType());
}
}
@@ -100,20 +100,20 @@ public class SpawnPacketRewriter1_9 {
int typeID = wrapper.get(Types.BYTE, 0);
if (EntityTypes1_8.getTypeFromId(typeID, true) == EntityTypes1_8.EntityType.POTION) {
// Convert this to meta data, woo!
PacketWrapper metaPacket = wrapper.create(ClientboundPackets1_9.SET_ENTITY_DATA, wrapper1 -> {
// Convert this to entity data, woo!
PacketWrapper entityDataPacket = wrapper.create(ClientboundPackets1_9.SET_ENTITY_DATA, wrapper1 -> {
wrapper1.write(Types.VAR_INT, entityID);
List<EntityData> meta = new ArrayList<>();
List<EntityData> entityData = new ArrayList<>();
Item item = new DataItem(373, (byte) 1, (short) data, null); // Potion
protocol.getItemRewriter().handleItemToClient(wrapper.user(), item); // Rewrite so that it gets the right nbt
// TEMP FIX FOR POTIONS UNTIL WE FIGURE OUT HOW TO TRANSFORM SENT PACKETS
EntityData potion = new EntityData(5, EntityDataTypes1_9.ITEM, item);
meta.add(potion);
wrapper1.write(Types1_9.ENTITY_DATA_LIST, meta);
entityData.add(potion);
wrapper1.write(Types1_9.ENTITY_DATA_LIST, entityData);
});
// Fix packet order
wrapper.send(Protocol1_8To1_9.class);
metaPacket.send(Protocol1_8To1_9.class);
entityDataPacket.send(Protocol1_8To1_9.class);
wrapper.cancel();
}
});
@@ -193,22 +193,22 @@ public class SpawnPacketRewriter1_9 {
map(Types1_8.ENTITY_DATA_LIST, Types1_9.ENTITY_DATA_LIST);
handler(wrapper -> {
List<EntityData> metadataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
List<EntityData> entityDataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (tracker.hasEntity(entityId)) {
protocol.getEntityRewriter().handleEntityData(entityId, metadataList, wrapper.user());
protocol.getEntityRewriter().handleEntityData(entityId, entityDataList, wrapper.user());
} else {
protocol.getLogger().warning("Unable to find entity for metadata, entity ID: " + entityId);
metadataList.clear();
protocol.getLogger().warning("Unable to find entity for entity data, entity ID: " + entityId);
entityDataList.clear();
}
});
// Handler for meta data
// Handler for entity data
handler(wrapper -> {
List<EntityData> metadataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
List<EntityData> entityDataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
int entityID = wrapper.get(Types.VAR_INT, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
tracker.handleMetadata(entityID, metadataList);
tracker.handleEntityData(entityID, entityDataList);
});
}
});
@@ -271,23 +271,23 @@ public class SpawnPacketRewriter1_9 {
map(Types1_8.ENTITY_DATA_LIST, Types1_9.ENTITY_DATA_LIST);
handler(wrapper -> {
List<EntityData> metadataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
List<EntityData> entityDataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
if (tracker.hasEntity(entityId)) {
protocol.getEntityRewriter().handleEntityData(entityId, metadataList, wrapper.user());
protocol.getEntityRewriter().handleEntityData(entityId, entityDataList, wrapper.user());
} else {
protocol.getLogger().warning("Unable to find entity for metadata, entity ID: " + entityId);
metadataList.clear();
protocol.getLogger().warning("Unable to find entity for entity data, entity ID: " + entityId);
entityDataList.clear();
}
});
// Handler for meta data
// Handler for entity data
handler(wrapper -> {
List<EntityData> metadataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
List<EntityData> entityDataList = wrapper.get(Types1_9.ENTITY_DATA_LIST, 0);
int entityID = wrapper.get(Types.VAR_INT, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
tracker.handleMetadata(entityID, metadataList);
tracker.handleEntityData(entityID, entityDataList);
});
}
});
@@ -112,6 +112,10 @@ public class WorldPacketRewriter1_9 {
}
wrapper.set(Types.STRING, 0, newname);
wrapper.write(Types.VAR_INT, catid); // Write Category ID
if (!Via.getConfig().cancelBlockSounds()) {
return;
}
if (effect != null && effect.isBreakSound()) {
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
int x = wrapper.passthrough(Types.INT); //Position X
@@ -358,7 +362,27 @@ public class WorldPacketRewriter1_9 {
map(Types.UNSIGNED_BYTE); // 5 - Y
map(Types.UNSIGNED_BYTE); // 6 - Z
//Register block place to fix sounds
// Handle CommandBlocks
handler(wrapper -> {
CommandBlockProvider provider = Via.getManager().getProviders().get(CommandBlockProvider.class);
BlockPosition pos = wrapper.get(Types.BLOCK_POSITION1_8, 0);
Optional<CompoundTag> tag = provider.get(wrapper.user(), pos);
// Send the Update Block Entity packet if present
if (tag.isPresent()) {
PacketWrapper updateBlockEntity = PacketWrapper.create(ClientboundPackets1_9.BLOCK_ENTITY_DATA, null, wrapper.user());
updateBlockEntity.write(Types.BLOCK_POSITION1_8, pos);
updateBlockEntity.write(Types.UNSIGNED_BYTE, (short) 2);
updateBlockEntity.write(Types.NAMED_COMPOUND_TAG, tag.get());
updateBlockEntity.scheduleSend(Protocol1_8To1_9.class);
}
});
if (!Via.getConfig().cancelBlockSounds()) {
return;
}
handler(wrapper -> {
int face = wrapper.get(Types.UNSIGNED_BYTE, 0);
if (face == 255)
@@ -378,25 +402,6 @@ public class WorldPacketRewriter1_9 {
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
tracker.addBlockInteraction(new BlockPosition(x, y, z));
});
// Handle CommandBlocks
handler(wrapper -> {
CommandBlockProvider provider = Via.getManager().getProviders().get(CommandBlockProvider.class);
BlockPosition pos = wrapper.get(Types.BLOCK_POSITION1_8, 0);
Optional<CompoundTag> tag = provider.get(wrapper.user(), pos);
// Send the Update Block Entity packet if present
if (tag.isPresent()) {
PacketWrapper updateBlockEntity = PacketWrapper.create(ClientboundPackets1_9.BLOCK_ENTITY_DATA, null, wrapper.user());
updateBlockEntity.write(Types.BLOCK_POSITION1_8, pos);
updateBlockEntity.write(Types.UNSIGNED_BYTE, (short) 2);
updateBlockEntity.write(Types.NAMED_COMPOUND_TAG, tag.get());
updateBlockEntity.scheduleSend(Protocol1_8To1_9.class);
}
});
}
});
}
@@ -156,32 +156,32 @@ public class EntityTracker1_9 extends EntityTrackerBase {
blockInteractions.add(p);
}
public void handleMetadata(int entityId, List<EntityData> metadataList) {
public void handleEntityData(int entityId, List<EntityData> entityDataList) {
com.viaversion.viaversion.api.minecraft.entities.EntityType type = entityType(entityId);
if (type == null) {
return;
}
for (EntityData metadata : new ArrayList<>(metadataList)) {
for (EntityData entityData : new ArrayList<>(entityDataList)) {
if (type == EntityType.SKELETON) {
if ((getMetaByIndex(metadataList, 12)) == null) {
metadataList.add(new EntityData(12, EntityDataTypes1_9.BOOLEAN, true));
if ((getDataByIndex(entityDataList, 12)) == null) {
entityDataList.add(new EntityData(12, EntityDataTypes1_9.BOOLEAN, true));
}
}
// 1.8 can handle out of range values and will just not show any armor, 1.9+ clients will get
// exceptions and won't render the entity at all
if (type == EntityType.HORSE && metadata.id() == 16) {
final int value = metadata.value();
if (type == EntityType.HORSE && entityData.id() == 16) {
final int value = entityData.value();
if (value < 0 || value > 3) { // no armor, iron armor, gold armor and diamond armor
metadata.setValue(0);
entityData.setValue(0);
}
}
if (type == EntityType.PLAYER) {
if (metadata.id() == 0) {
if (entityData.id() == 0) {
// Byte
byte data = (byte) metadata.getValue();
byte data = (byte) entityData.getValue();
if (entityId != getProvidedEntityId() && Via.getConfig().isShieldBlocking()) {
if ((data & 0x10) == 0x10) {
if (validBlocking.contains(entityId)) {
@@ -195,24 +195,24 @@ public class EntityTracker1_9 extends EntityTrackerBase {
}
}
}
if (metadata.id() == 12 && Via.getConfig().isLeftHandedHandling()) { // Player model
metadataList.add(new EntityData(
if (entityData.id() == 12 && Via.getConfig().isLeftHandedHandling()) { // Player model
entityDataList.add(new EntityData(
13, // Main hand
EntityDataTypes1_9.BYTE,
(byte) (((((byte) metadata.getValue()) & 0x80) != 0) ? 0 : 1)
(byte) (((((byte) entityData.getValue()) & 0x80) != 0) ? 0 : 1)
));
}
}
if (type == EntityType.ARMOR_STAND && Via.getConfig().isHologramPatch()) {
if (metadata.id() == 0 && getMetaByIndex(metadataList, 10) != null) {
EntityData meta = getMetaByIndex(metadataList, 10); //Only happens if the armorstand is small
byte data = (byte) metadata.getValue();
if (entityData.id() == 0 && getDataByIndex(entityDataList, 10) != null) {
EntityData data = getDataByIndex(entityDataList, 10); //Only happens if the armorstand is small
byte value = (byte) entityData.getValue();
// Check invisible | Check small | Check if custom name is empty | Check if custom name visible is true
EntityData displayName;
EntityData displayNameVisible;
if ((data & 0x20) == 0x20 && ((byte) meta.getValue() & 0x01) == 0x01
&& (displayName = getMetaByIndex(metadataList, 2)) != null && !((String) displayName.getValue()).isEmpty()
&& (displayNameVisible = getMetaByIndex(metadataList, 3)) != null && (boolean) displayNameVisible.getValue()) {
if ((value & 0x20) == 0x20 && ((byte) data.getValue() & 0x01) == 0x01
&& (displayName = getDataByIndex(entityDataList, 2)) != null && !((String) displayName.getValue()).isEmpty()
&& (displayNameVisible = getDataByIndex(entityDataList, 3)) != null && (boolean) displayNameVisible.getValue()) {
if (!knownHolograms.contains(entityId)) {
knownHolograms.add(entityId);
// Send movement
@@ -230,9 +230,9 @@ public class EntityTracker1_9 extends EntityTrackerBase {
// Boss bar
if (Via.getConfig().isBossbarPatch()) {
if (type == EntityType.ENDER_DRAGON || type == EntityType.WITHER) {
if (metadata.id() == 2) {
if (entityData.id() == 2) {
BossBar bar = bossBarMap.get(entityId);
String title = (String) metadata.getValue();
String title = (String) entityData.getValue();
title = title.isEmpty() ? (type == EntityType.ENDER_DRAGON ? DRAGON_TRANSLATABLE : WITHER_TRANSLATABLE) : title;
if (bar == null) {
bar = Via.getAPI().legacyAPI().createLegacyBossBar(title, BossColor.PINK, BossStyle.SOLID);
@@ -245,11 +245,11 @@ public class EntityTracker1_9 extends EntityTrackerBase {
} else {
bar.setTitle(title);
}
} else if (metadata.id() == 6 && !Via.getConfig().isBossbarAntiflicker()) { // If anti flicker is enabled, don't update health
} else if (entityData.id() == 6 && !Via.getConfig().isBossbarAntiflicker()) { // If anti flicker is enabled, don't update health
BossBar bar = bossBarMap.get(entityId);
// Make health range between 0 and 1
float maxHealth = type == EntityType.ENDER_DRAGON ? 200.0f : 300.0f;
float health = Math.max(0.0f, Math.min(((float) metadata.getValue()) / maxHealth, 1.0f));
float health = Math.max(0.0f, Math.min(((float) entityData.getValue()) / maxHealth, 1.0f));
if (bar == null) {
String title = type == EntityType.ENDER_DRAGON ? DRAGON_TRANSLATABLE : WITHER_TRANSLATABLE;
bar = Via.getAPI().legacyAPI().createLegacyBossBar(title, health, BossColor.PINK, BossStyle.SOLID);
@@ -267,10 +267,10 @@ public class EntityTracker1_9 extends EntityTrackerBase {
}
}
public EntityData getMetaByIndex(List<EntityData> list, int index) {
for (EntityData meta : list)
if (index == meta.id()) {
return meta;
public EntityData getDataByIndex(List<EntityData> list, int index) {
for (EntityData data : list)
if (index == data.id()) {
return data;
}
return null;
}
@@ -46,15 +46,15 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
return inputValue / 63.0F;
}
};
public static final ValueTransformer<List<EntityData>, List<EntityData>> TRANSFORM_METADATA = new ValueTransformer<>(Types1_9.ENTITY_DATA_LIST) {
public static final ValueTransformer<List<EntityData>, List<EntityData>> TRANSFORM_ENTITY_DATA = new ValueTransformer<>(Types1_9.ENTITY_DATA_LIST) {
@Override
public List<EntityData> transform(PacketWrapper wrapper, List<EntityData> inputValue) {
List<EntityData> metaList = new CopyOnWriteArrayList<>(inputValue);
for (EntityData m : metaList) {
if (m.id() >= 5)
m.setId(m.id() + 1);
List<EntityData> dataList = new CopyOnWriteArrayList<>(inputValue);
for (EntityData data : dataList) {
if (data.id() >= 5)
data.setId(data.id() + 1);
}
return metaList;
return dataList;
}
};
private final ItemPacketRewriter1_10 itemRewriter = new ItemPacketRewriter1_10(this);
@@ -100,12 +100,12 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
}
});
// Metadata packet
// Entity data packet
registerClientbound(ClientboundPackets1_9_3.SET_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types1_9.ENTITY_DATA_LIST, TRANSFORM_METADATA); // 1 - Metadata list
map(Types1_9.ENTITY_DATA_LIST, TRANSFORM_ENTITY_DATA); // 1 - Entity data list
}
});
@@ -125,7 +125,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_9.ENTITY_DATA_LIST, TRANSFORM_METADATA); // 12 - Metadata
map(Types1_9.ENTITY_DATA_LIST, TRANSFORM_ENTITY_DATA); // 12 - Entity data
}
});
@@ -140,7 +140,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_9.ENTITY_DATA_LIST, TRANSFORM_METADATA); // 7 - Metadata list
map(Types1_9.ENTITY_DATA_LIST, TRANSFORM_ENTITY_DATA); // 7 - Entity data list
}
});
@@ -85,8 +85,8 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
public void registerPlayerCombat(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
if (wrapper.passthrough(Types.VAR_INT) == 2) {
wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.INT);
wrapper.passthrough(Types.VAR_INT); // Player ID
wrapper.passthrough(Types.INT); // Killer ID
processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT));
}
});
@@ -142,8 +142,8 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT);
map(Types.INT);
map(Types.VAR_INT); // Player ID
map(Types.INT); // Killer ID
handler(wrapper -> processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT)));
}
});
@@ -153,7 +153,7 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Duration
map(Types.VAR_INT); // Player ID
handler(wrapper -> passthroughAndProcess(wrapper));
}
});
@@ -161,12 +161,8 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
public void passthroughAndProcess(final PacketWrapper wrapper) {
switch (type) {
case JSON:
processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT));
break;
case NBT:
processTag(wrapper.user(), wrapper.passthrough(Types.TAG));
break;
case JSON -> processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT));
case NBT -> processTag(wrapper.user(), wrapper.passthrough(Types.TAG));
}
}
@@ -108,10 +108,10 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
}
@Override
public void handleEntityData(final int entityId, final List<EntityData> entityDataList, final UserConnection connection) {
public void handleEntityData(final int entityId, final List<EntityData> dataList, final UserConnection connection) {
final TrackedEntity entity = tracker(connection).entity(entityId);
final EntityType type = entity != null ? entity.entityType() : null;
for (final EntityData entityData : entityDataList.toArray(EMPTY_ARRAY)) { // Copy the list to allow mutation
for (final EntityData entityData : dataList.toArray(EMPTY_ARRAY)) { // Copy the list to allow mutation
EntityDataHandlerEvent event = null;
for (final EntityDataFilter filter : entityDataFilters) {
if (!filter.isFiltered(type, entityData)) {
@@ -119,27 +119,27 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
}
if (event == null) {
// Instantiate lazily and share event instance
event = new EntityDataHandlerEventImpl(connection, entity, entityId, entityData, entityDataList);
event = new EntityDataHandlerEventImpl(connection, entity, entityId, entityData, dataList);
}
try {
filter.handler().handle(event, entityData);
} catch (final Exception e) {
logException(e, type, entityDataList, entityData);
entityDataList.remove(entityData);
logException(e, type, dataList, entityData);
dataList.remove(entityData);
break;
}
if (event.cancelled()) {
// Remove entity data, and break current filter loop
entityDataList.remove(entityData);
dataList.remove(entityData);
break;
}
}
if (event != null && event.hasExtraData()) {
// Finally, add newly created entity data
entityDataList.addAll(event.extraData());
dataList.addAll(event.extraData());
}
}
@@ -237,9 +237,9 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
}
public void registerBlockStateHandler(final EntityType entityType, final int index) {
filter().type(entityType).index(index).handler((event, meta) -> {
final int data = (int) meta.getValue();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
filter().type(entityType).index(index).handler((event, data) -> {
final int state = (int) data.getValue();
data.setValue(protocol.getMappingData().getNewBlockStateId(state));
});
}
@@ -17,6 +17,7 @@
*/
package com.viaversion.viaversion.rewriter;
import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.Mappings;
@@ -363,8 +364,14 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
// Display data
if (wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.COMPONENT); // Title
wrapper.passthrough(Types.COMPONENT); // Description
final JsonElement title = wrapper.passthrough(Types.COMPONENT); // Title
final JsonElement description = wrapper.passthrough(Types.COMPONENT); // Description
final ComponentRewriter componentRewriter = protocol.getComponentRewriter();
if (componentRewriter != null) {
componentRewriter.processText(wrapper.user(), title);
componentRewriter.processText(wrapper.user(), description);
}
handleClientboundItem(wrapper); // Icon
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
@@ -423,6 +430,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
});
}
// Pre 1.21 for enchantments
public void registerContainerSetData(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
@@ -31,13 +31,13 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
@Nullable EntityDataType dataType, int index, EntityDataHandler handler) {
public EntityDataFilter {
Preconditions.checkNotNull(handler, "MetaHandler cannot be null");
Preconditions.checkNotNull(handler, "EntityDataHandler cannot be null");
}
/**
* Returns the metadata index to filter, or -1.
* Returns the entity data index to filter, or -1.
*
* @return metadata index, or -1 if unset
* @return entity data index, or -1 if unset
*/
public int index() {
return index;
@@ -62,9 +62,9 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
}
/**
* Returns the metadata handler.
* Returns the entity data handler.
*
* @return metadata handler
* @return entity data handler
*/
public EntityDataHandler handler() {
return handler;
@@ -80,18 +80,18 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
}
/**
* Returns whether if the metadata should be handled by this filter.
* Returns whether if the entity data should be handled by this filter.
*
* @param type entity type
* @param metadata metadata
* @return whether the meta should be filtered
* @param entityData entityData
* @return whether the data should be filtered
*/
public boolean isFiltered(@Nullable EntityType type, EntityData metadata) {
public boolean isFiltered(@Nullable EntityType type, EntityData entityData) {
// Check if no specific index is filtered or the indexes are equal
// Then check if the filter has no entity type or the type is equal to or part of the filtered parent type
return (this.index == -1 || metadata.id() == this.index)
return (this.index == -1 || entityData.id() == this.index)
&& (this.type == null || matchesType(type))
&& (this.dataType == null || metadata.dataType() == this.dataType);
&& (this.dataType == null || entityData.dataType() == this.dataType);
}
private boolean matchesType(EntityType type) {
@@ -156,7 +156,7 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
* Sets the type to filter, including subtypes.
* <p>
* You should always register a type when accessing specific indexes,
* even if it is the base entity type, to avoid metadata from unregistered
* even if it is the base entity type, to avoid entity data from unregistered
* entities causing issues.
*
* @param type entity type to filter
@@ -173,7 +173,7 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
* Sets the type to filter, not including subtypes.
* <p>
* You should always register a type when accessing specific indexes,
* even if it is the base entity type, to avoid metadata from unregistered
* even if it is the base entity type, to avoid entity data from unregistered
* entities causing issues.
*
* @param type exact entity type to filter
@@ -199,10 +199,10 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
}
/**
* Sets the metadata handler and registers the metadata filter.
* Sets the entity data handler and registers the entity data filter.
* Should always be called last.
*
* @param handler metadata handler
* @param handler entity data handler
* @throws IllegalArgumentException if a handler has already been set
*/
public void handler(EntityDataHandler handler) {
@@ -212,10 +212,10 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
}
public void mapDataType(Int2ObjectFunction<EntityDataType> updateFunction) {
handler((event, meta) -> {
EntityDataType mappedType = updateFunction.apply(meta.dataType().typeId());
handler((event, data) -> {
EntityDataType mappedType = updateFunction.apply(data.dataType().typeId());
if (mappedType != null) {
meta.setDataType(mappedType);
data.setDataType(mappedType);
} else {
event.cancel();
}
@@ -223,14 +223,14 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
}
/**
* Sets a handler to remove metadata at the given index without affecting any other indexes and registers the filter.
* Sets a handler to remove entity data at the given index without affecting any other indexes and registers the filter.
* Should always be called last.
*
* @param index index to cancel
*/
public void cancel(int index) {
this.index = index;
handler((event, meta) -> event.cancel());
handler((event, data) -> event.cancel());
}
/**
@@ -242,7 +242,7 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
*/
public void toIndex(int newIndex) {
Preconditions.checkArgument(this.index != -1);
handler((event, meta) -> event.setIndex(newIndex));
handler((event, data) -> event.setIndex(newIndex));
}
/**
@@ -254,7 +254,7 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
*/
public void addIndex(int index) {
Preconditions.checkArgument(this.index == -1);
handler((event, meta) -> {
handler((event, data) -> {
if (event.index() >= index) {
event.setIndex(event.index() + 1);
}
@@ -262,7 +262,7 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
}
/**
* Sets a handler to remove metadata at the given index, decrementing every index above it and registers the filter.
* Sets a handler to remove entity data at the given index, decrementing every index above it and registers the filter.
* Should always be called last.
*
* @param index index to remove
@@ -270,27 +270,27 @@ public record EntityDataFilter(@Nullable EntityType type, boolean filterFamily,
*/
public void removeIndex(int index) {
Preconditions.checkArgument(this.index == -1);
handler((event, meta) -> {
int metaIndex = event.index();
if (metaIndex == index) {
handler((event, data) -> {
int dataIndex = event.index();
if (dataIndex == index) {
event.cancel();
} else if (metaIndex > index) {
event.setIndex(metaIndex - 1);
} else if (dataIndex > index) {
event.setIndex(dataIndex - 1);
}
});
}
/**
* Creates and registers the created MetaFilter in the linked {@link EntityRewriter} instance.
* Creates and registers the created EntityDataFilter in the linked {@link EntityRewriter} instance.
*/
public void register() {
rewriter.registerFilter(build());
}
/**
* Returns a new metadata filter without registering it.
* Returns a new entity data filter without registering it.
*
* @return created meta filter
* @return created data filter
*/
public EntityDataFilter build() {
return new EntityDataFilter(type, filterFamily, dataType, index, handler);
@@ -27,7 +27,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public interface EntityDataHandlerEvent {
/**
* Returns the user connection the metadata is sent to.
* Returns the user connection the entity data is sent to.
*
* @return user connection
*/
@@ -30,17 +30,17 @@ public class EntityDataHandlerEventImpl implements EntityDataHandlerEvent {
private final UserConnection connection;
private final TrackedEntity trackedEntity;
private final int entityId;
private final List<EntityData> metadataList;
private final EntityData meta;
private final List<EntityData> dataList;
private final EntityData data;
private List<EntityData> extraData;
private boolean cancel;
public EntityDataHandlerEventImpl(UserConnection connection, @Nullable TrackedEntity trackedEntity, int entityId, EntityData meta, List<EntityData> metadataList) {
public EntityDataHandlerEventImpl(UserConnection connection, @Nullable TrackedEntity trackedEntity, int entityId, EntityData data, List<EntityData> dataList) {
this.connection = connection;
this.trackedEntity = trackedEntity;
this.entityId = entityId;
this.meta = meta;
this.metadataList = metadataList;
this.data = data;
this.dataList = dataList;
}
@Override
@@ -60,7 +60,7 @@ public class EntityDataHandlerEventImpl implements EntityDataHandlerEvent {
@Override
public EntityData data() {
return meta;
return data;
}
@Override
@@ -75,9 +75,9 @@ public class EntityDataHandlerEventImpl implements EntityDataHandlerEvent {
@Override
public @Nullable EntityData dataAtIndex(int index) {
for (EntityData meta : metadataList) {
if (index == meta.id()) {
return meta;
for (EntityData data : dataList) {
if (index == data.id()) {
return data;
}
}
return null;
@@ -85,7 +85,7 @@ public class EntityDataHandlerEventImpl implements EntityDataHandlerEvent {
@Override
public List<EntityData> dataList() {
return Collections.unmodifiableList(metadataList);
return Collections.unmodifiableList(dataList);
}
@Override
@@ -94,11 +94,11 @@ public class EntityDataHandlerEventImpl implements EntityDataHandlerEvent {
}
@Override
public void createExtraData(EntityData metadata) {
public void createExtraData(EntityData entityData) {
if (extraData == null) {
extraData = new ArrayList<>();
}
extraData.add(metadata);
extraData.add(entityData);
}
}
@@ -86,8 +86,8 @@ public abstract class Config {
private synchronized Map<String, Object> loadConfig(File location, InputStreamSupplier configSupplier) {
List<String> unsupported = getUnsupportedOptions();
try {
commentStore.storeComments(configSupplier.get());
try (InputStream inputStream = configSupplier.get()) {
commentStore.storeComments(inputStream);
for (String option : unsupported) {
List<String> comments = commentStore.header(option);
if (comments != null) {
@@ -95,42 +95,46 @@ public abstract class Config {
}
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed to load default config comments", e);
}
// Load actual file data
Map<String, Object> config = null;
if (location.exists()) {
try (FileInputStream input = new FileInputStream(location)) {
//noinspection unchecked
config = (Map<String, Object>) YAML.get().load(input);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed to load config", e);
} catch (Exception e) {
logger.severe("Failed to load config, make sure your input is valid");
throw new RuntimeException("Failed to load config (malformed input?)", e);
}
}
if (config == null) {
config = new HashMap<>();
}
Map<String, Object> defaults = config;
// Load default config and merge with current to make sure we always have an up-to-date/correct config
Map<String, Object> mergedConfig;
try (InputStream stream = configSupplier.get()) {
defaults = (Map<String, Object>) YAML.get().load(stream);
for (String option : unsupported) {
defaults.remove(option);
}
// Merge with defaultLoader
for (Map.Entry<String, Object> entry : config.entrySet()) {
// Set option in new conf if exists
if (defaults.containsKey(entry.getKey()) && !unsupported.contains(entry.getKey())) {
defaults.put(entry.getKey(), entry.getValue());
}
}
//noinspection unchecked
mergedConfig = (Map<String, Object>) YAML.get().load(stream);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed to load default config", e);
}
for (String option : unsupported) {
mergedConfig.remove(option);
}
for (Map.Entry<String, Object> entry : config.entrySet()) {
// Set option in new conf if it exists
mergedConfig.computeIfPresent(entry.getKey(), (key, value) -> entry.getValue());
}
// Call Handler
handleConfig(defaults);
// Save
save(location, defaults);
return defaults;
handleConfig(mergedConfig);
save(location, mergedConfig);
return mergedConfig;
}
protected abstract void handleConfig(Map<String, Object> config);
@@ -62,7 +62,6 @@ public final class DumpUtil {
final VersionInfo version = new VersionInfo(
System.getProperty("java.version"),
System.getProperty("os.name"),
protocolVersion.getVersionType(),
protocolVersion.getVersion(),
protocolVersion.getName(),
Via.getManager().getProtocolManager().getSupportedVersions().stream().map(ProtocolVersion::toString).collect(Collectors.toCollection(LinkedHashSet::new)),
@@ -64,6 +64,11 @@ public final class TagUtil {
return compoundTag != null ? compoundTag : tag.getCompoundTag(Key.stripMinecraftNamespace(key));
}
public static @Nullable ListTag<CompoundTag> getNamespacedCompoundTagList(final CompoundTag tag, final String key) {
final ListTag<CompoundTag> listTag = tag.getListTag(Key.namespaced(key), CompoundTag.class);
return listTag != null ? listTag : tag.getListTag(Key.stripMinecraftNamespace(key), CompoundTag.class);
}
public static Tag handleDeep(final Tag tag, final TagUpdater consumer) {
return handleDeep(null, tag, consumer);
}
@@ -173,7 +173,7 @@ handle-invalid-item-count: false
prevent-collision: true
# If the above is true, should we automatically team players until you do?
auto-team: true
# When enabled if certain metadata can't be read, we won't tell you about it
# When enabled if certain entity data can't be read, we won't tell you about it
suppress-metadata-errors: false
# When enabled, 1.9+ will be able to block by using shields
shield-blocking: true
@@ -205,7 +205,7 @@ replace-pistons: false
replacement-piston-id: 0
# Fix 1.9+ clients not rendering the far away chunks and improve chunk rendering when moving fast (Increases network usage and decreases client fps slightly)
chunk-border-fix: false
# Minimize the cooldown animation in 1.8 servers
minimize-cooldown: true
# Allows 1.9+ left-handedness (main hand) on 1.8 servers
left-handed-handling: true
# Tries to cancel block break/place sounds sent by 1.8 servers to 1.9+ clients to prevent them from playing twice
cancel-block-sounds: true
@@ -1474,11 +1474,11 @@
"enchantment.binding_curse": "enchantment.minecraft.binding_curse",
"enchantment.vanishing_curse": "enchantment.minecraft.vanishing_curse",
"enchantment.level.1": null,
"enchantment.level.2": "potion.potency.1",
"enchantment.level.3": "potion.potency.2",
"enchantment.level.4": "potion.potency.3",
"enchantment.level.5": "potion.potency.4",
"enchantment.level.6": "potion.potency.5",
"enchantment.level.2": null,
"enchantment.level.3": null,
"enchantment.level.4": null,
"enchantment.level.5": null,
"enchantment.level.6": null,
"enchantment.level.7": null,
"enchantment.level.8": null,
"enchantment.level.9": null,
@@ -30,7 +30,7 @@ public final class DummyInitializer {
}
initialized = true;
Via.init(new ViaManagerImpl(new TestPlatform(), new TestInjector(), null, new TestLoader()));
Via.init(new ViaManagerImpl(new TestPlatform(), new TestInjector(), new TestCommandHandler(), new TestLoader()));
final ViaManagerImpl manager = (ViaManagerImpl) Via.getManager();
manager.init();
@@ -0,0 +1,24 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.common.dummy;
import com.viaversion.viaversion.commands.ViaCommandHandler;
public class TestCommandHandler extends ViaCommandHandler {
}
+1 -1
View File
@@ -1,5 +1,5 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=5.0.1
projectVersion=5.0.2
# Smile emoji
mcVersions=1.21,1.20.6,1.20.5,1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9
Loaded 100 of 109 files, more files were not shown because too many files have changed in this diff. Show more