mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Fix powder snow and fish buckets (#2437)
This commit is contained in:
parent
20b183ddda
commit
3eb73a5634
6 changed files with 182 additions and 20 deletions
|
@ -26,14 +26,27 @@
|
|||
package org.geysermc.connector.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import org.geysermc.connector.entity.living.AbstractFishEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TropicalFishEntity extends AbstractFishEntity {
|
||||
|
||||
/**
|
||||
* A list of variant numbers that are given special names
|
||||
* The index of the variant in this list is used as part of the locale key
|
||||
*/
|
||||
private static final IntList PREDEFINED_VARIANTS = IntList.of(117506305, 117899265, 185008129, 117441793, 118161664, 65536, 50726144, 67764993, 234882305, 67110144, 117441025, 16778497, 101253888, 50660352, 918529, 235340288, 918273, 67108865, 917504, 459008, 67699456, 67371009);
|
||||
|
||||
private static final List<String> VARIANT_NAMES = ImmutableList.of("kob", "sunstreak", "snooper", "dasher", "brinely", "spotty", "flopper", "stripey", "glitter", "blockfish", "betty", "clayfish");
|
||||
private static final List<String> COLOR_NAMES = ImmutableList.of("white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black");
|
||||
|
||||
public TropicalFishEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
@ -43,11 +56,48 @@ public class TropicalFishEntity extends AbstractFishEntity {
|
|||
if (entityMetadata.getId() == 17) {
|
||||
int varNumber = (int) entityMetadata.getValue();
|
||||
|
||||
metadata.put(EntityData.VARIANT, varNumber & 0xFF); // Shape 0-1
|
||||
metadata.put(EntityData.MARK_VARIANT, (varNumber >> 8) & 0xFF); // Pattern 0-5
|
||||
metadata.put(EntityData.COLOR, (byte) ((varNumber >> 16) & 0xFF)); // Base color 0-15
|
||||
metadata.put(EntityData.COLOR_2, (byte) ((varNumber >> 24) & 0xFF)); // Pattern color 0-15
|
||||
metadata.put(EntityData.VARIANT, getShape(varNumber)); // Shape 0-1
|
||||
metadata.put(EntityData.MARK_VARIANT, getPattern(varNumber)); // Pattern 0-5
|
||||
metadata.put(EntityData.COLOR, getBaseColor(varNumber)); // Base color 0-15
|
||||
metadata.put(EntityData.COLOR_2, getPatternColor(varNumber)); // Pattern color 0-15
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
public static int getShape(int variant) {
|
||||
return Math.min(variant & 0xFF, 1);
|
||||
}
|
||||
|
||||
public static int getPattern(int variant) {
|
||||
return Math.min((variant >> 8) & 0xFF, 5);
|
||||
}
|
||||
|
||||
public static byte getBaseColor(int variant) {
|
||||
byte color = (byte) ((variant >> 16) & 0xFF);
|
||||
if (!(0 <= color && color <= 15)) {
|
||||
return 0;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
public static byte getPatternColor(int variant) {
|
||||
byte color = (byte) ((variant >> 24) & 0xFF);
|
||||
if (!(0 <= color && color <= 15)) {
|
||||
return 0;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
public static String getVariantName(int variant) {
|
||||
int id = 6 * getShape(variant) + getPattern(variant);
|
||||
return VARIANT_NAMES.get(id);
|
||||
}
|
||||
|
||||
public static String getColorName(byte colorId) {
|
||||
return COLOR_NAMES.get(colorId);
|
||||
}
|
||||
|
||||
public static int getPredefinedId(int variant) {
|
||||
return PREDEFINED_VARIANTS.indexOf(variant);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye
|
|||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.*;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
|
||||
|
@ -149,7 +148,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
*/
|
||||
// CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch
|
||||
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
||||
|
||||
// Adjust position for current eye height
|
||||
switch (session.getPose()) {
|
||||
|
@ -210,21 +208,26 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
if (session.getItemMappings().getBoatIds().contains(packet.getItemInHand().getId())) {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}
|
||||
// Check actions, otherwise buckets may be activated when block inventories are accessed
|
||||
else if (session.getItemMappings().getBucketIds().contains(packet.getItemInHand().getId())) {
|
||||
} else if (session.getItemMappings().getBucketIds().contains(packet.getItemInHand().getId())) {
|
||||
// Let the server decide if the bucket item should change, not the client, and revert the changes the client made
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
slotPacket.setSlot(packet.getHotbarSlot());
|
||||
slotPacket.setItem(packet.getItemInHand());
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
// Delay the interaction in case the client doesn't intend to actually use the bucket
|
||||
// See BedrockActionTranslator.java
|
||||
session.setBucketScheduledFuture(session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}, 5, TimeUnit.MILLISECONDS));
|
||||
// Don't send ClientPlayerUseItemPacket for powder snow buckets
|
||||
if (packet.getItemInHand().getId() != session.getItemMappings().getStoredItems().powderSnowBucket().getBedrockId()) {
|
||||
// Special check for crafting tables since clients don't send BLOCK_INTERACT when interacting
|
||||
int blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition());
|
||||
if (session.isSneaking() || blockState != BlockRegistries.JAVA_IDENTIFIERS.get("minecraft:crafting_table")) {
|
||||
// Delay the interaction in case the client doesn't intend to actually use the bucket
|
||||
// See BedrockActionTranslator.java
|
||||
session.setBucketScheduledFuture(session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}, 5, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ public class StoredItemMappings {
|
|||
private final ItemMapping fishingRod;
|
||||
private final ItemMapping lodestoneCompass;
|
||||
private final ItemMapping milkBucket;
|
||||
private final ItemMapping powderSnowBucket;
|
||||
private final ItemMapping egg;
|
||||
private final ItemMapping shield;
|
||||
private final ItemMapping wheat;
|
||||
|
@ -60,6 +61,7 @@ public class StoredItemMappings {
|
|||
this.fishingRod = load(itemMappings, "fishing_rod");
|
||||
this.lodestoneCompass = load(itemMappings, "lodestone_compass");
|
||||
this.milkBucket = load(itemMappings, "milk_bucket");
|
||||
this.powderSnowBucket = load(itemMappings, "powder_snow_bucket");
|
||||
this.egg = load(itemMappings, "egg");
|
||||
this.shield = load(itemMappings, "shield");
|
||||
this.wheat = load(itemMappings, "wheat");
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.connector.network.translators.item.translators.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.geysermc.connector.entity.living.animal.TropicalFishEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ItemRemapper
|
||||
public class TropicalFishBucketTranslator extends NbtItemStackTranslator {
|
||||
|
||||
private static final Style LORE_STYLE = Style.style(NamedTextColor.GRAY, TextDecoration.ITALIC);
|
||||
|
||||
@Override
|
||||
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
|
||||
// Prevent name from appearing as "Bucket of"
|
||||
itemTag.put(new ByteTag("AppendCustomName", (byte) 1));
|
||||
itemTag.put(new StringTag("CustomName", LocaleUtils.getLocaleString("entity.minecraft.tropical_fish", session.getLocale())));
|
||||
// Add Java's client side lore tag
|
||||
Tag bucketVariantTag = itemTag.get("BucketVariantTag");
|
||||
if (bucketVariantTag instanceof IntTag) {
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag == null) {
|
||||
displayTag = new CompoundTag("display");
|
||||
itemTag.put(displayTag);
|
||||
}
|
||||
|
||||
List<Tag> lore = new ArrayList<>();
|
||||
|
||||
int varNumber = ((IntTag) bucketVariantTag).getValue();
|
||||
int predefinedVariantId = TropicalFishEntity.getPredefinedId(varNumber);
|
||||
if (predefinedVariantId != -1) {
|
||||
Component tooltip = Component.translatable("entity.minecraft.tropical_fish.predefined." + predefinedVariantId, LORE_STYLE);
|
||||
lore.add(0, new StringTag("", MessageTranslator.convertMessage(tooltip, session.getLocale())));
|
||||
} else {
|
||||
Component typeTooltip = Component.translatable("entity.minecraft.tropical_fish.type." + TropicalFishEntity.getVariantName(varNumber), LORE_STYLE);
|
||||
lore.add(0, new StringTag("", MessageTranslator.convertMessage(typeTooltip, session.getLocale())));
|
||||
|
||||
byte baseColor = TropicalFishEntity.getBaseColor(varNumber);
|
||||
byte patternColor = TropicalFishEntity.getPatternColor(varNumber);
|
||||
Component colorTooltip = Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(baseColor), LORE_STYLE);
|
||||
if (baseColor != patternColor) {
|
||||
colorTooltip = colorTooltip.append(Component.text(", ", LORE_STYLE))
|
||||
.append(Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(patternColor), LORE_STYLE));
|
||||
}
|
||||
lore.add(1, new StringTag("", MessageTranslator.convertMessage(colorTooltip, session.getLocale())));
|
||||
}
|
||||
|
||||
ListTag loreTag = displayTag.get("Lore");
|
||||
if (loreTag != null) {
|
||||
lore.addAll(loreTag.getValue());
|
||||
}
|
||||
displayTag.put(new ListTag("Lore", lore));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(ItemMapping mapping) {
|
||||
return mapping.getJavaIdentifier().equals("minecraft:tropical_fish_bucket");
|
||||
}
|
||||
}
|
|
@ -32,12 +32,14 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
import org.geysermc.connector.network.translators.sound.BlockSoundInteractionHandler;
|
||||
import org.geysermc.connector.network.translators.sound.SoundHandler;
|
||||
|
||||
@SoundHandler(items = "bucket")
|
||||
@SoundHandler(items = "bucket", ignoreSneakingWhileHolding = true)
|
||||
public class BucketSoundInteractionHandler implements BlockSoundInteractionHandler {
|
||||
|
||||
@Override
|
||||
public void handleInteraction(GeyserSession session, Vector3f position, String identifier) {
|
||||
if (session.getBucketScheduledFuture() == null) return; // No bucket was really interacted with
|
||||
if (session.getBucketScheduledFuture() == null) {
|
||||
return; // No bucket was really interacted with
|
||||
}
|
||||
String handItemIdentifier = session.getPlayerInventory().getItemInHand().getMapping(session).getJavaIdentifier();
|
||||
LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket();
|
||||
soundEventPacket.setPosition(position);
|
||||
|
@ -52,22 +54,31 @@ public class BucketSoundInteractionHandler implements BlockSoundInteractionHandl
|
|||
soundEvent = SoundEvent.BUCKET_FILL_WATER;
|
||||
} else if (identifier.contains("lava[")) {
|
||||
soundEvent = SoundEvent.BUCKET_FILL_LAVA;
|
||||
} else if (identifier.contains("powder_snow")) {
|
||||
soundEvent = SoundEvent.BUCKET_FILL_POWDER_SNOW;
|
||||
}
|
||||
break;
|
||||
case "minecraft:lava_bucket":
|
||||
soundEvent = SoundEvent.BUCKET_EMPTY_LAVA;
|
||||
break;
|
||||
case "minecraft:fish_bucket":
|
||||
case "minecraft:axolotl_bucket":
|
||||
case "minecraft:cod_bucket":
|
||||
case "minecraft:salmon_bucket":
|
||||
case "minecraft:pufferfish_bucket":
|
||||
case "minecraft:tropical_fish_bucket":
|
||||
soundEvent = SoundEvent.BUCKET_EMPTY_FISH;
|
||||
break;
|
||||
case "minecraft:water_bucket":
|
||||
soundEvent = SoundEvent.BUCKET_EMPTY_WATER;
|
||||
break;
|
||||
case "minecraft:powder_snow_bucket":
|
||||
soundEvent = SoundEvent.BUCKET_EMPTY_POWDER_SNOW;
|
||||
break;
|
||||
}
|
||||
if (soundEvent != null) {
|
||||
soundEventPacket.setSound(soundEvent);
|
||||
session.sendUpstreamPacket(soundEventPacket);
|
||||
session.setBucketScheduledFuture(null);
|
||||
}
|
||||
session.setBucketScheduledFuture(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f109d34a343da0ade6132661839b893859680d91
|
||||
Subproject commit 2efdb453e4e76992d63824b5c8b551bebec67b71
|
Loading…
Reference in a new issue