Player effect cache cleanup

Only cache effects and not their values unless we actually use the value.
This commit is contained in:
Camotoy 2021-08-16 11:53:56 -04:00
parent ce748990a4
commit ac17963baa
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
5 changed files with 352 additions and 322 deletions

View file

@ -1,54 +1,78 @@
/* /*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * 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 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
* *
* @author GeyserMC * @author GeyserMC
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.connector.network.session.cache; package org.geysermc.connector.network.session.cache;
import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.github.steveice10.mc.protocol.data.game.entity.Effect;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Getter;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import lombok.Getter; import java.util.EnumSet;
import java.util.Set;
public class EntityEffectCache {
public class EntityEffectCache {
@Getter /**
private final Object2IntMap<Effect> entityEffects = new Object2IntOpenHashMap<>(); * Used to clear effects on dimension switch.
*/
public void addEffect(Effect effect, int effectAmplifier) { @Getter
if (effect != null) { private final Set<Effect> entityEffects = EnumSet.noneOf(Effect.class);
entityEffects.putIfAbsent(effect, effectAmplifier + 1);
} /* Used to track mining speed */
} @Getter
private int conduitPower;
public void removeEffect(Effect effect) { @Getter
if (entityEffects.containsKey(effect)) { private int haste;
int effectLevel = entityEffects.getInt(effect); @Getter
entityEffects.remove(effect, effectLevel); private int miningFatigue;
}
} public void setEffect(Effect effect, int effectAmplifier) {
switch (effect) {
public int getEffectLevel(Effect effect) { case CONDUIT_POWER:
return entityEffects.getOrDefault(effect, 0); conduitPower = effectAmplifier + 1;
} break;
} case FASTER_DIG:
haste = effectAmplifier + 1;
break;
case SLOWER_DIG:
miningFatigue = effectAmplifier + 1;
break;
}
entityEffects.add(effect);
}
public void removeEffect(Effect effect) {
switch (effect) {
case CONDUIT_POWER:
conduitPower = 0;
break;
case FASTER_DIG:
haste = 0;
break;
case SLOWER_DIG:
miningFatigue = 0;
break;
}
entityEffects.remove(effect);
}
}

View file

@ -38,10 +38,12 @@ public class JavaEntityEffectTranslator extends PacketTranslator<ServerEntityEff
@Override @Override
public void translate(ServerEntityEffectPacket packet, GeyserSession session) { public void translate(ServerEntityEffectPacket packet, GeyserSession session) {
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); Entity entity;
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) { if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
entity = session.getPlayerEntity(); entity = session.getPlayerEntity();
session.getEffectCache().addEffect(packet.getEffect(), packet.getAmplifier()); session.getEffectCache().setEffect(packet.getEffect(), packet.getAmplifier());
} else {
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
} }
if (entity == null) if (entity == null)
return; return;

View file

@ -38,10 +38,12 @@ public class JavaEntityRemoveEffectTranslator extends PacketTranslator<ServerEnt
@Override @Override
public void translate(ServerEntityRemoveEffectPacket packet, GeyserSession session) { public void translate(ServerEntityRemoveEffectPacket packet, GeyserSession session) {
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); Entity entity;
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) { if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
entity = session.getPlayerEntity(); entity = session.getPlayerEntity();
session.getEffectCache().removeEffect(packet.getEffect()); session.getEffectCache().removeEffect(packet.getEffect());
} else {
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
} }
if (entity == null) if (entity == null)
return; return;

View file

@ -1,258 +1,257 @@
/* /*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * 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 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
* *
* @author GeyserMC * @author GeyserMC
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.connector.utils; package org.geysermc.connector.utils;
import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.math.vector.Vector3i; import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.inventory.GeyserItemStack; import org.geysermc.connector.inventory.PlayerInventory;
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.collision.translators.BlockCollision;
import org.geysermc.connector.network.translators.collision.translators.BlockCollision; import org.geysermc.connector.network.translators.world.block.BlockStateValues;
import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.registry.Registries;
import org.geysermc.connector.registry.Registries; import org.geysermc.connector.registry.type.BlockMapping;
import org.geysermc.connector.registry.type.BlockMapping; import org.geysermc.connector.registry.type.ItemMapping;
import org.geysermc.connector.registry.type.ItemMapping;
public class BlockUtils {
public class BlockUtils { /**
/** * A static constant of {@link Position} with all values being zero.
* A static constant of {@link Position} with all values being zero. */
*/ public static final Position POSITION_ZERO = new Position(0, 0, 0);
public static final Position POSITION_ZERO = new Position(0, 0, 0);
private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) {
private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) { switch (itemToolType) {
switch (itemToolType) { case "axe":
case "axe": return session.getTagCache().isAxeEffective(blockMapping);
return session.getTagCache().isAxeEffective(blockMapping); case "hoe":
case "hoe": return session.getTagCache().isHoeEffective(blockMapping);
return session.getTagCache().isHoeEffective(blockMapping); case "pickaxe":
case "pickaxe": return session.getTagCache().isPickaxeEffective(blockMapping);
return session.getTagCache().isPickaxeEffective(blockMapping); case "shears":
case "shears": return session.getTagCache().isShearsEffective(blockMapping);
return session.getTagCache().isShearsEffective(blockMapping); case "shovel":
case "shovel": return session.getTagCache().isShovelEffective(blockMapping);
return session.getTagCache().isShovelEffective(blockMapping); case "sword":
case "sword": return blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID;
return blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID; default:
default: session.getConnector().getLogger().warning("Unknown tool type: " + itemToolType);
session.getConnector().getLogger().warning("Unknown tool type: " + itemToolType); return false;
return false; }
} }
}
private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isShearsEffective) {
private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isShearsEffective) { if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0;
if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0; if (toolType.equals("")) return 1.0;
if (toolType.equals("")) return 1.0; switch (toolTier) {
switch (toolTier) { // https://minecraft.gamepedia.com/Breaking#Speed
// https://minecraft.gamepedia.com/Breaking#Speed case "wooden":
case "wooden": return 2.0;
return 2.0; case "stone":
case "stone": return 4.0;
return 4.0; case "iron":
case "iron": return 6.0;
return 6.0; case "diamond":
case "diamond": return 8.0;
return 8.0; case "netherite":
case "netherite": return 9.0;
return 9.0; case "golden":
case "golden": return 12.0;
return 12.0; default:
default: return 1.0;
return 1.0; }
} }
}
private static boolean canToolTierBreakBlock(GeyserSession session, BlockMapping blockMapping, String toolTier) {
private static boolean canToolTierBreakBlock(GeyserSession session, BlockMapping blockMapping, String toolTier) { if (toolTier.equals("netherite") || toolTier.equals("diamond")) {
if (toolTier.equals("netherite") || toolTier.equals("diamond")) { // As of 1.17, these tiers can mine everything that is mineable
// As of 1.17, these tiers can mine everything that is mineable return true;
return true; }
}
switch (toolTier) {
switch (toolTier) { // Use intentional fall-throughs to check each tier with this block
// Use intentional fall-throughs to check each tier with this block default:
default: if (session.getTagCache().requiresStoneTool(blockMapping)) {
if (session.getTagCache().requiresStoneTool(blockMapping)) { return false;
return false; }
} case "stone":
case "stone": if (session.getTagCache().requiresIronTool(blockMapping)) {
if (session.getTagCache().requiresIronTool(blockMapping)) { return false;
return false; }
} case "iron":
case "iron": if (session.getTagCache().requiresDiamondTool(blockMapping)) {
if (session.getTagCache().requiresDiamondTool(blockMapping)) { return false;
return false; }
} }
}
return true;
return true; }
}
// https://minecraft.gamepedia.com/Breaking
// https://minecraft.gamepedia.com/Breaking private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock,
private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock, String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel,
String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel, boolean insideOfWaterWithoutAquaAffinity, boolean outOfWaterButNotOnGround, boolean insideWaterAndNotOnGround) {
boolean insideOfWaterWithoutAquaAffinity, boolean outOfWaterButNotOnGround, boolean insideWaterAndNotOnGround) { double baseTime = (((correctTool && canTierMineBlock) || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness;
double baseTime = (((correctTool && canTierMineBlock) || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness; double speed = 1.0 / baseTime;
double speed = 1.0 / baseTime;
if (correctTool) {
if (correctTool) { speed *= toolBreakTimeBonus(toolType, toolTier, isShearsEffective);
speed *= toolBreakTimeBonus(toolType, toolTier, isShearsEffective); speed += toolEfficiencyLevel == 0 ? 0 : toolEfficiencyLevel * toolEfficiencyLevel + 1;
speed += toolEfficiencyLevel == 0 ? 0 : toolEfficiencyLevel * toolEfficiencyLevel + 1; }
} speed *= 1.0 + (0.2 * hasteLevel);
speed *= 1.0 + (0.2 * hasteLevel);
switch (miningFatigueLevel) {
switch (miningFatigueLevel) { case 0:
case 0: break;
break; case 1:
case 1: speed -= (speed * 0.7);
speed -= (speed * 0.7); break;
break; case 2:
case 2: speed -= (speed * 0.91);
speed -= (speed * 0.91); break;
break; case 3:
case 3: speed -= (speed * 0.9973);
speed -= (speed * 0.9973); break;
break; default:
default: speed -= (speed * 0.99919);
speed -= (speed * 0.99919); break;
break; }
}
if (insideOfWaterWithoutAquaAffinity) speed *= 0.2;
if (insideOfWaterWithoutAquaAffinity) speed *= 0.2; if (outOfWaterButNotOnGround) speed *= 0.2;
if (outOfWaterButNotOnGround) speed *= 0.2; if (insideWaterAndNotOnGround) speed *= 0.2;
if (insideWaterAndNotOnGround) speed *= 0.2; return 1.0 / speed;
return 1.0 / speed; }
}
public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, CompoundTag nbtData, boolean isSessionPlayer) {
public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, CompoundTag nbtData, boolean isSessionPlayer) { boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice
boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice boolean canHarvestWithHand = blockMapping.isCanBreakWithHand();
boolean canHarvestWithHand = blockMapping.isCanBreakWithHand(); String toolType = "";
String toolType = ""; String toolTier = "";
String toolTier = ""; boolean correctTool = false;
boolean correctTool = false; boolean toolCanBreak = false;
boolean toolCanBreak = false; if (item.isTool()) {
if (item.isTool()) { toolType = item.getToolType();
toolType = item.getToolType(); toolTier = item.getToolTier();
toolTier = item.getToolTier(); correctTool = correctTool(session, blockMapping, toolType);
correctTool = correctTool(session, blockMapping, toolType); toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier);
toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier); }
} int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(nbtData, "minecraft:efficiency");
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(nbtData, "minecraft:efficiency"); int hasteLevel = 0;
int hasteLevel = 0; int miningFatigueLevel = 0;
int miningFatigueLevel = 0;
if (!isSessionPlayer) {
if (!isSessionPlayer) { // Another entity is currently mining; we have all the information we know
// Another entity is currently mining; we have all the information we know return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false,
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, false, false);
false, false); }
}
hasteLevel = Math.max(session.getEffectCache().getHaste(), session.getEffectCache().getConduitPower());
hasteLevel = Math.max(session.getEffectCache().getEffectLevel(Effect.FASTER_DIG), session.getEffectCache().getEffectLevel(Effect.CONDUIT_POWER)); miningFatigueLevel = session.getEffectCache().getMiningFatigue();
miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
boolean isInWater = session.getCollisionManager().isPlayerInWater();
boolean isInWater = session.getCollisionManager().isPlayerInWater();
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
boolean insideOfWaterWithoutAquaAffinity = isInWater && ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
boolean outOfWaterButNotOnGround = (!isInWater) && (!session.getPlayerEntity().isOnGround());
boolean outOfWaterButNotOnGround = (!isInWater) && (!session.getPlayerEntity().isOnGround()); boolean insideWaterNotOnGround = isInWater && !session.getPlayerEntity().isOnGround();
boolean insideWaterNotOnGround = isInWater && !session.getPlayerEntity().isOnGround(); return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity,
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, outOfWaterButNotOnGround, insideWaterNotOnGround);
outOfWaterButNotOnGround, insideWaterNotOnGround); }
}
public static double getSessionBreakTime(GeyserSession session, BlockMapping blockMapping) {
public static double getSessionBreakTime(GeyserSession session, BlockMapping blockMapping) { PlayerInventory inventory = session.getPlayerInventory();
PlayerInventory inventory = session.getPlayerInventory(); GeyserItemStack item = inventory.getItemInHand();
GeyserItemStack item = inventory.getItemInHand(); ItemMapping mapping;
ItemMapping mapping; CompoundTag nbtData;
CompoundTag nbtData; if (item != null) {
if (item != null) { mapping = item.getMapping(session);
mapping = item.getMapping(session); nbtData = item.getNbt();
nbtData = item.getNbt(); } else {
} else { mapping = ItemMapping.AIR;
mapping = ItemMapping.AIR; nbtData = new CompoundTag("");
nbtData = new CompoundTag(""); }
} return getBreakTime(session, blockMapping, mapping, nbtData, true);
return getBreakTime(session, blockMapping, mapping, nbtData, true); }
}
/**
/** * Given a position, return the position if a block were located on the specified block face.
* Given a position, return the position if a block were located on the specified block face. * @param blockPos the block position
* @param blockPos the block position * @param face the face of the block - see {@link com.github.steveice10.mc.protocol.data.game.world.block.BlockFace}
* @param face the face of the block - see {@link com.github.steveice10.mc.protocol.data.game.world.block.BlockFace} * @return the block position with the block face accounted for
* @return the block position with the block face accounted for */
*/ public static Vector3i getBlockPosition(Vector3i blockPos, int face) {
public static Vector3i getBlockPosition(Vector3i blockPos, int face) { switch (face) {
switch (face) { case 0:
case 0: return blockPos.sub(0, 1, 0);
return blockPos.sub(0, 1, 0); case 1:
case 1: return blockPos.add(0, 1, 0);
return blockPos.add(0, 1, 0); case 2:
case 2: return blockPos.sub(0, 0, 1);
return blockPos.sub(0, 0, 1); case 3:
case 3: return blockPos.add(0, 0, 1);
return blockPos.add(0, 0, 1); case 4:
case 4: return blockPos.sub(1, 0, 0);
return blockPos.sub(1, 0, 0); case 5:
case 5: return blockPos.add(1, 0, 0);
return blockPos.add(1, 0, 0); }
} return blockPos;
return blockPos; }
}
/**
/** * Taking in a complete Java block state identifier, output just the block ID of this block state without the states.
* Taking in a complete Java block state identifier, output just the block ID of this block state without the states. * Examples:
* Examples: * minecraft:oak_log[axis=x] = minecraft:oak_log
* minecraft:oak_log[axis=x] = minecraft:oak_log * minecraft:stone_brick_wall[east=low,north=tall,south=none,up=true,waterlogged=false,west=tall] = minecraft:stone_brick_wall
* minecraft:stone_brick_wall[east=low,north=tall,south=none,up=true,waterlogged=false,west=tall] = minecraft:stone_brick_wall * minecraft:stone = minecraft:stone
* minecraft:stone = minecraft:stone *
* * @param fullJavaIdentifier a full Java block identifier, with possible block states.
* @param fullJavaIdentifier a full Java block identifier, with possible block states. * @return a clean identifier in the format of minecraft:block
* @return a clean identifier in the format of minecraft:block */
*/ public static String getCleanIdentifier(String fullJavaIdentifier) {
public static String getCleanIdentifier(String fullJavaIdentifier) { int stateIndex = fullJavaIdentifier.indexOf('[');
int stateIndex = fullJavaIdentifier.indexOf('['); if (stateIndex == -1) {
if (stateIndex == -1) { // Identical to its clean variation
// Identical to its clean variation return fullJavaIdentifier;
return fullJavaIdentifier; }
} return fullJavaIdentifier.substring(0, stateIndex);
return fullJavaIdentifier.substring(0, stateIndex); }
}
public static BlockCollision getCollision(int blockId, Vector3i blockPos) {
public static BlockCollision getCollision(int blockId, Vector3i blockPos) { BlockCollision collision = Registries.COLLISIONS.get(blockId);
BlockCollision collision = Registries.COLLISIONS.get(blockId); if (collision != null) {
if (collision != null) { collision.setPosition(blockPos);
collision.setPosition(blockPos); }
} return collision;
return collision; }
}
public static BlockCollision getCollisionAt(GeyserSession session, Vector3i blockPos) {
public static BlockCollision getCollisionAt(GeyserSession session, Vector3i blockPos) { return getCollision(session.getConnector().getWorldManager().getBlockAt(session, blockPos), blockPos);
return getCollision(session.getConnector().getWorldManager().getBlockAt(session, blockPos), blockPos); }
} }
}

View file

@ -28,7 +28,7 @@ package org.geysermc.connector.utils;
import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.github.steveice10.mc.protocol.data.game.entity.Effect;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.nukkitx.math.vector.Vector3i; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.ChangeDimensionPacket; import com.nukkitx.protocol.bedrock.packet.ChangeDimensionPacket;
import com.nukkitx.protocol.bedrock.packet.MobEffectPacket; import com.nukkitx.protocol.bedrock.packet.MobEffectPacket;
import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; import com.nukkitx.protocol.bedrock.packet.StopSoundPacket;
@ -36,6 +36,8 @@ import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import java.util.Set;
public class DimensionUtils { public class DimensionUtils {
// Changes if the above-bedrock Nether building workaround is applied // Changes if the above-bedrock Nether building workaround is applied
@ -63,27 +65,28 @@ public class DimensionUtils {
session.getLecternCache().clear(); session.getLecternCache().clear();
session.getSkullCache().clear(); session.getSkullCache().clear();
Vector3i pos = Vector3i.from(0, Short.MAX_VALUE, 0); Vector3f pos = Vector3f.from(0, Short.MAX_VALUE, 0);
ChangeDimensionPacket changeDimensionPacket = new ChangeDimensionPacket(); ChangeDimensionPacket changeDimensionPacket = new ChangeDimensionPacket();
changeDimensionPacket.setDimension(bedrockDimension); changeDimensionPacket.setDimension(bedrockDimension);
changeDimensionPacket.setRespawn(true); changeDimensionPacket.setRespawn(true);
changeDimensionPacket.setPosition(pos.toFloat()); changeDimensionPacket.setPosition(pos);
session.sendUpstreamPacket(changeDimensionPacket); session.sendUpstreamPacket(changeDimensionPacket);
session.setDimension(javaDimension); session.setDimension(javaDimension);
player.setPosition(pos.toFloat()); player.setPosition(pos);
session.setSpawned(false); session.setSpawned(false);
session.setLastChunkPosition(null); session.setLastChunkPosition(null);
for (Effect effect : session.getEffectCache().getEntityEffects().keySet()) { Set<Effect> entityEffects = session.getEffectCache().getEntityEffects();
for (Effect effect : entityEffects) {
MobEffectPacket mobEffectPacket = new MobEffectPacket(); MobEffectPacket mobEffectPacket = new MobEffectPacket();
mobEffectPacket.setEvent(MobEffectPacket.Event.REMOVE); mobEffectPacket.setEvent(MobEffectPacket.Event.REMOVE);
mobEffectPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); mobEffectPacket.setRuntimeEntityId(player.getGeyserId());
mobEffectPacket.setEffectId(EntityUtils.toBedrockEffectId(effect)); mobEffectPacket.setEffectId(EntityUtils.toBedrockEffectId(effect));
session.sendUpstreamPacket(mobEffectPacket); session.sendUpstreamPacket(mobEffectPacket);
} }
// Effects are re-sent from server // Effects are re-sent from server
session.getEffectCache().getEntityEffects().clear(); entityEffects.clear();
//let java server handle portal travel sound //let java server handle portal travel sound
StopSoundPacket stopSoundPacket = new StopSoundPacket(); StopSoundPacket stopSoundPacket = new StopSoundPacket();