From 37561705edcaf756181ad93fd06f5bf8b72b061e Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Wed, 24 Jan 2024 17:34:40 +0100 Subject: [PATCH] 24w04a --- .../api/data/entity/DimensionData.java | 2 + .../api/data/entity/EntityTracker.java | 2 + .../api/minecraft/RegistryEntry.java | 43 ++++++++++++++ .../api/protocol/version/ProtocolVersion.java | 2 +- .../viaversion/viaversion/api/type/Type.java | 5 ++ .../api/type/types/RegistryEntryType.java | 45 +++++++++++++++ .../data/entity/DimensionDataImpl.java | 12 +++- .../data/entity/EntityTrackerBase.java | 8 ++- .../packets/EntityPackets.java | 4 +- .../rewriter/EntityPacketRewriter1_20_5.java | 54 +++++++++++++++--- .../viaversion/rewriter/EntityRewriter.java | 48 +++++++++++++++- .../data/mappings-1.20.3to1.20.5.nbt | Bin 863 -> 863 bytes gradle.properties | 2 +- .../rewriter/EntityPacketRewriter1_99.java | 14 ++--- 14 files changed, 219 insertions(+), 22 deletions(-) create mode 100644 api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java create mode 100644 api/src/main/java/com/viaversion/viaversion/api/type/types/RegistryEntryType.java diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/entity/DimensionData.java b/api/src/main/java/com/viaversion/viaversion/api/data/entity/DimensionData.java index 8af8734c4..0b0dc82fc 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/entity/DimensionData.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/entity/DimensionData.java @@ -24,6 +24,8 @@ package com.viaversion.viaversion.api.data.entity; public interface DimensionData { + int id(); + int minY(); int height(); diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java b/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java index 5f9b636ee..56770754a 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java @@ -165,6 +165,8 @@ public interface EntityTracker { @Nullable DimensionData dimensionData(String dimension); + @Nullable DimensionData dimensionData(int dimensionId); + void setDimensions(Map dimensions); /** diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java new file mode 100644 index 000000000..c9199f905 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java @@ -0,0 +1,43 @@ +/* + * 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; + +import com.github.steveice10.opennbt.tag.builtin.Tag; + +public final class RegistryEntry { + private final String key; + private final Tag tag; + + public RegistryEntry(String key, Tag tag) { + this.key = key; + this.tag = tag; + } + + public String key() { + return key; + } + + public Tag tag() { + return tag; + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java index 44a566dd8..6709baedf 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java @@ -86,7 +86,7 @@ public class ProtocolVersion { public static final ProtocolVersion v1_20 = register(763, "1.20/1.20.1", new VersionRange("1.20", 0, 1)); public static final ProtocolVersion v1_20_2 = register(764, "1.20.2"); public static final ProtocolVersion v1_20_3 = register(765, "1.20.3/1.20.4", new VersionRange("1.20", 3, 4)); - public static final ProtocolVersion v1_20_5 = register(766, 172, "1.20.5"); + public static final ProtocolVersion v1_20_5 = register(766, 173, "1.20.5"); public static final ProtocolVersion unknown = register(-1, "UNKNOWN"); public static ProtocolVersion register(int version, String name) { diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/Type.java b/api/src/main/java/com/viaversion/viaversion/api/type/Type.java index b3a0d70ca..e0baf6979 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/Type.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/Type.java @@ -32,6 +32,7 @@ import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature; import com.viaversion.viaversion.api.minecraft.Position; import com.viaversion.viaversion.api.minecraft.ProfileKey; import com.viaversion.viaversion.api.minecraft.Quaternion; +import com.viaversion.viaversion.api.minecraft.RegistryEntry; import com.viaversion.viaversion.api.minecraft.Vector; import com.viaversion.viaversion.api.minecraft.Vector3f; import com.viaversion.viaversion.api.minecraft.VillagerData; @@ -49,6 +50,7 @@ import com.viaversion.viaversion.api.type.types.FloatType; import com.viaversion.viaversion.api.type.types.IntType; import com.viaversion.viaversion.api.type.types.LongArrayType; import com.viaversion.viaversion.api.type.types.LongType; +import com.viaversion.viaversion.api.type.types.RegistryEntryType; import com.viaversion.viaversion.api.type.types.RemainingBytesType; import com.viaversion.viaversion.api.type.types.ShortByteArrayType; import com.viaversion.viaversion.api.type.types.ShortType; @@ -178,6 +180,9 @@ public abstract class Type implements ByteBufReader, ByteBufWriter { public static final ByteArrayType SIGNATURE_BYTES = new ByteArrayType(256); public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES = new ByteArrayType.OptionalByteArrayType(256); + public static final Type REGISTRY_ENTRY = new RegistryEntryType(); + public static final Type REGISTRY_ENTRY_ARRAY = new ArrayType<>(REGISTRY_ENTRY); + public static final Type ITEM1_8 = new ItemType1_8(); public static final Type ITEM1_13 = new ItemType1_13(); public static final Type ITEM1_13_2 = new ItemType1_13_2(); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/RegistryEntryType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/RegistryEntryType.java new file mode 100644 index 000000000..7d1217efc --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/RegistryEntryType.java @@ -0,0 +1,45 @@ +/* + * 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.type.types; + +import com.viaversion.viaversion.api.minecraft.RegistryEntry; +import com.viaversion.viaversion.api.type.Type; +import io.netty.buffer.ByteBuf; + +public class RegistryEntryType extends Type { + + public RegistryEntryType() { + super(RegistryEntry.class); + } + + @Override + public RegistryEntry read(final ByteBuf buffer) throws Exception { + return new RegistryEntry(Type.STRING.read(buffer), Type.TAG.read(buffer)); + } + + @Override + public void write(final ByteBuf buffer, final RegistryEntry entry) throws Exception { + Type.STRING.write(buffer, entry.key()); + Type.TAG.write(buffer, entry.tag()); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/data/entity/DimensionDataImpl.java b/common/src/main/java/com/viaversion/viaversion/data/entity/DimensionDataImpl.java index 0e6af9609..790cdd3e8 100644 --- a/common/src/main/java/com/viaversion/viaversion/data/entity/DimensionDataImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/data/entity/DimensionDataImpl.java @@ -25,15 +25,18 @@ import com.viaversion.viaversion.api.data.entity.DimensionData; public final class DimensionDataImpl implements DimensionData { + private final int id; private final int minY; private final int height; - public DimensionDataImpl(final int minY, final int height) { + public DimensionDataImpl(final int id, final int minY, final int height) { + this.id = id; this.minY = minY; this.height = height; } - public DimensionDataImpl(final CompoundTag dimensionData) { + public DimensionDataImpl(final int id, final CompoundTag dimensionData) { + this.id = id; final Tag height = dimensionData.get("height"); if (height instanceof IntTag) { this.height = ((NumberTag) height).asInt(); @@ -49,6 +52,11 @@ public final class DimensionDataImpl implements DimensionData { } } + @Override + public int id() { + return id; + } + @Override public int minY() { return minY; diff --git a/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java b/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java index 761d37212..3d7548e8c 100644 --- a/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java +++ b/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java @@ -26,6 +26,7 @@ import com.viaversion.viaversion.api.data.entity.EntityTracker; import com.viaversion.viaversion.api.data.entity.StoredEntityData; import com.viaversion.viaversion.api.data.entity.TrackedEntity; import com.viaversion.viaversion.api.minecraft.entities.EntityType; +import com.viaversion.viaversion.util.Key; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import java.util.Collections; import java.util.Map; @@ -171,7 +172,12 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis @Override public @Nullable DimensionData dimensionData(String dimension) { - return dimensions.get(dimension); + return dimensions.get(Key.stripMinecraftNamespace(dimension)); + } + + @Override + public @Nullable DimensionData dimensionData(int dimensionId) { + return dimensions.values().stream().filter(data -> data.id() == dimensionId).findFirst().orElse(null); // TODO Store as array as well } @Override diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19to1_18_2/packets/EntityPackets.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19to1_18_2/packets/EntityPackets.java index f5af1027e..202220293 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19to1_18_2/packets/EntityPackets.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19to1_18_2/packets/EntityPackets.java @@ -21,6 +21,7 @@ import com.github.steveice10.opennbt.stringified.SNBT; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.NumberTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.google.common.collect.Maps; import com.google.gson.JsonElement; @@ -215,10 +216,11 @@ public final class EntityPackets extends EntityRewriter dimensionsMap = new HashMap<>(dimensions.size()); for (final Tag dimension : dimensions) { final CompoundTag dimensionCompound = (CompoundTag) dimension; + final NumberTag idTag = dimensionCompound.get("id"); final CompoundTag element = dimensionCompound.get("element"); final String name = (String) dimensionCompound.get("name").getValue(); addMonsterSpawnData(element); - dimensionDataMap.put(name, new DimensionDataImpl(element)); + dimensionDataMap.put(Key.stripMinecraftNamespace(name), new DimensionDataImpl(idTag.asInt(), element)); dimensionsMap.put(element.copy(), name); } tracker(wrapper.user()).setDimensions(dimensionDataMap); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/EntityPacketRewriter1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/EntityPacketRewriter1_20_5.java index e404ed663..8c45c9189 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/EntityPacketRewriter1_20_5.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/EntityPacketRewriter1_20_5.java @@ -17,8 +17,16 @@ */ package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.NumberTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.viaversion.viaversion.api.data.entity.DimensionData; +import com.viaversion.viaversion.api.minecraft.RegistryEntry; import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Type; @@ -28,8 +36,10 @@ import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.Clientb import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPackets1_20_3; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.Protocol1_20_5To1_20_3; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.AttributeMappings; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundConfigurationPackets1_20_5; import com.viaversion.viaversion.rewriter.EntityRewriter; import com.viaversion.viaversion.util.Key; +import java.util.Map; public final class EntityPacketRewriter1_20_5 extends EntityRewriter { @@ -46,9 +56,31 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter { + final CompoundTag registryData = wrapper.read(Type.COMPOUND_TAG); + cacheDimensionData(wrapper.user(), registryData); + trackBiomeSize(wrapper.user(), registryData); + + for (final Map.Entry entry : registryData.entrySet()) { + final CompoundTag entryTag = (CompoundTag) entry.getValue(); + final StringTag typeTag = entryTag.get("type"); + final ListTag valueTag = entryTag.get("value"); + final RegistryEntry[] registryEntries = new RegistryEntry[valueTag.size()]; + for (final Tag tag : valueTag) { + final CompoundTag compoundTag = (CompoundTag) tag; + final StringTag nameTag = compoundTag.get("name"); + final int id = ((NumberTag) compoundTag.get("id")).asInt(); + registryEntries[id] = new RegistryEntry(nameTag.getValue(), compoundTag.get("element")); + } + + final PacketWrapper registryPacket = wrapper.create(ClientboundConfigurationPackets1_20_5.REGISTRY_DATA); + registryPacket.write(Type.STRING, typeTag.getValue()); + registryPacket.write(Type.REGISTRY_ENTRY_ARRAY, registryEntries); + registryPacket.send(Protocol1_20_5To1_20_3.class); + } + + wrapper.cancel(); + }); } }); @@ -64,7 +96,11 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter { + final String dimensionKey = wrapper.read(Type.STRING); + final DimensionData data = tracker(wrapper.user()).dimensionData(dimensionKey); + wrapper.write(Type.VAR_INT, data.id()); + }); map(Type.STRING); // World map(Type.LONG); // Seed map(Type.BYTE); // Gamemode @@ -73,16 +109,20 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter { + final String dimensionKey = wrapper.read(Type.STRING); + final DimensionData data = tracker(wrapper.user()).dimensionData(dimensionKey); + wrapper.write(Type.VAR_INT, data.id()); + }); map(Type.STRING); // World - handler(worldDataTrackerHandlerByKey()); // Tracks world height and name for chunk data and entity (un)tracking + handler(worldDataTrackerHandlerByKey1_20_5(0)); // Tracks world height and name for chunk data and entity (un)tracking } }); diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java index 24db49946..cff878934 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java @@ -20,8 +20,8 @@ package com.viaversion.viaversion.rewriter; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.NumberTag; import com.github.steveice10.opennbt.tag.builtin.Tag; -import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; @@ -32,6 +32,7 @@ import com.viaversion.viaversion.api.data.entity.DimensionData; import com.viaversion.viaversion.api.data.entity.EntityTracker; import com.viaversion.viaversion.api.data.entity.TrackedEntity; import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.minecraft.RegistryEntry; import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.metadata.MetaType; @@ -46,6 +47,7 @@ import com.viaversion.viaversion.data.entity.DimensionDataImpl; import com.viaversion.viaversion.rewriter.meta.MetaFilter; import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent; import com.viaversion.viaversion.rewriter.meta.MetaHandlerEventImpl; +import com.viaversion.viaversion.util.Key; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; @@ -440,6 +442,29 @@ public abstract class EntityRewriter { + EntityTracker tracker = tracker(wrapper.user()); + int dimensionId = wrapper.get(Type.VAR_INT, dimensionIdIndex); + DimensionData dimensionData = tracker.dimensionData(dimensionId); + if (dimensionData == null) { + Via.getPlatform().getLogger().severe("Dimension data missing for dimension: " + dimensionId + ", falling back to overworld"); + dimensionData = tracker.dimensionData("minecraft:overworld"); + Preconditions.checkNotNull(dimensionData, "Overworld data missing"); + } + + tracker.setCurrentWorldSectionHeight(dimensionData.height() >> 4); + tracker.setCurrentMinY(dimensionData.minY()); + + String world = wrapper.get(Type.STRING, 0); + if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) { + tracker.clearEntities(); + tracker.trackClientEntity(); + } + tracker.setCurrentWorld(world); + }; + } + public PacketHandler biomeSizeTracker() { return wrapper -> trackBiomeSize(wrapper.user(), wrapper.get(Type.NAMED_COMPOUND_TAG, 0)); } @@ -470,13 +495,32 @@ public abstract class EntityRewriter dimensionDataMap = new HashMap<>(dimensions.size()); for (final Tag dimension : dimensions) { final CompoundTag dimensionCompound = (CompoundTag) dimension; + final NumberTag idTag = dimensionCompound.get("id"); final CompoundTag element = dimensionCompound.get("element"); final String name = (String) dimensionCompound.get("name").getValue(); - dimensionDataMap.put(name, new DimensionDataImpl(element)); + dimensionDataMap.put(Key.stripMinecraftNamespace(name), new DimensionDataImpl(idTag.asInt(), element)); } tracker(connection).setDimensions(dimensionDataMap); } + public PacketHandler registryDataHandler1_20_5() { + return wrapper -> { + final String registryKey = Key.stripMinecraftNamespace(wrapper.get(Type.STRING, 0)); + if (registryKey.equals("worldgen/biome")) { + final RegistryEntry[] entries = wrapper.get(Type.REGISTRY_ENTRY_ARRAY, 0); + tracker(wrapper.user()).setBiomesSent(entries.length); + } else if (registryKey.equals("dimension_type")) { + final RegistryEntry[] entries = wrapper.get(Type.REGISTRY_ENTRY_ARRAY, 0); + final Map dimensionDataMap = new HashMap<>(entries.length); + for (int i = 0; i < entries.length; i++) { + final RegistryEntry entry = entries[i]; + dimensionDataMap.put(entry.key(), new DimensionDataImpl(i, (CompoundTag) entry.tag())); + } + tracker(wrapper.user()).setDimensions(dimensionDataMap); + } + }; + } + // --------------------------------------------------------------------------- // Sub 1.14.1 methods diff --git a/common/src/main/resources/assets/viaversion/data/mappings-1.20.3to1.20.5.nbt b/common/src/main/resources/assets/viaversion/data/mappings-1.20.3to1.20.5.nbt index 2bf2f10ba0d4e0dc4371d041184e543dc68c3de8..360f8abd9083630f995551ce92326354f956c120 100644 GIT binary patch delta 29 icmcc5cAss+3P$0HE6sQv85kIRfOsnq@89^Qm