Skip to content

Commit 787368d

Browse files
committed
Properly track spin attack - should fix <#5262> - and don't allow the Bedrock client to stop gliding mid-air
1 parent 2484ec9 commit 787368d

10 files changed

Lines changed: 52 additions & 49 deletions

File tree

core/src/main/java/org/geysermc/geyser/entity/type/Entity.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ public void setFlags(ByteEntityMetadata entityMetadata) {
410410
setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
411411

412412
// Swimming is ignored here and instead we rely on the pose
413-
setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
413+
setGliding((xd & 0x80) == 0x80);
414414

415415
setInvisible((xd & 0x20) == 0x20);
416416
}
@@ -424,6 +424,13 @@ protected void setInvisible(boolean value) {
424424
setFlag(EntityFlag.INVISIBLE, value);
425425
}
426426

427+
/**
428+
* Set a boolean - whether the entity is gliding
429+
*/
430+
protected void setGliding(boolean value) {
431+
setFlag(EntityFlag.GLIDING, value);
432+
}
433+
427434
/**
428435
* Set an int from 0 - this entity's maximum air - (air / maxAir) represents the percentage of bubbles left
429436
*/
@@ -533,9 +540,8 @@ public void setGravity(BooleanEntityMetadata entityMetadata) {
533540
* Usually used for bounding box and not animation.
534541
*/
535542
public void setPose(Pose pose) {
536-
GeyserImpl.getInstance().getLogger().info("setting pose: " + pose);
537543
setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING));
538-
setFlag(EntityFlag.GLIDING, pose.equals(Pose.FALL_FLYING));
544+
// FALL_FLYING is instead set via setFlags
539545
// Triggered when crawling
540546
setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING));
541547
setDimensions(pose);
@@ -544,7 +550,7 @@ public void setPose(Pose pose) {
544550
/**
545551
* Set the height and width of the entity's bounding box
546552
*/
547-
protected void setDimensions(Pose pose) {
553+
public void setDimensions(Pose pose) {
548554
// No flexibility options for basic entities
549555
setBoundingBoxHeight(definition.height());
550556
setBoundingBoxWidth(definition.width());

core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ protected boolean isShaking() {
279279
}
280280

281281
@Override
282-
protected void setDimensions(Pose pose) {
282+
public void setDimensions(Pose pose) {
283283
if (pose == Pose.SLEEPING) {
284284
setBoundingBoxWidth(0.2f);
285285
setBoundingBoxHeight(0.2f);

core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public void setScreamer(BooleanEntityMetadata entityMetadata) {
6363
}
6464

6565
@Override
66-
protected void setDimensions(Pose pose) {
66+
public void setDimensions(Pose pose) {
6767
if (pose == Pose.LONG_JUMPING) {
6868
setBoundingBoxWidth(LONG_JUMPING_WIDTH);
6969
setBoundingBoxHeight(LONG_JUMPING_HEIGHT);

core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void setPose(Pose pose) {
6464
}
6565

6666
@Override
67-
protected void setDimensions(Pose pose) {
67+
public void setDimensions(Pose pose) {
6868
if (getFlag(EntityFlag.DIGGING)) {
6969
setBoundingBoxHeight(DIGGING_HEIGHT);
7070
setBoundingBoxWidth(definition.width());

core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public void setPose(Pose pose) {
113113
}
114114

115115
@Override
116-
protected void setDimensions(Pose pose) {
116+
public void setDimensions(Pose pose) {
117117
if (pose == Pose.SITTING) {
118118
setBoundingBoxHeight(definition.height() - SITTING_HEIGHT_DIFFERENCE);
119119
setBoundingBoxWidth(definition.width());

core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ protected void scoreVisibility(boolean show) {
416416
}
417417

418418
@Override
419-
protected void setDimensions(Pose pose) {
419+
public void setDimensions(Pose pose) {
420420
float height;
421421
float width;
422422
switch (pose) {

core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ public void setFlags(ByteEntityMetadata entityMetadata) {
206206
}
207207
}
208208

209+
@Override
210+
protected void setGliding(boolean value) {
211+
session.setGliding(value);
212+
}
213+
209214
/**
210215
* Since 1.19.40, the client must be re-informed of its bounding box on respawn
211216
* See <a href="https://github.com/GeyserMC/Geyser/issues/3370">issue 3370</a>
@@ -466,7 +471,7 @@ public boolean canStartGliding() {
466471
return false;
467472
}
468473

469-
if (this.isOnClimbableBlock()) {
474+
if (this.isOnClimbableBlock() || session.getPlayerEntity().isOnGround()) {
470475
return false;
471476
}
472477

@@ -484,17 +489,23 @@ public boolean canStartGliding() {
484489
return true;
485490
}
486491
}
492+
493+
// Bedrock will NOT allow flight when not wearing an elytra; even if it doesn't have a glider component
494+
if (entry.getKey() == EquipmentSlot.CHESTPLATE && !entry.getValue().asItem().equals(Items.ELYTRA)) {
495+
return false;
496+
}
487497
}
488498

489499
return false;
490500
}
491501

492-
public boolean isGliding() {
493-
return getFlag(EntityFlag.GLIDING);
502+
public void setGlidingFlag(boolean gliding) {
503+
setFlag(EntityFlag.GLIDING, gliding);
504+
// ALWAYS send the gliding flag - otherwise the Bedrock client can misbehave
505+
setFlagsDirty(true);
494506
}
495507

496-
public void stopGliding() {
497-
setFlag(EntityFlag.GLIDING, false);
498-
updateBedrockMetadata();
508+
public boolean isGliding() {
509+
return getFlag(EntityFlag.GLIDING);
499510
}
500511
}

core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public GeyserItemStack getItemInHand() {
8686
return items[36 + heldItemSlot];
8787
}
8888

89-
// TODO other equipment slots???
89+
// TODO other equipment slots
9090
public Map<EquipmentSlot, GeyserItemStack> getEquipment() {
9191
return Map.of(
9292
EquipmentSlot.MAIN_HAND, getItemInHand(),

core/src/main/java/org/geysermc/geyser/session/GeyserSession.java

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,15 +1254,14 @@ public void stopSneaking() {
12541254
setSneaking(false);
12551255
}
12561256

1257+
public void setSpinAttack(boolean spinAttack) {
1258+
switchPose(spinAttack, EntityFlag.DAMAGE_NEARBY_MOBS, Pose.SPIN_ATTACK);
1259+
}
1260+
12571261
public void setGliding(boolean gliding) {
1258-
if (gliding) {
1259-
this.pose = Pose.FALL_FLYING;
1260-
playerEntity.setBoundingBoxHeight(0.6f);
1261-
} else {
1262-
this.pose = Pose.STANDING;
1263-
playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height());
1264-
}
1265-
playerEntity.setFlag(EntityFlag.GLIDING, gliding);
1262+
this.pose = gliding ? Pose.FALL_FLYING : Pose.STANDING;
1263+
playerEntity.setDimensions(this.pose);
1264+
playerEntity.setGlidingFlag(gliding);
12661265
playerEntity.updateBedrockMetadata();
12671266
}
12681267

@@ -1302,22 +1301,17 @@ public void setSwimming(boolean swimming) {
13021301
playerEntity.updateBedrockMetadata();
13031302
return;
13041303
}
1305-
toggleSwimmingPose(swimming, EntityFlag.SWIMMING);
1304+
switchPose(swimming, EntityFlag.SWIMMING, Pose.SWIMMING);
13061305
}
13071306

13081307
public void setCrawling(boolean crawling) {
1309-
toggleSwimmingPose(crawling, EntityFlag.CRAWLING);
1308+
switchPose(crawling, EntityFlag.CRAWLING, Pose.SWIMMING);
13101309
}
13111310

1312-
private void toggleSwimmingPose(boolean crawling, EntityFlag flag) {
1313-
if (crawling) {
1314-
this.pose = Pose.SWIMMING;
1315-
playerEntity.setBoundingBoxHeight(0.6f);
1316-
} else {
1317-
this.pose = Pose.STANDING;
1318-
playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height());
1319-
}
1320-
playerEntity.setFlag(flag, crawling);
1311+
private void switchPose(boolean value, EntityFlag flag, Pose pose) {
1312+
this.pose = value ? pose : Pose.STANDING;
1313+
playerEntity.setDimensions(this.pose);
1314+
playerEntity.setFlag(flag, value);
13211315
playerEntity.updateBedrockMetadata();
13221316
}
13231317

@@ -1802,10 +1796,6 @@ public void sendGameRule(String gameRule, Object value) {
18021796

18031797
private static final Ability[] USED_ABILITIES = Ability.values();
18041798

1805-
public void sendAbilities() {
1806-
1807-
}
1808-
18091799
/**
18101800
* Send an AdventureSettingsPacket to the client with the latest flags
18111801
*/

core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
3737
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
3838
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
39-
import org.geysermc.geyser.GeyserImpl;
4039
import org.geysermc.geyser.entity.EntityDefinitions;
4140
import org.geysermc.geyser.entity.type.BoatEntity;
4241
import org.geysermc.geyser.entity.type.Entity;
@@ -88,11 +87,6 @@ public void translate(GeyserSession session, PlayerAuthInputPacket packet) {
8887
for (PlayerAuthInputData input : inputData) {
8988
leftOverInputData.remove(input);
9089
switch (input) {
91-
case HANDLE_TELEPORT, ASCEND_BLOCK, DESCEND_BLOCK -> {
92-
// TODO handle_teleport case
93-
// TODO scaffolding fixes for mobile
94-
GeyserImpl.getInstance().getLogger().error("handle tp / scaffolding!");
95-
}
9690
case PERFORM_ITEM_INTERACTION -> processItemUseTransaction(session, packet.getItemUseTransaction());
9791
case PERFORM_BLOCK_ACTIONS -> BedrockBlockActions.translate(session, packet.getPlayerActions());
9892
case START_SWIMMING -> session.setSwimming(true);
@@ -128,7 +122,7 @@ public void translate(GeyserSession session, PlayerAuthInputPacket packet) {
128122
}
129123
case START_GLIDING -> {
130124
// Bedrock can send both start_glide and stop_glide in the same packet.
131-
// We only want to start gliding if the client hasn't stopped gliding in the same tick.
125+
// We only want to start gliding if the client has not stopped gliding in the same tick.
132126
// last replicated on 1.21.70 by "walking" and jumping while in water
133127
if (!entity.isGliding() && !leftOverInputData.contains(PlayerAuthInputData.STOP_GLIDING)) {
134128
if (entity.canStartGliding()) {
@@ -140,17 +134,19 @@ public void translate(GeyserSession session, PlayerAuthInputPacket packet) {
140134
session.setGliding(true);
141135
session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING));
142136
} else {
143-
entity.stopGliding();
137+
session.setGliding(false);
144138
// return to flying if we can't start gliding
145139
if (session.isFlying()) {
146140
session.sendAdventureSettings();
147141
}
148142
}
149143
}
150144
}
145+
case START_SPIN_ATTACK -> session.setSpinAttack(true);
146+
case STOP_SPIN_ATTACK -> session.setSpinAttack(false);
151147
case STOP_GLIDING -> {
152-
GeyserImpl.getInstance().getLogger().info("Stopping gliding");
153-
session.setGliding(false);
148+
// Java doesn't allow elytra gliding to stop mid-air.
149+
session.setGliding(entity.isGliding() && entity.canStartGliding());
154150
}
155151
case MISSED_SWING -> {
156152
session.setLastAirHitTick(session.getTicks());

0 commit comments

Comments
 (0)