3
0
Mirror von https://github.com/ViaVersion/ViaVersion.git synchronisiert 2024-12-28 09:00:09 +01:00

Merge branch 'master' into component-rewriter-work

# Conflicts:
#	common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/ComponentRewriter1_20_5.java
Dieser Commit ist enthalten in:
FlorianMichael 2024-10-09 14:00:23 +02:00
Commit de05975dc3
75 geänderte Dateien mit 876 neuen und 611 gelöschten Zeilen

Datei anzeigen

@ -11,4 +11,4 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v1
uses: gradle-update/update-gradle-wrapper-action@v2

Datei anzeigen

@ -471,4 +471,11 @@ public interface ViaVersionConfig extends Config {
* @return true if enabled
*/
boolean hideScoreboardNumbers();
/**
* Fixes 1.21+ clients on 1.20.5 servers placing water/lava buckets at the wrong location when moving fast.
*
* @return true if enabled
*/
boolean fix1_21PlacementRotation();
}

Datei anzeigen

@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.connection;
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketTracker;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
@ -99,14 +100,33 @@ public interface UserConnection {
void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker);
/**
* Clear stored objects and entity trackers.
* Returns the client world by the given protocol class if present.
*
* @param protocolClass protocol class
* @param <T> client world type
* @return client world if present
*/
@Nullable
<T extends ClientWorld> T getClientWorld(Class<? extends Protocol> protocolClass);
/**
* Adds a client world to the user connection.
* Does not override existing client worlds.
*
* @param protocolClass protocol class
* @param clientWorld client world
*/
void addClientWorld(Class<? extends Protocol> protocolClass, ClientWorld clientWorld);
/**
* Clear stored objects, entity trackers and client worlds.
*/
default void clearStoredObjects() {
clearStoredObjects(false);
}
/**
* Clear stored objects and entity trackers.
* Clear stored objects, entity trackers and client worlds.
* If cleared for a proxy server switch, some stored objects and tracker data will be retained.
*
* @param isServerSwitch whether the clear is due to a server switch

Datei anzeigen

@ -83,6 +83,10 @@ public interface MappingData {
int getNewAttributeId(int id);
int getNewSoundId(int id);
int getOldSoundId(int i);
/**
* Returns a list of tags to send if present.
*

Datei anzeigen

@ -203,6 +203,16 @@ public class MappingDataBase implements MappingData {
return checkValidity(id, attributeMappings.getNewId(id), "attributes");
}
@Override
public int getNewSoundId(final int id) {
return checkValidity(id, soundMappings.getNewId(id), "sound");
}
@Override
public int getOldSoundId(final int i) {
return soundMappings.getNewIdOrDefault(i, 0);
}
@Override
public @Nullable List<TagData> getTags(final RegistryType type) {
return tags != null ? tags.get(type) : null;

Datei anzeigen

@ -30,7 +30,6 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.viaversion.nbt.io.NBTIO;
import com.viaversion.nbt.io.TagReader;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.IntTag;
@ -211,68 +210,64 @@ public class MappingDataLoader {
return null;
}
final ByteTag serializationStragetyTag = tag.getUnchecked("id");
final IntTag mappedSizeTag = tag.getUnchecked("mappedSize");
final byte strategy = serializationStragetyTag.asByte();
final int mappedSize = tag.getIntTag("mappedSize").asInt();
final byte strategy = tag.getByteTag("id").asByte();
final V mappings;
if (strategy == DIRECT_ID) {
final IntArrayTag valuesTag = tag.getIntArrayTag("val");
return IntArrayMappings.of(valuesTag.getValue(), mappedSizeTag.asInt());
return IntArrayMappings.of(valuesTag.getValue(), mappedSize);
} else if (strategy == SHIFTS_ID) {
final IntArrayTag shiftsAtTag = tag.getIntArrayTag("at");
final IntArrayTag shiftsTag = tag.getIntArrayTag("to");
final IntTag sizeTag = tag.getUnchecked("size");
final int[] shiftsAt = shiftsAtTag.getValue();
final int[] shiftsTo = shiftsTag.getValue();
final int size = sizeTag.asInt();
final int[] shiftsAt = tag.getIntArrayTag("at").getValue();
final int[] shiftsTo = tag.getIntArrayTag("to").getValue();
final int size = tag.getIntTag("size").asInt();
mappings = holderSupplier.get(size);
// Handle values until first shift
if (shiftsAt[0] != 0) {
// Add identity values before the first shift
final int to = shiftsAt[0];
for (int id = 0; id < to; id++) {
addConsumer.addTo(mappings, id, id);
}
}
// Handle shifts
// Read shifts
for (int i = 0; i < shiftsAt.length; i++) {
final boolean isLast = i == shiftsAt.length - 1;
final int from = shiftsAt[i];
final int to = i == shiftsAt.length - 1 ? size : shiftsAt[i + 1];
final int to = isLast ? size : shiftsAt[i + 1];
int mappedId = shiftsTo[i];
for (int id = from; id < to; id++) {
addConsumer.addTo(mappings, id, mappedId++);
}
}
} else if (strategy == CHANGES_ID) {
final IntArrayTag changesAtTag = tag.getIntArrayTag("at");
final IntArrayTag valuesTag = tag.getIntArrayTag("val");
final IntTag sizeTag = tag.getUnchecked("size");
final int[] changesAt = tag.getIntArrayTag("at").getValue();
final int[] values = tag.getIntArrayTag("val").getValue();
final int size = tag.getIntTag("size").asInt();
final boolean fillBetween = tag.get("nofill") == null;
final int[] changesAt = changesAtTag.getValue();
final int[] values = valuesTag.getValue();
mappings = holderSupplier.get(sizeTag.asInt());
mappings = holderSupplier.get(size);
int nextUnhandledId = 0;
for (int i = 0; i < changesAt.length; i++) {
final int id = changesAt[i];
final int changedId = changesAt[i];
if (fillBetween) {
// Fill from after the last change to before this change with unchanged ids
final int previousId = i != 0 ? changesAt[i - 1] + 1 : 0;
for (int identity = previousId; identity < id; identity++) {
addConsumer.addTo(mappings, identity, identity);
for (int id = nextUnhandledId; id < changedId; id++) {
addConsumer.addTo(mappings, id, id);
}
nextUnhandledId = changedId + 1;
}
// Assign the changed value
addConsumer.addTo(mappings, id, values[i]);
addConsumer.addTo(mappings, changedId, values[i]);
}
} else if (strategy == IDENTITY_ID) {
final IntTag sizeTag = tag.getUnchecked("size");
return new IdentityMappings(sizeTag.asInt(), mappedSizeTag.asInt());
final IntTag sizeTag = tag.getIntTag("size");
return new IdentityMappings(sizeTag.asInt(), mappedSize);
} else {
throw new IllegalArgumentException("Unknown serialization strategy: " + strategy);
}
return mappingsSupplier.create(mappings, mappedSizeTag.asInt());
return mappingsSupplier.create(mappings, mappedSize);
}
public @Nullable List<String> identifiersFromGlobalIds(final CompoundTag mappingsTag, final String key) {
@ -295,7 +290,7 @@ public class MappingDataLoader {
* @return map with indexes hashed by their id value
*/
public Object2IntMap<String> indexedObjectToMap(final JsonObject object) {
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(object.size(), .99F);
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(object.size());
map.defaultReturnValue(-1);
for (final Map.Entry<String, JsonElement> entry : object.entrySet()) {
map.put(entry.getValue().getAsString(), Integer.parseInt(entry.getKey()));
@ -310,7 +305,7 @@ public class MappingDataLoader {
* @return map with indexes hashed by their id value
*/
public Object2IntMap<String> arrayToMap(final JsonArray array) {
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(array.size(), .99F);
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(array.size());
map.defaultReturnValue(-1);
for (int i = 0; i < array.size(); i++) {
map.put(array.get(i).getAsString(), i);

Datei anzeigen

@ -78,7 +78,7 @@ public interface EntityTracker {
void removeEntity(int id);
/**
* Clears stored entity types and data.
* Clears stored entity types and data, only leaving behind the client entity.
*/
void clearEntities();
@ -102,11 +102,19 @@ public interface EntityTracker {
@Nullable StoredEntityData entityDataIfPresent(int id);
/**
* Returns the client entity id or -1 if unset.
* Returns whether the client entity id has been set.
*
* @return client entity id or -1 if unset
* @return whether the client entity id has been set
*/
int clientEntityId();
boolean hasClientEntityId();
/**
* Returns the client entity id. Should be wrapped around {@link #hasClientEntityId()}.
*
* @return client entity id
* @throws IllegalStateException if the client entity id has not been set
*/
int clientEntityId() throws IllegalStateException;
/**
* Sets the client entity id.
@ -169,12 +177,4 @@ public interface EntityTracker {
@Nullable DimensionData dimensionData(int dimensionId);
void setDimensions(Map<String, DimensionData> dimensions);
/**
* Adds the client player entity to the tracker.
* If the client entity has not been set yet, this will return false.
*
* @return whether the client has been tracked
*/
boolean trackClientEntity();
}

Datei anzeigen

@ -23,13 +23,12 @@
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.connection.StorableObject;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Stored up until 1.14 to be used in chunk sending.
*/
public class ClientWorld implements StorableObject {
private Environment environment;
private Environment environment = Environment.NORMAL;
public ClientWorld() {
}
@ -38,11 +37,20 @@ public class ClientWorld implements StorableObject {
this.environment = environment;
}
public @Nullable Environment getEnvironment() {
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(final int environmentId) {
/**
* Sets the environment of the world and returns whether the environment was changed.
*
* @param environmentId the id of the environment to set
* @return whether the environment was changed
*/
public boolean setEnvironment(final int environmentId) {
final int previousEnvironmentId = environment.id();
this.environment = Environment.getEnvironmentById(environmentId);
return previousEnvironmentId != environmentId;
}
}

Datei anzeigen

@ -22,6 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public interface Holder<T> {
/**
@ -79,4 +81,12 @@ public interface Holder<T> {
* @see #hasId()
*/
int id();
/**
* Returns a new holder with the id rewritten using the given function, or self if this is a direct holder or the id did not change.
*
* @param rewriteFunction the function to rewrite the id
* @return a new holder with the id rewritten, or self
*/
Holder<T> updateId(final Int2IntFunction rewriteFunction);
}

Datei anzeigen

@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
final class HolderImpl<T> implements Holder<T> {
@ -61,6 +62,22 @@ final class HolderImpl<T> implements Holder<T> {
return id;
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
if (isDirect()) {
return this;
}
final int rewrittenId = rewriteFunction.applyAsInt(id);
if (rewrittenId == id) {
return this;
}
if (rewrittenId == -1) {
throw new IllegalArgumentException("Received invalid id in updateId");
}
return Holder.of(rewrittenId);
}
@Override
public String toString() {
return "HolderImpl{" +

Datei anzeigen

@ -64,7 +64,7 @@ final class HolderSetImpl extends EitherImpl<String, int[]> implements HolderSet
final int[] ids = ids();
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.apply(ids[i]);
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
}
return new HolderSetImpl(mappedIds);
}

Datei anzeigen

@ -52,16 +52,14 @@ public interface StructuredData<T> extends IdHolder {
return new EmptyStructuredData<>(key, id);
}
void setValue(final T value);
@Nullable T value();
void write(final ByteBuf buffer);
void setValue(final T value);
void setId(final int id);
StructuredDataKey<T> key();
@Nullable T value();
/**
* Returns whether the structured data is present. Even if true, the value may be null.
*
@ -77,4 +75,6 @@ public interface StructuredData<T> extends IdHolder {
* @return true if the structured data is empty
*/
boolean isEmpty();
void write(final ByteBuf buffer);
}

Datei anzeigen

@ -33,6 +33,26 @@ import java.util.Map;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Loosely represents Minecraft's data component patch, but may also be used for an item's full data components.
* <p>
* The most commonly used methods will ignore empty data (aka empty overrides that remove item defaults) since those will rarely be needed.
* These are:
* <ul>
* <li>{@link #get(StructuredDataKey)}</li>
* <li>{@link #set(StructuredDataKey, Object)}</li>
* <li>{@link #set(StructuredDataKey)}</li>
* <li>{@link #getNonEmptyData(StructuredDataKey)}</li>
* <li>{@link #hasValue(StructuredDataKey)}</li>
* </ul>
*
* To interact with empty patches specifically, use:
* <ul>
* <li>{@link #setEmpty(StructuredDataKey)}</li>
* <li>{@link #hasEmpty(StructuredDataKey)}</li>
* </ul>
* Other methods (e.g. {@link #getData(StructuredDataKey)} and {@link #has(StructuredDataKey)}) will handle both empty and non-empty data.
*/
public final class StructuredDataContainer {
private final Map<StructuredDataKey<?>, StructuredData<?>> data;
@ -55,66 +75,45 @@ public final class StructuredDataContainer {
}
/**
* Returns structured data by id if present.
* Returns the non-empty value by id if present.
*
* @param key serializer id
* @param <T> data type
* @return structured data
* @see #hasEmpty(StructuredDataKey)
*/
public @Nullable <T> T get(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.get(key);
if (data == null || data.isEmpty()) {
return null;
}
//noinspection unchecked
return ((StructuredData<T>) data).value();
}
/**
* Returns structured data by id if present, either empty or non-empty.
*
* @param key serializer id
* @param <T> data type
* @return structured data
*/
public @Nullable <T> StructuredData<T> get(final StructuredDataKey<T> key) {
public @Nullable <T> StructuredData<T> getData(final StructuredDataKey<T> key) {
//noinspection unchecked
return (StructuredData<T>) this.data.get(key);
}
/**
* Returns structured data by id if not empty.
* Returns non-empty structured data by id if present.
*
* @param key serializer id
* @param <T> data type
* @return structured data if not empty
* @return non-empty structured data
*/
public @Nullable <T> StructuredData<T> getNonEmpty(final StructuredDataKey<T> key) {
public @Nullable <T> StructuredData<T> getNonEmptyData(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.get(key);
//noinspection unchecked
final StructuredData<T> data = (StructuredData<T>) this.data.get(key);
return data != null && data.isPresent() ? data : null;
}
/**
* Returns structured data by id if not empty, or creates it.
*
* @param key serializer id
* @param mappingFunction function to create structured data if not present
* @param <T> data type
* @return structured data if not empty
*/
public <T> StructuredData<T> computeIfAbsent(final StructuredDataKey<T> key, final Function<StructuredDataKey<T>, T> mappingFunction) {
final StructuredData<T> data = this.getNonEmpty(key);
if (data != null) {
return data;
}
final int id = serializerId(key);
final StructuredData<T> empty = StructuredData.of(key, mappingFunction.apply(key), id);
this.data.put(key, empty);
return empty;
}
/**
* Updates and returns the structured data by id if not empty.
*
* @param key serializer id
* @param mappingFunction function to update existing data
* @param <T> data type
* @return updated structured data if not empty
*/
public <T> @Nullable StructuredData<T> updateIfPresent(final StructuredDataKey<T> key, final Function<T, T> mappingFunction) {
final StructuredData<T> data = this.getNonEmpty(key);
if (data == null) {
return null;
}
data.setValue(mappingFunction.apply(data.value()));
return data;
return data != null && data.isPresent() ? (StructuredData<T>) data : null;
}
public <T> void set(final StructuredDataKey<T> key, final T value) {
@ -124,49 +123,105 @@ public final class StructuredDataContainer {
}
}
public <T> void replaceKey(final StructuredDataKey<T> key, final StructuredDataKey<T> toKey) {
replace(key, toKey, Function.identity());
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, V> valueMapper) {
final StructuredData<T> data = remove(key);
if (data == null) {
return;
}
if (data.isPresent()) {
set(toKey, valueMapper.apply(data.value()));
} else {
addEmpty(toKey);
}
}
public void set(final StructuredDataKey<Unit> key) {
this.set(key, Unit.INSTANCE);
}
public void addEmpty(final StructuredDataKey<?> key) {
public void setEmpty(final StructuredDataKey<?> key) {
// Empty optional to override the Minecraft default
this.data.put(key, StructuredData.empty(key, serializerId(key)));
}
/**
* Removes and returns structured data by the given key.
* Updates the structured data by id if not empty.
*
* @param key serializer key
* @param key serializer id
* @param valueMapper function to update existing data
* @param <T> data type
* @return removed structured data
*/
public @Nullable <T> StructuredData<T> remove(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.remove(key);
//noinspection unchecked
return data != null ? (StructuredData<T>) data : null;
public <T> void replace(final StructuredDataKey<T> key, final Function<T, @Nullable T> valueMapper) {
final StructuredData<T> data = this.getNonEmptyData(key);
if (data == null) {
return;
}
public boolean contains(final StructuredDataKey<?> key) {
final T replacement = valueMapper.apply(data.value());
if (replacement != null) {
data.setValue(replacement);
} else {
this.data.remove(key);
}
}
public <T> void replaceKey(final StructuredDataKey<T> key, final StructuredDataKey<T> toKey) {
replace(key, toKey, Function.identity());
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, @Nullable V> valueMapper) {
final StructuredData<?> data = this.data.remove(key);
if (data == null) {
return;
}
if (data.isPresent()) {
//noinspection unchecked
final T value = (T) data.value();
final V replacement = valueMapper.apply(value);
if (replacement != null) {
set(toKey, replacement);
}
} else {
// Also replace the key for empty data
setEmpty(toKey);
}
}
/**
* Removes data by the given key.
*
* @param key data key
* @see #replace(StructuredDataKey, Function)
* @see #replace(StructuredDataKey, StructuredDataKey, Function)
* @see #replaceKey(StructuredDataKey, StructuredDataKey)
*/
public void remove(final StructuredDataKey<?> key) {
this.data.remove(key);
}
/**
* Returns whether there is data for the given key, either empty or non-empty.
*
* @param key data key
* @return whether there data for the given key
* @see #hasEmpty(StructuredDataKey)
* @see #hasValue(StructuredDataKey)
*/
public boolean has(final StructuredDataKey<?> key) {
return this.data.containsKey(key);
}
/**
* Returns whether there is non-empty data for the given key.
*
* @param key data key
* @return whether there is non-empty data for the given key
*/
public boolean hasValue(final StructuredDataKey<?> key) {
final StructuredData<?> data = this.data.get(key);
return data != null && data.isPresent();
}
/**
* Returns whether the structured data has an empty patch/override.
*
* @param key serializer id
* @return whether the structured data has an empty patch/override
*/
public boolean hasEmpty(final StructuredDataKey<?> key) {
final StructuredData<?> data = this.data.get(key);
return data != null && data.isEmpty();
}
/**
* Sets the lookup for serializer ids. Required to call most of the other methods.
*

Datei anzeigen

@ -101,7 +101,7 @@ public class EntityTypes1_12 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(ENTITY), // Needed for entity (un)tracking
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking
// Living entities as a larger subclass
LIVING_ENTITY(LIVING_ENTITY_BASE),

Datei anzeigen

@ -99,7 +99,7 @@ public class EntityTypes1_9 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(ENTITY), // Needed for entity (un)tracking
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking
// Living entities as a larger subclass
LIVING_ENTITY(48, LIVING_ENTITY_BASE),

Datei anzeigen

@ -26,6 +26,7 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean showInTooltip) {
@ -44,6 +45,15 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
}
};
public AttributeModifiers1_21 rewrite(final Int2IntFunction rewriteFunction) {
final AttributeModifier[] modifiers = new AttributeModifier[this.modifiers.length];
for (int i = 0; i < this.modifiers.length; i++) {
final AttributeModifier modifier = this.modifiers[i];
modifiers[i] = new AttributeModifier(rewriteFunction.applyAsInt(modifier.attribute()), modifier.modifier(), modifier.slotType());
}
return new AttributeModifiers1_21(modifiers, showInTooltip);
}
public record AttributeModifier(int attribute, ModifierData modifier, int slotType) {
public static final Type<AttributeModifier> TYPE = new Type<>(AttributeModifier.class) {

Datei anzeigen

@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record Instrument(Holder<SoundEvent> soundEvent, int useDuration, float range) {
@ -47,4 +48,8 @@ public record Instrument(Holder<SoundEvent> soundEvent, int useDuration, float r
}
};
public Instrument rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument(soundEvent, useDuration, range);
}
}

Datei anzeigen

@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Either;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean showInTooltip) {
@ -56,6 +57,20 @@ public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean
}
};
public JukeboxPlayable rewrite(final Int2IntFunction soundIdRewriteFunction) {
if (song.isRight()) {
return this;
}
final Holder<JukeboxSong> songHolder = this.song.left();
if (songHolder.hasId()) {
return this;
}
final JukeboxSong rewrittenSong = songHolder.value().rewrite(soundIdRewriteFunction);
return rewrittenSong == songHolder.value() ? this : new JukeboxPlayable(Holder.of(rewrittenSong), showInTooltip);
}
public record JukeboxSong(Holder<SoundEvent> soundEvent, Tag description,
float lengthInSeconds, int comparatorOutput) {
@ -77,5 +92,10 @@ public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean
Types.VAR_INT.writePrimitive(buffer, value.comparatorOutput);
}
};
public JukeboxSong rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
}
}
}

Datei anzeigen

@ -1,56 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.Map;
public record MapDecorations(Map<String, MapDecoration> decorations) {
public static final Type<MapDecorations> TYPE = new Type<>(MapDecorations.class) {
@Override
public MapDecorations read(final ByteBuf buffer) {
final Object2ObjectMap<String, MapDecoration> decorations = new Object2ObjectOpenHashMap<>();
final int size = Types.VAR_INT.readPrimitive(buffer);
for (int i = 0; i < size; i++) {
final String id = Types.STRING.read(buffer);
final MapDecoration decoration = MapDecoration.TYPE.read(buffer);
decorations.put(id, decoration);
}
return new MapDecorations(decorations);
}
@Override
public void write(final ByteBuf buffer, final MapDecorations value) {
Types.VAR_INT.writePrimitive(buffer, value.decorations.size());
for (final Map.Entry<String, MapDecoration> entry : value.decorations.entrySet()) {
Types.STRING.write(buffer, entry.getKey());
MapDecoration.TYPE.write(buffer, entry.getValue());
}
}
};
}

Datei anzeigen

@ -5,7 +5,7 @@ plugins {
tasks {
// Variable replacements
processResources {
filesMatching(listOf("plugin.yml", "fabric.mod.json")) {
filesMatching(listOf("plugin.yml", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
expand("version" to project.version, "description" to project.description, "url" to "https://viaversion.com")
}
}

Datei anzeigen

@ -112,7 +112,10 @@ public class JoinListener implements Listener {
return;
}
// The connection has already closed, that was a quick leave
if (!channel.isOpen()) return;
// Channel may be null if a plugin is manually calling the event for a non-player...
if (channel == null || !channel.isOpen()) {
return;
}
UserConnection user = getUserConnection(channel);
if (user == null) {

Datei anzeigen

@ -25,14 +25,14 @@ import com.viaversion.viaversion.api.protocol.version.BlockedProtocolVersions;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.BlockedProtocolVersionsImpl;
import com.viaversion.viaversion.util.Config;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class AbstractViaConfig extends Config implements ViaVersionConfig {
@ -95,6 +95,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean handleInvalidItemCount;
private boolean cancelBlockSounds;
private boolean hideScoreboardNumbers;
private boolean fix1_21PlacementRotation;
protected AbstractViaConfig(final File configFile, final Logger logger) {
super(configFile, logger);
@ -163,6 +164,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
handleInvalidItemCount = getBoolean("handle-invalid-item-count", false);
cancelBlockSounds = getBoolean("cancel-block-sounds", true);
hideScoreboardNumbers = getBoolean("hide-scoreboard-numbers", false);
fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", false);
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
@ -549,4 +551,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
public boolean hideScoreboardNumbers() {
return hideScoreboardNumbers;
}
@Override
public boolean fix1_21PlacementRotation() {
return false && fix1_21PlacementRotation; // TODO Can't always set onGround to true
}
}

Datei anzeigen

@ -23,6 +23,7 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.platform.ViaInjector;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.Direction;
@ -58,6 +59,7 @@ public class UserConnectionImpl implements UserConnection {
private final long id = IDS.incrementAndGet();
private final Map<Class<?>, StorableObject> storedObjects = new ConcurrentHashMap<>();
private final Map<Class<? extends Protocol>, EntityTracker> entityTrackers = new HashMap<>();
private final Map<Class<? extends Protocol>, ClientWorld> clientWorlds = new HashMap<>();
private final PacketTracker packetTracker = new PacketTracker(this);
private final Set<UUID> passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
@ -125,9 +127,17 @@ public class UserConnectionImpl implements UserConnection {
@Override
public void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker) {
if (!entityTrackers.containsKey(protocolClass)) {
entityTrackers.put(protocolClass, tracker);
entityTrackers.putIfAbsent(protocolClass, tracker);
}
@Override
public @Nullable <T extends ClientWorld> T getClientWorld(final Class<? extends Protocol> protocolClass) {
return (T) clientWorlds.get(protocolClass);
}
@Override
public void addClientWorld(final Class<? extends Protocol> protocolClass, final ClientWorld clientWorld) {
clientWorlds.putIfAbsent(protocolClass, clientWorld);
}
@Override
@ -142,7 +152,6 @@ public class UserConnectionImpl implements UserConnection {
});
for (EntityTracker tracker : entityTrackers.values()) {
tracker.clearEntities();
tracker.trackClientEntity();
}
} else {
for (StorableObject object : storedObjects.values()) {
@ -150,6 +159,7 @@ public class UserConnectionImpl implements UserConnection {
}
storedObjects.clear();
entityTrackers.clear();
clientWorlds.clear();
}
}

Datei anzeigen

@ -37,7 +37,7 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
protected final Int2ObjectMap<TrackedEntity> entities = new Int2ObjectOpenHashMap<>();
private final UserConnection connection;
private final EntityType playerType;
private int clientEntityId = -1;
private Integer clientEntityId;
private int currentWorldSectionHeight = -1;
private int currentMinY;
private String currentWorld;
@ -87,7 +87,6 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
return entity != null && entity.hasData() ? entity.data() : null;
}
//TODO Soft memory leak: Remove entities on respawn in protocols prior to 1.18 (1.16+ only when the worldname is different)
@Override
public void removeEntity(int id) {
entities.remove(id);
@ -95,11 +94,27 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
@Override
public void clearEntities() {
entities.clear();
// Call wrapper function in case protocols need to do additional removals
for (final int id : entities.keySet().toIntArray()) {
removeEntity(id);
}
// Re-add the client entity. Keep the call above to untrack attached data if necessary
if (clientEntityId != null) {
entities.put(clientEntityId.intValue(), new TrackedEntityImpl(playerType));
}
}
@Override
public int clientEntityId() {
public boolean hasClientEntityId() {
return clientEntityId != null;
}
@Override
public int clientEntityId() throws IllegalStateException {
if (clientEntityId == null) {
throw new IllegalStateException("Client entity id not set");
}
return clientEntityId;
}
@ -107,7 +122,7 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
public void setClientEntityId(int clientEntityId) {
Preconditions.checkNotNull(playerType);
final TrackedEntity oldEntity;
if (this.clientEntityId != -1 && (oldEntity = entities.remove(this.clientEntityId)) != null) {
if (this.clientEntityId != null && (oldEntity = entities.remove(this.clientEntityId.intValue())) != null) {
entities.put(clientEntityId, oldEntity);
} else {
entities.put(clientEntityId, new TrackedEntityImpl(playerType));
@ -116,15 +131,6 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
this.clientEntityId = clientEntityId;
}
@Override
public boolean trackClientEntity() {
if (clientEntityId != -1) {
entities.put(clientEntityId, new TrackedEntityImpl(playerType));
return true;
}
return false;
}
@Override
public int currentWorldSectionHeight() {
return currentWorldSectionHeight;

Datei anzeigen

@ -99,7 +99,7 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
});
registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_11.class);
Chunk chunk = wrapper.passthrough(ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()));
@ -120,31 +120,6 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
}
});
registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
}
});
registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
}
});
this.registerClientbound(ClientboundPackets1_9_3.LEVEL_EVENT, new PacketHandlers() {
@Override
public void register() {
@ -238,11 +213,8 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
@Override
public void init(UserConnection userConnection) {
// Entity tracker
userConnection.addEntityTracker(this.getClass(), new EntityTracker1_11(userConnection));
if (!userConnection.has(ClientWorld.class))
userConnection.put(new ClientWorld());
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override

Datei anzeigen

@ -24,7 +24,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class PotionColorMappings1_11 {
//<oldData> to <newData, isInstant> mapping
private static final Int2ObjectMap<Pair<Integer, Boolean>> POTIONS = new Int2ObjectOpenHashMap<>(37, 0.99F);
private static final Int2ObjectMap<Pair<Integer, Boolean>> POTIONS = new Int2ObjectOpenHashMap<>(37);
static {
addRewrite(0, 3694022, false);

Datei anzeigen

@ -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.ClientWorld;
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;
@ -48,6 +49,34 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_11.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_11.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {

Datei anzeigen

@ -19,6 +19,7 @@ package com.viaversion.viaversion.protocols.v1_10to1_11.rewriter;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Types;
@ -55,6 +56,22 @@ public class ItemPacketRewriter1_11 extends ItemRewriter<ClientboundPackets1_9_3
item.setAmount(1);
}
EntityMappings1_11.toClientItem(item);
if (item == null || item.tag() == null) {
return item;
}
CompoundTag tag = item.tag();
// 1.10 will display item glint if the list tag is present, 1.11+ only if at least one element is present
ListTag enchTag = tag.getListTag("ench");
if (enchTag != null && enchTag.isEmpty()) {
tag.putBoolean(nbtTagName("clearEnch"), true);
CompoundTag dummyTag = new CompoundTag();
dummyTag.putShort("id", Short.MAX_VALUE);
enchTag.add(dummyTag);
}
return item;
}
@ -63,12 +80,18 @@ public class ItemPacketRewriter1_11 extends ItemRewriter<ClientboundPackets1_9_3
if (item == null) {
return null;
}
if (item.tag() != null && item.tag().contains(nbtTagName())) {
item.setAmount(item.tag().<ByteTag>removeUnchecked(nbtTagName()).asByte());
if (item.tag().isEmpty()) {
CompoundTag tag = item.tag();
if (tag != null) {
if (tag.contains(nbtTagName())) {
item.setAmount(tag.<ByteTag>removeUnchecked(nbtTagName()).asByte());
if (tag.isEmpty()) {
item.setTag(null);
}
}
if (tag.remove(nbtTagName("clearEnch")) != null) {
tag.put("ench", new ListTag());
}
}
EntityMappings1_11.toServerItem(item);
boolean newItem = item.identifier() >= 218 && item.identifier() <= 234;
newItem |= item.identifier() == 449 || item.identifier() == 450;

Datei anzeigen

@ -72,7 +72,7 @@ public class Protocol1_11_1To1_12 extends AbstractProtocol<ClientboundPackets1_9
});
registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11_1To1_12.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());
Chunk chunk = wrapper.passthrough(type);
@ -101,38 +101,6 @@ public class Protocol1_11_1To1_12 extends AbstractProtocol<ClientboundPackets1_9
}
});
registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
map(Types.UNSIGNED_BYTE);
map(Types.INT);
handler(wrapper -> {
UserConnection user = wrapper.user();
ClientWorld clientChunks = user.get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
// Reset recipes
if (user.getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_13)) {
wrapper.create(ClientboundPackets1_13.UPDATE_RECIPES, packetWrapper -> packetWrapper.write(Types.VAR_INT, 0))
.scheduleSend(Protocol1_12_2To1_13.class);
}
});
}
});
registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
}
});
new SoundRewriter<>(this, this::getNewSoundId).registerSound(ClientboundPackets1_9_3.SOUND);
@ -205,9 +173,7 @@ public class Protocol1_11_1To1_12 extends AbstractProtocol<ClientboundPackets1_9
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTrackerBase(userConnection, EntityTypes1_12.EntityType.PLAYER));
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override

Datei anzeigen

@ -23,7 +23,7 @@ import java.util.Set;
public class AchievementTranslations1_12 {
private static final Object2ObjectOpenHashMap<String, String> ACHIEVEMENTS = new Object2ObjectOpenHashMap<>(150, 0.99f);
private static final Object2ObjectOpenHashMap<String, String> ACHIEVEMENTS = new Object2ObjectOpenHashMap<>(150);
private static final Set<String> SPECIAL_ACHIEVEMENTS = new HashSet<>(10);
static {

Datei anzeigen

@ -17,14 +17,18 @@
*/
package com.viaversion.viaversion.protocols.v1_11_1to1_12.rewriter;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.minecraft.item.Item;
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_12;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.rewriter.EntityRewriter;
@ -36,6 +40,40 @@ public class EntityPacketRewriter1_12 extends EntityRewriter<ClientboundPackets1
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
map(Types.UNSIGNED_BYTE);
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11_1To1_12.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
// Reset recipes
if (wrapper.user().getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_13)) {
wrapper.create(ClientboundPackets1_13.UPDATE_RECIPES, packetWrapper -> packetWrapper.write(Types.VAR_INT, 0))
.scheduleSend(Protocol1_12_2To1_13.class);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11_1To1_12.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {

Datei anzeigen

@ -401,23 +401,6 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
}
});
registerClientbound(ClientboundPackets1_12_1.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
if (Via.getConfig().isServersideBlockConnections()) {
ConnectionData.clearBlockStorage(wrapper.user());
}
});
handler(SEND_DECLARE_COMMANDS_AND_TAGS);
}
});
registerClientbound(ClientboundPackets1_12_1.SET_OBJECTIVE, new PacketHandlers() {
@Override
public void register() {
@ -844,9 +827,9 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTrackerBase(userConnection, EntityTypes1_13.EntityType.PLAYER));
userConnection.addClientWorld(this.getClass(), new ClientWorld());
userConnection.put(new TabCompleteTracker());
if (!userConnection.has(ClientWorld.class))
userConnection.put(new ClientWorld());
userConnection.put(new BlockStorage());
if (Via.getConfig().isServersideBlockConnections()) {
if (Via.getManager().getProviders().get(BlockConnectionProvider.class) instanceof PacketBlockConnectionProvider) {

Datei anzeigen

@ -54,8 +54,8 @@ import java.util.Map.Entry;
public final class ConnectionData {
public static BlockConnectionProvider blockConnectionProvider;
static final Object2IntMap<String> KEY_TO_ID = new Object2IntOpenHashMap<>(8582, .99F);
static final IntSet OCCLUDING_STATES = new IntOpenHashSet(377, .99F);
static final Object2IntMap<String> KEY_TO_ID = new Object2IntOpenHashMap<>(8582);
static final IntSet OCCLUDING_STATES = new IntOpenHashSet(377);
static Int2ObjectMap<ConnectionHandler> connectionHandlerMap = new Int2ObjectOpenHashMap<>();
static Int2ObjectMap<BlockData> blockConnectionData = new Int2ObjectOpenHashMap<>();
private static final BlockChangeRecord1_8[] EMPTY_RECORDS = new BlockChangeRecord1_8[0];
@ -173,7 +173,7 @@ public final class ConnectionData {
KEY_TO_ID.put(key, id);
}
connectionHandlerMap = new Int2ObjectOpenHashMap<>(3650, .99F);
connectionHandlerMap = new Int2ObjectOpenHashMap<>(3650);
if (!Via.getConfig().isReduceBlockStorageMemory()) {
blockConnectionData = new Int2ObjectOpenHashMap<>(2048);

Datei anzeigen

@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
public class EntityIdMappings1_13 {
private static final Int2IntMap ENTITY_TYPES = new Int2IntOpenHashMap(83, .99F);
private static final Int2IntMap ENTITY_TYPES = new Int2IntOpenHashMap(83);
static {
ENTITY_TYPES.defaultReturnValue(-1);

Datei anzeigen

@ -28,6 +28,7 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_12;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.ConnectionData;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.EntityIdMappings1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.ParticleIdMappings1_13;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
@ -132,7 +133,7 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
ClientWorld clientChunks = wrapper.user().getClientWorld(Protocol1_12_2To1_13.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
@ -141,6 +142,24 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
}
});
protocol.registerClientbound(ClientboundPackets1_12_1.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_12_2To1_13.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
if (Via.getConfig().isServersideBlockConnections()) {
ConnectionData.clearBlockStorage(wrapper.user());
}
tracker(wrapper.user()).clearEntities();
}
});
handler(Protocol1_12_2To1_13.SEND_DECLARE_COMMANDS_AND_TAGS);
}
});
protocol.registerClientbound(ClientboundPackets1_12_1.UPDATE_MOB_EFFECT, new PacketHandlers() {
@Override
public void register() {

Datei anzeigen

@ -304,23 +304,15 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
if (ench != null) {
ListTag<CompoundTag> enchantments = new ListTag<>(CompoundTag.class);
for (CompoundTag enchEntry : ench) {
NumberTag idTag = enchEntry.getNumberTag("id");
if (idTag == null) {
continue;
}
short oldId = enchEntry.getShort("id", (short) 0);
CompoundTag enchantmentEntry = new CompoundTag();
short oldId = idTag.asShort();
String newId = Protocol1_12_2To1_13.MAPPINGS.getOldEnchantmentsIds().get(oldId);
if (newId == null) {
newId = "viaversion:legacy/" + oldId;
}
enchantmentEntry.putString("id", newId);
NumberTag levelTag = enchEntry.getNumberTag("lvl");
if (levelTag != null) {
enchantmentEntry.putShort("lvl", levelTag.asShort());
}
enchantmentEntry.putShort("lvl", enchEntry.getShort("lvl", (short) 0));
enchantments.add(enchantmentEntry);
}
@ -589,10 +581,7 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
}
if (oldId != null) {
enchEntry.putShort("id", oldId);
NumberTag levelTag = enchantmentEntry.getNumberTag("lvl");
if (levelTag != null) {
enchEntry.putShort("lvl", levelTag.asShort());
}
enchEntry.putShort("lvl", enchantmentEntry.getShort("lvl", (short) 0));
ench.add(enchEntry);
}
}

Datei anzeigen

@ -53,7 +53,7 @@ import java.util.Iterator;
import java.util.Optional;
public class WorldPacketRewriter1_13 {
private static final IntSet VALID_BIOMES = new IntOpenHashSet(70, .99F);
private static final IntSet VALID_BIOMES = new IntOpenHashSet(70);
static {
// Client will crash if it receives an invalid biome id
@ -325,7 +325,7 @@ public class WorldPacketRewriter1_13 {
});
protocol.registerClientbound(ClientboundPackets1_12_1.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_12_2To1_13.class);
BlockStorage storage = wrapper.user().get(BlockStorage.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());

Datei anzeigen

@ -26,7 +26,7 @@ import java.util.Map;
// TODO Fix memory leak lolz (only a smol one tho)
public class BlockStorage implements StorableObject {
private static final IntSet WHITELIST = new IntOpenHashSet(46, .99F);
private static final IntSet WHITELIST = new IntOpenHashSet(46);
private final Map<BlockPosition, ReplacementData> blocks = new HashMap<>();
static {

Datei anzeigen

@ -121,9 +121,7 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol<ClientboundPackets1_1
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTracker1_14(userConnection));
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override

Datei anzeigen

@ -204,7 +204,7 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
// Store the player
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
ClientWorld clientChunks = wrapper.user().getClientWorld(Protocol1_13_2To1_14.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});

Datei anzeigen

@ -125,7 +125,7 @@ public class WorldPacketRewriter1_14 {
});
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13_2To1_14.class);
Chunk chunk = wrapper.read(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()));
wrapper.write(ChunkType1_14.TYPE, chunk);
@ -282,21 +282,26 @@ public class WorldPacketRewriter1_14 {
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
short difficulty = wrapper.read(Types.UNSIGNED_BYTE); // 19w11a removed difficulty from respawn
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13_2To1_14.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
if (!clientWorld.setEnvironment(dimensionId)) {
return;
}
EntityTracker1_14 entityTracker = wrapper.user().getEntityTracker(Protocol1_13_2To1_14.class);
entityTracker.clearEntities();
// The client may reset the center chunk if dimension is changed
entityTracker.setForceSendCenterChunk(true);
});
handler(wrapper -> {
short difficulty = wrapper.read(Types.UNSIGNED_BYTE); // 19w11a removed difficulty from respawn
PacketWrapper difficultyPacket = wrapper.create(ClientboundPackets1_14.CHANGE_DIFFICULTY);
difficultyPacket.write(Types.UNSIGNED_BYTE, difficulty);
difficultyPacket.write(Types.BOOLEAN, false); // Unknown value added in 19w11a
difficultyPacket.scheduleSend(protocol.getClass());
});
handler(wrapper -> {
// Manually send the packet and update the viewdistance after
wrapper.send(Protocol1_13_2To1_14.class);
wrapper.cancel();

Datei anzeigen

@ -134,9 +134,7 @@ public class Protocol1_13To1_13_1 extends AbstractProtocol<ClientboundPackets1_1
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTrackerBase(userConnection, EntityTypes1_13.EntityType.PLAYER));
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override

Datei anzeigen

@ -17,6 +17,7 @@
*/
package com.viaversion.viaversion.protocols.v1_13to1_13_1.rewriter;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
@ -34,6 +35,36 @@ public class EntityPacketRewriter1_13_1 extends EntityRewriter<ClientboundPacket
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_13.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
// Store the player
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_13_1.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_13_1.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {

Datei anzeigen

@ -19,9 +19,6 @@ package com.viaversion.viaversion.protocols.v1_13to1_13_1.rewriter;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_13;
@ -35,7 +32,7 @@ public class WorldPacketRewriter1_13_1 {
BlockRewriter<ClientboundPackets1_13> blockRewriter = BlockRewriter.legacy(protocol);
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_13_1.class);
Chunk chunk = wrapper.passthrough(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()));
blockRewriter.handleChunk(chunk);
@ -84,33 +81,5 @@ public class WorldPacketRewriter1_13_1 {
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
// Store the player
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
}
});
}
}

Datei anzeigen

@ -86,7 +86,10 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
@Override
public void register() {
map(Types.INT);
handler(wrapper -> wrapper.write(Types.LONG, 0L)); // Level Seed
handler(wrapper -> {
tracker(wrapper.user()).clearEntities();
wrapper.write(Types.LONG, 0L); // Level Seed
});
}
});

Datei anzeigen

@ -119,6 +119,8 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
map(Types.LONG); // Seed
map(Types.UNSIGNED_BYTE); // Gamemode
handler(wrapper -> {
tracker(wrapper.user()).clearEntities();
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
@ -145,9 +147,8 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
handler(DIMENSION_HANDLER); // Dimension
map(Types.LONG); // Seed
map(Types.UNSIGNED_BYTE); // Max players
handler(playerTrackerHandler());
handler(wrapper -> {
wrapper.user().getEntityTracker(Protocol1_15_2To1_16.class).addEntity(wrapper.get(Types.INT, 0), EntityTypes1_16.PLAYER);
final String type = wrapper.read(Types.STRING);// level type
wrapper.passthrough(Types.VAR_INT); // View distance
wrapper.passthrough(Types.BOOLEAN); // Reduced debug info

Datei anzeigen

@ -72,6 +72,8 @@ public class EntityPacketRewriter1_16_2 extends EntityRewriter<ClientboundPacket
protocol.registerClientbound(ClientboundPackets1_16.RESPAWN, wrapper -> {
String dimensionType = wrapper.read(Types.STRING);
wrapper.write(Types.NAMED_COMPOUND_TAG, getDimensionData(dimensionType));
tracker(wrapper.user()).clearEntities();
});
}

Datei anzeigen

@ -37,7 +37,6 @@ import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.EntityPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.ItemPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.WorldPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.storage.InventoryAcknowledgements;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
@ -192,7 +191,6 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_17.PLAYER));
user.put(new InventoryAcknowledgements());
}
@Override

Datei anzeigen

@ -116,6 +116,8 @@ public final class EntityPacketRewriter1_17 extends EntityRewriter<ClientboundPa
protocol.registerClientbound(ClientboundPackets1_16_2.RESPAWN, wrapper -> {
CompoundTag dimensionData = wrapper.passthrough(Types.NAMED_COMPOUND_TAG);
addNewDimensionData(dimensionData);
tracker(wrapper.user()).clearEntities();
});
protocol.registerClientbound(ClientboundPackets1_16_2.UPDATE_ATTRIBUTES, new PacketHandlers() {

Datei anzeigen

@ -29,7 +29,6 @@ import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_16_4to1_17.Protocol1_16_4To1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ClientboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.storage.InventoryAcknowledgements;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
@ -97,7 +96,6 @@ public final class ItemPacketRewriter1_17 extends ItemRewriter<ClientboundPacket
if (!accepted) {
// Use the new ping packet to replace the removed acknowledgement, extra bit for fast dismissal
int id = (1 << 30) | (inventoryId << 16) | (confirmationId & 0xFFFF);
wrapper.user().get(InventoryAcknowledgements.class).addId(id);
PacketWrapper pingPacket = wrapper.create(ClientboundPackets1_17.PING);
pingPacket.write(Types.INT, id);
@ -111,7 +109,7 @@ public final class ItemPacketRewriter1_17 extends ItemRewriter<ClientboundPacket
protocol.registerServerbound(ServerboundPackets1_17.PONG, null, wrapper -> {
int id = wrapper.read(Types.INT);
// Check extra bit for fast dismissal
if ((id & (1 << 30)) != 0 && wrapper.user().get(InventoryAcknowledgements.class).removeId(id)) {
if ((id & (1 << 30)) != 0) {
// Decode our requested inventory acknowledgement
short inventoryId = (short) ((id >> 16) & 0xFF);
short confirmationId = (short) (id & 0xFFFF);

Datei anzeigen

@ -1,34 +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_16_4to1_17.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
public final class InventoryAcknowledgements implements StorableObject {
private final IntList ids = new IntArrayList();
public void addId(int id) {
ids.add(id);
}
public boolean removeId(int id) {
return ids.rem(id);
}
}

Datei anzeigen

@ -79,8 +79,8 @@ public final class EntityPacketRewriter1_20 extends EntityRewriter<ClientboundPa
final ListTag<CompoundTag> damageTypes = TagUtil.getRegistryEntries(registry, "damage_type");
int highestId = -1;
for (final CompoundTag damageType : damageTypes) {
final IntTag id = damageType.getUnchecked("id");
highestId = Math.max(highestId, id.asInt());
final int id = damageType.getInt("id");
highestId = Math.max(highestId, id);
}
// AaaaAAAaa

Datei anzeigen

@ -103,6 +103,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
componentRewriter.registerBossEvent(ClientboundPackets1_20_3.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_20_3.TAB_LIST);
componentRewriter.registerPlayerInfoUpdate1_20_3(ClientboundPackets1_20_3.PLAYER_INFO_UPDATE);
componentRewriter.registerPing();
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, wrapper -> {

Datei anzeigen

@ -416,7 +416,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final StructuredDataContainer data = item.dataContainer();
data.setIdLookup(protocol, true);
final StructuredData<CompoundTag> customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
final StructuredData<CompoundTag> customData = data.getNonEmptyData(StructuredDataKey.CUSTOM_DATA);
final CompoundTag tag = customData != null ? customData.value() : new CompoundTag();
final DataItem dataItem = new DataItem(item.identifier(), (byte) item.amount(), tag);
if (!dataConverter.backupInconvertibleData() && customData != null && tag.remove(nbtTagName()) != null) {
@ -488,8 +488,12 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
if (blockEntityTag != null) {
final CompoundTag clonedTag = blockEntityTag.copy();
updateBlockEntityTag(connection, data, clonedTag);
// Not always needed, e.g. shields that had the base color in a block entity tag before
if (blockEntityTag.contains("id")) {
item.dataContainer().set(StructuredDataKey.BLOCK_ENTITY_DATA, clonedTag);
}
}
final CompoundTag debugProperty = tag.getCompoundTag("DebugProperty");
if (debugProperty != null) {
@ -1163,13 +1167,24 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
}
private void updateWrittenBookPages(final UserConnection connection, final StructuredDataContainer data, final CompoundTag tag) {
final String title = tag.getString("title");
final String author = tag.getString("author");
final ListTag<StringTag> pagesTag = tag.getListTag("pages", StringTag.class);
final CompoundTag filteredPagesTag = tag.getCompoundTag("filtered_pages");
if (pagesTag == null) {
return;
boolean valid = author != null && title != null && title.length() <= 32 && pagesTag != null;
if (valid) {
for (final StringTag page : pagesTag) {
if (page.getValue().length() > Short.MAX_VALUE) {
valid = false;
break;
}
}
}
final List<FilterableComponent> pages = new ArrayList<>();
if (valid) {
final CompoundTag filteredPagesTag = tag.getCompoundTag("filtered_pages");
for (int i = 0; i < pagesTag.size(); i++) {
final StringTag page = pagesTag.get(i);
Tag filtered = null;
@ -1195,15 +1210,20 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
pages.add(new FilterableComponent(parsedPage, filtered));
}
} else {
final CompoundTag invalidPage = new CompoundTag();
invalidPage.putString("text", "* Invalid book tag *");
invalidPage.putString("color", "#AA0000"); // dark red
pages.add(new FilterableComponent(invalidPage, null));
}
final String title = tag.getString("title", "");
final String filteredTitle = tag.getString("filtered_title"); // Nullable
final String author = tag.getString("author", "");
final int generation = tag.getInt("generation");
final boolean resolved = tag.getBoolean("resolved");
final WrittenBook writtenBook = new WrittenBook(
new FilterableString(limit(title, 32), limit(filteredTitle, 32)),
author,
new FilterableString(limit(title == null ? "" : title, 32), limit(filteredTitle, 32)),
author == null ? "" : author,
clamp(generation, 0, 3),
pages.toArray(new FilterableComponent[0]),
resolved

Datei anzeigen

@ -459,6 +459,14 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
}
protected CompoundTag canPlaceOnToTag(final AdventureModePredicate value) {
return blockPredicateToTag(value);
}
protected CompoundTag canBreakToTag(final AdventureModePredicate value) {
return blockPredicateToTag(value);
}
protected CompoundTag blockPredicateToTag(final AdventureModePredicate value) {
final CompoundTag tag = new CompoundTag();
final ListTag<CompoundTag> predicates = new ListTag<>(CompoundTag.class);
for (final BlockPredicate predicate : value.predicates()) {
@ -467,8 +475,7 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
holderSetToTag(predicateTag, "blocks", predicate.holderSet());
}
if (predicate.propertyMatchers() != null) {
final CompoundTag state = predicateToTag(predicate);
predicateTag.put("state", state);
predicateTag.put("state", createState(predicate));
}
if (predicate.tag() != null) {
predicateTag.put("nbt", predicate.tag());
@ -483,8 +490,10 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
return tag;
}
protected CompoundTag predicateToTag(final BlockPredicate predicate) {
// Not an own conversion method, just to avoid high nesting
protected CompoundTag createState(final BlockPredicate predicate) {
final CompoundTag state = new CompoundTag();
for (final StatePropertyMatcher matcher : predicate.propertyMatchers()) {
final Either<String, StatePropertyMatcher.RangedMatcher> match = matcher.matcher();
if (match.isLeft()) {
@ -504,10 +513,6 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
return state;
}
protected CompoundTag canBreakToTag(final AdventureModePredicate value) {
return canPlaceOnToTag(value);
}
protected CompoundTag attributeModifiersToTag(final AttributeModifiers1_20_5 value) {
final CompoundTag tag = new CompoundTag();
final ListTag<CompoundTag> modifiers = new ListTag<>(CompoundTag.class);
@ -1009,7 +1014,17 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
if (set.hasTagKey()) {
tag.putString(name, set.tagKey());
} else {
tag.put(name, new IntArrayTag(set.ids()));
final ListTag<StringTag> identifiers = new ListTag<>(StringTag.class);
for (final int id : set.ids()) {
// Can use old block list because new ids are only at the end :tm:
final String identifier = Protocol1_20_3To1_20_5.MAPPINGS.blockName(id);
if (identifier == null) {
continue;
}
identifiers.add(new StringTag(identifier));
}
tag.put(name, identifiers);
}
}

Datei anzeigen

@ -83,13 +83,16 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
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
final int rawSlot = slot & 0x7F;
if (type != null && type.isOrHasParent(EntityTypes1_20_5.ABSTRACT_HORSE) && rawSlot == 4) {
final boolean lastSlot = (slot & 0xFFFFFF80) == 0;
slot = (byte) (lastSlot ? 6 : 6 | 0xFFFFFF80); // 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);
} while ((slot & 0xFFFFFF80) != 0);
});
protocol.registerClientbound(ClientboundConfigurationPackets1_20_3.REGISTRY_DATA, wrapper -> {

Datei anzeigen

@ -19,13 +19,14 @@ 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.Via;
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;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
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_5;
@ -106,8 +107,22 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
protocol.registerServerbound(ServerboundPackets1_20_5.USE_ITEM, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Hand
wrapper.passthrough(Types.VAR_INT); // Sequence
wrapper.read(Types.FLOAT); // Y rotation
wrapper.read(Types.FLOAT); // X rotation
final float yaw = wrapper.read(Types.FLOAT); // Y rotation
final float pitch = wrapper.read(Types.FLOAT); // X rotation
if (!Via.getConfig().fix1_21PlacementRotation()) {
return;
}
// Not correct but *enough* for vanilla/normal servers to have block placement synchronized
final PacketWrapper playerRotation = wrapper.create(ServerboundPackets1_20_5.MOVE_PLAYER_ROT);
playerRotation.write(Types.FLOAT, yaw);
playerRotation.write(Types.FLOAT, pitch);
playerRotation.write(Types.BOOLEAN, true); // On Ground
playerRotation.sendToServer(Protocol1_20_5To1_21.class);
wrapper.sendToServer(Protocol1_20_5To1_21.class);
wrapper.cancel();
});
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_20_5.UPDATE_RECIPES);
@ -123,7 +138,7 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
updateItemData(item);
final StructuredDataContainer dataContainer = item.dataContainer();
if (dataContainer.contains(StructuredDataKey.RARITY)) {
if (dataContainer.has(StructuredDataKey.RARITY)) {
return item;
}
@ -194,14 +209,14 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
public static void resetRarityValues(final Item item, final String tagName) {
final StructuredDataContainer dataContainer = item.dataContainer();
final StructuredData<CompoundTag> customData = dataContainer.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
final CompoundTag customData = dataContainer.get(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
return;
}
if (customData.value().remove(tagName) != null) {
if (customData.remove(tagName) != null) {
dataContainer.remove(StructuredDataKey.RARITY);
if (customData.value().isEmpty()) {
if (customData.isEmpty()) {
dataContainer.remove(StructuredDataKey.CUSTOM_DATA);
}
}

Datei anzeigen

@ -43,7 +43,7 @@ import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.ItemPacketRewriter
import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.PlayerPacketRewriter1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.SpawnPacketRewriter1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.WorldPacketRewriter1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientChunks;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientWorld1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.CommandBlockStorage;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.InventoryTracker;
@ -104,20 +104,12 @@ public class Protocol1_8To1_9 extends AbstractProtocol<ClientboundPackets1_8, Cl
@Override
public void init(UserConnection userConnection) {
// Entity tracker
userConnection.addEntityTracker(this.getClass(), new EntityTracker1_9(userConnection));
// Chunk tracker
userConnection.put(new ClientChunks());
// Movement tracker
userConnection.put(new MovementTracker());
// Inventory tracker
userConnection.put(new InventoryTracker());
// CommandBlock storage
userConnection.put(new CommandBlockStorage());
userConnection.addClientWorld(this.getClass(), new ClientWorld1_9());
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.put(new MovementTracker());
userConnection.put(new InventoryTracker());
userConnection.put(new CommandBlockStorage());
}
@Override

Datei anzeigen

@ -22,7 +22,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
public class EffectIdMappings1_9 {
private static final Int2IntMap EFFECTS = new Int2IntOpenHashMap(19, .99F);
private static final Int2IntMap EFFECTS = new Int2IntOpenHashMap(19);
static {
addRewrite(1005, 1010); //Play music disc

Datei anzeigen

@ -27,7 +27,7 @@ public class PotionIdMappings1_9 {
public static final Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
public static final Map<Integer, String> POTION_ID_TO_NAME = new HashMap<>();
public static final Int2IntMap POTION_INDEX = new Int2IntOpenHashMap(36, .99F);
public static final Int2IntMap POTION_INDEX = new Int2IntOpenHashMap(36);
static {
register(-1, "empty");

Datei anzeigen

@ -36,7 +36,7 @@ import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CommandBlockProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CompressionProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.MainHandProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientChunks;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientWorld1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.MovementTracker;
import com.viaversion.viaversion.util.ComponentUtil;
@ -203,7 +203,7 @@ public class PlayerPacketRewriter1_9 {
// Track player's dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
int dimensionId = wrapper.get(Types.BYTE, 0);
clientWorld.setEnvironment(dimensionId);
});
@ -295,27 +295,25 @@ public class PlayerPacketRewriter1_9 {
map(Types.UNSIGNED_BYTE); // 2 - GameMode
map(Types.STRING); // 3 - Level Type
// Track player's dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
handler(wrapper -> {
// Client unloads chunks on respawn
wrapper.user().get(ClientChunks.class).getLoadedChunks().clear();
int gamemode = wrapper.get(Types.UNSIGNED_BYTE, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
tracker.setGameMode(GameMode.getById(gamemode));
});
// Fake permissions to get Commandblocks working
handler(wrapper -> {
CommandBlockProvider provider = Via.getManager().getProviders().get(CommandBlockProvider.class);
// Fake permissions to get Commandblocks working
provider.sendPermission(wrapper.user());
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
int gamemode = wrapper.get(Types.UNSIGNED_BYTE, 0);
tracker.setGameMode(GameMode.getById(gamemode));
ClientWorld1_9 clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
int dimensionId = wrapper.get(Types.INT, 0);
// Track player's dimension
if (clientWorld.setEnvironment(dimensionId)) {
tracker.clearEntities();
clientWorld.getLoadedChunks().clear();
provider.unloadChunks(wrapper.user());
}
});
}
});

Datei anzeigen

@ -45,7 +45,7 @@ import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CommandBlockProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.HandItemProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientChunks;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientWorld1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
@ -130,11 +130,10 @@ public class WorldPacketRewriter1_9 {
});
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
ClientWorld1_9 clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(clientWorld.getEnvironment()));
long chunkHash = ClientChunks.toLong(chunk.getX(), chunk.getZ());
long chunkHash = ClientWorld1_9.toLong(chunk.getX(), chunk.getZ());
// Check if the chunk should be handled as an unload packet
if (chunk.isFullChunk() && chunk.getBitmask() == 0) {
@ -146,14 +145,14 @@ public class WorldPacketRewriter1_9 {
CommandBlockProvider provider = Via.getManager().getProviders().get(CommandBlockProvider.class);
provider.unloadChunk(wrapper.user(), chunk.getX(), chunk.getZ());
clientChunks.getLoadedChunks().remove(chunkHash);
clientWorld.getLoadedChunks().remove(chunkHash);
// Unload the empty chunks
if (Via.getConfig().isChunkBorderFix()) {
for (BlockFace face : BlockFace.HORIZONTAL) {
int chunkX = chunk.getX() + face.modX();
int chunkZ = chunk.getZ() + face.modZ();
if (!clientChunks.getLoadedChunks().contains(ClientChunks.toLong(chunkX, chunkZ))) {
if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) {
PacketWrapper unloadChunk = wrapper.create(ClientboundPackets1_9.FORGET_LEVEL_CHUNK);
unloadChunk.write(Types.INT, chunkX);
unloadChunk.write(Types.INT, chunkZ);
@ -165,14 +164,14 @@ public class WorldPacketRewriter1_9 {
Type<Chunk> chunkType = ChunkType1_9_1.forEnvironment(clientWorld.getEnvironment());
wrapper.write(chunkType, chunk);
clientChunks.getLoadedChunks().add(chunkHash);
clientWorld.getLoadedChunks().add(chunkHash);
// Send empty chunks surrounding the loaded chunk to force 1.9+ clients to render the new chunk
if (Via.getConfig().isChunkBorderFix()) {
for (BlockFace face : BlockFace.HORIZONTAL) {
int chunkX = chunk.getX() + face.modX();
int chunkZ = chunk.getZ() + face.modZ();
if (!clientChunks.getLoadedChunks().contains(ClientChunks.toLong(chunkX, chunkZ))) {
if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) {
PacketWrapper emptyChunk = wrapper.create(ClientboundPackets1_9.LEVEL_CHUNK);
Chunk c = new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], new int[256], new ArrayList<>());
emptyChunk.write(chunkType, c);
@ -185,8 +184,7 @@ public class WorldPacketRewriter1_9 {
protocol.registerClientbound(ClientboundPackets1_8.MAP_BULK_CHUNK, null, wrapper -> {
wrapper.cancel(); // Cancel the packet from being sent
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
ClientWorld1_9 clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
Chunk[] chunks = wrapper.read(BulkChunkType1_8.TYPE);
Type<Chunk> chunkType = ChunkType1_9_1.forEnvironment(clientWorld.getEnvironment());
@ -196,14 +194,14 @@ public class WorldPacketRewriter1_9 {
chunkData.write(chunkType, chunk);
chunkData.send(Protocol1_8To1_9.class);
clientChunks.getLoadedChunks().add(ClientChunks.toLong(chunk.getX(), chunk.getZ()));
clientWorld.getLoadedChunks().add(ClientWorld1_9.toLong(chunk.getX(), chunk.getZ()));
// Send empty chunks surrounding the loaded chunk to force 1.9+ clients to render the new chunk
if (Via.getConfig().isChunkBorderFix()) {
for (BlockFace face : BlockFace.HORIZONTAL) {
int chunkX = chunk.getX() + face.modX();
int chunkZ = chunk.getZ() + face.modZ();
if (!clientChunks.getLoadedChunks().contains(ClientChunks.toLong(chunkX, chunkZ))) {
if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) {
PacketWrapper emptyChunk = wrapper.create(ClientboundPackets1_9.LEVEL_CHUNK);
Chunk c = new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], new int[256], new ArrayList<>());
emptyChunk.write(chunkType, c);

Datei anzeigen

@ -18,10 +18,10 @@
package com.viaversion.viaversion.protocols.v1_8to1_9.storage;
import com.google.common.collect.Sets;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import java.util.Set;
public class ClientChunks implements StorableObject {
public class ClientWorld1_9 extends ClientWorld {
private final Set<Long> loadedChunks = Sets.newConcurrentHashSet();
public static long toLong(int msw, int lsw) {

Datei anzeigen

@ -87,7 +87,7 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
});
registerClientbound(ClientboundPackets1_9.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_1To1_9_3.class);
Chunk chunk = wrapper.read(ChunkType1_9_1.forEnvironment(clientWorld.getEnvironment()));
wrapper.write(ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()), chunk);
@ -120,7 +120,7 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_1To1_9_3.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
});
@ -132,7 +132,7 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_1To1_9_3.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
@ -156,8 +156,6 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
@Override
public void init(UserConnection user) {
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
user.addClientWorld(this.getClass(), new ClientWorld());
}
}

Datei anzeigen

@ -153,7 +153,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_3To1_10.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
@ -168,7 +168,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_3To1_10.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
@ -178,7 +178,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
// Chunk Data
registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_3To1_10.class);
Chunk chunk = wrapper.passthrough(ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()));
if (Via.getConfig().isReplacePistons()) {
@ -234,11 +234,9 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
@Override
public void init(UserConnection userConnection) {
userConnection.put(new ResourcePackTracker());
userConnection.addClientWorld(this.getClass(), new ClientWorld());
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.put(new ResourcePackTracker());
}
@Override

Datei anzeigen

@ -40,6 +40,7 @@ import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.SerializerVersion;
import com.viaversion.viaversion.util.TagUtil;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.BitSet;
/**
* Handles json and tag components, containing methods to override certain parts of the handling.
@ -139,6 +140,43 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
});
}
public void registerPlayerInfoUpdate1_20_3(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM);
if (!actions.get(5)) { // Update display name
return;
}
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID);
if (actions.get(0)) {
wrapper.passthrough(Types.STRING); // Player Name
final int properties = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Types.STRING); // Name
wrapper.passthrough(Types.STRING); // Value
wrapper.passthrough(Types.OPTIONAL_STRING); // Signature
}
}
if (actions.get(1) && wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.UUID); // Session UUID
wrapper.passthrough(Types.PROFILE_KEY);
}
if (actions.get(2)) {
wrapper.passthrough(Types.VAR_INT); // Gamemode
}
if (actions.get(3)) {
wrapper.passthrough(Types.BOOLEAN); // Listed
}
if (actions.get(4)) {
wrapper.passthrough(Types.VAR_INT); // Latency
}
processTag(wrapper.user(), wrapper.passthrough(Types.OPTIONAL_TAG));
}
});
}
public void registerPlayerCombatKill(final C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override

Datei anzeigen

@ -367,6 +367,11 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
registerSetEntityData(packetType, null, dataType);
}
public void clearEntities(final UserConnection connection) {
final EntityTracker tracker = tracker(connection);
tracker.clearEntities();
}
public PacketHandler trackerHandler() {
return trackerAndRewriterHandler(null);
}
@ -410,7 +415,6 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
String world = wrapper.get(Types.STRING, 0);
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
tracker.clearEntities();
tracker.trackClientEntity();
}
tracker.setCurrentWorld(world);
};
@ -433,7 +437,6 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
String world = wrapper.get(Types.STRING, 1);
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
tracker.clearEntities();
tracker.trackClientEntity();
}
tracker.setCurrentWorld(world);
};
@ -462,7 +465,6 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
// Clear entities if the world changes
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
tracker.clearEntities();
tracker.trackClientEntity();
}
tracker.setCurrentWorld(world);
}

Datei anzeigen

@ -22,6 +22,7 @@ import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
@ -30,7 +31,6 @@ import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import com.viaversion.viaversion.api.type.Type;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.Map;
@ -63,40 +63,12 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
}
final MappingData mappingData = protocol.getMappingData();
final StructuredDataContainer dataContainer = item.dataContainer();
if (mappingData != null) {
if (mappingData.getItemMappings() != null) {
if (mappingData != null && mappingData.getItemMappings() != null) {
item.setIdentifier(mappingData.getNewItemId(item.identifier()));
}
final FullMappings dataComponentMappings = mappingData.getDataComponentSerializerMappings();
if (dataComponentMappings != null) {
dataContainer.setIdLookup(protocol, true);
dataContainer.updateIds(protocol, dataComponentMappings::getNewId);
}
}
final ComponentRewriter componentRewriter = protocol.getComponentRewriter();
if (componentRewriter != null) {
// Handle name and lore components
updateComponent(connection, item, StructuredDataKey.ITEM_NAME, "item_name");
updateComponent(connection, item, StructuredDataKey.CUSTOM_NAME, "custom_name");
final StructuredData<Tag[]> loreData = dataContainer.getNonEmpty(StructuredDataKey.LORE);
if (loreData != null) {
for (final Tag tag : loreData.value()) {
componentRewriter.processTag(connection, tag);
}
}
}
Int2IntFunction itemIdRewriter = null;
Int2IntFunction blockIdRewriter = null;
if (mappingData != null) {
itemIdRewriter = mappingData.getItemMappings() != null ? mappingData::getNewItemId : null;
blockIdRewriter = mappingData.getBlockMappings() != null ? mappingData::getNewBlockId : null;
}
updateItemComponents(connection, dataContainer, this::handleItemToClient, itemIdRewriter, blockIdRewriter);
updateItemDataComponentTypeIds(item.dataContainer(), true);
updateItemDataComponents(connection, item, true);
return item;
}
@ -107,44 +79,69 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
}
final MappingData mappingData = protocol.getMappingData();
final StructuredDataContainer dataContainer = item.dataContainer();
if (mappingData != null) {
if (mappingData.getItemMappings() != null) {
if (mappingData != null && mappingData.getItemMappings() != null) {
item.setIdentifier(mappingData.getOldItemId(item.identifier()));
}
final FullMappings dataComponentMappings = mappingData.getDataComponentSerializerMappings();
if (dataComponentMappings != null) {
dataContainer.setIdLookup(protocol, false);
dataContainer.updateIds(protocol, id -> dataComponentMappings.inverse().getNewId(id));
}
}
updateItemDataComponentTypeIds(item.dataContainer(), false);
updateItemDataComponents(connection, item, false);
restoreTextComponents(item);
Int2IntFunction itemIdRewriter = null;
Int2IntFunction blockIdRewriter = null;
if (mappingData != null) {
itemIdRewriter = mappingData.getItemMappings() != null ? mappingData::getOldItemId : null;
blockIdRewriter = mappingData.getBlockMappings() != null ? mappingData::getOldBlockId : null;
}
updateItemComponents(connection, dataContainer, this::handleItemToServer, itemIdRewriter, blockIdRewriter);
return item;
}
protected void updateItemComponents(UserConnection connection, StructuredDataContainer container, ItemHandler itemHandler, @Nullable Int2IntFunction idRewriter, @Nullable Int2IntFunction blockIdRewriter) {
// Specific types that need deep handling
if (idRewriter != null) {
container.updateIfPresent(StructuredDataKey.TRIM, value -> value.rewrite(idRewriter));
container.updateIfPresent(StructuredDataKey.POT_DECORATIONS, value -> value.rewrite(idRewriter));
protected void updateItemDataComponentTypeIds(final StructuredDataContainer container, final boolean mappedNames) {
final MappingData mappingData = protocol.getMappingData();
if (mappingData == null) {
return;
}
FullMappings dataComponentMappings = mappingData.getDataComponentSerializerMappings();
if (dataComponentMappings == null) {
return;
}
if (!mappedNames) {
dataComponentMappings = dataComponentMappings.inverse();
}
container.setIdLookup(protocol, mappedNames); // Necessary to be set before trying to add values to the container
container.updateIds(protocol, dataComponentMappings::getNewId);
}
protected void updateItemDataComponents(final UserConnection connection, final Item item, final boolean clientbound) {
// Specific types that need deep handling
final StructuredDataContainer container = item.dataContainer();
final MappingData mappingData = protocol.getMappingData();
if (mappingData.getItemMappings() != null) {
final Int2IntFunction itemIdRewriter = clientbound ? mappingData::getNewItemId : mappingData::getOldItemId;
container.replace(StructuredDataKey.TRIM, value -> value.rewrite(itemIdRewriter));
container.replace(StructuredDataKey.POT_DECORATIONS, value -> value.rewrite(itemIdRewriter));
}
if (mappingData.getBlockMappings() != null) {
final Int2IntFunction blockIdRewriter = clientbound ? mappingData::getNewBlockId : mappingData::getOldBlockId;
container.replace(StructuredDataKey.TOOL, value -> value.rewrite(blockIdRewriter));
container.replace(StructuredDataKey.CAN_PLACE_ON, value -> value.rewrite(blockIdRewriter));
container.replace(StructuredDataKey.CAN_BREAK, value -> value.rewrite(blockIdRewriter));
}
if (mappingData.getSoundMappings() != null) {
final Int2IntFunction soundIdRewriter = clientbound ? mappingData::getNewSoundId : mappingData::getOldSoundId;
container.replace(StructuredDataKey.INSTRUMENT, value -> value.isDirect() ? Holder.of(value.value().rewrite(soundIdRewriter)) : value);
container.replace(StructuredDataKey.JUKEBOX_PLAYABLE, value -> value.rewrite(soundIdRewriter));
}
if (clientbound && protocol.getComponentRewriter() != null) {
updateComponent(connection, item, StructuredDataKey.ITEM_NAME, "item_name");
updateComponent(connection, item, StructuredDataKey.CUSTOM_NAME, "custom_name");
final Tag[] lore = container.get(StructuredDataKey.LORE);
if (lore != null) {
for (final Tag tag : lore) {
protocol.getComponentRewriter().processTag(connection, tag);
}
}
if (blockIdRewriter != null) {
container.updateIfPresent(StructuredDataKey.TOOL, value -> value.rewrite(blockIdRewriter));
container.updateIfPresent(StructuredDataKey.CAN_PLACE_ON, value -> value.rewrite(blockIdRewriter));
container.updateIfPresent(StructuredDataKey.CAN_BREAK, value -> value.rewrite(blockIdRewriter));
}
// Look for item types
final ItemHandler itemHandler = clientbound ? this::handleItemToClient : this::handleItemToServer;
for (final Map.Entry<StructuredDataKey<?>, StructuredData<?>> entry : container.data().entrySet()) {
final StructuredData<?> data = entry.getValue();
if (data.isEmpty()) {
@ -169,35 +166,35 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
}
protected void updateComponent(final UserConnection connection, final Item item, final StructuredDataKey<Tag> key, final String backupKey) {
final StructuredData<Tag> name = item.dataContainer().getNonEmpty(key);
final Tag name = item.dataContainer().get(key);
if (name == null) {
return;
}
final Tag originalName = name.value().copy();
protocol.getComponentRewriter().processTag(connection, name.value());
if (!name.value().equals(originalName)) {
final Tag originalName = name.copy();
protocol.getComponentRewriter().processTag(connection, name);
if (!name.equals(originalName)) {
saveTag(createCustomTag(item), originalName, backupKey);
}
}
protected void restoreTextComponents(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final StructuredData<CompoundTag> customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
return;
}
// Remove custom name
if (customData.value().remove(nbtTagName("added_custom_name")) != null) {
if (customData.remove(nbtTagName("added_custom_name")) != null) {
data.remove(StructuredDataKey.CUSTOM_NAME);
} else {
final Tag customName = removeBackupTag(customData.value(), "custom_name");
final Tag customName = removeBackupTag(customData, "custom_name");
if (customName != null) {
data.set(StructuredDataKey.CUSTOM_NAME, customName);
}
final Tag itemName = removeBackupTag(customData.value(), "item_name");
final Tag itemName = removeBackupTag(customData, "item_name");
if (itemName != null) {
data.set(StructuredDataKey.ITEM_NAME, itemName);
}
@ -206,14 +203,12 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
protected CompoundTag createCustomTag(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final StructuredData<CompoundTag> customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
if (customData != null) {
return customData.value();
CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
customData = new CompoundTag();
data.set(StructuredDataKey.CUSTOM_DATA, customData);
}
final CompoundTag tag = new CompoundTag();
data.set(StructuredDataKey.CUSTOM_DATA, tag);
return tag;
return customData;
}
protected void saveTag(final CompoundTag customData, final Tag tag, final String name) {
@ -228,7 +223,7 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
}
@FunctionalInterface
public interface ItemHandler {
private interface ItemHandler {
Item rewrite(UserConnection connection, Item item);
}

Datei anzeigen

@ -167,6 +167,9 @@ handle-invalid-item-count: false
# Hides scoreboard numbers for 1.20.3+ clients on older server versions.
hide-scoreboard-numbers: false
#
# Fixes 1.21+ clients on 1.20.5 servers placing water/lava buckets at the wrong location when moving fast, NOTE: This may cause issues with anti-cheat plugins.
fix-1_21-placement-rotation: false
#
#----------------------------------------------------------#
# 1.9+ CLIENTS ON 1.8 SERVERS OPTIONS #
#----------------------------------------------------------#

Datei anzeigen

@ -5,7 +5,7 @@ metadata.format.version = "1.1"
gson = "2.10.1"
fastutil = "8.5.12"
vianbt = "5.0.0"
mcstructs = "5-2.5.1"
mcstructs = "5-2.5.3"
# Common provided
netty = "4.0.20.Final"

Datei anzeigen

@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

Datei anzeigen

@ -29,6 +29,7 @@ setupViaSubproject("common")
setupViaSubproject("bukkit")
setupViaSubproject("bukkit-legacy")
setupViaSubproject("velocity")
setupViaSubproject("sponge")
setupViaSubproject("fabric")
setupSubproject("viaversion") {

Datei anzeigen

@ -0,0 +1,66 @@
{
"loader": {
"name": "java_plain",
"version": "1.0"
},
"license": "GNU GPLv3",
"global": {
"version": "${version}",
"links": {
"homepage": "https://viaversion.com/",
"source": "https://github.com/ViaVersion/ViaVersion",
"issues": "https://github.com/ViaVersion/ViaVersion/issues"
},
"contributors": [
{
"name": "_MylesC",
"description": "Maintainer"
},
{
"name": "creeper123123321",
"description": "Contributor"
},
{
"name": "Gerrygames",
"description": "Contributor"
},
{
"name": "kennytv",
"description": "Maintainer"
},
{
"name": "Matsv",
"description": "Contributor"
},
{
"name": "EnZaXD",
"description": "Maintainer"
},
{
"name": "RK_01",
"description": "Contributor"
}
],
"dependencies": [
{
"id": "spongeapi",
"version": "8.0.0"
},
{
"id": "viasponge",
"version": "1.1.0"
}
],
"branding": {
"logo": "assets/viaversion/textures/logo.png"
}
},
"plugins": [
{
"id": "viaversion",
"name": "ViaVersion",
"entrypoint": "com.viaversion.sponge.util.DummyEntrypoint",
"description": "${description}"
}
]
}

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 30 KiB

Datei anzeigen

@ -7,6 +7,7 @@ dependencies {
api(projects.viaversionCommon)
api(projects.viaversionBukkit)
api(projects.viaversionVelocity)
api(projects.viaversionSponge)
api(projects.viaversionFabric)
}