mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Block breaking animations
This commit is contained in:
commit
4a8aeda677
14 changed files with 379 additions and 7 deletions
|
@ -48,6 +48,24 @@
|
||||||
<version>8.1.1</version>
|
<version>8.1.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</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>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-object-byte-maps</artifactId>
|
<artifactId>fastutil-object-byte-maps</artifactId>
|
||||||
|
|
|
@ -39,6 +39,7 @@ import lombok.Setter;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
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.session.cache.EntityEffectCache;
|
||||||
import org.geysermc.connector.utils.SkinUtils;
|
import org.geysermc.connector.utils.SkinUtils;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -50,6 +51,7 @@ public class PlayerEntity extends LivingEntity {
|
||||||
private String username;
|
private String username;
|
||||||
private long lastSkinUpdate = -1;
|
private long lastSkinUpdate = -1;
|
||||||
private boolean playerList = true;
|
private boolean playerList = true;
|
||||||
|
private final EntityEffectCache effectCache;
|
||||||
|
|
||||||
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
||||||
|
@ -57,6 +59,7 @@ public class PlayerEntity extends LivingEntity {
|
||||||
profile = gameProfile;
|
profile = gameProfile;
|
||||||
uuid = gameProfile.getId();
|
uuid = gameProfile.getId();
|
||||||
username = gameProfile.getName();
|
username = gameProfile.getName();
|
||||||
|
effectCache = new EntityEffectCache();
|
||||||
if (geyserId == 1) valid = true;
|
if (geyserId == 1) valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,6 @@ public class PlayerInventory extends Inventory {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack getItemInHand() {
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,12 +47,15 @@ public class Registry<T> {
|
||||||
BEDROCK.MAP.put(clazz, translator);
|
BEDROCK.MAP.put(clazz, translator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||||
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||||
try {
|
try {
|
||||||
if (MAP.containsKey(clazz)) {
|
if (MAP.containsKey(clazz)) {
|
||||||
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||||
}
|
}
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||||
|
|
|
@ -54,6 +54,13 @@ public class BlockTranslator {
|
||||||
private static final Object2ByteOpenHashMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
|
private static final Object2ByteOpenHashMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
|
||||||
|
|
||||||
private static final Map<BlockState, String> JAVA_ID_TO_BLOCK_ENTITY_MAP = new HashMap<>();
|
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;
|
private static final int BLOCK_STATE_VERSION = 17760256;
|
||||||
|
|
||||||
|
@ -89,6 +96,7 @@ public class BlockTranslator {
|
||||||
int waterRuntimeId = -1;
|
int waterRuntimeId = -1;
|
||||||
int javaRuntimeId = -1;
|
int javaRuntimeId = -1;
|
||||||
int bedrockRuntimeId = 0;
|
int bedrockRuntimeId = 0;
|
||||||
|
int cobwebRuntimeId = -1;
|
||||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
||||||
while (blocksIterator.hasNext()) {
|
while (blocksIterator.hasNext()) {
|
||||||
javaRuntimeId++;
|
javaRuntimeId++;
|
||||||
|
@ -97,6 +105,27 @@ public class BlockTranslator {
|
||||||
BlockState javaBlockState = new BlockState(javaRuntimeId);
|
BlockState javaBlockState = new BlockState(javaRuntimeId);
|
||||||
CompoundTag blockTag = buildBedrockState(entry.getValue());
|
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);
|
JAVA_ID_BLOCK_MAP.put(javaId, javaBlockState);
|
||||||
|
|
||||||
if (javaId.contains("sign[")) {
|
if (javaId.contains("sign[")) {
|
||||||
|
@ -142,6 +171,11 @@ public class BlockTranslator {
|
||||||
bedrockRuntimeId++;
|
bedrockRuntimeId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cobwebRuntimeId == -1) {
|
||||||
|
throw new AssertionError("Unable to find cobwebs in palette");
|
||||||
|
}
|
||||||
|
JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId;
|
||||||
|
|
||||||
if (waterRuntimeId == -1) {
|
if (waterRuntimeId == -1) {
|
||||||
throw new AssertionError("Unable to find water in palette");
|
throw new AssertionError("Unable to find water in palette");
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,11 @@ public class ItemEntry {
|
||||||
|
|
||||||
public static ItemEntry AIR = new ItemEntry("minecraft:air", 0, 0, 0);
|
public static ItemEntry AIR = new ItemEntry("minecraft:air", 0, 0, 0);
|
||||||
|
|
||||||
private String javaIdentifier;
|
private final String javaIdentifier;
|
||||||
private int javaId;
|
private final int javaId;
|
||||||
|
|
||||||
private int bedrockId;
|
private final int bedrockId;
|
||||||
private int bedrockData;
|
private final int bedrockData;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.java.entity;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityEffectPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityEffectPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MobEffectPacket;
|
import com.nukkitx.protocol.bedrock.packet.MobEffectPacket;
|
||||||
import org.geysermc.connector.entity.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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.utils.EntityUtils;
|
import org.geysermc.connector.utils.EntityUtils;
|
||||||
|
@ -39,6 +40,7 @@ public class JavaEntityEffectTranslator extends PacketTranslator<ServerEntityEff
|
||||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||||
entity = session.getPlayerEntity();
|
entity = session.getPlayerEntity();
|
||||||
|
((PlayerEntity) entity).getEffectCache().addEffect(packet.getEffect(), packet.getAmplifier());
|
||||||
}
|
}
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.java.entity;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRemoveEffectPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRemoveEffectPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MobEffectPacket;
|
import com.nukkitx.protocol.bedrock.packet.MobEffectPacket;
|
||||||
import org.geysermc.connector.entity.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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.utils.EntityUtils;
|
import org.geysermc.connector.utils.EntityUtils;
|
||||||
|
@ -39,6 +40,7 @@ public class JavaEntityRemoveEffectTranslator extends PacketTranslator<ServerEnt
|
||||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||||
entity = session.getPlayerEntity();
|
entity = session.getPlayerEntity();
|
||||||
|
((PlayerEntity) entity).getEffectCache().removeEffect(packet.getEffect());
|
||||||
}
|
}
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -25,19 +25,64 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.java.entity.player;
|
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.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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.TranslatorsInit;
|
||||||
|
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.utils.ChunkUtils;
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
|
||||||
public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayerActionAckPacket> {
|
public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayerActionAckPacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerPlayerActionAckPacket packet, GeyserSession session) {
|
public void translate(ServerPlayerActionAckPacket packet, GeyserSession session) {
|
||||||
|
LevelEventPacket levelEvent = new LevelEventPacket();
|
||||||
switch (packet.getAction()) {
|
switch (packet.getAction()) {
|
||||||
case FINISH_DIGGING:
|
case FINISH_DIGGING:
|
||||||
ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
|
ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
|
||||||
break;
|
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 = TranslatorsInit.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.GeyserConnector;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ToolItemEntry;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -103,8 +104,28 @@ public class Toolbox {
|
||||||
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();
|
Map.Entry<String, JsonNode> entry = iterator.next();
|
||||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry(entry.getKey(), itemIndex,
|
if (entry.getValue().has("tool_type")) {
|
||||||
entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue()));
|
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++;
|
itemIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue