forked from GeyserMC/Geyser
Rebase
This commit is contained in:
commit
e76b67265a
18 changed files with 468 additions and 12 deletions
|
@ -72,6 +72,30 @@
|
|||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-double-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-boolean-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-object-int-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-object-byte-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
|
|
|
@ -39,6 +39,7 @@ import lombok.Setter;
|
|||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.EntityEffectCache;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -50,6 +51,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
private String username;
|
||||
private long lastSkinUpdate = -1;
|
||||
private boolean playerList = true;
|
||||
private final EntityEffectCache effectCache;
|
||||
|
||||
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
||||
|
@ -57,6 +59,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
profile = gameProfile;
|
||||
uuid = gameProfile.getId();
|
||||
username = gameProfile.getName();
|
||||
effectCache = new EntityEffectCache();
|
||||
if (geyserId == 1) valid = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,6 @@ public class PlayerInventory extends Inventory {
|
|||
}
|
||||
|
||||
public ItemStack getItemInHand() {
|
||||
return items[heldItemSlot];
|
||||
return items[36 + heldItemSlot];
|
||||
}
|
||||
}
|
||||
|
|
54
connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java
vendored
Normal file
54
connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.network.session.cache;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
public class EntityEffectCache {
|
||||
|
||||
@Getter
|
||||
private final Object2IntMap<Effect> entityEffects = new Object2IntOpenHashMap<>();
|
||||
|
||||
public void addEffect(Effect effect, int effectAmplifier) {
|
||||
if (effect != null) {
|
||||
entityEffects.putIfAbsent(effect, effectAmplifier + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEffect(Effect effect) {
|
||||
if (entityEffects.containsKey(effect)) {
|
||||
int effectLevel = entityEffects.getInt(effect);
|
||||
entityEffects.remove(effect, effectLevel);
|
||||
}
|
||||
}
|
||||
|
||||
public int getEffectLevel(Effect effect) {
|
||||
return entityEffects.getOrDefault(effect, 0);
|
||||
}
|
||||
}
|
|
@ -55,6 +55,8 @@ public class Registry<T> {
|
|||
if (MAP.containsKey(clazz)) {
|
||||
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
||||
return true;
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||
|
|
|
@ -32,12 +32,18 @@ import com.nukkitx.nbt.NbtUtils;
|
|||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.ListTag;
|
||||
import it.unimi.dsi.fastutil.ints.Int2BooleanMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2DoubleOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
@ -55,8 +61,16 @@ public class BlockTranslator {
|
|||
private static final Int2ObjectMap<BlockState> BEDROCK_TO_JAVA_BLOCK_MAP = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, BlockState> JAVA_ID_BLOCK_MAP = new HashMap<>();
|
||||
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
||||
private static final Object2ByteMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
|
||||
|
||||
private static final Map<BlockState, String> JAVA_ID_TO_BLOCK_ENTITY_MAP = new HashMap<>();
|
||||
public static final Int2DoubleMap JAVA_RUNTIME_ID_TO_HARDNESS = new Int2DoubleOpenHashMap();
|
||||
public static final Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap();
|
||||
public static final Int2ObjectMap<String> JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// For block breaking animation math
|
||||
public static final List<Integer> JAVA_RUNTIME_WOOL_IDS = new ArrayList<>();
|
||||
public static final int JAVA_RUNTIME_COBWEB_ID;
|
||||
|
||||
private static final int BLOCK_STATE_VERSION = 17760256;
|
||||
|
||||
|
@ -93,6 +107,7 @@ public class BlockTranslator {
|
|||
int waterRuntimeId = -1;
|
||||
int javaRuntimeId = -1;
|
||||
int bedrockRuntimeId = 0;
|
||||
int cobwebRuntimeId = -1;
|
||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
||||
while (blocksIterator.hasNext()) {
|
||||
javaRuntimeId++;
|
||||
|
@ -101,16 +116,46 @@ public class BlockTranslator {
|
|||
BlockState javaBlockState = new BlockState(javaRuntimeId);
|
||||
CompoundTag blockTag = buildBedrockState(entry.getValue());
|
||||
|
||||
// TODO fix this, (no block should have a null hardness)
|
||||
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
||||
if (hardnessNode != null) {
|
||||
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, javaBlockState);
|
||||
|
||||
if (javaId.contains("sign[")) {
|
||||
JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaBlockState, javaId);
|
||||
}
|
||||
|
||||
// If the Java ID is bed, signal that it needs a tag to show color
|
||||
// The color is in the namespace ID in Java Edition but it's a tag in Bedrock.
|
||||
JsonNode bedColor = entry.getValue().get("bed_color");
|
||||
if (bedColor != null) {
|
||||
// Converting to byte because the final tag value is a byte. bedColor.binaryValue() returns an array
|
||||
BED_COLORS.put(javaBlockState, (byte) bedColor.intValue());
|
||||
}
|
||||
|
||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||
waterRuntimeId = bedrockRuntimeId;
|
||||
}
|
||||
boolean waterlogged = entry.getValue().has("waterlogged") && entry.getValue().get("waterlogged").booleanValue();
|
||||
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, javaBlockState);
|
||||
|
@ -137,6 +182,11 @@ public class BlockTranslator {
|
|||
bedrockRuntimeId++;
|
||||
}
|
||||
|
||||
if (cobwebRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find cobwebs in palette");
|
||||
}
|
||||
JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId;
|
||||
|
||||
if (waterRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find water in palette");
|
||||
}
|
||||
|
@ -203,6 +253,13 @@ public class BlockTranslator {
|
|||
return WATERLOGGED.contains(state.getId());
|
||||
}
|
||||
|
||||
public static byte getBedColor(BlockState state) {
|
||||
if (BED_COLORS.containsKey(state)) {
|
||||
return BED_COLORS.getByte(state);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static BlockState getJavaWaterloggedState(int bedrockId) {
|
||||
return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | bedrockId);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.geysermc.connector.network.translators.block.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BedBlockEntityTranslator {
|
||||
|
||||
public static void checkForBedColor(GeyserSession session, BlockState blockState, Vector3i position) {
|
||||
byte bedcolor = BlockTranslator.getBedColor(blockState);
|
||||
// If Bed Color is not -1 then it is indeed a bed with a color.
|
||||
if (bedcolor > -1) {
|
||||
Position pos = new Position(position.getX(), position.getY(), position.getZ());
|
||||
com.nukkitx.nbt.tag.CompoundTag finalbedTag = getBedTag(bedcolor, pos);
|
||||
// Delay needed, otherwise newly placed beds will not get their color
|
||||
// Delay is not needed for beds already placed on login
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
BlockEntityUtils.updateBlockEntity(session, finalbedTag, pos),
|
||||
500,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static com.nukkitx.nbt.tag.CompoundTag getBedTag(byte bedcolor, Position pos) {
|
||||
CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder()
|
||||
.intTag("x", pos.getX())
|
||||
.intTag("y", pos.getY())
|
||||
.intTag("z", pos.getZ())
|
||||
.stringTag("id", "Bed");
|
||||
tagBuilder.byteTag("color", bedcolor);
|
||||
return tagBuilder.buildRootTag();
|
||||
}
|
||||
|
||||
}
|
|
@ -34,11 +34,11 @@ public class ItemEntry {
|
|||
|
||||
public static ItemEntry AIR = new ItemEntry("minecraft:air", 0, 0, 0);
|
||||
|
||||
private String javaIdentifier;
|
||||
private int javaId;
|
||||
private final String javaIdentifier;
|
||||
private final int javaId;
|
||||
|
||||
private int bedrockId;
|
||||
private int bedrockData;
|
||||
private final int bedrockId;
|
||||
private final int bedrockData;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ToolItemEntry extends ItemEntry {
|
||||
private final String toolType;
|
||||
private final String toolTier;
|
||||
|
||||
public ToolItemEntry(String javaIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier) {
|
||||
super(javaIdentifier, javaId, bedrockId, bedrockData);
|
||||
this.toolType = toolType;
|
||||
this.toolTier = toolTier;
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -42,6 +43,7 @@ public class JavaEntityEffectTranslator extends PacketTranslator<ServerEntityEff
|
|||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
((PlayerEntity) entity).getEffectCache().addEffect(packet.getEffect(), packet.getAmplifier());
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -42,6 +43,7 @@ public class JavaEntityRemoveEffectTranslator extends PacketTranslator<ServerEnt
|
|||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
((PlayerEntity) entity).getEffectCache().removeEffect(packet.getEffect());
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
|
|
@ -25,22 +25,64 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.BlockUtils;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
||||
|
||||
@Translator(packet = ServerPlayerActionAckPacket.class)
|
||||
public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayerActionAckPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerPlayerActionAckPacket packet, GeyserSession session) {
|
||||
LevelEventPacket levelEvent = new LevelEventPacket();
|
||||
switch (packet.getAction()) {
|
||||
case FINISH_DIGGING:
|
||||
ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
|
||||
break;
|
||||
|
||||
case START_DIGGING:
|
||||
levelEvent.setType(LevelEventType.BLOCK_START_BREAK);
|
||||
levelEvent.setPosition(Vector3f.from(
|
||||
packet.getPosition().getX(),
|
||||
packet.getPosition().getY(),
|
||||
packet.getPosition().getZ()
|
||||
));
|
||||
double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(packet.getNewState().getId());
|
||||
PlayerInventory inventory = session.getInventory();
|
||||
ItemStack item = inventory.getItemInHand();
|
||||
ItemEntry itemEntry = null;
|
||||
CompoundTag nbtData = new CompoundTag("");
|
||||
if (item != null) {
|
||||
itemEntry = Translators.getItemTranslator().getItem(item);
|
||||
nbtData = item.getNbt();
|
||||
}
|
||||
double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState().getId(), itemEntry, nbtData, session.getPlayerEntity()) * 20);
|
||||
levelEvent.setData((int) (65535 / breakTime));
|
||||
session.getUpstream().sendPacket(levelEvent);
|
||||
break;
|
||||
|
||||
case CANCEL_DIGGING:
|
||||
levelEvent.setType(LevelEventType.BLOCK_STOP_BREAK);
|
||||
levelEvent.setPosition(Vector3f.from(
|
||||
packet.getPosition().getX(),
|
||||
packet.getPosition().getY(),
|
||||
packet.getPosition().getZ()
|
||||
));
|
||||
levelEvent.setData(0);
|
||||
session.getUpstream().sendPacket(levelEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -105,7 +105,16 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
|||
|
||||
ChunkUtils.updateBlock(session, new BlockState(blockEntityEntry.getIntKey()), new Position(x, y, z));
|
||||
}
|
||||
|
||||
for (Int2ObjectMap.Entry<CompoundTag> blockEntityEntry: chunkData.beds.int2ObjectEntrySet()) {
|
||||
int x = blockEntityEntry.getValue().getInt("x");
|
||||
int y = blockEntityEntry.getValue().getInt("y");
|
||||
int z = blockEntityEntry.getValue().getInt("z");
|
||||
|
||||
ChunkUtils.updateBlock(session, new BlockState(blockEntityEntry.getIntKey()), new Position(x, y, z));
|
||||
}
|
||||
chunkData.signs.clear();
|
||||
chunkData.beds.clear();
|
||||
} else {
|
||||
final int xOffset = packet.getColumn().getX() << 4;
|
||||
final int zOffset = packet.getColumn().getZ() << 4;
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.utils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ToolItemEntry;
|
||||
|
||||
public class BlockUtils {
|
||||
|
||||
private static boolean correctTool(String blockToolType, String itemToolType) {
|
||||
return (blockToolType.equals("sword") && itemToolType.equals("sword")) ||
|
||||
(blockToolType.equals("shovel") && itemToolType.equals("shovel")) ||
|
||||
(blockToolType.equals("pickaxe") && itemToolType.equals("pickaxe")) ||
|
||||
(blockToolType.equals("axe") && itemToolType.equals("axe")) ||
|
||||
(blockToolType.equals("shears") && itemToolType.equals("shears"));
|
||||
}
|
||||
|
||||
private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isWoolBlock) {
|
||||
if (toolType.equals("shears")) return isWoolBlock ? 5.0 : 15.0;
|
||||
if (toolType.equals("")) return 1.0;
|
||||
switch (toolTier) {
|
||||
case "wooden":
|
||||
return 2.0;
|
||||
case "stone":
|
||||
return 4.0;
|
||||
case "iron":
|
||||
return 6.0;
|
||||
case "diamond":
|
||||
return 8.0;
|
||||
case "golden":
|
||||
return 12.0;
|
||||
default:
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
//http://minecraft.gamepedia.com/Breaking
|
||||
private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool,
|
||||
String toolType, boolean isWoolBlock, boolean isCobweb, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel
|
||||
/*boolean insideOfWaterWithoutAquaAffinity, boolean outOfWaterButNotOnGround*/) {
|
||||
double baseTime = ((correctTool || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness;
|
||||
double speed = 1.0 / baseTime;
|
||||
|
||||
if (correctTool) {
|
||||
speed *= toolBreakTimeBonus(toolType, toolTier, isWoolBlock);
|
||||
speed += toolEfficiencyLevel == 0 ? 0 : toolEfficiencyLevel * toolEfficiencyLevel + 1;
|
||||
} else if (toolType.equals("sword")) {
|
||||
speed*= (isCobweb ? 15.0 : 1.5);
|
||||
}
|
||||
speed *= 1.0 + (0.2 * hasteLevel);
|
||||
|
||||
switch (miningFatigueLevel) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
speed -= (speed * 0.7);
|
||||
break;
|
||||
case 2:
|
||||
speed -= (speed * 0.91);
|
||||
break;
|
||||
case 3:
|
||||
speed -= (speed * 0.9973);
|
||||
break;
|
||||
default:
|
||||
speed -= (speed * 0.99919);
|
||||
break;
|
||||
}
|
||||
|
||||
//if (insideOfWaterWithoutAquaAffinity) speed *= 0.2;
|
||||
//if (outOfWaterButNotOnGround) speed *= 0.2;
|
||||
// else if insideWaterAndNotOnGround speed *= 0.2;
|
||||
return 1.0 / speed;
|
||||
}
|
||||
|
||||
public static double getBreakTime(double blockHardness, int blockId, ItemEntry item, CompoundTag nbtData, PlayerEntity player) {
|
||||
boolean isWoolBlock = BlockTranslator.JAVA_RUNTIME_WOOL_IDS.contains(blockId);
|
||||
boolean isCobweb = blockId == BlockTranslator.JAVA_RUNTIME_COBWEB_ID;
|
||||
String blockToolType = BlockTranslator.JAVA_RUNTIME_ID_TO_TOOL_TYPE.getOrDefault(blockId, "");
|
||||
boolean canHarvestWithHand = BlockTranslator.JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.get(blockId);
|
||||
String toolType = "";
|
||||
String toolTier = "";
|
||||
boolean correctTool = false;
|
||||
if (item instanceof ToolItemEntry) {
|
||||
ToolItemEntry toolItem = (ToolItemEntry) item;
|
||||
toolType = toolItem.getToolType();
|
||||
toolTier = toolItem.getToolTier();
|
||||
correctTool = correctTool(blockToolType, toolType);
|
||||
}
|
||||
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(nbtData, "minecraft:efficiency");
|
||||
int hasteLevel = player.getEffectCache().getEffectLevel(Effect.FASTER_DIG);
|
||||
int miningFatigueLevel = player.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
|
||||
|
||||
// TODO implement these checks and material check if possible
|
||||
//boolean insideOfWaterWithoutAquaAffinity = player.isInsideOfWater() &&
|
||||
// Optional.ofNullable(player.getInventory().getHelmet().getEnchantment(Enchantment.ID_WATER_WORKER))
|
||||
// .map(Enchantment::getLevel).map(l -> l >= 1).orElse(false);
|
||||
//boolean outOfWaterButNotOnGround = (!player.isInsideOfWater()) && (!player.isOnGround());
|
||||
return calculateBreakTime(blockHardness, toolTier, canHarvestWithHand, correctTool, toolType, isWoolBlock, isCobweb, toolEfficiencyLevel, hasteLevel, miningFatigueLevel);
|
||||
}
|
||||
|
||||
}
|
|
@ -44,6 +44,7 @@ import org.geysermc.connector.world.chunk.ChunkPosition;
|
|||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||
import org.geysermc.connector.world.chunk.ChunkSection;
|
||||
import org.geysermc.connector.network.translators.block.entity.BedBlockEntityTranslator;
|
||||
|
||||
import static org.geysermc.connector.network.translators.block.BlockTranslator.BEDROCK_WATER_ID;
|
||||
|
||||
|
@ -72,6 +73,9 @@ public class ChunkUtils {
|
|||
if (BlockTranslator.getBlockEntityString(blockState) != null && BlockTranslator.getBlockEntityString(blockState).contains("sign[")) {
|
||||
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
||||
chunkData.signs.put(blockState.getId(), Translators.getBlockEntityTranslators().get("Sign").getDefaultBedrockTag("Sign", pos.getX(), pos.getY(), pos.getZ()));
|
||||
} else if (BlockTranslator.getBedColor(blockState) > -1) {
|
||||
Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z);
|
||||
chunkData.beds.put(blockState.getId(), BedBlockEntityTranslator.getBedTag(BlockTranslator.getBedColor(blockState), pos));
|
||||
} else {
|
||||
section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id);
|
||||
}
|
||||
|
@ -128,6 +132,10 @@ public class ChunkUtils {
|
|||
waterPacket.setRuntimeId(0);
|
||||
}
|
||||
session.getUpstream().sendPacket(waterPacket);
|
||||
|
||||
// Since Java stores bed colors as part of the namespaced ID and Bedrock stores it as a tag
|
||||
// This is the only place I could find that interacts with the Java block state and block updates
|
||||
BedBlockEntityTranslator.checkForBedColor(session, blockState, position);
|
||||
}
|
||||
|
||||
public static void sendEmptyChunks(GeyserSession session, Vector3i position, int radius, boolean forceUpdate) {
|
||||
|
@ -160,5 +168,6 @@ public class ChunkUtils {
|
|||
|
||||
public com.nukkitx.nbt.tag.CompoundTag[] blockEntities = new com.nukkitx.nbt.tag.CompoundTag[0];
|
||||
public Int2ObjectMap<com.nukkitx.nbt.tag.CompoundTag> signs = new Int2ObjectOpenHashMap<>();
|
||||
public Int2ObjectMap<com.nukkitx.nbt.tag.CompoundTag> beds = new Int2ObjectOpenHashMap<>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.utils;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
|
||||
public class ItemUtils {
|
||||
|
||||
public static int getEnchantmentLevel(CompoundTag itemNBTData, String enchantmentId) {
|
||||
ListTag enchantments = (itemNBTData == null ? null : itemNBTData.get("Enchantments"));
|
||||
if (enchantments != null) {
|
||||
int enchantmentLevel = 0;
|
||||
for (Tag tag : enchantments) {
|
||||
CompoundTag enchantment = (CompoundTag) tag;
|
||||
StringTag enchantId = enchantment.get("id");
|
||||
if (enchantId.getValue().equals(enchantmentId)) {
|
||||
enchantmentLevel = (int) ((ShortTag) enchantment.get("lvl")).getValue();
|
||||
}
|
||||
}
|
||||
return enchantmentLevel;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ToolItemEntry;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -103,8 +104,28 @@ public class Toolbox {
|
|||
Iterator<Map.Entry<String, JsonNode>> iterator = items.fields();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = iterator.next();
|
||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry(entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue()));
|
||||
if (entry.getValue().has("tool_type")) {
|
||||
if (entry.getValue().has("tool_tier")) {
|
||||
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("tool_tier").textValue()));
|
||||
} 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(),
|
||||
""));
|
||||
}
|
||||
} else {
|
||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry(
|
||||
entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(),
|
||||
entry.getValue().get("bedrock_data").intValue()));
|
||||
}
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 278c73449aeeb4064c7513a68f98a49a5f463f0a
|
||||
Subproject commit efc9db6b7d51bdf145230933ac23b321ac1c132d
|
Loading…
Reference in a new issue