Skip to content

Commit

Permalink
Goat horns and item cooldowns for 1.21.2 (#5102)
Browse files Browse the repository at this point in the history

Co-authored-by: Camotoy <[email protected]>
  • Loading branch information
eclipseisoffline and Camotoy authored Oct 31, 2024
1 parent 4588f34 commit 6cc2aa3
Show file tree
Hide file tree
Showing 19 changed files with 320 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* 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.geyser.inventory.item;

import net.kyori.adventure.key.Key;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.MinecraftKey;
import org.geysermc.geyser.util.SoundUtils;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument;
import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound;

import java.util.Locale;

public interface GeyserInstrument {

static GeyserInstrument read(RegistryEntryContext context) {
NbtMap data = context.data();
String soundEvent = SoundUtils.readSoundEvent(data, "instrument " + context.id());
float range = data.getFloat("range");
String description = MessageTranslator.deserializeDescriptionForTooltip(context.session(), data);
BedrockInstrument bedrockInstrument = BedrockInstrument.getByJavaIdentifier(context.id());
return new GeyserInstrument.Impl(soundEvent, range, description, bedrockInstrument);
}

String soundEvent();

float range();

/**
* In Bedrock format
*/
String description();

BedrockInstrument bedrockInstrument();

/**
* @return the ID of the Bedrock counterpart for this instrument. If there is none ({@link #bedrockInstrument()} is null), then -1 is returned.
*/
default int bedrockId() {
BedrockInstrument bedrockInstrument = bedrockInstrument();
if (bedrockInstrument != null) {
return bedrockInstrument.ordinal();
}
return -1;
}

/**
* @return the ID of the Java counterpart for the given Bedrock ID. If an invalid Bedrock ID was given, or there is no counterpart, -1 is returned.
*/
static int bedrockIdToJava(GeyserSession session, int id) {
JavaRegistry<GeyserInstrument> instruments = session.getRegistryCache().instruments();
BedrockInstrument bedrockInstrument = BedrockInstrument.getByBedrockId(id);
if (bedrockInstrument != null) {
for (int i = 0; i < instruments.values().size(); i++) {
GeyserInstrument instrument = instruments.byId(i);
if (instrument.bedrockInstrument() == bedrockInstrument) {
return i;
}
}
}
return -1;
}

static GeyserInstrument fromHolder(GeyserSession session, Holder<Instrument> holder) {
if (holder.isId()) {
return session.getRegistryCache().instruments().byId(holder.id());
}
Instrument custom = holder.custom();
return new Wrapper(custom, session.locale());
}

record Wrapper(Instrument instrument, String locale) implements GeyserInstrument {
@Override
public String soundEvent() {
return instrument.getSoundEvent().getName();
}

@Override
public float range() {
return instrument.getRange();
}

@Override
public String description() {
return MessageTranslator.convertMessageForTooltip(instrument.getDescription(), locale);
}

@Override
public BedrockInstrument bedrockInstrument() {
if (instrument.getSoundEvent() instanceof BuiltinSound) {
return BedrockInstrument.getByJavaIdentifier(MinecraftKey.key(instrument.getSoundEvent().getName()));
}
// Probably custom
return null;
}
}

record Impl(String soundEvent, float range, String description, @Nullable BedrockInstrument bedrockInstrument) implements GeyserInstrument {
}

/**
* Each vanilla instrument on Bedrock, ordered in their network IDs.
*/
enum BedrockInstrument {
PONDER,
SING,
SEEK,
FEEL,
ADMIRE,
CALL,
YEARN,
DREAM;

private static final BedrockInstrument[] VALUES = values();
private final Key javaIdentifier;

BedrockInstrument() {
this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ENGLISH) + "_goat_horn");
}

public static @Nullable BedrockInstrument getByJavaIdentifier(Key javaIdentifier) {
for (BedrockInstrument instrument : VALUES) {
if (instrument.javaIdentifier.equals(javaIdentifier)) {
return instrument;
}
}
return null;
}

public static @Nullable BedrockInstrument getByBedrockId(int bedrockId) {
if (bedrockId >= 0 && bedrockId < VALUES.length) {
return VALUES[bedrockId];
}
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
import java.util.Set;

/**
* @param description only populated if {@link #bedrockEnchantment()} is not null.
* @param description only populated if {@link #bedrockEnchantment()} is null.
* @param anvilCost also as a rarity multiplier
*/
public record Enchantment(String identifier,
Expand All @@ -66,8 +66,6 @@ public static Enchantment read(RegistryEntryContext context) {

BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(context.id().asString());

// TODO - description is a component. So if a hardcoded literal string is given, this will display normally on Java,
// but Geyser will attempt to lookup the literal string as translation - and will fail, displaying an empty string as enchantment name.
String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(context.session(), data) : null;

return new Enchantment(context.id().asString(), effects, supportedItems, maxLevel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;

Expand All @@ -41,9 +42,9 @@ public ArrowItem(String javaIdentifier, Builder builder) {
}

@Override
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
Potion potion = Potion.getByTippedArrowDamage(itemData.getDamage());
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings);
if (potion != null) {
itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents());
PotionContents contents = potion.toComponent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public CompassItem(String javaIdentifier, Builder builder) {
}

@Override
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
if (isLodestoneCompass(components)) {
return super.translateToBedrock(count, components, mappings.getLodestoneCompass(), mappings);
return super.translateToBedrock(session, count, components, mappings.getLodestoneCompass(), mappings);
}
return super.translateToBedrock(count, components, mapping, mappings);
return super.translateToBedrock(session, count, components, mapping, mappings);
}

@Override
Expand Down Expand Up @@ -78,12 +78,12 @@ private boolean isLodestoneCompass(@Nullable DataComponents components) {
}

@Override
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
if (mapping.getBedrockIdentifier().equals("minecraft:lodestone_compass")) {
// Revert the entry back to the compass
mapping = mappings.getStoredItems().compass();
}

return super.translateToJava(itemData, mapping, mappings);
return super.translateToJava(session, itemData, mapping, mappings);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;

Expand All @@ -37,8 +38,8 @@ public FilledMapItem(String javaIdentifier, Builder builder) {
}

@Override
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
ItemData.Builder builder = super.translateToBedrock(count, components, mapping, mappings);
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
ItemData.Builder builder = super.translateToBedrock(session, count, components, mapping, mappings);
if (components == null) {
// This is a fallback for maps with no nbt (Change added back in June 2020; is it needed in 2023?)
//return builder.tag(NbtMap.builder().putInt("map", 0).build()); TODO if this is *still* broken, let's move it to translateComponentsToBedrock
Expand Down
40 changes: 32 additions & 8 deletions core/src/main/java/org/geysermc/geyser/item/type/GoatHornItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.item.GeyserInstrument;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
Expand All @@ -41,24 +44,45 @@ public GoatHornItem(String javaIdentifier, Builder builder) {
}

@Override
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
ItemData.Builder builder = super.translateToBedrock(count, components, mapping, mappings);
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
ItemData.Builder builder = super.translateToBedrock(session, count, components, mapping, mappings);
if (components == null) {
return builder;
}
Holder<Instrument> instrument = components.get(DataComponentType.INSTRUMENT);
if (instrument != null && instrument.isId()) {
builder.damage(instrument.id());

Holder<Instrument> holder = components.get(DataComponentType.INSTRUMENT);
if (holder != null) {
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
int bedrockId = instrument.bedrockId();
if (bedrockId >= 0) {
builder.damage(bedrockId);
}
}

return builder;
}

@Override
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
super.translateComponentsToBedrock(session, components, builder);

Holder<Instrument> holder = components.get(DataComponentType.INSTRUMENT);
if (holder != null && components.get(DataComponentType.HIDE_TOOLTIP) == null
&& components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) == null) {
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
if (instrument.bedrockInstrument() == null) {
builder.getOrCreateLore().add(instrument.description());
}
}
}

@Override
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings);

int damage = itemData.getDamage();
itemStack.getOrCreateComponents().put(DataComponentType.INSTRUMENT, Holder.ofId(damage));
// This could cause an issue since -1 is returned for non-vanilla goat horns
itemStack.getOrCreateComponents().put(DataComponentType.INSTRUMENT, Holder.ofId(GeyserInstrument.bedrockIdToJava(session, damage)));

return itemStack;
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/geysermc/geyser/item/type/Item.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public String translationKey() {

/* Translation methods to Bedrock and back */

public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
if (this == Items.AIR || count <= 0) {
// Return, essentially, air
return ItemData.builder();
Expand All @@ -130,7 +130,7 @@ public ItemData.Builder translateToBedrock(int count, DataComponents components,
return builder;
}

public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
return GeyserItemStack.of(javaId, itemData.getCount());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;

Expand All @@ -40,8 +41,8 @@ public OminousBottleItem(String javaIdentifier, Builder builder) {
}

@Override
public ItemData.Builder translateToBedrock(int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) {
var builder = super.translateToBedrock(count, components, mapping, mappings);
public ItemData.Builder translateToBedrock(GeyserSession session, int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) {
var builder = super.translateToBedrock(session, count, components, mapping, mappings);
if (components == null) {
// Level 1 ominous bottle is null components - Java 1.21.
return builder;
Expand All @@ -54,9 +55,9 @@ public ItemData.Builder translateToBedrock(int count, @Nullable DataComponents c
}

@Override
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
// This item can be pulled from the creative inventory with amplifiers.
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings);
int damage = itemData.getDamage();
if (damage == 0) {
return itemStack;
Expand Down
Loading

0 comments on commit 6cc2aa3

Please sign in to comment.