Implement wind charges

This commit is contained in:
Camotoy 2024-06-09 16:57:51 -04:00
parent e9e364636a
commit ae6059bdc3
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
5 changed files with 108 additions and 23 deletions

View file

@ -25,6 +25,8 @@
package org.geysermc.geyser.entity;
import org.geysermc.geyser.entity.type.AbstractWindChargeEntity;
import org.geysermc.geyser.entity.factory.EntityFactory;
import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
@ -64,6 +66,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<BlazeEntity> BLAZE;
public static final EntityDefinition<BoatEntity> BOAT;
public static final EntityDefinition<BoggedEntity> BOGGED;
public static final EntityDefinition<AbstractWindChargeEntity> BREEZE_WIND_CHARGE;
public static final EntityDefinition<CamelEntity> CAMEL;
public static final EntityDefinition<CatEntity> CAT;
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
@ -166,6 +169,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<VindicatorEntity> VINDICATOR;
public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER;
public static final EntityDefinition<WardenEntity> WARDEN;
public static final EntityDefinition<AbstractWindChargeEntity> WIND_CHARGE;
public static final EntityDefinition<RaidParticipantEntity> WITCH;
public static final EntityDefinition<WitherEntity> WITHER;
public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON;
@ -376,6 +380,18 @@ public final class EntityDefinitions {
.heightAndWidth(0.25f)
.build();
EntityFactory<AbstractWindChargeEntity> windChargeSupplier = AbstractWindChargeEntity::new;
BREEZE_WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
.type(EntityType.BREEZE_WIND_CHARGE)
.identifier("minecraft:breeze_wind_charge_projectile")
.heightAndWidth(0.3125f)
.build();
WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
.type(EntityType.WIND_CHARGE)
.identifier("minecraft:wind_charge_projectile")
.heightAndWidth(0.3125f)
.build();
EntityDefinition<AbstractArrowEntity> abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase)
.addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags)
.addTranslator(null) // "Piercing level"

View file

@ -0,0 +1,53 @@
/*
* 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.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID;
/**
* Note that, as of 1.21, a wind charge entity does not actually implement the thrown item. We're just reusing
* the "hide until far away" aspect.
*/
public class AbstractWindChargeEntity extends ThrowableItemEntity {
public AbstractWindChargeEntity(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
public void tick() {
super.tick();
}
@Override
protected float getDrag() {
// Always, even in water. As of 1.21.
return 1f;
}
}

View file

@ -1047,6 +1047,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
@Override
public void packetReceived(Session session, Packet packet) {
System.out.println(packet);
Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, GeyserSession.this);
}

View file

@ -25,22 +25,24 @@
package org.geysermc.geyser.translator.protocol.java.level;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.SoundUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.ExplosionInteraction;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket;
import java.util.concurrent.ThreadLocalRandom;
@Translator(packet = ClientboundExplodePacket.class)
public class JavaExplodeTranslator extends PacketTranslator<ClientboundExplodePacket> {
@ -56,6 +58,8 @@ public class JavaExplodeTranslator extends PacketTranslator<ClientboundExplodePa
builder.putFloat("originZ", (float) packet.getZ());
builder.putFloat("radius", packet.getRadius());
builder.putInt("size", packet.getExploded().size());
// As of 1.21, KEEP means no block actions are run. TRIGGER_BLOCK will run some actions, like buttons can be pressed
if (packet.getBlockInteraction() != ExplosionInteraction.KEEP && packet.getBlockInteraction() != ExplosionInteraction.TRIGGER_BLOCK) {
int i = 0;
for (Vector3i position : packet.getExploded()) {
Vector3i pos = Vector3i.from(packet.getX() + position.getX(), packet.getY() + position.getY(), packet.getZ() + position.getZ());
@ -65,18 +69,28 @@ public class JavaExplodeTranslator extends PacketTranslator<ClientboundExplodePa
builder.putFloat("pos" + i + "z", pos.getZ());
i++;
}
} else {
// As of Bedrock 1.21 - particles will only be created by the above packet if there are blocks to blow up?
// Not sure if the packet does anything - sending it just in case, because BDS still sends it.
// TODO move out of packet translator class
Particle particle;
if (!(packet.getRadius() < 2f) && packet.getBlockInteraction() == ExplosionInteraction.KEEP) {
particle = packet.getLargeExplosionParticles();
} else {
particle = packet.getSmallExplosionParticles();
}
var particleCreator = JavaLevelParticlesTranslator.createParticle(session, particle);
if (particleCreator != null) {
session.sendUpstreamPacket(particleCreator.apply(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())));
}
}
levelEventPacket.setTag(builder.build());
session.sendUpstreamPacket(levelEventPacket);
Vector3f pos = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket();
levelSoundEventPacket.setRelativeVolumeDisabled(false);
levelSoundEventPacket.setBabySound(false);
levelSoundEventPacket.setExtraData(-1);
levelSoundEventPacket.setSound(SoundEvent.EXPLODE);
levelSoundEventPacket.setIdentifier(":");
levelSoundEventPacket.setPosition(pos);
session.sendUpstreamPacket(levelSoundEventPacket);
ThreadLocalRandom random = ThreadLocalRandom.current();
float pitch = (1.0f + (random.nextFloat() - random.nextFloat()) * 0.2f) * 0.7f; // As of 1.21, Explosion#finalizeExplosion
SoundUtils.playSound(session, packet.getExplosionSound(), pos, 4.0f, pitch);
if (packet.getPushX() != 0f || packet.getPushY() != 0f || packet.getPushZ() != 0f) {
SetEntityMotionPacket motionPacket = new SetEntityMotionPacket();

View file

@ -92,7 +92,7 @@ public class JavaLevelParticlesTranslator extends PacketTranslator<ClientboundLe
* @return a function to create a packet with a specified particle, in the event we need to spawn multiple particles
* with different offsets.
*/
private @Nullable Function<Vector3f, BedrockPacket> createParticle(GeyserSession session, Particle particle) {
public static @Nullable Function<Vector3f, BedrockPacket> createParticle(GeyserSession session, Particle particle) {
switch (particle.getType()) {
case BLOCK -> {
int blockState = session.getBlockMappings().getBedrockBlockId(((BlockParticleData) particle.getData()).getBlockState());
@ -177,6 +177,7 @@ public class JavaLevelParticlesTranslator extends PacketTranslator<ClientboundLe
}
default -> {
ParticleMapping particleMapping = Registries.PARTICLES.get(particle.getType());
System.out.println(particle.getType() + " " + particleMapping);
if (particleMapping == null) { //TODO ensure no particle can be null
return null;
}
@ -205,7 +206,7 @@ public class JavaLevelParticlesTranslator extends PacketTranslator<ClientboundLe
}
}
private NbtMap buildVec3PositionTag(Vector3f position) {
private static NbtMap buildVec3PositionTag(Vector3f position) {
return NbtMap.builder()
.putString("type", "vec3")
.putFloat("x", position.getX())