Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ public enum FireworkExplosionShape {
STAR,
CREEPER,
BURST
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,26 @@
package org.geysermc.geyser.item.type;

import it.unimi.dsi.fastutil.ints.IntArrays;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.item.TooltipOptions;
import org.geysermc.geyser.item.hashing.data.FireworkExplosionShape;
import org.geysermc.geyser.level.FireworkColor;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Fireworks;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class FireworkRocketItem extends Item implements BedrockRequiresTagItem {
public FireworkRocketItem(String javaIdentifier, Builder builder) {
Expand All @@ -50,12 +54,11 @@ public FireworkRocketItem(String javaIdentifier, Builder builder) {

@Override
public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) {
super.translateComponentsToBedrock(session, components, tooltip, builder);

Fireworks fireworks = components.get(DataComponentTypes.FIREWORKS);
if (fireworks == null) {
return;
}
// We still need to translate the explosion so this is still correct, and can be reverse translate in translateNbtToJava.
NbtMapBuilder fireworksNbt = NbtMap.builder();
fireworksNbt.putByte("Flight", (byte) fireworks.getFlightDuration());

Expand All @@ -71,6 +74,49 @@ public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNul
fireworksNbt.put("Explosions", NbtList.EMPTY);
}
builder.putCompound("Fireworks", fireworksNbt.build());

// If the tooltip is hidden, don't add any lore.
if (!tooltip.showInTooltip(DataComponentTypes.FIREWORKS)) {
return;
}

final String locale = session.locale();

// Then we translate everything into lore since the explosion tag and everything is not visible anymore due to this being a data driven item.
List<String> lore = builder.getOrCreateLore();
lore.add(MessageTranslator.convertMessageForTooltip(Component.translatable("item.minecraft.firework_rocket.flight"), locale) + " " + fireworks.getFlightDuration());

for (Fireworks.FireworkExplosion explosion : explosions) {
lore.add(" " + MessageTranslator.convertMessageForTooltip(Component.translatable("item.minecraft.firework_star.shape." + FireworkExplosionShape.values()[explosion.getShapeId()].name().toLowerCase(Locale.ROOT)), locale));

final StringBuilder colorBuilder = new StringBuilder(" ");
for (int color : explosion.getColors()) {
FireworkColor fireworkColor = FireworkColor.values()[FireworkColor.fromJavaRGB(color)];
colorBuilder.append(MessageTranslator.convertMessageForTooltip(Component.translatable("item.minecraft.firework_star." + fireworkColor.name().toLowerCase(Locale.ROOT)), locale));
colorBuilder.append(" ");
}
if (explosion.getColors().length != 0) {
lore.add(MessageTranslator.convertMessageForTooltip(Component.translatable(colorBuilder.toString()), locale));
}

final StringBuilder fadeColorBuilder = new StringBuilder();
for (int color : explosion.getFadeColors()) {
FireworkColor fireworkColor = FireworkColor.values()[FireworkColor.fromJavaRGB(color)];
fadeColorBuilder.append(MessageTranslator.convertMessageForTooltip(Component.translatable("item.minecraft.firework_star." + fireworkColor.name().toLowerCase(Locale.ROOT)), locale));
fadeColorBuilder.append(" ");
}
if (explosion.getFadeColors().length != 0) {
lore.add(" " + MessageTranslator.convertMessageForTooltip(Component.translatable("item.minecraft.firework_star.fade_to"), locale) + " " + fadeColorBuilder);
}

if (explosion.isHasTrail()) {
lore.add(" " + MessageTranslator.convertMessageForTooltip(Component.translatable("item.minecraft.firework_star.trail"), locale));
}

if (explosion.isHasTwinkle()) {
lore.add(" " + MessageTranslator.convertMessageForTooltip(Component.translatable("item.minecraft.firework_star.flicker"), locale));
}
}
}

@Override
Expand All @@ -79,6 +125,11 @@ public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap b

NbtMap fireworksTag = bedrockTag.getCompound("Fireworks");
if (!fireworksTag.isEmpty()) {
int flightDuration = 1;
if (fireworksTag.containsKey("Flight")) {
flightDuration = fireworksTag.getByte("Flight");
}

List<NbtMap> explosions = fireworksTag.getList("Explosions", NbtType.COMPOUND);
if (!explosions.isEmpty()) {
List<Fireworks.FireworkExplosion> javaExplosions = new ArrayList<>();
Expand All @@ -88,7 +139,9 @@ public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap b
javaExplosions.add(javaExplosion);
}
}
components.put(DataComponentTypes.FIREWORKS, new Fireworks(1, javaExplosions));
components.put(DataComponentTypes.FIREWORKS, new Fireworks(flightDuration, javaExplosions));
} else {
components.put(DataComponentTypes.FIREWORKS, new Fireworks(flightDuration, List.of()));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,4 @@ public static int fromBedrockId(int id) {

return WHITE.color.value();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import org.geysermc.geyser.inventory.item.StoredItemMappings;
import org.geysermc.geyser.item.GeyserCustomMappingData;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.TooltipOptions;
import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.level.block.property.Properties;
Expand All @@ -80,6 +81,8 @@
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.registry.type.NonVanillaItemRegistration;
import org.geysermc.geyser.registry.type.PaletteItem;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;

import java.io.InputStream;
import java.util.ArrayList;
Expand Down Expand Up @@ -216,6 +219,20 @@ public static void populate() {
}

ItemDefinition definition = new SimpleItemDefinition(entry.getName().intern(), id, ItemVersion.from(entry.getVersion()), entry.isComponentBased(), components);

// Some item on Bedrock Edition have a different stack size, so we're changing that through the component.
// This resolve https://github.com/GeyserMC/Geyser/issues/5612 and https://github.com/GeyserMC/Geyser/issues/4905
if (definition.getIdentifier().equals("minecraft:cake")) {
definition = new SimpleItemDefinition(entry.getName().intern(), id, ItemVersion.from(entry.getVersion()), true, fromItemDefinitionToDataDriven(definition, 1, null, null));
} else if (definition.getIdentifier().equals("minecraft:armor_stand")) {
// You have to change the item version to data driven for armor stand else this won't work.
definition = new SimpleItemDefinition(entry.getName().intern(), id, ItemVersion.DATA_DRIVEN, true, fromItemDefinitionToDataDriven(definition, 16, "armor_stand", "item.armor_stand.name"));
} else if (definition.getIdentifier().equals("minecraft:firework_rocket")) {
// For fireworks rocket, we purposely make this item data driven so now bedrock won't do client-sided boosting
// and now we can control fireworks boost ourselves! This resolve https://github.com/GeyserMC/Geyser/issues/5409
definition = new SimpleItemDefinition(entry.getName().intern(), id, ItemVersion.DATA_DRIVEN, true, fromItemDefinitionToDataDriven(definition, 64, "fireworks", "item.fireworks.name"));
}

definitions.put(entry.getName(), definition);
registry.put(definition.getRuntimeId(), definition);
}
Expand Down Expand Up @@ -725,4 +742,33 @@ private static NbtMap registerFurnaceMinecart(int nextFreeBedrockId) {
builder.putCompound("components", componentBuilder.build());
return builder.build();
}

private static NbtMap fromItemDefinitionToDataDriven(ItemDefinition definition, int maxStackSize, String texture, String displayName) {
NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", definition.getIdentifier()).putInt("id", definition.getRuntimeId());

NbtMapBuilder itemProperties = NbtMap.builder();

NbtMapBuilder componentBuilder = NbtMap.builder();

if (texture != null) {
NbtMap iconMap = NbtMap.builder()
.putCompound("textures", NbtMap.builder()
.putString("default", texture)
.build())
.build();
itemProperties.putCompound("minecraft:icon", iconMap);
}

if (displayName != null) {
componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", displayName).build());
}

itemProperties.putBoolean("allow_off_hand", true);
itemProperties.putInt("max_stack_size", maxStackSize);

componentBuilder.putCompound("item_properties", itemProperties.build());
builder.putCompound("components", componentBuilder.build());
return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType;
import org.cloudburstmc.protocol.bedrock.data.definitions.DimensionDefinition;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.CraftingRecipeData;
import org.cloudburstmc.protocol.bedrock.packet.AvailableEntityIdentifiersPacket;
Expand Down Expand Up @@ -148,6 +149,7 @@
import org.geysermc.geyser.inventory.recipe.GeyserSmithingRecipe;
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.TooltipOptions;
import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.level.BedrockDimension;
import org.geysermc.geyser.level.JavaDimension;
Expand Down Expand Up @@ -185,6 +187,7 @@
import org.geysermc.geyser.session.dialog.DialogManager;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.EntityUtils;
Expand All @@ -208,6 +211,7 @@
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.HandPreference;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.setting.ChatVisibility;
import org.geysermc.mcprotocollib.protocol.data.game.setting.ParticleStatus;
import org.geysermc.mcprotocollib.protocol.data.game.setting.SkinPart;
Expand All @@ -229,6 +233,7 @@
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -843,8 +848,38 @@ public void connect() {
cameraPresetsPacket.getPresets().addAll(CameraDefinitions.CAMERA_PRESETS);
upstream.sendPacket(cameraPresetsPacket);

// Since the fireworks tag now won't show up due to this is being a data driven item, we have to translate it to lore ourselves
// so the item data can show up in the creative menu. Also doing it here so that we know what locale player choose and translate it properly.

final List<CreativeItemData> creativeItemList = new ArrayList<>();

for (CreativeItemData data : this.itemMappings.getCreativeItems()) {
if (!data.getItem().getDefinition().getIdentifier().equals("minecraft:firework_rocket")) {
creativeItemList.add(data);
continue;
}

NbtMap tag = null;
if (data.getItem().getTag() != null) {
final DataComponents components = new DataComponents(new HashMap<>());
Items.FIREWORK_ROCKET.translateNbtToJava(this, data.getItem().getTag(), components, this.getItemMappings().getMapping(Items.FIREWORK_ROCKET));
final BedrockItemBuilder builder = new BedrockItemBuilder();
Items.FIREWORK_ROCKET.translateComponentsToBedrock(this, components, TooltipOptions.ALL_SHOWN, builder);

tag = builder.build();
}

creativeItemList.add(new CreativeItemData(ItemData.builder()
.usingNetId(true)
.netId(data.getItem().getNetId())
.definition(data.getItem().getDefinition())
.tag(tag)
.count(data.getItem().getCount())
.build(), data.getNetId(), data.getGroupId()));
}

CreativeContentPacket creativePacket = new CreativeContentPacket();
creativePacket.getContents().addAll(this.itemMappings.getCreativeItems());
creativePacket.getContents().addAll(creativeItemList);
creativePacket.getGroups().addAll(this.itemMappings.getCreativeItemGroups());
upstream.sendPacket(creativePacket);

Expand Down