284 lines
No EOL
11 KiB
Java
284 lines
No EOL
11 KiB
Java
package com.atsuishio.superbwarfare.entity;
|
|
|
|
import com.atsuishio.superbwarfare.ModUtils;
|
|
import com.atsuishio.superbwarfare.config.server.ExplosionDestroyConfig;
|
|
import com.atsuishio.superbwarfare.entity.vehicle.VehicleEntity;
|
|
import com.atsuishio.superbwarfare.init.*;
|
|
import com.atsuishio.superbwarfare.tools.CustomExplosion;
|
|
import com.atsuishio.superbwarfare.tools.EntityFindUtil;
|
|
import com.atsuishio.superbwarfare.tools.ParticleTool;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
|
import net.minecraft.network.syncher.SynchedEntityData;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.players.OldUsersConverter;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.InteractionResult;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.damagesource.DamageTypes;
|
|
import net.minecraft.world.entity.*;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.entity.projectile.ThrownPotion;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.Explosion;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraftforge.items.ItemHandlerHelper;
|
|
import software.bernie.geckolib.animatable.GeoEntity;
|
|
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
|
|
import software.bernie.geckolib.core.animation.AnimatableManager;
|
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
|
|
|
import javax.annotation.Nullable;
|
|
import java.util.Comparator;
|
|
import java.util.Optional;
|
|
import java.util.UUID;
|
|
|
|
public class ClaymoreEntity extends Entity implements GeoEntity, AnimatedEntity, OwnableEntity {
|
|
|
|
protected static final EntityDataAccessor<Optional<UUID>> OWNER_UUID = SynchedEntityData.defineId(ClaymoreEntity.class, EntityDataSerializers.OPTIONAL_UUID);
|
|
protected static final EntityDataAccessor<String> LAST_ATTACKER_UUID = SynchedEntityData.defineId(ClaymoreEntity.class, EntityDataSerializers.STRING);
|
|
public static final EntityDataAccessor<Float> HEALTH = SynchedEntityData.defineId(ClaymoreEntity.class, EntityDataSerializers.FLOAT);
|
|
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
|
|
|
|
public ClaymoreEntity(EntityType<ClaymoreEntity> type, Level world) {
|
|
super(type, world);
|
|
this.noCulling = true;
|
|
}
|
|
|
|
public ClaymoreEntity(LivingEntity owner, Level level) {
|
|
super(ModEntities.CLAYMORE.get(), level);
|
|
this.setOwnerUUID(owner.getUUID());
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData() {
|
|
this.entityData.define(OWNER_UUID, Optional.empty());
|
|
this.entityData.define(LAST_ATTACKER_UUID, "undefined");
|
|
this.entityData.define(HEALTH, 10f);
|
|
}
|
|
|
|
@Override
|
|
public boolean isPickable() {
|
|
return !this.isRemoved();
|
|
}
|
|
|
|
@Override
|
|
public boolean hurt(DamageSource source, float amount) {
|
|
if (source.getDirectEntity() instanceof ThrownPotion || source.getDirectEntity() instanceof AreaEffectCloud)
|
|
return false;
|
|
if (source.is(DamageTypes.FALL))
|
|
return false;
|
|
if (source.is(DamageTypes.CACTUS))
|
|
return false;
|
|
if (source.is(DamageTypes.DROWN))
|
|
return false;
|
|
if (source.is(DamageTypes.DRAGON_BREATH))
|
|
return false;
|
|
if (source.is(DamageTypes.WITHER))
|
|
return false;
|
|
if (source.is(DamageTypes.WITHER_SKULL))
|
|
return false;
|
|
if (source.is(ModDamageTypes.CUSTOM_EXPLOSION) || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.PROJECTILE_BOOM)) {
|
|
amount *= 0.2f;
|
|
}
|
|
|
|
if (source.getEntity() != null) {
|
|
this.entityData.set(LAST_ATTACKER_UUID, source.getEntity().getStringUUID());
|
|
}
|
|
|
|
if (this.level() instanceof ServerLevel serverLevel) {
|
|
ParticleTool.sendParticle(serverLevel, ModParticleTypes.FIRE_STAR.get(), this.getX(), this.getY() + 0.2, this.getZ(), 2, 0.02, 0.02, 0.02, 0.1, false);
|
|
}
|
|
this.level().playSound(null, this.getOnPos(), ModSounds.HIT.get(), SoundSource.PLAYERS, 1, 1);
|
|
this.entityData.set(HEALTH, this.entityData.get(HEALTH) - amount);
|
|
|
|
return super.hurt(source, amount);
|
|
}
|
|
|
|
public void setOwnerUUID(@Nullable UUID pUuid) {
|
|
this.entityData.set(OWNER_UUID, Optional.ofNullable(pUuid));
|
|
}
|
|
|
|
@Nullable
|
|
public UUID getOwnerUUID() {
|
|
return this.entityData.get(OWNER_UUID).orElse(null);
|
|
}
|
|
|
|
public boolean isOwnedBy(LivingEntity pEntity) {
|
|
return pEntity == this.getOwner();
|
|
}
|
|
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag compound) {
|
|
compound.putFloat("Health", this.entityData.get(HEALTH));
|
|
compound.putString("LastAttacker", this.entityData.get(LAST_ATTACKER_UUID));
|
|
if (this.getOwnerUUID() != null) {
|
|
compound.putUUID("Owner", this.getOwnerUUID());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void readAdditionalSaveData(CompoundTag compound) {
|
|
if (compound.contains("Health")) {
|
|
this.entityData.set(HEALTH, compound.getFloat("Health"));
|
|
}
|
|
|
|
if (compound.contains("LastAttacker")) {
|
|
this.entityData.set(LAST_ATTACKER_UUID, compound.getString("LastAttacker"));
|
|
}
|
|
|
|
UUID uuid;
|
|
if (compound.hasUUID("Owner")) {
|
|
uuid = compound.getUUID("Owner");
|
|
} else {
|
|
String s = compound.getString("Owner");
|
|
|
|
assert this.getServer() != null;
|
|
uuid = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), s);
|
|
}
|
|
|
|
if (uuid != null) {
|
|
try {
|
|
this.setOwnerUUID(uuid);
|
|
} catch (Throwable ignored) {
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public InteractionResult interact(Player player, InteractionHand hand) {
|
|
if (this.isOwnedBy(player) && player.isShiftKeyDown()) {
|
|
if (!this.level().isClientSide()) {
|
|
this.discard();
|
|
}
|
|
|
|
if (!player.getAbilities().instabuild) {
|
|
ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(ModItems.CLAYMORE_MINE.get()));
|
|
}
|
|
}
|
|
|
|
return InteractionResult.sidedSuccess(this.level().isClientSide());
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
var level = this.level();
|
|
var x = this.getX();
|
|
var y = this.getY();
|
|
var z = this.getZ();
|
|
|
|
if (this.tickCount >= 12000) {
|
|
if (!this.level().isClientSide()) this.discard();
|
|
}
|
|
|
|
if (this.tickCount >= 40) {
|
|
final Vec3 center = new Vec3(x + 1.5 * this.getLookAngle().x, y + 1.5 * this.getLookAngle().y, z + 1.5 * this.getLookAngle().z);
|
|
for (Entity target : level.getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(2.5 / 2d), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) {
|
|
var condition = this.getOwner() != target
|
|
&& (target instanceof LivingEntity || target instanceof VehicleEntity)
|
|
&& !(target instanceof TargetEntity)
|
|
&& !(target instanceof Player player && (player.isCreative() || player.isSpectator()))
|
|
&& (this.getOwner() != null && !this.getOwner().isAlliedTo(target) || target.getTeam() == null || target.getTeam().getName().equals("TDM"))
|
|
&& !target.isShiftKeyDown();
|
|
if (!condition) continue;
|
|
|
|
if (!level.isClientSide()) {
|
|
if (!this.level().isClientSide()) {
|
|
ParticleTool.spawnMediumExplosionParticles(this.level(), this.position());
|
|
}
|
|
this.discard();
|
|
}
|
|
|
|
ModUtils.queueServerWork(1, () -> {
|
|
if (!level.isClientSide())
|
|
triggerExplode();
|
|
});
|
|
}
|
|
}
|
|
|
|
this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.03, 0.0));
|
|
|
|
if (!this.level().noCollision(this.getBoundingBox())) {
|
|
this.moveTowardsClosestSpace(this.getX(), (this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0, this.getZ());
|
|
}
|
|
|
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
|
float f = 0.98F;
|
|
if (this.onGround()) {
|
|
BlockPos pos = this.getBlockPosBelowThatAffectsMyMovement();
|
|
f = this.level().getBlockState(pos).getFriction(this.level(), pos, this) * 0.98F;
|
|
}
|
|
|
|
this.setDeltaMovement(this.getDeltaMovement().multiply(f, 0.98, f));
|
|
if (this.onGround()) {
|
|
this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, -0.9, 1.0));
|
|
}
|
|
|
|
if (this.entityData.get(HEALTH) <= 0) {
|
|
destroy();
|
|
}
|
|
|
|
this.refreshDimensions();
|
|
}
|
|
|
|
public void destroy() {
|
|
if (level() instanceof ServerLevel) {
|
|
Entity attacker = EntityFindUtil.findEntity(this.level(), this.entityData.get(LAST_ATTACKER_UUID));
|
|
CustomExplosion explosion = new CustomExplosion(this.level(), attacker == null ? this : attacker,
|
|
ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), attacker == null ? this : attacker, attacker == null ? this : attacker), 25.0f,
|
|
this.getX(), this.getY(), this.getZ(), 5f, ExplosionDestroyConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1);
|
|
explosion.explode();
|
|
net.minecraftforge.event.ForgeEventFactory.onExplosionStart(this.level(), explosion);
|
|
explosion.finalizeExplosion(false);
|
|
ParticleTool.spawnMediumExplosionParticles(this.level(), this.position());
|
|
this.discard();
|
|
}
|
|
}
|
|
|
|
private void triggerExplode() {
|
|
CustomExplosion explosion = new CustomExplosion(this.level(), this,
|
|
ModDamageTypes.causeMineDamage(this.level().registryAccess(), this.getOwner()), 140f,
|
|
this.getX(), this.getEyeY(), this.getZ(), 4f, ExplosionDestroyConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1);
|
|
explosion.explode();
|
|
net.minecraftforge.event.ForgeEventFactory.onExplosionStart(this.level(), explosion);
|
|
explosion.finalizeExplosion(false);
|
|
}
|
|
|
|
@Override
|
|
public EntityDimensions getDimensions(Pose p_33597_) {
|
|
return super.getDimensions(p_33597_).scale((float) 0.5);
|
|
}
|
|
|
|
@Override
|
|
public boolean isPushable() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public String getSyncedAnimation() {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void setAnimation(String animation) {
|
|
}
|
|
|
|
@Override
|
|
public void setAnimationProcedure(String procedure) {
|
|
}
|
|
|
|
@Override
|
|
public void registerControllers(AnimatableManager.ControllerRegistrar data) {
|
|
}
|
|
|
|
@Override
|
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
|
return this.cache;
|
|
}
|
|
} |