2019-07-29 22:20:48 +00:00
|
|
|
/*
|
2020-01-09 03:05:42 +00:00
|
|
|
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
2019-07-29 22:20:48 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @author GeyserMC
|
|
|
|
* @link https://github.com/GeyserMC/Geyser
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.geysermc.connector.network.translators.item;
|
|
|
|
|
|
|
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
|
|
|
import com.nukkitx.protocol.bedrock.data.ItemData;
|
2019-12-21 17:35:48 +00:00
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
|
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
2019-12-21 17:35:48 +00:00
|
|
|
import org.geysermc.connector.GeyserConnector;
|
2020-03-06 02:00:14 +00:00
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
import org.geysermc.connector.network.session.GeyserSession;
|
|
|
|
import org.geysermc.connector.network.translators.*;
|
2019-10-10 00:11:50 +00:00
|
|
|
import org.geysermc.connector.utils.Toolbox;
|
2020-04-22 21:26:16 +00:00
|
|
|
import org.reflections.Reflections;
|
2019-07-29 22:20:48 +00:00
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
import java.util.*;
|
|
|
|
import java.util.stream.Collectors;
|
2019-07-29 22:20:48 +00:00
|
|
|
|
|
|
|
public class ItemTranslator {
|
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
private Int2ObjectMap<ItemStackTranslator> itemTranslators = new Int2ObjectOpenHashMap();
|
|
|
|
private List<NbtItemStackTranslator> nbtItemTranslators;
|
2019-12-31 03:55:17 +00:00
|
|
|
private Map<String, ItemEntry> javaIdentifierMap = new HashMap<>();
|
2020-04-29 15:58:29 +00:00
|
|
|
|
|
|
|
// Shield ID, used in Entity.java
|
2020-04-25 03:11:28 +00:00
|
|
|
public static final int SHIELD = 829;
|
2020-05-23 21:39:17 +00:00
|
|
|
// Boat ID, used in BedrockInventoryTransactionTranslator.java
|
|
|
|
public static final int BOAT = 333;
|
2019-12-31 03:55:17 +00:00
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
public void init() {
|
|
|
|
Reflections ref = new Reflections("org.geysermc.connector.network.translators.item");
|
|
|
|
|
|
|
|
Map<NbtItemStackTranslator, Integer> loadedNbtItemTranslators = new HashMap<>();
|
|
|
|
for (Class<?> clazz : ref.getTypesAnnotatedWith(ItemRemapper.class)) {
|
|
|
|
int priority = clazz.getAnnotation(ItemRemapper.class).priority();
|
|
|
|
|
|
|
|
GeyserConnector.getInstance().getLogger().debug("Found annotated item translator: " + clazz.getCanonicalName());
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (NbtItemStackTranslator.class.isAssignableFrom(clazz)) {
|
|
|
|
NbtItemStackTranslator nbtItemTranslator = (NbtItemStackTranslator) clazz.newInstance();
|
|
|
|
loadedNbtItemTranslators.put(nbtItemTranslator, priority);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ItemStackTranslator itemStackTranslator = (ItemStackTranslator) clazz.newInstance();
|
|
|
|
List<ItemEntry> appliedItems = itemStackTranslator.getAppliedItems();
|
|
|
|
for (ItemEntry item : appliedItems) {
|
|
|
|
ItemStackTranslator registered = itemTranslators.get(item.getJavaId());
|
|
|
|
if (registered != null) {
|
|
|
|
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "." +
|
|
|
|
" Item translator " + registered.getClass().getCanonicalName() + " is already registered for the item " + item.getJavaIdentifier());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
itemTranslators.put(item.getJavaId(), itemStackTranslator);
|
|
|
|
}
|
|
|
|
} catch (InstantiationException | IllegalAccessException e) {
|
|
|
|
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + ".");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nbtItemTranslators = loadedNbtItemTranslators.keySet().stream()
|
|
|
|
.sorted(Comparator.comparingInt(value -> loadedNbtItemTranslators.get(value))).collect(Collectors.toList());
|
|
|
|
}
|
|
|
|
|
|
|
|
public ItemStack translateToJava(GeyserSession session, ItemData data) {
|
|
|
|
if (data == null) {
|
|
|
|
return new ItemStack(0);
|
|
|
|
}
|
2019-10-10 00:11:50 +00:00
|
|
|
ItemEntry javaItem = getItem(data);
|
2019-07-29 22:20:48 +00:00
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
ItemStack itemStack;
|
|
|
|
ItemStackTranslator itemStackTranslator = itemTranslators.get(javaItem.getJavaId());
|
|
|
|
if (itemStackTranslator != null) {
|
|
|
|
itemStack = itemStackTranslator.translateToJava(data, javaItem);
|
|
|
|
} else {
|
|
|
|
itemStack = DEFAULT_TRANSLATOR.translateToJava(data, javaItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itemStack != null && itemStack.getNbt() != null) {
|
|
|
|
for (NbtItemStackTranslator translator : nbtItemTranslators) {
|
|
|
|
if (translator.acceptItem(javaItem)) {
|
|
|
|
translator.translateToJava(itemStack.getNbt(), javaItem);
|
|
|
|
}
|
2019-12-03 00:53:46 +00:00
|
|
|
}
|
2019-08-04 22:23:19 +00:00
|
|
|
}
|
2020-04-22 21:26:16 +00:00
|
|
|
return itemStack;
|
2019-07-29 22:20:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
public ItemData translateToBedrock(GeyserSession session, ItemStack stack) {
|
2019-07-29 22:20:48 +00:00
|
|
|
if (stack == null) {
|
2020-01-31 01:05:57 +00:00
|
|
|
return ItemData.AIR;
|
2019-07-29 22:20:48 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 00:11:50 +00:00
|
|
|
ItemEntry bedrockItem = getItem(stack);
|
2020-04-22 21:26:16 +00:00
|
|
|
|
2020-04-29 15:58:29 +00:00
|
|
|
ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() != null ? stack.getNbt().clone() : null);
|
|
|
|
|
|
|
|
if (itemStack.getNbt() != null) {
|
2020-04-22 21:26:16 +00:00
|
|
|
for (NbtItemStackTranslator translator : nbtItemTranslators) {
|
|
|
|
if (translator.acceptItem(bedrockItem)) {
|
2020-04-29 15:58:29 +00:00
|
|
|
translator.translateToBedrock(itemStack.getNbt(), bedrockItem);
|
2019-12-02 09:48:27 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-04 22:23:19 +00:00
|
|
|
}
|
2020-04-04 20:23:02 +00:00
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
ItemStackTranslator itemStackTranslator = itemTranslators.get(bedrockItem.getJavaId());
|
|
|
|
if (itemStackTranslator != null) {
|
2020-04-29 15:58:29 +00:00
|
|
|
return itemStackTranslator.translateToBedrock(itemStack, bedrockItem);
|
2020-04-22 21:26:16 +00:00
|
|
|
} else {
|
2020-04-29 15:58:29 +00:00
|
|
|
return DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
2020-04-12 00:45:31 +00:00
|
|
|
}
|
2019-07-29 22:20:48 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 00:11:50 +00:00
|
|
|
public ItemEntry getItem(ItemStack stack) {
|
2019-10-16 03:21:44 +00:00
|
|
|
return Toolbox.ITEM_ENTRIES.get(stack.getId());
|
2019-07-29 22:20:48 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 00:11:50 +00:00
|
|
|
public ItemEntry getItem(ItemData data) {
|
2019-11-30 19:26:51 +00:00
|
|
|
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
2019-12-02 09:48:27 +00:00
|
|
|
if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) {
|
2019-10-10 00:11:50 +00:00
|
|
|
return itemEntry;
|
|
|
|
}
|
2019-07-31 19:59:23 +00:00
|
|
|
}
|
2020-04-15 19:24:57 +00:00
|
|
|
// If item find was unsuccessful first time, we try again while ignoring damage
|
|
|
|
// Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory
|
|
|
|
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
|
|
|
if (itemEntry.getBedrockId() == data.getId()) {
|
|
|
|
return itemEntry;
|
|
|
|
}
|
|
|
|
}
|
2019-07-29 22:20:48 +00:00
|
|
|
|
2019-12-21 17:35:48 +00:00
|
|
|
GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage());
|
2019-10-10 00:11:50 +00:00
|
|
|
return ItemEntry.AIR;
|
2019-07-29 22:20:48 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 03:55:17 +00:00
|
|
|
public ItemEntry getItemEntry(String javaIdentifier) {
|
|
|
|
return javaIdentifierMap.computeIfAbsent(javaIdentifier, key -> Toolbox.ITEM_ENTRIES.values()
|
|
|
|
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
|
|
|
}
|
|
|
|
|
2020-04-22 21:26:16 +00:00
|
|
|
private static final ItemStackTranslator DEFAULT_TRANSLATOR = new ItemStackTranslator() {
|
|
|
|
@Override
|
|
|
|
public List<ItemEntry> getAppliedItems() {
|
|
|
|
return null;
|
2019-07-29 22:20:48 +00:00
|
|
|
}
|
2020-04-22 21:26:16 +00:00
|
|
|
};
|
2019-07-29 22:20:48 +00:00
|
|
|
}
|