Full 1.20.5 client and server support

This commit is contained in:
RaphiMC 2024-04-26 18:00:03 +02:00
parent bf2b806d99
commit 64b9926e55
No known key found for this signature in database
GPG Key ID: 0F6BB0657A03AC94
31 changed files with 7393 additions and 110 deletions

View File

@ -3,7 +3,7 @@ Standalone proxy which allows players to join EVERY Minecraft server version (Cl
To download the latest version, go to the [Releases section](#executable-jar-file) and download the latest version.
Using it is very simple, just run the jar file, and it will start a user interface where everything can be configured.
For a full user guide go to the [Usage for Players](#usage-for-players-gui) section or the [Usage for Server Owners](#usage-for-server-owners-cli) section.
For a full user guide go to the [Usage for Players](#usage-for-players-gui) section or the [Usage for Server Owners](#usage-for-server-owners-config) section.
## Supported Server versions
- Release (1.0.0 - 1.20.5)
@ -24,6 +24,7 @@ ViaProxy supports joining to any of the listed server version from any of the li
## Special Features
- Support for joining online mode servers
- Support for joining on servers which have chat signing enabled from all listed client versions
- Supports transfer and cookies for <=1.20.4 clients on 1.20.5+ servers
- Allows joining Minecraft Realms with any supported client version
## Releases
@ -70,19 +71,27 @@ dependencies {
7. Join with your Minecraft client on the displayed address
8. Have fun!
## Usage for Server owners (Config)
1. Download the latest version from the [Releases section](#executable-jar-file)
2. Put the jar file into a folder (ViaProxy will generate config files and store some data there)
3. Run the jar file (Using ``java -jar ViaProxy-whateverversion.jar config viaproxy.yml``)
4. ViaProxy now generates a config file called ``viaproxy.yml`` in the same folder and exits
5. Open the config file and configure the proxy (Most important options are at the top)
6. Start the proxy using the start command and test whether it works (Join using the server's public address and the bind port you configured)
7. Have fun!
## Usage for Server owners (CLI)
1. Download the latest version from the [Releases section](#executable-jar-file)
2. Put the jar file into a folder (ViaProxy will generate config files and store some data there)
3. Run the jar file (Using java -jar ViaProxy-whateverversion.jar --help)
4. Look at the available config options and use those you need just like you would in the GUI
5. Start the proxy using the start command and test whether it works (Join using the server's public address and the bind port you configured)
6. Have fun!
Here is an example command to allow players to join on yourserverip:25568 and connect to a beta 1.7.3 server running on port 25565:
``java -jar ViaProxy-whateverversion.jar --bind_address 0.0.0.0:25568 --target_ip 127.0.0.1:25565 --version b1.7-b1.7.3``
3. Run the jar file (Using ``java -jar ViaProxy-whateverversion.jar cli --help``)
4. ViaProxy will print the CLI usage and exit
5. Configure the proxy and optionally put the finished start command into a script
6. Start the proxy using the start command and test whether it works (Join using the server's public address and the bind port you configured)
7. Have fun!
### Configuring the protocol translation
To change the protocol translation settings/features you can look into the ViaLoader folder.
To change ViaProxy settings you can check out the ``viaproxy.yml`` config file. Most of the settings are configurable via the GUI.
To change the protocol translation settings/features you can look into the ``ViaLoader`` folder.
You will find 5 config files there:
- viaversion.yml (ViaVersion)
- viabackwards.yml (ViaBackwards)

View File

@ -54,16 +54,16 @@ repositories {
}
dependencies {
include "com.viaversion:viaversion-common:4.10.0-24w09a-SNAPSHOT"
include "com.viaversion:viabackwards-common:4.10.0-24w09a-SNAPSHOT"
include "com.viaversion:viarewind-common:3.0.7-24w09a-SNAPSHOT"
include "net.raphimc:ViaLegacy:2.2.22-SNAPSHOT"
include "net.raphimc:ViaAprilFools:2.0.11-SNAPSHOT"
include "com.viaversion:viaversion-common:4.10.0"
include "com.viaversion:viabackwards-common:4.10.0"
include "com.viaversion:viarewind-common:3.1.0"
include "net.raphimc:ViaLegacy:2.2.22"
include "net.raphimc:ViaAprilFools:2.0.11"
include("net.raphimc:ViaBedrock:0.0.6-SNAPSHOT") {
exclude group: "io.netty"
exclude group: "io.jsonwebtoken"
}
include("net.raphimc:ViaLoader:2.2.13-SNAPSHOT") {
include("net.raphimc:ViaLoader:2.2.13") {
exclude group: "org.slf4j", module: "slf4j-api"
}

View File

@ -111,7 +111,7 @@ public class ViaProxy {
Logger.setup();
final boolean useUI = args.length == 0 && !GraphicsEnvironment.isHeadless();
final boolean useConfig = args.length > 0 && args[0].equals("config");
final boolean useConfig = args.length == 2 && args[0].equals("config");
final boolean useCLI = args.length > 0 && args[0].equals("cli");
final boolean useLegacyCLI = args.length > 0 && args[0].startsWith("-");
if (!useUI && !useConfig && !useCLI && !useLegacyCLI) {

View File

@ -0,0 +1,25 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2024 RK_01/RaphiMC 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 net.raphimc.viaproxy.injection.interfaces;
public interface IBlockItemPacketRewriter1_20_5 {
void onMappingDataLoaded();
}

View File

@ -0,0 +1,213 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2024 RK_01/RaphiMC 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 net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.HolderSet;
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.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties;
import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.ToolRule;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.libs.fastutil.ints.IntOpenHashSet;
import com.viaversion.viaversion.libs.fastutil.ints.IntSet;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPacket1_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.packet.ServerboundPacket1_20_5;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter.BlockItemPacketRewriter1_20_5;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.viaproxy.injection.interfaces.IBlockItemPacketRewriter1_20_5;
import net.raphimc.viaproxy.protocoltranslator.impl.ViaProxyMappingDataLoader;
import net.raphimc.viaproxy.util.logging.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.*;
@Mixin(value = BlockItemPacketRewriter1_20_5.class, remap = false)
public abstract class MixinBlockItemPacketRewriter1_20_5 extends ItemRewriter<ClientboundPacket1_20_3, ServerboundPacket1_20_5, Protocol1_20_5To1_20_3> implements IBlockItemPacketRewriter1_20_5 {
@Unique
private final Set<String> foodItems_b1_7_3 = new HashSet<>();
@Unique
private final Map<String, Integer> armorMaxDamage_b1_8_1 = new HashMap<>();
@Unique
private final Set<String> swordItems1_8 = new HashSet<>();
@Unique
private final Map<ProtocolVersion, Map<String, ToolProperties>> toolDataChanges = new LinkedHashMap<>();
public MixinBlockItemPacketRewriter1_20_5() {
super(null, null, null, null, null);
}
@Override
public void onMappingDataLoaded() {
this.foodItems_b1_7_3.add("minecraft:apple");
this.foodItems_b1_7_3.add("minecraft:mushroom_stew");
this.foodItems_b1_7_3.add("minecraft:bread");
this.foodItems_b1_7_3.add("minecraft:porkchop");
this.foodItems_b1_7_3.add("minecraft:cooked_porkchop");
this.foodItems_b1_7_3.add("minecraft:golden_apple");
this.foodItems_b1_7_3.add("minecraft:cod");
this.foodItems_b1_7_3.add("minecraft:cooked_cod");
this.foodItems_b1_7_3.add("minecraft:cookie");
this.armorMaxDamage_b1_8_1.put("minecraft:leather_helmet", 33);
this.armorMaxDamage_b1_8_1.put("minecraft:leather_chestplate", 48);
this.armorMaxDamage_b1_8_1.put("minecraft:leather_leggings", 45);
this.armorMaxDamage_b1_8_1.put("minecraft:leather_boots", 39);
this.armorMaxDamage_b1_8_1.put("minecraft:chainmail_helmet", 66);
this.armorMaxDamage_b1_8_1.put("minecraft:chainmail_chestplate", 96);
this.armorMaxDamage_b1_8_1.put("minecraft:chainmail_leggings", 90);
this.armorMaxDamage_b1_8_1.put("minecraft:chainmail_boots", 78);
this.armorMaxDamage_b1_8_1.put("minecraft:iron_helmet", 132);
this.armorMaxDamage_b1_8_1.put("minecraft:iron_chestplate", 192);
this.armorMaxDamage_b1_8_1.put("minecraft:iron_leggings", 180);
this.armorMaxDamage_b1_8_1.put("minecraft:iron_boots", 156);
this.armorMaxDamage_b1_8_1.put("minecraft:diamond_helmet", 264);
this.armorMaxDamage_b1_8_1.put("minecraft:diamond_chestplate", 384);
this.armorMaxDamage_b1_8_1.put("minecraft:diamond_leggings", 360);
this.armorMaxDamage_b1_8_1.put("minecraft:diamond_boots", 312);
this.armorMaxDamage_b1_8_1.put("minecraft:golden_helmet", 66);
this.armorMaxDamage_b1_8_1.put("minecraft:golden_chestplate", 96);
this.armorMaxDamage_b1_8_1.put("minecraft:golden_leggings", 90);
this.armorMaxDamage_b1_8_1.put("minecraft:golden_boots", 78);
this.swordItems1_8.add("minecraft:wooden_sword");
this.swordItems1_8.add("minecraft:stone_sword");
this.swordItems1_8.add("minecraft:iron_sword");
this.swordItems1_8.add("minecraft:golden_sword");
this.swordItems1_8.add("minecraft:diamond_sword");
final JsonObject itemToolComponents = ViaProxyMappingDataLoader.INSTANCE.loadData("item-tool-components.json");
for (Map.Entry<String, JsonElement> entry : itemToolComponents.entrySet()) {
int attempts = 0;
while (ProtocolVersion.getClosest(entry.getKey()) == null) {
try {
Thread.sleep(100);
if (attempts++ > 100) { // 10 seconds
Logger.LOGGER.warn("Failed to load item-tool-components.json after 10 seconds. Skipping entry.");
break;
}
} catch (InterruptedException e) {
break;
}
}
final ProtocolVersion version = ProtocolVersion.getClosest(entry.getKey());
if (version == null) { // Only happens if the timeout above is reached or the thread is interrupted
continue;
}
final Map<String, ToolProperties> toolProperties = new HashMap<>();
final JsonArray toolComponents = entry.getValue().getAsJsonArray();
for (JsonElement toolComponent : toolComponents) {
final JsonObject toolComponentObject = toolComponent.getAsJsonObject();
final String item = toolComponentObject.get("item").getAsString();
final float defaultMiningSpeed = toolComponentObject.get("default_mining_speed").getAsFloat();
final int damagePerBlock = toolComponentObject.get("damage_per_block").getAsInt();
final int[] suitableFor = this.blockJsonArrayToIds(version, toolComponentObject.getAsJsonArray("suitable_for"));
final List<ToolRule> toolRules = new ArrayList<>();
final JsonArray miningSpeeds = toolComponentObject.getAsJsonArray("mining_speeds");
for (JsonElement miningSpeed : miningSpeeds) {
final JsonObject miningSpeedObject = miningSpeed.getAsJsonObject();
final int[] blocks = this.blockJsonArrayToIds(version, miningSpeedObject.getAsJsonArray("blocks"));
final float speed = miningSpeedObject.get("speed").getAsFloat();
toolRules.add(new ToolRule(HolderSet.of(blocks), speed, null));
}
if (suitableFor.length > 0) {
toolRules.add(new ToolRule(HolderSet.of(suitableFor), null, true));
}
toolProperties.put(item, new ToolProperties(toolRules.toArray(new ToolRule[0]), defaultMiningSpeed, damagePerBlock));
}
this.toolDataChanges.put(version, toolProperties);
}
}
@Inject(method = "toStructuredItem", at = @At("RETURN"))
private void appendItemDataFixComponents(UserConnection connection, Item old, CallbackInfoReturnable<Item> cir) {
final StructuredDataContainer data = cir.getReturnValue().structuredData();
final String identifier = this.protocol.getMappingData().getFullItemMappings().identifier(cir.getReturnValue().identifier());
if (connection.getProtocolInfo().serverProtocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_17_1)) {
if (identifier.equals("minecraft:crossbow")) {
data.set(StructuredDataKey.MAX_DAMAGE, 326);
}
}
if (connection.getProtocolInfo().serverProtocolVersion().betweenInclusive(LegacyProtocolVersion.b1_8tob1_8_1, ProtocolVersion.v1_8)) {
if (this.swordItems1_8.contains(identifier)) {
data.set(StructuredDataKey.FOOD, new FoodProperties(0, 0F, true, 3600, new FoodEffect[0]));
}
}
if (connection.getProtocolInfo().serverProtocolVersion().olderThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) {
if (this.armorMaxDamage_b1_8_1.containsKey(identifier)) {
data.set(StructuredDataKey.MAX_DAMAGE, this.armorMaxDamage_b1_8_1.get(identifier));
}
}
if (connection.getProtocolInfo().serverProtocolVersion().olderThanOrEqualTo(LegacyProtocolVersion.b1_7tob1_7_3)) {
if (this.foodItems_b1_7_3.contains(identifier)) {
data.set(StructuredDataKey.MAX_STACK_SIZE, 1);
data.addEmpty(StructuredDataKey.FOOD);
}
}
for (Map.Entry<ProtocolVersion, Map<String, ToolProperties>> entry : this.toolDataChanges.entrySet()) {
if (connection.getProtocolInfo().serverProtocolVersion().olderThanOrEqualTo(entry.getKey())) {
final ToolProperties toolProperties = entry.getValue().get(identifier);
if (toolProperties != null) {
data.set(StructuredDataKey.TOOL, toolProperties);
break;
}
}
}
}
@Unique
private int[] blockJsonArrayToIds(final ProtocolVersion protocolVersion, final JsonArray jsonArray) {
final IntSet ids = new IntOpenHashSet();
for (final JsonElement element : jsonArray) {
final String name = element.getAsString();
if (name.startsWith("#")) { // Material name
final String material = name.substring(1);
for (Map.Entry<String, Map<ProtocolVersion, String>> entry : ViaProxyMappingDataLoader.BLOCK_MATERIALS.entrySet()) {
for (Map.Entry<ProtocolVersion, String> materialEntry : entry.getValue().entrySet()) {
if (protocolVersion.olderThanOrEqualTo(materialEntry.getKey()) && materialEntry.getValue().equals(material)) {
ids.add(this.protocol.getMappingData().blockId(entry.getKey()));
break;
}
}
}
} else { // Block name
ids.add(this.protocol.getMappingData().blockId(element.getAsString()));
}
}
return ids.toIntArray();
}
}

View File

@ -0,0 +1,86 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2024 RK_01/RaphiMC 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 net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPacket1_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.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter.EntityPacketRewriter1_20_5;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import java.util.UUID;
@Mixin(value = EntityPacketRewriter1_20_5.class, remap = false)
public abstract class MixinEntityPacketRewriter1_20_5 extends EntityRewriter<ClientboundPacket1_20_3, Protocol1_20_5To1_20_3> {
@Shadow
@Final
private static UUID CREATIVE_BLOCK_INTERACTION_RANGE;
@Shadow
@Final
private static UUID CREATIVE_ENTITY_INTERACTION_RANGE;
protected MixinEntityPacketRewriter1_20_5(Protocol1_20_5To1_20_3 protocol) {
super(protocol);
}
@Shadow
protected abstract void writeAttribute(PacketWrapper wrapper, String attributeId, double base, @Nullable UUID modifierId, double amount);
/**
* @author RK_01
* @reason Fix interaction range and step height differences
*/
@Overwrite
private void sendRangeAttributes(final UserConnection connection, final boolean creativeMode) throws Exception {
final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_20_5.ENTITY_PROPERTIES, connection);
wrapper.write(Type.VAR_INT, this.tracker(connection).clientEntityId());
if (connection.getProtocolInfo().serverProtocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_7_6)) {
wrapper.write(Type.VAR_INT, 3); // Number of attributes
this.writeAttribute(wrapper, "generic.step_height", 0.5D, null, 0D);
} else {
wrapper.write(Type.VAR_INT, 2); // Number of attributes
}
if (connection.getProtocolInfo().serverProtocolVersion().olderThan(LegacyProtocolVersion.r1_0_0tor1_0_1)) {
this.writeAttribute(wrapper, "player.block_interaction_range", 4D, creativeMode ? CREATIVE_BLOCK_INTERACTION_RANGE : null, 1D);
} else {
this.writeAttribute(wrapper, "player.block_interaction_range", 4.5D, creativeMode ? CREATIVE_BLOCK_INTERACTION_RANGE : null, 0.5D);
}
if (connection.getProtocolInfo().serverProtocolVersion().olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) {
this.writeAttribute(wrapper, "player.entity_interaction_range", 3D, creativeMode ? CREATIVE_ENTITY_INTERACTION_RANGE : null, 3D);
} else if (connection.getProtocolInfo().serverProtocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_13_2)) {
this.writeAttribute(wrapper, "player.entity_interaction_range", 3D, creativeMode ? CREATIVE_ENTITY_INTERACTION_RANGE : null, 1D);
} else {
this.writeAttribute(wrapper, "player.entity_interaction_range", 3D, creativeMode ? CREATIVE_ENTITY_INTERACTION_RANGE : null, 2D);
}
wrapper.scheduleSend(Protocol1_20_5To1_20_3.class);
}
}

View File

@ -0,0 +1,128 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2024 RK_01/RaphiMC 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 net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.ModifierData;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ItemRewriter;
import com.viaversion.viaversion.util.Pair;
import net.raphimc.viaproxy.protocoltranslator.impl.ViaProxyMappingDataLoader;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Mixin(value = ItemRewriter.class, remap = false)
public abstract class MixinItemRewriter {
@Unique
private static final Int2ObjectMap<String> ITEM_IDENTIFIERS = new Int2ObjectOpenHashMap<>();
@Unique
private static final Map<String, Map<String, Pair<String, ModifierData>>> ITEM_ATTRIBUTES = new HashMap<>();
@Unique
private static final String TAG_NAME = "VV|AttributeFix";
@Inject(method = "<clinit>", at = @At("RETURN"))
private static void loadAdditionalData(CallbackInfo ci) {
final JsonObject itemIdentifiers = ViaProxyMappingDataLoader.INSTANCE.loadData("item-identifiers-1.8.json");
for (Map.Entry<String, JsonElement> entry : itemIdentifiers.entrySet()) {
ITEM_IDENTIFIERS.put(entry.getValue().getAsInt(), entry.getKey());
}
final JsonObject itemAttributes = ViaProxyMappingDataLoader.INSTANCE.loadData("item-attributes-1.8.json");
for (Map.Entry<String, JsonElement> itemEntry : itemAttributes.entrySet()) {
final String itemIdentifier = itemEntry.getKey();
final Map<String, Pair<String, ModifierData>> attributes = new HashMap<>();
for (Map.Entry<String, JsonElement> attributeEntry : itemEntry.getValue().getAsJsonObject().entrySet()) {
final String attribute = attributeEntry.getKey();
final JsonObject attributeData = attributeEntry.getValue().getAsJsonObject();
final ModifierData modifierData = new ModifierData(UUID.fromString(attributeData.get("id").getAsString()), attributeData.get("name").getAsString(), attributeData.get("amount").getAsDouble(), attributeData.get("operation").getAsInt());
final String slot = attributeData.get("slot").getAsString();
attributes.put(attribute, new Pair<>(slot, modifierData));
}
ITEM_ATTRIBUTES.put(itemIdentifier, attributes);
}
}
@Inject(method = "toClient", at = @At("RETURN"))
private static void addAttributeFixData(Item item, CallbackInfo ci) {
if (item == null) return;
final String identifier = ITEM_IDENTIFIERS.get(item.identifier());
if (identifier != null && ITEM_ATTRIBUTES.containsKey(identifier)) {
final Map<String, Pair<String, ModifierData>> attributes = ITEM_ATTRIBUTES.get(identifier);
final CompoundTag attributeFixTag = new CompoundTag();
CompoundTag tag = item.tag();
if (tag == null) {
tag = new CompoundTag();
item.setTag(tag);
attributeFixTag.putBoolean("RemoveTag", true);
}
tag.put(TAG_NAME, attributeFixTag);
ListTag<CompoundTag> attributeModifiers = tag.getListTag("AttributeModifiers", CompoundTag.class);
if (attributeModifiers == null) {
attributeModifiers = new ListTag<>(CompoundTag.class);
for (Map.Entry<String, Pair<String, ModifierData>> entry : attributes.entrySet()) {
final CompoundTag attributeModifier = new CompoundTag();
attributeModifier.putString("AttributeName", entry.getKey());
attributeModifier.putString("Name", entry.getValue().value().name());
attributeModifier.putDouble("Amount", entry.getValue().value().amount());
attributeModifier.putInt("Operation", entry.getValue().value().operation());
attributeModifier.putLong("UUIDMost", entry.getValue().value().uuid().getMostSignificantBits());
attributeModifier.putLong("UUIDLeast", entry.getValue().value().uuid().getLeastSignificantBits());
attributeModifier.putString("Slot", entry.getValue().key());
attributeModifiers.add(attributeModifier);
}
tag.put("AttributeModifiers", attributeModifiers);
attributeFixTag.putBoolean("RemoveAttributeModifiers", true);
}
}
}
@Inject(method = "toServer", at = @At("RETURN"))
private static void removeAttributeFixData(Item item, CallbackInfo ci) {
if (item == null) return;
final CompoundTag tag = item.tag();
if (tag == null) return;
final CompoundTag attributeFixTag = tag.removeUnchecked(TAG_NAME);
if (attributeFixTag == null) return;
if (attributeFixTag.contains("RemoveAttributeModifiers")) {
tag.remove("AttributeModifiers");
}
if (attributeFixTag.contains("RemoveTag")) {
item.setTag(null);
}
}
}

View File

@ -0,0 +1,43 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2024 RK_01/RaphiMC 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 net.raphimc.viaproxy.injection.mixins;
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.rewriter.BlockItemPacketRewriter1_20_5;
import net.raphimc.viaproxy.injection.interfaces.IBlockItemPacketRewriter1_20_5;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = Protocol1_20_5To1_20_3.class, remap = false)
public abstract class MixinProtocol1_20_5To1_20_3 {
@Shadow
@Final
private BlockItemPacketRewriter1_20_5 itemRewriter;
@Inject(method = "onMappingDataLoaded", at = @At("RETURN"))
private void callOnMappingDataLoaded(CallbackInfo ci) {
((IBlockItemPacketRewriter1_20_5) (Object) this.itemRewriter).onMappingDataLoaded();
}
}

View File

@ -1,87 +0,0 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2024 RK_01/RaphiMC 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 net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.SubVersionRange;
import com.viaversion.viaversion.util.Pair;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.HashMap;
import java.util.Map;
@Mixin(value = ProtocolVersion.class, remap = false)
public abstract class MixinProtocolVersion {
@Unique
private static Map<String, Pair<String, SubVersionRange>> remaps;
@Inject(method = "<clinit>", at = @At("HEAD"))
private static void initMaps(CallbackInfo ci) {
remaps = new HashMap<>();
remaps.put("1.9.3/1.9.4", new Pair<>("1.9.3-1.9.4", null));
remaps.put("1.11.1/1.11.2", new Pair<>("1.11.1-1.11.2", null));
remaps.put("1.16.4/1.16.5", new Pair<>("1.16.4-1.16.5", null));
remaps.put("1.18/1.18.1", new Pair<>("1.18-1.18.1", null));
remaps.put("1.19.1/1.19.2", new Pair<>("1.19.1-1.19.2", null));
remaps.put("1.20/1.20.1", new Pair<>("1.20-1.20.1", null));
remaps.put("1.20.3/1.20.4", new Pair<>("1.20.3-1.20.4", null));
remaps.put("1.20.5", new Pair<>("24w09a", null));
}
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;register(ILjava/lang/String;)Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;"))
private static ProtocolVersion unregisterAndRenameVersions(int version, String name) {
final Pair<String, SubVersionRange> remapEntry = remaps.get(name);
if (remapEntry != null) {
if (remapEntry.key() != null) name = remapEntry.key();
if (remapEntry.value() != null) {
return ProtocolVersion.register(version, name, remapEntry.value());
}
}
return ProtocolVersion.register(version, name);
}
@SuppressWarnings({"UnresolvedMixinReference", "MixinAnnotationTarget", "InvalidInjectorMethodSignature"}) // Optional injection
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;register(IILjava/lang/String;)Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;"), require = 0)
private static ProtocolVersion unregisterAndRenameVersions(int version, int snapshotVersion, String name) {
final Pair<String, SubVersionRange> remapEntry = remaps.get(name);
if (remapEntry != null) {
if (remapEntry.key() != null) name = remapEntry.key();
}
return ProtocolVersion.register(version, snapshotVersion, name);
}
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;register(ILjava/lang/String;Lcom/viaversion/viaversion/api/protocol/version/SubVersionRange;)Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;"))
private static ProtocolVersion unregisterAndRenameVersions(int version, String name, SubVersionRange versionRange) {
final Pair<String, SubVersionRange> remapEntry = remaps.get(name);
if (remapEntry != null) {
if (remapEntry.key() != null) name = remapEntry.key();
if (remapEntry.value() != null) versionRange = remapEntry.value();
}
return ProtocolVersion.register(version, name, versionRange);
}
}

View File

@ -19,6 +19,7 @@ package net.raphimc.viaproxy.protocoltranslator;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.Protocol1_20_5To1_20_3;
import net.raphimc.vialoader.ViaLoader;
import net.raphimc.vialoader.impl.platform.ViaAprilFoolsPlatformImpl;
import net.raphimc.vialoader.impl.platform.ViaBackwardsPlatformImpl;
@ -63,6 +64,7 @@ public class ProtocolTranslator {
patchConfigs();
final Supplier<?>[] platformSuppliers = ViaProxy.EVENT_MANAGER.call(new ProtocolTranslatorInitEvent(ViaBackwardsPlatformImpl::new, ViaRewindPlatformImpl::new, ViaProxyViaLegacyPlatformImpl::new, ViaAprilFoolsPlatformImpl::new, ViaBedrockPlatformImpl::new)).getPlatformSuppliers().toArray(new Supplier[0]);
ViaLoader.init(new ViaProxyViaVersionPlatformImpl(), new ViaProxyVLLoader(), null, null, platformSuppliers);
Protocol1_20_5To1_20_3.strictErrorHandling = false;
ProtocolVersion.register(AUTO_DETECT_PROTOCOL);
}

View File

@ -0,0 +1,63 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2021-2024 RK_01/RaphiMC 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 net.raphimc.viaproxy.protocoltranslator.impl;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import java.util.HashMap;
import java.util.Map;
public class ViaProxyMappingDataLoader extends MappingDataLoader {
public static final Map<String, Material> MATERIALS = new HashMap<>();
public static final Map<String, Map<ProtocolVersion, String>> BLOCK_MATERIALS = new HashMap<>();
public static final ViaProxyMappingDataLoader INSTANCE = new ViaProxyMappingDataLoader();
private ViaProxyMappingDataLoader() {
super(ViaProxyMappingDataLoader.class, "assets/viaproxy/data/");
final JsonObject materialsData = this.loadData("materials-1.19.4.json");
for (Map.Entry<String, JsonElement> entry : materialsData.getAsJsonObject("materials").entrySet()) {
final JsonObject materialData = entry.getValue().getAsJsonObject();
MATERIALS.put(entry.getKey(), new Material(
materialData.get("blocksMovement").getAsBoolean(),
materialData.get("burnable").getAsBoolean(),
materialData.get("liquid").getAsBoolean(),
materialData.get("blocksLight").getAsBoolean(),
materialData.get("replaceable").getAsBoolean(),
materialData.get("solid").getAsBoolean()
));
}
for (Map.Entry<String, JsonElement> blockEntry : materialsData.getAsJsonObject("blocks").entrySet()) {
final Map<ProtocolVersion, String> blockMaterials = new HashMap<>();
for (Map.Entry<String, JsonElement> entry : blockEntry.getValue().getAsJsonObject().entrySet()) {
blockMaterials.put(ProtocolVersion.getClosest(entry.getKey()), entry.getValue().getAsString());
}
BLOCK_MATERIALS.put(blockEntry.getKey(), blockMaterials);
}
}
public record Material(boolean blocksMovement, boolean burnable, boolean liquid, boolean blocksLight, boolean replaceable, boolean solid) {
}
}

View File

@ -45,6 +45,9 @@ public class ViaProxyVLLoader extends VLLoader {
Via.getManager().getProviders().use(HandItemProvider.class, new ViaProxyHandItemProvider());
Via.getManager().getProviders().use(VersionProvider.class, new ViaProxyVersionProvider());
// ViaBackwards
Via.getManager().getProviders().use(com.viaversion.viabackwards.protocol.protocol1_20_3to1_20_5.provider.TransferProvider.class, new ViaProxyTransferProvider());
// ViaLegacy
Via.getManager().getProviders().use(GameProfileFetcher.class, new ViaProxyGameProfileFetcher());
Via.getManager().getProviders().use(EncryptionProvider.class, new ViaProxyEncryptionProvider());

View File

@ -17,7 +17,9 @@
*/
package net.raphimc.viaproxy.protocoltranslator.providers;
import com.viaversion.viabackwards.protocol.protocol1_20_3to1_20_5.storage.CookieStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import io.netty.channel.Channel;
import net.raphimc.viabedrock.protocol.providers.TransferProvider;
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
import net.raphimc.viaproxy.proxy.util.CloseAndReturn;
@ -25,15 +27,24 @@ import net.raphimc.viaproxy.proxy.util.TransferDataHolder;
import java.net.InetSocketAddress;
public class ViaProxyTransferProvider extends TransferProvider {
public class ViaProxyTransferProvider extends TransferProvider implements com.viaversion.viabackwards.protocol.protocol1_20_3to1_20_5.provider.TransferProvider {
@Override
public void connectToServer(UserConnection user, InetSocketAddress newAddress) {
TransferDataHolder.addTempRedirect(ProxyConnection.fromChannel(user.getChannel()).getC2P(), newAddress);
final Channel channel = ProxyConnection.fromChannel(user.getChannel()).getC2P();
TransferDataHolder.addTempRedirect(channel, newAddress);
if (user.has(CookieStorage.class)) {
TransferDataHolder.addCookieStorage(channel, user.get(CookieStorage.class));
}
try {
ProxyConnection.fromUserConnection(user).kickClient("§aThe server transferred you to another server §7(§e" + newAddress.getHostName() + ":" + newAddress.getPort() + "§7)§a. Please reconnect to ViaProxy.");
} catch (CloseAndReturn ignored) {
}
}
@Override
public void connectToServer(UserConnection user, String host, int port) {
this.connectToServer(user, new InetSocketAddress(host, port));
}
}

View File

@ -18,6 +18,8 @@
package net.raphimc.viaproxy.proxy.client2proxy;
import com.google.common.collect.Lists;
import com.viaversion.viabackwards.protocol.protocol1_20_3to1_20_5.storage.CookieStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
@ -251,6 +253,10 @@ public class Client2ProxyHandler extends SimpleChannelInboundHandler<IPacket> {
this.proxyConnection.getChannel().writeAndFlush(newHandshakePacket).addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE, (ChannelFutureListener) f2 -> {
if (f2.isSuccess()) {
this.proxyConnection.setP2sConnectionState(intendedState.getConnectionState());
final UserConnection userConnection = this.proxyConnection.getUserConnection();
if (userConnection.has(CookieStorage.class) && TransferDataHolder.hasCookieStorage(this.proxyConnection.getC2P())) {
userConnection.get(CookieStorage.class).cookies().putAll(TransferDataHolder.removeCookieStorage(this.proxyConnection.getC2P()).cookies());
}
}
});

View File

@ -23,6 +23,7 @@ import io.netty.channel.ChannelFutureListener;
import net.raphimc.netminecraft.constants.ConnectionState;
import net.raphimc.netminecraft.constants.MCPackets;
import net.raphimc.netminecraft.packet.IPacket;
import net.raphimc.netminecraft.packet.PacketTypes;
import net.raphimc.netminecraft.packet.UnknownPacket;
import net.raphimc.netminecraft.packet.impl.configuration.S2CConfigTransfer1_20_5;
import net.raphimc.viaproxy.ViaProxy;
@ -51,6 +52,7 @@ public class TransferPacketHandler extends PacketHandler {
this.handleTransfer(transfer);
final ByteBuf transferToViaProxy = Unpooled.buffer();
PacketTypes.writeVarInt(transferToViaProxy, this.transferId);
this.createTransferPacket().write(transferToViaProxy);
this.proxyConnection.getC2P().writeAndFlush(transferToViaProxy).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
return false;

View File

@ -17,6 +17,7 @@
*/
package net.raphimc.viaproxy.proxy.util;
import com.viaversion.viabackwards.protocol.protocol1_20_3to1_20_5.storage.CookieStorage;
import io.netty.channel.Channel;
import java.net.InetAddress;
@ -27,21 +28,30 @@ import java.util.concurrent.ConcurrentHashMap;
public class TransferDataHolder {
private static final Map<InetAddress, InetSocketAddress> TEMP_REDIRECTS = new ConcurrentHashMap<>();
private static final Map<InetAddress, CookieStorage> COOKIE_STORAGES = new ConcurrentHashMap<>();
public static void addTempRedirect(final Channel channel, final InetSocketAddress redirect) {
TEMP_REDIRECTS.put(getChannelAddress(channel), redirect);
}
public static void addCookieStorage(final Channel channel, final CookieStorage cookieStorage) {
COOKIE_STORAGES.put(getChannelAddress(channel), cookieStorage);
}
public static InetSocketAddress removeTempRedirect(final Channel channel) {
return TEMP_REDIRECTS.remove(getChannelAddress(channel));
}
public static CookieStorage removeCookieStorage(final Channel channel) {
return COOKIE_STORAGES.remove(getChannelAddress(channel));
}
public static boolean hasTempRedirect(final Channel channel) {
return TEMP_REDIRECTS.containsKey(getChannelAddress(channel));
}
public static InetSocketAddress getTempRedirect(final Channel channel) {
return TEMP_REDIRECTS.get(getChannelAddress(channel));
public static boolean hasCookieStorage(final Channel channel) {
return COOKIE_STORAGES.containsKey(getChannelAddress(channel));
}
private static InetAddress getChannelAddress(final Channel channel) {

View File

@ -38,7 +38,7 @@ public class I18n {
}
try {
for (Map.Entry<Path, byte[]> entry : FileSystemUtil.getFilesInDirectory("assets/language").entrySet()) {
for (Map.Entry<Path, byte[]> entry : FileSystemUtil.getFilesInDirectory("assets/viaproxy/language").entrySet()) {
final Properties properties = new Properties();
properties.load(new InputStreamReader(new ByteArrayInputStream(entry.getValue()), StandardCharsets.UTF_8));
LOCALES.put(entry.getKey().getFileName().toString().replace(".properties", ""), properties);

View File

@ -44,7 +44,7 @@ public class SplashScreen extends JFrame {
contentPane.setOpaque(false);
contentPane.setBackground(new Color(0, 0, 0, 0));
contentPane.setLayout(new BorderLayout());
contentPane.add(new SplashPanel(ImageIO.read(SplashScreen.class.getResourceAsStream("/assets/icons/icon.png"))), BorderLayout.CENTER);
contentPane.add(new SplashPanel(ImageIO.read(SplashScreen.class.getResourceAsStream("/assets/viaproxy/icons/icon.png"))), BorderLayout.CENTER);
contentPane.add(this.progressPanel, BorderLayout.SOUTH);
this.setContentPane(contentPane);
}

View File

@ -84,7 +84,7 @@ public class ViaProxyWindow extends JFrame {
}
private void loadIcons() {
this.icon = new ImageIcon(this.getClass().getClassLoader().getResource("assets/icons/icon.png"));
this.icon = new ImageIcon(this.getClass().getClassLoader().getResource("assets/viaproxy/icons/icon.png"));
}
private void initWindow() {

View File

@ -0,0 +1,232 @@
{
"minecraft:wooden_axe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 3.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:stone_axe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 4.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:iron_axe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 5.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:golden_axe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 3.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:diamond_axe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 6.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:wooden_pickaxe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 2.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:stone_pickaxe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 3.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:iron_pickaxe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 4.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:golden_pickaxe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 2.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:diamond_pickaxe": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 5.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:wooden_shovel": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 1.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:stone_shovel": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 2.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:iron_shovel": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 3.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:golden_shovel": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 1.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:diamond_shovel": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Tool modifier",
"amount": 4.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:wooden_sword": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Weapon modifier",
"amount": 4.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:stone_sword": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Weapon modifier",
"amount": 5.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:iron_sword": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Weapon modifier",
"amount": 6.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:golden_sword": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Weapon modifier",
"amount": 4.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:diamond_sword": {
"generic.attackDamage": {
"id": "CB3F55D3-645C-4F38-A497-9C13A33DB5CF",
"name": "Weapon modifier",
"amount": 7.0,
"operation": 0,
"slot": "mainhand"
}
},
"minecraft:wooden_hoe": {
},
"minecraft:stone_hoe": {
},
"minecraft:iron_hoe": {
},
"minecraft:golden_hoe": {
},
"minecraft:diamond_hoe": {
},
"minecraft:leather_boots": {
},
"minecraft:leather_leggings": {
},
"minecraft:leather_chestplate": {
},
"minecraft:leather_helmet": {
},
"minecraft:chainmail_boots": {
},
"minecraft:chainmail_leggings": {
},
"minecraft:chainmail_chestplate": {
},
"minecraft:chainmail_helmet": {
},
"minecraft:iron_boots": {
},
"minecraft:iron_leggings": {
},
"minecraft:iron_chestplate": {
},
"minecraft:iron_helmet": {
},
"minecraft:golden_boots": {
},
"minecraft:golden_leggings": {
},
"minecraft:golden_chestplate": {
},
"minecraft:golden_helmet": {
},
"minecraft:diamond_boots": {
},
"minecraft:diamond_leggings": {
},
"minecraft:diamond_chestplate": {
},
"minecraft:diamond_helmet": {
}
}

View File

@ -0,0 +1,47 @@
{
"minecraft:wooden_axe": 271,
"minecraft:stone_axe": 275,
"minecraft:iron_axe": 258,
"minecraft:golden_axe": 286,
"minecraft:diamond_axe": 279,
"minecraft:wooden_pickaxe": 270,
"minecraft:stone_pickaxe": 274,
"minecraft:iron_pickaxe": 257,
"minecraft:golden_pickaxe": 285,
"minecraft:diamond_pickaxe": 278,
"minecraft:wooden_shovel": 269,
"minecraft:stone_shovel": 273,
"minecraft:iron_shovel": 256,
"minecraft:golden_shovel": 284,
"minecraft:diamond_shovel": 277,
"minecraft:wooden_sword": 268,
"minecraft:stone_sword": 272,
"minecraft:iron_sword": 267,
"minecraft:golden_sword": 283,
"minecraft:diamond_sword": 276,
"minecraft:wooden_hoe": 290,
"minecraft:stone_hoe": 291,
"minecraft:iron_hoe": 292,
"minecraft:golden_hoe": 294,
"minecraft:diamond_hoe": 293,
"minecraft:leather_boots": 301,
"minecraft:leather_leggings": 300,
"minecraft:leather_chestplate": 299,
"minecraft:leather_helmet": 298,
"minecraft:chainmail_boots": 305,
"minecraft:chainmail_leggings": 304,
"minecraft:chainmail_chestplate": 303,
"minecraft:chainmail_helmet": 302,
"minecraft:iron_boots": 309,
"minecraft:iron_leggings": 308,
"minecraft:iron_chestplate": 307,
"minecraft:iron_helmet": 306,
"minecraft:golden_boots": 317,
"minecraft:golden_leggings": 316,
"minecraft:golden_chestplate": 315,
"minecraft:golden_helmet": 314,
"minecraft:diamond_boots": 313,
"minecraft:diamond_leggings": 312,
"minecraft:diamond_chestplate": 311,
"minecraft:diamond_helmet": 310
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB