1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-28 19:29:14 +00:00

Start on implementing happy ghast flying

This commit is contained in:
onebeastchris
2025-06-24 01:46:19 +02:00
parent d3683b970a
commit bd16b3be34
5 changed files with 165 additions and 12 deletions

View File

@@ -41,7 +41,9 @@ import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.entity.type.living.animal.HappyGhastEntity;
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
import org.geysermc.geyser.entity.vehicle.HappyGhastVehicleComponent;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping;
@@ -510,7 +512,14 @@ public class LivingEntity extends Entity {
}
}
case ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE));
case FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED));
case FLYING_SPEED -> {
AttributeData attributeData = calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED);
newAttributes.add(attributeData);
if (this instanceof HappyGhastEntity happyGhast &&
happyGhast.getVehicleComponent() instanceof HappyGhastVehicleComponent vehicleComponent) {
vehicleComponent.setFlyingSpeed(attributeData.getValue());
}
}
case FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
case KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
case JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));

View File

@@ -27,9 +27,15 @@ package org.geysermc.geyser.entity.type.living.animal;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
import org.geysermc.geyser.entity.vehicle.HappyGhastVehicleComponent;
import org.geysermc.geyser.entity.vehicle.VehicleComponent;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
@@ -43,20 +49,30 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
public class HappyGhastEntity extends AnimalEntity {
public class HappyGhastEntity extends AnimalEntity implements ClientVehicle {
private final HappyGhastVehicleComponent vehicleComponent = new HappyGhastVehicleComponent(this, 0.0f);
private boolean staysStill;
private float speed;
public HappyGhastEntity(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();
// BDS 1.21.90
setFlag(EntityFlag.CAN_FLY, true);
setFlag(EntityFlag.TAMED, true);
setFlag(EntityFlag.CAN_WALK, true);
setFlag(EntityFlag.TAMED, true);
setFlag(EntityFlag.BODY_ROTATION_ALWAYS_FOLLOWS_HEAD, true);
setFlag(EntityFlag.COLLIDABLE, true);
setFlag(EntityFlag.WASD_AIR_CONTROLLED, true);
setFlag(EntityFlag.DOES_SERVER_AUTH_ONLY_DISMOUNT, true);
// TODO: verify which flags are necessary
setAirSupply(100);
propertyManager.add("minecraft:can_move", true);
}
@Override
@@ -71,6 +87,7 @@ public class HappyGhastEntity extends AnimalEntity {
}
public void setStaysStill(BooleanEntityMetadata entityMetadata) {
staysStill = entityMetadata.getPrimitiveValue();
propertyManager.add("minecraft:can_move", !entityMetadata.getPrimitiveValue());
updateBedrockEntityProperties();
}
@@ -124,4 +141,38 @@ public class HappyGhastEntity extends AnimalEntity {
}
}
}
@Override
public VehicleComponent<?> getVehicleComponent() {
return vehicleComponent;
}
@Override
public Vector2f getAdjustedInput(Vector2f input) {
// not used; calculations look a bit different for the happy ghast
return Vector2f.ZERO;
}
@Override
public float getVehicleSpeed() {
return speed; // TODO this doesnt seem right?
}
@Override
public boolean isClientControlled() {
// TODO proper check, just lazy
if (body == null) {
return false;
}
// TODO must have ai check
if (staysStill) {
return false;
}
return getFirstPassenger() instanceof SessionPlayerEntity;
}
private Entity getFirstPassenger() {
return passengers.isEmpty() ? null : passengers.get(0);
}
}

View File

@@ -30,10 +30,13 @@ import org.cloudburstmc.math.vector.Vector2f;
public interface ClientVehicle {
VehicleComponent<?> getVehicleComponent();
// LivingEntity#getRiddenInput
Vector2f getAdjustedInput(Vector2f input);
// MojMap LivingEntity#getRiddenSpeed
float getVehicleSpeed();
// MojMap Mob#getControllingPassenger
boolean isClientControlled();
default boolean canWalkOnLava() {

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2025 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.vehicle;
import lombok.Setter;
import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.type.living.animal.HappyGhastEntity;
public class HappyGhastVehicleComponent extends VehicleComponent<HappyGhastEntity> {
@Setter
private float flyingSpeed;
public HappyGhastVehicleComponent(HappyGhastEntity vehicle, float stepHeight) {
super(vehicle, stepHeight);
}
protected Vector3f getInputVelocity(VehicleContext ctx, float speed) {
Vector2f input = vehicle.getSession().getPlayerEntity().getVehicleInput();
input = input.mul(0.98f); // ?
float x = input.getX();
float y = 0.0f;
float z = 0.0f;
float playerZ = input.getY();
if (playerZ != 0.0F) {
float i = Mth.cos(player.getXRot() * (float) (Math.PI / 180.0));
float j = -Mth.sin(player.getXRot() * (float) (Math.PI / 180.0));
if (playerZ < 0.0F) {
i *= -0.5F;
j *= -0.5F;
}
y = j;
z = i;
}
if (session.isJumping()) {
y += 0.5F;
}
return Vector3f.from((double) x, (double) y, (double)z).mul(3.9F * flyingSpeed);
}
}

View File

@@ -39,6 +39,7 @@ import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.TextDisplayEntity;
import org.geysermc.geyser.entity.type.living.ArmorStandEntity;
import org.geysermc.geyser.entity.type.living.animal.AnimalEntity;
import org.geysermc.geyser.entity.type.living.animal.HappyGhastEntity;
import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
@@ -221,6 +222,13 @@ public final class EntityUtils {
}
}
}
case HAPPY_GHAST -> {
// TODO seat index matters here, likely
// 0.0, 5.02001, 1.7 BDS
xOffset = 0;
yOffset = 3.4f;
zOffset = 1.7f;
}
}
if (mount instanceof ChestBoatEntity) {
xOffset = 0.15F;
@@ -268,17 +276,30 @@ public final class EntityUtils {
}
public static void updateRiderRotationLock(Entity passenger, Entity mount, boolean isRiding) {
if (isRiding && mount instanceof BoatEntity) {
// Head rotation is locked while riding in a boat
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION, true);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION_DEGREES, 90f);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_HAS_ROTATION, true);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_ROTATION_OFFSET_DEGREES, -90f);
if (isRiding) {
if (mount instanceof BoatEntity) {
// Head rotation is locked while riding in a boat
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION, true);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION_DEGREES, 90f);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_HAS_ROTATION, true);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_ROTATION_OFFSET_DEGREES, -90f);
} else if (mount instanceof HappyGhastEntity) {
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION, false);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION_DEGREES, 181f);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_THIRD_PERSON_CAMERA_RADIUS, 8f);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_CAMERA_RELAX_DISTANCE_SMOOTHING, 6f);
passenger.getDirtyMetadata().put(EntityDataTypes.CONTROLLING_RIDER_SEAT_INDEX, (byte) 0);
}
} else {
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION, false);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_LOCK_RIDER_ROTATION_DEGREES, 0f);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_HAS_ROTATION, false);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_ROTATION_OFFSET_DEGREES, 0f);
// TODO what are defaults here???
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_THIRD_PERSON_CAMERA_RADIUS, 8f);
passenger.getDirtyMetadata().put(EntityDataTypes.SEAT_CAMERA_RELAX_DISTANCE_SMOOTHING, 6f);
passenger.getDirtyMetadata().put(EntityDataTypes.CONTROLLING_RIDER_SEAT_INDEX, (byte) 0);
}
}