ViaVersion/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/ItemRewriter.java

428 lines
15 KiB
Java

/*
* 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.protocol1_9to1_8;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ItemRewriter {
public static final Map<String, Integer> ENTITY_NAME_TO_ID = new HashMap<>();
public static final Map<Integer, String> ENTITY_ID_TO_NAME = new HashMap<>();
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);
static {
/* Entities */
registerEntity(1, "Item");
registerEntity(2, "XPOrb");
registerEntity(7, "ThrownEgg");
registerEntity(8, "LeashKnot");
registerEntity(9, "Painting");
registerEntity(10, "Arrow");
registerEntity(11, "Snowball");
registerEntity(12, "Fireball");
registerEntity(13, "SmallFireball");
registerEntity(14, "ThrownEnderpearl");
registerEntity(15, "EyeOfEnderSignal");
registerEntity(16, "ThrownPotion");
registerEntity(17, "ThrownExpBottle");
registerEntity(18, "ItemFrame");
registerEntity(19, "WitherSkull");
registerEntity(20, "PrimedTnt");
registerEntity(21, "FallingSand");
registerEntity(22, "FireworksRocketEntity");
registerEntity(30, "ArmorStand");
registerEntity(40, "MinecartCommandBlock");
registerEntity(41, "Boat");
registerEntity(42, "MinecartRideable");
registerEntity(43, "MinecartChest");
registerEntity(44, "MinecartFurnace");
registerEntity(45, "MinecartTNT");
registerEntity(46, "MinecartHopper");
registerEntity(47, "MinecartSpawner");
registerEntity(48, "Mob");
registerEntity(49, "Monster");
registerEntity(50, "Creeper");
registerEntity(51, "Skeleton");
registerEntity(52, "Spider");
registerEntity(53, "Giant");
registerEntity(54, "Zombie");
registerEntity(55, "Slime");
registerEntity(56, "Ghast");
registerEntity(57, "PigZombie");
registerEntity(58, "Enderman");
registerEntity(59, "CaveSpider");
registerEntity(60, "Silverfish");
registerEntity(61, "Blaze");
registerEntity(62, "LavaSlime");
registerEntity(63, "EnderDragon");
registerEntity(64, "WitherBoss");
registerEntity(65, "Bat");
registerEntity(66, "Witch");
registerEntity(67, "Endermite");
registerEntity(68, "Guardian");
registerEntity(90, "Pig");
registerEntity(91, "Sheep");
registerEntity(92, "Cow");
registerEntity(93, "Chicken");
registerEntity(94, "Squid");
registerEntity(95, "Wolf");
registerEntity(96, "MushroomCow");
registerEntity(97, "SnowMan");
registerEntity(98, "Ozelot");
registerEntity(99, "VillagerGolem");
registerEntity(100, "EntityHorse");
registerEntity(101, "Rabbit");
registerEntity(120, "Villager");
registerEntity(200, "EnderCrystal");
/* Potions */
registerPotion(-1, "empty");
registerPotion(0, "water");
registerPotion(64, "mundane");
registerPotion(32, "thick");
registerPotion(16, "awkward");
registerPotion(8198, "night_vision");
registerPotion(8262, "long_night_vision");
registerPotion(8206, "invisibility");
registerPotion(8270, "long_invisibility");
registerPotion(8203, "leaping");
registerPotion(8267, "long_leaping");
registerPotion(8235, "strong_leaping");
registerPotion(8195, "fire_resistance");
registerPotion(8259, "long_fire_resistance");
registerPotion(8194, "swiftness");
registerPotion(8258, "long_swiftness");
registerPotion(8226, "strong_swiftness");
registerPotion(8202, "slowness");
registerPotion(8266, "long_slowness");
registerPotion(8205, "water_breathing");
registerPotion(8269, "long_water_breathing");
registerPotion(8261, "healing");
registerPotion(8229, "strong_healing");
registerPotion(8204, "harming");
registerPotion(8236, "strong_harming");
registerPotion(8196, "poison");
registerPotion(8260, "long_poison");
registerPotion(8228, "strong_poison");
registerPotion(8193, "regeneration");
registerPotion(8257, "long_regeneration");
registerPotion(8225, "strong_regeneration");
registerPotion(8201, "strength");
registerPotion(8265, "long_strength");
registerPotion(8233, "strong_strength");
registerPotion(8200, "weakness");
registerPotion(8264, "long_weakness");
}
public static void toServer(Item item) {
if (item != null) {
if (item.identifier() == 383 && item.data() == 0) { // Monster Egg
CompoundTag tag = item.tag();
int data = 0;
if (tag != null && tag.getCompoundTag("EntityTag") != null) {
CompoundTag entityTag = tag.getCompoundTag("EntityTag");
StringTag id = entityTag.getStringTag("id");
if (id != null) {
if (ENTITY_NAME_TO_ID.containsKey(id.getValue()))
data = ENTITY_NAME_TO_ID.get(id.getValue());
}
tag.remove("EntityTag");
}
item.setTag(tag);
item.setData((short) data);
}
if (item.identifier() == 373) { // Potion
CompoundTag tag = item.tag();
int data = 0;
if (tag != null && tag.getStringTag("Potion") != null) {
StringTag potion = tag.getStringTag("Potion");
String potionName = Key.stripMinecraftNamespace(potion.getValue());
if (POTION_NAME_TO_ID.containsKey(potionName)) {
data = POTION_NAME_TO_ID.get(potionName);
}
tag.remove("Potion");
}
item.setTag(tag);
item.setData((short) data);
}
// Splash potion
if (item.identifier() == 438) {
CompoundTag tag = item.tag();
int data = 0;
item.setIdentifier(373); // Potion
if (tag != null && tag.getStringTag("Potion") != null) {
StringTag potion = tag.getStringTag("Potion");
String potionName = Key.stripMinecraftNamespace(potion.getValue());
if (POTION_NAME_TO_ID.containsKey(potionName)) {
data = POTION_NAME_TO_ID.get(potionName) + 8192;
}
tag.remove("Potion");
}
item.setTag(tag);
item.setData((short) data);
}
boolean newItem = item.identifier() >= 198 && item.identifier() <= 212;
newItem |= item.identifier() == 397 && item.data() == 5;
newItem |= item.identifier() >= 432 && item.identifier() <= 448;
if (newItem) { // Replace server-side unknown items
item.setIdentifier(1);
item.setData((short) 0);
}
}
}
public static void rewriteBookToServer(Item item) {
int id = item.identifier();
if (id != 387) {
return;
}
CompoundTag tag = item.tag();
ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
if (pages == null) {
return;
}
for (int i = 0; i < pages.size(); i++) {
StringTag pageTag = pages.get(i);
String value = pageTag.getValue();
if (value.replaceAll(" ", "").isEmpty()) {
value = "\"" + fixBookSpaceChars(value) + "\"";
} else {
value = fixBookSpaceChars(value);
}
pageTag.setValue(value);
}
}
private static String fixBookSpaceChars(String str) {
if (!str.startsWith(" ")) {
return str;
}
// hacky but it works :)
str = "§r" + str;
return str;
}
public static void toClient(Item item) {
if (item != null) {
if (item.identifier() == 383 && item.data() != 0) { // Monster Egg
CompoundTag tag = item.tag();
if (tag == null) {
tag = new CompoundTag();
}
CompoundTag entityTag = new CompoundTag();
String entityName = ENTITY_ID_TO_NAME.get((int) item.data());
if (entityName != null) {
StringTag id = new StringTag(entityName);
entityTag.put("id", id);
tag.put("EntityTag", entityTag);
}
item.setTag(tag);
item.setData((short) 0);
}
if (item.identifier() == 373) { // Potion
CompoundTag tag = item.tag();
if (tag == null) {
tag = new CompoundTag();
}
if (item.data() >= 16384) {
item.setIdentifier(438); // splash id
item.setData((short) (item.data() - 8192));
}
String name = potionNameFromDamage(item.data());
StringTag potion = new StringTag(Key.namespaced(name));
tag.put("Potion", potion);
item.setTag(tag);
item.setData((short) 0);
}
if (item.identifier() == 387) { // WRITTEN_BOOK
CompoundTag tag = item.tag();
if (tag == null) {
tag = new CompoundTag();
}
ListTag<StringTag> pages = tag.getListTag("pages", StringTag.class);
if (pages == null) {
pages = new ListTag<>(Collections.singletonList(new StringTag(Protocol1_9To1_8.fixJson("").toString())));
tag.put("pages", pages);
item.setTag(tag);
return;
}
for (int i = 0; i < pages.size(); i++) {
StringTag page = pages.get(i);
page.setValue(Protocol1_9To1_8.fixJson(page.getValue()).toString());
}
item.setTag(tag);
}
}
}
public static String potionNameFromDamage(short damage) {
String cached = POTION_ID_TO_NAME.get((int) damage);
if (cached != null) {
return cached;
}
if (damage == 0) {
return "water";
}
int effect = damage & 0xF;
int name = damage & 0x3F;
boolean enhanced = (damage & 0x20) > 0;
boolean extended = (damage & 0x40) > 0;
boolean canEnhance = true;
boolean canExtend = true;
String id;
switch (effect) {
case 1:
id = "regeneration";
break;
case 2:
id = "swiftness";
break;
case 3:
id = "fire_resistance";
canEnhance = false;
break;
case 4:
id = "poison";
break;
case 5:
id = "healing";
canExtend = false;
break;
case 6:
id = "night_vision";
canEnhance = false;
break;
case 8:
id = "weakness";
canEnhance = false;
break;
case 9:
id = "strength";
break;
case 10:
id = "slowness";
canEnhance = false;
break;
case 11:
id = "leaping";
break;
case 12:
id = "harming";
canExtend = false;
break;
case 13:
id = "water_breathing";
canEnhance = false;
break;
case 14:
id = "invisibility";
canEnhance = false;
break;
default:
canEnhance = false;
canExtend = false;
switch (name) {
case 0:
id = "mundane";
break;
case 16:
id = "awkward";
break;
case 32:
id = "thick";
break;
default:
id = "empty";
}
}
if (effect > 0) {
if (canEnhance && enhanced) {
id = "strong_" + id;
} else if (canExtend && extended) {
id = "long_" + id;
}
}
return id;
}
public static int getNewEffectID(int oldID) {
if (oldID >= 16384) {
oldID -= 8192;
}
int index = POTION_INDEX.get(oldID);
if (index != -1) {
return index;
}
oldID = POTION_NAME_TO_ID.get(potionNameFromDamage((short) oldID));
return (index = POTION_INDEX.get(oldID)) != -1 ? index : 0;
}
private static void registerEntity(int id, String name) {
ENTITY_ID_TO_NAME.put(id, name);
ENTITY_NAME_TO_ID.put(name, id);
}
private static void registerPotion(int id, String name) {
POTION_INDEX.put(id, POTION_ID_TO_NAME.size());
POTION_ID_TO_NAME.put(id, name);
POTION_NAME_TO_ID.put(name, id);
}
}