forked from GeyserMC/Geyser
Add more interactive tags (mobile buttons) (#1443)
* Add more interactive tags (mobile buttons) This expands our support for showing the interactive tags on touchscreen and console setups. This is not complete - specifically, the food compatibility of creatures needs to be expanded upon (I will work on this later and does not stop this PR from being mergable). This also includes: - Creepers who are ignited with flint and steel now show up properly - Zombie villagers now shake properly when converting and show their region outfits * Add more food choices and add more panda entity metadata * Re-add eating flag * Remove debug line * Refactor dimension usage, finish interactive tag usage, bees * Print statements... ._. * Don't make eating item packet data a non-constant * Move BAMBOO to ItemRegistry * Add missing break * Make changes * Minor final changes
This commit is contained in:
parent
3676dd185f
commit
e748240a02
28 changed files with 643 additions and 110 deletions
|
@ -103,11 +103,11 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
case "--config":
|
case "--config":
|
||||||
case "-c":
|
case "-c":
|
||||||
if (i >= args.length - 1) {
|
if (i >= args.length - 1) {
|
||||||
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.confignotspecified"), "-c"));
|
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_not_specified"), "-c"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
configFilenameOpt = args[i+1]; i++;
|
configFilenameOpt = args[i+1]; i++;
|
||||||
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.configspecified"), configFilenameOpt));
|
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_specified"), configFilenameOpt));
|
||||||
break;
|
break;
|
||||||
case "--help":
|
case "--help":
|
||||||
case "-h":
|
case "-h":
|
||||||
|
|
|
@ -179,8 +179,7 @@ public class GeyserConnector {
|
||||||
remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort);
|
remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort);
|
||||||
authType = AuthType.getByName(config.getRemote().getAuthType());
|
authType = AuthType.getByName(config.getRemote().getAuthType());
|
||||||
|
|
||||||
if (config.isAboveBedrockNetherBuilding())
|
DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
|
||||||
DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether
|
|
||||||
|
|
||||||
// https://github.com/GeyserMC/Geyser/issues/957
|
// https://github.com/GeyserMC/Geyser/issues/957
|
||||||
RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu();
|
RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu();
|
||||||
|
|
|
@ -67,8 +67,6 @@ public class Entity {
|
||||||
protected long entityId;
|
protected long entityId;
|
||||||
protected long geyserId;
|
protected long geyserId;
|
||||||
|
|
||||||
protected String dimension;
|
|
||||||
|
|
||||||
protected Vector3f position;
|
protected Vector3f position;
|
||||||
protected Vector3f motion;
|
protected Vector3f motion;
|
||||||
|
|
||||||
|
@ -100,7 +98,6 @@ public class Entity {
|
||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
|
|
||||||
this.valid = false;
|
this.valid = false;
|
||||||
this.dimension = "minecraft:overworld";
|
|
||||||
|
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,10 @@ package org.geysermc.connector.entity.living.animal;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -41,10 +44,23 @@ public class BeeEntity extends AnimalEntity {
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
// Bee is performing sting attack; trigger animation
|
||||||
|
if ((xd & 0x02) == 0x02) {
|
||||||
|
EntityEventPacket packet = new EntityEventPacket();
|
||||||
|
packet.setRuntimeEntityId(geyserId);
|
||||||
|
packet.setType(EntityEventType.ATTACK_START);
|
||||||
|
packet.setData(0);
|
||||||
|
session.sendUpstreamPacket(packet);
|
||||||
|
}
|
||||||
|
// If the bee has stung
|
||||||
|
metadata.put(EntityData.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0);
|
||||||
// If the bee has nectar or not
|
// If the bee has nectar or not
|
||||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
|
metadata.getFlags().setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
|
||||||
}
|
}
|
||||||
|
if (entityMetadata.getId() == 17) {
|
||||||
|
// Converting "anger time" to a boolean
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.ANGRY, (int) entityMetadata.getValue() > 0);
|
||||||
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class FoxEntity extends AnimalEntity {
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 17) {
|
if (entityMetadata.getId() == 17) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 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.entity.living.animal;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
|
||||||
|
public class HoglinEntity extends AnimalEntity {
|
||||||
|
|
||||||
|
public HoglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 16) {
|
||||||
|
// Immune to zombification?
|
||||||
|
// Apply shaking effect if not in the nether and zombification is possible
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER));
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,23 +27,75 @@ package org.geysermc.connector.entity.living.animal;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
|
||||||
public class PandaEntity extends AnimalEntity {
|
public class PandaEntity extends AnimalEntity {
|
||||||
|
|
||||||
|
private int mainGene;
|
||||||
|
private int hiddenGene;
|
||||||
|
|
||||||
public PandaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public PandaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 18) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.EATING, (int) entityMetadata.getValue() > 0);
|
||||||
|
metadata.put(EntityData.EATING_COUNTER, entityMetadata.getValue());
|
||||||
|
if ((int) entityMetadata.getValue() != 0) {
|
||||||
|
// Particles and sound
|
||||||
|
EntityEventPacket packet = new EntityEventPacket();
|
||||||
|
packet.setRuntimeEntityId(geyserId);
|
||||||
|
packet.setType(EntityEventType.EATING_ITEM);
|
||||||
|
packet.setData(ItemRegistry.BAMBOO.getBedrockId() << 16);
|
||||||
|
session.sendUpstreamPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entityMetadata.getId() == 19) {
|
||||||
|
mainGene = (int) (byte) entityMetadata.getValue();
|
||||||
|
updateAppearance();
|
||||||
|
}
|
||||||
|
if (entityMetadata.getId() == 20) {
|
||||||
|
hiddenGene = (int) (byte) entityMetadata.getValue();
|
||||||
|
updateAppearance();
|
||||||
|
}
|
||||||
if (entityMetadata.getId() == 21) {
|
if (entityMetadata.getId() == 21) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.SNEEZING, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.SNEEZING, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x04) == 0x04);
|
metadata.getFlags().setFlag(EntityFlag.ROLLING, (xd & 0x04) == 0x04);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x08) == 0x08);
|
||||||
|
// Required to put these both for sitting to actually show
|
||||||
|
metadata.put(EntityData.SITTING_AMOUNT, (xd & 0x08) == 0x08 ? 1f : 0f);
|
||||||
|
metadata.put(EntityData.SITTING_AMOUNT_PREVIOUS, (xd & 0x08) == 0x08 ? 1f : 0f);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.LAYING_DOWN, (xd & 0x10) == 0x10);
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the panda's appearance, and take into consideration the recessive brown and weak traits that only show up
|
||||||
|
* when both main and hidden genes match
|
||||||
|
*/
|
||||||
|
private void updateAppearance() {
|
||||||
|
if (mainGene == 4 || mainGene == 5) {
|
||||||
|
// Main gene is a recessive trait
|
||||||
|
if (mainGene == hiddenGene) {
|
||||||
|
// Main and hidden genes match; this is what the panda looks like.
|
||||||
|
metadata.put(EntityData.VARIANT, mainGene);
|
||||||
|
} else {
|
||||||
|
// Genes have no effect on appearance
|
||||||
|
metadata.put(EntityData.VARIANT, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No need to worry about hidden gene
|
||||||
|
metadata.put(EntityData.VARIANT, mainGene);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ package org.geysermc.connector.entity.living.animal.horse;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ public class HorseEntity extends AbstractHorseEntity {
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 18) {
|
if (entityMetadata.getId() == 18) {
|
||||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||||
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -34,6 +34,8 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class CatEntity extends TameableEntity {
|
public class CatEntity extends TameableEntity {
|
||||||
|
|
||||||
|
private byte collarColor;
|
||||||
|
|
||||||
public CatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public CatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +47,13 @@ public class CatEntity extends TameableEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
if (entityMetadata.getId() == 16) {
|
||||||
|
// Update collar color if tamed
|
||||||
|
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
|
metadata.put(EntityData.COLOR, collarColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (entityMetadata.getId() == 18) {
|
if (entityMetadata.getId() == 18) {
|
||||||
// Different colors in Java and Bedrock for some reason
|
// Different colors in Java and Bedrock for some reason
|
||||||
int variantColor;
|
int variantColor;
|
||||||
|
@ -67,11 +76,11 @@ public class CatEntity extends TameableEntity {
|
||||||
metadata.put(EntityData.VARIANT, variantColor);
|
metadata.put(EntityData.VARIANT, variantColor);
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 21) {
|
if (entityMetadata.getId() == 21) {
|
||||||
|
collarColor = (byte) (int) entityMetadata.getValue();
|
||||||
// Needed or else wild cats are a red color
|
// Needed or else wild cats are a red color
|
||||||
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
|
metadata.put(EntityData.COLOR, collarColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class TameableEntity extends AnimalEntity {
|
public class TameableEntity extends AnimalEntity {
|
||||||
|
|
||||||
public TameableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public TameableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
@ -46,11 +49,22 @@ public class TameableEntity extends AnimalEntity {
|
||||||
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
||||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04);
|
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04);
|
||||||
// Must be set for wolf collar color to work
|
}
|
||||||
// Extending it to all entities to prevent future bugs
|
|
||||||
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
// Note: Must be set for wolf collar color to work
|
||||||
metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId());
|
if (entityMetadata.getId() == 17) {
|
||||||
} // Can't de-tame an entity so no resetting the owner ID
|
if (entityMetadata.getValue() != null) {
|
||||||
|
// Owner UUID of entity
|
||||||
|
Entity entity = session.getEntityCache().getPlayerEntity((UUID) entityMetadata.getValue());
|
||||||
|
// Used as both a check since the player isn't in the entity cache and a normal fallback
|
||||||
|
if (entity == null) {
|
||||||
|
entity = session.getPlayerEntity();
|
||||||
|
}
|
||||||
|
// Translate to entity ID
|
||||||
|
metadata.put(EntityData.OWNER_EID, entity.getGeyserId());
|
||||||
|
} else {
|
||||||
|
metadata.put(EntityData.OWNER_EID, 0L); // Reset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,27 +26,32 @@
|
||||||
package org.geysermc.connector.entity.living.merchant;
|
package org.geysermc.connector.entity.living.merchant;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class VillagerEntity extends AbstractMerchantEntity {
|
public class VillagerEntity extends AbstractMerchantEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of Java profession IDs to Bedrock IDs
|
||||||
|
*/
|
||||||
private static final Int2IntMap VILLAGER_VARIANTS = new Int2IntOpenHashMap();
|
private static final Int2IntMap VILLAGER_VARIANTS = new Int2IntOpenHashMap();
|
||||||
private static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap();
|
/**
|
||||||
|
* A map of all Java region IDs (plains, savanna...) to Bedrock
|
||||||
|
*/
|
||||||
|
public static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Java villager profession IDs -> Bedrock
|
// Java villager profession IDs -> Bedrock
|
||||||
|
|
|
@ -1,11 +1,25 @@
|
||||||
package org.geysermc.connector.entity.living.monster;
|
package org.geysermc.connector.entity.living.monster;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
|
||||||
public class BasePiglinEntity extends MonsterEntity {
|
public class BasePiglinEntity extends MonsterEntity {
|
||||||
|
|
||||||
public BasePiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public BasePiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 15) {
|
||||||
|
// Immune to zombification?
|
||||||
|
// Apply shaking effect if not in the nether and zombification is possible
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER));
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -33,6 +33,12 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class CreeperEntity extends MonsterEntity {
|
public class CreeperEntity extends MonsterEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the creeper has been ignited and is using ID 17.
|
||||||
|
* In this instance we ignore ID 15 since it's sending us -1 which confuses poor Bedrock.
|
||||||
|
*/
|
||||||
|
private boolean ignitedByFlintAndSteel = false;
|
||||||
|
|
||||||
public CreeperEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public CreeperEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
@ -40,13 +46,16 @@ public class CreeperEntity extends MonsterEntity {
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 15) {
|
if (entityMetadata.getId() == 15) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1);
|
if (!ignitedByFlintAndSteel) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue());
|
metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue());
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 17) {
|
if (entityMetadata.getId() == 17) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (boolean) entityMetadata.getValue());
|
ignitedByFlintAndSteel = (boolean) entityMetadata.getValue();
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.IGNITED, ignitedByFlintAndSteel);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class PiglinEntity extends BasePiglinEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 15) {
|
if (entityMetadata.getId() == 16) {
|
||||||
boolean isBaby = (boolean) entityMetadata.getValue();
|
boolean isBaby = (boolean) entityMetadata.getValue();
|
||||||
if (isBaby) {
|
if (isBaby) {
|
||||||
metadata.put(EntityData.SCALE, .55f);
|
metadata.put(EntityData.SCALE, .55f);
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 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.entity.living.monster;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.living.merchant.VillagerEntity;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class ZombieVillagerEntity extends ZombieEntity {
|
||||||
|
|
||||||
|
public ZombieVillagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 18) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.IS_TRANSFORMING, (boolean) entityMetadata.getValue());
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SHAKING, (boolean) entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
if (entityMetadata.getId() == 19) {
|
||||||
|
VillagerData villagerData = (VillagerData) entityMetadata.getValue();
|
||||||
|
// Region - only one used on Bedrock
|
||||||
|
metadata.put(EntityData.MARK_VARIANT, VillagerEntity.VILLAGER_REGIONS.get(villagerData.getType()));
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,7 +77,7 @@ public enum EntityType {
|
||||||
GHAST(GhastEntity.class, 41, 4.0f),
|
GHAST(GhastEntity.class, 41, 4.0f),
|
||||||
MAGMA_CUBE(MagmaCubeEntity.class, 42, 0.51f),
|
MAGMA_CUBE(MagmaCubeEntity.class, 42, 0.51f),
|
||||||
BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f),
|
BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f),
|
||||||
ZOMBIE_VILLAGER(ZombieEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f),
|
ZOMBIE_VILLAGER(ZombieVillagerEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie_villager_v2"),
|
||||||
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
STRAY(AbstractSkeletonEntity.class, 46, 1.8f, 0.6f, 0.6f, 1.62f),
|
STRAY(AbstractSkeletonEntity.class, 46, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
|
@ -153,7 +153,7 @@ public enum EntityType {
|
||||||
FOX(FoxEntity.class, 121, 0.5f, 1.25f),
|
FOX(FoxEntity.class, 121, 0.5f, 1.25f),
|
||||||
BEE(BeeEntity.class, 122, 0.6f, 0.6f),
|
BEE(BeeEntity.class, 122, 0.6f, 0.6f),
|
||||||
STRIDER(StriderEntity.class, 125, 1.7f, 0.9f, 0f, 0f, "minecraft:strider"),
|
STRIDER(StriderEntity.class, 125, 1.7f, 0.9f, 0f, 0f, "minecraft:strider"),
|
||||||
HOGLIN(AnimalEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"),
|
HOGLIN(HoglinEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"),
|
||||||
ZOGLIN(ZoglinEntity.class, 126, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:zoglin"),
|
ZOGLIN(ZoglinEntity.class, 126, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:zoglin"),
|
||||||
PIGLIN(PiglinEntity.class, 123, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin"),
|
PIGLIN(PiglinEntity.class, 123, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin"),
|
||||||
PIGLIN_BRUTE(BasePiglinEntity.class, 127, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin_brute"),
|
PIGLIN_BRUTE(BasePiglinEntity.class, 127, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin_brute"),
|
||||||
|
|
|
@ -146,6 +146,13 @@ public class GeyserSession implements CommandSender {
|
||||||
@Setter
|
@Setter
|
||||||
private boolean jumping;
|
private boolean jumping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dimension of the player.
|
||||||
|
* As all entities are in the same world, this can be safely applied to all other entities.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private String dimension = DimensionUtils.OVERWORLD;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private int breakingBlock;
|
private int breakingBlock;
|
||||||
|
|
||||||
|
@ -629,7 +636,7 @@ public class GeyserSession implements CommandSender {
|
||||||
startGamePacket.setRotation(Vector2f.from(1, 1));
|
startGamePacket.setRotation(Vector2f.from(1, 1));
|
||||||
|
|
||||||
startGamePacket.setSeed(-1);
|
startGamePacket.setSeed(-1);
|
||||||
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(playerEntity.getDimension()));
|
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(dimension));
|
||||||
startGamePacket.setGeneratorId(1);
|
startGamePacket.setGeneratorId(1);
|
||||||
startGamePacket.setLevelGameType(GameType.SURVIVAL);
|
startGamePacket.setLevelGameType(GameType.SURVIVAL);
|
||||||
startGamePacket.setDifficulty(1);
|
startGamePacket.setDifficulty(1);
|
||||||
|
|
|
@ -25,27 +25,65 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||||
|
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
|
||||||
import org.geysermc.connector.entity.Entity;
|
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Translator(packet = InteractPacket.class)
|
@Translator(packet = InteractPacket.class)
|
||||||
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
|
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all foods a horse/donkey can eat on Java Edition.
|
||||||
|
* Used to display interactive tag if needed.
|
||||||
|
*/
|
||||||
|
private static final List<String> DONKEY_AND_HORSE_FOODS = Arrays.asList("golden_apple", "enchanted_golden_apple",
|
||||||
|
"golden_carrot", "sugar", "apple", "wheat", "hay_block");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all flowers. Used for feeding bees.
|
||||||
|
*/
|
||||||
|
private static final List<String> FLOWERS = Arrays.asList("dandelion", "poppy", "blue_orchid", "allium", "azure_bluet",
|
||||||
|
"red_tulip", "pink_tulip", "white_tulip", "orange_tulip", "cornflower", "lily_of_the_valley", "wither_rose",
|
||||||
|
"sunflower", "lilac", "rose_bush", "peony");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All entity types that can be leashed on Java Edition
|
||||||
|
*/
|
||||||
|
private static final List<EntityType> LEASHABLE_MOB_TYPES = Arrays.asList(EntityType.BEE, EntityType.CAT, EntityType.CHICKEN,
|
||||||
|
EntityType.COW, EntityType.DOLPHIN, EntityType.DONKEY, EntityType.FOX, EntityType.HOGLIN, EntityType.HORSE, EntityType.SKELETON_HORSE,
|
||||||
|
EntityType.ZOMBIE_HORSE, EntityType.IRON_GOLEM, EntityType.LLAMA, EntityType.TRADER_LLAMA, EntityType.MOOSHROOM,
|
||||||
|
EntityType.MULE, EntityType.OCELOT, EntityType.PARROT, EntityType.PIG, EntityType.POLAR_BEAR, EntityType.RABBIT,
|
||||||
|
EntityType.SHEEP, EntityType.SNOW_GOLEM, EntityType.STRIDER, EntityType.WOLF, EntityType.ZOGLIN);
|
||||||
|
|
||||||
|
private static final List<EntityType> SADDLEABLE_WHEN_TAMED_MOB_TYPES = Arrays.asList(EntityType.DONKEY, EntityType.HORSE,
|
||||||
|
EntityType.ZOMBIE_HORSE, EntityType.MULE);
|
||||||
|
/**
|
||||||
|
* A list of all foods a wolf can eat on Java Edition.
|
||||||
|
* Used to display interactive tag if needed.
|
||||||
|
*/
|
||||||
|
private static final List<String> WOLF_FOODS = Arrays.asList("pufferfish", "tropical_fish", "chicken", "cooked_chicken",
|
||||||
|
"porkchop", "beef", "rabbit", "cooked_porkchop", "cooked_beef", "rotten_flesh", "mutton", "cooked_mutton",
|
||||||
|
"cooked_rabbit");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(InteractPacket packet, GeyserSession session) {
|
public void translate(InteractPacket packet, GeyserSession session) {
|
||||||
Entity entity;
|
Entity entity;
|
||||||
|
@ -84,50 +122,232 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
||||||
if (interactEntity == null)
|
if (interactEntity == null)
|
||||||
return;
|
return;
|
||||||
EntityDataMap entityMetadata = interactEntity.getMetadata();
|
EntityDataMap entityMetadata = interactEntity.getMetadata();
|
||||||
|
ItemEntry itemEntry = session.getInventory().getItemInHand() == null ? ItemEntry.AIR : ItemRegistry.getItem(session.getInventory().getItemInHand());
|
||||||
|
String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", "");
|
||||||
|
|
||||||
String interactiveTag;
|
// TODO - in the future, update these in the metadata? So the client doesn't have to wiggle their cursor around for it to happen
|
||||||
switch (interactEntity.getEntityType()) {
|
// TODO - also, might be good to abstract out the eating thing. I know there will need to be food tracked for https://github.com/GeyserMC/Geyser/issues/1005 but not all food is breeding food
|
||||||
case BOAT:
|
InteractiveTag interactiveTag = InteractiveTag.NONE;
|
||||||
interactiveTag = "action.interact.ride.boat";
|
if (entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||||
break;
|
// Unleash the entity
|
||||||
case DONKEY:
|
interactiveTag = InteractiveTag.REMOVE_LEASH;
|
||||||
case HORSE:
|
} else if (javaIdentifierStripped.equals("saddle") && !entityMetadata.getFlags().getFlag(EntityFlag.SADDLED) &&
|
||||||
case LLAMA:
|
((SADDLEABLE_WHEN_TAMED_MOB_TYPES.contains(interactEntity.getEntityType()) && entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) ||
|
||||||
case MULE:
|
interactEntity.getEntityType() == EntityType.PIG || interactEntity.getEntityType() == EntityType.STRIDER)) {
|
||||||
case SKELETON_HORSE:
|
// Entity can be saddled and the conditions meet (entity can be saddled and, if needed, is tamed)
|
||||||
case TRADER_LLAMA:
|
interactiveTag = InteractiveTag.SADDLE;
|
||||||
case ZOMBIE_HORSE:
|
} else if (javaIdentifierStripped.equals("name_tag") && session.getInventory().getItemInHand().getNbt() != null &&
|
||||||
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
session.getInventory().getItemInHand().getNbt().contains("display")) {
|
||||||
interactiveTag = "action.interact.ride.horse";
|
// Holding a named name tag
|
||||||
} else {
|
interactiveTag = InteractiveTag.NAME;
|
||||||
interactiveTag = "action.interact.mount";
|
} else if (javaIdentifierStripped.equals("lead") && LEASHABLE_MOB_TYPES.contains(interactEntity.getEntityType()) &&
|
||||||
}
|
entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == -1L) {
|
||||||
break;
|
// Holding a leash and the mob is leashable for sure
|
||||||
case MINECART:
|
// (Plugins can change this behavior so that's something to look into in the far far future)
|
||||||
interactiveTag = "action.interact.ride.minecart";
|
interactiveTag = InteractiveTag.LEASH;
|
||||||
break;
|
} else {
|
||||||
case PIG:
|
switch (interactEntity.getEntityType()) {
|
||||||
if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
case BEE:
|
||||||
interactiveTag = "action.interact.mount";
|
if (FLOWERS.contains(javaIdentifierStripped)) {
|
||||||
} else interactiveTag = "";
|
interactiveTag = InteractiveTag.FEED;
|
||||||
break;
|
}
|
||||||
case VILLAGER:
|
break;
|
||||||
if (entityMetadata.getInt(EntityData.VARIANT) != 14 && entityMetadata.getInt(EntityData.VARIANT) != 0
|
case BOAT:
|
||||||
&& entityMetadata.getFloat(EntityData.SCALE) >= 0.75f) { // Not a nitwit, has a profession and is not a baby
|
interactiveTag = InteractiveTag.BOARD_BOAT;
|
||||||
interactiveTag = "action.interact.trade";
|
break;
|
||||||
} else interactiveTag = "";
|
case CAT:
|
||||||
break;
|
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||||
case WANDERING_TRADER:
|
interactiveTag = InteractiveTag.FEED;
|
||||||
interactiveTag = "action.interact.trade"; // Since you can always trade with a wandering villager, presumably.
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||||
break;
|
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||||
default:
|
// Tamed and owned by player - can sit/stand
|
||||||
return; // No need to process any further since there is no interactive tag
|
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHICKEN:
|
||||||
|
if (javaIdentifierStripped.contains("seeds")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOOSHROOM:
|
||||||
|
// Shear the mooshroom
|
||||||
|
if (javaIdentifierStripped.equals("shears")) {
|
||||||
|
interactiveTag = InteractiveTag.MOOSHROOM_SHEAR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Bowls are acceptable here
|
||||||
|
else if (javaIdentifierStripped.equals("bowl")) {
|
||||||
|
interactiveTag = InteractiveTag.MOOSHROOM_MILK_STEW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Fall down to COW as this works on mooshrooms
|
||||||
|
case COW:
|
||||||
|
if (javaIdentifierStripped.equals("wheat")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (javaIdentifierStripped.equals("bucket")) {
|
||||||
|
// Milk the cow
|
||||||
|
interactiveTag = InteractiveTag.MILK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CREEPER:
|
||||||
|
if (javaIdentifierStripped.equals("flint_and_steel")) {
|
||||||
|
// Today I learned that you can ignite a creeper with flint and steel! Huh.
|
||||||
|
interactiveTag = InteractiveTag.IGNITE_CREEPER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DONKEY:
|
||||||
|
case LLAMA:
|
||||||
|
case MULE:
|
||||||
|
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && !entityMetadata.getFlags().getFlag(EntityFlag.CHESTED)
|
||||||
|
&& javaIdentifierStripped.equals("chest")) {
|
||||||
|
// Can attach a chest
|
||||||
|
interactiveTag = InteractiveTag.ATTACH_CHEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Intentional fall-through
|
||||||
|
case HORSE:
|
||||||
|
case SKELETON_HORSE:
|
||||||
|
case TRADER_LLAMA:
|
||||||
|
case ZOMBIE_HORSE:
|
||||||
|
// have another switch statement as, while these share mount attributes they don't share food
|
||||||
|
switch (interactEntity.getEntityType()) {
|
||||||
|
case LLAMA:
|
||||||
|
case TRADER_LLAMA:
|
||||||
|
if (javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DONKEY:
|
||||||
|
case HORSE:
|
||||||
|
// Undead can't eat
|
||||||
|
if (DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped)) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY)) {
|
||||||
|
// Can't ride a baby
|
||||||
|
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
|
interactiveTag = InteractiveTag.RIDE_HORSE;
|
||||||
|
} else if (!entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && itemEntry.equals(ItemEntry.AIR)) {
|
||||||
|
// Can't hide an untamed entity without having your hand empty
|
||||||
|
interactiveTag = InteractiveTag.MOUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOX:
|
||||||
|
if (javaIdentifierStripped.equals("sweet_berries")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HOGLIN:
|
||||||
|
if (javaIdentifierStripped.equals("crimson_fungus")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MINECART:
|
||||||
|
interactiveTag = InteractiveTag.RIDE_MINECART;
|
||||||
|
break;
|
||||||
|
case MINECART_CHEST:
|
||||||
|
case MINECART_COMMAND_BLOCK:
|
||||||
|
case MINECART_HOPPER:
|
||||||
|
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
||||||
|
break;
|
||||||
|
case OCELOT:
|
||||||
|
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PANDA:
|
||||||
|
if (javaIdentifierStripped.equals("bamboo")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PARROT:
|
||||||
|
if (javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PIG:
|
||||||
|
if (javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||||
|
interactiveTag = InteractiveTag.MOUNT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PIGLIN:
|
||||||
|
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY) && javaIdentifierStripped.equals("gold_ingot")) {
|
||||||
|
interactiveTag = InteractiveTag.BARTER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RABBIT:
|
||||||
|
if (javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SHEEP:
|
||||||
|
if (javaIdentifierStripped.equals("wheat")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (!entityMetadata.getFlags().getFlag(EntityFlag.SHEARED)) {
|
||||||
|
if (javaIdentifierStripped.equals("shears")) {
|
||||||
|
// Shear the sheep
|
||||||
|
interactiveTag = InteractiveTag.SHEAR;
|
||||||
|
} else if (javaIdentifierStripped.contains("_dye")) {
|
||||||
|
// Dye the sheep
|
||||||
|
interactiveTag = InteractiveTag.DYE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STRIDER:
|
||||||
|
if (javaIdentifierStripped.equals("warped_fungus")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||||
|
interactiveTag = InteractiveTag.RIDE_STRIDER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TURTLE:
|
||||||
|
if (javaIdentifierStripped.equals("seagrass")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VILLAGER:
|
||||||
|
if (entityMetadata.getInt(EntityData.VARIANT) != 14 && entityMetadata.getInt(EntityData.VARIANT) != 0
|
||||||
|
&& entityMetadata.getFloat(EntityData.SCALE) >= 0.75f) { // Not a nitwit, has a profession and is not a baby
|
||||||
|
interactiveTag = InteractiveTag.TRADE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WANDERING_TRADER:
|
||||||
|
interactiveTag = InteractiveTag.TRADE; // Since you can always trade with a wandering villager, presumably.
|
||||||
|
break;
|
||||||
|
case WOLF:
|
||||||
|
if (javaIdentifierStripped.equals("bone") && !entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
|
// Bone and untamed - can tame
|
||||||
|
interactiveTag = InteractiveTag.TAME;
|
||||||
|
} else if (WOLF_FOODS.contains(javaIdentifierStripped)) {
|
||||||
|
// Compatible food in hand - feed
|
||||||
|
// Sometimes just sits/stands when the wolf isn't hungry - there doesn't appear to be a way to fix this
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||||
|
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||||
|
// Tamed and owned by player - can sit/stand
|
||||||
|
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZOMBIE_VILLAGER:
|
||||||
|
// We can't guarantee the existence of the weakness effect so we just always show it.
|
||||||
|
if (javaIdentifierStripped.equals("golden_apple")) {
|
||||||
|
interactiveTag = InteractiveTag.CURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag);
|
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag.getValue());
|
||||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||||
} else {
|
} else {
|
||||||
if (!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == null) ||
|
if (!session.getPlayerEntity().getMetadata().getString(EntityData.INTERACTIVE_TAG).isEmpty()) {
|
||||||
!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == "")) {
|
|
||||||
// No interactive tag should be sent
|
// No interactive tag should be sent
|
||||||
session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG);
|
session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG);
|
||||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||||
|
@ -147,4 +367,65 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All interactive tags in enum form. For potential API usage.
|
||||||
|
*/
|
||||||
|
public enum InteractiveTag {
|
||||||
|
NONE(true),
|
||||||
|
IGNITE_CREEPER("creeper"),
|
||||||
|
EDIT,
|
||||||
|
LEAVE_BOAT("exit.boat"),
|
||||||
|
FEED,
|
||||||
|
FISH("fishing"),
|
||||||
|
MILK,
|
||||||
|
MOOSHROOM_SHEAR("mooshear"),
|
||||||
|
MOOSHROOM_MILK_STEW("moostew"),
|
||||||
|
BOARD_BOAT("ride.boat"),
|
||||||
|
RIDE_MINECART("ride.minecart"),
|
||||||
|
RIDE_HORSE("ride.horse"),
|
||||||
|
RIDE_STRIDER("ride.strider"),
|
||||||
|
SHEAR,
|
||||||
|
SIT,
|
||||||
|
STAND,
|
||||||
|
TALK,
|
||||||
|
TAME,
|
||||||
|
DYE,
|
||||||
|
CURE,
|
||||||
|
OPEN_CONTAINER("opencontainer"),
|
||||||
|
CREATE_MAP("createMap"),
|
||||||
|
TAKE_PICTURE("takepicture"),
|
||||||
|
SADDLE,
|
||||||
|
MOUNT,
|
||||||
|
BOOST,
|
||||||
|
WRITE,
|
||||||
|
LEASH,
|
||||||
|
REMOVE_LEASH("unleash"),
|
||||||
|
NAME,
|
||||||
|
ATTACH_CHEST("attachchest"),
|
||||||
|
TRADE,
|
||||||
|
POSE_ARMOR_STAND("armorstand.pose"),
|
||||||
|
EQUIP_ARMOR_STAND("armorstand.equip"),
|
||||||
|
READ,
|
||||||
|
WAKE_VILLAGER("wakevillager"),
|
||||||
|
BARTER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The full string that should be passed on to the client.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
InteractiveTag(boolean isNone) {
|
||||||
|
this.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractiveTag(String value) {
|
||||||
|
this.value = "action.interact." + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractiveTag() {
|
||||||
|
this.value = "action.interact." + name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,10 @@ public class ItemRegistry {
|
||||||
public static final List<StartGamePacket.ItemEntry> ITEMS = new ArrayList<>();
|
public static final List<StartGamePacket.ItemEntry> ITEMS = new ArrayList<>();
|
||||||
public static final Int2ObjectMap<ItemEntry> ITEM_ENTRIES = new Int2ObjectOpenHashMap<>();
|
public static final Int2ObjectMap<ItemEntry> ITEM_ENTRIES = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bamboo item entry, used in PandaEntity.java
|
||||||
|
*/
|
||||||
|
public static ItemEntry BAMBOO;
|
||||||
/**
|
/**
|
||||||
* Boat item entry, used in BedrockInventoryTransactionTranslator.java
|
* Boat item entry, used in BedrockInventoryTransactionTranslator.java
|
||||||
*/
|
*/
|
||||||
|
@ -146,6 +150,9 @@ public class ItemRegistry {
|
||||||
case "minecraft:barrier":
|
case "minecraft:barrier":
|
||||||
BARRIER_INDEX = itemIndex;
|
BARRIER_INDEX = itemIndex;
|
||||||
break;
|
break;
|
||||||
|
case "minecraft:bamboo":
|
||||||
|
BAMBOO = ITEM_ENTRIES.get(itemIndex);
|
||||||
|
break;
|
||||||
case "minecraft:oak_boat":
|
case "minecraft:oak_boat":
|
||||||
BOAT = ITEM_ENTRIES.get(itemIndex);
|
BOAT = ITEM_ENTRIES.get(itemIndex);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||||
// are swapping servers
|
// are swapping servers
|
||||||
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
|
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
|
||||||
if (session.isSpawned()) {
|
if (session.isSpawned()) {
|
||||||
String fakeDim = entity.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
String fakeDim = session.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
||||||
DimensionUtils.switchDimension(session, fakeDim);
|
DimensionUtils.switchDimension(session, fakeDim);
|
||||||
DimensionUtils.switchDimension(session, newDimension);
|
DimensionUtils.switchDimension(session, newDimension);
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||||
|
|
||||||
session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
|
session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
|
||||||
|
|
||||||
if (!newDimension.equals(entity.getDimension())) {
|
if (!newDimension.equals(session.getDimension())) {
|
||||||
DimensionUtils.switchDimension(session, newDimension);
|
DimensionUtils.switchDimension(session, newDimension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,11 +67,11 @@ public class JavaRespawnTranslator extends PacketTranslator<ServerRespawnPacket>
|
||||||
}
|
}
|
||||||
|
|
||||||
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
|
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
|
||||||
if (!entity.getDimension().equals(newDimension)) {
|
if (!session.getDimension().equals(newDimension)) {
|
||||||
DimensionUtils.switchDimension(session, newDimension);
|
DimensionUtils.switchDimension(session, newDimension);
|
||||||
} else {
|
} else {
|
||||||
if (session.isManyDimPackets()) { //reloading world
|
if (session.isManyDimPackets()) { //reloading world
|
||||||
String fakeDim = entity.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
String fakeDim = session.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
||||||
DimensionUtils.switchDimension(session, fakeDim);
|
DimensionUtils.switchDimension(session, fakeDim);
|
||||||
DimensionUtils.switchDimension(session, newDimension);
|
DimensionUtils.switchDimension(session, newDimension);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class JavaEntityAttachTranslator extends PacketTranslator<ServerEntityAtt
|
||||||
if ((attachedToId == null || packet.getAttachedToId() == 0)) {
|
if ((attachedToId == null || packet.getAttachedToId() == 0)) {
|
||||||
// Is not being leashed
|
// Is not being leashed
|
||||||
holderId.getMetadata().getFlags().setFlag(EntityFlag.LEASHED, false);
|
holderId.getMetadata().getFlags().setFlag(EntityFlag.LEASHED, false);
|
||||||
holderId.getMetadata().put(EntityData.LEASH_HOLDER_EID, 0);
|
holderId.getMetadata().put(EntityData.LEASH_HOLDER_EID, -1L);
|
||||||
holderId.updateBedrockMetadata(session);
|
holderId.updateBedrockMetadata(session);
|
||||||
EntityEventPacket eventPacket = new EntityEventPacket();
|
EntityEventPacket eventPacket = new EntityEventPacket();
|
||||||
eventPacket.setRuntimeEntityId(holderId.getGeyserId());
|
eventPacket.setRuntimeEntityId(holderId.getGeyserId());
|
||||||
|
|
|
@ -25,15 +25,13 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.java.entity;
|
package org.geysermc.connector.network.translators.java.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.particle.ItemParticleData;
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityStatusPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityStatusPacket;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||||
|
@ -42,9 +40,7 @@ import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
|
||||||
|
|
||||||
@Translator(packet = ServerEntityStatusPacket.class)
|
@Translator(packet = ServerEntityStatusPacket.class)
|
||||||
public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntityStatusPacket> {
|
public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntityStatusPacket> {
|
||||||
|
@ -141,9 +137,15 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
|
||||||
case TAMEABLE_TAMING_SUCCEEDED:
|
case TAMEABLE_TAMING_SUCCEEDED:
|
||||||
entityEventPacket.setType(EntityEventType.TAME_SUCCEEDED);
|
entityEventPacket.setType(EntityEventType.TAME_SUCCEEDED);
|
||||||
break;
|
break;
|
||||||
case ZOMBIE_VILLAGER_CURE:
|
case ZOMBIE_VILLAGER_CURE: // Played when a zombie bites the golden apple
|
||||||
entityEventPacket.setType(EntityEventType.ZOMBIE_VILLAGER_CURE);
|
LevelSoundEvent2Packet soundPacket = new LevelSoundEvent2Packet();
|
||||||
break;
|
soundPacket.setSound(SoundEvent.REMEDY);
|
||||||
|
soundPacket.setPosition(entity.getPosition());
|
||||||
|
soundPacket.setExtraData(-1);
|
||||||
|
soundPacket.setIdentifier("");
|
||||||
|
soundPacket.setRelativeVolumeDisabled(false);
|
||||||
|
session.sendUpstreamPacket(soundPacket);
|
||||||
|
return;
|
||||||
case ANIMAL_EMIT_HEARTS:
|
case ANIMAL_EMIT_HEARTS:
|
||||||
entityEventPacket.setType(EntityEventType.LOVE_PARTICLES);
|
entityEventPacket.setType(EntityEventType.LOVE_PARTICLES);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class JavaMapDataTranslator extends PacketTranslator<ServerMapDataPacket>
|
||||||
boolean shouldStore = false;
|
boolean shouldStore = false;
|
||||||
|
|
||||||
mapItemDataPacket.setUniqueMapId(packet.getMapId());
|
mapItemDataPacket.setUniqueMapId(packet.getMapId());
|
||||||
mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getPlayerEntity().getDimension()));
|
mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension()));
|
||||||
mapItemDataPacket.setLocked(packet.isLocked());
|
mapItemDataPacket.setLocked(packet.isLocked());
|
||||||
mapItemDataPacket.setScale(packet.getScale());
|
mapItemDataPacket.setScale(packet.getScale());
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator<ServerSpawnPar
|
||||||
if (stringParticle != null) {
|
if (stringParticle != null) {
|
||||||
SpawnParticleEffectPacket stringPacket = new SpawnParticleEffectPacket();
|
SpawnParticleEffectPacket stringPacket = new SpawnParticleEffectPacket();
|
||||||
stringPacket.setIdentifier(stringParticle);
|
stringPacket.setIdentifier(stringParticle);
|
||||||
stringPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getPlayerEntity().getDimension()));
|
stringPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension()));
|
||||||
stringPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()));
|
stringPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()));
|
||||||
session.sendUpstreamPacket(stringPacket);
|
session.sendUpstreamPacket(stringPacket);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class JavaSpawnPositionTranslator extends PacketTranslator<ServerSpawnPos
|
||||||
SetSpawnPositionPacket spawnPositionPacket = new SetSpawnPositionPacket();
|
SetSpawnPositionPacket spawnPositionPacket = new SetSpawnPositionPacket();
|
||||||
spawnPositionPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
spawnPositionPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
||||||
spawnPositionPacket.setSpawnForced(true);
|
spawnPositionPacket.setSpawnForced(true);
|
||||||
spawnPositionPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getPlayerEntity().getDimension()));
|
spawnPositionPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension()));
|
||||||
spawnPositionPacket.setSpawnType(SetSpawnPositionPacket.Type.WORLD_SPAWN);
|
spawnPositionPacket.setSpawnType(SetSpawnPositionPacket.Type.WORLD_SPAWN);
|
||||||
session.sendUpstreamPacket(spawnPositionPacket);
|
session.sendUpstreamPacket(spawnPositionPacket);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,15 +41,23 @@ public class DimensionUtils {
|
||||||
// Changes if the above-bedrock Nether building workaround is applied
|
// Changes if the above-bedrock Nether building workaround is applied
|
||||||
private static int BEDROCK_NETHER_ID = 1;
|
private static int BEDROCK_NETHER_ID = 1;
|
||||||
|
|
||||||
// Static references to all vanilla dimensions
|
/**
|
||||||
|
* String reference to vanilla Java overworld dimension identifier
|
||||||
|
*/
|
||||||
public static final String OVERWORLD = "minecraft:overworld";
|
public static final String OVERWORLD = "minecraft:overworld";
|
||||||
|
/**
|
||||||
|
* String reference to vanilla Java nether dimension identifier
|
||||||
|
*/
|
||||||
public static final String NETHER = "minecraft:the_nether";
|
public static final String NETHER = "minecraft:the_nether";
|
||||||
|
/**
|
||||||
|
* String reference to vanilla Java end dimension identifier
|
||||||
|
*/
|
||||||
public static final String THE_END = "minecraft:the_end";
|
public static final String THE_END = "minecraft:the_end";
|
||||||
|
|
||||||
public static void switchDimension(GeyserSession session, String javaDimension) {
|
public static void switchDimension(GeyserSession session, String javaDimension) {
|
||||||
int bedrockDimension = javaToBedrock(javaDimension);
|
int bedrockDimension = javaToBedrock(javaDimension);
|
||||||
Entity player = session.getPlayerEntity();
|
Entity player = session.getPlayerEntity();
|
||||||
if (javaDimension.equals(player.getDimension()))
|
if (javaDimension.equals(session.getDimension()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (session.getMovementSendIfIdle() != null) {
|
if (session.getMovementSendIfIdle() != null) {
|
||||||
|
@ -69,7 +77,7 @@ public class DimensionUtils {
|
||||||
changeDimensionPacket.setRespawn(true);
|
changeDimensionPacket.setRespawn(true);
|
||||||
changeDimensionPacket.setPosition(pos.toFloat());
|
changeDimensionPacket.setPosition(pos.toFloat());
|
||||||
session.sendUpstreamPacket(changeDimensionPacket);
|
session.sendUpstreamPacket(changeDimensionPacket);
|
||||||
player.setDimension(javaDimension);
|
session.setDimension(javaDimension);
|
||||||
player.setPosition(pos.toFloat());
|
player.setPosition(pos.toFloat());
|
||||||
session.setSpawned(false);
|
session.setSpawned(false);
|
||||||
session.setLastChunkPosition(null);
|
session.setLastChunkPosition(null);
|
||||||
|
@ -115,23 +123,30 @@ public class DimensionUtils {
|
||||||
/**
|
/**
|
||||||
* Determines the new dimension based on the {@link CompoundTag} sent by either the {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket}
|
* Determines the new dimension based on the {@link CompoundTag} sent by either the {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket}
|
||||||
* or {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket}.
|
* or {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket}.
|
||||||
|
*
|
||||||
* @param dimensionTag the packet's dimension tag.
|
* @param dimensionTag the packet's dimension tag.
|
||||||
* @return the dimension identifier.
|
* @return the dimension identifier.
|
||||||
*/
|
*/
|
||||||
public static String getNewDimension(CompoundTag dimensionTag) {
|
public static String getNewDimension(CompoundTag dimensionTag) {
|
||||||
if (dimensionTag == null || dimensionTag.isEmpty()) {
|
if (dimensionTag == null || dimensionTag.isEmpty()) {
|
||||||
GeyserConnector.getInstance().getLogger().debug("Dimension tag was null or empty.");
|
GeyserConnector.getInstance().getLogger().debug("Dimension tag was null or empty.");
|
||||||
return "minecraft:overworld";
|
return OVERWORLD;
|
||||||
}
|
}
|
||||||
if (dimensionTag.getValue().get("effects") != null) {
|
if (dimensionTag.getValue().get("effects") != null) {
|
||||||
return ((StringTag) dimensionTag.getValue().get("effects")).getValue();
|
return ((StringTag) dimensionTag.getValue().get("effects")).getValue();
|
||||||
}
|
}
|
||||||
GeyserConnector.getInstance().getLogger().debug("Effects portion of the tag was null or empty.");
|
GeyserConnector.getInstance().getLogger().debug("Effects portion of the tag was null or empty.");
|
||||||
return "minecraft:overworld";
|
return OVERWORLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void changeBedrockNetherId() {
|
/**
|
||||||
|
* The Nether dimension in Bedrock does not permit building above Y128 - the Bedrock above the dimension.
|
||||||
|
* This workaround sets the Nether as the End dimension to ignore this limit.
|
||||||
|
*
|
||||||
|
* @param isAboveNetherBedrockBuilding true if we should apply The End workaround
|
||||||
|
*/
|
||||||
|
public static void changeBedrockNetherId(boolean isAboveNetherBedrockBuilding) {
|
||||||
// Change dimension ID to the End to allow for building above Bedrock
|
// Change dimension ID to the End to allow for building above Bedrock
|
||||||
BEDROCK_NETHER_ID = 2;
|
BEDROCK_NETHER_ID = isAboveNetherBedrockBuilding ? 2 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,12 +243,13 @@ public class LocaleUtils {
|
||||||
*/
|
*/
|
||||||
public static String getLocaleString(String messageText, String locale) {
|
public static String getLocaleString(String messageText, String locale) {
|
||||||
Map<String, String> localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase());
|
Map<String, String> localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase());
|
||||||
if (localeStrings == null)
|
|
||||||
localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(LanguageUtils.getDefaultLocale());
|
|
||||||
if (localeStrings == null) {
|
if (localeStrings == null) {
|
||||||
// Don't cause a NPE if the locale is STILL missing
|
localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(LanguageUtils.getDefaultLocale());
|
||||||
GeyserConnector.getInstance().getLogger().debug("MISSING DEFAULT LOCALE: " + LanguageUtils.getDefaultLocale());
|
if (localeStrings == null) {
|
||||||
return messageText;
|
// Don't cause a NPE if the locale is STILL missing
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("MISSING DEFAULT LOCALE: " + LanguageUtils.getDefaultLocale());
|
||||||
|
return messageText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return localeStrings.getOrDefault(messageText, messageText);
|
return localeStrings.getOrDefault(messageText, messageText);
|
||||||
|
|
Loading…
Reference in a new issue