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:
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user