mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Merge 089d96c81f into 4f7e9fca9c
This commit is contained in:
commit
0cbd3092bf
11 changed files with 246 additions and 65 deletions
|
|
@ -93,7 +93,7 @@ public final class EntityDefinitions {
|
||||||
public static final EntityDefinition<EvokerFangsEntity> EVOKER_FANGS;
|
public static final EntityDefinition<EvokerFangsEntity> EVOKER_FANGS;
|
||||||
public static final EntityDefinition<ThrowableItemEntity> EXPERIENCE_BOTTLE;
|
public static final EntityDefinition<ThrowableItemEntity> EXPERIENCE_BOTTLE;
|
||||||
public static final EntityDefinition<ExpOrbEntity> EXPERIENCE_ORB;
|
public static final EntityDefinition<ExpOrbEntity> EXPERIENCE_ORB;
|
||||||
public static final EntityDefinition<Entity> EYE_OF_ENDER;
|
public static final EntityDefinition<EnderEyeEntity> EYE_OF_ENDER;
|
||||||
public static final EntityDefinition<FallingBlockEntity> FALLING_BLOCK;
|
public static final EntityDefinition<FallingBlockEntity> FALLING_BLOCK;
|
||||||
public static final EntityDefinition<FireballEntity> FIREBALL;
|
public static final EntityDefinition<FireballEntity> FIREBALL;
|
||||||
public static final EntityDefinition<FireworkEntity> FIREWORK_ROCKET;
|
public static final EntityDefinition<FireworkEntity> FIREWORK_ROCKET;
|
||||||
|
|
@ -250,7 +250,7 @@ public final class EntityDefinitions {
|
||||||
.height(0.8f).width(0.5f)
|
.height(0.8f).width(0.5f)
|
||||||
.identifier("minecraft:evocation_fang")
|
.identifier("minecraft:evocation_fang")
|
||||||
.build();
|
.build();
|
||||||
EYE_OF_ENDER = EntityDefinition.inherited(Entity::new, entityBase)
|
EYE_OF_ENDER = EntityDefinition.inherited(EnderEyeEntity::new, entityBase)
|
||||||
.type(EntityType.EYE_OF_ENDER)
|
.type(EntityType.EYE_OF_ENDER)
|
||||||
.heightAndWidth(0.25f)
|
.heightAndWidth(0.25f)
|
||||||
.identifier("minecraft:eye_of_ender_signal")
|
.identifier("minecraft:eye_of_ender_signal")
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||||
doTick = !doTick; // Run every 100 ms
|
doTick = !doTick; // Run every other tick
|
||||||
if (!doTick || passengers.isEmpty()) {
|
if (!doTick || passengers.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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.geyser.entity.type;
|
||||||
|
|
||||||
|
|
||||||
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class EnderEyeEntity extends Entity {
|
||||||
|
public EnderEyeEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initializeMetadata() {
|
||||||
|
super.initializeMetadata();
|
||||||
|
// Correct sizing
|
||||||
|
dirtyMetadata.put(EntityDataTypes.SCALE, 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -429,3 +429,4 @@ public class LivingEntity extends Entity {
|
||||||
return type.getAttribute((float) AttributeUtils.calculateValue(javaAttribute));
|
return type.getAttribute((float) AttributeUtils.calculateValue(javaAttribute));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,13 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.entity.type;
|
package org.geysermc.geyser.entity.type;
|
||||||
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public class ThrowableItemEntity extends ThrowableEntity {
|
public class ThrowableItemEntity extends ThrowableEntity {
|
||||||
/**
|
/**
|
||||||
* Number of ticks since the entity was spawned by the Java server
|
* Number of draw ticks since the entity was spawned by the Java server
|
||||||
*/
|
*/
|
||||||
private int age;
|
private int age;
|
||||||
private boolean invisible;
|
private boolean invisible;
|
||||||
|
|
@ -48,29 +49,37 @@ public class ThrowableItemEntity extends ThrowableEntity {
|
||||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
setFlag(EntityFlag.INVISIBLE, true);
|
setFlag(EntityFlag.INVISIBLE, true);
|
||||||
invisible = false;
|
invisible = false;
|
||||||
}
|
age = 1;
|
||||||
|
|
||||||
private void checkVisibility() {
|
|
||||||
if (invisible != getFlag(EntityFlag.INVISIBLE)) {
|
|
||||||
if (!invisible) {
|
|
||||||
Vector3f playerPos = session.getPlayerEntity().getPosition();
|
|
||||||
// Prevent projectiles from blocking the player's screen
|
|
||||||
if (age >= 4 || position.distanceSquared(playerPos) > 16) {
|
|
||||||
setFlag(EntityFlag.INVISIBLE, false);
|
|
||||||
updateBedrockMetadata();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setFlag(EntityFlag.INVISIBLE, true);
|
|
||||||
updateBedrockMetadata();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
age++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
protected void initializeMetadata() {
|
||||||
|
super.initializeMetadata();
|
||||||
|
// Correct sizing
|
||||||
|
dirtyMetadata.put(EntityDataTypes.SCALE, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkVisibility() {
|
||||||
|
age++;
|
||||||
|
|
||||||
|
// Prevent projectiles from blocking the player's screen
|
||||||
|
if (session.isTickingFrozen()) {
|
||||||
|
Vector3f playerPos = session.getPlayerEntity().getPosition().sub(0, session.getPlayerEntity().getDefinition().offset(), 0);
|
||||||
|
setInvisible(playerPos.distanceSquared(position.add(0, definition.offset(), 0)) < 12.25);
|
||||||
|
} else {
|
||||||
|
setInvisible(age <= 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invisible != getFlag(EntityFlag.INVISIBLE)) {
|
||||||
|
setFlag(EntityFlag.INVISIBLE, invisible);
|
||||||
|
updateBedrockMetadata();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTick() {
|
||||||
checkVisibility();
|
checkVisibility();
|
||||||
super.tick();
|
super.drawTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
* Copyright (c) 2019-2024 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
|
||||||
|
|
@ -26,8 +26,21 @@
|
||||||
package org.geysermc.geyser.entity.type;
|
package org.geysermc.geyser.entity.type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implemented onto anything that should have code ran every Minecraft tick - 50 milliseconds.
|
* Implemented onto anything that should have code ran every Minecraft tick.
|
||||||
|
* By default, the Java server runs at 20 TPS, 50 milliseconds for each tick.
|
||||||
*/
|
*/
|
||||||
public interface Tickable {
|
public interface Tickable {
|
||||||
|
/**
|
||||||
|
* This function gets called every tick at all times, even when the server requests that
|
||||||
|
* the game should be frozen. This should be used for updating things that are always
|
||||||
|
* client side updated on Java, regardless of if the server is frozen or not.
|
||||||
|
*/
|
||||||
|
default void drawTick() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function gets called every game tick as long as the
|
||||||
|
* game tick loop isn't frozen.
|
||||||
|
*/
|
||||||
void tick();
|
void tick();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
* Copyright (c) 2019-2024 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
|
||||||
|
|
@ -172,6 +172,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
import org.geysermc.geyser.util.ChunkUtils;
|
import org.geysermc.geyser.util.ChunkUtils;
|
||||||
import org.geysermc.geyser.util.DimensionUtils;
|
import org.geysermc.geyser.util.DimensionUtils;
|
||||||
import org.geysermc.geyser.util.EntityUtils;
|
import org.geysermc.geyser.util.EntityUtils;
|
||||||
|
import org.geysermc.geyser.util.MathUtils;
|
||||||
import org.geysermc.geyser.util.LoginEncryptionUtils;
|
import org.geysermc.geyser.util.LoginEncryptionUtils;
|
||||||
import org.geysermc.geyser.util.MinecraftAuthLogger;
|
import org.geysermc.geyser.util.MinecraftAuthLogger;
|
||||||
import org.geysermc.mcprotocollib.auth.GameProfile;
|
import org.geysermc.mcprotocollib.auth.GameProfile;
|
||||||
|
|
@ -598,7 +599,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
private boolean advancedTooltips = false;
|
private boolean advancedTooltips = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The thread that will run every 50 milliseconds - one Minecraft tick.
|
* The thread that will run every game tick.
|
||||||
*/
|
*/
|
||||||
private ScheduledFuture<?> tickThread = null;
|
private ScheduledFuture<?> tickThread = null;
|
||||||
|
|
||||||
|
|
@ -629,7 +630,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
/**
|
/**
|
||||||
* Stores cookies sent by the Java server.
|
* Stores cookies sent by the Java server.
|
||||||
*/
|
*/
|
||||||
@Setter @Getter
|
@Setter
|
||||||
private Map<String, byte[]> cookies = new Object2ObjectOpenHashMap<>();
|
private Map<String, byte[]> cookies = new Object2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
private final GeyserCameraData cameraData;
|
private final GeyserCameraData cameraData;
|
||||||
|
|
@ -638,6 +639,17 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
|
|
||||||
private MinecraftProtocol protocol;
|
private MinecraftProtocol protocol;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private int nanosecondsPerTick = 50000000;
|
||||||
|
@Getter
|
||||||
|
private float millisecondsPerTick = 50.0f;
|
||||||
|
private boolean tickingFrozen = false;
|
||||||
|
/**
|
||||||
|
* The amount of ticks requested by the server that the game should proceed with, even if the game tick loop is frozen.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private int stepTicks = 0;
|
||||||
|
|
||||||
public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop eventLoop) {
|
public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop eventLoop) {
|
||||||
this.geyser = geyser;
|
this.geyser = geyser;
|
||||||
this.upstream = new UpstreamSession(bedrockServerSession);
|
this.upstream = new UpstreamSession(bedrockServerSession);
|
||||||
|
|
@ -860,31 +872,31 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
}
|
}
|
||||||
task.cleanup(); // player is online -> remove pending authentication immediately
|
task.cleanup(); // player is online -> remove pending authentication immediately
|
||||||
return task.getAuthentication().handle((result, ex) -> {
|
return task.getAuthentication().handle((result, ex) -> {
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
geyser.getLogger().error("Failed to log in with Microsoft code!", ex);
|
geyser.getLogger().error("Failed to log in with Microsoft code!", ex);
|
||||||
disconnect(ex.toString());
|
disconnect(ex.toString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StepMCProfile.MCProfile mcProfile = result.session().getMcProfile();
|
StepMCProfile.MCProfile mcProfile = result.session().getMcProfile();
|
||||||
StepMCToken.MCToken mcToken = mcProfile.getMcToken();
|
StepMCToken.MCToken mcToken = mcProfile.getMcToken();
|
||||||
|
|
||||||
this.protocol = new MinecraftProtocol(
|
this.protocol = new MinecraftProtocol(
|
||||||
new GameProfile(mcProfile.getId(), mcProfile.getName()),
|
new GameProfile(mcProfile.getId(), mcProfile.getName()),
|
||||||
mcToken.getAccessToken()
|
mcToken.getAccessToken()
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
connectDownstream();
|
connectDownstream();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save our auth chain for later use
|
// Save our auth chain for later use
|
||||||
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session())));
|
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session())));
|
||||||
return true;
|
return true;
|
||||||
}).getNow(false);
|
}).getNow(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -905,7 +917,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE;
|
boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE;
|
||||||
|
|
||||||
// Start ticking
|
// Start ticking
|
||||||
tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
|
tickThread = eventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS);
|
||||||
|
|
||||||
this.protocol.setUseDefaultListeners(false);
|
this.protocol.setUseDefaultListeners(false);
|
||||||
|
|
||||||
|
|
@ -1222,8 +1234,17 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
}, duration, timeUnit);
|
}, duration, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateTickingState(float tickRate, boolean frozen) {
|
||||||
|
tickThread.cancel(false);
|
||||||
|
this.tickingFrozen = frozen;
|
||||||
|
millisecondsPerTick = 1000.0f / tickRate;
|
||||||
|
|
||||||
|
nanosecondsPerTick = MathUtils.ceil(1000000000.0f / MathUtils.clamp(tickRate, 1.0f, 10000.0f));
|
||||||
|
tickThread = eventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called every 50 milliseconds - one Minecraft tick.
|
* Called every Minecraft tick.
|
||||||
*/
|
*/
|
||||||
protected void tick() {
|
protected void tick() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -1261,9 +1282,15 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
isInWorldBorderWarningArea = false;
|
isInWorldBorderWarningArea = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean gameShouldUpdate = !tickingFrozen || stepTicks > 0;
|
||||||
|
if (stepTicks > 0) {
|
||||||
|
--stepTicks;
|
||||||
|
}
|
||||||
for (Tickable entity : entityCache.getTickableEntities()) {
|
for (Tickable entity : entityCache.getTickableEntities()) {
|
||||||
entity.tick();
|
entity.drawTick();
|
||||||
|
if (gameShouldUpdate) {
|
||||||
|
entity.tick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (armAnimationTicks >= 0) {
|
if (armAnimationTicks >= 0) {
|
||||||
|
|
@ -1792,7 +1819,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
* Send a gamerule value to the client
|
* Send a gamerule value to the client
|
||||||
*
|
*
|
||||||
* @param gameRule The gamerule to send
|
* @param gameRule The gamerule to send
|
||||||
* @param value The value of the gamerule
|
* @param value The value of the gamerule
|
||||||
*/
|
*/
|
||||||
public void sendGameRule(String gameRule, Object value) {
|
public void sendGameRule(String gameRule, Object value) {
|
||||||
GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket();
|
GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket();
|
||||||
|
|
@ -1993,7 +2020,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID javaUuid() {
|
public UUID javaUuid() {
|
||||||
return playerEntity != null ? playerEntity.getUuid() : null ;
|
return playerEntity != null ? playerEntity.getUuid() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
|
||||||
// (No need to send a release item packet - Java doesn't do this when swapping items)
|
// (No need to send a release item packet - Java doesn't do this when swapping items)
|
||||||
// Required to do it a tick later or else it doesn't register
|
// Required to do it a tick later or else it doesn't register
|
||||||
session.scheduleInEventLoop(() -> session.useItem(Hand.MAIN_HAND),
|
session.scheduleInEventLoop(() -> session.useItem(Hand.MAIN_HAND),
|
||||||
50, TimeUnit.MILLISECONDS);
|
session.getNanosecondsPerTick(), TimeUnit.NANOSECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldItem.getJavaId() != newItem.getJavaId()) {
|
if (oldItem.getJavaId() != newItem.getJavaId()) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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.geyser.translator.protocol.java;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTickingStatePacket;
|
||||||
|
|
||||||
|
@Translator(packet = ClientboundTickingStatePacket.class)
|
||||||
|
public class JavaTickingStateTranslator extends PacketTranslator<ClientboundTickingStatePacket> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translate(GeyserSession session, ClientboundTickingStatePacket packet) {
|
||||||
|
session.updateTickingState(packet.getTickRate(), packet.isFrozen());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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.geyser.translator.protocol.java;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTickingStepPacket;
|
||||||
|
|
||||||
|
@Translator(packet = ClientboundTickingStepPacket.class)
|
||||||
|
public class JavaTickingStepTranslator extends PacketTranslator<ClientboundTickingStepPacket> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translate(GeyserSession session, ClientboundTickingStepPacket packet) {
|
||||||
|
session.setStepTicks(packet.getTickSteps());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -50,6 +50,7 @@ public class CooldownUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts sending the fake cooldown to the Bedrock client. If the cooldown is not disabled, the sent type is the cooldownPreference in {@link PreferencesCache}
|
* Starts sending the fake cooldown to the Bedrock client. If the cooldown is not disabled, the sent type is the cooldownPreference in {@link PreferencesCache}
|
||||||
|
*
|
||||||
* @param session GeyserSession
|
* @param session GeyserSession
|
||||||
*/
|
*/
|
||||||
public static void sendCooldown(GeyserSession session) {
|
public static void sendCooldown(GeyserSession session) {
|
||||||
|
|
@ -57,7 +58,8 @@ public class CooldownUtils {
|
||||||
CooldownType sessionPreference = session.getPreferencesCache().getCooldownPreference();
|
CooldownType sessionPreference = session.getPreferencesCache().getCooldownPreference();
|
||||||
if (sessionPreference == CooldownType.DISABLED) return;
|
if (sessionPreference == CooldownType.DISABLED) return;
|
||||||
|
|
||||||
if (session.getAttackSpeed() == 0.0 || session.getAttackSpeed() > 20) return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used
|
if (session.getAttackSpeed() == 0.0 || session.getAttackSpeed() > 20)
|
||||||
|
return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used
|
||||||
// Set the times to stay a bit with no fade in nor out
|
// Set the times to stay a bit with no fade in nor out
|
||||||
SetTitlePacket titlePacket = new SetTitlePacket();
|
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||||
titlePacket.setType(SetTitlePacket.Type.TIMES);
|
titlePacket.setType(SetTitlePacket.Type.TIMES);
|
||||||
|
|
@ -83,13 +85,15 @@ public class CooldownUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps updating the cooldown until the bar is complete.
|
* Keeps updating the cooldown until the bar is complete.
|
||||||
|
*
|
||||||
* @param session GeyserSession
|
* @param session GeyserSession
|
||||||
* @param sessionPreference The type of cooldown the client prefers
|
* @param sessionPreference The type of cooldown the client prefers
|
||||||
* @param lastHitTime The time of the last hit. Used to gauge how long the cooldown is taking.
|
* @param lastHitTime The time of the last hit. Used to gauge how long the cooldown is taking.
|
||||||
*/
|
*/
|
||||||
private static void computeCooldown(GeyserSession session, CooldownType sessionPreference, long lastHitTime) {
|
private static void computeCooldown(GeyserSession session, CooldownType sessionPreference, long lastHitTime) {
|
||||||
if (session.isClosed()) return; // Don't run scheduled tasks if the client left
|
if (session.isClosed()) return; // Don't run scheduled tasks if the client left
|
||||||
if (lastHitTime != session.getLastHitTime()) return; // Means another cooldown has started so there's no need to continue this one
|
if (lastHitTime != session.getLastHitTime())
|
||||||
|
return; // Means another cooldown has started so there's no need to continue this one
|
||||||
SetTitlePacket titlePacket = new SetTitlePacket();
|
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||||
if (sessionPreference == CooldownType.ACTIONBAR) {
|
if (sessionPreference == CooldownType.ACTIONBAR) {
|
||||||
titlePacket.setType(SetTitlePacket.Type.ACTIONBAR);
|
titlePacket.setType(SetTitlePacket.Type.ACTIONBAR);
|
||||||
|
|
@ -102,7 +106,7 @@ public class CooldownUtils {
|
||||||
session.sendUpstreamPacket(titlePacket);
|
session.sendUpstreamPacket(titlePacket);
|
||||||
if (hasCooldown(session)) {
|
if (hasCooldown(session)) {
|
||||||
session.scheduleInEventLoop(() ->
|
session.scheduleInEventLoop(() ->
|
||||||
computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50
|
computeCooldown(session, sessionPreference, lastHitTime), session.getNanosecondsPerTick(), TimeUnit.NANOSECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50
|
||||||
} else {
|
} else {
|
||||||
SetTitlePacket removeTitlePacket = new SetTitlePacket();
|
SetTitlePacket removeTitlePacket = new SetTitlePacket();
|
||||||
removeTitlePacket.setType(SetTitlePacket.Type.CLEAR);
|
removeTitlePacket.setType(SetTitlePacket.Type.CLEAR);
|
||||||
|
|
@ -115,8 +119,8 @@ public class CooldownUtils {
|
||||||
|
|
||||||
private static boolean hasCooldown(GeyserSession session) {
|
private static boolean hasCooldown(GeyserSession session) {
|
||||||
long time = System.currentTimeMillis() - session.getLastHitTime();
|
long time = System.currentTimeMillis() - session.getLastHitTime();
|
||||||
double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1.5);
|
double cooldown = restrain(((double) time) * session.getAttackSpeed() / (session.getMillisecondsPerTick() * 20d), 1.5);
|
||||||
return cooldown < 1.1;
|
return cooldown < 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -128,7 +132,7 @@ public class CooldownUtils {
|
||||||
|
|
||||||
private static String getTitle(GeyserSession session) {
|
private static String getTitle(GeyserSession session) {
|
||||||
long time = System.currentTimeMillis() - session.getLastHitTime();
|
long time = System.currentTimeMillis() - session.getLastHitTime();
|
||||||
double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1);
|
double cooldown = restrain(((double) time) * session.getAttackSpeed() / (session.getMillisecondsPerTick() * 20d), 1);
|
||||||
|
|
||||||
int darkGrey = (int) Math.floor(10d * cooldown);
|
int darkGrey = (int) Math.floor(10d * cooldown);
|
||||||
int grey = 10 - darkGrey;
|
int grey = 10 - darkGrey;
|
||||||
|
|
@ -157,7 +161,6 @@ public class CooldownUtils {
|
||||||
* Convert the CooldownType string (from config) to the enum, DISABLED on fail
|
* Convert the CooldownType string (from config) to the enum, DISABLED on fail
|
||||||
*
|
*
|
||||||
* @param name CooldownType string
|
* @param name CooldownType string
|
||||||
*
|
|
||||||
* @return The converted CooldownType
|
* @return The converted CooldownType
|
||||||
*/
|
*/
|
||||||
public static CooldownType getByName(String name) {
|
public static CooldownType getByName(String name) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue