Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle ClientboundTickingStatePacket correctly and fix Throwable Scales #4850

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3d957e3
Proper tick rate handling
letsgoawaydev Jul 12, 2024
91a1a12
Fix frozen variable getter
letsgoawaydev Jul 13, 2024
83fab59
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 13, 2024
8418691
Fix formatting i think third attempt
letsgoawaydev Jul 13, 2024
fc04909
Formatting fix attempt 5 fsdiofhsdioufhvuisdhviuo9ds
letsgoawaydev Jul 13, 2024
f83e2fb
Fix stuff, also fixed the sizing of throwables as they were to big
letsgoawaydev Jul 13, 2024
4fd9cbe
Move update ticking state
letsgoawaydev Jul 13, 2024
dc130eb
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 14, 2024
d20b18a
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 15, 2024
0eb9134
Update core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
letsgoawaydev Jul 18, 2024
b2a5cd5
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 23, 2024
b8b0517
Fixes for spaces and documentation
letsgoawaydev Jul 24, 2024
02c0469
Missed a space
letsgoawaydev Jul 24, 2024
611b010
wait now ive fixed it
letsgoawaydev Jul 24, 2024
4f345c0
Fix languages
letsgoawaydev Jul 24, 2024
046d287
try again to fix languages
letsgoawaydev Jul 24, 2024
2da5599
Fix Java doc comments for tickable interface
letsgoawaydev Jul 25, 2024
09bfe4b
Fix javadoc comment in Geyser Session
letsgoawaydev Jul 25, 2024
dadd5ba
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 26, 2024
e86d11c
fix comment
letsgoawaydev Jul 26, 2024
8d4f259
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 28, 2024
0ce7240
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 29, 2024
e348d3e
fix some tick rate stuffs
letsgoawaydev Jul 29, 2024
7af831f
Fix build fail
letsgoawaydev Jul 30, 2024
c5f1f83
Merge branch 'master' into tick-rate-handling
letsgoawaydev Jul 31, 2024
e78568d
Merge branch 'master' into tick-rate-handling
letsgoawaydev Aug 6, 2024
ad3990b
Merge branch 'master' into tick-rate-handling
letsgoawaydev Aug 9, 2024
99e7385
fix some stuff
letsgoawaydev Aug 10, 2024
089d96c
Merge branch 'tick-rate-handling' of https://github.com/letsgoawaydev…
letsgoawaydev Aug 10, 2024
bd27743
Merge remote-tracking branch 'upstream/master' into tick-rate-handling
letsgoawaydev Aug 16, 2024
27de994
Merge remote-tracking branch 'upstream/master' into tick-rate-handling
letsgoawaydev Aug 16, 2024
e5a2ae4
merge
letsgoawaydev Aug 16, 2024
807881f
test
letsgoawaydev Aug 16, 2024
3602fc2
Update languages
letsgoawaydev Aug 16, 2024
21b87c8
Update mappings
letsgoawaydev Aug 16, 2024
dd40bb1
Merge branch 'master' into tick-rate-handling
letsgoawaydev Aug 31, 2024
079c4e6
delete broken stuff
letsgoawaydev Aug 31, 2024
90a0119
Fix cooldown
letsgoawaydev Aug 31, 2024
dcc3dce
fix cooldowns
letsgoawaydev Aug 31, 2024
4fc1d66
Update core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java
letsgoawaydev Aug 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<EvokerFangsEntity> EVOKER_FANGS;
public static final EntityDefinition<ThrowableItemEntity> EXPERIENCE_BOTTLE;
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<FireballEntity> FIREBALL;
public static final EntityDefinition<FireworkEntity> FIREWORK_ROCKET;
Expand Down Expand Up @@ -250,7 +250,7 @@ public final class EntityDefinitions {
.height(0.8f).width(0.5f)
.identifier("minecraft:evocation_fang")
.build();
EYE_OF_ENDER = EntityDefinition.inherited(Entity::new, entityBase)
EYE_OF_ENDER = EntityDefinition.inherited(EnderEyeEntity::new, entityBase)
.type(EntityType.EYE_OF_ENDER)
.heightAndWidth(0.25f)
.identifier("minecraft:eye_of_ender_signal")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public InteractionResult interact(Hand hand) {
@Override
public void tick() {
// 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()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,4 @@ protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttrib
return type.getAttribute((float) AttributeUtils.calculateValue(javaAttribute));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@

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.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
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;

Expand All @@ -39,7 +40,7 @@
*/
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;
onebeastchris marked this conversation as resolved.
Show resolved Hide resolved
private boolean invisible;
Expand All @@ -48,29 +49,38 @@ public ThrowableItemEntity(GeyserSession session, int entityId, long geyserId, U
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
setFlag(EntityFlag.INVISIBLE, true);
invisible = false;
age = 0;
}

@Override
protected void initializeMetadata() {
super.initializeMetadata();
// Correct sizing
dirtyMetadata.put(EntityDataTypes.SCALE, 0.5f);
}
letsgoawaydev marked this conversation as resolved.
Show resolved Hide resolved
letsgoawaydev marked this conversation as resolved.
Show resolved Hide resolved

private void checkVisibility() {
age++;

// Prevent projectiles from blocking the player's screen
if (session.isTickingFrozen()) {
// This may seem odd, but it matches java edition
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)) {
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();
}
setFlag(EntityFlag.INVISIBLE, invisible);
updateBedrockMetadata();
}
age++;
}

@Override
public void tick() {
public void drawTick() {
checkVisibility();
super.tick();
super.drawTick();
}

@Override
Expand Down
17 changes: 15 additions & 2 deletions core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java
Original file line number Diff line number Diff line change
@@ -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
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -26,8 +26,21 @@
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 {
/**
* 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();
}
93 changes: 64 additions & 29 deletions core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
Original file line number Diff line number Diff line change
@@ -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
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -66,6 +66,7 @@
import org.cloudburstmc.protocol.bedrock.data.GamePublishSetting;
import org.cloudburstmc.protocol.bedrock.data.GameRuleData;
import org.cloudburstmc.protocol.bedrock.data.GameType;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.PlayerPermission;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.SpawnBiomeType;
Expand All @@ -85,6 +86,7 @@
import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket;
import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket;
import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket;
Expand Down Expand Up @@ -173,6 +175,7 @@
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.geyser.util.LoginEncryptionUtils;
import org.geysermc.geyser.util.MinecraftAuthLogger;
import org.geysermc.mcprotocollib.auth.GameProfile;
Expand Down Expand Up @@ -599,7 +602,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
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;

Expand Down Expand Up @@ -643,7 +646,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
/**
* Stores cookies sent by the Java server.
*/
@Setter @Getter
@Setter
private Map<String, byte[]> cookies = new Object2ObjectOpenHashMap<>();

private final GeyserCameraData cameraData;
Expand All @@ -652,6 +655,17 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {

private MinecraftProtocol protocol;

@Getter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class is annotated with a getter, this is likely unnecessary

private int nanosecondsPerTick = 50000000;
@Getter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

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;
letsgoawaydev marked this conversation as resolved.
Show resolved Hide resolved

public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop eventLoop) {
this.geyser = geyser;
this.upstream = new UpstreamSession(bedrockServerSession);
Expand Down Expand Up @@ -874,31 +888,31 @@ public boolean onMicrosoftLoginComplete(PendingMicrosoftAuthentication.Authentic
}
task.cleanup(); // player is online -> remove pending authentication immediately
return task.getAuthentication().handle((result, ex) -> {
if (ex != null) {
geyser.getLogger().error("Failed to log in with Microsoft code!", ex);
disconnect(ex.toString());
return false;
}
if (ex != null) {
geyser.getLogger().error("Failed to log in with Microsoft code!", ex);
disconnect(ex.toString());
return false;
}

StepMCProfile.MCProfile mcProfile = result.session().getMcProfile();
StepMCToken.MCToken mcToken = mcProfile.getMcToken();
StepMCProfile.MCProfile mcProfile = result.session().getMcProfile();
StepMCToken.MCToken mcToken = mcProfile.getMcToken();

this.protocol = new MinecraftProtocol(
new GameProfile(mcProfile.getId(), mcProfile.getName()),
mcToken.getAccessToken()
);
this.protocol = new MinecraftProtocol(
new GameProfile(mcProfile.getId(), mcProfile.getName()),
mcToken.getAccessToken()
);

try {
connectDownstream();
} catch (Throwable t) {
t.printStackTrace();
return false;
}
try {
connectDownstream();
} catch (Throwable t) {
t.printStackTrace();
return false;
}

// Save our auth chain for later use
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session())));
return true;
}).getNow(false);
// Save our auth chain for later use
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session())));
return true;
}).getNow(false);
}

/**
Expand All @@ -919,7 +933,7 @@ private void connectDownstream() {
boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE;

// Start ticking
tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
tickThread = eventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS);

this.protocol.setUseDefaultListeners(false);

Expand Down Expand Up @@ -1236,8 +1250,21 @@ public ScheduledFuture<?> scheduleInEventLoop(Runnable runnable, long duration,
}, duration, timeUnit);
}

public void updateTickingState(float tickRate, boolean frozen) {
tickThread.cancel(false);

this.tickingFrozen = frozen;

tickRate = MathUtils.clamp(tickRate, 1.0f, 10000.0f);

millisecondsPerTick = 1000.0f / tickRate;

nanosecondsPerTick = MathUtils.ceil(1000000000.0f / tickRate);
tickThread = eventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS);
}

/**
* Called every 50 milliseconds - one Minecraft tick.
* Called every Minecraft tick.
*/
protected void tick() {
try {
Expand Down Expand Up @@ -1275,13 +1302,21 @@ protected void tick() {
isInWorldBorderWarningArea = false;
}

boolean gameShouldUpdate = !tickingFrozen || stepTicks > 0;
if (stepTicks > 0) {
--stepTicks;
}

Entity vehicle = playerEntity.getVehicle();
if (vehicle instanceof ClientVehicle clientVehicle && vehicle.isValid()) {
clientVehicle.getVehicleComponent().tickVehicle();
}

for (Tickable entity : entityCache.getTickableEntities()) {
entity.tick();
entity.drawTick();
if (gameShouldUpdate) {
entity.tick();
}
}

letsgoawaydev marked this conversation as resolved.
Show resolved Hide resolved
if (armAnimationTicks >= 0) {
Expand Down Expand Up @@ -1813,7 +1848,7 @@ public void setDaylightCycle(boolean doCycle) {
* Send a gamerule value to the client
*
* @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) {
GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket();
Expand Down Expand Up @@ -2014,7 +2049,7 @@ public float getEyeHeight() {

@Override
public UUID javaUuid() {
return playerEntity != null ? playerEntity.getUuid() : null ;
return playerEntity != null ? playerEntity.getUuid() : null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,13 @@ private void forceSyncCorrectTitleTimes() {
SetTitlePacket titlePacket = new SetTitlePacket();
titlePacket.setType(SetTitlePacket.Type.TIMES);
titlePacket.setText("");
titlePacket.setFadeInTime(trueTitleFadeInTime);
titlePacket.setStayTime(trueTitleStayTime);
titlePacket.setFadeOutTime(trueTitleFadeOutTime);

// We need a tick rate multiplier as otherwise the timings are incorrect on different tick rates because
// bedrock can only run at 20 TPS (50ms = 1 tick)
int tickrateMultiplier = Math.round(session.getMillisecondsPerTick()) / 50;
titlePacket.setFadeInTime(trueTitleFadeInTime * tickrateMultiplier);
titlePacket.setStayTime(trueTitleStayTime * tickrateMultiplier);
titlePacket.setFadeOutTime(trueTitleFadeOutTime * tickrateMultiplier);
titlePacket.setPlatformOnlineId("");
titlePacket.setXuid("");

Expand Down
Loading