Skip to content

Commit

Permalink
Clean up bullet entity code
Browse files Browse the repository at this point in the history
Bullet data is attached and synced automatically now, rather than requiring per-bullet special casing.
  • Loading branch information
malte0811 committed Sep 29, 2024
1 parent 7c231f3 commit 24c08ed
Show file tree
Hide file tree
Showing 15 changed files with 273 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

package blusunrize.immersiveengineering.api.tool;

import blusunrize.immersiveengineering.api.utils.Color4;
import blusunrize.immersiveengineering.api.utils.SetRestrictedField;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
Expand Down Expand Up @@ -124,13 +125,16 @@ default int getProjectileCount(@Nullable Player shooter)
*/
default Entity getProjectile(@Nullable Player shooter, StackData data, Entity projectile, boolean charged)
{
// TODO why is charged not passed through globally?
return projectile;
}

/**
* called when the bullet hits a target
*/
void onHitTarget(Level world, HitResult target, @Nullable UUID shooter, Entity projectile, boolean headshot);
void onHitTarget(
Level world, HitResult target, @Nullable UUID shooter, Entity projectile, boolean headshot,
StackData bulletData);

/**
* @return the casing left when fired. Can return the static ItemStacks in BulletHandler
Expand All @@ -145,7 +149,10 @@ default Entity getProjectile(@Nullable Player shooter, StackData data, Entity pr
/**
* @return the colour applied to the given layer
*/
int getColour(StackData data, int layer);
default Color4 getColour(StackData data, int layer)
{
return Color4.WHITE;
}

/**
* @return whether this cartridge should be allowed to be placed in, and used from a turret.<br>
Expand Down Expand Up @@ -207,7 +214,7 @@ protected float getDamage(Entity hitEntity, boolean headshot)
}

@Override
public void onHitTarget(Level world, HitResult rtr, @Nullable UUID shooterUUID, Entity projectile, boolean headshot)
public void onHitTarget(Level world, HitResult rtr, @Nullable UUID shooterUUID, Entity projectile, boolean headshot, StackData bulletData)
{
if(!(rtr instanceof EntityHitResult))
return;
Expand Down Expand Up @@ -240,12 +247,6 @@ public ResourceLocation[] getTextures()
return textures;
}

@Override
public int getColour(StackData data, int layer)
{
return 0xffffffff;
}

@Override
public boolean isValidForTurret()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import malte0811.dualcodecs.DualCompositeCodecs;
import net.minecraft.nbt.Tag;
import net.minecraft.world.item.DyeColor;
import org.joml.Vector3f;

public record Color4(float r, float g, float b, float a)
{
Expand Down Expand Up @@ -68,4 +69,9 @@ public int toInt()
final int aInt = (int)(255*a);
return (aInt<<24)|(rInt<<16)|(gInt<<8)|bInt;
}

public Vector3f toVector3f()
{
return new Vector3f(r, g, b);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import blusunrize.immersiveengineering.api.tool.BulletHandler.IBullet;
import blusunrize.immersiveengineering.common.blocks.BlockCapabilityRegistration.BECapabilityRegistrar;
import blusunrize.immersiveengineering.common.config.IEServerConfig;
import blusunrize.immersiveengineering.common.entities.RevolvershotEntity;
import blusunrize.immersiveengineering.common.items.BulletItem;
import blusunrize.immersiveengineering.common.network.MessageBlockEntitySync;
import blusunrize.immersiveengineering.common.register.IEMenuTypes;
Expand All @@ -33,7 +32,6 @@
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
Expand Down Expand Up @@ -91,7 +89,7 @@ protected void activate()
ItemStack bulletStack = inventory.get(0);
if(bulletStack.getItem() instanceof BulletItem&&this.energyStorage.extractEnergy(energy, true)==energy)
{
IBullet bullet = ((BulletItem)bulletStack.getItem()).getType();
IBullet<?> bullet = ((BulletItem<?>)bulletStack.getItem()).getType();
if(bullet!=null&&bullet.isValidForTurret())
{
ItemStack casing = bullet.getCasing(bulletStack);
Expand All @@ -105,16 +103,12 @@ protected void activate()

int count = bullet.getProjectileCount(null);
if(count==1)
{
Entity entBullet = getBulletEntity(level, vec, bullet);
level.addFreshEntity(bullet.getProjectile(null, bulletStack, entBullet, false));
}
level.addFreshEntity(getBulletEntity(vec, bulletStack));
else
for(int i = 0; i < count; i++)
{
Vec3 vecDir = vec.add(ApiUtils.RANDOM.nextGaussian()*.1, ApiUtils.RANDOM.nextGaussian()*.1, ApiUtils.RANDOM.nextGaussian()*.1);
Entity entBullet = getBulletEntity(level, vecDir, bullet);
level.addFreshEntity(bullet.getProjectile(null, bulletStack, entBullet, false));
level.addFreshEntity(getBulletEntity(vecDir, bulletStack));
}
bulletStack.shrink(1);
if(bulletStack.getCount() <= 0)
Expand Down Expand Up @@ -158,12 +152,11 @@ protected void sendRenderPacket()
);
}

RevolvershotEntity getBulletEntity(Level world, Vec3 vecDir, IBullet type)
private Entity getBulletEntity(Vec3 vecDir, ItemStack bulletStack)
{
Vec3 gunPos = getGunPosition();
RevolvershotEntity bullet = new RevolvershotEntity(world, gunPos.x+vecDir.x, gunPos.y+vecDir.y, gunPos.z+vecDir.z, 0, 0, 0, type);
bullet.setDeltaMovement(vecDir);
return bullet;
return ((BulletItem<?>)bulletStack.getItem()).createBullet(
level, null, getGunPosition(), vecDir, bulletStack, false
);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,22 @@

import blusunrize.immersiveengineering.api.tool.BulletHandler;
import blusunrize.immersiveengineering.api.tool.BulletHandler.IBullet;
import blusunrize.immersiveengineering.common.items.bullets.IEBullets;
import blusunrize.immersiveengineering.common.network.MessageBirthdayParty;
import blusunrize.immersiveengineering.common.register.IEEntityDataSerializers;
import blusunrize.immersiveengineering.common.register.IEEntityTypes;
import blusunrize.immersiveengineering.common.util.EnergyHelper;
import blusunrize.immersiveengineering.common.util.IESounds;
import blusunrize.immersiveengineering.common.util.Utils;
import com.google.common.base.Preconditions;
import malte0811.dualcodecs.DualCodec;
import malte0811.dualcodecs.DualCodecs;
import malte0811.dualcodecs.DualMapCodec;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.SynchedEntityData.Builder;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
Expand All @@ -35,11 +43,16 @@
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.network.PacketDistributor;

import java.util.UUID;

public class RevolvershotEntity extends IEProjectileEntity
{
private IBullet bulletType;
private static final EntityDataAccessor<BulletData<?>> DATAMARKER_BULLET = SynchedEntityData.defineId(
RevolvershotEntity.class, IEEntityDataSerializers.BULLET.get()
);

private BulletData<?> bullet;
public boolean bulletElectro = false;
public ItemStack bulletPotion = ItemStack.EMPTY;
private float gravity;
private float movementDecay;

Expand All @@ -48,28 +61,43 @@ public RevolvershotEntity(EntityType<? extends RevolvershotEntity> type, Level w
super(type, world);
}

public RevolvershotEntity(EntityType<? extends RevolvershotEntity> eType, Level world, LivingEntity shooter, double x, double y, double z,
double ax, double ay, double az, IBullet type)
public <T> RevolvershotEntity(
EntityType<? extends RevolvershotEntity> eType, Level world, LivingEntity shooter,
double x, double y, double z, double ax, double ay, double az,
IBullet<T> bullet, T bulletData
)
{
super(eType, world, shooter, x, y, z, ax, ay, az);
this.setPos(x, y, z);
this.bulletType = type;
this.bullet = new BulletData<>(bullet, bulletData);
this.entityData.set(DATAMARKER_BULLET, this.bullet);
}

public RevolvershotEntity(Level world, double x, double y, double z,
double ax, double ay, double az, IBullet type)
public <T> RevolvershotEntity(
Level world,
double x, double y, double z, double ax, double ay, double az,
IBullet<T> bullet, T bulletData
)
{
this(IEEntityTypes.REVOLVERSHOT.get(), world, null, x, y, z, ax, ay, az, type);
this(IEEntityTypes.REVOLVERSHOT.get(), world, null, x, y, z, ax, ay, az, bullet, bulletData);
}

public RevolvershotEntity(Level world, LivingEntity living, double ax, double ay, double az, IBullet type)
public <T> RevolvershotEntity(
Level world, LivingEntity living,
double ax, double ay, double az,
IBullet<T> bullet, T bulletData
)
{
this(IEEntityTypes.REVOLVERSHOT.get(), world, living, ax, ay, az, type);
this(IEEntityTypes.REVOLVERSHOT.get(), world, living, ax, ay, az, bullet, bulletData);
}

public RevolvershotEntity(EntityType<? extends RevolvershotEntity> eType, Level world, LivingEntity living, double ax, double ay, double az, IBullet type)
public <T> RevolvershotEntity(
EntityType<? extends RevolvershotEntity> eType, Level world, LivingEntity living,
double ax, double ay, double az,
IBullet<T> bullet, T bulletData
)
{
this(eType, world, living, living.getX()+ax, living.getY()+living.getEyeHeight()+ay, living.getZ()+az, ax, ay, az, type);
this(eType, world, living, living.getX()+ax, living.getY()+living.getEyeHeight()+ay, living.getZ()+az, ax, ay, az, bullet, bulletData);
setShooterSynced();
setDeltaMovement(Vec3.ZERO);
}
Expand All @@ -82,6 +110,21 @@ public boolean shouldRenderAtSqrDistance(double distance)
return distance < d1*d1;
}

@Override
protected void defineSynchedData(Builder builder)
{
super.defineSynchedData(builder);
builder.define(DATAMARKER_BULLET, new BulletData<>(BulletHandler.getBullet(IEBullets.CASULL)));
}

public BulletData<?> getBullet()
{
if(level().isClientSide)
return entityData.get(DATAMARKER_BULLET);
else
return bullet;
}

@Override
public void onHit(HitResult mop)
{
Expand All @@ -93,9 +136,9 @@ public void onHit(HitResult mop)
headshot = Utils.isVecInEntityHead((LivingEntity)hitEntity, position());
}

if(this.bulletType!=null)
if(this.bullet!=null)
{
bulletType.onHitTarget(level(), mop, this.shooterUUID, this, headshot);
bullet.onHitTarget(level(), mop, this.shooterUUID, this, headshot);
if(mop instanceof EntityHitResult)
{
Entity hitEntity = ((EntityHitResult)mop).getEntity();
Expand Down Expand Up @@ -125,7 +168,7 @@ public void secondaryImpact(HitResult mop)
if(bulletElectro&&hitEntity instanceof LivingEntity&&shooterUUID!=null)
{
Player shooter = level().getPlayerByUUID(shooterUUID);
float percentualDrain = .15f/(bulletType==null?1: bulletType.getProjectileCount(shooter));
float percentualDrain = .15f/(bullet==null?1: bullet.bullet.getProjectileCount(shooter));
((LivingEntity)hitEntity).addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 15, 4));
for(EquipmentSlot slot : EquipmentSlot.values())
{
Expand All @@ -151,18 +194,14 @@ public void addAdditionalSaveData(CompoundTag nbt)
{
super.addAdditionalSaveData(nbt);
nbt.putByte("inGround", (byte)(this.inGround?1: 0));
nbt.putString("bulletType", BulletHandler.findRegistryName(this.bulletType).toString());
if(!bulletPotion.isEmpty())
nbt.put("bulletPotion", bulletPotion.save(level().registryAccess()));
nbt.put("bullet", BulletData.CODECS.toNBT(bullet));
}

@Override
public void readAdditionalSaveData(CompoundTag nbt)
{
super.readAdditionalSaveData(nbt);
this.bulletType = BulletHandler.getBullet(ResourceLocation.parse(nbt.getString("bulletType")));
if(nbt.contains("bulletPotion", Tag.TAG_COMPOUND))
this.bulletPotion = ItemStack.parseOptional(level().registryAccess(), nbt.getCompound("bulletPotion"));
this.bullet = BulletData.CODECS.fromNBT(nbt.get("bullet"));
}

@Override
Expand Down Expand Up @@ -210,4 +249,44 @@ protected float getMotionDecayFactor()
{
return movementDecay;
}

public record BulletData<T>(IBullet<T> bullet, T data)
{
public static final DualCodec<RegistryFriendlyByteBuf, BulletData<?>> CODECS = DualCodecs.RESOURCE_LOCATION
.<RegistryFriendlyByteBuf>castStream()
.dispatch(
bd -> BulletHandler.findRegistryName(bd.bullet),
rl -> specificCodec(BulletHandler.getBullet(rl))
);

public BulletData(IBullet<T> bullet)
{
this(bullet, bullet.getCodec().defaultValue());
}

public void onHitTarget(
Level level, HitResult mop, UUID shooterUUID, RevolvershotEntity revolvershotEntity, boolean headshot
)
{
bullet.onHitTarget(level, mop, shooterUUID, revolvershotEntity, headshot, data);
}

public <T1> T1 getForOptional(IBullet<T1> type)
{
return type==bullet?(T1)data: null;
}

public <T1> T1 getFor(IBullet<T1> type)
{
return Preconditions.checkNotNull(getForOptional(type));
}

private static <T> DualMapCodec<RegistryFriendlyByteBuf, BulletData<?>> specificCodec(IBullet<T> bullet)
{
DualCodec<? super RegistryFriendlyByteBuf, BulletData<?>> codec = bullet.getCodec().codecs().map(
t -> new BulletData<>(bullet, t), bd -> (T)bd.data
);
return codec.<RegistryFriendlyByteBuf>castStream().fieldOf("data");
}
}
}
Loading

0 comments on commit 24c08ed

Please sign in to comment.