Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-27 08:30:12 +01:00
Begin updating Geyser. Requires manual MCProtocolLib compile
Dieser Commit ist enthalten in:
Ursprung
77873b6fbb
Commit
117cdf282d
@ -105,7 +105,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.steveice10</groupId>
|
<groupId>com.github.steveice10</groupId>
|
||||||
<artifactId>mcprotocollib</artifactId>
|
<artifactId>mcprotocollib</artifactId>
|
||||||
<version>013e8e6dc4</version>
|
<version>1.16-rc1-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
|
@ -67,7 +67,7 @@ public class Entity {
|
|||||||
protected long entityId;
|
protected long entityId;
|
||||||
protected long geyserId;
|
protected long geyserId;
|
||||||
|
|
||||||
protected int dimension;
|
protected String dimension;
|
||||||
|
|
||||||
protected Vector3f position;
|
protected Vector3f position;
|
||||||
protected Vector3f motion;
|
protected Vector3f motion;
|
||||||
@ -100,7 +100,7 @@ public class Entity {
|
|||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
|
|
||||||
this.valid = false;
|
this.valid = false;
|
||||||
this.dimension = 0;
|
this.dimension = "minecraft:overworld";
|
||||||
|
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
|
|
||||||
|
@ -33,20 +33,20 @@ import lombok.Getter;
|
|||||||
public enum AttributeType {
|
public enum AttributeType {
|
||||||
|
|
||||||
// Universal Attributes
|
// Universal Attributes
|
||||||
FOLLOW_RANGE("generic.followRange", "minecraft:follow_range", 0f, 2048f, 32f),
|
FOLLOW_RANGE("minecraft:generic.follow_range", "minecraft:follow_range", 0f, 2048f, 32f),
|
||||||
KNOCKBACK_RESISTANCE("generic.knockbackResistance", "minecraft:knockback_resistance", 0f, 1f, 0f),
|
KNOCKBACK_RESISTANCE("minecraft:generic.knockback_resistance", "minecraft:knockback_resistance", 0f, 1f, 0f),
|
||||||
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f),
|
MOVEMENT_SPEED("minecraft:generic.movement_speed", "minecraft:movement", 0f, 1024f, 0.1f),
|
||||||
FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
FLYING_SPEED("minecraft:generic.flying_speed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
||||||
ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
ATTACK_DAMAGE("minecraft:generic.attack_damage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
||||||
HORSE_JUMP_STRENGTH("horse.jumpStrength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f),
|
HORSE_JUMP_STRENGTH("minecraft:horse.jump_strength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f),
|
||||||
|
|
||||||
// Java Attributes
|
// Java Attributes
|
||||||
ARMOR("generic.armor", null, 0f, 30f, 0f),
|
ARMOR("minecraft:generic.armor", null, 0f, 30f, 0f),
|
||||||
ARMOR_TOUGHNESS("generic.armorToughness", null, 0F, 20f, 0f),
|
ARMOR_TOUGHNESS("minecraft:generic.armor_toughness", null, 0F, 20f, 0f),
|
||||||
ATTACK_KNOCKBACK("generic.attackKnockback", null, 1.5f, Float.MAX_VALUE, 0f),
|
ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f),
|
||||||
ATTACK_SPEED("generic.attackSpeed", null, 0f, 1024f, 4f),
|
ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f),
|
||||||
LUCK("generic.luck", null, -1024f, 1024f, 0f),
|
LUCK("minecraft:generic.luck", null, -1024f, 1024f, 0f),
|
||||||
MAX_HEALTH("generic.maxHealth", null, 0f, 1024f, 20f),
|
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
|
||||||
|
|
||||||
// Bedrock Attributes
|
// Bedrock Attributes
|
||||||
ABSORPTION(null, "minecraft:absorption", 0f, Float.MAX_VALUE, 0f),
|
ABSORPTION(null, "minecraft:absorption", 0f, Float.MAX_VALUE, 0f),
|
||||||
|
@ -68,7 +68,7 @@ public enum EntityType {
|
|||||||
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
||||||
SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f),
|
SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f),
|
SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f),
|
||||||
ZOMBIE_PIGMAN(MonsterEntity.class, 36, 1.8f, 0.6f, 0.6f, 1.62f),
|
ZOMBIFIED_PIGLIN(MonsterEntity.class, 36, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
SLIME(SlimeEntity.class, 37, 0.51f),
|
SLIME(SlimeEntity.class, 37, 0.51f),
|
||||||
ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f),
|
ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f),
|
||||||
SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f),
|
SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f),
|
||||||
@ -150,7 +150,6 @@ public enum EntityType {
|
|||||||
COD(AbstractFishEntity.class, 112, 0.25f, 0.5f),
|
COD(AbstractFishEntity.class, 112, 0.25f, 0.5f),
|
||||||
PANDA(PandaEntity.class, 113, 1.25f, 1.125f, 1.825f),
|
PANDA(PandaEntity.class, 113, 1.25f, 1.125f, 1.825f),
|
||||||
FOX(FoxEntity.class, 121, 0.5f, 1.25f),
|
FOX(FoxEntity.class, 121, 0.5f, 1.25f),
|
||||||
BEE(BeeEntity.class, 122, 0.6f, 0.6f),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item frames are handled differently since they are a block in Bedrock.
|
* Item frames are handled differently since they are a block in Bedrock.
|
||||||
|
@ -68,10 +68,7 @@ import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
|||||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
import org.geysermc.connector.utils.*;
|
||||||
import org.geysermc.connector.utils.LocaleUtils;
|
|
||||||
import org.geysermc.connector.utils.MathUtils;
|
|
||||||
import org.geysermc.connector.utils.SkinUtils;
|
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
import org.geysermc.floodgate.util.EncryptionUtil;
|
import org.geysermc.floodgate.util.EncryptionUtil;
|
||||||
|
|
||||||
@ -503,7 +500,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(playerEntity.getDimension());
|
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(playerEntity.getDimension()));
|
||||||
startGamePacket.setGeneratorId(1);
|
startGamePacket.setGeneratorId(1);
|
||||||
startGamePacket.setLevelGamemode(0);
|
startGamePacket.setLevelGamemode(0);
|
||||||
startGamePacket.setDifficulty(1);
|
startGamePacket.setDifficulty(1);
|
||||||
|
@ -44,7 +44,7 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator<Adventu
|
|||||||
boolean flying = packet.getFlags().contains(AdventureSettingsPacket.Flag.FLYING);
|
boolean flying = packet.getFlags().contains(AdventureSettingsPacket.Flag.FLYING);
|
||||||
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
||||||
ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(
|
ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(
|
||||||
false, canFly, flying, creative, 0.05f, 0.1f
|
false, canFly, flying, creative
|
||||||
);
|
);
|
||||||
session.sendDownstreamPacket(abilitiesPacket);
|
session.sendDownstreamPacket(abilitiesPacket);
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,12 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||||
InteractAction.INTERACT, Hand.MAIN_HAND);
|
InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking());
|
||||||
session.sendDownstreamPacket(interactPacket);
|
session.sendDownstreamPacket(interactPacket);
|
||||||
break;
|
break;
|
||||||
case DAMAGE:
|
case DAMAGE:
|
||||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||||
InteractAction.ATTACK, Hand.MAIN_HAND);
|
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
|
||||||
session.sendDownstreamPacket(attackPacket);
|
session.sendDownstreamPacket(attackPacket);
|
||||||
break;
|
break;
|
||||||
case LEAVE_VEHICLE:
|
case LEAVE_VEHICLE:
|
||||||
|
@ -82,9 +82,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
||||||
Vector3f vector = packet.getClickPosition();
|
Vector3f vector = packet.getClickPosition();
|
||||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||||
InteractAction.INTERACT, Hand.MAIN_HAND);
|
InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking());
|
||||||
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||||
InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND);
|
InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND, session.isSneaking());
|
||||||
session.sendDownstreamPacket(interactPacket);
|
session.sendDownstreamPacket(interactPacket);
|
||||||
session.sendDownstreamPacket(interactAtPacket);
|
session.sendDownstreamPacket(interactAtPacket);
|
||||||
break;
|
break;
|
||||||
@ -161,7 +161,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
if (ItemFrameEntity.positionContainsItemFrame(session, packet.getBlockPosition()) &&
|
if (ItemFrameEntity.positionContainsItemFrame(session, packet.getBlockPosition()) &&
|
||||||
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
||||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||||
InteractAction.ATTACK);
|
InteractAction.ATTACK, session.isSneaking());
|
||||||
session.sendDownstreamPacket(attackPacket);
|
session.sendDownstreamPacket(attackPacket);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -191,9 +191,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
case 0: //Interact
|
case 0: //Interact
|
||||||
Vector3f vector = packet.getClickPosition();
|
Vector3f vector = packet.getClickPosition();
|
||||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||||
InteractAction.INTERACT, Hand.MAIN_HAND);
|
InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking());
|
||||||
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||||
InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND);
|
InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND, session.isSneaking());
|
||||||
session.sendDownstreamPacket(interactPacket);
|
session.sendDownstreamPacket(interactPacket);
|
||||||
session.sendDownstreamPacket(interactAtPacket);
|
session.sendDownstreamPacket(interactAtPacket);
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
break;
|
break;
|
||||||
case 1: //Attack
|
case 1: //Attack
|
||||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||||
InteractAction.ATTACK);
|
InteractAction.ATTACK, session.isSneaking());
|
||||||
session.sendDownstreamPacket(attackPacket);
|
session.sendDownstreamPacket(attackPacket);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator<ItemFra
|
|||||||
}
|
}
|
||||||
Vector3i position = Vector3i.from(packet.getBlockPosition().getX(), y, packet.getBlockPosition().getZ());
|
Vector3i position = Vector3i.from(packet.getBlockPosition().getX(), y, packet.getBlockPosition().getZ());
|
||||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, position),
|
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, position),
|
||||||
InteractAction.ATTACK, Hand.MAIN_HAND);
|
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
|
||||||
session.sendDownstreamPacket(interactPacket);
|
session.sendDownstreamPacket(interactPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,37 +100,42 @@ public class ItemRegistry {
|
|||||||
int itemIndex = 0;
|
int itemIndex = 0;
|
||||||
Iterator<Map.Entry<String, JsonNode>> iterator = items.fields();
|
Iterator<Map.Entry<String, JsonNode>> iterator = items.fields();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Map.Entry<String, JsonNode> entry = iterator.next();
|
try {
|
||||||
if (entry.getValue().has("tool_type")) {
|
Map.Entry<String, JsonNode> entry = iterator.next();
|
||||||
if (entry.getValue().has("tool_tier")) {
|
if (entry.getValue().has("tool_type")) {
|
||||||
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
if (entry.getValue().has("tool_tier")) {
|
||||||
entry.getKey(), itemIndex,
|
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
||||||
entry.getValue().get("bedrock_id").intValue(),
|
entry.getKey(), itemIndex,
|
||||||
entry.getValue().get("bedrock_data").intValue(),
|
entry.getValue().get("bedrock_id").intValue(),
|
||||||
entry.getValue().get("tool_type").textValue(),
|
entry.getValue().get("bedrock_data").intValue(),
|
||||||
entry.getValue().get("tool_tier").textValue(),
|
entry.getValue().get("tool_type").textValue(),
|
||||||
entry.getValue().get("is_block").booleanValue()));
|
entry.getValue().get("tool_tier").textValue(),
|
||||||
|
entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue()));
|
||||||
|
} else {
|
||||||
|
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
||||||
|
entry.getKey(), itemIndex,
|
||||||
|
entry.getValue().get("bedrock_id").intValue(),
|
||||||
|
entry.getValue().get("bedrock_data").intValue(),
|
||||||
|
entry.getValue().get("tool_type").textValue(),
|
||||||
|
"",
|
||||||
|
entry.getValue().get("is_block").booleanValue()));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
ITEM_ENTRIES.put(itemIndex, new ItemEntry(
|
||||||
entry.getKey(), itemIndex,
|
entry.getKey(), itemIndex,
|
||||||
entry.getValue().get("bedrock_id").intValue(),
|
entry.getValue().get("bedrock_id").intValue(),
|
||||||
entry.getValue().get("bedrock_data").intValue(),
|
entry.getValue().get("bedrock_data").intValue(),
|
||||||
entry.getValue().get("tool_type").textValue(),
|
entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue()));
|
||||||
"",
|
}
|
||||||
entry.getValue().get("is_block").booleanValue()));
|
if (entry.getKey().equals("minecraft:barrier")) {
|
||||||
|
BARRIER_INDEX = itemIndex;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry(
|
|
||||||
entry.getKey(), itemIndex,
|
|
||||||
entry.getValue().get("bedrock_id").intValue(),
|
|
||||||
entry.getValue().get("bedrock_data").intValue(),
|
|
||||||
entry.getValue().get("is_block").booleanValue()));
|
|
||||||
}
|
|
||||||
if (entry.getKey().equals("minecraft:barrier")) {
|
|
||||||
BARRIER_INDEX = itemIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
itemIndex++;
|
itemIndex++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Exception in item registry! " + e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load creative items */
|
/* Load creative items */
|
||||||
|
@ -80,7 +80,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
|||||||
ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, Hand.MAIN_HAND);
|
ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, Hand.MAIN_HAND);
|
||||||
session.sendDownstreamPacket(clientSettingsPacket);
|
session.sendDownstreamPacket(clientSettingsPacket);
|
||||||
|
|
||||||
if (DimensionUtils.javaToBedrock(packet.getDimension()) != entity.getDimension()) {
|
if (!packet.getDimension().equals(entity.getDimension())) {
|
||||||
DimensionUtils.switchDimension(session, packet.getDimension());
|
DimensionUtils.switchDimension(session, packet.getDimension());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,11 +66,11 @@ public class JavaRespawnTranslator extends PacketTranslator<ServerRespawnPacket>
|
|||||||
stopRainPacket.setPosition(Vector3f.ZERO);
|
stopRainPacket.setPosition(Vector3f.ZERO);
|
||||||
session.sendUpstreamPacket(stopRainPacket);
|
session.sendUpstreamPacket(stopRainPacket);
|
||||||
|
|
||||||
if (entity.getDimension() != DimensionUtils.javaToBedrock(packet.getDimension())) {
|
if (!entity.getDimension().equals(packet.getDimension())) {
|
||||||
DimensionUtils.switchDimension(session, packet.getDimension());
|
DimensionUtils.switchDimension(session, packet.getDimension());
|
||||||
} else {
|
} else {
|
||||||
if (session.isManyDimPackets()) { //reloading world
|
if (session.isManyDimPackets()) { //reloading world
|
||||||
int fakeDim = entity.getDimension() == 0 ? -1 : 0;
|
String fakeDim = entity.getDimension().equals("minecraft:overworld") ? "minecraft:nether" : "minecraft:overworld";
|
||||||
DimensionUtils.switchDimension(session, fakeDim);
|
DimensionUtils.switchDimension(session, fakeDim);
|
||||||
DimensionUtils.switchDimension(session, packet.getDimension());
|
DimensionUtils.switchDimension(session, packet.getDimension());
|
||||||
} else {
|
} else {
|
||||||
|
@ -35,6 +35,7 @@ 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.utils.BedrockMapIcon;
|
import org.geysermc.connector.utils.BedrockMapIcon;
|
||||||
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
import org.geysermc.connector.utils.MapColor;
|
import org.geysermc.connector.utils.MapColor;
|
||||||
|
|
||||||
@Translator(packet = ServerMapDataPacket.class)
|
@Translator(packet = ServerMapDataPacket.class)
|
||||||
@ -45,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(session.getPlayerEntity().getDimension());
|
mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getPlayerEntity().getDimension()));
|
||||||
mapItemDataPacket.setLocked(packet.isLocked());
|
mapItemDataPacket.setLocked(packet.isLocked());
|
||||||
mapItemDataPacket.setScale(packet.getScale());
|
mapItemDataPacket.setScale(packet.getScale());
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerSpawnParticlePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerSpawnParticlePacket;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||||
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
|
||||||
@Translator(packet = ServerSpawnParticlePacket.class)
|
@Translator(packet = ServerSpawnParticlePacket.class)
|
||||||
public class JavaSpawnParticleTranslator extends PacketTranslator<ServerSpawnParticlePacket> {
|
public class JavaSpawnParticleTranslator extends PacketTranslator<ServerSpawnParticlePacket> {
|
||||||
@ -93,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(session.getPlayerEntity().getDimension());
|
stringPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getPlayerEntity().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);
|
||||||
}
|
}
|
||||||
|
@ -117,94 +117,104 @@ public class BlockTranslator {
|
|||||||
int spawnerRuntimeId = -1;
|
int spawnerRuntimeId = -1;
|
||||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
||||||
while (blocksIterator.hasNext()) {
|
while (blocksIterator.hasNext()) {
|
||||||
javaRuntimeId++;
|
try {
|
||||||
Map.Entry<String, JsonNode> entry = blocksIterator.next();
|
javaRuntimeId++;
|
||||||
String javaId = entry.getKey();
|
Map.Entry<String, JsonNode> entry = blocksIterator.next();
|
||||||
CompoundTag blockTag = buildBedrockState(entry.getValue());
|
String javaId = entry.getKey();
|
||||||
|
CompoundTag blockTag = buildBedrockState(entry.getValue());
|
||||||
|
|
||||||
// TODO fix this, (no block should have a null hardness)
|
// TODO fix this, (no block should have a null hardness)
|
||||||
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
||||||
if (hardnessNode != null) {
|
if (hardnessNode != null) {
|
||||||
JAVA_RUNTIME_ID_TO_HARDNESS.put(javaRuntimeId, hardnessNode.doubleValue());
|
JAVA_RUNTIME_ID_TO_HARDNESS.put(javaRuntimeId, hardnessNode.doubleValue());
|
||||||
}
|
|
||||||
|
|
||||||
JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.put(javaRuntimeId, entry.getValue().get("can_break_with_hand").booleanValue());
|
|
||||||
|
|
||||||
JsonNode toolTypeNode = entry.getValue().get("tool_type");
|
|
||||||
if (toolTypeNode != null) {
|
|
||||||
JAVA_RUNTIME_ID_TO_TOOL_TYPE.put(javaRuntimeId, toolTypeNode.textValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (javaId.contains("wool")) {
|
|
||||||
JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (javaId.contains("cobweb")) {
|
|
||||||
cobwebRuntimeId = javaRuntimeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId);
|
|
||||||
|
|
||||||
// Used for adding all "special" Java block states to block state map
|
|
||||||
String identifier;
|
|
||||||
String bedrock_identifer = entry.getValue().get("bedrock_identifier").asText();
|
|
||||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
|
||||||
identifier = clazz.getAnnotation(BlockEntity.class).regex();
|
|
||||||
// Endswith, or else the block bedrock gets picked up for bed
|
|
||||||
if (bedrock_identifer.endsWith(identifier) && !identifier.equals("")) {
|
|
||||||
JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaRuntimeId, clazz.getAnnotation(BlockEntity.class).name());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BlockStateValues.storeBlockStateValues(entry, javaRuntimeId);
|
try {
|
||||||
|
JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.put(javaRuntimeId, entry.getValue().get("can_break_with_hand").booleanValue());
|
||||||
|
} catch (Exception e) {
|
||||||
|
JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.put(javaRuntimeId, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the tag needed for non-empty flower pots
|
JsonNode toolTypeNode = entry.getValue().get("tool_type");
|
||||||
if (entry.getValue().get("pottable") != null) {
|
if (toolTypeNode != null) {
|
||||||
BlockStateValues.getFlowerPotBlocks().put(entry.getKey().split("\\[")[0], buildBedrockState(entry.getValue()));
|
JAVA_RUNTIME_ID_TO_TOOL_TYPE.put(javaRuntimeId, toolTypeNode.textValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
if (javaId.contains("wool")) {
|
||||||
waterRuntimeId = bedrockRuntimeId;
|
JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId);
|
||||||
}
|
}
|
||||||
boolean waterlogged = entry.getKey().contains("waterlogged=true")
|
|
||||||
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
|
||||||
|
|
||||||
if (waterlogged) {
|
if (javaId.contains("cobweb")) {
|
||||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId);
|
cobwebRuntimeId = javaRuntimeId;
|
||||||
WATERLOGGED.add(javaRuntimeId);
|
}
|
||||||
} else {
|
|
||||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaRuntimeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompoundTag runtimeTag = blockStateMap.remove(blockTag);
|
JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId);
|
||||||
if (runtimeTag != null) {
|
|
||||||
addedStatesMap.put(blockTag, bedrockRuntimeId);
|
// Used for adding all "special" Java block states to block state map
|
||||||
paletteList.add(runtimeTag);
|
String identifier;
|
||||||
} else {
|
String bedrock_identifer = entry.getValue().get("bedrock_identifier").asText();
|
||||||
int duplicateRuntimeId = addedStatesMap.getOrDefault(blockTag, -1);
|
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
||||||
if (duplicateRuntimeId == -1) {
|
identifier = clazz.getAnnotation(BlockEntity.class).regex();
|
||||||
GeyserConnector.getInstance().getLogger().debug("Mapping " + javaId + " was not found for bedrock edition!");
|
// Endswith, or else the block bedrock gets picked up for bed
|
||||||
|
if (bedrock_identifer.endsWith(identifier) && !identifier.equals("")) {
|
||||||
|
JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaRuntimeId, clazz.getAnnotation(BlockEntity.class).name());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockStateValues.storeBlockStateValues(entry, javaRuntimeId);
|
||||||
|
|
||||||
|
// Get the tag needed for non-empty flower pots
|
||||||
|
if (entry.getValue().get("pottable") != null) {
|
||||||
|
BlockStateValues.getFlowerPotBlocks().put(entry.getKey().split("\\[")[0], buildBedrockState(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||||
|
waterRuntimeId = bedrockRuntimeId;
|
||||||
|
}
|
||||||
|
boolean waterlogged = entry.getKey().contains("waterlogged=true")
|
||||||
|
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
||||||
|
|
||||||
|
if (waterlogged) {
|
||||||
|
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId);
|
||||||
|
WATERLOGGED.add(javaRuntimeId);
|
||||||
} else {
|
} else {
|
||||||
JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, duplicateRuntimeId);
|
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaRuntimeId);
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId);
|
|
||||||
|
|
||||||
if (javaId.startsWith("minecraft:furnace[facing=north")) {
|
CompoundTag runtimeTag = blockStateMap.remove(blockTag);
|
||||||
if (javaId.contains("lit=true")) {
|
if (runtimeTag != null) {
|
||||||
furnaceLitRuntimeId = javaRuntimeId;
|
addedStatesMap.put(blockTag, bedrockRuntimeId);
|
||||||
|
paletteList.add(runtimeTag);
|
||||||
} else {
|
} else {
|
||||||
furnaceRuntimeId = javaRuntimeId;
|
int duplicateRuntimeId = addedStatesMap.getOrDefault(blockTag, -1);
|
||||||
|
if (duplicateRuntimeId == -1) {
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Mapping " + javaId + " was not found for bedrock edition!");
|
||||||
|
} else {
|
||||||
|
JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, duplicateRuntimeId);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId);
|
||||||
|
|
||||||
if (javaId.startsWith("minecraft:spawner")) {
|
if (javaId.startsWith("minecraft:furnace[facing=north")) {
|
||||||
spawnerRuntimeId = javaRuntimeId;
|
if (javaId.contains("lit=true")) {
|
||||||
}
|
furnaceLitRuntimeId = javaRuntimeId;
|
||||||
|
} else {
|
||||||
|
furnaceRuntimeId = javaRuntimeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bedrockRuntimeId++;
|
if (javaId.startsWith("minecraft:spawner")) {
|
||||||
|
spawnerRuntimeId = javaRuntimeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bedrockRuntimeId++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// REMOVE AFTER 1.16 UPDATE PROBABLY
|
||||||
|
System.out.println("Block translator error! " + e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cobwebRuntimeId == -1) {
|
if (cobwebRuntimeId == -1) {
|
||||||
|
@ -36,10 +36,10 @@ 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;
|
||||||
|
|
||||||
public static void switchDimension(GeyserSession session, int 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 (bedrockDimension == player.getDimension())
|
if (bedrockToJava(bedrockDimension) == player.getDimension())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
session.getEntityCache().removeAllEntities();
|
session.getEntityCache().removeAllEntities();
|
||||||
@ -55,7 +55,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(bedrockDimension);
|
player.setDimension(bedrockToJava(bedrockDimension));
|
||||||
player.setPosition(pos.toFloat());
|
player.setPosition(pos.toFloat());
|
||||||
session.setSpawned(false);
|
session.setSpawned(false);
|
||||||
session.setLastChunkPosition(null);
|
session.setLastChunkPosition(null);
|
||||||
@ -83,14 +83,25 @@ public class DimensionUtils {
|
|||||||
* @param javaDimension Dimension ID to convert
|
* @param javaDimension Dimension ID to convert
|
||||||
* @return Converted Bedrock edition dimension ID
|
* @return Converted Bedrock edition dimension ID
|
||||||
*/
|
*/
|
||||||
public static int javaToBedrock(int javaDimension) {
|
public static int javaToBedrock(String javaDimension) {
|
||||||
switch (javaDimension) {
|
switch (javaDimension) {
|
||||||
case -1:
|
case "minecraft:nether":
|
||||||
return BEDROCK_NETHER_ID;
|
return BEDROCK_NETHER_ID;
|
||||||
case 1:
|
case "minecraft:the_end":
|
||||||
return 2;
|
return 2;
|
||||||
default:
|
default:
|
||||||
return javaDimension;
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String bedrockToJava(int bedrockDimension) {
|
||||||
|
switch (bedrockDimension) {
|
||||||
|
case 1:
|
||||||
|
return "minecraft:nether";
|
||||||
|
case 2:
|
||||||
|
return "minecraft:the_end";
|
||||||
|
default:
|
||||||
|
return "minecraft:overworld";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,13 +210,13 @@ public class MessageUtils {
|
|||||||
* @return Colour string to be used
|
* @return Colour string to be used
|
||||||
*/
|
*/
|
||||||
private static String getColorOrParent(MessageStyle style) {
|
private static String getColorOrParent(MessageStyle style) {
|
||||||
ChatColor chatColor = style.getColor();
|
String color = style.getColor();
|
||||||
|
|
||||||
/*if (chatColor == ChatColor.NONE && style.getParent() != null) {
|
/*if (color == ChatColor.NONE && style.getParent() != null) {
|
||||||
return getColorOrParent(style.getParent());
|
return getColorOrParent(style.getParent());
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
return getColor(chatColor);
|
return getColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -225,58 +225,58 @@ public class MessageUtils {
|
|||||||
* @param color ChatColor to convert
|
* @param color ChatColor to convert
|
||||||
* @return The converted color string
|
* @return The converted color string
|
||||||
*/
|
*/
|
||||||
private static String getColor(ChatColor color) {
|
private static String getColor(String color) {
|
||||||
String base = "\u00a7";
|
String base = "\u00a7";
|
||||||
switch (color) {
|
switch (color) {
|
||||||
case BLACK:
|
case ChatColor.BLACK:
|
||||||
base += "0";
|
base += "0";
|
||||||
break;
|
break;
|
||||||
case DARK_BLUE:
|
case ChatColor.DARK_BLUE:
|
||||||
base += "1";
|
base += "1";
|
||||||
break;
|
break;
|
||||||
case DARK_GREEN:
|
case ChatColor.DARK_GREEN:
|
||||||
base += "2";
|
base += "2";
|
||||||
break;
|
break;
|
||||||
case DARK_AQUA:
|
case ChatColor.DARK_AQUA:
|
||||||
base += "3";
|
base += "3";
|
||||||
break;
|
break;
|
||||||
case DARK_RED:
|
case ChatColor.DARK_RED:
|
||||||
base += "4";
|
base += "4";
|
||||||
break;
|
break;
|
||||||
case DARK_PURPLE:
|
case ChatColor.DARK_PURPLE:
|
||||||
base += "5";
|
base += "5";
|
||||||
break;
|
break;
|
||||||
case GOLD:
|
case ChatColor.GOLD:
|
||||||
base += "6";
|
base += "6";
|
||||||
break;
|
break;
|
||||||
case GRAY:
|
case ChatColor.GRAY:
|
||||||
base += "7";
|
base += "7";
|
||||||
break;
|
break;
|
||||||
case DARK_GRAY:
|
case ChatColor.DARK_GRAY:
|
||||||
base += "8";
|
base += "8";
|
||||||
break;
|
break;
|
||||||
case BLUE:
|
case ChatColor.BLUE:
|
||||||
base += "9";
|
base += "9";
|
||||||
break;
|
break;
|
||||||
case GREEN:
|
case ChatColor.GREEN:
|
||||||
base += "a";
|
base += "a";
|
||||||
break;
|
break;
|
||||||
case AQUA:
|
case ChatColor.AQUA:
|
||||||
base += "b";
|
base += "b";
|
||||||
break;
|
break;
|
||||||
case RED:
|
case ChatColor.RED:
|
||||||
base += "c";
|
base += "c";
|
||||||
break;
|
break;
|
||||||
case LIGHT_PURPLE:
|
case ChatColor.LIGHT_PURPLE:
|
||||||
base += "d";
|
base += "d";
|
||||||
break;
|
break;
|
||||||
case YELLOW:
|
case ChatColor.YELLOW:
|
||||||
base += "e";
|
base += "e";
|
||||||
break;
|
break;
|
||||||
case WHITE:
|
case ChatColor.WHITE:
|
||||||
base += "f";
|
base += "f";
|
||||||
break;
|
break;
|
||||||
case RESET:
|
case ChatColor.RESET:
|
||||||
//case NONE:
|
//case NONE:
|
||||||
base += "r";
|
base += "r";
|
||||||
break;
|
break;
|
||||||
@ -369,16 +369,16 @@ public class MessageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String toChatColor(TeamColor teamColor) {
|
public static String toChatColor(TeamColor teamColor) {
|
||||||
for (ChatColor color : ChatColor.values()) {
|
// for (ChatColor color : ChatColor.) {
|
||||||
if (color.name().equals(teamColor.name())) {
|
// if (color.name().equals(teamColor.name())) {
|
||||||
return getColor(color);
|
// return getColor(color);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
for (ChatFormat format : ChatFormat.values()) {
|
// for (ChatFormat format : ChatFormat.values()) {
|
||||||
if (format.name().equals(teamColor.name())) {
|
// if (format.name().equals(teamColor.name())) {
|
||||||
return getFormat(Collections.singletonList(format));
|
// return getFormat(Collections.singletonList(format));
|
||||||
}
|
// }
|
||||||
}
|
// } Not dealing with this
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren